diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..40ce0c2 --- /dev/null +++ b/.gitignore @@ -0,0 +1,10 @@ +src/Library +src/Temp +src/Assembly-CSharp-Editor-vs.csproj +src/Assembly-CSharp-Editor.csproj +src/Assembly-CSharp-vs.csproj +src/Assembly-CSharp.csproj +src/Assembly-UnityScript-Editor-vs.unityproj +src/Assembly-UnityScript-Editor.unityproj +src/src-csharp.sln +src/src.sln diff --git a/License.txt b/License.txt new file mode 100644 index 0000000..da3dc93 --- /dev/null +++ b/License.txt @@ -0,0 +1,31 @@ +Microsoft Public License (Ms-PL) + +This license governs use of the accompanying software. If you use the software, you accept this license. If you do not accept the license, do not use the software. + +1. Definitions + +The terms "reproduce," "reproduction," "derivative works," and "distribution" have the same meaning here as under U.S. copyright law. + +A "contribution" is the original software, or any additions or changes to the software. + +A "contributor" is any person that distributes its contribution under this license. + +"Licensed patents" are a contributor's patent claims that read directly on its contribution. + +2. Grant of Rights + +(A) Copyright Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free copyright license to reproduce its contribution, prepare derivative works of its contribution, and distribute its contribution or any derivative works that you create. + +(B) Patent Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free license under its licensed patents to make, have made, use, sell, offer for sale, import, and/or otherwise dispose of its contribution in the software or derivative works of the contribution in the software. + +3. Conditions and Limitations + +(A) No Trademark License- This license does not grant you rights to use any contributors' name, logo, or trademarks. + +(B) If you bring a patent claim against any contributor over patents that you claim are infringed by the software, your patent license from such contributor to the software ends automatically. + +(C) If you distribute any portion of the software, you must retain all copyright, patent, trademark, and attribution notices that are present in the software. + +(D) If you distribute any portion of the software in source code form, you may do so only under this license by including a complete copy of this license with your distribution. If you distribute any portion of the software in compiled or object code form, you may only do so under a license that complies with this license. + +(E) The software is licensed "as-is." You bear the risk of using it. The contributors give no express warranties, guarantees or conditions. You may have additional consumer rights under your local laws which this license cannot change. To the extent permitted under your local laws, the contributors exclude the implied warranties of merchantability, fitness for a particular purpose and non-infringement. \ No newline at end of file diff --git a/src/Assets/UnityTestTools.meta b/src/Assets/UnityTestTools.meta new file mode 100644 index 0000000..0d30e01 --- /dev/null +++ b/src/Assets/UnityTestTools.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: 29ca4a0c0429a4a8287ac4161c22c1b8 +folderAsset: yes +DefaultImporter: + userData: diff --git a/src/Assets/UnityTestTools/Assertions.meta b/src/Assets/UnityTestTools/Assertions.meta new file mode 100644 index 0000000..229b8b8 --- /dev/null +++ b/src/Assets/UnityTestTools/Assertions.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: b27b28700d3365146808b6e082748201 +folderAsset: yes +DefaultImporter: + userData: diff --git a/src/Assets/UnityTestTools/Assertions/AssertionComponent.cs b/src/Assets/UnityTestTools/Assertions/AssertionComponent.cs new file mode 100644 index 0000000..9c6707c --- /dev/null +++ b/src/Assets/UnityTestTools/Assertions/AssertionComponent.cs @@ -0,0 +1,372 @@ +using System; +using System.Collections; +using System.Linq; +using UnityEngine; + +namespace UnityTest +{ + [Serializable] + public class AssertionComponent : MonoBehaviour, AssertionComponentConfigurator + { + [SerializeField] public float checkAfterTime = 1f; + [SerializeField] public bool repeatCheckTime = true; + [SerializeField] public float repeatEveryTime = 1f; + [SerializeField] public int checkAfterFrames = 1; + [SerializeField] public bool repeatCheckFrame = true; + [SerializeField] public int repeatEveryFrame = 1; + [SerializeField] public bool hasFailed; + + [SerializeField] public CheckMethod checkMethods = CheckMethod.Start; + [SerializeField] private ActionBase m_ActionBase; + + [SerializeField] public int checksPerformed = 0; + + private int checkOnFrame = 0; + + private string createdInFilePath; + private int createdInFileLine = -1; + + public ActionBase Action + { + get { return m_ActionBase; } + set + { + m_ActionBase = value; + m_ActionBase.go = gameObject; + } + } + + public UnityEngine.Object GetFailureReferenceObject () + { + if (!string.IsNullOrEmpty (createdInFilePath)) + { + return Resources.LoadAssetAtPath (createdInFilePath, typeof (UnityEngine.Object)); + } + return this; + } + + public string GetCreationLocation () + { + if (!string.IsNullOrEmpty (createdInFilePath)) + { + var idx = createdInFilePath.LastIndexOf ("\\") + 1; + return string.Format ("{0}, line {1} ({2})", createdInFilePath.Substring (idx), createdInFileLine, createdInFilePath); + } + return ""; + } + + public void Awake () + { + if (!Debug.isDebugBuild) + Destroy (this); + OnComponentCopy (); + } + +#if UNITY_EDITOR + public void OnValidate () + { + OnComponentCopy (); + } +#endif + + private void OnComponentCopy () + { + if (m_ActionBase == null) return; + var oldActionList = Resources.FindObjectsOfTypeAll (typeof (AssertionComponent)).Where (o => ((AssertionComponent) o).m_ActionBase == m_ActionBase && o != this); + + //if it's not a copy but a new component don't do anything + if (!oldActionList.Any ()) return; + if (oldActionList.Count () > 1) + Debug.LogWarning ("More than one refence to comparer found. This shouldn't happen"); + + var oldAction = oldActionList.First() as AssertionComponent; + m_ActionBase = oldAction.m_ActionBase.CreateCopy (oldAction.gameObject, gameObject); + } + + public void Start () + { + CheckAssertionFor (CheckMethod.Start); + + if(IsCheckMethodSelected(CheckMethod.AfterPeriodOfTime)) + { + StartCoroutine("CheckPeriodically"); + } + if(IsCheckMethodSelected (CheckMethod.Update)) + { + checkOnFrame = Time.frameCount + checkAfterFrames; + } + } + + public IEnumerator CheckPeriodically() + { + yield return new WaitForSeconds(checkAfterTime); + CheckAssertionFor(CheckMethod.AfterPeriodOfTime); + while (repeatCheckTime) + { + yield return new WaitForSeconds(repeatEveryTime); + CheckAssertionFor(CheckMethod.AfterPeriodOfTime); + } + } + + public bool ShouldCheckOnFrame() + { + if (Time.frameCount > checkOnFrame) + { + if (repeatCheckFrame) + checkOnFrame += repeatEveryFrame; + else + checkOnFrame = Int32.MaxValue; + return true; + } + return false; + } + + public void OnDisable () + { + CheckAssertionFor (CheckMethod.OnDisable); + } + + public void OnEnable () + { + CheckAssertionFor (CheckMethod.OnEnable); + } + + public void OnDestroy () + { + CheckAssertionFor (CheckMethod.OnDestroy); + } + + public void Update () + { + if (IsCheckMethodSelected(CheckMethod.Update) && ShouldCheckOnFrame ()) + { + CheckAssertionFor (CheckMethod.Update); + } + } + + public void FixedUpdate () + { + CheckAssertionFor(CheckMethod.FixedUpdate); + } + + public void LateUpdate () + { + CheckAssertionFor (CheckMethod.LateUpdate); + } + + public void OnControllerColliderHit () + { + CheckAssertionFor (CheckMethod.OnControllerColliderHit); + } + + public void OnParticleCollision () + { + CheckAssertionFor (CheckMethod.OnParticleCollision); + } + + public void OnJointBreak () + { + CheckAssertionFor (CheckMethod.OnJointBreak); + } + + public void OnBecameInvisible () + { + CheckAssertionFor (CheckMethod.OnBecameInvisible); + } + + public void OnBecameVisible () + { + CheckAssertionFor (CheckMethod.OnBecameVisible); + } + + public void OnTriggerEnter () + { + CheckAssertionFor (CheckMethod.OnTriggerEnter); + } + + public void OnTriggerExit () + { + CheckAssertionFor (CheckMethod.OnTriggerExit); + } + + public void OnTriggerStay () + { + CheckAssertionFor (CheckMethod.OnTriggerStay); + } + + public void OnCollisionEnter () + { + CheckAssertionFor (CheckMethod.OnCollisionEnter); + } + + public void OnCollisionExit () + { + CheckAssertionFor (CheckMethod.OnCollisionExit); + } + + public void OnCollisionStay () + { + CheckAssertionFor (CheckMethod.OnCollisionStay); + } + + public void OnTriggerEnter2D () + { + CheckAssertionFor (CheckMethod.OnTriggerEnter2D); + } + + public void OnTriggerExit2D () + { + CheckAssertionFor (CheckMethod.OnTriggerExit2D); + } + + public void OnTriggerStay2D () + { + CheckAssertionFor (CheckMethod.OnTriggerStay2D); + } + + public void OnCollisionEnter2D () + { + CheckAssertionFor (CheckMethod.OnCollisionEnter2D); + } + + public void OnCollisionExit2D () + { + CheckAssertionFor (CheckMethod.OnCollisionExit2D); + } + + public void OnCollisionStay2D () + { + CheckAssertionFor (CheckMethod.OnCollisionStay2D); + } + + private void CheckAssertionFor (CheckMethod checkMethod) + { + if (IsCheckMethodSelected (checkMethod)) + { + Assertions.CheckAssertions (this); + } + } + + public bool IsCheckMethodSelected (CheckMethod method) + { + return method == (checkMethods & method); + } + + + #region Assertion Component create methods + + public static T Create (CheckMethod checkOnMethods, GameObject gameObject, string propertyPath) where T : ActionBase + { + AssertionComponentConfigurator configurator; + return Create (out configurator, checkOnMethods, gameObject, propertyPath); + } + + public static T Create ( out AssertionComponentConfigurator configurator, CheckMethod checkOnMethods, GameObject gameObject, string propertyPath ) where T : ActionBase + { + return CreateAssertionComponent (out configurator, checkOnMethods, gameObject, propertyPath); + } + + public static T Create ( CheckMethod checkOnMethods, GameObject gameObject, string propertyPath, GameObject gameObject2, string propertyPath2 ) where T : ComparerBase + { + AssertionComponentConfigurator configurator; + return Create (out configurator, checkOnMethods, gameObject, propertyPath, gameObject2, propertyPath2); + } + + public static T Create ( out AssertionComponentConfigurator configurator, CheckMethod checkOnMethods, GameObject gameObject, string propertyPath, GameObject gameObject2, string propertyPath2 ) where T : ComparerBase + { + var comparer = CreateAssertionComponent (out configurator, checkOnMethods, gameObject, propertyPath); + comparer.compareToType = ComparerBase.CompareToType.CompareToObject; + comparer.other = gameObject2; + comparer.otherPropertyPath = propertyPath2; + return comparer; + } + + public static T Create (CheckMethod checkOnMethods, GameObject gameObject, string propertyPath, object constValue) where T : ComparerBase + { + AssertionComponentConfigurator configurator; + return Create (out configurator, checkOnMethods, gameObject, propertyPath, constValue); + } + + public static T Create ( out AssertionComponentConfigurator configurator, CheckMethod checkOnMethods, GameObject gameObject, string propertyPath, object constValue ) where T : ComparerBase + { + var comparer = CreateAssertionComponent (out configurator, checkOnMethods, gameObject, propertyPath); + if (constValue == null) + { + comparer.compareToType = ComparerBase.CompareToType.CompareToNull; + return comparer; + } + comparer.compareToType = ComparerBase.CompareToType.CompareToConstantValue; + comparer.ConstValue = constValue; + return comparer; + } + + private static T CreateAssertionComponent ( out AssertionComponentConfigurator configurator, CheckMethod checkOnMethods, GameObject gameObject, string propertyPath ) where T : ActionBase + { + var ac = gameObject.AddComponent (); + ac.checkMethods = checkOnMethods; + var comparer = ScriptableObject.CreateInstance (); + ac.Action = comparer; + ac.Action.go = gameObject; + ac.Action.thisPropertyPath = propertyPath; + configurator = ac; + + var stackTrace = new System.Diagnostics.StackTrace (true); + var thisFileName = stackTrace.GetFrame (0).GetFileName (); + for (int i = 1; i < stackTrace.FrameCount; i++) + { + var stackFrame = stackTrace.GetFrame (i); + if (stackFrame.GetFileName () != thisFileName) + { + string filePath = stackFrame.GetFileName ().Substring (Application.dataPath.Length - "Assets".Length); + ac.createdInFilePath = filePath; + ac.createdInFileLine = stackFrame.GetFileLineNumber (); + break; + } + } + return comparer; + } + + #endregion + + #region AssertionComponentConfigurator + public int UpdateCheckStartOnFrame { set { checkAfterFrames = value; } } + public int UpdateCheckRepeatFrequency { set { repeatEveryFrame = value; } } + public bool UpdateCheckRepeat { set { repeatCheckFrame = value; } } + public float TimeCheckStartAfter { set { checkAfterTime = value; } } + public float TimeCheckRepeatFrequency { set { repeatEveryTime = value; } } + public bool TimeCheckRepeat { set { repeatCheckTime = value; } } + public AssertionComponent Component { get { return this; } } + #endregion + } + + public interface AssertionComponentConfigurator + { + /// + /// If the assertion is evaluated in Update, after how many frame should the evaluation start. Deafult is 1 (first frame) + /// + int UpdateCheckStartOnFrame { set; } + /// + /// If the assertion is evaluated in Update and UpdateCheckRepeat is true, how many frame should pass between evaluations + /// + int UpdateCheckRepeatFrequency { set; } + /// + /// If the assertion is evaluated in Update, should the evaluation be repeated after UpdateCheckRepeatFrequency frames + /// + bool UpdateCheckRepeat { set; } + + /// + /// If the assertion is evaluated after a period of time, after how many seconds the first evaluation should be done + /// + float TimeCheckStartAfter { set; } + /// + /// If the assertion is evaluated after a period of time and TimeCheckRepeat is true, after how many seconds should the next evaluation happen + /// + float TimeCheckRepeatFrequency { set; } + /// + /// If the assertion is evaluated after a period, should the evaluation happen again after TimeCheckRepeatFrequency seconds + /// + bool TimeCheckRepeat { set; } + + AssertionComponent Component { get; } + } +} diff --git a/src/Assets/UnityTestTools/Assertions/AssertionComponent.cs.meta b/src/Assets/UnityTestTools/Assertions/AssertionComponent.cs.meta new file mode 100644 index 0000000..26f9ab4 --- /dev/null +++ b/src/Assets/UnityTestTools/Assertions/AssertionComponent.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 8bafa54482a87ac4cbd7ff1bfd1ac93a +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/UnityTestTools/Assertions/AssertionException.cs b/src/Assets/UnityTestTools/Assertions/AssertionException.cs new file mode 100644 index 0000000..f7a2fad --- /dev/null +++ b/src/Assets/UnityTestTools/Assertions/AssertionException.cs @@ -0,0 +1,22 @@ +using System; + +namespace UnityTest +{ + public class AssertionException : Exception + { + private AssertionComponent assertion; + + public AssertionException (AssertionComponent assertion) : base(assertion.Action.GetFailureMessage ()) + { + this.assertion = assertion; + } + + public override string StackTrace + { + get + { + return "Created in " + assertion.GetCreationLocation (); + } + } + } +} diff --git a/src/Assets/UnityTestTools/Assertions/AssertionException.cs.meta b/src/Assets/UnityTestTools/Assertions/AssertionException.cs.meta new file mode 100644 index 0000000..9605bf0 --- /dev/null +++ b/src/Assets/UnityTestTools/Assertions/AssertionException.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ef3769ab00d50bc4fbb05a9a91c741d9 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/UnityTestTools/Assertions/Assertions.cs b/src/Assets/UnityTestTools/Assertions/Assertions.cs new file mode 100644 index 0000000..b59edaf --- /dev/null +++ b/src/Assets/UnityTestTools/Assertions/Assertions.cs @@ -0,0 +1,40 @@ +using UnityEngine; +using Object = UnityEngine.Object; + +namespace UnityTest +{ + public static class Assertions + { + public static void CheckAssertions () + { + var assertions = Object.FindObjectsOfType (typeof (AssertionComponent)) as AssertionComponent[]; + CheckAssertions (assertions); + } + + public static void CheckAssertions (AssertionComponent assertion) + { + CheckAssertions (new[] {assertion}); + } + + public static void CheckAssertions (GameObject gameObject) + { + CheckAssertions (gameObject.GetComponents ()); + } + + public static void CheckAssertions (AssertionComponent[] assertions) + { + if (!Debug.isDebugBuild) + return; + foreach (var assertion in assertions) + { + assertion.checksPerformed++; + var result = assertion.Action.Compare (); + if (!result) + { + assertion.hasFailed = true; + assertion.Action.Fail (assertion); + } + } + } + } +} diff --git a/src/Assets/UnityTestTools/Assertions/Assertions.cs.meta b/src/Assets/UnityTestTools/Assertions/Assertions.cs.meta new file mode 100644 index 0000000..00878a4 --- /dev/null +++ b/src/Assets/UnityTestTools/Assertions/Assertions.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 85280dad1e618c143bd3fb07a197b469 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/UnityTestTools/Assertions/CheckMethod.cs b/src/Assets/UnityTestTools/Assertions/CheckMethod.cs new file mode 100644 index 0000000..06f6830 --- /dev/null +++ b/src/Assets/UnityTestTools/Assertions/CheckMethod.cs @@ -0,0 +1,32 @@ +namespace UnityTest +{ + [System.Flags] + public enum CheckMethod + { + AfterPeriodOfTime = 1 << 0, + Start = 1 << 1, + Update = 1 << 2, + FixedUpdate = 1 << 3, + LateUpdate = 1 << 4, + OnDestroy = 1 << 5, + OnEnable = 1 << 6, + OnDisable = 1 << 7, + OnControllerColliderHit = 1 << 8, + OnParticleCollision = 1 << 9, + OnJointBreak = 1 << 10, + OnBecameInvisible = 1 << 11, + OnBecameVisible = 1 << 12, + OnTriggerEnter = 1 << 13, + OnTriggerExit = 1 << 14, + OnTriggerStay = 1 << 15, + OnCollisionEnter = 1 << 16, + OnCollisionExit = 1 << 17, + OnCollisionStay = 1 << 18, + OnTriggerEnter2D = 1 << 19, + OnTriggerExit2D = 1 << 20, + OnTriggerStay2D = 1 << 21, + OnCollisionEnter2D = 1 << 22, + OnCollisionExit2D = 1 << 23, + OnCollisionStay2D = 1 << 24, + } +} diff --git a/src/Assets/UnityTestTools/Assertions/CheckMethod.cs.meta b/src/Assets/UnityTestTools/Assertions/CheckMethod.cs.meta new file mode 100644 index 0000000..d3f6ec9 --- /dev/null +++ b/src/Assets/UnityTestTools/Assertions/CheckMethod.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: cbb75d1643c5a55439f8861a827f411b +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/UnityTestTools/Assertions/Comparers.meta b/src/Assets/UnityTestTools/Assertions/Comparers.meta new file mode 100644 index 0000000..15d3a92 --- /dev/null +++ b/src/Assets/UnityTestTools/Assertions/Comparers.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: bb9e10c25f478c84f826ea85b03ec179 +folderAsset: yes +DefaultImporter: + userData: diff --git a/src/Assets/UnityTestTools/Assertions/Comparers/ActionBase.cs b/src/Assets/UnityTestTools/Assertions/Comparers/ActionBase.cs new file mode 100644 index 0000000..47c7b82 --- /dev/null +++ b/src/Assets/UnityTestTools/Assertions/Comparers/ActionBase.cs @@ -0,0 +1,119 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using UnityEngine; + +namespace UnityTest +{ + public abstract class ActionBase : ScriptableObject + { + public GameObject go; + protected object objVal; + + private MemberResolver memberResolver; + + public string thisPropertyPath = ""; + public virtual Type[] GetAccepatbleTypesForA() + { + return null; + } + public virtual int GetDepthOfSearch() { return 2; } + + public virtual string[] GetExcludedFieldNames() + { + return new string[] { }; + } + + public bool Compare () + { + if (memberResolver == null) + memberResolver = new MemberResolver (go, thisPropertyPath); + objVal = memberResolver.GetValue (UseCache); + var result = Compare(objVal); + return result; + } + + protected abstract bool Compare (object objVal); + + virtual protected bool UseCache { get { return false; } } + + public virtual Type GetParameterType() { return typeof(object); } + + public virtual string GetConfigurationDescription () + { + string result = ""; +#if !UNITY_METRO + foreach (var prop in GetType().GetFields(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly) + .Where (info => info.FieldType.IsSerializable)) + { + var value = prop.GetValue (this); + if (value is double) + value = ((double)value).ToString("0.########"); + if (value is float) + value = ((float)value).ToString("0.########"); + result += value + " "; + } +#endif + return result; + } + + IEnumerable GetFields (Type type) + { +#if !UNITY_METRO + return type.GetFields (BindingFlags.Public | BindingFlags.Instance); +#else + return null; +#endif + } + + public ActionBase CreateCopy (GameObject oldGameObject, GameObject newGameObject) + { + var newObj = CreateInstance (GetType ()) as ActionBase; + var fields = GetFields (GetType ()); + foreach (var field in fields) + { + var value = field.GetValue (this); + if (value is GameObject) + { + if (value as GameObject == oldGameObject) + value = newGameObject; + } + field.SetValue (newObj, value); + } + return newObj; + } + + public virtual void Fail ( AssertionComponent assertion ) + { + Debug.LogException (new AssertionException (assertion), assertion.GetFailureReferenceObject()); + } + + public virtual string GetFailureMessage () + { + return GetType ().Name + " assertion failed.\n(" + go + ")." + thisPropertyPath + " failed. Value: " + objVal; + } + + + } + + public abstract class ActionBaseGeneric : ActionBase + { + protected override bool Compare(object objVal) + { + return Compare ((T) objVal); + } + protected abstract bool Compare(T objVal); + + public override Type[] GetAccepatbleTypesForA() + { + return new[] { typeof(T) }; + } + + public override Type GetParameterType () + { + return typeof(T); + } + protected override bool UseCache { get { return true; } } + } +} diff --git a/src/Assets/UnityTestTools/Assertions/Comparers/ActionBase.cs.meta b/src/Assets/UnityTestTools/Assertions/Comparers/ActionBase.cs.meta new file mode 100644 index 0000000..6d4c3ab --- /dev/null +++ b/src/Assets/UnityTestTools/Assertions/Comparers/ActionBase.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b4995756bd539804e8143ff1e730f806 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/UnityTestTools/Assertions/Comparers/BoolComparer.cs b/src/Assets/UnityTestTools/Assertions/Comparers/BoolComparer.cs new file mode 100644 index 0000000..72c079e --- /dev/null +++ b/src/Assets/UnityTestTools/Assertions/Comparers/BoolComparer.cs @@ -0,0 +1,10 @@ +namespace UnityTest +{ + public class BoolComparer : ComparerBaseGeneric + { + protected override bool Compare (bool a, bool b) + { + return a == b; + } + } +} diff --git a/src/Assets/UnityTestTools/Assertions/Comparers/BoolComparer.cs.meta b/src/Assets/UnityTestTools/Assertions/Comparers/BoolComparer.cs.meta new file mode 100644 index 0000000..7ee21b6 --- /dev/null +++ b/src/Assets/UnityTestTools/Assertions/Comparers/BoolComparer.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 2586c8e41f35d2f4fadde53020bf4207 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/UnityTestTools/Assertions/Comparers/ColliderComparer.cs b/src/Assets/UnityTestTools/Assertions/Comparers/ColliderComparer.cs new file mode 100644 index 0000000..d0d18f3 --- /dev/null +++ b/src/Assets/UnityTestTools/Assertions/Comparers/ColliderComparer.cs @@ -0,0 +1,28 @@ +using System; +using UnityEngine; + +namespace UnityTest +{ + public class ColliderComparer : ComparerBaseGeneric + { + public enum CompareType + { + Intersects, + DoesNotIntersect + }; + + public CompareType compareType; + + protected override bool Compare(Bounds a, Bounds b) + { + switch (compareType) + { + case CompareType.Intersects: + return a.Intersects(b); + case CompareType.DoesNotIntersect: + return !a.Intersects(b); + } + throw new Exception(); + } + } +} diff --git a/src/Assets/UnityTestTools/Assertions/Comparers/ColliderComparer.cs.meta b/src/Assets/UnityTestTools/Assertions/Comparers/ColliderComparer.cs.meta new file mode 100644 index 0000000..ab3aa47 --- /dev/null +++ b/src/Assets/UnityTestTools/Assertions/Comparers/ColliderComparer.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 4eff45b2ac4067b469d7994298341db6 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/UnityTestTools/Assertions/Comparers/ComparerBase.cs b/src/Assets/UnityTestTools/Assertions/Comparers/ComparerBase.cs new file mode 100644 index 0000000..ae803ec --- /dev/null +++ b/src/Assets/UnityTestTools/Assertions/Comparers/ComparerBase.cs @@ -0,0 +1,144 @@ +using System; +using UnityEngine; +using Object = System.Object; + +namespace UnityTest +{ + public abstract class ComparerBase : ActionBase + { + public enum CompareToType + { + CompareToObject, + CompareToConstantValue, + CompareToNull + } + + public CompareToType compareToType = CompareToType.CompareToObject; + + public GameObject other; + protected object objOtherVal; + public string otherPropertyPath = ""; + private MemberResolver memberResolverB; + + protected abstract bool Compare (object a, object b); + + protected override bool Compare(object objVal) + { + if (compareToType == CompareToType.CompareToConstantValue) + { + objOtherVal = ConstValue; + } + else if (compareToType == CompareToType.CompareToNull) + { + objOtherVal = null; + } + else + { + if (other == null) + objOtherVal = null; + else + { + if (memberResolverB == null) + memberResolverB = new MemberResolver (other, otherPropertyPath); + objOtherVal = memberResolverB.GetValue (UseCache); + } + } + return Compare (objVal, objOtherVal); + } + + public virtual Type[] GetAccepatbleTypesForB() + { + return null; + } + + #region Const value + + public virtual object ConstValue { get; set; } + public virtual object GetDefaultConstValue() + { + throw new NotImplementedException(); + } + + #endregion + + public override string GetFailureMessage () + { + var message = GetType ().Name + " assertion failed.\n" + go.name + "." + thisPropertyPath + " " + compareToType; + switch (compareToType) + { + case ComparerBase.CompareToType.CompareToObject: + message += " (" + other + ")." + otherPropertyPath + " failed."; + break; + case ComparerBase.CompareToType.CompareToConstantValue: + message += " " + ConstValue + " failed."; + break; + case ComparerBase.CompareToType.CompareToNull: + message += " failed."; + break; + } + message += " Expected: " + objOtherVal + " Actual: " + objVal; + return message; + } + } + + [Serializable] + public abstract class ComparerBaseGeneric : ComparerBaseGeneric + { + } + + [Serializable] + public abstract class ComparerBaseGeneric : ComparerBase + { + public T2 constantValueGeneric = default(T2); + + public override Object ConstValue + { + get + { + return constantValueGeneric; + } + set + { + constantValueGeneric = (T2) value; + } + } + + public override Object GetDefaultConstValue() + { + return default(T2); + } + + static bool IsValueType (Type type) + { +#if !UNITY_METRO + return type.IsValueType; +#else + return false; +#endif + } + + protected override bool Compare(object a, object b) + { + var type = typeof(T2); + if (b == null && IsValueType (type)) + { + throw new ArgumentException("Null was passed to a value-type argument"); + } + return Compare((T1)a, (T2)b); + } + + protected abstract bool Compare(T1 a, T2 b); + + public override Type[] GetAccepatbleTypesForA() + { + return new[] { typeof(T1) }; + } + + public override Type[] GetAccepatbleTypesForB () + { + return new[] {typeof (T2)}; + } + + protected override bool UseCache { get { return true; } } + } +} diff --git a/src/Assets/UnityTestTools/Assertions/Comparers/ComparerBase.cs.meta b/src/Assets/UnityTestTools/Assertions/Comparers/ComparerBase.cs.meta new file mode 100644 index 0000000..65909eb --- /dev/null +++ b/src/Assets/UnityTestTools/Assertions/Comparers/ComparerBase.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: c86508f389d643b40b6e1d7dcc1d4df2 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/UnityTestTools/Assertions/Comparers/FloatComparer.cs b/src/Assets/UnityTestTools/Assertions/Comparers/FloatComparer.cs new file mode 100644 index 0000000..e4a98b2 --- /dev/null +++ b/src/Assets/UnityTestTools/Assertions/Comparers/FloatComparer.cs @@ -0,0 +1,38 @@ +using System; + +namespace UnityTest +{ + public class FloatComparer : ComparerBaseGeneric + { + public enum CompareTypes + { + Equal, + NotEqual, + Greater, + Less + } + + public CompareTypes compareTypes; + public double floatingPointError = 0.0001f; + + protected override bool Compare (float a, float b) + { + switch (compareTypes) + { + case CompareTypes.Equal: + return Math.Abs (a - b) < floatingPointError; + case CompareTypes.NotEqual: + return Math.Abs (a - b) > floatingPointError; + case CompareTypes.Greater: + return a > b; + case CompareTypes.Less: + return a < b; + } + throw new Exception(); + } + public override int GetDepthOfSearch() + { + return 3; + } + } +} diff --git a/src/Assets/UnityTestTools/Assertions/Comparers/FloatComparer.cs.meta b/src/Assets/UnityTestTools/Assertions/Comparers/FloatComparer.cs.meta new file mode 100644 index 0000000..07353ad --- /dev/null +++ b/src/Assets/UnityTestTools/Assertions/Comparers/FloatComparer.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: a4928c6c2b973874c8d4e6c9a69bb5b4 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/UnityTestTools/Assertions/Comparers/GeneralComparer.cs b/src/Assets/UnityTestTools/Assertions/Comparers/GeneralComparer.cs new file mode 100644 index 0000000..a336a3f --- /dev/null +++ b/src/Assets/UnityTestTools/Assertions/Comparers/GeneralComparer.cs @@ -0,0 +1,20 @@ +using System; + +namespace UnityTest +{ + public class GeneralComparer : ComparerBase + { + public enum CompareType { AEqualsB, ANotEqualsB } + + public CompareType compareType; + + protected override bool Compare (object a, object b) + { + if(compareType == CompareType.AEqualsB) + return a.Equals (b); + if (compareType == CompareType.ANotEqualsB) + return !a.Equals(b); + throw new Exception(); + } + } +} diff --git a/src/Assets/UnityTestTools/Assertions/Comparers/GeneralComparer.cs.meta b/src/Assets/UnityTestTools/Assertions/Comparers/GeneralComparer.cs.meta new file mode 100644 index 0000000..6b7edb3 --- /dev/null +++ b/src/Assets/UnityTestTools/Assertions/Comparers/GeneralComparer.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 902961c69f102f4409c29b9e54258701 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/UnityTestTools/Assertions/Comparers/IntComparer.cs b/src/Assets/UnityTestTools/Assertions/Comparers/IntComparer.cs new file mode 100644 index 0000000..003601b --- /dev/null +++ b/src/Assets/UnityTestTools/Assertions/Comparers/IntComparer.cs @@ -0,0 +1,39 @@ +using System; + +namespace UnityTest +{ + public class IntComparer : ComparerBaseGeneric + { + public enum CompareType + { + Equal, + NotEqual, + Greater, + GreaterOrEqual, + Less, + LessOrEqual + }; + + public CompareType compareType; + + protected override bool Compare (int a, int b) + { + switch (compareType) + { + case CompareType.Equal: + return a == b; + case CompareType.NotEqual: + return a != b; + case CompareType.Greater: + return a > b; + case CompareType.GreaterOrEqual: + return a >= b; + case CompareType.Less: + return a < b; + case CompareType.LessOrEqual: + return a <= b; + } + throw new Exception (); + } + } +} diff --git a/src/Assets/UnityTestTools/Assertions/Comparers/IntComparer.cs.meta b/src/Assets/UnityTestTools/Assertions/Comparers/IntComparer.cs.meta new file mode 100644 index 0000000..64f4fc3 --- /dev/null +++ b/src/Assets/UnityTestTools/Assertions/Comparers/IntComparer.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: da4a3a521c5c1494aae123742ca5c8f5 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/UnityTestTools/Assertions/Comparers/IsRenderedByCamera.cs b/src/Assets/UnityTestTools/Assertions/Comparers/IsRenderedByCamera.cs new file mode 100644 index 0000000..01a4eaf --- /dev/null +++ b/src/Assets/UnityTestTools/Assertions/Comparers/IsRenderedByCamera.cs @@ -0,0 +1,30 @@ +using System; +using UnityEngine; + +namespace UnityTest +{ + public class IsRenderedByCamera : ComparerBaseGeneric + { + public enum CompareType + { + IsVisible, + IsNotVisible, + }; + + public CompareType compareType; + + protected override bool Compare(Renderer renderer, Camera camera) + { + var planes = GeometryUtility.CalculateFrustumPlanes(camera); + var isVisible = GeometryUtility.TestPlanesAABB(planes, renderer.bounds); + switch (compareType) + { + case CompareType.IsVisible: + return isVisible; + case CompareType.IsNotVisible: + return !isVisible; + } + throw new Exception(); + } + } +} diff --git a/src/Assets/UnityTestTools/Assertions/Comparers/IsRenderedByCamera.cs.meta b/src/Assets/UnityTestTools/Assertions/Comparers/IsRenderedByCamera.cs.meta new file mode 100644 index 0000000..9cfc1f2 --- /dev/null +++ b/src/Assets/UnityTestTools/Assertions/Comparers/IsRenderedByCamera.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 8d45a1674f5e2e04485eafef922fac41 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/UnityTestTools/Assertions/Comparers/StringComparer.cs b/src/Assets/UnityTestTools/Assertions/Comparers/StringComparer.cs new file mode 100644 index 0000000..c337f84 --- /dev/null +++ b/src/Assets/UnityTestTools/Assertions/Comparers/StringComparer.cs @@ -0,0 +1,40 @@ +using System; + +namespace UnityTest +{ + public class StringComparer : ComparerBaseGeneric + { + public enum CompareType + { + Equal, + NotEqual, + Shorter, + Longer + } + + public CompareType compareType; + public StringComparison comparisonType = StringComparison.Ordinal; + public bool ignoreCase = false; + + protected override bool Compare (string a, string b) + { + if (ignoreCase) + { + a = a.ToLower (); + b = b.ToLower (); + } + switch (compareType) + { + case CompareType.Equal: + return String.Compare(a, b, comparisonType) == 0; + case CompareType.NotEqual: + return String.Compare(a, b, comparisonType) != 0; + case CompareType.Longer: + return String.Compare(a, b, comparisonType) > 0; + case CompareType.Shorter: + return String.Compare(a, b, comparisonType) < 0; + } + throw new Exception (); + } + } +} diff --git a/src/Assets/UnityTestTools/Assertions/Comparers/StringComparer.cs.meta b/src/Assets/UnityTestTools/Assertions/Comparers/StringComparer.cs.meta new file mode 100644 index 0000000..a414f61 --- /dev/null +++ b/src/Assets/UnityTestTools/Assertions/Comparers/StringComparer.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 58783f051e477fd4e93b42ec7a43bb64 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/UnityTestTools/Assertions/Comparers/TransformComparer.cs b/src/Assets/UnityTestTools/Assertions/Comparers/TransformComparer.cs new file mode 100644 index 0000000..2ba11fb --- /dev/null +++ b/src/Assets/UnityTestTools/Assertions/Comparers/TransformComparer.cs @@ -0,0 +1,25 @@ +using System; +using UnityEngine; + +namespace UnityTest +{ + public class TransformComparer : ComparerBaseGeneric + { + public enum CompareType{ Equals, NotEquals } + + public CompareType compareType; + + protected override bool Compare (Transform a, Transform b) + { + if (compareType == CompareType.Equals) + { + return a.position == b.position; + } + if (compareType == CompareType.NotEquals) + { + return a.position != b.position; + } + throw new Exception(); + } + } +} diff --git a/src/Assets/UnityTestTools/Assertions/Comparers/TransformComparer.cs.meta b/src/Assets/UnityTestTools/Assertions/Comparers/TransformComparer.cs.meta new file mode 100644 index 0000000..f3d72e4 --- /dev/null +++ b/src/Assets/UnityTestTools/Assertions/Comparers/TransformComparer.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 927f2d7e4f63632448b2a63d480e601a +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/UnityTestTools/Assertions/Comparers/ValueDoesNotChange.cs b/src/Assets/UnityTestTools/Assertions/Comparers/ValueDoesNotChange.cs new file mode 100644 index 0000000..00835b1 --- /dev/null +++ b/src/Assets/UnityTestTools/Assertions/Comparers/ValueDoesNotChange.cs @@ -0,0 +1,16 @@ +namespace UnityTest +{ + public class ValueDoesNotChange : ActionBase + { + private object val = null; + + protected override bool Compare (object a) + { + if (val == null) + val = a; + if (!val.Equals (a)) + return false; + return true; + } + } +} diff --git a/src/Assets/UnityTestTools/Assertions/Comparers/ValueDoesNotChange.cs.meta b/src/Assets/UnityTestTools/Assertions/Comparers/ValueDoesNotChange.cs.meta new file mode 100644 index 0000000..b913d35 --- /dev/null +++ b/src/Assets/UnityTestTools/Assertions/Comparers/ValueDoesNotChange.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 9d6d16a58a17940419a1dcbff3c60ca5 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/UnityTestTools/Assertions/Comparers/Vector2Comparer.cs b/src/Assets/UnityTestTools/Assertions/Comparers/Vector2Comparer.cs new file mode 100644 index 0000000..cd88f8a --- /dev/null +++ b/src/Assets/UnityTestTools/Assertions/Comparers/Vector2Comparer.cs @@ -0,0 +1,35 @@ +using System; +using UnityEngine; + +namespace UnityTest +{ + public class Vector2Comparer : VectorComparerBase + { + public enum CompareType + { + MagnitudeEquals, + MagnitudeNotEquals + } + + public CompareType compareType; + public float floatingPointError = 0.0001f; + + protected override bool Compare(Vector2 a, Vector2 b) + { + switch (compareType) + { + case CompareType.MagnitudeEquals: + return AreVectorMagnitudeEqual(a.magnitude, + b.magnitude, floatingPointError); + case CompareType.MagnitudeNotEquals: + return !AreVectorMagnitudeEqual(a.magnitude, + b.magnitude, floatingPointError); + } + throw new Exception(); + } + public override int GetDepthOfSearch() + { + return 3; + } + } +} diff --git a/src/Assets/UnityTestTools/Assertions/Comparers/Vector2Comparer.cs.meta b/src/Assets/UnityTestTools/Assertions/Comparers/Vector2Comparer.cs.meta new file mode 100644 index 0000000..19ef5d2 --- /dev/null +++ b/src/Assets/UnityTestTools/Assertions/Comparers/Vector2Comparer.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: a713db190443e814f8254a5a59014ec4 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/UnityTestTools/Assertions/Comparers/Vector3Comparer.cs b/src/Assets/UnityTestTools/Assertions/Comparers/Vector3Comparer.cs new file mode 100644 index 0000000..3a9ff2e --- /dev/null +++ b/src/Assets/UnityTestTools/Assertions/Comparers/Vector3Comparer.cs @@ -0,0 +1,31 @@ +using System; +using UnityEngine; + +namespace UnityTest +{ + public class Vector3Comparer : VectorComparerBase + { + public enum CompareType + { + MagnitudeEquals, + MagnitudeNotEquals + } + + public CompareType compareType; + public double floatingPointError = 0.0001f; + + protected override bool Compare (Vector3 a, Vector3 b) + { + switch (compareType) + { + case CompareType.MagnitudeEquals: + return AreVectorMagnitudeEqual (a.magnitude, + b.magnitude, floatingPointError); + case CompareType.MagnitudeNotEquals: + return !AreVectorMagnitudeEqual (a.magnitude, + b.magnitude, floatingPointError); + } + throw new Exception (); + } + } +} diff --git a/src/Assets/UnityTestTools/Assertions/Comparers/Vector3Comparer.cs.meta b/src/Assets/UnityTestTools/Assertions/Comparers/Vector3Comparer.cs.meta new file mode 100644 index 0000000..b871f24 --- /dev/null +++ b/src/Assets/UnityTestTools/Assertions/Comparers/Vector3Comparer.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 6febd2d5046657040b3da98b7010ee29 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/UnityTestTools/Assertions/Comparers/Vector4Comparer.cs b/src/Assets/UnityTestTools/Assertions/Comparers/Vector4Comparer.cs new file mode 100644 index 0000000..128e98c --- /dev/null +++ b/src/Assets/UnityTestTools/Assertions/Comparers/Vector4Comparer.cs @@ -0,0 +1,37 @@ +using System; +using UnityEngine; + +namespace UnityTest +{ + public class Vector4Comparer : VectorComparerBase + { + public enum CompareType + { + MagnitudeEquals, + MagnitudeNotEquals + } + + public CompareType compareType; + public double floatingPointError; + + protected override bool Compare (Vector4 a, Vector4 b) + { + switch (compareType) + { + case CompareType.MagnitudeEquals: + return AreVectorMagnitudeEqual (a.magnitude, + b.magnitude, + floatingPointError); + case CompareType.MagnitudeNotEquals: + return !AreVectorMagnitudeEqual (a.magnitude, + b.magnitude, + floatingPointError); + } + throw new Exception(); + } + public override int GetDepthOfSearch() + { + return 3; + } + } +} diff --git a/src/Assets/UnityTestTools/Assertions/Comparers/Vector4Comparer.cs.meta b/src/Assets/UnityTestTools/Assertions/Comparers/Vector4Comparer.cs.meta new file mode 100644 index 0000000..1e0314f --- /dev/null +++ b/src/Assets/UnityTestTools/Assertions/Comparers/Vector4Comparer.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 383a85a79f164d04b8a56b0ff4e04cb7 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/UnityTestTools/Assertions/Comparers/VectorComparerBase.cs b/src/Assets/UnityTestTools/Assertions/Comparers/VectorComparerBase.cs new file mode 100644 index 0000000..acf5108 --- /dev/null +++ b/src/Assets/UnityTestTools/Assertions/Comparers/VectorComparerBase.cs @@ -0,0 +1,16 @@ +using System; + +namespace UnityTest +{ + public abstract class VectorComparerBase : ComparerBaseGeneric + { + protected bool AreVectorMagnitudeEqual (float a, float b, double floatingPointError) + { + if (Math.Abs (a) < floatingPointError && Math.Abs (b) < floatingPointError) + return true; + if (Math.Abs (a - b) < floatingPointError) + return true; + return false; + } + } +} diff --git a/src/Assets/UnityTestTools/Assertions/Comparers/VectorComparerBase.cs.meta b/src/Assets/UnityTestTools/Assertions/Comparers/VectorComparerBase.cs.meta new file mode 100644 index 0000000..d4da9f7 --- /dev/null +++ b/src/Assets/UnityTestTools/Assertions/Comparers/VectorComparerBase.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 7b35a237804d5eb42bd8c4e67568ae24 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/UnityTestTools/Assertions/Editor.meta b/src/Assets/UnityTestTools/Assertions/Editor.meta new file mode 100644 index 0000000..2fa5238 --- /dev/null +++ b/src/Assets/UnityTestTools/Assertions/Editor.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: a28bb39b4fb20514990895d9cb4eaea9 +folderAsset: yes +DefaultImporter: + userData: diff --git a/src/Assets/UnityTestTools/Assertions/Editor/AssertionComponentEditor.cs b/src/Assets/UnityTestTools/Assertions/Editor/AssertionComponentEditor.cs new file mode 100644 index 0000000..1860f7b --- /dev/null +++ b/src/Assets/UnityTestTools/Assertions/Editor/AssertionComponentEditor.cs @@ -0,0 +1,217 @@ +using System; +using System.Linq; +using System.Reflection; +using UnityEditor; +using UnityEngine; + +namespace UnityTest +{ + [CustomEditor (typeof (AssertionComponent))] + public class AssertionComponentEditor : Editor + { + private readonly DropDownControl comparerDropDown = new DropDownControl(); + + private readonly PropertyPathSelector thisPathSelector = new PropertyPathSelector ("Compare"); + private readonly PropertyPathSelector otherPathSelector = new PropertyPathSelector("Compare to"); + + private bool focusBackToEdit; + + #region GUI Contents + private readonly GUIContent guiCheckAfterTimeGuiContent = new GUIContent ("Check after (seconds)", "After how many seconds the assertion should be checked"); + private readonly GUIContent guiRepeatCheckTimeGuiContent = new GUIContent ("Repeat check", "Should the check be repeated."); + private readonly GUIContent guiRepeatEveryTimeGuiContent = new GUIContent ("Frequency of repetitions", "How often should the check be done"); + private readonly GUIContent guiCheckAfterFramesGuiContent = new GUIContent ("Check after (frames)", "After how many frames the assertion should be checked"); + private readonly GUIContent guiRepeatCheckFrameGuiContent = new GUIContent ("Repeat check", "Should the check be repeated."); + #endregion + + public AssertionComponentEditor() + { + comparerDropDown.convertForButtonLabel = type => type.Name; + comparerDropDown.convertForGUIContent = type => type.Name; + comparerDropDown.ignoreConvertForGUIContent = types => false; + comparerDropDown.tooltip = "Comparer that will be used to compare values and determine the result of assertion."; + + } + + public override void OnInspectorGUI () + { + var script = (AssertionComponent) target; + EditorGUILayout.BeginHorizontal (); + var obj = DrawComparerSelection (script); + script.checkMethods = (CheckMethod)EditorGUILayout.EnumMaskField (script.checkMethods, + EditorStyles.popup, + GUILayout.ExpandWidth (false)); + EditorGUILayout.EndHorizontal (); + + if(script.IsCheckMethodSelected (CheckMethod.AfterPeriodOfTime)) + { + DrawOptionsForAfterPeriodOfTime (script); + } + + if (script.IsCheckMethodSelected(CheckMethod.Update)) + { + DrawOptionsForOnUpdate (script); + } + + if (obj) + { + EditorGUILayout.Space (); + + thisPathSelector.Draw(script.Action.go, script.Action, + script.Action.thisPropertyPath, script.Action.GetAccepatbleTypesForA (), + go => + { + script.Action.go = go; + AssertionExplorerWindow.Reload(); + }, + s => + { + script.Action.thisPropertyPath = s; + AssertionExplorerWindow.Reload(); + }); + + EditorGUILayout.Space (); + + DrawCustomFields (script); + + EditorGUILayout.Space (); + + if (script.Action is ComparerBase) + { + DrawCompareToType (script.Action as ComparerBase); + } + } + } + + private void DrawOptionsForAfterPeriodOfTime (AssertionComponent script) + { + EditorGUILayout.Space (); + script.checkAfterTime = EditorGUILayout.FloatField (guiCheckAfterTimeGuiContent, + script.checkAfterTime); + if (script.checkAfterTime < 0) + script.checkAfterTime = 0; + script.repeatCheckTime = EditorGUILayout.Toggle (guiRepeatCheckTimeGuiContent, + script.repeatCheckTime); + if (script.repeatCheckTime) + { + script.repeatEveryTime = EditorGUILayout.FloatField (guiRepeatEveryTimeGuiContent, + script.repeatEveryTime); + if (script.repeatEveryTime < 0) + script.repeatEveryTime = 0; + } + } + + private void DrawOptionsForOnUpdate (AssertionComponent script) + { + EditorGUILayout.Space (); + script.checkAfterFrames = EditorGUILayout.IntField (guiCheckAfterFramesGuiContent, + script.checkAfterFrames); + if (script.checkAfterFrames < 1) + script.checkAfterFrames = 1; + script.repeatCheckFrame = EditorGUILayout.Toggle (guiRepeatCheckFrameGuiContent, + script.repeatCheckFrame); + if (script.repeatCheckFrame) + { + script.repeatEveryFrame = EditorGUILayout.IntField (guiRepeatEveryTimeGuiContent, + script.repeatEveryFrame); + if (script.repeatEveryFrame < 1) + script.repeatEveryFrame = 1; + } + } + + private void DrawCompareToType (ComparerBase comparer) + { + comparer.compareToType = (ComparerBase.CompareToType) EditorGUILayout.EnumPopup ("Compare to type", + comparer.compareToType, + EditorStyles.popup); + + if (comparer.compareToType == ComparerBase.CompareToType.CompareToConstantValue) + { + try + { + DrawConstCompareField(comparer); + } + catch (NotImplementedException) + { + Debug.LogWarning("This comparer can't compare to static value"); + comparer.compareToType = ComparerBase.CompareToType.CompareToObject; + } + } + else if (comparer.compareToType == ComparerBase.CompareToType.CompareToObject) + { + DrawObjectCompareField(comparer); + } + } + + private void DrawObjectCompareField(ComparerBase comparer) + { + otherPathSelector.Draw(comparer.other, comparer, + comparer.otherPropertyPath, comparer.GetAccepatbleTypesForB(), + go => + { + comparer.other = go; + AssertionExplorerWindow.Reload (); + }, + s => + { + comparer.otherPropertyPath = s; + AssertionExplorerWindow.Reload (); + } + ); + } + + private void DrawConstCompareField(ComparerBase comparer) + { + if (comparer.ConstValue == null) + { + comparer.ConstValue = comparer.GetDefaultConstValue(); + } + + var so = new SerializedObject(comparer); + var sp = so.FindProperty ("constantValueGeneric"); + if (sp != null) + { + EditorGUILayout.PropertyField (sp, new GUIContent("Constant"), true); + so.ApplyModifiedProperties (); + } + } + + private bool DrawComparerSelection (AssertionComponent script) + { + var types = typeof(ActionBase).Assembly.GetTypes(); + var allComparers = types.Where(type => type.IsSubclassOf(typeof(ActionBase)) && !type.IsAbstract).ToArray(); + + if (script.Action == null) + script.Action = (ActionBase)CreateInstance(allComparers.First()); + + comparerDropDown.Draw(script.Action.GetType (), allComparers, + type => + { + if (script.Action == null || script.Action.GetType().Name != type.Name) + { + script.Action = (ActionBase)CreateInstance(type); + AssertionExplorerWindow.Reload (); + } + }); + + return script.Action != null; + } + + private void DrawCustomFields (AssertionComponent script) + { + foreach (var prop in script.Action.GetType ().GetFields (BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly)) + { + var type = prop.FieldType; + if (!type.IsSerializable) + continue; + var so = new SerializedObject(script.Action); + var sp = so.FindProperty(prop.Name); + if (sp != null) + { + EditorGUILayout.PropertyField (sp); + so.ApplyModifiedProperties (); + } + } + } + } +} diff --git a/src/Assets/UnityTestTools/Assertions/Editor/AssertionComponentEditor.cs.meta b/src/Assets/UnityTestTools/Assertions/Editor/AssertionComponentEditor.cs.meta new file mode 100644 index 0000000..eb4174d --- /dev/null +++ b/src/Assets/UnityTestTools/Assertions/Editor/AssertionComponentEditor.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: fd1cabf2c45d0a8489635607a6048621 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/UnityTestTools/Assertions/Editor/AssertionExplorerWindow.cs b/src/Assets/UnityTestTools/Assertions/Editor/AssertionExplorerWindow.cs new file mode 100644 index 0000000..3cb2d71 --- /dev/null +++ b/src/Assets/UnityTestTools/Assertions/Editor/AssertionExplorerWindow.cs @@ -0,0 +1,192 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using UnityEditor; +using UnityEngine; + +namespace UnityTest +{ + [Serializable] + public class AssertionExplorerWindow : EditorWindow + { + private List allAssertions = new List (); + [SerializeField] + private string filterText = ""; + [SerializeField] + private FilterType filterType; + [SerializeField] + private readonly List foldMarkers = new List (); + [SerializeField] + private GroupByType groupBy; + [SerializeField] + private Vector2 scrollPosition = Vector2.zero; + private DateTime nextReload = DateTime.Now; + [SerializeField] + private static bool shouldReload; + [SerializeField] + private ShowType showType; + + public AssertionExplorerWindow () + { + title = "Assertion Explorer"; + } + + public void OnDidOpenScene () + { + ReloadAssertionList (); + } + + public void OnFocus () + { + ReloadAssertionList (); + } + + private void ReloadAssertionList () + { + nextReload = DateTime.Now.AddSeconds (1); + shouldReload = true; + } + + public void OnHierarchyChange () + { + ReloadAssertionList (); + } + + public void OnInspectorUpdate () + { + if (shouldReload && nextReload < DateTime.Now) + { + shouldReload = false; + allAssertions = new List (Resources.FindObjectsOfTypeAll (typeof (AssertionComponent)) as AssertionComponent[]); + Repaint (); + } + } + + public void OnGUI () + { + DrawMenuPanel (); + + scrollPosition = EditorGUILayout.BeginScrollView (scrollPosition); + if (allAssertions != null) + GetResultRendere ().Render (FilterResults (allAssertions, filterText.ToLower ()), foldMarkers); + EditorGUILayout.EndScrollView (); + } + + private IEnumerable FilterResults (List assertionComponents, string text) + { + if (showType == ShowType.ShowDisabled) + assertionComponents = assertionComponents.Where (c => !c.enabled).ToList (); + else if (showType == ShowType.ShowEnabled) + assertionComponents = assertionComponents.Where (c => c.enabled).ToList (); + + if (string.IsNullOrEmpty (text)) + return assertionComponents; + + switch (filterType) + { + case FilterType.ComparerName: + return assertionComponents.Where (c => c.Action.GetType ().Name.ToLower ().Contains (text)); + case FilterType.AttachedGameObject: + return assertionComponents.Where (c => c.gameObject.name.ToLower ().Contains (text)); + case FilterType.FirstComparedGameObjectPath: + return assertionComponents.Where (c => c.Action.thisPropertyPath.ToLower ().Contains (text)); + case FilterType.FirstComparedGameObject: + return assertionComponents.Where (c => c.Action.go != null + && c.Action.go.name.ToLower ().Contains (text)); + case FilterType.SecondComparedGameObjectPath: + return assertionComponents.Where (c => + c.Action is ComparerBase + && (c.Action as ComparerBase).otherPropertyPath.ToLower ().Contains (text)); + case FilterType.SecondComparedGameObject: + return assertionComponents.Where (c => + c.Action is ComparerBase + && (c.Action as ComparerBase).other != null + && (c.Action as ComparerBase).other.name.ToLower ().Contains (text)); + default: + return assertionComponents; + } + } + + private readonly IListRenderer groupByComparerRenderer = new GroupByComparerRenderer (); + private readonly IListRenderer groupByExecutionMethodRenderer = new GroupByExecutionMethodRenderer (); + private readonly IListRenderer groupByGORenderer = new GroupByGORenderer (); + private readonly IListRenderer groupByTestsRenderer = new GroupByTestsRenderer (); + private readonly IListRenderer groupByNothingRenderer = new GroupByNothingRenderer (); + + private IListRenderer GetResultRendere () + { + switch (groupBy) + { + case GroupByType.Comparer: + return groupByComparerRenderer; + case GroupByType.ExecutionMethod: + return groupByExecutionMethodRenderer; + case GroupByType.GameObjects: + return groupByGORenderer; + case GroupByType.Tests: + return groupByTestsRenderer; + case GroupByType.Nothing: + default: + return groupByNothingRenderer; + } + } + + private void DrawMenuPanel () + { + EditorGUILayout.BeginHorizontal (); + EditorGUILayout.LabelField ("Group by", GUILayout.MaxWidth (60)); + groupBy = (GroupByType) EditorGUILayout.EnumPopup (groupBy, GUILayout.MaxWidth (150)); + + GUILayout.FlexibleSpace (); + + showType = (ShowType) EditorGUILayout.EnumPopup (showType, GUILayout.MaxWidth (100)); + + EditorGUILayout.LabelField ("Filter by", GUILayout.MaxWidth (50)); + filterType = (FilterType) EditorGUILayout.EnumPopup (filterType, GUILayout.MaxWidth (100)); + filterText = EditorGUILayout.TextField (filterText, GUILayout.MaxWidth (100)); + if (GUILayout.Button ("clear", GUILayout.ExpandWidth (false))) + filterText = ""; + EditorGUILayout.EndHorizontal (); + } + + [MenuItem ("Unity Test Tools/Assertion Explorer")] + public static AssertionExplorerWindow ShowWindow () + { + var w = GetWindow (typeof (AssertionExplorerWindow)); + w.Show (); + return w as AssertionExplorerWindow; + } + + private enum FilterType + { + ComparerName, + FirstComparedGameObject, + FirstComparedGameObjectPath, + SecondComparedGameObject, + SecondComparedGameObjectPath, + AttachedGameObject + } + + private enum ShowType + { + ShowAll, + ShowEnabled, + ShowDisabled + } + + private enum GroupByType + { + Nothing, + Comparer, + GameObjects, + ExecutionMethod, + Tests + + } + + public static void Reload () + { + shouldReload = true; + } + } +} diff --git a/src/Assets/UnityTestTools/Assertions/Editor/AssertionExplorerWindow.cs.meta b/src/Assets/UnityTestTools/Assertions/Editor/AssertionExplorerWindow.cs.meta new file mode 100644 index 0000000..f5591ab --- /dev/null +++ b/src/Assets/UnityTestTools/Assertions/Editor/AssertionExplorerWindow.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 1a1e855053e7e2f46ace1dc93f2036f2 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/UnityTestTools/Assertions/Editor/AssertionListRenderer.cs b/src/Assets/UnityTestTools/Assertions/Editor/AssertionListRenderer.cs new file mode 100644 index 0000000..d962b28 --- /dev/null +++ b/src/Assets/UnityTestTools/Assertions/Editor/AssertionListRenderer.cs @@ -0,0 +1,255 @@ +using System.Collections.Generic; +using System.Linq; +using UnityEditor; +using UnityEngine; + +namespace UnityTest +{ + public interface IListRenderer + { + void Render (IEnumerable allAssertions, List foldMarkers); + } + + public abstract class AssertionListRenderer : IListRenderer + { + private static class Styles + { + public static readonly GUIStyle redLabel; + static Styles () + { + redLabel = new GUIStyle (EditorStyles.label); + redLabel.normal.textColor = Color.red; + } + } + + public void Render ( IEnumerable allAssertions, List foldMarkers ) + { + foreach (var grouping in GroupResult (allAssertions)) + { + var key = GetStringKey (grouping.Key); + bool isFolded = foldMarkers.Contains (key); + if (key != "") + { + EditorGUILayout.BeginHorizontal (); + + EditorGUI.BeginChangeCheck (); + isFolded = PrintFoldout (isFolded, + grouping.Key); + if (EditorGUI.EndChangeCheck ()) + { + if (isFolded) + foldMarkers.Add (key); + else + foldMarkers.Remove (key); + } + EditorGUILayout.EndHorizontal (); + if (isFolded) + continue; + } + foreach (var assertionComponent in grouping) + { + EditorGUILayout.BeginVertical (); + EditorGUILayout.BeginHorizontal (); + + if (key != "") + GUILayout.Space (15); + + var assertionKey = assertionComponent.GetHashCode ().ToString (); + bool isDetailsFolded = foldMarkers.Contains (assertionKey); + + EditorGUI.BeginChangeCheck (); + if (GUILayout.Button ("", + EditorStyles.foldout, + GUILayout.Width (15))) + { + isDetailsFolded = !isDetailsFolded; + } + if (EditorGUI.EndChangeCheck ()) + { + if (isDetailsFolded) + foldMarkers.Add (assertionKey); + else + foldMarkers.Remove (assertionKey); + } + PrintFoldedAssertionLine (assertionComponent); + EditorGUILayout.EndHorizontal (); + + if (isDetailsFolded) + { + + EditorGUILayout.BeginHorizontal (); + if (key != "") + GUILayout.Space (15); + PrintAssertionLineDetails (assertionComponent); + EditorGUILayout.EndHorizontal (); + + } + GUILayout.Box ("", new [] {GUILayout.ExpandWidth (true), GUILayout.Height (1)}); + + EditorGUILayout.EndVertical (); + } + } + } + + protected abstract IEnumerable> GroupResult (IEnumerable assertionComponents); + + protected virtual string GetStringKey (T key) + { + return key.GetHashCode ().ToString (); + } + + protected virtual bool PrintFoldout (bool isFolded, T key) + { + var content = new GUIContent (GetFoldoutDisplayName (key)); + var size = EditorStyles.foldout.CalcSize (content); + + var rect = GUILayoutUtility.GetRect (content, + EditorStyles.foldout, + GUILayout.MaxWidth (size.x)); + var res = EditorGUI.Foldout (rect, + !isFolded, + content, + true); + + return !res; + } + + protected virtual string GetFoldoutDisplayName (T key) + { + return key.ToString (); + } + + protected virtual void PrintFoldedAssertionLine (AssertionComponent assertionComponent) + { + EditorGUILayout.BeginHorizontal (); + + EditorGUILayout.BeginVertical (GUILayout.MaxWidth (300)); + EditorGUILayout.BeginHorizontal (GUILayout.MaxWidth (300)); + PrintPath (assertionComponent.Action.go, + assertionComponent.Action.thisPropertyPath); + EditorGUILayout.EndHorizontal (); + EditorGUILayout.EndVertical (); + + EditorGUILayout.BeginVertical (GUILayout.MaxWidth (250)); + var labelStr = assertionComponent.Action.GetType ().Name; + var labelStr2 = assertionComponent.Action.GetConfigurationDescription (); + if (labelStr2 != "") + labelStr += "( " + labelStr2 + ")"; + EditorGUILayout.LabelField (labelStr); + EditorGUILayout.EndVertical (); + + if (assertionComponent.Action is ComparerBase) + { + var comparer = assertionComponent.Action as ComparerBase; + + var otherStrVal = "(no value selected)"; + EditorGUILayout.BeginVertical (); + EditorGUILayout.BeginHorizontal (GUILayout.MaxWidth (300)); + switch (comparer.compareToType) + { + case ComparerBase.CompareToType.CompareToObject: + if (comparer.other != null) + { + PrintPath (comparer.other, + comparer.otherPropertyPath); + } + else + { + EditorGUILayout.LabelField (otherStrVal, + Styles.redLabel); + } + break; + case ComparerBase.CompareToType.CompareToConstantValue: + otherStrVal = comparer.ConstValue.ToString (); + EditorGUILayout.LabelField (otherStrVal); + break; + case ComparerBase.CompareToType.CompareToNull: + otherStrVal = "null"; + EditorGUILayout.LabelField (otherStrVal); + break; + } + EditorGUILayout.EndHorizontal (); + EditorGUILayout.EndVertical (); + } + else + { + EditorGUILayout.LabelField (""); + } + EditorGUILayout.EndHorizontal (); + EditorGUILayout.Space (); + } + + protected virtual void PrintAssertionLineDetails (AssertionComponent assertionComponent) + { + + EditorGUILayout.BeginHorizontal (); + + + EditorGUILayout.BeginVertical (GUILayout.MaxWidth (320)); + EditorGUILayout.BeginHorizontal (); + EditorGUILayout.LabelField ("Attached to", + GUILayout.Width (70)); + var sss = EditorStyles.objectField.CalcSize (new GUIContent (assertionComponent.gameObject.name)); + EditorGUILayout.ObjectField (assertionComponent.gameObject, + typeof (GameObject), + true, + GUILayout.Width (sss.x)); + EditorGUILayout.EndHorizontal (); + EditorGUILayout.EndVertical (); + + + EditorGUILayout.BeginVertical (GUILayout.MaxWidth (250)); + EditorGUILayout.EnumMaskField (assertionComponent.checkMethods, + EditorStyles.popup, + GUILayout.MaxWidth (150)); + EditorGUILayout.EndVertical (); + + + EditorGUILayout.BeginVertical (); + EditorGUILayout.BeginHorizontal (); + EditorGUILayout.LabelField ("Disabled", + GUILayout.Width (55)); + assertionComponent.enabled = !EditorGUILayout.Toggle (!assertionComponent.enabled, + GUILayout.Width (15)); + EditorGUILayout.EndHorizontal (); + EditorGUILayout.EndVertical (); + + EditorGUILayout.EndHorizontal (); + } + + private void PrintPath (GameObject go, string propertyPath) + { + string contentString = ""; + GUIStyle styleThisPath = EditorStyles.label; + if (go != null) + { + var sss = EditorStyles.objectField.CalcSize (new GUIContent (go.name)); + EditorGUILayout.ObjectField ( + go, + typeof (GameObject), + true, + GUILayout.Width (sss.x)); + + if (!string.IsNullOrEmpty (propertyPath)) + contentString = "." + propertyPath; + } + else + { + contentString = "(no value selected)"; + styleThisPath = Styles.redLabel; + } + + var content = new GUIContent (contentString, + contentString); + var rect = GUILayoutUtility.GetRect (content, + EditorStyles.label, + GUILayout.MaxWidth (200)); + + EditorGUI.LabelField (rect, + content, + styleThisPath); + } + + + } +} diff --git a/src/Assets/UnityTestTools/Assertions/Editor/AssertionListRenderer.cs.meta b/src/Assets/UnityTestTools/Assertions/Editor/AssertionListRenderer.cs.meta new file mode 100644 index 0000000..8e6a0d4 --- /dev/null +++ b/src/Assets/UnityTestTools/Assertions/Editor/AssertionListRenderer.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d83c02fb0f220344da42a8213ed36cb5 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/UnityTestTools/Assertions/Editor/AssertionStripper.cs b/src/Assets/UnityTestTools/Assertions/Editor/AssertionStripper.cs new file mode 100644 index 0000000..e6e53fb --- /dev/null +++ b/src/Assets/UnityTestTools/Assertions/Editor/AssertionStripper.cs @@ -0,0 +1,22 @@ +using UnityEditor.Callbacks; +using UnityEngine; +using UnityTest; + +public class AssertionStripper +{ + [PostProcessScene] + public static void OnPostprocessScene () + { + if (Debug.isDebugBuild) return; + RemoveAssertionsFromGameObjects (); + } + + private static void RemoveAssertionsFromGameObjects () + { + var allAssertions = Resources.FindObjectsOfTypeAll (typeof (AssertionComponent)) as AssertionComponent[]; + foreach (var assertion in allAssertions) + { + Object.DestroyImmediate (assertion); + } + } +} diff --git a/src/Assets/UnityTestTools/Assertions/Editor/AssertionStripper.cs.meta b/src/Assets/UnityTestTools/Assertions/Editor/AssertionStripper.cs.meta new file mode 100644 index 0000000..bf18bbe --- /dev/null +++ b/src/Assets/UnityTestTools/Assertions/Editor/AssertionStripper.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 95c9cd9570a6fba4198b6e4f15e11e5e +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/UnityTestTools/Assertions/Editor/DropDownControl.cs b/src/Assets/UnityTestTools/Assertions/Editor/DropDownControl.cs new file mode 100644 index 0000000..73b8035 --- /dev/null +++ b/src/Assets/UnityTestTools/Assertions/Editor/DropDownControl.cs @@ -0,0 +1,77 @@ +using System; +using UnityEditor; +using UnityEngine; + +namespace UnityTest +{ + [Serializable] + internal class DropDownControl + { + private GUILayoutOption[] buttonLayoutOptions = new [] { GUILayout.ExpandWidth (true) }; + public Func convertForButtonLabel = s => s.ToString (); + public Func convertForGUIContent = s => s.ToString (); + public Func ignoreConvertForGUIContent = t => t.Length <= 40; + public Action printContextMenu = null; + public string tooltip = ""; + + private object selectedValue; + + + public void Draw (T selected, T[] options, Action onValueSelected) + { + Draw (null, + selected, + options, + onValueSelected); + } + + public void Draw(string label, T selected, T[] options, Action onValueSelected) + { + Draw (label, selected, ()=>options, onValueSelected); + } + + public void Draw(string label, T selected, Func loadOptions, Action onValueSelected) + { + if (!string.IsNullOrEmpty (label)) + EditorGUILayout.BeginHorizontal (); + var guiContent = new GUIContent (label); + var labelSize = EditorStyles.label.CalcSize(guiContent); + + if (!string.IsNullOrEmpty(label)) + GUILayout.Label (label, EditorStyles.label, GUILayout.Width (labelSize.x)); + + if (GUILayout.Button(new GUIContent(convertForButtonLabel(selected), tooltip), + EditorStyles.popup, buttonLayoutOptions)) + { + if (Event.current.button == 0) + { + PrintMenu(loadOptions()); + } + else if (printContextMenu!=null && Event.current.button == 1) + printContextMenu (selected); + } + + if (selectedValue != null) + { + onValueSelected ((T) selectedValue); + selectedValue = null; + } + if (!string.IsNullOrEmpty (label)) + EditorGUILayout.EndHorizontal (); + } + + public void PrintMenu (T[] options) + { + var menu = new GenericMenu (); + foreach (var s in options) + { + var localS = s; + menu.AddItem(new GUIContent((ignoreConvertForGUIContent(options) ? localS.ToString() : convertForGUIContent(localS))), + false, + () => { selectedValue = localS;} + ); + } + menu.ShowAsContext (); + } + } +} diff --git a/src/Assets/UnityTestTools/Assertions/Editor/DropDownControl.cs.meta b/src/Assets/UnityTestTools/Assertions/Editor/DropDownControl.cs.meta new file mode 100644 index 0000000..424d243 --- /dev/null +++ b/src/Assets/UnityTestTools/Assertions/Editor/DropDownControl.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 83ec3ed09f8f2f34ea7483e055f6d76d +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/UnityTestTools/Assertions/Editor/GroupByComparerRenderer.cs b/src/Assets/UnityTestTools/Assertions/Editor/GroupByComparerRenderer.cs new file mode 100644 index 0000000..00487cb --- /dev/null +++ b/src/Assets/UnityTestTools/Assertions/Editor/GroupByComparerRenderer.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace UnityTest +{ + public class GroupByComparerRenderer : AssertionListRenderer + { + protected override IEnumerable> GroupResult (IEnumerable assertionComponents) + { + return assertionComponents.GroupBy (c => c.Action.GetType ()); + } + + protected override string GetStringKey (Type key) + { + return key.Name; + } + } +} diff --git a/src/Assets/UnityTestTools/Assertions/Editor/GroupByComparerRenderer.cs.meta b/src/Assets/UnityTestTools/Assertions/Editor/GroupByComparerRenderer.cs.meta new file mode 100644 index 0000000..e917399 --- /dev/null +++ b/src/Assets/UnityTestTools/Assertions/Editor/GroupByComparerRenderer.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: efab536803bd0154a8a7dc78e8767ad9 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/UnityTestTools/Assertions/Editor/GroupByExecutionMethodRenderer.cs b/src/Assets/UnityTestTools/Assertions/Editor/GroupByExecutionMethodRenderer.cs new file mode 100644 index 0000000..eb0440b --- /dev/null +++ b/src/Assets/UnityTestTools/Assertions/Editor/GroupByExecutionMethodRenderer.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace UnityTest +{ + public class GroupByExecutionMethodRenderer : AssertionListRenderer + { + protected override IEnumerable> GroupResult (IEnumerable assertionComponents) + { + var enumVals = Enum.GetValues (typeof (CheckMethod)).Cast (); + var pairs = new List (); + + foreach (var checkMethod in enumVals) + { + var components = assertionComponents.Where (c => (c.checkMethods & checkMethod) == checkMethod); + var componentPairs = components.Select ((a) => new CheckFunctionAssertionPair () {checkMethod = checkMethod, assertionComponent = a}); + pairs.AddRange (componentPairs); + } + return pairs.GroupBy (pair => pair.checkMethod, + pair => pair.assertionComponent); + } + + private class CheckFunctionAssertionPair + { + public AssertionComponent assertionComponent; + public CheckMethod checkMethod; + } + } +} diff --git a/src/Assets/UnityTestTools/Assertions/Editor/GroupByExecutionMethodRenderer.cs.meta b/src/Assets/UnityTestTools/Assertions/Editor/GroupByExecutionMethodRenderer.cs.meta new file mode 100644 index 0000000..e542ae1 --- /dev/null +++ b/src/Assets/UnityTestTools/Assertions/Editor/GroupByExecutionMethodRenderer.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 97340abf816b1424fa835a4f26bbdc78 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/UnityTestTools/Assertions/Editor/GroupByGORenderer.cs b/src/Assets/UnityTestTools/Assertions/Editor/GroupByGORenderer.cs new file mode 100644 index 0000000..45db630 --- /dev/null +++ b/src/Assets/UnityTestTools/Assertions/Editor/GroupByGORenderer.cs @@ -0,0 +1,33 @@ +using System.Collections.Generic; +using System.Linq; +using UnityEditor; +using UnityEngine; + +namespace UnityTest +{ + public class GroupByGORenderer : AssertionListRenderer + { + protected override IEnumerable> GroupResult (IEnumerable assertionComponents) + { + return assertionComponents.GroupBy (c => c.gameObject); + } + + protected override bool PrintFoldout (bool isFolded, GameObject key) + { + isFolded = base.PrintFoldout (isFolded, + key); + + EditorGUILayout.ObjectField (key, + typeof (GameObject), + true, + GUILayout.ExpandWidth (false)); + + return isFolded; + } + + protected override string GetFoldoutDisplayName (GameObject key) + { + return key.name; + } + } +} diff --git a/src/Assets/UnityTestTools/Assertions/Editor/GroupByGORenderer.cs.meta b/src/Assets/UnityTestTools/Assertions/Editor/GroupByGORenderer.cs.meta new file mode 100644 index 0000000..a11d1dc --- /dev/null +++ b/src/Assets/UnityTestTools/Assertions/Editor/GroupByGORenderer.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: cb824de9146b42343a985aaf63beffd1 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/UnityTestTools/Assertions/Editor/GroupByNothingRenderer.cs b/src/Assets/UnityTestTools/Assertions/Editor/GroupByNothingRenderer.cs new file mode 100644 index 0000000..30692a4 --- /dev/null +++ b/src/Assets/UnityTestTools/Assertions/Editor/GroupByNothingRenderer.cs @@ -0,0 +1,18 @@ +using System.Collections.Generic; +using System.Linq; + +namespace UnityTest +{ + public class GroupByNothingRenderer : AssertionListRenderer + { + protected override IEnumerable> GroupResult (IEnumerable assertionComponents) + { + return assertionComponents.GroupBy (c => ""); + } + + protected override string GetStringKey (string key) + { + return ""; + } + } +} diff --git a/src/Assets/UnityTestTools/Assertions/Editor/GroupByNothingRenderer.cs.meta b/src/Assets/UnityTestTools/Assertions/Editor/GroupByNothingRenderer.cs.meta new file mode 100644 index 0000000..f7d9d2a --- /dev/null +++ b/src/Assets/UnityTestTools/Assertions/Editor/GroupByNothingRenderer.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 33bf96aa461ea1d478bb757c52f51c95 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/UnityTestTools/Assertions/Editor/GroupByTestsRenderer.cs b/src/Assets/UnityTestTools/Assertions/Editor/GroupByTestsRenderer.cs new file mode 100644 index 0000000..422ff17 --- /dev/null +++ b/src/Assets/UnityTestTools/Assertions/Editor/GroupByTestsRenderer.cs @@ -0,0 +1,28 @@ +using System.Collections.Generic; +using System.Linq; +using UnityEngine; + +namespace UnityTest +{ + public class GroupByTestsRenderer : AssertionListRenderer + { + protected override IEnumerable> GroupResult (IEnumerable assertionComponents) + { + return assertionComponents.GroupBy (c => + { + var temp = c.transform; + while (temp != null) + { + if (temp.GetComponent (typeof (TestComponent)) != null) return c.gameObject; + temp = temp.parent.transform; + } + return null; + }); + } + + protected override string GetFoldoutDisplayName (GameObject key) + { + return key.name; + } + } +} diff --git a/src/Assets/UnityTestTools/Assertions/Editor/GroupByTestsRenderer.cs.meta b/src/Assets/UnityTestTools/Assertions/Editor/GroupByTestsRenderer.cs.meta new file mode 100644 index 0000000..cbc3124 --- /dev/null +++ b/src/Assets/UnityTestTools/Assertions/Editor/GroupByTestsRenderer.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 5e577f31e55208b4d8a1774b958e6ed5 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/UnityTestTools/Assertions/Editor/PropertyPathSelector.cs b/src/Assets/UnityTestTools/Assertions/Editor/PropertyPathSelector.cs new file mode 100644 index 0000000..ea9af27 --- /dev/null +++ b/src/Assets/UnityTestTools/Assertions/Editor/PropertyPathSelector.cs @@ -0,0 +1,211 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using UnityEditor; +using UnityEngine; + +namespace UnityTest +{ + public class PropertyPathSelector + { + private readonly DropDownControl thisDropDown = new DropDownControl(); + private readonly Func replaceDotWithSlashAndAddGOGroup = s => s.Replace('.', '/'); + + private readonly string name; + private bool focusBackToEdit; + private SelectedPathError error; + + public PropertyPathSelector (string name) + { + this.name = name; + thisDropDown.convertForGUIContent = replaceDotWithSlashAndAddGOGroup; + thisDropDown.tooltip = "Select path the value you want to be used for comparisment."; + } + + public void Draw(GameObject go, ActionBase comparer, string propertPath, Type[] accepatbleTypes, Action onSelectedGO, Action onSelectedPath) + { + var newGO = (GameObject)EditorGUILayout.ObjectField(name, go, typeof (GameObject), true); + if (newGO != go) + onSelectedGO(newGO); + + if (go != null) + { + var newPath = DrawListOfMethods (go, comparer, propertPath, accepatbleTypes, thisDropDown); + + if (newPath != propertPath) + onSelectedPath (newPath); + } + } + + private string DrawListOfMethods(GameObject go, ActionBase comparer, string propertPath, Type[] accepatbleTypes, DropDownControl dropDown) + { + string result = propertPath; + if (accepatbleTypes == null) + { + result = DrawManualPropertyEditField(go, propertPath, accepatbleTypes, dropDown); + } + else + { + bool isPropertyOrFieldFound = true; + if (string.IsNullOrEmpty(result)) + { + var options = GetFieldsAndProperties (go, comparer, result, accepatbleTypes); + isPropertyOrFieldFound = options.Any (); + if (isPropertyOrFieldFound) + { + result = options.First(); + } + } + + if (isPropertyOrFieldFound) + { + dropDown.Draw (go.name + '.', result, + () => + { + try + { + var options = GetFieldsAndProperties (go, comparer, result, accepatbleTypes); + return options.ToArray (); + } + catch (Exception) + { + Debug.LogWarning ("An exception was thrown while resolving property list. Reseting property path."); + result = ""; + return new string[0]; + } + }, s => result = s); + } + else + { + result = DrawManualPropertyEditField(go, propertPath, accepatbleTypes, dropDown); + } + } + return result; + } + + private static List GetFieldsAndProperties ( GameObject go, ActionBase comparer, string extendPath, Type[] accepatbleTypes ) + { + var propertyResolver = new PropertyResolver {AllowedTypes = accepatbleTypes, ExcludedFieldNames = comparer.GetExcludedFieldNames ()}; + var options = propertyResolver.GetFieldsAndPropertiesFromGameObject (go, comparer.GetDepthOfSearch (), extendPath).ToList (); + options.Sort ((x, y) => + { + if (char.IsLower (x[0])) + return -1; + if (char.IsLower (y[0])) + return 1; + return x.CompareTo (y); + }); + return options; + } + + private string DrawManualPropertyEditField(GameObject go, string propertPath, Type[] acceptableTypes, DropDownControl dropDown) + { + var propertyResolver = new PropertyResolver { AllowedTypes = acceptableTypes }; + IList list; + + var loadProps = new Func (() => + { + try + { + list = propertyResolver.GetFieldsAndPropertiesUnderPath (go, propertPath); + } + catch (ArgumentException) + { + list = propertyResolver.GetFieldsAndPropertiesUnderPath (go, ""); + } + return list.ToArray (); + }); + + EditorGUILayout.BeginHorizontal(); + + var labelSize = EditorStyles.label.CalcSize(new GUIContent(go.name + '.')); + GUILayout.Label (go.name + (propertPath.Length > 0 ? "." : ""), EditorStyles.label, GUILayout.Width (labelSize.x)); + + string btnName = "hintBtn"; + if ( GUI.GetNameOfFocusedControl () == btnName + && Event.current.type == EventType.KeyDown + && Event.current.keyCode == KeyCode.DownArrow) + { + Event.current.Use (); + dropDown.PrintMenu (loadProps ()); + GUI.FocusControl (""); + focusBackToEdit = true; + } + + EditorGUI.BeginChangeCheck (); + GUI.SetNextControlName (btnName); + var result = GUILayout.TextField(propertPath, EditorStyles.textField); + if (EditorGUI.EndChangeCheck ()) + { + error = DoesPropertyExist (go, result); + } + + if (focusBackToEdit) + { + focusBackToEdit = false; + GUI.FocusControl (btnName); + } + + if (GUILayout.Button ("clear", EditorStyles.miniButton, GUILayout.Width (38))) + { + result = ""; + GUI.FocusControl (null); + focusBackToEdit = true; + error = DoesPropertyExist (go, result); + } + EditorGUILayout.EndHorizontal(); + EditorGUILayout.BeginHorizontal (); + GUILayout.Label ("", GUILayout.Width (labelSize.x)); + + dropDown.Draw("", result ?? "", loadProps, s => + { + result = s; + GUI.FocusControl (null); + focusBackToEdit = true; + error = DoesPropertyExist (go, result); + }); + EditorGUILayout.EndHorizontal(); + + switch (error) + { + case SelectedPathError.InvalidPath: + EditorGUILayout.HelpBox ("This property does not exist", MessageType.Error); + break; + case SelectedPathError.MissingComponent: + EditorGUILayout.HelpBox ("This property or field is not attached or set. It will fail unless it will be attached before the check is perfomed.", MessageType.Warning); + break; + } + + return result; + } + + private SelectedPathError DoesPropertyExist ( GameObject go, string propertPath ) + { + try + { + object obj; + if(MemberResolver.TryGetValue (go, propertPath, out obj)) + return SelectedPathError.None; + else + return SelectedPathError.InvalidPath; + } + catch (TargetInvocationException e) + { + if(e.InnerException is MissingComponentException) + return SelectedPathError.MissingComponent; + else + throw; + } + } + + private enum SelectedPathError + { + None, + MissingComponent, + InvalidPath + } + } + + +} diff --git a/src/Assets/UnityTestTools/Assertions/Editor/PropertyPathSelector.cs.meta b/src/Assets/UnityTestTools/Assertions/Editor/PropertyPathSelector.cs.meta new file mode 100644 index 0000000..b1998a8 --- /dev/null +++ b/src/Assets/UnityTestTools/Assertions/Editor/PropertyPathSelector.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 6619da1897737044080bdb8bc60eff87 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/UnityTestTools/Assertions/Editor/PropertyResolver.cs b/src/Assets/UnityTestTools/Assertions/Editor/PropertyResolver.cs new file mode 100644 index 0000000..510fd03 --- /dev/null +++ b/src/Assets/UnityTestTools/Assertions/Editor/PropertyResolver.cs @@ -0,0 +1,188 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text.RegularExpressions; +using UnityEngine; + +namespace UnityTest +{ + [Serializable] + public class PropertyResolver + { + public string[] ExcludedFieldNames { get; set; } + public Type[] ExcludedTypes { get; set; } + public Type[] AllowedTypes { get; set; } + + public PropertyResolver () + { + ExcludedFieldNames = new string[] {}; + ExcludedTypes = new Type[] {}; + AllowedTypes = new Type[] {}; + } + + public IList GetFieldsAndPropertiesUnderPath(GameObject go, string propertPath) + { + propertPath = propertPath.Trim (); + if (!PropertyPathIsValid (propertPath)) + { + throw new ArgumentException("Incorrent property path: " + propertPath); + } + + var idx = propertPath.LastIndexOf('.'); + + if (idx < 0) + { + var components = GetFieldsAndPropertiesFromGameObject(go, 2, null); + return components; + } + + var propertyToSearch = propertPath; + Type type = null; + if (MemberResolver.TryGetMemberType (go, propertyToSearch, out type)) + { + idx = propertPath.Length - 1; + } + else + { + propertyToSearch = propertPath.Substring(0, idx); + if (!MemberResolver.TryGetMemberType (go, propertyToSearch, out type)) + { + var components = GetFieldsAndPropertiesFromGameObject(go, 2, null); + return components.Where(s => s.StartsWith(propertPath.Substring(idx + 1))).ToArray(); + } + } + + var resultList = new List(); + var path = ""; + if(propertyToSearch.EndsWith(".")) + propertyToSearch = propertyToSearch.Substring(0, propertyToSearch.Length-1); + foreach(var c in propertyToSearch) + { + if(c == '.') + resultList.Add(path); + path += c; + } + resultList.Add(path); + foreach (var prop in type.GetProperties ().Where(info=>info.GetIndexParameters ().Length==0)) + { + if (prop.Name.StartsWith(propertPath.Substring(idx + 1))) + resultList.Add(propertyToSearch + "." + prop.Name); + } + foreach (var prop in type.GetFields()) + { + if (prop.Name.StartsWith(propertPath.Substring(idx + 1))) + resultList.Add(propertyToSearch + "." + prop.Name); + } + return resultList.ToArray(); + } + + internal bool PropertyPathIsValid ( string propertPath ) + { + if (propertPath.StartsWith (".")) + return false; + if (propertPath.IndexOf ("..") >= 0) + return false; + if (Regex.IsMatch (propertPath, @"\s")) + return false; + return true; + } + + public IList GetFieldsAndPropertiesFromGameObject ( GameObject gameObject, int depthOfSearch, string extendPath ) + { + if(depthOfSearch<1) throw new ArgumentOutOfRangeException("depthOfSearch need to be greater than 0"); + + var goVals = GetPropertiesAndFieldsFromType(typeof(GameObject), + depthOfSearch - 1).Select(s => "gameObject." + s); + + var result = new List(); + if (AllowedTypes == null || !AllowedTypes.Any() || AllowedTypes.Contains(typeof(GameObject))) + result.Add("gameObject"); + result.AddRange (goVals); + + foreach (var componentType in GetAllComponents(gameObject)) + { + if (AllowedTypes == null || !AllowedTypes.Any() || AllowedTypes.Any(t => t.IsAssignableFrom (componentType))) + result.Add(componentType.Name); + + if (depthOfSearch > 1) + { + var vals = GetPropertiesAndFieldsFromType (componentType, depthOfSearch - 1 ); + var valsFullName = vals.Select (s => componentType.Name + "." + s); + result.AddRange (valsFullName); + } + } + + if (!string.IsNullOrEmpty (extendPath)) + { + var memberResolver = new MemberResolver (gameObject, extendPath); + var pathType = memberResolver.GetMemberType (); + var vals = GetPropertiesAndFieldsFromType (pathType, depthOfSearch - 1); + var valsFullName = vals.Select (s => extendPath + "." + s); + result.AddRange (valsFullName); + } + + return result; + } + + private string[] GetPropertiesAndFieldsFromType ( Type type, int level ) + { + level--; + + var result = new List(); + var fields = new List(); + fields.AddRange(type.GetFields().Where (f=>!Attribute.IsDefined (f, typeof (ObsoleteAttribute))).ToArray ()); + fields.AddRange(type.GetProperties().Where (info => info.GetIndexParameters ().Length == 0 && !Attribute.IsDefined (info, typeof (ObsoleteAttribute))).ToArray()); + + foreach (var member in fields) + { + var memberType = GetMemberFieldType(member); + var memberTypeName = memberType.Name; + + if (AllowedTypes == null + || !AllowedTypes.Any() + || (AllowedTypes.Any (t => t.IsAssignableFrom (memberType)) && !ExcludedFieldNames.Contains (memberTypeName))) + { + result.Add(member.Name); + } + + if (level > 0 && IsTypeOrNameNotExcluded(memberType, memberTypeName)) + { + var vals = GetPropertiesAndFieldsFromType(memberType, level); + var valsFullName = vals.Select(s => member.Name + "." + s); + result.AddRange(valsFullName); + } + } + return result.ToArray(); + } + + private Type GetMemberFieldType ( MemberInfo info ) + { + if (info.MemberType == MemberTypes.Property) + return (info as PropertyInfo).PropertyType; + if (info.MemberType == MemberTypes.Field) + return (info as FieldInfo).FieldType; + throw new Exception("Only properties and fields are allowed"); + } + + internal Type[] GetAllComponents ( GameObject gameObject ) + { + var result = new List(); + var components = gameObject.GetComponents(typeof(Component)); + foreach (var component in components) + { + var componentType = component.GetType(); + if (IsTypeOrNameNotExcluded(componentType, null)) + { + result.Add(componentType); + } + } + return result.ToArray(); + } + + private bool IsTypeOrNameNotExcluded(Type memberType, string memberTypeName) + { + return !ExcludedTypes.Contains(memberType) && !ExcludedFieldNames.Contains(memberTypeName); + } + } +} diff --git a/src/Assets/UnityTestTools/Assertions/Editor/PropertyResolver.cs.meta b/src/Assets/UnityTestTools/Assertions/Editor/PropertyResolver.cs.meta new file mode 100644 index 0000000..22210c7 --- /dev/null +++ b/src/Assets/UnityTestTools/Assertions/Editor/PropertyResolver.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: bbbd193a27920d9478c2a766a7291d72 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/UnityTestTools/Assertions/InvalidPathException.cs b/src/Assets/UnityTestTools/Assertions/InvalidPathException.cs new file mode 100644 index 0000000..fb9992d --- /dev/null +++ b/src/Assets/UnityTestTools/Assertions/InvalidPathException.cs @@ -0,0 +1,12 @@ +using System; + +namespace UnityTest +{ + public class InvalidPathException : Exception + { + public InvalidPathException (string path) + : base ("Invalid path part " + path) + { + } + } +} \ No newline at end of file diff --git a/src/Assets/UnityTestTools/Assertions/InvalidPathException.cs.meta b/src/Assets/UnityTestTools/Assertions/InvalidPathException.cs.meta new file mode 100644 index 0000000..a5f882d --- /dev/null +++ b/src/Assets/UnityTestTools/Assertions/InvalidPathException.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 3b85786dfd1aef544bf8bb873d6a4ebb +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/UnityTestTools/Assertions/MemberResolver.cs b/src/Assets/UnityTestTools/Assertions/MemberResolver.cs new file mode 100644 index 0000000..051165f --- /dev/null +++ b/src/Assets/UnityTestTools/Assertions/MemberResolver.cs @@ -0,0 +1,217 @@ +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Text.RegularExpressions; +using UnityEngine; + +namespace UnityTest +{ + public class MemberResolver + { + private object callingObjectRef; + private MemberInfo[] callstack; + private GameObject gameObject; + private string path; + + public MemberResolver (GameObject gameObject, string path) + { + path = path.Trim (); + ValidatePath (path); + + this.gameObject = gameObject; + this.path = path.Trim (); + } + + public object GetValue (bool useCache) + { + if (useCache && callingObjectRef!=null) + { + object val = callingObjectRef; + for (int i = 0; i < callstack.Length;i++) + val = GetValueFromMember (val, callstack[i]); + return val; + } + + object result = GetBaseObject (); + var fullCallStack = GetCallstack (); + + callingObjectRef = result; + var tempCallstack = new List (); + for (int i = 0; i < fullCallStack.Length; i++ ) + { + var member = fullCallStack[i]; + result = GetValueFromMember (result, member); + tempCallstack.Add (member); + if(result==null) return null; + if (!IsValueType (result.GetType ())) + { + tempCallstack.Clear (); + callingObjectRef = result; + } + } + callstack = tempCallstack.ToArray (); + return result; + } + + public Type GetMemberType () + { + var callstack = GetCallstack (); + if (callstack.Length == 0) return GetBaseObject().GetType(); + + var member = callstack[callstack.Length - 1]; + if (member is FieldInfo) + return (member as FieldInfo).FieldType; + if (member is MethodInfo) + return (member as MethodInfo).ReturnType; + return null; + } + + #region Static wrappers + public static bool TryGetMemberType ( GameObject gameObject, string path, out Type value ) + { + try + { + var mr = new MemberResolver (gameObject, path); + value = mr.GetMemberType (); + return true; + } + catch (InvalidPathException) + { + value = null; + return false; + } + } + + public static bool TryGetValue ( GameObject gameObject, string path, out object value ) + { + try + { + var mr = new MemberResolver (gameObject, path); + value = mr.GetValue (false); + return true; + } + catch (InvalidPathException) + { + value = null; + return false; + } + } + #endregion + + private object GetValueFromMember (object obj, MemberInfo memberInfo) + { + if (memberInfo is FieldInfo) + return (memberInfo as FieldInfo).GetValue (obj); + if (memberInfo is MethodInfo) + return (memberInfo as MethodInfo).Invoke (obj, null); + throw new InvalidPathException (memberInfo.Name); + } + + private object GetBaseObject () + { + if (string.IsNullOrEmpty (path)) return gameObject; + var firstElement = path.Split ('.')[0]; + var comp = gameObject.GetComponent (firstElement); + if (comp != null) + return comp; + else + return gameObject; + } + + private MemberInfo[] GetCallstack () + { + if (path == "") return new MemberInfo[0]; + var propsQueue = new Queue (path.Split ('.')); + + Type type = GetBaseObject ().GetType (); + if (type != typeof(GameObject)) + propsQueue.Dequeue (); + + PropertyInfo propertyTemp = null; + FieldInfo fieldTemp = null; + var list = new List (); + while (propsQueue.Count != 0) + { + var nameToFind = propsQueue.Dequeue (); + fieldTemp = GetField(type,nameToFind); + if (fieldTemp != null) + { + type = fieldTemp.FieldType; + list.Add (fieldTemp); + continue; + } + propertyTemp = GetProperty(type,nameToFind); + if (propertyTemp != null) + { + type = propertyTemp.PropertyType; + var getMethod = GetGetMethod(propertyTemp); + list.Add (getMethod); + continue; + } + throw new InvalidPathException (nameToFind); + } + return list.ToArray (); + } + + private Type GetTypeFromMember ( MemberInfo memberInfo ) + { + if (memberInfo is FieldInfo) + return (memberInfo as FieldInfo).FieldType; + if (memberInfo is MethodInfo) + return (memberInfo as MethodInfo).ReturnType; + throw new InvalidPathException (memberInfo.Name); + } + + private void ValidatePath (string path) + { + bool invalid = false; + if (path.StartsWith (".") || path.EndsWith (".")) + invalid = true; + if (path.IndexOf ("..") >= 0) + invalid = true; + if (Regex.IsMatch (path, @"\s")) + invalid = true; + + if (invalid) + throw new InvalidPathException (path); + } + + private static bool IsValueType(Type type) + { + #if !UNITY_METRO + return type.IsValueType; + #else + return false; + #endif + } + + private static FieldInfo GetField (Type type, string fieldName) + { + #if !UNITY_METRO + return type.GetField (fieldName); + #else + return null; + #endif + } + + private static PropertyInfo GetProperty (Type type, string propertyName) + { + #if !UNITY_METRO + return type.GetProperty (propertyName); + #else + return null; + #endif + } + + private static MethodInfo GetGetMethod (PropertyInfo propertyInfo) + { + #if !UNITY_METRO + return propertyInfo.GetGetMethod (); + #else + return null; + #endif + } + + } + +} diff --git a/src/Assets/UnityTestTools/Assertions/MemberResolver.cs.meta b/src/Assets/UnityTestTools/Assertions/MemberResolver.cs.meta new file mode 100644 index 0000000..6b1ea42 --- /dev/null +++ b/src/Assets/UnityTestTools/Assertions/MemberResolver.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 80df8ef907961e34dbcc7c89b22729b9 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/UnityTestTools/Common.meta b/src/Assets/UnityTestTools/Common.meta new file mode 100644 index 0000000..5f0acfe --- /dev/null +++ b/src/Assets/UnityTestTools/Common.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: a2caba6436df568499c84c1c607ce766 +folderAsset: yes +DefaultImporter: + userData: diff --git a/src/Assets/UnityTestTools/Common/Editor.meta b/src/Assets/UnityTestTools/Common/Editor.meta new file mode 100644 index 0000000..cc14913 --- /dev/null +++ b/src/Assets/UnityTestTools/Common/Editor.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: f4ab061d0035ee545a936bdf8f3f8620 +folderAsset: yes +DefaultImporter: + userData: diff --git a/src/Assets/UnityTestTools/Common/Editor/Icons.cs b/src/Assets/UnityTestTools/Common/Editor/Icons.cs new file mode 100644 index 0000000..c47d11c --- /dev/null +++ b/src/Assets/UnityTestTools/Common/Editor/Icons.cs @@ -0,0 +1,74 @@ +using System.IO; +using UnityEditor; +using UnityEngine; + +namespace UnityTest +{ + public static class Icons + { + private const string iconsAssetsPathPattern = "Common/Editor/icons/"; + private static string iconsAssetsPath = ""; + + public static readonly Texture2D failImg; + public static readonly Texture2D ignoreImg; + public static readonly Texture2D runImg; + public static readonly Texture2D runFailedImg; + public static readonly Texture2D runAllImg; + public static readonly Texture2D successImg; + public static readonly Texture2D unknownImg; + public static readonly Texture2D inconclusiveImg; + public static readonly Texture2D stopwatchImg; + public static readonly Texture2D plusImg; + public static readonly Texture2D gearImg; + + public static readonly GUIContent guiUnknownImg; + public static readonly GUIContent guiInconclusiveImg; + public static readonly GUIContent guiIgnoreImg; + public static readonly GUIContent guiSuccessImg; + public static readonly GUIContent guiFailImg; + + static Icons () + { + var dirs = Directory.GetDirectories ("Assets", "UnityTestTools", SearchOption.AllDirectories); + if (dirs.Length>0) + iconsAssetsPath = Path.Combine (dirs[0], iconsAssetsPathPattern); + else + Debug.LogWarning ("The UnityTestTools asset folder path is incorrect. If you relocated the tools please change the path accordingly (Icons.cs)."); + + failImg = LoadTexture ("failed.png"); + ignoreImg = LoadTexture("ignored.png"); + successImg = LoadTexture("passed.png"); + unknownImg = LoadTexture("normal.png"); + inconclusiveImg = LoadTexture("inconclusive.png"); + stopwatchImg = LoadTexture("stopwatch.png"); + + if (EditorGUIUtility.isProSkin) + { + runAllImg = LoadTexture ("play-darktheme.png"); + runImg = LoadTexture ("play_selected-darktheme.png"); + runFailedImg = LoadTexture ("rerun-darktheme.png"); + plusImg = LoadTexture ("create-darktheme.png"); + gearImg = LoadTexture ("options-darktheme.png"); + } + else + { + runAllImg = LoadTexture ("play-lighttheme.png"); + runImg = LoadTexture ("play_selected-lighttheme.png"); + runFailedImg = LoadTexture ("rerun-lighttheme.png"); + plusImg = LoadTexture ("create-lighttheme.png"); + gearImg = LoadTexture ("options-lighttheme.png"); + } + + guiUnknownImg = new GUIContent (unknownImg); + guiInconclusiveImg = new GUIContent (inconclusiveImg); + guiIgnoreImg = new GUIContent (ignoreImg); + guiSuccessImg = new GUIContent (successImg); + guiFailImg = new GUIContent (failImg); + } + + private static Texture2D LoadTexture (string fileName) + { + return (Texture2D)Resources.LoadAssetAtPath (iconsAssetsPath + fileName, typeof (Texture2D)); + } + } +} diff --git a/src/Assets/UnityTestTools/Common/Editor/Icons.cs.meta b/src/Assets/UnityTestTools/Common/Editor/Icons.cs.meta new file mode 100644 index 0000000..267269a --- /dev/null +++ b/src/Assets/UnityTestTools/Common/Editor/Icons.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 8571844b0c115b84cbe8b3f67e8dec04 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/UnityTestTools/Common/Editor/Styles.cs b/src/Assets/UnityTestTools/Common/Editor/Styles.cs new file mode 100644 index 0000000..9fa41c1 --- /dev/null +++ b/src/Assets/UnityTestTools/Common/Editor/Styles.cs @@ -0,0 +1,47 @@ +using UnityEditor; +using UnityEngine; + +namespace UnityTest +{ + public static class Styles + { + public static GUIStyle buttonLeft; + public static GUIStyle buttonMid; + public static GUIStyle buttonRight; + public static GUIStyle info; + public static GUIStyle testList; + + public static GUIStyle selectedLabel; + public static GUIStyle label; + public static GUIStyle selectedFoldout; + public static GUIStyle foldout; + + private static Color selectedColor = new Color (0.3f, 0.5f, 0.85f); + + static Styles () + { + buttonLeft = GUI.skin.FindStyle (GUI.skin.button.name + "left"); + buttonMid = GUI.skin.FindStyle (GUI.skin.button.name + "mid"); + buttonRight = GUI.skin.FindStyle (GUI.skin.button.name + "right"); + + info = new GUIStyle (EditorStyles.wordWrappedLabel); + info.wordWrap = false; + info.stretchHeight = true; + info.margin.right = 15; + + testList = new GUIStyle ("CN Box"); + testList.margin.top = 3; + testList.padding.left = 3; + + label = new GUIStyle (EditorStyles.label); + selectedLabel = new GUIStyle (EditorStyles.label); + selectedLabel.active.textColor = selectedLabel.normal.textColor = selectedLabel.onActive.textColor = selectedColor; + + foldout = new GUIStyle (EditorStyles.foldout); + selectedFoldout = new GUIStyle (EditorStyles.foldout); + selectedFoldout.onFocused.textColor = selectedFoldout.focused.textColor = + selectedFoldout.onActive.textColor = selectedFoldout.active.textColor = + selectedFoldout.onNormal.textColor = selectedFoldout.normal.textColor = selectedColor; + } + } +} diff --git a/src/Assets/UnityTestTools/Common/Editor/Styles.cs.meta b/src/Assets/UnityTestTools/Common/Editor/Styles.cs.meta new file mode 100644 index 0000000..294a619 --- /dev/null +++ b/src/Assets/UnityTestTools/Common/Editor/Styles.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: a8b92379e11501742b1badcbb08da812 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/UnityTestTools/Common/Editor/icons.meta b/src/Assets/UnityTestTools/Common/Editor/icons.meta new file mode 100644 index 0000000..89852ea --- /dev/null +++ b/src/Assets/UnityTestTools/Common/Editor/icons.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: e8bb6eae11352f44da0d6d8a8959b69e +folderAsset: yes +DefaultImporter: + userData: diff --git a/src/Assets/UnityTestTools/Common/Editor/icons/create-darktheme.png b/src/Assets/UnityTestTools/Common/Editor/icons/create-darktheme.png new file mode 100644 index 0000000..2200e30 Binary files /dev/null and b/src/Assets/UnityTestTools/Common/Editor/icons/create-darktheme.png differ diff --git a/src/Assets/UnityTestTools/Common/Editor/icons/create-darktheme.png.meta b/src/Assets/UnityTestTools/Common/Editor/icons/create-darktheme.png.meta new file mode 100644 index 0000000..3e77d05 --- /dev/null +++ b/src/Assets/UnityTestTools/Common/Editor/icons/create-darktheme.png.meta @@ -0,0 +1,46 @@ +fileFormatVersion: 2 +guid: a4193b17f22b72546a632f2735b22421 +TextureImporter: + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + linearTexture: 1 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: 1 + mipBias: -1 + wrapMode: 1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 1 + textureType: 2 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/src/Assets/UnityTestTools/Common/Editor/icons/create-lighttheme.png b/src/Assets/UnityTestTools/Common/Editor/icons/create-lighttheme.png new file mode 100644 index 0000000..faf4d72 Binary files /dev/null and b/src/Assets/UnityTestTools/Common/Editor/icons/create-lighttheme.png differ diff --git a/src/Assets/UnityTestTools/Common/Editor/icons/create-lighttheme.png.meta b/src/Assets/UnityTestTools/Common/Editor/icons/create-lighttheme.png.meta new file mode 100644 index 0000000..2d7a140 --- /dev/null +++ b/src/Assets/UnityTestTools/Common/Editor/icons/create-lighttheme.png.meta @@ -0,0 +1,46 @@ +fileFormatVersion: 2 +guid: 39f371f2ad7a53a4693cc4d50c5f24ca +TextureImporter: + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + linearTexture: 1 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: 1 + mipBias: -1 + wrapMode: 1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 1 + textureType: 2 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/src/Assets/UnityTestTools/Common/Editor/icons/failed.png b/src/Assets/UnityTestTools/Common/Editor/icons/failed.png new file mode 100644 index 0000000..7c0aba4 Binary files /dev/null and b/src/Assets/UnityTestTools/Common/Editor/icons/failed.png differ diff --git a/src/Assets/UnityTestTools/Common/Editor/icons/failed.png.meta b/src/Assets/UnityTestTools/Common/Editor/icons/failed.png.meta new file mode 100644 index 0000000..cd8e92d --- /dev/null +++ b/src/Assets/UnityTestTools/Common/Editor/icons/failed.png.meta @@ -0,0 +1,46 @@ +fileFormatVersion: 2 +guid: 41488feb372865440b7c01773f04c0cf +TextureImporter: + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + linearTexture: 1 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: 1 + mipBias: -1 + wrapMode: 1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 1 + textureType: 2 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/src/Assets/UnityTestTools/Common/Editor/icons/ignored.png b/src/Assets/UnityTestTools/Common/Editor/icons/ignored.png new file mode 100644 index 0000000..0190e59 Binary files /dev/null and b/src/Assets/UnityTestTools/Common/Editor/icons/ignored.png differ diff --git a/src/Assets/UnityTestTools/Common/Editor/icons/ignored.png.meta b/src/Assets/UnityTestTools/Common/Editor/icons/ignored.png.meta new file mode 100644 index 0000000..1d5ff8b --- /dev/null +++ b/src/Assets/UnityTestTools/Common/Editor/icons/ignored.png.meta @@ -0,0 +1,46 @@ +fileFormatVersion: 2 +guid: 0076bfa6073f17546b3535ac1b456b0b +TextureImporter: + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + linearTexture: 1 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: 1 + mipBias: -1 + wrapMode: 1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 1 + textureType: 2 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/src/Assets/UnityTestTools/Common/Editor/icons/inconclusive.png b/src/Assets/UnityTestTools/Common/Editor/icons/inconclusive.png new file mode 100644 index 0000000..df398dd Binary files /dev/null and b/src/Assets/UnityTestTools/Common/Editor/icons/inconclusive.png differ diff --git a/src/Assets/UnityTestTools/Common/Editor/icons/inconclusive.png.meta b/src/Assets/UnityTestTools/Common/Editor/icons/inconclusive.png.meta new file mode 100644 index 0000000..910154f --- /dev/null +++ b/src/Assets/UnityTestTools/Common/Editor/icons/inconclusive.png.meta @@ -0,0 +1,46 @@ +fileFormatVersion: 2 +guid: e28761099904678488cdddf7b6be2ceb +TextureImporter: + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + linearTexture: 1 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: 1 + mipBias: -1 + wrapMode: 1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 1 + textureType: 2 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/src/Assets/UnityTestTools/Common/Editor/icons/normal.png b/src/Assets/UnityTestTools/Common/Editor/icons/normal.png new file mode 100644 index 0000000..6a04f79 Binary files /dev/null and b/src/Assets/UnityTestTools/Common/Editor/icons/normal.png differ diff --git a/src/Assets/UnityTestTools/Common/Editor/icons/normal.png.meta b/src/Assets/UnityTestTools/Common/Editor/icons/normal.png.meta new file mode 100644 index 0000000..78f0121 --- /dev/null +++ b/src/Assets/UnityTestTools/Common/Editor/icons/normal.png.meta @@ -0,0 +1,46 @@ +fileFormatVersion: 2 +guid: a9f3c491f4c2f9f43ac33a27c16913dd +TextureImporter: + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + linearTexture: 1 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: 1 + mipBias: -1 + wrapMode: 1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 1 + textureType: 2 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/src/Assets/UnityTestTools/Common/Editor/icons/options-darktheme.png b/src/Assets/UnityTestTools/Common/Editor/icons/options-darktheme.png new file mode 100644 index 0000000..8710af2 Binary files /dev/null and b/src/Assets/UnityTestTools/Common/Editor/icons/options-darktheme.png differ diff --git a/src/Assets/UnityTestTools/Common/Editor/icons/options-darktheme.png.meta b/src/Assets/UnityTestTools/Common/Editor/icons/options-darktheme.png.meta new file mode 100644 index 0000000..d6910a1 --- /dev/null +++ b/src/Assets/UnityTestTools/Common/Editor/icons/options-darktheme.png.meta @@ -0,0 +1,46 @@ +fileFormatVersion: 2 +guid: bbd9485c1fc611b44a4ac1abfdcffbf5 +TextureImporter: + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + linearTexture: 1 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: 1 + mipBias: -1 + wrapMode: 1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 1 + textureType: 2 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/src/Assets/UnityTestTools/Common/Editor/icons/options-lighttheme.png b/src/Assets/UnityTestTools/Common/Editor/icons/options-lighttheme.png new file mode 100644 index 0000000..e33c43f Binary files /dev/null and b/src/Assets/UnityTestTools/Common/Editor/icons/options-lighttheme.png differ diff --git a/src/Assets/UnityTestTools/Common/Editor/icons/options-lighttheme.png.meta b/src/Assets/UnityTestTools/Common/Editor/icons/options-lighttheme.png.meta new file mode 100644 index 0000000..bca33bc --- /dev/null +++ b/src/Assets/UnityTestTools/Common/Editor/icons/options-lighttheme.png.meta @@ -0,0 +1,46 @@ +fileFormatVersion: 2 +guid: 4e6ebb403e0c3974fbe7cbd6f89ea6a6 +TextureImporter: + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + linearTexture: 1 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: 1 + mipBias: -1 + wrapMode: 1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 1 + textureType: 2 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/src/Assets/UnityTestTools/Common/Editor/icons/passed.png b/src/Assets/UnityTestTools/Common/Editor/icons/passed.png new file mode 100644 index 0000000..1edd286 Binary files /dev/null and b/src/Assets/UnityTestTools/Common/Editor/icons/passed.png differ diff --git a/src/Assets/UnityTestTools/Common/Editor/icons/passed.png.meta b/src/Assets/UnityTestTools/Common/Editor/icons/passed.png.meta new file mode 100644 index 0000000..4c03e10 --- /dev/null +++ b/src/Assets/UnityTestTools/Common/Editor/icons/passed.png.meta @@ -0,0 +1,46 @@ +fileFormatVersion: 2 +guid: 31f7928179ee46d4690d274579efb037 +TextureImporter: + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + linearTexture: 1 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: 1 + mipBias: -1 + wrapMode: 1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 1 + textureType: 2 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/src/Assets/UnityTestTools/Common/Editor/icons/play-darktheme.png b/src/Assets/UnityTestTools/Common/Editor/icons/play-darktheme.png new file mode 100644 index 0000000..c522086 Binary files /dev/null and b/src/Assets/UnityTestTools/Common/Editor/icons/play-darktheme.png differ diff --git a/src/Assets/UnityTestTools/Common/Editor/icons/play-darktheme.png.meta b/src/Assets/UnityTestTools/Common/Editor/icons/play-darktheme.png.meta new file mode 100644 index 0000000..19fe9a2 --- /dev/null +++ b/src/Assets/UnityTestTools/Common/Editor/icons/play-darktheme.png.meta @@ -0,0 +1,46 @@ +fileFormatVersion: 2 +guid: ea69579f34a673a46a1a33ca2f473917 +TextureImporter: + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + linearTexture: 1 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: 1 + mipBias: -1 + wrapMode: 1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 1 + textureType: 2 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/src/Assets/UnityTestTools/Common/Editor/icons/play-lighttheme.png b/src/Assets/UnityTestTools/Common/Editor/icons/play-lighttheme.png new file mode 100644 index 0000000..30207ad Binary files /dev/null and b/src/Assets/UnityTestTools/Common/Editor/icons/play-lighttheme.png differ diff --git a/src/Assets/UnityTestTools/Common/Editor/icons/play-lighttheme.png.meta b/src/Assets/UnityTestTools/Common/Editor/icons/play-lighttheme.png.meta new file mode 100644 index 0000000..371bcbb --- /dev/null +++ b/src/Assets/UnityTestTools/Common/Editor/icons/play-lighttheme.png.meta @@ -0,0 +1,46 @@ +fileFormatVersion: 2 +guid: 0e1238656fa8ab7469f7c2c3c3863e8d +TextureImporter: + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + linearTexture: 1 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: 1 + mipBias: -1 + wrapMode: 1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 1 + textureType: 2 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/src/Assets/UnityTestTools/Common/Editor/icons/play_selected-darktheme.png b/src/Assets/UnityTestTools/Common/Editor/icons/play_selected-darktheme.png new file mode 100644 index 0000000..a2471e8 Binary files /dev/null and b/src/Assets/UnityTestTools/Common/Editor/icons/play_selected-darktheme.png differ diff --git a/src/Assets/UnityTestTools/Common/Editor/icons/play_selected-darktheme.png.meta b/src/Assets/UnityTestTools/Common/Editor/icons/play_selected-darktheme.png.meta new file mode 100644 index 0000000..b5bdc6b --- /dev/null +++ b/src/Assets/UnityTestTools/Common/Editor/icons/play_selected-darktheme.png.meta @@ -0,0 +1,46 @@ +fileFormatVersion: 2 +guid: e0047013a792e5043b411565030f0939 +TextureImporter: + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + linearTexture: 1 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: 1 + mipBias: -1 + wrapMode: 1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 1 + textureType: 2 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/src/Assets/UnityTestTools/Common/Editor/icons/play_selected-lighttheme.png b/src/Assets/UnityTestTools/Common/Editor/icons/play_selected-lighttheme.png new file mode 100644 index 0000000..dad2385 Binary files /dev/null and b/src/Assets/UnityTestTools/Common/Editor/icons/play_selected-lighttheme.png differ diff --git a/src/Assets/UnityTestTools/Common/Editor/icons/play_selected-lighttheme.png.meta b/src/Assets/UnityTestTools/Common/Editor/icons/play_selected-lighttheme.png.meta new file mode 100644 index 0000000..193349d --- /dev/null +++ b/src/Assets/UnityTestTools/Common/Editor/icons/play_selected-lighttheme.png.meta @@ -0,0 +1,46 @@ +fileFormatVersion: 2 +guid: fa83cb00bb03c834889658b2c3e03259 +TextureImporter: + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + linearTexture: 1 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: 1 + mipBias: -1 + wrapMode: 1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 1 + textureType: 2 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/src/Assets/UnityTestTools/Common/Editor/icons/rerun-darktheme.png b/src/Assets/UnityTestTools/Common/Editor/icons/rerun-darktheme.png new file mode 100644 index 0000000..07f10b9 Binary files /dev/null and b/src/Assets/UnityTestTools/Common/Editor/icons/rerun-darktheme.png differ diff --git a/src/Assets/UnityTestTools/Common/Editor/icons/rerun-darktheme.png.meta b/src/Assets/UnityTestTools/Common/Editor/icons/rerun-darktheme.png.meta new file mode 100644 index 0000000..a372410 --- /dev/null +++ b/src/Assets/UnityTestTools/Common/Editor/icons/rerun-darktheme.png.meta @@ -0,0 +1,46 @@ +fileFormatVersion: 2 +guid: c78dbba64437b0844a5325b44179612b +TextureImporter: + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + linearTexture: 1 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: 1 + mipBias: -1 + wrapMode: 1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 1 + textureType: 2 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/src/Assets/UnityTestTools/Common/Editor/icons/rerun-lighttheme.png b/src/Assets/UnityTestTools/Common/Editor/icons/rerun-lighttheme.png new file mode 100644 index 0000000..bc2172c Binary files /dev/null and b/src/Assets/UnityTestTools/Common/Editor/icons/rerun-lighttheme.png differ diff --git a/src/Assets/UnityTestTools/Common/Editor/icons/rerun-lighttheme.png.meta b/src/Assets/UnityTestTools/Common/Editor/icons/rerun-lighttheme.png.meta new file mode 100644 index 0000000..a464443 --- /dev/null +++ b/src/Assets/UnityTestTools/Common/Editor/icons/rerun-lighttheme.png.meta @@ -0,0 +1,46 @@ +fileFormatVersion: 2 +guid: 31b9d2dd12f869348b9fbb0049cbb106 +TextureImporter: + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + linearTexture: 1 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: 1 + mipBias: -1 + wrapMode: 1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 1 + textureType: 2 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/src/Assets/UnityTestTools/Common/Editor/icons/stopwatch.png b/src/Assets/UnityTestTools/Common/Editor/icons/stopwatch.png new file mode 100644 index 0000000..ac5721c Binary files /dev/null and b/src/Assets/UnityTestTools/Common/Editor/icons/stopwatch.png differ diff --git a/src/Assets/UnityTestTools/Common/Editor/icons/stopwatch.png.meta b/src/Assets/UnityTestTools/Common/Editor/icons/stopwatch.png.meta new file mode 100644 index 0000000..ed0a6fa --- /dev/null +++ b/src/Assets/UnityTestTools/Common/Editor/icons/stopwatch.png.meta @@ -0,0 +1,46 @@ +fileFormatVersion: 2 +guid: f73f95ae19d51af47ad56044f2779aa1 +TextureImporter: + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + linearTexture: 1 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: 1 + mipBias: -1 + wrapMode: 1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 1 + textureType: 2 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/src/Assets/UnityTestTools/Common/ITestResult.cs b/src/Assets/UnityTestTools/Common/ITestResult.cs new file mode 100644 index 0000000..26dd5c5 --- /dev/null +++ b/src/Assets/UnityTestTools/Common/ITestResult.cs @@ -0,0 +1,14 @@ +using UnityTest; + +public interface ITestResult +{ + TestResultState ResultState { get; } + string Message { get; } + bool Executed { get; } + string Name { get; } + string FullName { get; } + string Id { get; } + bool IsSuccess { get; } + double Duration { get; } + string StackTrace { get; } +} diff --git a/src/Assets/UnityTestTools/Common/ITestResult.cs.meta b/src/Assets/UnityTestTools/Common/ITestResult.cs.meta new file mode 100644 index 0000000..4864197 --- /dev/null +++ b/src/Assets/UnityTestTools/Common/ITestResult.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d1e4e2c4d00b3f2469494fc0f67cdeae +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/UnityTestTools/Common/ResultWriter.meta b/src/Assets/UnityTestTools/Common/ResultWriter.meta new file mode 100644 index 0000000..9b2e13b --- /dev/null +++ b/src/Assets/UnityTestTools/Common/ResultWriter.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: 4ffbf5a07740aa5479651bd415f52ebb +folderAsset: yes +DefaultImporter: + userData: diff --git a/src/Assets/UnityTestTools/Common/ResultWriter/ResultSummarizer.cs b/src/Assets/UnityTestTools/Common/ResultWriter/ResultSummarizer.cs new file mode 100644 index 0000000..17f8ed5 --- /dev/null +++ b/src/Assets/UnityTestTools/Common/ResultWriter/ResultSummarizer.cs @@ -0,0 +1,160 @@ +// **************************************************************** +// Based on nUnit 2.6.2 (http://www.nunit.org/) +// **************************************************************** + +using System; + +namespace UnityTest +{ + /// + /// Summary description for ResultSummarizer. + /// + public class ResultSummarizer + { + private int errorCount = 0; + private int failureCount = 0; + private int ignoreCount = 0; + private int inconclusiveCount = 0; + private int notRunnable = 0; + private int resultCount = 0; + private int skipCount = 0; + private int successCount = 0; + private int testsRun = 0; + + private TimeSpan duration = new TimeSpan(); + + public ResultSummarizer (ITestResult[] results) + { + foreach (var result in results) + Summarize (result); + } + + public bool Success + { + get { return failureCount == 0; } + } + + /// + /// Returns the number of test cases for which results + /// have been summarized. Any tests excluded by use of + /// Category or Explicit attributes are not counted. + /// + public int ResultCount + { + get { return resultCount; } + } + + /// + /// Returns the number of test cases actually run, which + /// is the same as ResultCount, less any Skipped, Ignored + /// or NonRunnable tests. + /// + public int TestsRun + { + get { return testsRun; } + } + + /// + /// Returns the number of tests that passed + /// + public int Passed + { + get { return successCount; } + } + + /// + /// Returns the number of test cases that had an error. + /// + public int Errors + { + get { return errorCount; } + } + + /// + /// Returns the number of test cases that failed. + /// + public int Failures + { + get { return failureCount; } + } + + /// + /// Returns the number of test cases that failed. + /// + public int Inconclusive + { + get { return inconclusiveCount; } + } + + /// + /// Returns the number of test cases that were not runnable + /// due to errors in the signature of the class or method. + /// Such tests are also counted as Errors. + /// + public int NotRunnable + { + get { return notRunnable; } + } + + /// + /// Returns the number of test cases that were skipped. + /// + public int Skipped + { + get { return skipCount; } + } + + public int Ignored + { + get { return ignoreCount; } + } + + public double Duration + { + get { return duration.TotalSeconds; } + } + + public int TestsNotRun + { + get { return skipCount + ignoreCount + notRunnable; } + } + + public void Summarize (ITestResult result) + { + duration += TimeSpan.FromSeconds (result.Duration); + resultCount++; + + switch (result.ResultState) + { + case TestResultState.Success: + successCount++; + testsRun++; + break; + case TestResultState.Failure: + failureCount++; + testsRun++; + break; + case TestResultState.Error: + case TestResultState.Cancelled: + errorCount++; + testsRun++; + break; + case TestResultState.Inconclusive: + inconclusiveCount++; + testsRun++; + break; + case TestResultState.NotRunnable: + notRunnable++; + //errorCount++; + break; + case TestResultState.Ignored: + ignoreCount++; + break; + case TestResultState.Skipped: + default: + skipCount++; + break; + } + } + } +} diff --git a/src/Assets/UnityTestTools/Common/ResultWriter/ResultSummarizer.cs.meta b/src/Assets/UnityTestTools/Common/ResultWriter/ResultSummarizer.cs.meta new file mode 100644 index 0000000..ca3c41f --- /dev/null +++ b/src/Assets/UnityTestTools/Common/ResultWriter/ResultSummarizer.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ce89106be5bd4204388d58510e4e55da +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/UnityTestTools/Common/ResultWriter/StackTraceFilter.cs b/src/Assets/UnityTestTools/Common/ResultWriter/StackTraceFilter.cs new file mode 100644 index 0000000..1108f46 --- /dev/null +++ b/src/Assets/UnityTestTools/Common/ResultWriter/StackTraceFilter.cs @@ -0,0 +1,61 @@ +// **************************************************************** +// Based on nUnit 2.6.2 (http://www.nunit.org/) +// **************************************************************** + +namespace UnityTest +{ + using System; + using System.IO; + + /// + /// Summary description for StackTraceFilter. + /// + public class StackTraceFilter + { + public static string Filter(string stack) + { + if(stack == null) return null; + StringWriter sw = new StringWriter(); + StringReader sr = new StringReader(stack); + + try + { + string line; + while ((line = sr.ReadLine()) != null) + { + if (!FilterLine(line)) + sw.WriteLine(line.Trim()); + } + } + catch (Exception) + { + return stack; + } + return sw.ToString(); + } + + static bool FilterLine(string line) + { + string[] patterns = new string[] + { + "NUnit.Core.TestCase", + "NUnit.Core.ExpectedExceptionTestCase", + "NUnit.Core.TemplateTestCase", + "NUnit.Core.TestResult", + "NUnit.Core.TestSuite", + "NUnit.Framework.Assertion", + "NUnit.Framework.Assert", + "System.Reflection.MonoMethod" + }; + + for (int i = 0; i < patterns.Length; i++) + { + if (line.IndexOf(patterns[i]) > 0) + return true; + } + + return false; + } + + } +} diff --git a/src/Assets/UnityTestTools/Common/ResultWriter/StackTraceFilter.cs.meta b/src/Assets/UnityTestTools/Common/ResultWriter/StackTraceFilter.cs.meta new file mode 100644 index 0000000..7051843 --- /dev/null +++ b/src/Assets/UnityTestTools/Common/ResultWriter/StackTraceFilter.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: fe6b4d68575d4ba44b1d5c5c3f0e96d3 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/UnityTestTools/Common/ResultWriter/XmlResultWriter.cs b/src/Assets/UnityTestTools/Common/ResultWriter/XmlResultWriter.cs new file mode 100644 index 0000000..abaedb5 --- /dev/null +++ b/src/Assets/UnityTestTools/Common/ResultWriter/XmlResultWriter.cs @@ -0,0 +1,333 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Security; +using System.Text; +using UnityEngine; + +namespace UnityTest +{ + public class XmlResultWriter + { + private StringBuilder resultWriter = new StringBuilder(); + private int indend = 0; + private string suiteName; + private ITestResult[] results; + + public XmlResultWriter (string suiteName, ITestResult[] results) + { + this.suiteName = suiteName; + this.results = results; + } + + private const string nUnitVersion = "2.6.2-Unity"; + + public string GetTestResult() + { + InitializeXmlFile(suiteName, new ResultSummarizer(results)); + foreach (var result in results) + { + WriteResultElement(result); + } + TerminateXmlFile(); + return resultWriter.ToString (); + } + + private void InitializeXmlFile ( string resultsName, ResultSummarizer summaryResults ) + { + WriteHeader (); + + DateTime now = DateTime.Now; + var attributes = new Dictionary + { + {"name", "Unity Tests"}, + {"total", summaryResults.TestsRun.ToString ()}, + {"errors", summaryResults.Errors.ToString ()}, + {"failures", summaryResults.Failures.ToString ()}, + {"not-run", summaryResults.TestsNotRun.ToString ()}, + {"inconclusive", summaryResults.Inconclusive.ToString ()}, + {"ignored", summaryResults.Ignored.ToString ()}, + {"skipped", summaryResults.Skipped.ToString ()}, + {"invalid", summaryResults.NotRunnable.ToString ()}, + {"date", now.ToString("yyyy-MM-dd")}, + {"time", now.ToString("HH:mm:ss")} + }; + + WriteOpeningElement ("test-results", attributes); + + WriteEnvironment(); + WriteCultureInfo(); + WriteTestSuite (resultsName, summaryResults); + WriteOpeningElement("results"); + } + + private void WriteOpeningElement (string elementName) + { + WriteOpeningElement (elementName, new Dictionary ()); + } + + private void WriteOpeningElement (string elementName, Dictionary attributes) + { + WriteOpeningElement (elementName, attributes, false); + } + + + private void WriteOpeningElement (string elementName, Dictionary attributes, bool closeImmediatelly) + { + WriteIndend (); + indend++; + resultWriter.Append ("<"); + resultWriter.Append (elementName); + foreach (var attribute in attributes) + { + resultWriter.AppendFormat (" {0}=\"{1}\"", attribute.Key, SecurityElement.Escape (attribute.Value)); + } + if (closeImmediatelly) + { + resultWriter.Append (" /"); + indend--; + } + resultWriter.AppendLine(">"); + } + + private void WriteIndend () + { + for (int i = 0; i < indend; i++) + { + resultWriter.Append (" "); + } + } + + private void WriteClosingElement ( string elementName ) + { + indend--; + WriteIndend (); + resultWriter.AppendLine (""); + } + + private void WriteHeader () + { + resultWriter.AppendLine (""); + resultWriter.AppendLine (""); + } + + static string GetEnvironmentUserName () + { + #if !UNITY_WP8 && !UNITY_METRO + return Environment.UserName; + #else + return ""; + #endif + } + + static string GetEnvironmentMachineName () + { + #if !UNITY_WP8 && !UNITY_METRO + return Environment.MachineName; + #else + return ""; + #endif + } + + static string GetEnvironmentUserDomainName () + { + #if !UNITY_WP8 && !UNITY_METRO + return Environment.UserDomainName; + #else + return ""; + #endif + } + + static string GetEnvironmentVersion () + { + #if !UNITY_METRO + return Environment.Version.ToString (); + #else + return ""; + #endif + } + + static string GetEnvironmentOSVersion () + { + #if !UNITY_METRO + return Environment.OSVersion.ToString (); + #else + return ""; + #endif + } + + static string GetEnvironmentOSVersionPlatform () + { + #if !UNITY_METRO + return Environment.OSVersion.Platform.ToString (); + #else + return ""; + #endif + } + + static string EnvironmentGetCurrentDirectory () + { + #if !UNITY_METRO + return Environment.CurrentDirectory; + #else + return ""; + #endif + } + + private void WriteEnvironment () + { + var attributes = new Dictionary + { + {"nunit-version", nUnitVersion}, + {"clr-version", GetEnvironmentVersion ()}, + {"os-version", GetEnvironmentOSVersion ()}, + {"platform", GetEnvironmentOSVersionPlatform ()}, + {"cwd", EnvironmentGetCurrentDirectory ()}, + {"machine-name", GetEnvironmentMachineName ()}, + {"user", GetEnvironmentUserName ()}, + {"user-domain", GetEnvironmentUserDomainName ()} + }; + WriteOpeningElement ("environment", attributes, true); + } + + private void WriteCultureInfo() + { + var attributes = new Dictionary + { + {"current-culture", CultureInfo.CurrentCulture.ToString ()}, + {"current-uiculture", CultureInfo.CurrentUICulture.ToString ()} + }; + WriteOpeningElement ("culture-info", attributes, true); + } + + private void WriteTestSuite (string resultsName, ResultSummarizer summaryResults) + { + var attributes = new Dictionary + { + {"name", resultsName}, + {"type", "Assembly"}, + {"executed", "True"}, + {"result", summaryResults.Success ? "Success" : "Failure"}, + {"success", summaryResults.Success ? "True" : "False"}, + {"time", summaryResults.Duration.ToString ("#####0.000", NumberFormatInfo.InvariantInfo)} + }; + WriteOpeningElement ("test-suite", attributes); + } + + private void WriteResultElement(ITestResult result) + { + StartTestElement(result); + + switch (result.ResultState) + { + case TestResultState.Ignored: + case TestResultState.NotRunnable: + case TestResultState.Skipped: + WriteReasonElement(result); + break; + + case TestResultState.Failure: + case TestResultState.Error: + case TestResultState.Cancelled: + WriteFailureElement(result); + break; + case TestResultState.Success: + case TestResultState.Inconclusive: + if (result.Message != null) + WriteReasonElement(result); + break; + } + + WriteClosingElement("test-case"); + } + + private void TerminateXmlFile() + { + WriteClosingElement ("results"); + WriteClosingElement ("test-suite"); + WriteClosingElement ("test-results"); + } + + #region Element Creation Helpers + + private void StartTestElement(ITestResult result) + { + var attributes = new Dictionary + { + {"name", result.FullName}, + {"executed", result.Executed.ToString ()} + }; + var resultString = ""; + switch (result.ResultState) + { + case TestResultState.Cancelled: + resultString = TestResultState.Failure.ToString(); + break; + default: + resultString = result.ResultState.ToString (); + break; + } + attributes.Add ("result", resultString); + if (result.Executed) + { + attributes.Add ("success", result.IsSuccess.ToString ()); + attributes.Add( "time", result.Duration.ToString("#####0.000", NumberFormatInfo.InvariantInfo)); + } + WriteOpeningElement ("test-case", attributes); + } + + private void WriteReasonElement(ITestResult result) + { + WriteOpeningElement ("reason"); + WriteOpeningElement ("message"); + WriteCData(result.Message); + WriteClosingElement ("message"); + WriteClosingElement ("reason"); + + } + + private void WriteFailureElement(ITestResult result) + { + WriteOpeningElement ("failure"); + WriteOpeningElement ("message"); + WriteCData (result.Message); + WriteClosingElement ("message"); + WriteOpeningElement ("stack-trace"); + if (result.StackTrace != null) + WriteCData (StackTraceFilter.Filter (result.StackTrace)); + WriteClosingElement ("stack-trace"); + WriteClosingElement ("failure"); + } + + #endregion + + private void WriteCData(string text) + { + if (text.Length == 0) + return; + resultWriter.AppendFormat ("", text); + resultWriter.AppendLine (); + } + +#if !UNITY_METRO + public void WriteToFile (string resultDestiantion, string resultFileName) + { + try + { + var path = System.IO.Path.Combine (resultDestiantion, resultFileName); + Debug.Log ("Saving results in " + path); + using (var fs = System.IO.File.OpenWrite (path)) + using (var sw = new System.IO.StreamWriter (fs, Encoding.UTF8)) + { + sw.Write (GetTestResult ()); + } + } + catch (Exception e) + { + Debug.LogError ("Error while opening file"); + Debug.LogException (e); + } + } +#endif + } +} diff --git a/src/Assets/UnityTestTools/Common/ResultWriter/XmlResultWriter.cs.meta b/src/Assets/UnityTestTools/Common/ResultWriter/XmlResultWriter.cs.meta new file mode 100644 index 0000000..2fffa90 --- /dev/null +++ b/src/Assets/UnityTestTools/Common/ResultWriter/XmlResultWriter.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e9bba41ace7686d4ab0c400d1e7f55b7 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/UnityTestTools/Common/TestResultState.cs b/src/Assets/UnityTestTools/Common/TestResultState.cs new file mode 100644 index 0000000..98c75bb --- /dev/null +++ b/src/Assets/UnityTestTools/Common/TestResultState.cs @@ -0,0 +1,42 @@ +namespace UnityTest +{ + public enum TestResultState + { + Inconclusive = 0, + + /// + /// The test was not runnable. + /// + NotRunnable = 1, + + /// + /// The test has been skipped. + /// + Skipped = 2, + + /// + /// The test has been ignored. + /// + Ignored = 3, + + /// + /// The test succeeded + /// + Success = 4, + + /// + /// The test failed + /// + Failure = 5, + + /// + /// The test encountered an unexpected exception + /// + Error = 6, + + /// + /// The test was cancelled by the user + /// + Cancelled = 7 + } +} diff --git a/src/Assets/UnityTestTools/Common/TestResultState.cs.meta b/src/Assets/UnityTestTools/Common/TestResultState.cs.meta new file mode 100644 index 0000000..e1576c7 --- /dev/null +++ b/src/Assets/UnityTestTools/Common/TestResultState.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: da3ca54ee4cce064989d27165f3081fb +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/UnityTestTools/Docs.meta b/src/Assets/UnityTestTools/Docs.meta new file mode 100644 index 0000000..d636c02 --- /dev/null +++ b/src/Assets/UnityTestTools/Docs.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: 8e0891bd2d8055d43af56216ad95d3d5 +folderAsset: yes +DefaultImporter: + userData: diff --git a/src/Assets/UnityTestTools/Docs/UnityTestTools-en.pdf b/src/Assets/UnityTestTools/Docs/UnityTestTools-en.pdf new file mode 100644 index 0000000..3793457 Binary files /dev/null and b/src/Assets/UnityTestTools/Docs/UnityTestTools-en.pdf differ diff --git a/src/Assets/UnityTestTools/Docs/UnityTestTools-en.pdf.meta b/src/Assets/UnityTestTools/Docs/UnityTestTools-en.pdf.meta new file mode 100644 index 0000000..75f9868 --- /dev/null +++ b/src/Assets/UnityTestTools/Docs/UnityTestTools-en.pdf.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: a53dc58cb0c6c474b9c48185829d59c7 +DefaultImporter: + userData: diff --git a/src/Assets/UnityTestTools/Docs/UnityTestTools-ja.pdf b/src/Assets/UnityTestTools/Docs/UnityTestTools-ja.pdf new file mode 100644 index 0000000..b3acfca Binary files /dev/null and b/src/Assets/UnityTestTools/Docs/UnityTestTools-ja.pdf differ diff --git a/src/Assets/UnityTestTools/Docs/UnityTestTools-ja.pdf.meta b/src/Assets/UnityTestTools/Docs/UnityTestTools-ja.pdf.meta new file mode 100644 index 0000000..1a13ff0 --- /dev/null +++ b/src/Assets/UnityTestTools/Docs/UnityTestTools-ja.pdf.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: 13f9f9d67f694b54bb311e079f2e7d7a +DefaultImporter: + userData: diff --git a/src/Assets/UnityTestTools/IntegrationTestsFramework.meta b/src/Assets/UnityTestTools/IntegrationTestsFramework.meta new file mode 100644 index 0000000..da22872 --- /dev/null +++ b/src/Assets/UnityTestTools/IntegrationTestsFramework.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: 241054a0fe63fbb4bb51609fce9b3112 +folderAsset: yes +DefaultImporter: + userData: diff --git a/src/Assets/UnityTestTools/IntegrationTestsFramework/TestRunner.meta b/src/Assets/UnityTestTools/IntegrationTestsFramework/TestRunner.meta new file mode 100644 index 0000000..c65a67d --- /dev/null +++ b/src/Assets/UnityTestTools/IntegrationTestsFramework/TestRunner.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: da93545c3ab1aa043bcfb22281b1f66c +folderAsset: yes +DefaultImporter: + userData: diff --git a/src/Assets/UnityTestTools/IntegrationTestsFramework/TestRunner/Editor.meta b/src/Assets/UnityTestTools/IntegrationTestsFramework/TestRunner/Editor.meta new file mode 100644 index 0000000..bd38839 --- /dev/null +++ b/src/Assets/UnityTestTools/IntegrationTestsFramework/TestRunner/Editor.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: caee08596a5965747b8edfde19e2f873 +folderAsset: yes +DefaultImporter: + userData: diff --git a/src/Assets/UnityTestTools/IntegrationTestsFramework/TestRunner/Editor/Batch.cs b/src/Assets/UnityTestTools/IntegrationTestsFramework/TestRunner/Editor/Batch.cs new file mode 100644 index 0000000..048824b --- /dev/null +++ b/src/Assets/UnityTestTools/IntegrationTestsFramework/TestRunner/Editor/Batch.cs @@ -0,0 +1,96 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using UnityEditor; +using UnityEngine; +using UnityTest.IntegrationTests; + +namespace UnityTest +{ + public static partial class Batch + { + private const string testScenesParam = "-testscenes="; + private static string targetPlatformParam = "-targetPlatform="; + private static string resultFileDirParam = "-resultsFileDirectory="; + + public static void RunIntegrationTests () + { + var targetPlatform = GetTargetPlatform (); + var sceneList = GetTestScenesList (); + + if (targetPlatform.HasValue) + BuildAndRun (targetPlatform.Value, sceneList); + else + RunInEditor (sceneList); + } + + private static void BuildAndRun (BuildTarget target, List sceneList) + { + var resultFilePath = GetParameterArgument (resultFileDirParam); + PlatformRunner.BuildAndRunInPlayer (target, sceneList.ToArray (), "IntegrationTests", resultFilePath); + EditorApplication.Exit (0); + } + + private static void RunInEditor (List sceneList) + { + if (sceneList == null || sceneList.Count == 0) + { + Debug.Log ("No scenes on the list"); + EditorApplication.Exit (0); + return; + } + EditorBuildSettings.scenes = sceneList.Select (s => new EditorBuildSettingsScene (s, true)).ToArray (); + EditorApplication.OpenScene (sceneList.First ()); + GuiHelper.SetConsoleErrorPause (false); + EditorApplication.isPlaying = true; + } + + private static BuildTarget? GetTargetPlatform () + { + string platformString = null; + BuildTarget buildTarget; + foreach (var arg in Environment.GetCommandLineArgs ()) + { + if (arg.ToLower ().StartsWith (targetPlatformParam.ToLower ())) + { + platformString = arg.Substring (resultFilePathParam.Length); + break; + } + } + try + { + buildTarget = (BuildTarget) Enum.Parse (typeof (BuildTarget), platformString); + } + catch + { + return null; + } + return buildTarget; + } + + private static List GetTestScenesList () + { + var sceneList = new List (); + foreach (var arg in Environment.GetCommandLineArgs ()) + { + if (arg.ToLower ().StartsWith (testScenesParam)) + { + var scenesFromParam = arg.Substring (testScenesParam.Length).Split (','); + foreach (var scene in scenesFromParam) + { + var sceneName = scene; + if (!sceneName.EndsWith (".unity")) + sceneName += ".unity"; + var foundScenes = Directory.GetFiles (Directory.GetCurrentDirectory (), sceneName, SearchOption.AllDirectories); + if (foundScenes.Length == 1) + sceneList.Add (foundScenes[0].Substring (Directory.GetCurrentDirectory ().Length + 1)); + else + Debug.Log (sceneName + " not found or multiple entries found"); + } + } + } + return sceneList.Where (s => !string.IsNullOrEmpty (s)).Distinct ().ToList (); + } + } +} diff --git a/src/Assets/UnityTestTools/IntegrationTestsFramework/TestRunner/Editor/Batch.cs.meta b/src/Assets/UnityTestTools/IntegrationTestsFramework/TestRunner/Editor/Batch.cs.meta new file mode 100644 index 0000000..248a6ce --- /dev/null +++ b/src/Assets/UnityTestTools/IntegrationTestsFramework/TestRunner/Editor/Batch.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 29d4fb050362c5b43aea52342045543a +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/UnityTestTools/IntegrationTestsFramework/TestRunner/Editor/IntegrationTestsRunnerWindow.cs b/src/Assets/UnityTestTools/IntegrationTestsFramework/TestRunner/Editor/IntegrationTestsRunnerWindow.cs new file mode 100644 index 0000000..526dd7d --- /dev/null +++ b/src/Assets/UnityTestTools/IntegrationTestsFramework/TestRunner/Editor/IntegrationTestsRunnerWindow.cs @@ -0,0 +1,612 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using UnityEditor; +using UnityEngine; + +namespace UnityTest +{ + [Serializable] + public class IntegrationTestsRunnerWindow : EditorWindow + { + #region GUI Contents + private readonly GUIContent guiOptionsHideLabel = new GUIContent ("Hide", Icons.gearImg); + private readonly GUIContent guiOptionsShowLabel = new GUIContent ("Options", Icons.gearImg); + private readonly GUIContent guiCreateNewTest = new GUIContent (Icons.plusImg, "Create new test"); + private readonly GUIContent guiRunSelectedTests = new GUIContent (Icons.runImg, "Run selected test(s)"); + private readonly GUIContent guiRunAllTests = new GUIContent (Icons.runAllImg, "Run all tests"); + private readonly GUIContent guiAdvancedFilterShow = new GUIContent ("Advanced"); + private readonly GUIContent guiAdvancedFilterHide = new GUIContent ("Hide"); + private readonly GUIContent guiAddGOUderTest = new GUIContent ("Add GOs under test", "Add new GameObject under selected test"); + private readonly GUIContent guiBlockUI = new GUIContent ("Block UI when running", "Block UI when running tests"); + private readonly GUIContent guiShowSucceededTests = new GUIContent ("Succeeded", Icons.successImg, "Show tests that succeeded"); + private readonly GUIContent guiShowFailedTests = new GUIContent ("Failed", Icons.failImg, "Show tests that failed"); + private readonly GUIContent guiShowIgnoredTests = new GUIContent ("Ignored", Icons.ignoreImg, "Show tests that are ignored"); + private readonly GUIContent guiShowNotRunTests = new GUIContent ("Not Run", Icons.unknownImg, "Show tests that didn't run"); + #endregion + + #region runner steerign vars + private static IntegrationTestsRunnerWindow Instance = null; + [SerializeField] private List testsToRun; + [SerializeField] private List dynamicTestsToRun; + [SerializeField] private bool readyToRun; + private bool isCompiling; + private bool isBuilding; + public static bool selectedInHierarchy; + private float horizontalSplitBarPosition = 200; + private Vector2 testInfoScroll, testListScroll; + private IntegrationTestRendererBase[] testLines; + private string currectSceneName = null; + + [SerializeField] private GameObject selectedLine; + [SerializeField] private List resultList = new List (); + [SerializeField] private List foldMarkers = new List (); + + private bool showOptions; + private string filterString; + private bool showAdvancedFilter; + + private bool showSucceededTest = true; + private bool showFailedTest = true; + private bool showNotRunnedTest = true; + private bool showIgnoredTest = true; + private bool addNewGameObjectUnderSelectedTest; + private bool blockUIWhenRunning = true; + #endregion + + + + static IntegrationTestsRunnerWindow () + { + InitBackgroundRunners (); + } + + private static void InitBackgroundRunners () + { + EditorApplication.hierarchyWindowItemOnGUI -= OnHierarchyWindowItemDraw; + EditorApplication.hierarchyWindowItemOnGUI += OnHierarchyWindowItemDraw; + EditorApplication.hierarchyWindowChanged -= OnHierarchyChangeUpdate; + EditorApplication.hierarchyWindowChanged += OnHierarchyChangeUpdate; + EditorApplication.update -= BackgroundSceneChangeWatch; + EditorApplication.update += BackgroundSceneChangeWatch; + EditorApplication.playmodeStateChanged -= OnPlaymodeStateChanged; + EditorApplication.playmodeStateChanged += OnPlaymodeStateChanged; + } + + private static void OnPlaymodeStateChanged () + { + if (EditorApplication.isPlaying == EditorApplication.isPlayingOrWillChangePlaymode) + Instance.RebuildTestList (); + } + + public void OnDestroy () + { + EditorApplication.hierarchyWindowItemOnGUI -= OnHierarchyWindowItemDraw; + EditorApplication.update -= BackgroundSceneChangeWatch; + EditorApplication.hierarchyWindowChanged -= OnHierarchyChangeUpdate; + EditorApplication.playmodeStateChanged -= OnPlaymodeStateChanged; + + TestComponent.DestroyAllDynamicTests (); + } + + private static void BackgroundSceneChangeWatch () + { + if (Instance.currectSceneName != null && Instance.currectSceneName == EditorApplication.currentScene) return; + if (EditorApplication.isPlayingOrWillChangePlaymode) return; + TestComponent.DestroyAllDynamicTests (); + Instance.currectSceneName = EditorApplication.currentScene; + Instance.RebuildTestList (); + } + + public void OnEnable () + { + title = "Integration Tests Runner"; + Instance = this; + + if (EditorPrefs.HasKey ("ITR-addNewGameObjectUnderSelectedTest")) + { + addNewGameObjectUnderSelectedTest = EditorPrefs.GetBool ("ITR-addNewGameObjectUnderSelectedTest"); + blockUIWhenRunning = EditorPrefs.GetBool ("ITR-blockUIWhenRunning"); + showSucceededTest = EditorPrefs.GetBool ("ITR-showSucceededTest"); + showFailedTest = EditorPrefs.GetBool ("ITR-showFailedTest"); + showIgnoredTest = EditorPrefs.GetBool ("ITR-showIgnoredTest"); + showNotRunnedTest = EditorPrefs.GetBool ("ITR-showNotRunnedTest"); + } + + InitBackgroundRunners (); + if (!EditorApplication.isPlayingOrWillChangePlaymode && !readyToRun) RebuildTestList (); + } + + public void OnSelectionChange() + { + if ( EditorApplication.isPlayingOrWillChangePlaymode + || Selection.objects == null + || Selection.objects.Length == 0) return; + + if (Selection.gameObjects.Length == 1) + { + var go = Selection.gameObjects.Single (); + var temp = go.transform; + while (temp != null) + { + var tc = temp.GetComponent (); + if (tc != null) break; + temp = temp.parent; + } + + if (temp != null) + { + SelectInHierarchy (temp.gameObject); + Selection.activeGameObject = temp.gameObject; + selectedLine = temp.gameObject; + } + } + } + + public static void OnHierarchyChangeUpdate() + { + if (Instance.testLines == null || EditorApplication.isPlayingOrWillChangePlaymode) return; + + //create a test runner if it doesn't exist + TestRunner.GetTestRunner (); + + if (Instance.addNewGameObjectUnderSelectedTest + && Instance.selectedLine != null + && Selection.activeGameObject != null) + { + var go = Selection.activeGameObject; + if (go.transform.parent == null + && go.GetComponent () == null + && go.GetComponent () == null) + { + go.transform.parent = Instance.selectedLine.transform; + } + } + + //make tests are not places under a go that is not a test itself + foreach (var test in TestComponent.FindAllTestsOnScene ()) + { + if (test.gameObject.transform.parent != null && test.gameObject.transform.parent.gameObject.GetComponent () == null) + { + test.gameObject.transform.parent = null; + Debug.LogWarning ("Tests need to be on top of hierarchy or directly under another test."); + } + } + if (selectedInHierarchy) selectedInHierarchy = false; + else Instance.RebuildTestList (); + } + + public static void OnHierarchyWindowItemDraw ( int id, Rect rect ) + { + var o = EditorUtility.InstanceIDToObject (id); + if (o is GameObject) + { + var go = o as GameObject; + var tc = go.GetComponent (); + if (tc != null) + { + if (!EditorApplication.isPlayingOrWillChangePlaymode + && rect.Contains (Event.current.mousePosition) + && Event.current.type == EventType.MouseDown + && Event.current.button == 1) + { + IntegrationTestRendererBase.DrawContextMenu (tc); + } + + EditorGUIUtility.SetIconSize (new Vector2 (15, 15)); + var result = Instance.resultList.Find (r => r.GameObject == go); + if(result != null) + { + var icon = result.Executed ? GuiHelper.GetIconForResult (result.resultType) : Icons.unknownImg; + EditorGUI.LabelField (new Rect (rect.xMax - 18, rect.yMin - 2, rect.width, rect.height), new GUIContent(icon)); + } + EditorGUIUtility.SetIconSize (Vector2.zero); + } + + if (Event.current.type == EventType.MouseDown + && Event.current.button == 0 + && rect.Contains (Event.current.mousePosition)) + { + var temp = go.transform; + while (temp != null) + { + var c = temp.GetComponent (); + if (c != null) break; + temp = temp.parent; + } + if(temp!=null) SelectInHierarchy (temp.gameObject); + } + } + } + + private static void SelectInHierarchy ( GameObject gameObject ) + { + if (gameObject == Instance.selectedLine) return; + if (!gameObject.activeSelf) + { + selectedInHierarchy = true; + gameObject.SetActive (true); + } + + var tests = TestComponent.FindAllTestsOnScene (); + var skipList = gameObject.GetComponentsInChildren (typeof (TestComponent), true); + tests.RemoveAll (skipList.Contains); + foreach (var test in tests) + { + var enable = test.GetComponentsInChildren (typeof (TestComponent), true).Any (c => c.gameObject == gameObject); + if (test.gameObject.activeSelf != enable) test.gameObject.SetActive (enable); + } + } + + private void RunTests ( IList tests ) + { + if (!tests.Any () || EditorApplication.isCompiling || EditorApplication.isPlayingOrWillChangePlaymode) + return; + FocusWindowIfItsOpen (GetType ()); + + testsToRun = tests.Where(t=>t is TestComponent).Cast ().ToList (); + var temp = testsToRun.Where (t => t.dynamic).ToArray(); + dynamicTestsToRun = temp.Select (c => c.dynamicTypeName).ToList (); + testsToRun.RemoveAll (temp.Contains); + + readyToRun = true; + TestComponent.DisableAllTests (); + EditorApplication.isPlaying = true; + + if (blockUIWhenRunning) + EditorUtility.DisplayProgressBar ("Integration Test Runner", "Initializing", 0); + } + + public void Update() + { + if (readyToRun && EditorApplication.isPlaying) + { + readyToRun = false; + var testRunner = TestRunner.GetTestRunner(); + testRunner.TestRunnerCallback.Add (new RunnerCallback (this)); + testRunner.InitRunner (testsToRun.ToList (), dynamicTestsToRun); + } + } + + private void RebuildTestList () + { + testLines = null; + if (!TestComponent.AnyTestsOnScene ()) return; + + if (!EditorApplication.isPlayingOrWillChangePlaymode ) + { + var dynamicTestsOnScene = TestComponent.FindAllDynamicTestsOnScene (); + var dynamicTestTypes = TestComponent.GetTypesWithHelpAttribute (EditorApplication.currentScene); + + foreach (var dynamicTestType in dynamicTestTypes) + { + var existingTests = dynamicTestsOnScene.Where (component => component.dynamicTypeName == dynamicTestType.AssemblyQualifiedName); + if (existingTests.Any ()) + { + dynamicTestsOnScene.Remove (existingTests.Single ()); + continue; + } + TestComponent.CreateDynamicTest (dynamicTestType); + } + + foreach (var testComponent in dynamicTestsOnScene) + DestroyImmediate (testComponent.gameObject); + } + + var topTestList = TestComponent.FindAllTopTestsOnScene (); + + var newResultList = new List (); + testLines = ParseTestList (topTestList, newResultList); + + var oldDynamicResults = resultList.Where (result => result.dynamicTest); + foreach (var oldResult in resultList) + { + var result = newResultList.Find (r => r.Id == oldResult.Id); + if (result == null) continue; + result.Update (oldResult); + } + newResultList.AddRange (oldDynamicResults.Where ( r => !newResultList.Contains(r) )); + resultList = newResultList; + + IntegrationTestRendererBase.RunTest = RunTests; + IntegrationTestGroupLine.FoldMarkers = foldMarkers; + IntegrationTestLine.Results = resultList; + + foldMarkers.RemoveAll (o => o == null); + + selectedInHierarchy = true; + Repaint (); + } + + + + private IntegrationTestRendererBase[] ParseTestList ( List testList, List results ) + { + var tempList = new List (); + foreach (var testObject in testList) + { + if (!testObject.IsTestGroup ()) + { + var result = new TestResult (testObject); + if(results!=null) + results.Add (result); + tempList.Add (new IntegrationTestLine (testObject.gameObject, result)); + continue; + } + var group = new IntegrationTestGroupLine (testObject.gameObject); + var children = testObject.gameObject.GetComponentsInChildren (typeof (TestComponent), true).Cast ().ToList (); + children = children.Where(c => c.gameObject.transform.parent == testObject.gameObject.transform).ToList(); + group.AddChildren (ParseTestList (children, results)); + tempList.Add (group); + } + tempList.Sort (); + return tempList.ToArray (); + } + + public void OnGUI() + { + +#if !UNITY_4_0 && !UNITY_4_0_1 && !UNITY_4_1 && !UNITY_4_2 + if (BuildPipeline.isBuildingPlayer) + { + isBuilding = true; + } + else if (isBuilding) + { + isBuilding = false; + Repaint (); + } +#endif + PrintHeadPanel(); + + EditorGUILayout.BeginVertical (Styles.testList); + testListScroll = EditorGUILayout.BeginScrollView (testListScroll); + bool repaint = PrintTestList (testLines); + GUILayout.FlexibleSpace (); + EditorGUILayout.EndScrollView (); + EditorGUILayout.EndVertical (); + + RenderDetails (); + + if (repaint) Repaint (); + } + + public void PrintHeadPanel ( ) + { + GUILayout.Space (10); + EditorGUILayout.BeginHorizontal (); + var layoutOptions = new[] { GUILayout.Height(24), GUILayout.Width(32) }; + if (GUILayout.Button (guiRunAllTests, Styles.buttonLeft, layoutOptions) + && !EditorApplication.isPlayingOrWillChangePlaymode) + { + RunTests (TestComponent.FindAllTestsOnScene ().Cast ().ToList ()); + } + if (GUILayout.Button (guiRunSelectedTests, Styles.buttonMid, layoutOptions) + && !EditorApplication.isPlayingOrWillChangePlaymode) + { + RunTests (Selection.gameObjects.Select (t => t.GetComponent (typeof(TestComponent))).Cast ().ToList ()); + } + if (GUILayout.Button (guiCreateNewTest, Styles.buttonRight, layoutOptions) + && !EditorApplication.isPlayingOrWillChangePlaymode) + { + var test = TestComponent.CreateTest (); + if (Selection.gameObjects.Length == 1 + && Selection.activeGameObject != null + && Selection.activeGameObject.GetComponent ()) + { + test.transform.parent = Selection.activeGameObject.transform.parent; + } + Selection.activeGameObject = test; + RebuildTestList (); + } + GUILayout.FlexibleSpace (); + if (GUILayout.Button (showOptions ? guiOptionsHideLabel : guiOptionsShowLabel, GUILayout.Height (24), GUILayout.Width (80))) + showOptions = !showOptions; + EditorGUILayout.EndHorizontal (); + + if (showOptions) + PrintOptions (); + + EditorGUILayout.BeginHorizontal (); + EditorGUILayout.LabelField ("Filter:", GUILayout.Width (35)); + filterString = EditorGUILayout.TextField (filterString); + if (GUILayout.Button (showAdvancedFilter ? guiAdvancedFilterHide : guiAdvancedFilterShow, GUILayout.Width (80), GUILayout.Height (16))) + showAdvancedFilter = !showAdvancedFilter; + EditorGUILayout.EndHorizontal (); + + if (showAdvancedFilter) + PrintAdvancedFilter (); + } + + public void PrintOptions () + { + var style = EditorStyles.toggle; + EditorGUILayout.BeginVertical (); + EditorGUI.BeginChangeCheck (); + addNewGameObjectUnderSelectedTest = EditorGUILayout.Toggle (guiAddGOUderTest, addNewGameObjectUnderSelectedTest, style); + blockUIWhenRunning = EditorGUILayout.Toggle (guiBlockUI, blockUIWhenRunning, style); + if (EditorGUI.EndChangeCheck ()) + { + EditorPrefs.SetBool ("ITR-addNewGameObjectUnderSelectedTest", addNewGameObjectUnderSelectedTest); + EditorPrefs.SetBool ("ITR-blockUIWhenRunning", blockUIWhenRunning); + } + EditorGUILayout.EndVertical (); + } + + private void PrintAdvancedFilter () + { + EditorGUI.BeginChangeCheck (); + EditorGUILayout.BeginHorizontal (); + showSucceededTest = GUILayout.Toggle (showSucceededTest, guiShowSucceededTests, GUI.skin.FindStyle (GUI.skin.button.name + "left"), GUILayout.ExpandWidth (true)); + showFailedTest = GUILayout.Toggle (showFailedTest, guiShowFailedTests, GUI.skin.FindStyle (GUI.skin.button.name + "mid")); + showIgnoredTest = GUILayout.Toggle (showIgnoredTest, guiShowIgnoredTests, GUI.skin.FindStyle (GUI.skin.button.name + "mid")); + showNotRunnedTest = GUILayout.Toggle (showNotRunnedTest, guiShowNotRunTests, GUI.skin.FindStyle (GUI.skin.button.name + "right"), GUILayout.ExpandWidth (true)); + EditorGUILayout.EndHorizontal (); + if (EditorGUI.EndChangeCheck ()) + { + EditorPrefs.SetBool ("ITR-showSucceededTest", showSucceededTest); + EditorPrefs.SetBool ("ITR-showFailedTest", showFailedTest); + EditorPrefs.SetBool ("ITR-showIgnoredTest", showIgnoredTest); + EditorPrefs.SetBool ("ITR-showNotRunnedTest", showNotRunnedTest); + } + } + + private bool PrintTestList ( IntegrationTestRendererBase[] renderedLines ) + { + if (renderedLines == null) return false; + + var filter = new RenderingOptions (); + filter.showSucceeded = showSucceededTest; + filter.showFailed = showFailedTest; + filter.showNotRunned = showNotRunnedTest; + filter.showIgnored = showIgnoredTest; + filter.nameFilter = filterString; + + bool repaint = false; + foreach (var renderedLine in renderedLines) + { + repaint |= renderedLine.Render (filter); + } + return repaint; + } + + private void RenderDetails () + { + var ctrlId = EditorGUIUtility.GetControlID (FocusType.Passive); + + Rect rect = GUILayoutUtility.GetLastRect (); + rect.y = rect.height + rect.y - 1; + rect.height = 3; + + EditorGUIUtility.AddCursorRect (rect, MouseCursor.ResizeVertical ); + var e = Event.current; + switch (e.type) + { + case EventType.MouseDown: + if (EditorGUIUtility.hotControl == 0 && rect.Contains (e.mousePosition)) + EditorGUIUtility.hotControl = ctrlId; + break; + case EventType.MouseDrag: + if (EditorGUIUtility.hotControl == ctrlId) + { + horizontalSplitBarPosition -= e.delta.y; + if (horizontalSplitBarPosition < 20) horizontalSplitBarPosition = 20; + Repaint (); + } + break; + case EventType.MouseUp: + if (EditorGUIUtility.hotControl == ctrlId) + EditorGUIUtility.hotControl = 0; + break; + } + + testInfoScroll = EditorGUILayout.BeginScrollView (testInfoScroll, GUILayout.MinHeight (horizontalSplitBarPosition)); + + var message = ""; + + if (selectedLine != null) + message = GetResultText (selectedLine); + EditorGUILayout.TextArea (message, Styles.info); + EditorGUILayout.EndScrollView (); + } + + private string GetResultText (GameObject go) + { + var result = resultList.Find (r => r.GameObject == go); + if (result == null) return ""; + var messages = result.Name; + messages += "\n\n" + result.messages; + if (!string.IsNullOrEmpty (result.stacktrace)) + messages += "\n" + result.stacktrace; + return messages.Trim (); + } + + public void OnInspectorUpdate () + { + if(focusedWindow != this) Repaint (); + } + + private void SetCurrentTest ( TestComponent tc ) + { + foreach (var line in testLines) + line.SetCurrentTest (tc); + } + + class RunnerCallback : IntegrationTestRunner.ITestRunnerCallback + { + private IntegrationTestsRunnerWindow window; + private int testNumber=0; + private int currentTestNumber = 0; + + private bool consoleErrorOnPauseValue; + private bool runInBackground; + + public RunnerCallback(IntegrationTestsRunnerWindow window) + { + this.window = window; + + consoleErrorOnPauseValue = GuiHelper.GetConsoleErrorPause (); + GuiHelper.SetConsoleErrorPause (false); + runInBackground = PlayerSettings.runInBackground; + PlayerSettings.runInBackground = true; + } + + public void RunStarted (string platform, List testsToRun) + { + testNumber = testsToRun.Count; + foreach (var test in testsToRun) + { + var result = window.resultList.Find (r => r.TestComponent == test); + if (result != null) result.Reset (); + } + } + + public void RunFinished (List testResults) + { + window.SetCurrentTest(null); + EditorApplication.isPlaying = false; + EditorUtility.ClearProgressBar(); + GuiHelper.SetConsoleErrorPause (consoleErrorOnPauseValue); + PlayerSettings.runInBackground = runInBackground; + } + + public void TestStarted (TestResult test) + { + window.SetCurrentTest (test.TestComponent); + if (window.blockUIWhenRunning + && EditorUtility.DisplayCancelableProgressBar("Integration Test Runner", + "Running " + test.Name, + (float) currentTestNumber / testNumber)) + { + TestRunInterrupted (null); + } + } + + + public void TestFinished (TestResult test) + { + currentTestNumber++; + + var result = window.resultList.Find (r => r.Id == test.Id); + if(result!=null) + result.Update (test); + else + window.resultList.Add (test); + } + + public void TestRunInterrupted(List testsNotRun) + { + Debug.Log("Test run interrupted"); + RunFinished(new List()); + } + } + + [MenuItem ("Unity Test Tools/Integration Test Runner %#&t")] + public static IntegrationTestsRunnerWindow ShowWindow() + { + var w = GetWindow(typeof(IntegrationTestsRunnerWindow)); + w.Show(); + return w as IntegrationTestsRunnerWindow; + } + } +} diff --git a/src/Assets/UnityTestTools/IntegrationTestsFramework/TestRunner/Editor/IntegrationTestsRunnerWindow.cs.meta b/src/Assets/UnityTestTools/IntegrationTestsFramework/TestRunner/Editor/IntegrationTestsRunnerWindow.cs.meta new file mode 100644 index 0000000..86b5775 --- /dev/null +++ b/src/Assets/UnityTestTools/IntegrationTestsFramework/TestRunner/Editor/IntegrationTestsRunnerWindow.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 2c898357efb599944818326bb43ba879 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/UnityTestTools/IntegrationTestsFramework/TestRunner/Editor/PlatformRunner.meta b/src/Assets/UnityTestTools/IntegrationTestsFramework/TestRunner/Editor/PlatformRunner.meta new file mode 100644 index 0000000..f8df9bd --- /dev/null +++ b/src/Assets/UnityTestTools/IntegrationTestsFramework/TestRunner/Editor/PlatformRunner.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: c44e9167d633ee94bb6e078238178308 +folderAsset: yes +DefaultImporter: + userData: diff --git a/src/Assets/UnityTestTools/IntegrationTestsFramework/TestRunner/Editor/PlatformRunner/PlatformRunner.cs b/src/Assets/UnityTestTools/IntegrationTestsFramework/TestRunner/Editor/PlatformRunner/PlatformRunner.cs new file mode 100644 index 0000000..fa75587 --- /dev/null +++ b/src/Assets/UnityTestTools/IntegrationTestsFramework/TestRunner/Editor/PlatformRunner/PlatformRunner.cs @@ -0,0 +1,147 @@ +using System; +using System.IO; +using System.Linq; +using UnityEditor; +using UnityEngine; + +namespace UnityTest.IntegrationTests +{ + public class PlatformRunner + { + static string resourcesPath = Path.Combine ("Assets", "Resources"); + + public static BuildTarget defaultBuildTarget + { + get + { + var target = EditorPrefs.GetString ("ITR-platformRunnerBuildTarget"); + BuildTarget buildTarget; + try + { + buildTarget = (BuildTarget) Enum.Parse (typeof (BuildTarget), target); + } + catch + { + return GetDefaultBuildTarget (); + } + return buildTarget; + } + set { EditorPrefs.SetString ("ITR-platformRunnerBuildTarget", value.ToString ()); } + } + + [MenuItem ("Unity Test Tools/Platform Runner/Run current scene %#&r")] + public static void BuildAndRunCurrentScene () + { + Debug.Log ("Building and running current test for " + defaultBuildTarget); + BuildAndRunInPlayer (defaultBuildTarget, new string[0], null, null); + } + + [MenuItem ("Unity Test Tools/Platform Runner/Run on platform %#r")] + public static void RunInPlayer () + { + var w = EditorWindow.GetWindow (typeof (PlatformRunnerSettingsWindow)); + w.Show (); + } + + public static void BuildAndRunInPlayer (BuildTarget buildTarget, string[] scenes, string name, string resultFilePath) + { + var folderExisted = AddConfigurationFile (resultFilePath); + + var tempDisplayResolutionDialog = PlayerSettings.displayResolutionDialog; + PlayerSettings.displayResolutionDialog = ResolutionDialogSetting.Disabled; + var tempRunInBackground = PlayerSettings.runInBackground; + PlayerSettings.runInBackground = true; + var tempFullScreen = PlayerSettings.defaultIsFullScreen; + PlayerSettings.defaultIsFullScreen = false; + PlayerSettings.resizableWindow = true; + + BuildPipeline.BuildPlayer (scenes, + GetTempPath (buildTarget, name ?? Application.loadedLevelName), + buildTarget, + BuildOptions.AutoRunPlayer | BuildOptions.Development); + + + PlayerSettings.defaultIsFullScreen = tempFullScreen; + PlayerSettings.runInBackground = tempRunInBackground; + PlayerSettings.displayResolutionDialog = tempDisplayResolutionDialog; + + RemoveConfigurationFile (folderExisted); + } + + private static void RemoveConfigurationFile (bool directoryExisted) + { + var batchRunFileMarkerPath = Path.Combine (resourcesPath, TestRunner.batchRunFileMarker); + AssetDatabase.DeleteAsset (batchRunFileMarkerPath); + var configFilePath = Path.Combine (resourcesPath, TestRunner.integrationTestsConfigFileName); + AssetDatabase.DeleteAsset (configFilePath); + if (!directoryExisted) + AssetDatabase.DeleteAsset (resourcesPath); + } + + private static bool AddConfigurationFile (string resultFilePath) + { + var resDirExisted = Directory.Exists (resourcesPath); + if (!resDirExisted) + AssetDatabase.CreateFolder ("Assets", "Resources"); + if (UnityEditorInternal.InternalEditorUtility.inBatchMode) + { + var batchRunFileMarkerPath = Path.Combine (resourcesPath, TestRunner.batchRunFileMarker); + File.WriteAllText (batchRunFileMarkerPath, ""); + } + if (!string.IsNullOrEmpty (resultFilePath)) + { + if (!Directory.Exists (resultFilePath)) + Directory.CreateDirectory (resultFilePath); + var configFilePath = Path.Combine (resourcesPath, TestRunner.integrationTestsConfigFileName); + File.WriteAllText (configFilePath, resultFilePath); + } + AssetDatabase.Refresh (); + return resDirExisted; + } + + private static string GetTempPath (BuildTarget buildTarget, string name) + { + if (string.IsNullOrEmpty (name)) + name = Path.GetTempFileName (); + + var path = Path.Combine ("Temp", name); + switch (buildTarget) + { + case BuildTarget.StandaloneWindows: + case BuildTarget.StandaloneWindows64: + return path + ".exe"; + case BuildTarget.StandaloneOSXIntel: + return path + ".app"; + case BuildTarget.Android: + return path + ".apk"; + default: + return path; + } + } + + private static BuildTarget GetDefaultBuildTarget () + { + switch (EditorUserBuildSettings.selectedBuildTargetGroup) + { + case BuildTargetGroup.Android: + return BuildTarget.Android; + case BuildTargetGroup.WebPlayer: + return BuildTarget.WebPlayer; + case BuildTargetGroup.Standalone: + default: + { + switch (Application.platform) + { + case RuntimePlatform.WindowsPlayer: + return BuildTarget.StandaloneWindows; + case RuntimePlatform.OSXPlayer: + return BuildTarget.StandaloneOSXIntel; + case RuntimePlatform.LinuxPlayer: + return BuildTarget.StandaloneLinux; + } + return BuildTarget.WebPlayer; + } + } + } + } +} diff --git a/src/Assets/UnityTestTools/IntegrationTestsFramework/TestRunner/Editor/PlatformRunner/PlatformRunner.cs.meta b/src/Assets/UnityTestTools/IntegrationTestsFramework/TestRunner/Editor/PlatformRunner/PlatformRunner.cs.meta new file mode 100644 index 0000000..5ecced0 --- /dev/null +++ b/src/Assets/UnityTestTools/IntegrationTestsFramework/TestRunner/Editor/PlatformRunner/PlatformRunner.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: a3581fa3f207a8a4c9988b9f59a510d3 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/UnityTestTools/IntegrationTestsFramework/TestRunner/Editor/PlatformRunner/PlatformRunnerSettingsWindow.cs b/src/Assets/UnityTestTools/IntegrationTestsFramework/TestRunner/Editor/PlatformRunner/PlatformRunnerSettingsWindow.cs new file mode 100644 index 0000000..4749692 --- /dev/null +++ b/src/Assets/UnityTestTools/IntegrationTestsFramework/TestRunner/Editor/PlatformRunner/PlatformRunnerSettingsWindow.cs @@ -0,0 +1,105 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using UnityEditor; +using UnityEngine; + +namespace UnityTest.IntegrationTests +{ + public class PlatformRunnerSettingsWindow : EditorWindow + { + private BuildTarget buildTarget; + private List sceneList; + private Vector2 scrollPosition; + private string resultsPath; + private List selectedScenes = new List (); + + GUIContent label = new GUIContent ("Results target directory", "Directory where the results will be saved. If no value is specified, the results will be generated in project's data folder."); + + public PlatformRunnerSettingsWindow () + { + title = "Run on platform"; + buildTarget = PlatformRunner.defaultBuildTarget; + position.Set (position.xMin, position.yMin, 200, position.height); + sceneList = Directory.GetFiles (Directory.GetCurrentDirectory (), "*.unity", SearchOption.AllDirectories).ToList (); + sceneList.Sort(); + var currentScene = (Directory.GetCurrentDirectory () + EditorApplication.currentScene).Replace ("\\", "").Replace ("/", ""); + var currentScenePath = sceneList.Where (s => s.Replace ("\\", "").Replace ("/", "") == currentScene); + selectedScenes.AddRange (currentScenePath); + + resultsPath = EditorPrefs.GetString ("PR-resultsPath"); + } + + private void OnGUI () + { + EditorGUILayout.BeginVertical (); + + scrollPosition = EditorGUILayout.BeginScrollView (scrollPosition); + EditorGUILayout.LabelField ("List of scenes to build:", EditorStyles.boldLabel); + EditorGUI.indentLevel++; + foreach (var scenePath in sceneList) + { + var path = Path.GetFileNameWithoutExtension (scenePath); + var guiContent = new GUIContent (path, scenePath); + var rect = GUILayoutUtility.GetRect (guiContent, EditorStyles.label); + if (rect.Contains (Event.current.mousePosition)) + { + if (Event.current.type == EventType.mouseDown && Event.current.button == 0) + { + if (!Event.current.control) + selectedScenes.Clear (); + if (!selectedScenes.Contains (scenePath)) + selectedScenes.Add (scenePath); + else + selectedScenes.Remove (scenePath); + Event.current.Use (); + } + } + var style = new GUIStyle(EditorStyles.label); + if (selectedScenes.Contains (scenePath)) + style.normal.textColor = new Color (0.3f, 0.5f, 0.85f); + EditorGUI.LabelField (rect, guiContent, style); + } + EditorGUI.indentLevel--; + EditorGUILayout.EndScrollView (); + + GUILayout.Box ("", new[] {GUILayout.ExpandWidth (true), GUILayout.Height (1)}); + + buildTarget = (BuildTarget) EditorGUILayout.EnumPopup ("Build tests for", buildTarget); + + if (PlatformRunner.defaultBuildTarget != buildTarget) + { + if (GUILayout.Button ("Make default target platform")) + { + PlatformRunner.defaultBuildTarget = buildTarget; + } + } + DrawSetting (); + var build = GUILayout.Button ("Build and run tests"); + EditorGUILayout.EndVertical (); + + if (!build) return; + PlatformRunner.BuildAndRunInPlayer (buildTarget, selectedScenes.ToArray (), "IntegrationTests", resultsPath); + Close (); + } + + private void DrawSetting () + { + EditorGUI.BeginChangeCheck (); + resultsPath = EditorGUILayout.TextField (label, resultsPath); + if (EditorGUI.EndChangeCheck ()) + { + EditorPrefs.SetString ("PR-resultsPath", resultsPath); + } + if (!string.IsNullOrEmpty (resultsPath)) + { + Uri uri; + if (!Uri.TryCreate (resultsPath, UriKind.Absolute, out uri) || !uri.IsFile || uri.IsWellFormedOriginalString ()) + { + EditorGUILayout.HelpBox ("Invalid URI path", MessageType.Warning); + } + } + } + } +} diff --git a/src/Assets/UnityTestTools/IntegrationTestsFramework/TestRunner/Editor/PlatformRunner/PlatformRunnerSettingsWindow.cs.meta b/src/Assets/UnityTestTools/IntegrationTestsFramework/TestRunner/Editor/PlatformRunner/PlatformRunnerSettingsWindow.cs.meta new file mode 100644 index 0000000..8fed609 --- /dev/null +++ b/src/Assets/UnityTestTools/IntegrationTestsFramework/TestRunner/Editor/PlatformRunner/PlatformRunnerSettingsWindow.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 3819282b0887bc742911b89745080acb +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/UnityTestTools/IntegrationTestsFramework/TestRunner/Editor/Renderer.meta b/src/Assets/UnityTestTools/IntegrationTestsFramework/TestRunner/Editor/Renderer.meta new file mode 100644 index 0000000..374f5b4 --- /dev/null +++ b/src/Assets/UnityTestTools/IntegrationTestsFramework/TestRunner/Editor/Renderer.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: 5944b82e46f1682439d20b4c3a4f029c +folderAsset: yes +DefaultImporter: + userData: diff --git a/src/Assets/UnityTestTools/IntegrationTestsFramework/TestRunner/Editor/Renderer/IntegrationTestGroupLine.cs b/src/Assets/UnityTestTools/IntegrationTestsFramework/TestRunner/Editor/Renderer/IntegrationTestGroupLine.cs new file mode 100644 index 0000000..c628c78 --- /dev/null +++ b/src/Assets/UnityTestTools/IntegrationTestsFramework/TestRunner/Editor/Renderer/IntegrationTestGroupLine.cs @@ -0,0 +1,87 @@ +using System.Collections.Generic; +using System.Linq; +using UnityEditor; +using UnityEngine; + +namespace UnityTest +{ + class IntegrationTestGroupLine : IntegrationTestRendererBase + { + public static List FoldMarkers; + private IntegrationTestRendererBase[] children; + + public IntegrationTestGroupLine (GameObject gameObject) : base (gameObject) + { + } + + protected internal override void DrawLine ( Rect rect, GUIContent label, bool isSelected, RenderingOptions options ) + { + EditorGUILayout.BeginHorizontal (); + + EditorGUI.BeginChangeCheck (); + var isClassFolded = !EditorGUI.Foldout (rect, !Folded, label , isSelected ? Styles.selectedFoldout : Styles.foldout); + if (EditorGUI.EndChangeCheck ()) Folded = isClassFolded; + + EditorGUILayout.EndHorizontal (); + } + + private bool Folded + { + get { return FoldMarkers.Contains (gameObject); } + + set + { + if (value) FoldMarkers.Add (gameObject); + else FoldMarkers.RemoveAll (s => s == gameObject); + } + } + + protected internal override void Render ( int indend, RenderingOptions options ) + { + base.Render (indend, options); + if (!Folded) + foreach (var child in children) + child.Render (indend + 1, options); + } + + protected internal override TestResult.ResultType GetResult () + { + bool ignored = false; + bool success = false; + foreach (var child in children) + { + var result = child.GetResult (); + + if (result == TestResult.ResultType.Failed || result == TestResult.ResultType.FailedException || result == TestResult.ResultType.Timeout) + return TestResult.ResultType.Failed; + if (result == TestResult.ResultType.Success) + success = true; + else if (result == TestResult.ResultType.Ignored) + ignored = true; + else + ignored = false; + } + if(success) return TestResult.ResultType.Success; + if(ignored) return TestResult.ResultType.Ignored; + return TestResult.ResultType.NotRun; + } + + protected internal override bool IsVisible (RenderingOptions options) + { + return children.Any (c => c.IsVisible (options)); + } + + public override bool SetCurrentTest (TestComponent tc) + { + IsRunning = false; + foreach (var child in children) + IsRunning |= child.SetCurrentTest (tc); + return IsRunning; + } + + public void AddChildren ( IntegrationTestRendererBase[] parseTestList ) + { + children = parseTestList; + } + } +} diff --git a/src/Assets/UnityTestTools/IntegrationTestsFramework/TestRunner/Editor/Renderer/IntegrationTestGroupLine.cs.meta b/src/Assets/UnityTestTools/IntegrationTestsFramework/TestRunner/Editor/Renderer/IntegrationTestGroupLine.cs.meta new file mode 100644 index 0000000..0051064 --- /dev/null +++ b/src/Assets/UnityTestTools/IntegrationTestsFramework/TestRunner/Editor/Renderer/IntegrationTestGroupLine.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: f6dc74195aa98ef4da8901199cda4a63 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/UnityTestTools/IntegrationTestsFramework/TestRunner/Editor/Renderer/IntegrationTestLine.cs b/src/Assets/UnityTestTools/IntegrationTestsFramework/TestRunner/Editor/Renderer/IntegrationTestLine.cs new file mode 100644 index 0000000..183f3c3 --- /dev/null +++ b/src/Assets/UnityTestTools/IntegrationTestsFramework/TestRunner/Editor/Renderer/IntegrationTestLine.cs @@ -0,0 +1,57 @@ +using System.Collections.Generic; +using UnityEditor; +using UnityEngine; + +namespace UnityTest +{ + class IntegrationTestLine : IntegrationTestRendererBase + { + public static List Results; + protected TestResult result; + + public IntegrationTestLine (GameObject gameObject, TestResult testResult) : base (gameObject) + { + this.result = testResult; + } + + protected internal override void DrawLine ( Rect rect, GUIContent label, bool isSelected, RenderingOptions options ) + { + EditorGUILayout.BeginHorizontal (); + rect.x += 10; + + EditorGUI.LabelField (rect, label, isSelected ? Styles.selectedLabel : Styles.label); + + if (result.IsTimeout) + { + var timeoutRect = new Rect(rect); + timeoutRect.x = timeoutRect.x + timeoutRect.width; + timeoutRect.width = 24; + EditorGUI.LabelField (timeoutRect, guiTimeoutIcon); + GUILayout.FlexibleSpace (); + } + EditorGUILayout.EndHorizontal (); + } + + protected internal override TestResult.ResultType GetResult () + { + if(!result.Executed && test.ignored) return TestResult.ResultType.Ignored; + return result.resultType; + } + + protected internal override bool IsVisible (RenderingOptions options) + { + if (!string.IsNullOrEmpty (options.nameFilter) && !gameObject.name.ToLower ().Contains (options.nameFilter.ToLower ())) return false; + if (!options.showSucceeded && result.IsSuccess) return false; + if (!options.showFailed && result.IsFailure) return false; + if (!options.showNotRunned && !result.Executed) return false; + if (!options.showIgnored && test.ignored) return false; + return true; + } + + public override bool SetCurrentTest (TestComponent tc) + { + IsRunning = test == tc; + return IsRunning; + } + } +} diff --git a/src/Assets/UnityTestTools/IntegrationTestsFramework/TestRunner/Editor/Renderer/IntegrationTestLine.cs.meta b/src/Assets/UnityTestTools/IntegrationTestsFramework/TestRunner/Editor/Renderer/IntegrationTestLine.cs.meta new file mode 100644 index 0000000..25c9f11 --- /dev/null +++ b/src/Assets/UnityTestTools/IntegrationTestsFramework/TestRunner/Editor/Renderer/IntegrationTestLine.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 212be02e4a7da194688b08ab0c946fbd +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/UnityTestTools/IntegrationTestsFramework/TestRunner/Editor/Renderer/IntegrationTestRendererBase.cs b/src/Assets/UnityTestTools/IntegrationTestsFramework/TestRunner/Editor/Renderer/IntegrationTestRendererBase.cs new file mode 100644 index 0000000..802d76c --- /dev/null +++ b/src/Assets/UnityTestTools/IntegrationTestsFramework/TestRunner/Editor/Renderer/IntegrationTestRendererBase.cs @@ -0,0 +1,146 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using UnityEditor; +using UnityEngine; +using Event = UnityEngine.Event; +using Object = UnityEngine.Object; + +namespace UnityTest +{ + public abstract class IntegrationTestRendererBase : IComparable + { + public static Action> RunTest; + + protected static bool refresh; + + private static GUIContent guiRunSelected = new GUIContent ("Run Selected"); + private static GUIContent guiRun = new GUIContent ("Run"); + private static GUIContent guiDelete = new GUIContent ("Delete"); + private static GUIContent guiDeleteSelected = new GUIContent ("Delete selected"); + + protected static GUIContent guiTimeoutIcon = new GUIContent (Icons.stopwatchImg, "Timeout"); + + protected GameObject gameObject; + public TestComponent test; + private string name; + + protected IntegrationTestRendererBase ( GameObject gameObject ) + { + this.test = gameObject.GetComponent (typeof (TestComponent)) as TestComponent; + if (test == null) throw new ArgumentException ("Provided GameObject is not a test object"); + this.gameObject = gameObject; + this.name = test.Name; + } + + public int CompareTo (IntegrationTestRendererBase other) + { + return test.CompareTo (other.test); + } + + public bool Render (RenderingOptions options) + { + refresh = false; + EditorGUIUtility.SetIconSize (new Vector2 (15, 15)); + Render (0, options); + EditorGUIUtility.SetIconSize (Vector2.zero); + return refresh; + } + + protected internal virtual void Render (int indend, RenderingOptions options) + { + if (!IsVisible (options)) return; + EditorGUILayout.BeginHorizontal (); + GUILayout.Space (indend * 10); + + var tempColor = GUI.color; + if (IsRunning) + { + var frame = Mathf.Abs (Mathf.Cos (Time.realtimeSinceStartup * 4)) * 0.6f + 0.4f; + GUI.color = new Color (1, 1, 1, frame); + } + + var isSelected = Selection.gameObjects.Contains (gameObject); + + var value = GetResult (); + var icon = GuiHelper.GetIconForResult (value); + + var label = new GUIContent (name, icon); + var labelRect = GUILayoutUtility.GetRect (label, EditorStyles.label, GUILayout.ExpandWidth (true), GUILayout.Height (18)); + + OnLeftMouseButtonClick (labelRect); + OnContextClick (labelRect); + DrawLine (labelRect, label, isSelected, options); + + if (IsRunning) GUI.color = tempColor; + EditorGUILayout.EndHorizontal (); + } + + protected void OnSelect () + { + if (!Event.current.control) Selection.objects = new UnityEngine.Object[0]; + + if (Event.current.control && Selection.gameObjects.Contains (test.gameObject)) + Selection.objects = Selection.gameObjects.Where (o => o != test.gameObject).ToArray (); + else + Selection.objects = Selection.gameObjects.Concat (new[] { test.gameObject }).ToArray (); + } + + protected void OnLeftMouseButtonClick ( Rect rect ) + { + if (rect.Contains (Event.current.mousePosition) && Event.current.type == EventType.mouseDown && Event.current.button == 0) + { + rect.width = 20; + if (rect.Contains (Event.current.mousePosition)) return; + Event.current.Use (); + OnSelect (); + } + } + + protected void OnContextClick ( Rect rect ) + { + if (rect.Contains (Event.current.mousePosition) && Event.current.type == EventType.ContextClick) + { + DrawContextMenu (test); + } + } + + public static void DrawContextMenu ( TestComponent testComponent ) + { + if (EditorApplication.isPlayingOrWillChangePlaymode) return; + + var selectedTests = Selection.gameObjects.Where (go => go.GetComponent (typeof (TestComponent))); + var manySelected = selectedTests.Count () > 1; + + var m = new GenericMenu (); + if (manySelected) + { + //var testsToRun + m.AddItem (guiRunSelected, false, data => RunTest (selectedTests.Select(o => o.GetComponent (typeof (TestComponent))).Cast ().ToList ()), null); + } + m.AddItem (guiRun, false, data => RunTest (new[] { testComponent }), null); + m.AddSeparator (""); + m.AddItem (manySelected ? guiDeleteSelected : guiDelete, false, data => RemoveTests (selectedTests.ToArray ()), null); + m.ShowAsContext (); + } + + private static void RemoveTests (GameObject[] testsToDelete) + { + foreach (var t in testsToDelete) + { +#if UNITY_4_0 || UNITY_4_0_1 || UNITY_4_1 || UNITY_4_2 + Undo.RegisterSceneUndo ("Destroy Tests"); + GameObject.DestroyImmediate (t); +#else + Undo.DestroyObjectImmediate (t); +#endif + } + } + + protected internal bool IsRunning; + protected internal abstract void DrawLine ( Rect rect, GUIContent label, bool isSelected, RenderingOptions options ); + protected internal abstract TestResult.ResultType GetResult (); + protected internal abstract bool IsVisible (RenderingOptions options); + public abstract bool SetCurrentTest (TestComponent tc); + } +} diff --git a/src/Assets/UnityTestTools/IntegrationTestsFramework/TestRunner/Editor/Renderer/IntegrationTestRendererBase.cs.meta b/src/Assets/UnityTestTools/IntegrationTestsFramework/TestRunner/Editor/Renderer/IntegrationTestRendererBase.cs.meta new file mode 100644 index 0000000..1fb186e --- /dev/null +++ b/src/Assets/UnityTestTools/IntegrationTestsFramework/TestRunner/Editor/Renderer/IntegrationTestRendererBase.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 604645a3b57179a4d873906b625ef8ec +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/UnityTestTools/IntegrationTestsFramework/TestRunner/Editor/TestComponentEditor.cs b/src/Assets/UnityTestTools/IntegrationTestsFramework/TestRunner/Editor/TestComponentEditor.cs new file mode 100644 index 0000000..2cc970a --- /dev/null +++ b/src/Assets/UnityTestTools/IntegrationTestsFramework/TestRunner/Editor/TestComponentEditor.cs @@ -0,0 +1,119 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using UnityEditor; +using UnityEngine; + +namespace UnityTest +{ + [CanEditMultipleObjects] + [CustomEditor (typeof (TestComponent))] + public class TestComponentEditor : Editor + { + private SerializedProperty expectException; + private SerializedProperty expectedExceptionList; + private SerializedProperty ignored; + private SerializedProperty succeedAssertions; + private SerializedProperty succeedWhenExceptionIsThrown; + private SerializedProperty timeout; + + #region GUI Contens + + private readonly GUIContent guiExpectException = new GUIContent ("Expect exception", "Should the test expect an exception"); + private readonly GUIContent guiExpectExceptionList = new GUIContent ("Expected exception list", "A comma separated list of exception types which will not fail the test when thrown"); + private readonly GUIContent guiIgnore = new GUIContent ("Ignore", "Ignore the tests in runs"); + private readonly GUIContent guiIncludePlatforms = new GUIContent ("Included platforms", "Platform on which the test should run"); + private readonly GUIContent guiSuccedOnAssertions = new GUIContent ("Succeed on assertions", "Succeed after all assertions are executed"); + private readonly GUIContent guiSucceedWhenExceptionIsThrown = new GUIContent ("Succeed when exception is thrown", "Should the test succeed when an expected exception is thrown"); + private readonly GUIContent guiTestName = new GUIContent ("Test name", "Name of the test (is equal to the GameObject name)"); + private readonly GUIContent guiTimeout = new GUIContent ("Timeout", "Number of seconds after which the test will timeout"); + + #endregion + + public void OnEnable () + { + timeout = serializedObject.FindProperty ("timeout"); + ignored = serializedObject.FindProperty ("ignored"); + succeedAssertions = serializedObject.FindProperty ("succeedAfterAllAssertionsAreExecuted"); + expectException = serializedObject.FindProperty ("expectException"); + expectedExceptionList = serializedObject.FindProperty ("expectedExceptionList"); + succeedWhenExceptionIsThrown = serializedObject.FindProperty ("succeedWhenExceptionIsThrown"); + } + + public override void OnInspectorGUI () + { + var component = (TestComponent) target; + + if (component.dynamic && GUILayout.Button ("Reload dynamic tests")) + { + TestComponent.DestroyAllDynamicTests (); + Selection.objects = new UnityEngine.Object[0]; + IntegrationTestsRunnerWindow.selectedInHierarchy = false; + return; + } + + if (component.IsTestGroup ()) + { + EditorGUI.BeginChangeCheck (); + var newGroupName = EditorGUILayout.TextField (guiTestName, component.name); + if (EditorGUI.EndChangeCheck ()) component.name = newGroupName; + + serializedObject.ApplyModifiedProperties (); + return; + } + + serializedObject.Update (); + + EditorGUI.BeginDisabledGroup (serializedObject.isEditingMultipleObjects); + + EditorGUI.BeginChangeCheck (); + var newName = EditorGUILayout.TextField (guiTestName, component.name); + if (EditorGUI.EndChangeCheck ()) component.name = newName; + + if (component.platformsToIgnore == null) + { + component.platformsToIgnore = GetListOfIgnoredPlatforms (Enum.GetNames (typeof (TestComponent.IncludedPlatforms)), (int)component.includedPlatforms); + } + + var enumList = Enum.GetNames (typeof (RuntimePlatform)); + var flags = GetFlagList (enumList, component.platformsToIgnore); + flags = EditorGUILayout.MaskField (guiIncludePlatforms, flags, enumList, EditorStyles.popup); + var newList = GetListOfIgnoredPlatforms (enumList, flags); + if (!component.dynamic) + component.platformsToIgnore = newList; + EditorGUI.EndDisabledGroup (); + + EditorGUILayout.PropertyField (timeout, guiTimeout); + EditorGUILayout.PropertyField (ignored, guiIgnore); + EditorGUILayout.PropertyField (succeedAssertions, guiSuccedOnAssertions); + EditorGUILayout.PropertyField (expectException, guiExpectException); + + EditorGUI.BeginDisabledGroup (!expectException.boolValue); + EditorGUILayout.PropertyField (expectedExceptionList, guiExpectExceptionList); + EditorGUILayout.PropertyField (succeedWhenExceptionIsThrown, guiSucceedWhenExceptionIsThrown); + EditorGUI.EndDisabledGroup (); + + if (!component.dynamic) serializedObject.ApplyModifiedProperties (); + } + + private string[] GetListOfIgnoredPlatforms (string[] enumList, int flags) + { + var notSelectedPlatforms = new List (); + for (int i = 0; i < enumList.Length; i++) + { + var sel = (flags & (1 << i)) != 0; + if (!sel) notSelectedPlatforms.Add (enumList[i]); + } + return notSelectedPlatforms.ToArray (); + } + + private int GetFlagList ( string[] enumList, string[] platformsToIgnore ) + { + int flags = ~0; + for (int i = 0; i < enumList.Length; i++) + if (platformsToIgnore != null && platformsToIgnore.Any (s => s == enumList[i])) + flags &= ~(1 << i); + return flags; + } + } +} diff --git a/src/Assets/UnityTestTools/IntegrationTestsFramework/TestRunner/Editor/TestComponentEditor.cs.meta b/src/Assets/UnityTestTools/IntegrationTestsFramework/TestRunner/Editor/TestComponentEditor.cs.meta new file mode 100644 index 0000000..e3a1348 --- /dev/null +++ b/src/Assets/UnityTestTools/IntegrationTestsFramework/TestRunner/Editor/TestComponentEditor.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 160889f21f4d5944b9f6fcaf9c33f684 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/UnityTestTools/IntegrationTestsFramework/TestRunner/ITestRunnerCallback.cs b/src/Assets/UnityTestTools/IntegrationTestsFramework/TestRunner/ITestRunnerCallback.cs new file mode 100644 index 0000000..a1f10b9 --- /dev/null +++ b/src/Assets/UnityTestTools/IntegrationTestsFramework/TestRunner/ITestRunnerCallback.cs @@ -0,0 +1,13 @@ +using System.Collections.Generic; + +namespace UnityTest.IntegrationTestRunner +{ + public interface ITestRunnerCallback + { + void RunStarted (string platform, List testsToRun); + void RunFinished (List testResults); + void TestStarted (TestResult test); + void TestFinished (TestResult test); + void TestRunInterrupted (List testsNotRun); + } +} diff --git a/src/Assets/UnityTestTools/IntegrationTestsFramework/TestRunner/ITestRunnerCallback.cs.meta b/src/Assets/UnityTestTools/IntegrationTestsFramework/TestRunner/ITestRunnerCallback.cs.meta new file mode 100644 index 0000000..3a1c54b --- /dev/null +++ b/src/Assets/UnityTestTools/IntegrationTestsFramework/TestRunner/ITestRunnerCallback.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 35af7d395e501a348ae1a0aa3c91dee4 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/UnityTestTools/IntegrationTestsFramework/TestRunner/IntegrationTest.cs b/src/Assets/UnityTestTools/IntegrationTestsFramework/TestRunner/IntegrationTest.cs new file mode 100644 index 0000000..d06aaac --- /dev/null +++ b/src/Assets/UnityTestTools/IntegrationTestsFramework/TestRunner/IntegrationTest.cs @@ -0,0 +1,141 @@ +using System; +using System.IO; +using System.Linq; +using UnityEngine; + +public static class IntegrationTest +{ + public const string passMessage = "IntegrationTest Pass"; + public const string failMessage = "IntegrationTest Fail"; + + public static void Pass (GameObject go) + { + go = FindTopGameObject (go); + LogResult (go, passMessage); + } + + public static void Fail (GameObject go, string reason) + { + Fail (go); + if(!string.IsNullOrEmpty (reason)) Debug.Log (reason); + } + + public static void Fail (GameObject go) + { + go = FindTopGameObject (go); + LogResult (go, failMessage); + } + + public static void Assert ( GameObject go, bool condition ) + { + Assert (go, condition, ""); + } + + public static void Assert ( GameObject go, bool condition, string message ) + { + if(condition) Pass (go); + else Fail (go, message); + } + + private static void LogResult (GameObject go, string message) + { + Debug.Log (message + " (" + FindTopGameObject (go).name + ")", + go); + } + + private static GameObject FindTopGameObject (GameObject go) + { + while (go.transform.parent != null) + go = go.transform.parent.gameObject; + return go; + } + + #region Dynamic test attributes + + [AttributeUsage (AttributeTargets.Class, AllowMultiple = false)] + public class ExcludePlatformAttribute : Attribute + { + public string[] platformsToExclude; + + public ExcludePlatformAttribute (params RuntimePlatform[] platformsToExclude) + { + this.platformsToExclude = platformsToExclude.Select (platform => platform.ToString ()).ToArray (); + } + } + + [AttributeUsage (AttributeTargets.Class, AllowMultiple = false)] + public class ExpectExceptions : Attribute + { + public string[] exceptionTypeNames; + public bool succeedOnException; + + public ExpectExceptions () : this (false) + { + } + + public ExpectExceptions (bool succeedOnException) : this (succeedOnException, new string[0]) + { + } + + public ExpectExceptions (bool succeedOnException, params string[] exceptionTypeNames) + { + this.succeedOnException = succeedOnException; + this.exceptionTypeNames = exceptionTypeNames; + } + + public ExpectExceptions (bool succeedOnException, params Type[] exceptionTypes) + : this (succeedOnException, exceptionTypes.Select (type => type.FullName).ToArray ()) + { + } + + public ExpectExceptions (params string[] exceptionTypeNames) : this (false, exceptionTypeNames) + { + } + + public ExpectExceptions (params Type[] exceptionTypes) : this (false, exceptionTypes) + { + } + } + + [AttributeUsage (AttributeTargets.Class, AllowMultiple = false)] + public class IgnoreAttribute : Attribute + { + } + + [AttributeUsage (AttributeTargets.Class, AllowMultiple = false)] + public class DynamicTestAttribute : Attribute + { + private string sceneName; + + public DynamicTestAttribute (string sceneName) + { + if (sceneName.EndsWith (".unity")) + sceneName = sceneName.Substring (0, sceneName.Length - ".unity".Length); + this.sceneName = sceneName; + } + + public bool IncludeOnScene (string sceneName) + { + var fileName = Path.GetFileNameWithoutExtension (sceneName); + return fileName == this.sceneName; + } + } + + [AttributeUsage (AttributeTargets.Class, AllowMultiple = false)] + public class SucceedWithAssertions : Attribute + { + } + + [AttributeUsage (AttributeTargets.Class, AllowMultiple = false)] + public class TimeoutAttribute : Attribute + { + public float timeout; + + public TimeoutAttribute (float seconds) + { + this.timeout = seconds; + } + } + + #endregion +} diff --git a/src/Assets/UnityTestTools/IntegrationTestsFramework/TestRunner/IntegrationTest.cs.meta b/src/Assets/UnityTestTools/IntegrationTestsFramework/TestRunner/IntegrationTest.cs.meta new file mode 100644 index 0000000..b6974b8 --- /dev/null +++ b/src/Assets/UnityTestTools/IntegrationTestsFramework/TestRunner/IntegrationTest.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: eb367bbc76e489443a4ebc8b0a8642f4 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/UnityTestTools/IntegrationTestsFramework/TestRunner/IntegrationTestAttribute.cs b/src/Assets/UnityTestTools/IntegrationTestsFramework/TestRunner/IntegrationTestAttribute.cs new file mode 100644 index 0000000..daccacd --- /dev/null +++ b/src/Assets/UnityTestTools/IntegrationTestsFramework/TestRunner/IntegrationTestAttribute.cs @@ -0,0 +1,23 @@ +using System; +using System.IO; + +[AttributeUsage (AttributeTargets.Class, AllowMultiple = false)] +public class IntegrationTestAttribute : Attribute +{ + private string path; + + public IntegrationTestAttribute (string path) + { + if (path.EndsWith (".unity")) + path = path.Substring (0, path.Length - ".unity".Length); + this.path = path; + } + + public bool IncludeOnScene ( string scenePath ) + { + if (scenePath == path) return true; + var fileName = Path.GetFileNameWithoutExtension (scenePath); + return fileName == path; + } + +} diff --git a/src/Assets/UnityTestTools/IntegrationTestsFramework/TestRunner/IntegrationTestAttribute.cs.meta b/src/Assets/UnityTestTools/IntegrationTestsFramework/TestRunner/IntegrationTestAttribute.cs.meta new file mode 100644 index 0000000..1c80721 --- /dev/null +++ b/src/Assets/UnityTestTools/IntegrationTestsFramework/TestRunner/IntegrationTestAttribute.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: f1a5c61a06ed66e41a6ee1b5f88b5afd +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/UnityTestTools/IntegrationTestsFramework/TestRunner/IntegrationTestsProvider.cs b/src/Assets/UnityTestTools/IntegrationTestsFramework/TestRunner/IntegrationTestsProvider.cs new file mode 100644 index 0000000..db49efd --- /dev/null +++ b/src/Assets/UnityTestTools/IntegrationTestsFramework/TestRunner/IntegrationTestsProvider.cs @@ -0,0 +1,112 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using UnityEngine; + +namespace UnityTest.IntegrationTestRunner +{ + class IntegrationTestsProvider + { + internal Dictionary> testCollection = new Dictionary> (); + internal ITestComponent currentTestGroup; + internal IEnumerable testToRun; + + public IntegrationTestsProvider ( IEnumerable tests ) + { + testToRun = tests; + foreach (var test in tests.OrderBy (component => component)) + { + if (test.IsTestGroup ()) + { + throw new Exception (test.Name + " is test a group"); + } + AddTestToList (test); + } + if (currentTestGroup == null) + { + currentTestGroup = FindInnerTestGroup (TestComponent.NullTestComponent); + } + } + + private void AddTestToList (ITestComponent test) + { + var group = test.GetTestGroup (); + if (!testCollection.ContainsKey (group)) + testCollection.Add (group, new HashSet ()); + testCollection[group].Add (test); + if (group == TestComponent.NullTestComponent) return; + AddTestToList (group); + } + + public ITestComponent GetNextTest () + { + var test = testCollection[currentTestGroup].First (); + testCollection[currentTestGroup].Remove (test); + test.EnableTest(true); + return test; + } + + public void FinishTest (ITestComponent test) + { + try + { + test.EnableTest (false); + currentTestGroup = FindNextTestGroup (currentTestGroup); + } + catch (MissingReferenceException e) + { + Debug.LogException(e); + return; + } + } + + private ITestComponent FindNextTestGroup ( ITestComponent testGroup ) + { + if (testGroup != null) + { + if (testCollection[testGroup].Any ()) + { + testGroup.EnableTest (true); + return FindInnerTestGroup (testGroup); + } + testCollection.Remove (testGroup); + testGroup.EnableTest (false); + + var parentTestGroup = testGroup.GetTestGroup (); + if (parentTestGroup == null) return null; + + testCollection[parentTestGroup].Remove (testGroup); + return FindNextTestGroup(parentTestGroup); + } + throw new Exception ("No test left"); + } + + private ITestComponent FindInnerTestGroup ( ITestComponent group ) + { + var innerGroups = testCollection[group]; + foreach (var innerGroup in innerGroups) + { + if (!innerGroup.IsTestGroup()) continue; + innerGroup.EnableTest(true); + return FindInnerTestGroup (innerGroup); + } + return group; + } + + public bool AnyTestsLeft () + { + return testCollection.Count != 0; + } + + public List GetRemainingTests () + { + var remainingTests = new List (); + foreach (var test in testCollection) + { + remainingTests.AddRange (test.Value); + } + return remainingTests; + } + } +} diff --git a/src/Assets/UnityTestTools/IntegrationTestsFramework/TestRunner/IntegrationTestsProvider.cs.meta b/src/Assets/UnityTestTools/IntegrationTestsFramework/TestRunner/IntegrationTestsProvider.cs.meta new file mode 100644 index 0000000..d444629 --- /dev/null +++ b/src/Assets/UnityTestTools/IntegrationTestsFramework/TestRunner/IntegrationTestsProvider.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 21d32637b19ee51489062a66ad922193 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/UnityTestTools/IntegrationTestsFramework/TestRunner/TestComponent.cs b/src/Assets/UnityTestTools/IntegrationTestsFramework/TestRunner/TestComponent.cs new file mode 100644 index 0000000..b8c0dc0 --- /dev/null +++ b/src/Assets/UnityTestTools/IntegrationTestsFramework/TestRunner/TestComponent.cs @@ -0,0 +1,370 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using UnityEngine; + +namespace UnityTest +{ + public interface ITestComponent : IComparable + { + void EnableTest (bool enable); + bool IsTestGroup (); + GameObject gameObject { get; } + string Name { get; } + ITestComponent GetTestGroup (); + bool IsExceptionExpected (string exceptionType); + bool ShouldSucceedOnException (); + double GetTimeout (); + bool IsIgnored (); + bool ShouldSucceedOnAssertions (); + bool IsExludedOnThisPlatform (); + } + + public class TestComponent : MonoBehaviour, ITestComponent + { + public static ITestComponent NullTestComponent = new NullTestComponentImpl (); + + public float timeout = 5; + public bool ignored = false; + public bool succeedAfterAllAssertionsAreExecuted = false; + public bool expectException = false; + public string expectedExceptionList = ""; + public bool succeedWhenExceptionIsThrown = false; + public IncludedPlatforms includedPlatforms = (IncludedPlatforms) ~0L; + public string[] platformsToIgnore = null; + + public bool dynamic; + public string dynamicTypeName; + + public bool IsExludedOnThisPlatform () + { + return platformsToIgnore != null && platformsToIgnore.Any (platform => platform == Application.platform.ToString ()); + } + + static bool IsAssignableFrom(Type a, Type b) + { +#if !UNITY_METRO + return a.IsAssignableFrom(b); +#else + return false; +#endif + } + + public bool IsExceptionExpected (string exception) + { + if (!expectException) return false; + exception = exception.Trim (); + foreach (var expectedException in expectedExceptionList.Split (',').Select (e => e.Trim ())) + { + if (exception == expectedException) return true; + var exceptionType = Type.GetType (exception) ?? GetTypeByName (exception); + var expectedExceptionType = Type.GetType (expectedException) ?? GetTypeByName (expectedException); + if (exceptionType != null && expectedExceptionType != null && IsAssignableFrom(expectedExceptionType,exceptionType)) + return true; + } + return false; + } + + public bool ShouldSucceedOnException () + { + return succeedWhenExceptionIsThrown; + } + + public double GetTimeout () + { + return timeout; + } + + public bool IsIgnored () + { + return ignored; + } + + public bool ShouldSucceedOnAssertions () + { + return succeedAfterAllAssertionsAreExecuted; + } + + private static Type GetTypeByName (string className) + { +#if !UNITY_METRO + return AppDomain.CurrentDomain.GetAssemblies ().SelectMany (a => a.GetTypes ()).FirstOrDefault (type => type.Name == className); +#else + return null; +#endif + } + + public void OnValidate () + { + if (timeout < 0.01f) timeout = 0.01f; + } + + //Legacy + [Flags] + public enum IncludedPlatforms + { + WindowsEditor = 1 << 0, + OSXEditor = 1 << 1, + WindowsPlayer = 1 << 2, + OSXPlayer = 1 << 3, + LinuxPlayer = 1 << 4, + MetroPlayerX86 = 1 << 5, + MetroPlayerX64 = 1 << 6, + MetroPlayerARM = 1 << 7, + WindowsWebPlayer = 1 << 8, + OSXWebPlayer = 1 << 9, + Android = 1 << 10, + IPhonePlayer = 1 << 11, + TizenPlayer = 1 << 12, + WP8Player = 1 << 13, + BB10Player = 1 << 14, + NaCl = 1 << 15, + PS3 = 1 << 16, + XBOX360 = 1 << 17, + WiiPlayer = 1 << 18, + PSP2 = 1 << 19, + PS4 = 1 << 20, + PSMPlayer = 1 << 21, + XboxOne = 1 << 22, + } + + #region ITestComponent implementation + + public void EnableTest (bool enable) + { + if (enable && dynamic) + { + Type t = Type.GetType (dynamicTypeName); + var s = gameObject.GetComponent(t) as MonoBehaviour; + if(s!=null) + DestroyImmediate (s); + + gameObject.AddComponent (t); + } + + if(gameObject.activeSelf!=enable) gameObject.SetActive (enable); + } + + public int CompareTo (ITestComponent obj) + { + if (obj == NullTestComponent) + return 1; + var result = gameObject.name.CompareTo (obj.gameObject.name); + if (result == 0) + result = gameObject.GetInstanceID ().CompareTo (obj.gameObject.GetInstanceID ()); + return result; + } + + public bool IsTestGroup () + { + for (int i = 0; i < gameObject.transform.childCount; i++) + { + var childTC = gameObject.transform.GetChild (i).GetComponent (typeof (TestComponent)); + if (childTC != null) + return true; + } + return false; + } + + public string Name { get { return gameObject == null ? "" : gameObject.name; } } + + public ITestComponent GetTestGroup () + { + var parent = gameObject.transform.parent; + if (parent == null) + return NullTestComponent; + return parent.GetComponent (); + } + + public override bool Equals ( object o ) + { + if (o is TestComponent) + return this == (o as TestComponent); + return false; + } + + public override int GetHashCode () + { + return base.GetHashCode (); + } + + public static bool operator == ( TestComponent a, TestComponent b ) + { + if (ReferenceEquals (a, b)) + return true; + if (((object)a == null) || ((object)b == null)) + return false; + if(a.dynamic && b.dynamic) + return a.dynamicTypeName == b.dynamicTypeName; + if(a.dynamic || b.dynamic) + return false; + return a.gameObject == b.gameObject; + } + + public static bool operator != ( TestComponent a, TestComponent b ) + { + return !(a == b); + } + + #endregion + + #region Static helpers + + public static TestComponent CreateDynamicTest (Type type) + { + var go = CreateTest (type.Name); + go.hideFlags |= HideFlags.DontSave; + go.SetActive (false); + + var tc = go.GetComponent (); + tc.dynamic = true; + tc.dynamicTypeName = type.AssemblyQualifiedName; + + foreach (var typeAttribute in type.GetCustomAttributes (false)) + { + if (typeAttribute is IntegrationTest.TimeoutAttribute) + tc.timeout = (typeAttribute as IntegrationTest.TimeoutAttribute).timeout; + else if (typeAttribute is IntegrationTest.IgnoreAttribute) + tc.ignored = true; + else if (typeAttribute is IntegrationTest.SucceedWithAssertions) + tc.succeedAfterAllAssertionsAreExecuted = true; + else if (typeAttribute is IntegrationTest.ExcludePlatformAttribute) + tc.platformsToIgnore = (typeAttribute as IntegrationTest.ExcludePlatformAttribute).platformsToExclude; + else if (typeAttribute is IntegrationTest.ExpectExceptions) + { + var attribute = (typeAttribute as IntegrationTest.ExpectExceptions); + tc.expectException = true; + tc.expectedExceptionList = string.Join (",", attribute.exceptionTypeNames); + tc.succeedWhenExceptionIsThrown = attribute.succeedOnException; + } + } + + go.AddComponent (type); + + return tc; + } + + public static GameObject CreateTest () + { + return CreateTest ("New Test"); + } + + private static GameObject CreateTest (string name) + { + var go = new GameObject (name); + go.AddComponent (); + go.transform.hideFlags |= HideFlags.HideInInspector; + return go; + } + + public static List FindAllTestsOnScene () + { + return Resources.FindObjectsOfTypeAll (typeof (TestComponent)).Cast ().ToList (); + } + + public static List FindAllTopTestsOnScene () + { + return FindAllTestsOnScene ().Where (component => component.gameObject.transform.parent == null).ToList (); + } + + public static List FindAllDynamicTestsOnScene () + { + return FindAllTestsOnScene ().Where (t => t.dynamic).ToList (); + } + + public static void DestroyAllDynamicTests () + { + foreach (var dynamicTestComponent in FindAllDynamicTestsOnScene ()) + DestroyImmediate (dynamicTestComponent.gameObject); + } + + public static void DisableAllTests () + { + foreach (var t in FindAllTestsOnScene ()) t.EnableTest (false); + } + + public static bool AnyTestsOnScene () + { + return FindAllTestsOnScene().Any(); + } + + #endregion + + private sealed class NullTestComponentImpl : ITestComponent + { + public int CompareTo (ITestComponent other) + { + if (other == this) return 0; + return -1; + } + + public void EnableTest (bool enable) + { + } + + public ITestComponent GetParentTestComponent () + { + throw new NotImplementedException (); + } + + public bool IsTestGroup () + { + throw new NotImplementedException (); + } + + public GameObject gameObject { get; private set; } + public string Name { get { return ""; } } + + public ITestComponent GetTestGroup () + { + return null; + } + + public bool IsExceptionExpected (string exceptionType) + { + throw new NotImplementedException (); + } + + public bool ShouldSucceedOnException () + { + throw new NotImplementedException (); + } + + public double GetTimeout () + { + throw new NotImplementedException (); + } + + public bool IsIgnored () + { + throw new NotImplementedException (); + } + + public bool ShouldSucceedOnAssertions () + { + throw new NotImplementedException (); + } + + public bool IsExludedOnThisPlatform () + { + throw new NotImplementedException (); + } + } + + public static IEnumerable GetTypesWithHelpAttribute (string sceneName) + { + foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies ()) + { + foreach (Type type in assembly.GetTypes ()) + { + var attributes = type.GetCustomAttributes (typeof (IntegrationTest.DynamicTestAttribute), true); + if (attributes.Length == 1) + { + var a = attributes.Single () as IntegrationTest.DynamicTestAttribute; + if (a.IncludeOnScene (sceneName)) yield return type; + } + } + } + } + } +} diff --git a/src/Assets/UnityTestTools/IntegrationTestsFramework/TestRunner/TestComponent.cs.meta b/src/Assets/UnityTestTools/IntegrationTestsFramework/TestRunner/TestComponent.cs.meta new file mode 100644 index 0000000..fd67c93 --- /dev/null +++ b/src/Assets/UnityTestTools/IntegrationTestsFramework/TestRunner/TestComponent.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b1dba0b27b0864740a8720e920aa88c0 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/UnityTestTools/IntegrationTestsFramework/TestRunner/TestResult.cs b/src/Assets/UnityTestTools/IntegrationTestsFramework/TestRunner/TestResult.cs new file mode 100644 index 0000000..0b85607 --- /dev/null +++ b/src/Assets/UnityTestTools/IntegrationTestsFramework/TestRunner/TestResult.cs @@ -0,0 +1,141 @@ +using System; +using UnityEngine; + +namespace UnityTest +{ + [Serializable] + public class TestResult : ITestResult, IComparable + { + private GameObject go; + private TestComponent testComponent; + private string name; + public ResultType resultType = ResultType.NotRun; + public double duration; + public string messages; + public string stacktrace; + public string id; + public bool dynamicTest; + + public TestComponent TestComponent; + + public GameObject GameObject + { + get { return go; } + } + + public TestResult ( TestComponent testComponent ) + { + this.TestComponent = testComponent; + this.go = testComponent.gameObject; + this.id = testComponent.gameObject.GetInstanceID ().ToString(); + this.dynamicTest = testComponent.dynamic; + + if (go != null) name = go.name; + + if (dynamicTest) + id = testComponent.dynamicTypeName; + } + + public void Update ( TestResult oldResult ) + { + resultType = oldResult.resultType; + duration = oldResult.duration; + messages = oldResult.messages; + stacktrace = oldResult.stacktrace; + } + + public enum ResultType + { + Success, + Failed, + Timeout, + NotRun, + FailedException, + Ignored + } + + public void Reset () + { + resultType = ResultType.NotRun; + duration = 0f; + messages = ""; + stacktrace = ""; + } + + #region ITestResult implementation + public TestResultState ResultState { get + { + switch (resultType) + { + case ResultType.Success: return TestResultState.Success; + case ResultType.Failed: return TestResultState.Failure; + case ResultType.FailedException: return TestResultState.Error; + case ResultType.Ignored: return TestResultState.Ignored; + case ResultType.NotRun: return TestResultState.Skipped; + case ResultType.Timeout: return TestResultState.Cancelled; + default: throw new Exception(); + } + }} + public string Message { get { return messages; } } + public bool Executed { get { return resultType != ResultType.NotRun; } } + public string Name { get { if (go != null) name = go.name; return name; } } + public string Id { get { return id; } } + public bool IsSuccess { get { return resultType == ResultType.Success; } } + public bool IsTimeout { get { return resultType == ResultType.Timeout; } } + public double Duration { get { return duration; } } + public string StackTrace { get { return stacktrace; } } + public string FullName { + get + { + var fullName = Name; + if (go != null) + { + var tempGO = go.transform.parent; + while (tempGO != null) + { + fullName = tempGO.name + "." + fullName; + tempGO = tempGO.transform.parent; + } + + } + return fullName; + } + } + + public bool IsIgnored { get { return resultType == ResultType.Ignored; } } + public bool IsFailure + { + get + { + return resultType == ResultType.Failed + || resultType == ResultType.FailedException + || resultType == ResultType.Timeout; + } + } + #endregion + + + #region IComparable, GetHashCode and Equals implementation + public override int GetHashCode () + { + return id.GetHashCode (); + } + + public int CompareTo ( TestResult other ) + { + var result = Name.CompareTo (other.Name); + if (result == 0) + result = go.GetInstanceID ().CompareTo (other.go.GetInstanceID ()); + return result; + } + + public override bool Equals ( object obj ) + { + if (obj is TestResult) + return GetHashCode () == obj.GetHashCode (); + return base.Equals (obj); + } + #endregion + + } +} diff --git a/src/Assets/UnityTestTools/IntegrationTestsFramework/TestRunner/TestResult.cs.meta b/src/Assets/UnityTestTools/IntegrationTestsFramework/TestRunner/TestResult.cs.meta new file mode 100644 index 0000000..c604bea --- /dev/null +++ b/src/Assets/UnityTestTools/IntegrationTestsFramework/TestRunner/TestResult.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 68740a702763aaa4594e8319a05ae0d3 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/UnityTestTools/IntegrationTestsFramework/TestRunner/TestResultRenderer.cs b/src/Assets/UnityTestTools/IntegrationTestsFramework/TestRunner/TestResultRenderer.cs new file mode 100644 index 0000000..692a4ff --- /dev/null +++ b/src/Assets/UnityTestTools/IntegrationTestsFramework/TestRunner/TestResultRenderer.cs @@ -0,0 +1,75 @@ +using System.Collections.Generic; +using System.Linq; +using UnityEngine; + +public class TestResultRenderer +{ + private static class Styles + { + public static GUIStyle succeedLabelStyle; + public static GUIStyle failedLabelStyle; + public static GUIStyle failedMessagesStyle; + + static Styles() + { + succeedLabelStyle = new GUIStyle ("label"); + succeedLabelStyle.normal.textColor = Color.green; + succeedLabelStyle.fontSize = 48; + + failedLabelStyle = new GUIStyle ("label"); + failedLabelStyle.normal.textColor = Color.red; + failedLabelStyle.fontSize = 32; + + failedMessagesStyle = new GUIStyle ("label"); + failedMessagesStyle.wordWrap = false; + failedMessagesStyle.richText = true; + } + } + private Dictionary> testCollection = new Dictionary> (); + + private bool showResults; + Vector2 scrollPosition; + + public void ShowResults () + { + showResults = true; + Screen.showCursor = true; + } + + public void AddResults ( string sceneName, ITestResult result ) + { + if(!testCollection.ContainsKey (sceneName)) + testCollection.Add (sceneName, new List ()); + testCollection[sceneName].Add (result); + } + + public void Draw () + { + if (!showResults) return; + if (testCollection.Count==0) + { + GUILayout.Label ("All test succeeded", Styles.succeedLabelStyle, GUILayout.Width (600)); + } + else + { + int count = 0; + foreach (var testGroup in testCollection) count += testGroup.Value.Count; + GUILayout.Label (count + " tests failed!", Styles.failedLabelStyle); + + scrollPosition = GUILayout.BeginScrollView (scrollPosition, GUILayout.ExpandWidth (true)); + var text = ""; + foreach (var testGroup in testCollection) + { + text += "" + testGroup.Key + "\n"; + text += string.Join ("\n", testGroup.Value + .Where (result => !result.IsSuccess) + .Select (result => result.Name + " " + result.ResultState + "\n" + result.Message) + .ToArray ()); + } + GUILayout.TextArea (text, Styles.failedMessagesStyle); + GUILayout.EndScrollView (); + } + if (GUILayout.Button ("Close")) + Application.Quit (); + } +} diff --git a/src/Assets/UnityTestTools/IntegrationTestsFramework/TestRunner/TestResultRenderer.cs.meta b/src/Assets/UnityTestTools/IntegrationTestsFramework/TestRunner/TestResultRenderer.cs.meta new file mode 100644 index 0000000..7d70150 --- /dev/null +++ b/src/Assets/UnityTestTools/IntegrationTestsFramework/TestRunner/TestResultRenderer.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 7ae9d3b4b57cae343b7ff360f9deb628 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/UnityTestTools/IntegrationTestsFramework/TestRunner/TestRunner.cs b/src/Assets/UnityTestTools/IntegrationTestsFramework/TestRunner/TestRunner.cs new file mode 100644 index 0000000..7f0d1bf --- /dev/null +++ b/src/Assets/UnityTestTools/IntegrationTestsFramework/TestRunner/TestRunner.cs @@ -0,0 +1,446 @@ +//#define IMITATE_BATCH_MODE //uncomment if you want to imitate batch mode behaviour in non-batch mode mode run +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using UnityEngine; +using UnityTest.IntegrationTestRunner; + +namespace UnityTest +{ + [Serializable] + public class TestRunner : MonoBehaviour + { + static public string integrationTestsConfigFileName = "integrationtestsconfig.txt"; + static public string batchRunFileMarker = "batchrun.txt"; + static public string defaultResulFilePostfix = "TestResults.xml"; + static private TestResultRenderer resultRenderer = new TestResultRenderer (); + + public TestComponent currentTest; + private List resultList = new List (); + private List testComponents; + + public bool isInitializedByRunner + { + get + { +#if UNITY_EDITOR && !IMITATE_BATCH_MODE + if (!UnityEditorInternal.InternalEditorUtility.inBatchMode) return true; +#endif + return false; + } + } + + private double startTime; + private bool readyToRun; + + private AssertionComponent[] assertionsToCheck = null; + private string testMessages; + private string stacktrace; + private TestState testState = TestState.Running; + + public TestRunnerCallbackList TestRunnerCallback = new TestRunnerCallbackList(); + private IntegrationTestsProvider testsProvider; + + private const string startedMessage = "IntegrationTest started"; + private const string finishedMessage = "IntegrationTest finished"; + private const string timeoutMessage = "IntegrationTest timeout"; + private const string failedMessage = "IntegrationTest failed"; + private const string failedExceptionMessage = "IntegrationTest failed with exception"; + private const string ignoredMessage = "IntegrationTest ignored"; + private const string interruptedMessage = "IntegrationTest Run interrupted"; + + + public void Awake () + { +#if UNITY_EDITOR && !IMITATE_BATCH_MODE + if (!UnityEditorInternal.InternalEditorUtility.inBatchMode) return; +#endif + TestComponent.DisableAllTests (); + } + + + + public void Start() + { +#if UNITY_EDITOR && !IMITATE_BATCH_MODE + if (!UnityEditorInternal.InternalEditorUtility.inBatchMode) return; +#endif + TestComponent.DestroyAllDynamicTests (); + var dynamicTestTypes = TestComponent.GetTypesWithHelpAttribute (Application.loadedLevelName); + foreach (var dynamicTestType in dynamicTestTypes) + TestComponent.CreateDynamicTest (dynamicTestType); + + var tests = TestComponent.FindAllTestsOnScene (); + + InitRunner (tests, dynamicTestTypes.Select (type => type.AssemblyQualifiedName).ToList ()); + } + + public void InitRunner(List tests, List dynamicTestsToRun) + { + Application.RegisterLogCallback(LogHandler); + + //Init dynamic tests + foreach (var typeName in dynamicTestsToRun) + { + var t = Type.GetType (typeName); + if (t == null) continue; + var scriptComponents = Resources.FindObjectsOfTypeAll (t) as MonoBehaviour[]; + if (scriptComponents.Length == 0) + { + Debug.LogWarning (t + " not found. Skipping."); + continue; + } + if (scriptComponents.Length > 1) Debug.LogWarning ("Multiple GameObjects refer to " + typeName); + tests.Add (scriptComponents.First().GetComponent ()); + } + //create test structure + testComponents = ParseListForGroups (tests).ToList (); + //create results for tests + resultList = testComponents.Select (component => new TestResult (component)).ToList (); + //init test provider + testsProvider = new IntegrationTestsProvider (resultList.Select (result => result.TestComponent as ITestComponent)); + readyToRun = true; + } + + private static IEnumerable ParseListForGroups ( IEnumerable tests ) + { + var results = new HashSet (); + foreach (var testResult in tests) + { + if (testResult.IsTestGroup ()) + { + var childrenTestResult = testResult.gameObject.GetComponentsInChildren (typeof (TestComponent), true) + .Where (t=>t!=testResult) + .Cast () + .ToArray (); + foreach (var result in childrenTestResult) + { + if(!result.IsTestGroup()) + results.Add (result); + } + continue; + } + results.Add (testResult); + } + return results; + } + + public void Update () + { + if (readyToRun && Time.frameCount > 1) + { + readyToRun = false; + StartCoroutine ("StateMachine"); + } + } + + public void OnDestroy() + { + if (currentTest != null) + { + var testResult = resultList.Single (result => result.TestComponent == currentTest); + testResult.messages += "Test run interrupted (crash?)"; + LogMessage(interruptedMessage); + FinishTest(TestResult.ResultType.Failed); + } + if (currentTest != null || (testsProvider != null && testsProvider.AnyTestsLeft ())) + { + var remainingTests = testsProvider.GetRemainingTests (); + TestRunnerCallback.TestRunInterrupted( remainingTests.ToList () ); + } + Application.RegisterLogCallback(null); + } + + private void LogHandler (string condition, string stacktrace, LogType type) + { + testMessages += condition + "\n"; + if (type == LogType.Exception) + { + var exceptionType = condition.Substring (0, condition.IndexOf(':')); + if (currentTest.IsExceptionExpected (exceptionType)) + { + testMessages += exceptionType + " was expected\n"; + if (currentTest.ShouldSucceedOnException()) + { + testState = TestState.Success; + } + } + else + { + testState = TestState.Exception; + this.stacktrace = stacktrace; + } + } + else if (type == LogType.Log) + { + if (testState == TestState.Running && condition.StartsWith (IntegrationTest.passMessage)) + { + testState = TestState.Success; + } + if (condition.StartsWith(IntegrationTest.failMessage)) + { + testState = TestState.Failure; + } + } + } + + public IEnumerator StateMachine () + { + TestRunnerCallback.RunStarted (Application.platform.ToString (), testComponents); + while (true) + { + if (!testsProvider.AnyTestsLeft() && currentTest == null) + { + FinishTestRun (); + yield break; + } + if (currentTest == null) + { + StartNewTest (); + } + if (currentTest != null) + { + if (testState == TestState.Running) + { + if (assertionsToCheck != null && assertionsToCheck.All (a => a.checksPerformed > 0)) + { + IntegrationTest.Pass (currentTest.gameObject); + testState = TestState.Success; + } + if (currentTest != null && Time.time > startTime + currentTest.GetTimeout()) + { + testState = TestState.Timeout; + } + } + + switch (testState) + { + case TestState.Success: + LogMessage (finishedMessage); + FinishTest (TestResult.ResultType.Success); + break; + case TestState.Failure: + LogMessage (failedMessage); + FinishTest (TestResult.ResultType.Failed); + break; + case TestState.Exception: + LogMessage (failedExceptionMessage); + FinishTest (TestResult.ResultType.FailedException); + break; + case TestState.Timeout: + LogMessage(timeoutMessage); + FinishTest(TestResult.ResultType.Timeout); + break; + case TestState.Ignored: + LogMessage (ignoredMessage); + FinishTest(TestResult.ResultType.Ignored); + break; + } + } + yield return null; + } + } + + private void LogMessage(string message) + { + if (currentTest != null) + Debug.Log (message + " (" + currentTest.Name + ")", currentTest.gameObject); + else + Debug.Log (message); + } + + private void FinishTestRun () + { + if (IsBatchRun ()) + SaveResults (); + PrintResultToLog (); + TestRunnerCallback.RunFinished (resultList); + LoadNextLevelOrQuit (); + } + + private void PrintResultToLog () + { + var resultString = ""; + resultString += "Passed: " + resultList.Count (t => t.IsSuccess); + if (resultList.Any (result => result.IsFailure)) + { + resultString += " Failed: " + resultList.Count (t => t.IsFailure); + Debug.Log ("Failed tests: " + string.Join (", ", resultList.Where (t => t.IsFailure).Select (result => result.Name).ToArray ())); + } + if (resultList.Any (result => result.IsIgnored)) + { + resultString += " Ignored: " + resultList.Count (t => t.IsIgnored); + Debug.Log ("Ignored tests: " + string.Join (", ", + resultList.Where (t => t.IsIgnored).Select (result => result.Name).ToArray ())); + } + Debug.Log (resultString); + } + + private void LoadNextLevelOrQuit () + { + if (isInitializedByRunner) return; + + if (Application.loadedLevel < Application.levelCount - 1) + Application.LoadLevel (Application.loadedLevel + 1); + else + { +#if UNITY_EDITOR && !IMITATE_BATCH_MODE + UnityEditor.EditorApplication.Exit (0); +#else + resultRenderer.ShowResults (); + if(IsBatchRun()) + Application.Quit (); +#endif + } + } + + public void OnGUI () + { + resultRenderer.Draw (); + } + + private void SaveResults () + { + if (!IsFileSavingSupported ()) return; + var resultDestiantion = GetResultDestiantion (); + var resultFileName = Application.loadedLevelName; + if (resultFileName != "") + resultFileName += "-"; + resultFileName += defaultResulFilePostfix; + + var resultWriter = new XmlResultWriter (Application.loadedLevelName, resultList.ToArray ()); + +#if !UNITY_METRO + Uri uri; + if ( Uri.TryCreate (resultDestiantion, UriKind.Absolute, out uri) && uri.Scheme == Uri.UriSchemeFile) + { + resultWriter.WriteToFile (resultDestiantion, resultFileName); + } + else + { + Debug.LogError ("Provided path is invalid"); + } +#endif + } + + private bool IsFileSavingSupported () + { +#if UNITY_EDITOR || UNITY_STANDALONE + return true; +#else + return false; +#endif + } + + private string GetResultDestiantion () + { + var nameWithoutExtension = integrationTestsConfigFileName.Substring (0, integrationTestsConfigFileName.LastIndexOf ('.')); + var resultpathFile = Resources.Load (nameWithoutExtension) as TextAsset; + var resultDestiantion = Application.dataPath; + if (resultpathFile != null) + resultDestiantion = resultpathFile.text; +#if UNITY_EDITOR + var resultsFileDirectory = "-resultsFileDirectory="; + if (UnityEditorInternal.InternalEditorUtility.inBatchMode && Environment.GetCommandLineArgs ().Any (s => s.StartsWith (resultsFileDirectory))) + resultDestiantion = Environment.GetCommandLineArgs ().First (s => s.StartsWith (resultsFileDirectory)).Substring (resultsFileDirectory.Length); +#endif + return resultDestiantion; + } + + private bool IsBatchRun () + { +#if UNITY_EDITOR && !IMITATE_BATCH_MODE + if (UnityEditorInternal.InternalEditorUtility.inBatchMode) return true; +#endif + var nameWithoutExtension = batchRunFileMarker.Substring (0, batchRunFileMarker.LastIndexOf ('.')); + var resultpathFile = Resources.Load (nameWithoutExtension) as TextAsset; + return resultpathFile != null; + } + + private void StartNewTest () + { + this.testMessages = ""; + this.stacktrace = ""; + testState = TestState.Running; + assertionsToCheck = null; + + startTime = Time.time; + currentTest = testsProvider.GetNextTest () as TestComponent; + + var testResult = resultList.Single (result => result.TestComponent == currentTest); + + if (currentTest.ShouldSucceedOnAssertions ()) + { + var assertionList = currentTest.gameObject.GetComponentsInChildren ().Where (a => a.enabled); + if(assertionList.Any()) + assertionsToCheck = assertionList.ToArray(); + } + + if (currentTest.IsExludedOnThisPlatform ()) + { + testState = TestState.Ignored; + Debug.Log(currentTest.gameObject.name + " is excluded on this platform"); + } + + //don't ignore test if user initiated it from the runner and it's the only test that is being run + if (currentTest.IsIgnored () && !(isInitializedByRunner && resultList.Count == 1)) testState = TestState.Ignored; + + LogMessage(startedMessage); + TestRunnerCallback.TestStarted (testResult); + } + + private void FinishTest(TestResult.ResultType result) + { + testsProvider.FinishTest (currentTest); + var testResult = resultList.Single (t => t.GameObject == currentTest.gameObject); + testResult.resultType = result; + testResult.duration = Time.time - startTime; + testResult.messages = testMessages; + testResult.stacktrace = stacktrace; + TestRunnerCallback.TestFinished (testResult); + currentTest = null; + //currentTest2 = null; + if (!testResult.IsSuccess + && testResult.Executed + && !testResult.IsIgnored) resultRenderer.AddResults (Application.loadedLevelName, testResult); + } + + #region Test Runner Helpers + + public static TestRunner GetTestRunner () + { + TestRunner testRunnerComponent = null; + var testRunnerComponents = Resources.FindObjectsOfTypeAll(typeof(TestRunner)); + + if (testRunnerComponents.Count () > 1) + foreach (var t in testRunnerComponents) DestroyImmediate((t as TestRunner).gameObject); + else if (!testRunnerComponents.Any()) + testRunnerComponent = Create().GetComponent(); + else + testRunnerComponent = testRunnerComponents.Single() as TestRunner; + + return testRunnerComponent; + } + + private static GameObject Create() + { + var runner = new GameObject ("TestRunner"); + var component = runner.AddComponent (); + component.hideFlags = HideFlags.NotEditable; + Debug.Log ("Created Test Runner"); + return runner; + } + #endregion + + enum TestState + { + Running, + Success, + Failure, + Exception, + Timeout, + Ignored + } + } +} diff --git a/src/Assets/UnityTestTools/IntegrationTestsFramework/TestRunner/TestRunner.cs.meta b/src/Assets/UnityTestTools/IntegrationTestsFramework/TestRunner/TestRunner.cs.meta new file mode 100644 index 0000000..5ef068e --- /dev/null +++ b/src/Assets/UnityTestTools/IntegrationTestsFramework/TestRunner/TestRunner.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 5c3afc1c624179749bcdecf7b0224902 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/UnityTestTools/IntegrationTestsFramework/TestRunner/TestRunnerCallbackList.cs b/src/Assets/UnityTestTools/IntegrationTestsFramework/TestRunner/TestRunnerCallbackList.cs new file mode 100644 index 0000000..e7b6958 --- /dev/null +++ b/src/Assets/UnityTestTools/IntegrationTestsFramework/TestRunner/TestRunnerCallbackList.cs @@ -0,0 +1,60 @@ +using System; +using System.Collections.Generic; + +namespace UnityTest.IntegrationTestRunner +{ + public class TestRunnerCallbackList : ITestRunnerCallback + { + private List callbackList = new List (); + + public void Add (ITestRunnerCallback callback) + { + callbackList.Add (callback); + } + + public void Remove (ITestRunnerCallback callback) + { + callbackList.Remove (callback); + } + + public void RunStarted (string platform, List testsToRun) + { + foreach (var unitTestRunnerCallback in callbackList) + { + unitTestRunnerCallback.RunStarted(platform, testsToRun); + } + } + + public void RunFinished (List testResults) + { + foreach (var unitTestRunnerCallback in callbackList) + { + unitTestRunnerCallback.RunFinished(testResults); + } + } + + public void TestStarted (TestResult test) + { + foreach (var unitTestRunnerCallback in callbackList) + { + unitTestRunnerCallback.TestStarted(test); + } + } + + public void TestFinished (TestResult test) + { + foreach (var unitTestRunnerCallback in callbackList) + { + unitTestRunnerCallback.TestFinished(test); + } + } + + public void TestRunInterrupted (List testsNotRun) + { + foreach (var unitTestRunnerCallback in callbackList) + { + unitTestRunnerCallback.TestRunInterrupted(testsNotRun); + } + } + } +} diff --git a/src/Assets/UnityTestTools/IntegrationTestsFramework/TestRunner/TestRunnerCallbackList.cs.meta b/src/Assets/UnityTestTools/IntegrationTestsFramework/TestRunner/TestRunnerCallbackList.cs.meta new file mode 100644 index 0000000..c39656a --- /dev/null +++ b/src/Assets/UnityTestTools/IntegrationTestsFramework/TestRunner/TestRunnerCallbackList.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 7729da83f7c08d244b5788c870a93780 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/UnityTestTools/IntegrationTestsFramework/TestingAssets.meta b/src/Assets/UnityTestTools/IntegrationTestsFramework/TestingAssets.meta new file mode 100644 index 0000000..433c295 --- /dev/null +++ b/src/Assets/UnityTestTools/IntegrationTestsFramework/TestingAssets.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: 1d1ccbd729921544dbd71f7e80c405b6 +folderAsset: yes +DefaultImporter: + userData: diff --git a/src/Assets/UnityTestTools/IntegrationTestsFramework/TestingAssets/CallTesting.cs b/src/Assets/UnityTestTools/IntegrationTestsFramework/TestingAssets/CallTesting.cs new file mode 100644 index 0000000..c45b795 --- /dev/null +++ b/src/Assets/UnityTestTools/IntegrationTestsFramework/TestingAssets/CallTesting.cs @@ -0,0 +1,206 @@ +using UnityEngine; + +namespace UnityTest +{ + public class CallTesting : MonoBehaviour + { + public enum Functions + { + CallAfterSeconds, + CallAfterFrames, + Start, + Update, + FixedUpdate, + LateUpdate, + OnDestroy, + OnEnable, + OnDisable, + OnControllerColliderHit, + OnParticleCollision, + OnJointBreak, + OnBecameInvisible, + OnBecameVisible, + OnTriggerEnter, + OnTriggerExit, + OnTriggerStay, + OnCollisionEnter, + OnCollisionExit, + OnCollisionStay, +#if !UNITY_4_0 && !UNITY_4_0_1 && !UNITY_4_1 && !UNITY_4_2 + OnTriggerEnter2D, + OnTriggerExit2D, + OnTriggerStay2D, + OnCollisionEnter2D, + OnCollisionExit2D, + OnCollisionStay2D, +#endif + } + + public enum Method + { + Pass, + Fail + } + + public int afterFrames = 0; + public float afterSeconds = 0.0f; + public Functions callOnMethod = Functions.Start; + + public Method methodToCall; + private int startFrame = 0; + private float startTime; + + private void TryToCallTesting (Functions invokingMethod) + { + if (invokingMethod == callOnMethod) + { + if (methodToCall == Method.Pass) + IntegrationTest.Pass (gameObject); + else + IntegrationTest.Fail (gameObject); + + afterFrames = 0; + afterSeconds = 0.0f; + startTime = float.PositiveInfinity; + startFrame = int.MinValue; + } + } + + public void Start () + { + startTime = Time.time; + startFrame = afterFrames; + TryToCallTesting (Functions.Start); + } + + public void Update () + { + TryToCallTesting (Functions.Update); + CallAfterSeconds (); + CallAfterFrames (); + } + + private void CallAfterFrames () + { + if (afterFrames > 0 && (startFrame + afterFrames) <= Time.frameCount) + TryToCallTesting (Functions.CallAfterFrames); + } + + private void CallAfterSeconds () + { + if ((startTime + afterSeconds) <= Time.time) + TryToCallTesting (Functions.CallAfterSeconds); + } + + public void OnDisable () + { + TryToCallTesting (Functions.OnDisable); + } + + public void OnEnable () + { + TryToCallTesting (Functions.OnEnable); + } + + public void OnDestroy () + { + TryToCallTesting (Functions.OnDestroy); + } + + public void FixedUpdate () + { + TryToCallTesting (Functions.FixedUpdate); + } + + public void LateUpdate () + { + TryToCallTesting (Functions.LateUpdate); + } + + public void OnControllerColliderHit () + { + TryToCallTesting (Functions.OnControllerColliderHit); + } + + public void OnParticleCollision () + { + TryToCallTesting (Functions.OnParticleCollision); + } + + public void OnJointBreak () + { + TryToCallTesting (Functions.OnJointBreak); + } + + public void OnBecameInvisible () + { + TryToCallTesting (Functions.OnBecameInvisible); + } + + public void OnBecameVisible () + { + TryToCallTesting (Functions.OnBecameVisible); + } + + public void OnTriggerEnter () + { + TryToCallTesting (Functions.OnTriggerEnter); + } + + public void OnTriggerExit () + { + TryToCallTesting (Functions.OnTriggerExit); + } + + public void OnTriggerStay () + { + TryToCallTesting (Functions.OnTriggerStay); + } + public void OnCollisionEnter () + { + TryToCallTesting (Functions.OnCollisionEnter); + } + + public void OnCollisionExit () + { + TryToCallTesting (Functions.OnCollisionExit); + } + + public void OnCollisionStay () + { + TryToCallTesting (Functions.OnCollisionStay); + } + +#if !UNITY_4_0 && !UNITY_4_0_1 && !UNITY_4_1 && !UNITY_4_2 + public void OnTriggerEnter2D () + { + TryToCallTesting (Functions.OnTriggerEnter2D); + } + + public void OnTriggerExit2D () + { + TryToCallTesting (Functions.OnTriggerExit2D); + } + + public void OnTriggerStay2D () + { + TryToCallTesting (Functions.OnTriggerStay2D); + } + + public void OnCollisionEnter2D () + { + TryToCallTesting (Functions.OnCollisionEnter2D); + } + + public void OnCollisionExit2D () + { + TryToCallTesting (Functions.OnCollisionExit2D); + } + + public void OnCollisionStay2D () + { + TryToCallTesting (Functions.OnCollisionStay2D); + } +#endif + } +} diff --git a/src/Assets/UnityTestTools/IntegrationTestsFramework/TestingAssets/CallTesting.cs.meta b/src/Assets/UnityTestTools/IntegrationTestsFramework/TestingAssets/CallTesting.cs.meta new file mode 100644 index 0000000..91cbde1 --- /dev/null +++ b/src/Assets/UnityTestTools/IntegrationTestsFramework/TestingAssets/CallTesting.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 0d545b1288d5fc74d8e6c961fb67ab18 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/UnityTestTools/IntegrationTestsFramework/TestingAssets/CubeCollisionFailure.prefab b/src/Assets/UnityTestTools/IntegrationTestsFramework/TestingAssets/CubeCollisionFailure.prefab new file mode 100644 index 0000000..3425eb9 Binary files /dev/null and b/src/Assets/UnityTestTools/IntegrationTestsFramework/TestingAssets/CubeCollisionFailure.prefab differ diff --git a/src/Assets/UnityTestTools/IntegrationTestsFramework/TestingAssets/CubeCollisionFailure.prefab.meta b/src/Assets/UnityTestTools/IntegrationTestsFramework/TestingAssets/CubeCollisionFailure.prefab.meta new file mode 100644 index 0000000..777585e --- /dev/null +++ b/src/Assets/UnityTestTools/IntegrationTestsFramework/TestingAssets/CubeCollisionFailure.prefab.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: d5fc3c3488db1e74689f1fc67c33944a +NativeFormatImporter: + userData: diff --git a/src/Assets/UnityTestTools/IntegrationTestsFramework/TestingAssets/CubeCollisionSuccess.prefab b/src/Assets/UnityTestTools/IntegrationTestsFramework/TestingAssets/CubeCollisionSuccess.prefab new file mode 100644 index 0000000..1b7e571 Binary files /dev/null and b/src/Assets/UnityTestTools/IntegrationTestsFramework/TestingAssets/CubeCollisionSuccess.prefab differ diff --git a/src/Assets/UnityTestTools/IntegrationTestsFramework/TestingAssets/CubeCollisionSuccess.prefab.meta b/src/Assets/UnityTestTools/IntegrationTestsFramework/TestingAssets/CubeCollisionSuccess.prefab.meta new file mode 100644 index 0000000..73ed474 --- /dev/null +++ b/src/Assets/UnityTestTools/IntegrationTestsFramework/TestingAssets/CubeCollisionSuccess.prefab.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: 1228dff762eab21488cfefd42792c37b +NativeFormatImporter: + userData: diff --git a/src/Assets/UnityTestTools/IntegrationTestsFramework/TestingAssets/CubeTriggerFailure.prefab b/src/Assets/UnityTestTools/IntegrationTestsFramework/TestingAssets/CubeTriggerFailure.prefab new file mode 100644 index 0000000..5469913 Binary files /dev/null and b/src/Assets/UnityTestTools/IntegrationTestsFramework/TestingAssets/CubeTriggerFailure.prefab differ diff --git a/src/Assets/UnityTestTools/IntegrationTestsFramework/TestingAssets/CubeTriggerFailure.prefab.meta b/src/Assets/UnityTestTools/IntegrationTestsFramework/TestingAssets/CubeTriggerFailure.prefab.meta new file mode 100644 index 0000000..e04b231 --- /dev/null +++ b/src/Assets/UnityTestTools/IntegrationTestsFramework/TestingAssets/CubeTriggerFailure.prefab.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: 616ddafe39e02da4081e56f7f763af3c +NativeFormatImporter: + userData: diff --git a/src/Assets/UnityTestTools/IntegrationTestsFramework/TestingAssets/CubeTriggerSuccess.prefab b/src/Assets/UnityTestTools/IntegrationTestsFramework/TestingAssets/CubeTriggerSuccess.prefab new file mode 100644 index 0000000..947a40f Binary files /dev/null and b/src/Assets/UnityTestTools/IntegrationTestsFramework/TestingAssets/CubeTriggerSuccess.prefab differ diff --git a/src/Assets/UnityTestTools/IntegrationTestsFramework/TestingAssets/CubeTriggerSuccess.prefab.meta b/src/Assets/UnityTestTools/IntegrationTestsFramework/TestingAssets/CubeTriggerSuccess.prefab.meta new file mode 100644 index 0000000..d16c91a --- /dev/null +++ b/src/Assets/UnityTestTools/IntegrationTestsFramework/TestingAssets/CubeTriggerSuccess.prefab.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: d940e636fd44be84e9b7e8da46f700ef +NativeFormatImporter: + userData: diff --git a/src/Assets/UnityTestTools/IntegrationTestsFramework/TestingAssets/Materials.meta b/src/Assets/UnityTestTools/IntegrationTestsFramework/TestingAssets/Materials.meta new file mode 100644 index 0000000..ea98c41 --- /dev/null +++ b/src/Assets/UnityTestTools/IntegrationTestsFramework/TestingAssets/Materials.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: 8d55f43641ba3c14eaa1156abc0edabd +folderAsset: yes +DefaultImporter: + userData: diff --git a/src/Assets/UnityTestTools/IntegrationTestsFramework/TestingAssets/Materials/green.mat b/src/Assets/UnityTestTools/IntegrationTestsFramework/TestingAssets/Materials/green.mat new file mode 100644 index 0000000..ac8a70c Binary files /dev/null and b/src/Assets/UnityTestTools/IntegrationTestsFramework/TestingAssets/Materials/green.mat differ diff --git a/src/Assets/UnityTestTools/IntegrationTestsFramework/TestingAssets/Materials/green.mat.meta b/src/Assets/UnityTestTools/IntegrationTestsFramework/TestingAssets/Materials/green.mat.meta new file mode 100644 index 0000000..2cabfad --- /dev/null +++ b/src/Assets/UnityTestTools/IntegrationTestsFramework/TestingAssets/Materials/green.mat.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: 43da3275cd08d41429f56675d70c58df +NativeFormatImporter: + userData: diff --git a/src/Assets/UnityTestTools/IntegrationTestsFramework/TestingAssets/Materials/red.mat b/src/Assets/UnityTestTools/IntegrationTestsFramework/TestingAssets/Materials/red.mat new file mode 100644 index 0000000..beeafc5 Binary files /dev/null and b/src/Assets/UnityTestTools/IntegrationTestsFramework/TestingAssets/Materials/red.mat differ diff --git a/src/Assets/UnityTestTools/IntegrationTestsFramework/TestingAssets/Materials/red.mat.meta b/src/Assets/UnityTestTools/IntegrationTestsFramework/TestingAssets/Materials/red.mat.meta new file mode 100644 index 0000000..3914d56 --- /dev/null +++ b/src/Assets/UnityTestTools/IntegrationTestsFramework/TestingAssets/Materials/red.mat.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: 0503fcccc592ba54ba2564beb42ce08b +NativeFormatImporter: + userData: diff --git a/src/Assets/UnityTestTools/IntegrationTestsFramework/TestingAssets/green.png b/src/Assets/UnityTestTools/IntegrationTestsFramework/TestingAssets/green.png new file mode 100644 index 0000000..f4dcca2 Binary files /dev/null and b/src/Assets/UnityTestTools/IntegrationTestsFramework/TestingAssets/green.png differ diff --git a/src/Assets/UnityTestTools/IntegrationTestsFramework/TestingAssets/green.png.meta b/src/Assets/UnityTestTools/IntegrationTestsFramework/TestingAssets/green.png.meta new file mode 100644 index 0000000..2738fc5 --- /dev/null +++ b/src/Assets/UnityTestTools/IntegrationTestsFramework/TestingAssets/green.png.meta @@ -0,0 +1,46 @@ +fileFormatVersion: 2 +guid: 928be703400f4eb48af2f94d55bf3f74 +TextureImporter: + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + linearTexture: 0 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: -1 + mipBias: -1 + wrapMode: -1 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 0 + textureType: -1 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/src/Assets/UnityTestTools/IntegrationTestsFramework/TestingAssets/red.png b/src/Assets/UnityTestTools/IntegrationTestsFramework/TestingAssets/red.png new file mode 100644 index 0000000..8b29b45 Binary files /dev/null and b/src/Assets/UnityTestTools/IntegrationTestsFramework/TestingAssets/red.png differ diff --git a/src/Assets/UnityTestTools/IntegrationTestsFramework/TestingAssets/red.png.meta b/src/Assets/UnityTestTools/IntegrationTestsFramework/TestingAssets/red.png.meta new file mode 100644 index 0000000..5b47471 --- /dev/null +++ b/src/Assets/UnityTestTools/IntegrationTestsFramework/TestingAssets/red.png.meta @@ -0,0 +1,46 @@ +fileFormatVersion: 2 +guid: 591632297e74ba34fa4c65d1265d370a +TextureImporter: + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + linearTexture: 0 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: -1 + mipBias: -1 + wrapMode: -1 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 0 + textureType: -1 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/src/Assets/UnityTestTools/LICENSE.txt b/src/Assets/UnityTestTools/LICENSE.txt new file mode 100644 index 0000000..8da6126 --- /dev/null +++ b/src/Assets/UnityTestTools/LICENSE.txt @@ -0,0 +1,83 @@ +This software is provided 'as-is', without any express or implied warranty. + + +THE UNITY TEST TOOLS CONTAIN THE FOLLOWING THIRD PARTY LIBRARIES: +NSubstitute Copyright (c) 2009 Anthony Egerton (nsubstitute@delfish.com) and David Tchepak (dave@davesquared.net). All rights reserved. +NUnit Portions Copyright © 2002-2009 Charlie Poole or Copyright © 2002-2004 James W. Newkirk, Michael C. Two, Alexei A. Vorontsov or Copyright © 2000-2002 Philip A. Craig +Cecil Copyright (c) 2008 - 2011, Jb Evain + + + +NSubstitute is open source software, licensed under the BSD License. The modifications made by Unity are available on github. + +Copyright (c) 2009 Anthony Egerton (nsubstitute@delfish.com) and David Tchepak (dave@davesquared.net) +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + * Neither the names of the copyright holders nor the names of + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +[ http://www.opensource.org/licenses/bsd-license.php ] + + + +NUnit is provided 'as-is', without any express or implied warranty. The modifications made by Unity are available on github. + +Copyright © 2002-2013 Charlie Poole +Copyright © 2002-2004 James W. Newkirk, Michael C. Two, Alexei A. Vorontsov +Copyright © 2000-2002 Philip A. Craig + +This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment (see the following) in the product documentation is required. + +Portions Copyright © 2002-2013 Charlie Poole or Copyright © 2002-2004 James W. Newkirk, Michael C. Two, Alexei A. Vorontsov or Copyright © 2000-2002 Philip A. Craig + +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source distribution. + + + +Cecil is licensed under the MIT/X11. + +Copyright (c) 2008 - 2011, Jb Evain + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. \ No newline at end of file diff --git a/src/Assets/UnityTestTools/LICENSE.txt.meta b/src/Assets/UnityTestTools/LICENSE.txt.meta new file mode 100644 index 0000000..6a87d69 --- /dev/null +++ b/src/Assets/UnityTestTools/LICENSE.txt.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: 0d5b4501bf773f349ad95ec34491dc61 +TextScriptImporter: + userData: diff --git a/src/Assets/UnityTestTools/UnitTesting.meta b/src/Assets/UnityTestTools/UnitTesting.meta new file mode 100644 index 0000000..10d2dd5 --- /dev/null +++ b/src/Assets/UnityTestTools/UnitTesting.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: 9a87f1db904f1e948a2385ab9961e3aa +folderAsset: yes +DefaultImporter: + userData: diff --git a/src/Assets/UnityTestTools/UnitTesting/Editor.meta b/src/Assets/UnityTestTools/UnitTesting/Editor.meta new file mode 100644 index 0000000..40bb5ee --- /dev/null +++ b/src/Assets/UnityTestTools/UnitTesting/Editor.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: 59b47eb3fc62eb44cb73a329a1e6b6cb +folderAsset: yes +DefaultImporter: + userData: diff --git a/src/Assets/UnityTestTools/UnitTesting/Editor/Batch.cs b/src/Assets/UnityTestTools/UnitTesting/Editor/Batch.cs new file mode 100644 index 0000000..b6fd09f --- /dev/null +++ b/src/Assets/UnityTestTools/UnitTesting/Editor/Batch.cs @@ -0,0 +1,88 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using UnityEditor; +using UnityEngine; +using UnityTest.UnitTestRunner; + +namespace UnityTest +{ + public static partial class Batch + { + private static string resultFilePathParam = "-resultFilePath="; + private static string defaultResultFileName = "UnitTestResults.xml"; + + public static void RunUnitTests () + { + + var resultFilePath = GetParameterArgument (resultFilePathParam) ?? Directory.GetCurrentDirectory (); + if (Directory.Exists (resultFilePath)) + resultFilePath = Path.Combine (resultFilePath, defaultResultFileName); + EditorApplication.NewScene (); + var engine = new NUnitTestEngine (); + UnitTestResult[] results; + string[] categories; + engine.GetTests (out results, out categories); + engine.RunTests (new TestRunnerEventListener (resultFilePath,results.ToList())); + } + + private static string GetParameterArgument ( string parameterName ) + { + foreach (var arg in Environment.GetCommandLineArgs ()) + { + if (arg.ToLower ().StartsWith (parameterName.ToLower ())) + { + return arg.Substring (parameterName.Length); + } + } + return null; + } + + private class TestRunnerEventListener : ITestRunnerCallback + { + private string resultFilePath; + private List results; + + public TestRunnerEventListener ( string resultFilePath, List resultList ) + { + this.resultFilePath = resultFilePath; + this.results = resultList; + } + + public void TestFinished (ITestResult test) + { + results.Single( r=>r.Id == test.Id).Update(test, false); + } + + public void RunFinished () + { + var resultDestiantion = Application.dataPath; + if (!string.IsNullOrEmpty (resultFilePath)) + resultDestiantion = resultFilePath; + var fileName = Path.GetFileName (resultDestiantion); + if (!string.IsNullOrEmpty (fileName)) + resultDestiantion = resultDestiantion.Substring (0, resultDestiantion.Length - fileName.Length); + else + fileName = "UnitTestResults.xml"; +#if !UNITY_METRO + var resultWriter = new XmlResultWriter ("Unit Tests", results.ToArray ()); + resultWriter.WriteToFile (resultDestiantion, fileName); +#endif + } + + public void TestStarted (string fullName) + { + } + + public void RunStarted (string suiteName, int testCount) + { + } + + public void RunFinishedException (Exception exception) + { + throw exception; + } + } + } +} diff --git a/src/Assets/UnityTestTools/UnitTesting/Editor/Batch.cs.meta b/src/Assets/UnityTestTools/UnitTesting/Editor/Batch.cs.meta new file mode 100644 index 0000000..4595868 --- /dev/null +++ b/src/Assets/UnityTestTools/UnitTesting/Editor/Batch.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 5401885870ebec84f8e9c6ee18d79695 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/UnityTestTools/UnitTesting/Editor/NSubstitute.meta b/src/Assets/UnityTestTools/UnitTesting/Editor/NSubstitute.meta new file mode 100644 index 0000000..9a7cadb --- /dev/null +++ b/src/Assets/UnityTestTools/UnitTesting/Editor/NSubstitute.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: 92b38897656771f409e9235955975754 +folderAsset: yes +DefaultImporter: + userData: diff --git a/src/Assets/UnityTestTools/UnitTesting/Editor/NSubstitute/NSubstitute.dll b/src/Assets/UnityTestTools/UnitTesting/Editor/NSubstitute/NSubstitute.dll new file mode 100644 index 0000000..ee8b155 Binary files /dev/null and b/src/Assets/UnityTestTools/UnitTesting/Editor/NSubstitute/NSubstitute.dll differ diff --git a/src/Assets/UnityTestTools/UnitTesting/Editor/NSubstitute/NSubstitute.dll.meta b/src/Assets/UnityTestTools/UnitTesting/Editor/NSubstitute/NSubstitute.dll.meta new file mode 100644 index 0000000..38d55f5 --- /dev/null +++ b/src/Assets/UnityTestTools/UnitTesting/Editor/NSubstitute/NSubstitute.dll.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 3c5e1afc6e0d68849ae6639aff58cfc7 +MonoAssemblyImporter: + serializedVersion: 1 + iconMap: {} + executionOrder: {} + userData: diff --git a/src/Assets/UnityTestTools/UnitTesting/Editor/NUnit.meta b/src/Assets/UnityTestTools/UnitTesting/Editor/NUnit.meta new file mode 100644 index 0000000..a94ee3e --- /dev/null +++ b/src/Assets/UnityTestTools/UnitTesting/Editor/NUnit.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: a92d914a774b29f42906161a387d79f7 +folderAsset: yes +DefaultImporter: + userData: diff --git a/src/Assets/UnityTestTools/UnitTesting/Editor/NUnit/Libs.meta b/src/Assets/UnityTestTools/UnitTesting/Editor/NUnit/Libs.meta new file mode 100644 index 0000000..96b0d0f --- /dev/null +++ b/src/Assets/UnityTestTools/UnitTesting/Editor/NUnit/Libs.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: e22ba039de7077c4aa95758ef723b803 +folderAsset: yes +DefaultImporter: + userData: diff --git a/src/Assets/UnityTestTools/UnitTesting/Editor/NUnit/Libs/Mono.Cecil.Mdb.dll b/src/Assets/UnityTestTools/UnitTesting/Editor/NUnit/Libs/Mono.Cecil.Mdb.dll new file mode 100644 index 0000000..2ddd976 Binary files /dev/null and b/src/Assets/UnityTestTools/UnitTesting/Editor/NUnit/Libs/Mono.Cecil.Mdb.dll differ diff --git a/src/Assets/UnityTestTools/UnitTesting/Editor/NUnit/Libs/Mono.Cecil.Mdb.dll.meta b/src/Assets/UnityTestTools/UnitTesting/Editor/NUnit/Libs/Mono.Cecil.Mdb.dll.meta new file mode 100644 index 0000000..36a8c4f --- /dev/null +++ b/src/Assets/UnityTestTools/UnitTesting/Editor/NUnit/Libs/Mono.Cecil.Mdb.dll.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 96c89cba541e8fa41acc13fcc8382878 +MonoAssemblyImporter: + serializedVersion: 1 + iconMap: {} + executionOrder: {} + userData: diff --git a/src/Assets/UnityTestTools/UnitTesting/Editor/NUnit/Libs/Mono.Cecil.dll b/src/Assets/UnityTestTools/UnitTesting/Editor/NUnit/Libs/Mono.Cecil.dll new file mode 100644 index 0000000..5e59e64 Binary files /dev/null and b/src/Assets/UnityTestTools/UnitTesting/Editor/NUnit/Libs/Mono.Cecil.dll differ diff --git a/src/Assets/UnityTestTools/UnitTesting/Editor/NUnit/Libs/Mono.Cecil.dll.meta b/src/Assets/UnityTestTools/UnitTesting/Editor/NUnit/Libs/Mono.Cecil.dll.meta new file mode 100644 index 0000000..242413a --- /dev/null +++ b/src/Assets/UnityTestTools/UnitTesting/Editor/NUnit/Libs/Mono.Cecil.dll.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: f8f4181eb51beb043a92433b1c807529 +MonoAssemblyImporter: + serializedVersion: 1 + iconMap: {} + executionOrder: {} + userData: diff --git a/src/Assets/UnityTestTools/UnitTesting/Editor/NUnit/Libs/nunit.core.dll b/src/Assets/UnityTestTools/UnitTesting/Editor/NUnit/Libs/nunit.core.dll new file mode 100644 index 0000000..e07c4c6 Binary files /dev/null and b/src/Assets/UnityTestTools/UnitTesting/Editor/NUnit/Libs/nunit.core.dll differ diff --git a/src/Assets/UnityTestTools/UnitTesting/Editor/NUnit/Libs/nunit.core.dll.meta b/src/Assets/UnityTestTools/UnitTesting/Editor/NUnit/Libs/nunit.core.dll.meta new file mode 100644 index 0000000..7517631 --- /dev/null +++ b/src/Assets/UnityTestTools/UnitTesting/Editor/NUnit/Libs/nunit.core.dll.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: e8950b8b4aa418a458a503526c8a2f65 +MonoAssemblyImporter: + serializedVersion: 1 + iconMap: {} + executionOrder: {} + userData: diff --git a/src/Assets/UnityTestTools/UnitTesting/Editor/NUnit/Libs/nunit.core.interfaces.dll b/src/Assets/UnityTestTools/UnitTesting/Editor/NUnit/Libs/nunit.core.interfaces.dll new file mode 100644 index 0000000..1f2e48a Binary files /dev/null and b/src/Assets/UnityTestTools/UnitTesting/Editor/NUnit/Libs/nunit.core.interfaces.dll differ diff --git a/src/Assets/UnityTestTools/UnitTesting/Editor/NUnit/Libs/nunit.core.interfaces.dll.meta b/src/Assets/UnityTestTools/UnitTesting/Editor/NUnit/Libs/nunit.core.interfaces.dll.meta new file mode 100644 index 0000000..b68531c --- /dev/null +++ b/src/Assets/UnityTestTools/UnitTesting/Editor/NUnit/Libs/nunit.core.interfaces.dll.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: ef8ce5f8e3e580349ac63ac38e87ee2f +MonoAssemblyImporter: + serializedVersion: 1 + iconMap: {} + executionOrder: {} + userData: diff --git a/src/Assets/UnityTestTools/UnitTesting/Editor/NUnit/Libs/nunit.framework.dll b/src/Assets/UnityTestTools/UnitTesting/Editor/NUnit/Libs/nunit.framework.dll new file mode 100644 index 0000000..3c08520 Binary files /dev/null and b/src/Assets/UnityTestTools/UnitTesting/Editor/NUnit/Libs/nunit.framework.dll differ diff --git a/src/Assets/UnityTestTools/UnitTesting/Editor/NUnit/Libs/nunit.framework.dll.meta b/src/Assets/UnityTestTools/UnitTesting/Editor/NUnit/Libs/nunit.framework.dll.meta new file mode 100644 index 0000000..dad72f0 --- /dev/null +++ b/src/Assets/UnityTestTools/UnitTesting/Editor/NUnit/Libs/nunit.framework.dll.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: f54558e884607254ca91abc9038ac749 +MonoAssemblyImporter: + serializedVersion: 1 + iconMap: {} + executionOrder: {} + userData: diff --git a/src/Assets/UnityTestTools/UnitTesting/Editor/NUnit/Renderer.meta b/src/Assets/UnityTestTools/UnitTesting/Editor/NUnit/Renderer.meta new file mode 100644 index 0000000..e220371 --- /dev/null +++ b/src/Assets/UnityTestTools/UnitTesting/Editor/NUnit/Renderer.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: f94e120956782c5498f559719ff38f2a +folderAsset: yes +DefaultImporter: + userData: diff --git a/src/Assets/UnityTestTools/UnitTesting/Editor/NUnit/Renderer/GroupLine.cs b/src/Assets/UnityTestTools/UnitTesting/Editor/NUnit/Renderer/GroupLine.cs new file mode 100644 index 0000000..4f2f7fb --- /dev/null +++ b/src/Assets/UnityTestTools/UnitTesting/Editor/NUnit/Renderer/GroupLine.cs @@ -0,0 +1,155 @@ +using System.Collections.Generic; +using System.Linq; +using NUnit.Core; +using UnityEditor; +using UnityEngine; +using Event = UnityEngine.Event; + +namespace UnityTest +{ + public class GroupLine : UnitTestRendererLine + { + public static List FoldMarkers; + + protected static GUIContent guiExpandAll = new GUIContent ("Expand all"); + protected static GUIContent guiCollapseAll = new GUIContent ("Collapse all"); + private List children = new List (); + + public GroupLine (TestSuite suite) + : base (suite) + { + if (suite is NamespaceSuite) renderedName = fullName; + } + + private bool Folded + { + get { return FoldMarkers.Contains (fullName); } + + set + { + if (value) + FoldMarkers.Add (fullName); + else + FoldMarkers.RemoveAll (s => s == fullName); + } + } + + public void AddChildren (UnitTestRendererLine[] children) + { + this.children.AddRange (children); + } + + protected internal override void Render (int indend, RenderingOptions options) + { + if (!AnyVisibleChildren (options)) return; + base.Render (indend, options); + if (!Folded) + foreach (var child in children) + child.Render (indend + 1, options); + } + + private bool AnyVisibleChildren (RenderingOptions options) + { + return children.Any (l => l.IsVisible (options) == true); + } + + protected internal override bool IsVisible (RenderingOptions options) + { + return AnyVisibleChildren (options); + } + + protected override void DrawLine (bool isSelected, RenderingOptions options) + { + var resultIcon = GetResult ().HasValue ? GuiHelper.GetIconForResult (GetResult ().Value) : Icons.unknownImg; + + var guiContent = new GUIContent (renderedName, resultIcon, fullName); + + var rect = GUILayoutUtility.GetRect (guiContent, Styles.foldout, GUILayout.MaxHeight (16)); + + OnLeftMouseButtonClick (rect); + OnContextClick (rect); + + EditorGUI.BeginChangeCheck (); + var expanded = !EditorGUI.Foldout (rect, !Folded, guiContent, false, isSelected ? Styles.selectedFoldout : Styles.foldout); + if (EditorGUI.EndChangeCheck ()) Folded = expanded; + } + + protected internal override TestResultState? GetResult () + { + TestResultState? tempResult = null; + + foreach (var child in children) + { + var childResultState = child.GetResult (); + + if (childResultState == TestResultState.Failure || childResultState == TestResultState.Error) + { + tempResult = TestResultState.Failure; + break; + } + if (childResultState == TestResultState.Success) + tempResult = TestResultState.Success; + else if (childResultState == TestResultState.Ignored) + tempResult = TestResultState.Ignored; + } + if (tempResult.HasValue) return tempResult.Value; + + return null; + } + + private void OnLeftMouseButtonClick (Rect rect) + { + if (rect.Contains (Event.current.mousePosition) && Event.current.type == EventType.mouseDown && Event.current.button == 0) + { + OnSelect (); + } + } + + private void OnContextClick (Rect rect) + { + if (rect.Contains (Event.current.mousePosition) && Event.current.type == EventType.ContextClick) + { + PrintGroupContextMenu (); + } + } + + private void PrintGroupContextMenu () + { + var multilineSelection = SelectedLines.Count () > 1; + var m = new GenericMenu (); + if (multilineSelection) + { + m.AddItem (guiRunSelected, + false, + data => RunTests (SelectedLines.Select (line => line.test.TestName).ToArray ()), + ""); + } + if (!string.IsNullOrEmpty (fullName)) + { + m.AddItem (guiRun, + false, + data => RunTests (new[] { test.TestName }), + ""); + } + if (!multilineSelection) + { + m.AddSeparator (""); + + m.AddItem (Folded ? guiExpandAll : guiCollapseAll, + false, + data => ExpandOrCollapseAll (Folded), + ""); + } + m.ShowAsContext (); + } + + private void ExpandOrCollapseAll (bool expand) + { + Folded = !expand; + foreach (var child in children) + { + if (child is GroupLine) (child as GroupLine).ExpandOrCollapseAll (expand); + } + } + } +} diff --git a/src/Assets/UnityTestTools/UnitTesting/Editor/NUnit/Renderer/GroupLine.cs.meta b/src/Assets/UnityTestTools/UnitTesting/Editor/NUnit/Renderer/GroupLine.cs.meta new file mode 100644 index 0000000..9195f33 --- /dev/null +++ b/src/Assets/UnityTestTools/UnitTesting/Editor/NUnit/Renderer/GroupLine.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 4fcef1ec40255f14d827da8b0d742334 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/UnityTestTools/UnitTesting/Editor/NUnit/Renderer/RenderingOptions.cs b/src/Assets/UnityTestTools/UnitTesting/Editor/NUnit/Renderer/RenderingOptions.cs new file mode 100644 index 0000000..49c6ada --- /dev/null +++ b/src/Assets/UnityTestTools/UnitTesting/Editor/NUnit/Renderer/RenderingOptions.cs @@ -0,0 +1,12 @@ +namespace UnityTest +{ + public class RenderingOptions + { + public string nameFilter; + public bool showSucceeded; + public bool showFailed; + public bool showIgnored; + public bool showNotRunned; + public string[] categories; + } +} diff --git a/src/Assets/UnityTestTools/UnitTesting/Editor/NUnit/Renderer/RenderingOptions.cs.meta b/src/Assets/UnityTestTools/UnitTesting/Editor/NUnit/Renderer/RenderingOptions.cs.meta new file mode 100644 index 0000000..6ecfc38 --- /dev/null +++ b/src/Assets/UnityTestTools/UnitTesting/Editor/NUnit/Renderer/RenderingOptions.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 5c0aec4b4a6d1b047a98e8cc213e1a36 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/UnityTestTools/UnitTesting/Editor/NUnit/Renderer/TestLine.cs b/src/Assets/UnityTestTools/UnitTesting/Editor/NUnit/Renderer/TestLine.cs new file mode 100644 index 0000000..2703ab4 --- /dev/null +++ b/src/Assets/UnityTestTools/UnitTesting/Editor/NUnit/Renderer/TestLine.cs @@ -0,0 +1,167 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using NUnit.Core; +using UnityEditor; +using UnityEngine; +using Event = UnityEngine.Event; + +namespace UnityTest +{ + public class TestLine : UnitTestRendererLine, IComparable + { + public static Func GetUnitTestResult; + + protected static GUIContent guiOpenInEditor = new GUIContent ("Open in editor"); + private string resultId; + private IList categories; + + public TestLine (TestMethod test, string resultId) : base (test) + { + renderedName = test.Parent is ParameterizedMethodSuite ? test.TestName.Name : test.MethodName; + this.resultId = resultId; + var c = new List(); + foreach (string category in test.Categories) + { + c.Add (category); + } + foreach (string category in test.Parent.Categories) + { + c.Add (category); + } + categories = c; + } + + public UnitTestResult result + { + get { return GetUnitTestResult (resultId); } + } + + public int CompareTo (TestLine other) + { + return result.Id.CompareTo (other.result.Id); + } + + protected override void DrawLine (bool isSelected, RenderingOptions options) + { + if (!IsVisible (options)) return; + + var tempColor = GUI.color; + if (result.Executed && result.Outdated) GUI.color = new Color (1, 1, 1, 0.7f); + + var icon = result.Executed || result.IsIgnored || result.ResultState == TestResultState.NotRunnable + ? GuiHelper.GetIconForResult (result.ResultState) + : Icons.unknownImg; + if (test.RunState == RunState.Ignored) + icon = GuiHelper.GetIconForResult (TestResultState.Ignored); + + var guiContent = new GUIContent (renderedName, icon, fullName); + + GUILayout.Space (10); + var rect = GUILayoutUtility.GetRect (guiContent, EditorStyles.label, GUILayout.ExpandWidth (true) /*, GUILayout.MaxHeight (18)*/); + + OnLeftMouseButtonClick (rect); + OnContextClick (rect); + + EditorGUI.LabelField (rect, guiContent, isSelected ? Styles.selectedLabel : Styles.label); + + if (result.Outdated) GUI.color = tempColor; + } + + protected internal override TestResultState? GetResult () + { + return result.ResultState; + } + + protected internal override bool IsVisible ( RenderingOptions options ) + { + if (!string.IsNullOrEmpty (options.nameFilter) && !fullName.ToLower().Contains (options.nameFilter.ToLower())) + return false; + if (options.categories != null && options.categories.Length >0 && !options.categories.Any (c => categories.Contains (c))) + return false; + if (!options.showIgnored && (test.RunState == RunState.Ignored || test.RunState == RunState.Skipped)) + return false; + if (!options.showFailed && (result.IsFailure || result.IsError || result.IsInconclusive)) + return false; + if (!options.showNotRunned && !result.Executed) + return false; + if (!options.showSucceeded && result.IsSuccess) + return false; + return true; + } + + public override string GetResultText () + { + var test = result; + var text = test.Name; + if (test.Executed) + text += " (" + test.Duration.ToString ("##0.###") + "s)"; + if (!test.IsSuccess) + { + text += "\n"; + if (!string.IsNullOrEmpty (test.Message)) + { + text += "---\n"; + text += test.Message.Trim (); + } + if (!string.IsNullOrEmpty (test.StackTrace)) + { + var stackTrace = StackTraceFilter.Filter (test.StackTrace).Trim (); + text += "\n---EXCEPTION---\n" + stackTrace; + } + } + return text.Trim (); + } + + private void OnContextClick (Rect rect) + { + if (rect.Contains (Event.current.mousePosition) && Event.current.type == EventType.ContextClick) + { + Event.current.Use (); + PrintTestContextMenu (); + } + } + + private void PrintTestContextMenu () + { + var m = new GenericMenu (); + var multilineSelection = SelectedLines.Count () > 1; + if (multilineSelection) + { + m.AddItem (guiRunSelected, + false, + data => RunTests (SelectedLines.Select (line => line.test.TestName).ToArray ()), + ""); + } + if (!string.IsNullOrEmpty (fullName)) + { + m.AddItem (guiRun, + false, + data => RunTests (new[] { test.TestName }), + ""); + } + if (!multilineSelection) + { + m.AddSeparator (""); + + m.AddItem (guiOpenInEditor, + false, + data => GuiHelper.OpenInEditor (result, false), + ""); + } + m.ShowAsContext (); + } + + private void OnLeftMouseButtonClick (Rect rect) + { + if (rect.Contains (Event.current.mousePosition) && Event.current.type == EventType.MouseDown && Event.current.button == 0) + { + OnSelect (); + if (Event.current.clickCount == 2 && SelectedLines.Count == 1) + { + GuiHelper.OpenInEditor (result, true); + } + } + } + } +} diff --git a/src/Assets/UnityTestTools/UnitTesting/Editor/NUnit/Renderer/TestLine.cs.meta b/src/Assets/UnityTestTools/UnitTesting/Editor/NUnit/Renderer/TestLine.cs.meta new file mode 100644 index 0000000..5f6cf25 --- /dev/null +++ b/src/Assets/UnityTestTools/UnitTesting/Editor/NUnit/Renderer/TestLine.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: cfe0c7d95a79d374e9121633c719241e +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/UnityTestTools/UnitTesting/Editor/NUnit/Renderer/UnitTestRendererLine.cs b/src/Assets/UnityTestTools/UnitTesting/Editor/NUnit/Renderer/UnitTestRendererLine.cs new file mode 100644 index 0000000..dedbbac --- /dev/null +++ b/src/Assets/UnityTestTools/UnitTesting/Editor/NUnit/Renderer/UnitTestRendererLine.cs @@ -0,0 +1,93 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using NUnit.Core; +using UnityEditor; +using UnityEngine; +using Event = UnityEngine.Event; + +namespace UnityTest +{ + public abstract class UnitTestRendererLine : IComparable + { + public static Action RunTest; + public static List SelectedLines; + + protected static bool refresh; + + protected static GUIContent guiRunSelected = new GUIContent ("Run Selected"); + protected static GUIContent guiRun = new GUIContent ("Run"); + protected static GUIContent guiTimeoutIcon = new GUIContent (Icons.stopwatchImg, "Timeout"); + + protected string uniqueId; + protected internal string fullName; + protected string renderedName; + protected internal Test test; + + protected UnitTestRendererLine ( Test test ) + { + this.fullName = test.TestName.FullName; + this.renderedName = test.TestName.Name; + this.uniqueId = test.TestName.UniqueName; + + this.test = test; + } + + public int CompareTo (UnitTestRendererLine other) + { + return uniqueId.CompareTo (other.uniqueId); + } + + public bool Render (RenderingOptions options) + { + refresh = false; + EditorGUIUtility.SetIconSize (new Vector2 (15, 15)); + Render (0, options); + EditorGUIUtility.SetIconSize (Vector2.zero); + return refresh; + } + + protected internal virtual void Render (int indend, RenderingOptions options) + { + EditorGUILayout.BeginHorizontal (); + GUILayout.Space (indend * 10); + DrawLine (SelectedLines.Contains (this), options); + EditorGUILayout.EndHorizontal (); + } + + protected void OnSelect () + { + if (!Event.current.control) SelectedLines.Clear (); + + if (Event.current.control && SelectedLines.Contains (this)) + SelectedLines.Remove (this); + else + SelectedLines.Add (this); + refresh = true; + } + + protected abstract void DrawLine ( bool isSelected, RenderingOptions options ); + protected internal abstract TestResultState? GetResult (); + protected internal abstract bool IsVisible (RenderingOptions options); + + public void RunTests (object[] testObjectsList) + { + RunTest (new TestFilter () { objects = testObjectsList }); + } + + public void RunTests ( string[] testList ) + { + RunTest (new TestFilter (){names = testList}); + } + + public void RunSelectedTests () + { + RunTest (new TestFilter () { objects = SelectedLines.Select (line => line.test.TestName).ToArray () }); + } + + public virtual string GetResultText () + { + return renderedName; + } + } +} diff --git a/src/Assets/UnityTestTools/UnitTesting/Editor/NUnit/Renderer/UnitTestRendererLine.cs.meta b/src/Assets/UnityTestTools/UnitTesting/Editor/NUnit/Renderer/UnitTestRendererLine.cs.meta new file mode 100644 index 0000000..6c73d20 --- /dev/null +++ b/src/Assets/UnityTestTools/UnitTesting/Editor/NUnit/Renderer/UnitTestRendererLine.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: fddb568bfa3ed03438d5c482ea8c6aea +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/UnityTestTools/UnitTesting/Editor/TestRunner.meta b/src/Assets/UnityTestTools/UnitTesting/Editor/TestRunner.meta new file mode 100644 index 0000000..a253f99 --- /dev/null +++ b/src/Assets/UnityTestTools/UnitTesting/Editor/TestRunner.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: 615921b0760fc0c4eaf10b7c88add37b +folderAsset: yes +DefaultImporter: + userData: diff --git a/src/Assets/UnityTestTools/UnitTesting/Editor/TestRunner/BackgroundRunner.cs b/src/Assets/UnityTestTools/UnitTesting/Editor/TestRunner/BackgroundRunner.cs new file mode 100644 index 0000000..1b52f50 --- /dev/null +++ b/src/Assets/UnityTestTools/UnitTesting/Editor/TestRunner/BackgroundRunner.cs @@ -0,0 +1,65 @@ +using System; +using System.Linq; +using System.Net; +using System.Net.Sockets; +using System.Text; +using UnityEditor; +using UnityEngine; + +namespace UnityTest +{ + [InitializeOnLoad] + public partial class UnitTestView + { + static UnitTestView () + { + if (Instance != null && Instance.runOnRecompilation) + EnableBackgroundRunner (true); + } + + #region Background runner + + private static float nextCheck; + private static string uttRecompile = "UTT-recompile"; + + public static void EnableBackgroundRunner ( bool enable ) + { + EditorApplication.update -= BackgroudRunner; + + if (enable) + { + EditorApplication.update += BackgroudRunner; + nextCheck = 0; + } + } + + private static void BackgroudRunner () + { + if (EditorApplication.isPlayingOrWillChangePlaymode) return; + if (!Instance.runOnRecompilation) EnableBackgroundRunner (false); + if (EditorApplication.isCompiling) + { + EditorPrefs.SetString (uttRecompile, Application.dataPath); + EditorApplication.update -= BackgroudRunner; + return; + } + + var t = Time.realtimeSinceStartup; + if (t < nextCheck) return; + nextCheck = t + 0.5f; + + if (EditorPrefs.HasKey (uttRecompile)) + { + var recompile = EditorPrefs.GetString (uttRecompile); + if (recompile == Application.dataPath) + { + Instance.RunTests (); + Instance.Repaint (); + } + EditorPrefs.DeleteKey (uttRecompile); + nextCheck = 0; + } + } + #endregion + } +} diff --git a/src/Assets/UnityTestTools/UnitTesting/Editor/TestRunner/BackgroundRunner.cs.meta b/src/Assets/UnityTestTools/UnitTesting/Editor/TestRunner/BackgroundRunner.cs.meta new file mode 100644 index 0000000..84da919 --- /dev/null +++ b/src/Assets/UnityTestTools/UnitTesting/Editor/TestRunner/BackgroundRunner.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: c0ef055bc08798f448b1adba9948e351 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/UnityTestTools/UnitTesting/Editor/TestRunner/GuiHelper.cs b/src/Assets/UnityTestTools/UnitTesting/Editor/TestRunner/GuiHelper.cs new file mode 100644 index 0000000..561e32d --- /dev/null +++ b/src/Assets/UnityTestTools/UnitTesting/Editor/TestRunner/GuiHelper.cs @@ -0,0 +1,162 @@ +using System; +using System.Linq; +using System.Reflection; +using System.Text.RegularExpressions; +using Mono.Cecil; +using Mono.Cecil.Cil; +using Mono.Cecil.Mdb; +using UnityEditor; +using UnityEditorInternal; +using UnityEngine; + +namespace UnityTest +{ + public static class GuiHelper + { + public static Texture GetIconForResult (TestResultState resultState) + { + switch (resultState) + { + case TestResultState.Success: + return Icons.successImg; + case TestResultState.Failure: + case TestResultState.Error: + return Icons.failImg; + case TestResultState.Ignored: + case TestResultState.Skipped: + return Icons.ignoreImg; + case TestResultState.Inconclusive: + case TestResultState.Cancelled: + case TestResultState.NotRunnable: + return Icons.inconclusiveImg; + default: + return Icons.unknownImg; + } + } + + public static Texture GetIconForResult ( TestResult.ResultType resultState ) + { + switch (resultState) + { + case TestResult.ResultType.Success: + return Icons.successImg; + case TestResult.ResultType.Timeout: + case TestResult.ResultType.Failed: + case TestResult.ResultType.FailedException: + return Icons.failImg; + case TestResult.ResultType.Ignored: + return Icons.ignoreImg; + case TestResult.ResultType.NotRun: + default: + return Icons.unknownImg; + } + } + + private static int ExtractSourceFileLine(string stackTrace) + { + int line = 0; + if (!string.IsNullOrEmpty(stackTrace)) + { + var regEx = new Regex(@".* in (?'path'.*):(?'line'\d+)"); + var matches = regEx.Matches(stackTrace); + for (int i = 0; i < matches.Count; i++) + { + line = int.Parse(matches[i].Groups["line"].Value); + if (line != 0) + break; + } + } + return line; + } + + private static string ExtractSourceFilePath(string stackTrace) + { + string path = ""; + if (!string.IsNullOrEmpty(stackTrace)) + { + var regEx = new Regex(@".* in (?'path'.*):(?'line'\d+)"); + var matches = regEx.Matches(stackTrace); + for (int i = 0; i < matches.Count; i++) + { + path = matches[i].Groups["path"].Value; + if (path != "") + break; + } + } + return path; + } + + public static void OpenInEditor(UnitTestResult test, bool openError) + { + + var sourceFilePath = ExtractSourceFilePath(test.StackTrace); + var sourceFileLine = ExtractSourceFileLine(test.StackTrace); + + if (!openError || sourceFileLine == 0 || string.IsNullOrEmpty (sourceFilePath)) + { + var sp = GetSequencePointOfTest(test); + if (sp != null) + { + sourceFileLine = sp.StartLine; + sourceFilePath = sp.Document.Url; + } + } + + OpenInEditorInternal(sourceFilePath, sourceFileLine); + } + + private static SequencePoint GetSequencePointOfTest(UnitTestResult test) + { + var readerParameters = new ReaderParameters + { + ReadSymbols = true, + SymbolReaderProvider = new MdbReaderProvider (), + ReadingMode = ReadingMode.Immediate + }; + + var assemblyDefinition = AssemblyDefinition.ReadAssembly (test.Test.AssemblyPath, readerParameters); + var classModule = assemblyDefinition.MainModule.Types.Single (t => t.FullName == test.Test.FullClassName); + + var methods = classModule.Methods; + MethodDefinition method = null; + while(classModule.BaseType != null) + { + methods = classModule.Methods; + if(methods.Any(t => t.Name == test.Test.MethodName)) + { + method = classModule.Methods.First(t => t.Name == test.Test.MethodName); + break; + } + classModule = classModule.BaseType as TypeDefinition; + } + if(method !=null) + { + var sp = method.Body.Instructions.First (i => i.SequencePoint != null).SequencePoint; + return sp; + } + return null; + } + + private static void OpenInEditorInternal (string filename, int line) + { + InternalEditorUtility.OpenFileAtLineExternal (filename, line); + } + + public static bool GetConsoleErrorPause () + { + Assembly assembly = Assembly.GetAssembly (typeof (SceneView)); + Type type = assembly.GetType ("UnityEditorInternal.LogEntries"); + PropertyInfo method = type.GetProperty ("consoleFlags"); + var result = (int)method.GetValue (new object (), new object[] { }); + return (result & (1 << 2)) != 0; + } + + public static void SetConsoleErrorPause ( bool b ) + { + Assembly assembly = Assembly.GetAssembly (typeof (SceneView)); + Type type = assembly.GetType ("UnityEditorInternal.LogEntries"); + MethodInfo method = type.GetMethod ("SetConsoleFlag"); + method.Invoke (new object (), new object[] { 1 << 2, b }); + } + } +} diff --git a/src/Assets/UnityTestTools/UnitTesting/Editor/TestRunner/GuiHelper.cs.meta b/src/Assets/UnityTestTools/UnitTesting/Editor/TestRunner/GuiHelper.cs.meta new file mode 100644 index 0000000..596d39f --- /dev/null +++ b/src/Assets/UnityTestTools/UnitTesting/Editor/TestRunner/GuiHelper.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b0b95014154ef554485afc9c0316556d +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/UnityTestTools/UnitTesting/Editor/TestRunner/ITestRunnerCallback.cs b/src/Assets/UnityTestTools/UnitTesting/Editor/TestRunner/ITestRunnerCallback.cs new file mode 100644 index 0000000..14c9274 --- /dev/null +++ b/src/Assets/UnityTestTools/UnitTesting/Editor/TestRunner/ITestRunnerCallback.cs @@ -0,0 +1,13 @@ +using System; + +namespace UnityTest.UnitTestRunner +{ + public interface ITestRunnerCallback + { + void TestStarted (string fullName); + void TestFinished (ITestResult fullName); + void RunStarted (string suiteName, int testCount); + void RunFinished (); + void RunFinishedException (Exception exception); + } +} diff --git a/src/Assets/UnityTestTools/UnitTesting/Editor/TestRunner/ITestRunnerCallback.cs.meta b/src/Assets/UnityTestTools/UnitTesting/Editor/TestRunner/ITestRunnerCallback.cs.meta new file mode 100644 index 0000000..9aea576 --- /dev/null +++ b/src/Assets/UnityTestTools/UnitTesting/Editor/TestRunner/ITestRunnerCallback.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 45a983e950f22034ba987c6db2a8b216 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/UnityTestTools/UnitTesting/Editor/TestRunner/IUnitTestEngine.cs b/src/Assets/UnityTestTools/UnitTesting/Editor/TestRunner/IUnitTestEngine.cs new file mode 100644 index 0000000..2aabadb --- /dev/null +++ b/src/Assets/UnityTestTools/UnitTesting/Editor/TestRunner/IUnitTestEngine.cs @@ -0,0 +1,8 @@ +namespace UnityTest +{ + public interface IUnitTestEngine + { + UnitTestRendererLine GetTests (out UnitTestResult[] results, out string[] categories); + void RunTests ( TestFilter filter, UnitTestRunner.ITestRunnerCallback testRunnerEventListener ); + } +} diff --git a/src/Assets/UnityTestTools/UnitTesting/Editor/TestRunner/IUnitTestEngine.cs.meta b/src/Assets/UnityTestTools/UnitTesting/Editor/TestRunner/IUnitTestEngine.cs.meta new file mode 100644 index 0000000..9eba5da --- /dev/null +++ b/src/Assets/UnityTestTools/UnitTesting/Editor/TestRunner/IUnitTestEngine.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 96615b7fd2cb32b4dbea04d84cc3f7fb +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/UnityTestTools/UnitTesting/Editor/TestRunner/NUnitExtensions.cs b/src/Assets/UnityTestTools/UnitTesting/Editor/TestRunner/NUnitExtensions.cs new file mode 100644 index 0000000..b799a2c --- /dev/null +++ b/src/Assets/UnityTestTools/UnitTesting/Editor/TestRunner/NUnitExtensions.cs @@ -0,0 +1,20 @@ +using NUnit.Core; + +namespace UnityTest +{ + public static class NUnitExtensions + { + public static UnitTestResult UnitTestResult ( this NUnit.Core.TestResult result ) + { + return new UnitTestResult() + { + Executed = result.Executed, + ResultState = (TestResultState)result.ResultState, + Message = result.Message, + StackTrace = result.StackTrace, + Duration = result.Time, + Test = new UnitTestInfo (result.Test.TestName.TestID.ToString ()), + }; + } + } +} diff --git a/src/Assets/UnityTestTools/UnitTesting/Editor/TestRunner/NUnitExtensions.cs.meta b/src/Assets/UnityTestTools/UnitTesting/Editor/TestRunner/NUnitExtensions.cs.meta new file mode 100644 index 0000000..00de790 --- /dev/null +++ b/src/Assets/UnityTestTools/UnitTesting/Editor/TestRunner/NUnitExtensions.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 7df86c5f85b0f7d4096d6bc23e9a4e01 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/UnityTestTools/UnitTesting/Editor/TestRunner/NUnitTestEngine.cs b/src/Assets/UnityTestTools/UnitTesting/Editor/TestRunner/NUnitTestEngine.cs new file mode 100644 index 0000000..dfc3ae8 --- /dev/null +++ b/src/Assets/UnityTestTools/UnitTesting/Editor/TestRunner/NUnitTestEngine.cs @@ -0,0 +1,197 @@ +using System; +using System.Collections.Generic; +using System.Reflection; +using NUnit.Core; +using System.Linq; +using NUnit.Core.Filters; +using UnityEditor; +using UnityEngine; + +namespace UnityTest +{ + public class NUnitTestEngine : IUnitTestEngine + { + static string[] whitelistedAssemblies = + { + "Assembly-CSharp-Editor", + "Assembly-Boo-Editor", + "Assembly-UnityScript-Editor" + }; + private TestSuite testSuite; + + public UnitTestRendererLine GetTests ( out UnitTestResult[] results, out string[] categories ) + { + if (testSuite == null) + { + List assemblies = GetAssembliesWithTests ().Select (a=>a.Location).ToList (); + TestSuite suite = PrepareTestSuite (assemblies); + testSuite = suite; + } + + var resultList = new List (); + var categoryList = new HashSet (); + + UnitTestRendererLine lines = null; + if(testSuite != null) + lines = ParseTestList (testSuite, resultList, categoryList).Single (); + results = resultList.ToArray (); + categories = categoryList.ToArray (); + + return lines; + } + + private UnitTestRendererLine[] ParseTestList ( Test test, List results, HashSet categories ) + { + foreach (string category in test.Categories) categories.Add (category); + + if (test is TestMethod) + { + var result = new UnitTestResult () + { + Test = new UnitTestInfo (test as TestMethod) + }; + + results.Add (result); + return new[] { new TestLine (test as TestMethod, result.Id) }; + } + + GroupLine group = null; + if (test is TestSuite) + group = new GroupLine (test as TestSuite); + + var namespaceList = new List (new []{group}); + + foreach (Test result in test.Tests ) + { + if (result is NamespaceSuite || test is TestAssembly) + namespaceList.AddRange (ParseTestList (result, results, categories)); + else + group.AddChildren (ParseTestList (result, results, categories)); + } + + namespaceList.Sort (); + return namespaceList.ToArray (); + } + + public void RunTests (UnitTestRunner.ITestRunnerCallback testRunnerEventListener) + { + RunTests (TestFilter.Empty, testRunnerEventListener); + } + + public void RunTests ( TestFilter filter, UnitTestRunner.ITestRunnerCallback testRunnerEventListener ) + { + try + { + if (testRunnerEventListener != null) + testRunnerEventListener.RunStarted (testSuite.TestName.FullName, testSuite.TestCount); + + ExecuteTestSuite (testSuite, testRunnerEventListener, filter); + + if (testRunnerEventListener != null) + testRunnerEventListener.RunFinished (); + } + catch (Exception e) + { + Debug.LogException (e); + if (testRunnerEventListener != null) + testRunnerEventListener.RunFinishedException (e); + } + } + + public static Assembly[] GetAssembliesWithTests () + { + var libs = new List (); + foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies ()) + { + if(assembly.GetReferencedAssemblies ().All (a => a.Name != "nunit.framework")) continue; + if (assembly.Location.Replace ('\\', '/').StartsWith (Application.dataPath) + || whitelistedAssemblies.Contains (assembly.GetName ().Name)) libs.Add (assembly); + } + return libs.ToArray (); + } + + private TestSuite PrepareTestSuite(List assemblyList) + { + CoreExtensions.Host.InitializeService(); + var testPackage = new TestPackage (PlayerSettings.productName, assemblyList); + var builder = new TestSuiteBuilder(); + TestExecutionContext.CurrentContext.TestPackage = testPackage; + TestSuite suite = builder.Build(testPackage); + return suite; + } + + private void ExecuteTestSuite ( TestSuite suite, UnitTestRunner.ITestRunnerCallback testRunnerEventListener, TestFilter filter ) + { + EventListener eventListener; + if (testRunnerEventListener == null) + eventListener = new NullListener (); + else + eventListener = new TestRunnerEventListener (testRunnerEventListener); + suite.Run(eventListener, GetFilter(filter)); + } + + private ITestFilter GetFilter (TestFilter filter) + { + var nUnitFilter = new AndFilter(); + + if(filter.names != null && filter.names.Length>0) + nUnitFilter.Add ( new SimpleNameFilter(filter.names)); + if (filter.categories != null && filter.categories.Length > 0) + nUnitFilter.Add (new CategoryFilter(filter.categories)); + if (filter.objects != null && filter.objects.Length > 0) + nUnitFilter.Add (new OrFilter (filter.objects.Where (o => o is TestName).Select(o => new NameFilter (o as TestName)).ToArray ())); + return nUnitFilter; + } + + public class TestRunnerEventListener : EventListener + { + private UnitTestRunner.ITestRunnerCallback testRunnerEventListener; + + public TestRunnerEventListener(UnitTestRunner.ITestRunnerCallback testRunnerEventListener) + { + this.testRunnerEventListener = testRunnerEventListener; + } + + public void RunStarted(string name, int testCount) + { + testRunnerEventListener.RunStarted(name, testCount); + } + + public void RunFinished(NUnit.Core.TestResult result) + { + testRunnerEventListener.RunFinished(); + } + + public void RunFinished(Exception exception) + { + testRunnerEventListener.RunFinishedException(exception); + } + + public void TestStarted(NUnit.Core.TestName testName) + { + testRunnerEventListener.TestStarted(testName.FullName); + } + + public void TestFinished(NUnit.Core.TestResult result) + { + testRunnerEventListener.TestFinished(result.UnitTestResult()); + } + + public void SuiteStarted(NUnit.Core.TestName testName) + { + } + + public void SuiteFinished(NUnit.Core.TestResult result) + { + } + + public void UnhandledException(Exception exception) + { + } + + public void TestOutput(NUnit.Core.TestOutput testOutput) + { + } + } + } +} diff --git a/src/Assets/UnityTestTools/UnitTesting/Editor/TestRunner/NUnitTestEngine.cs.meta b/src/Assets/UnityTestTools/UnitTesting/Editor/TestRunner/NUnitTestEngine.cs.meta new file mode 100644 index 0000000..241b6f9 --- /dev/null +++ b/src/Assets/UnityTestTools/UnitTesting/Editor/TestRunner/NUnitTestEngine.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: f313d48559bf30145b88ef7f173685c9 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/UnityTestTools/UnitTesting/Editor/TestRunner/TestRunner.cs b/src/Assets/UnityTestTools/UnitTesting/Editor/TestRunner/TestRunner.cs new file mode 100644 index 0000000..f55d0ca --- /dev/null +++ b/src/Assets/UnityTestTools/UnitTesting/Editor/TestRunner/TestRunner.cs @@ -0,0 +1,158 @@ +using System; +using System.Linq; +using UnityEditor; +using UnityEngine; +using UnityTest.UnitTestRunner; +using Event = UnityEngine.Event; + +namespace UnityTest +{ + public partial class UnitTestView + { + private void UpdateTestInfo ( ITestResult result ) + { + FindTestResult (result.Id).Update (result, false); + } + + private UnitTestResult FindTestResult( string resultId ) + { + var idx = resultList.FindIndex (testResult => testResult.Id == resultId); + if (idx == -1) + { + Debug.LogWarning ("Id not found for test: " + resultId); + return null; + } + return resultList.ElementAt (idx); + } + + private void RunTests () + { + var filter = new TestFilter(); + var categories = GetSelectedCategories (); + if (categories != null && categories.Length > 0) + filter.categories = categories; + RunTests(filter); + } + + private void RunTests ( TestFilter filter ) + { + if (runTestOnANewScene) + { + if (autoSaveSceneBeforeRun) EditorApplication.SaveScene (); + if (!EditorApplication.SaveCurrentSceneIfUserWantsTo ()) return; + } + + string currentScene = null; + int undoGroup = -1; + if(runTestOnANewScene) + currentScene = OpenNewScene (); + else + undoGroup = RegisterUndo (); + + StartTestRun (filter, new TestRunnerEventListener (UpdateTestInfo)); + + if (runTestOnANewScene) + LoadPreviousScene (currentScene); + else + PerformUndo (undoGroup); + } + + private string OpenNewScene () + { + var currentScene = EditorApplication.currentScene; + if (runTestOnANewScene) + EditorApplication.NewScene (); + return currentScene; + } + + private void LoadPreviousScene ( string currentScene ) + { + if (!string.IsNullOrEmpty (currentScene)) + EditorApplication.OpenScene (currentScene); + else + EditorApplication.NewScene (); + + if (Event.current != null) + GUIUtility.ExitGUI (); + } + + public void StartTestRun ( TestFilter filter, ITestRunnerCallback eventListener) + { + var callbackList = new TestRunnerCallbackList (); + if (eventListener != null) callbackList.Add (eventListener); + testEngine.RunTests ( filter, callbackList ); + } + + private static int RegisterUndo () + { +#if UNITY_4_0 || UNITY_4_0_1 || UNITY_4_1 || UNITY_4_2 + Undo.RegisterSceneUndo ("UnitTestRunSceneSave"); + return -1; +#else + return Undo.GetCurrentGroup (); +#endif + } + + private static void PerformUndo (int undoGroup) + { + EditorUtility.DisplayProgressBar ("Undo", "Reverting changes to the scene", 0); + var undoStartTime = DateTime.Now; +#if UNITY_4_0 || UNITY_4_0_1 || UNITY_4_1 || UNITY_4_2 + Undo.PerformUndo (); +#else + Undo.RevertAllDownToGroup (undoGroup); +#endif + if ((DateTime.Now - undoStartTime).Seconds > 1) + Debug.LogWarning ("Undo after unit test run took " + (DateTime.Now - undoStartTime).Seconds + " seconds. Consider running unit tests on a new scene for better performance."); + EditorUtility.ClearProgressBar (); + } + + public class TestRunnerEventListener : ITestRunnerCallback + { + private Action updateCallback; + + public TestRunnerEventListener ( Action updateCallback ) + { + this.updateCallback = updateCallback; + } + + public void TestStarted (string fullName) + { + EditorUtility.DisplayProgressBar ("Unit Tests Runner", fullName, 1); + } + + public void TestFinished (ITestResult result) + { + updateCallback (result); + } + + public void RunStarted (string suiteName, int testCount) + { + } + + public void RunFinished () + { + EditorUtility.ClearProgressBar (); + } + + public void RunFinishedException (Exception exception) + { + RunFinished (); + } + } + + [MenuItem ("Unity Test Tools/Unit Test Runner %#&u")] + public static void ShowWindow () + { + GetWindow (typeof (UnitTestView)).Show (); + } + } + + public class TestFilter + { + public string[] names; + public string[] categories; + public object[] objects; + public static TestFilter Empty = new TestFilter (); + } +} diff --git a/src/Assets/UnityTestTools/UnitTesting/Editor/TestRunner/TestRunner.cs.meta b/src/Assets/UnityTestTools/UnitTesting/Editor/TestRunner/TestRunner.cs.meta new file mode 100644 index 0000000..19127aa --- /dev/null +++ b/src/Assets/UnityTestTools/UnitTesting/Editor/TestRunner/TestRunner.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: fbf567afda42eec43a7dbb052d318076 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/UnityTestTools/UnitTesting/Editor/TestRunner/TestRunnerCallbackList.cs b/src/Assets/UnityTestTools/UnitTesting/Editor/TestRunner/TestRunnerCallbackList.cs new file mode 100644 index 0000000..c2e1b42 --- /dev/null +++ b/src/Assets/UnityTestTools/UnitTesting/Editor/TestRunner/TestRunnerCallbackList.cs @@ -0,0 +1,61 @@ +using System; +using System.Collections.Generic; + +namespace UnityTest.UnitTestRunner +{ + public class TestRunnerCallbackList : ITestRunnerCallback + { + private List callbackList = new List (); + + public void TestStarted (string fullName) + { + foreach (var unitTestRunnerCallback in callbackList) + { + unitTestRunnerCallback.TestStarted (fullName); + } + } + + public void TestFinished (ITestResult fullName) + { + foreach (var unitTestRunnerCallback in callbackList) + { + unitTestRunnerCallback.TestFinished (fullName); + } + } + + public void RunStarted (string suiteName, int testCount) + { + foreach (var unitTestRunnerCallback in callbackList) + { + unitTestRunnerCallback.RunStarted (suiteName, + testCount); + } + } + + public void RunFinished () + { + foreach (var unitTestRunnerCallback in callbackList) + { + unitTestRunnerCallback.RunFinished (); + } + } + + public void RunFinishedException (Exception exception) + { + foreach (var unitTestRunnerCallback in callbackList) + { + unitTestRunnerCallback.RunFinishedException (exception); + } + } + + public void Add (ITestRunnerCallback callback) + { + callbackList.Add (callback); + } + + public void Remove (ITestRunnerCallback callback) + { + callbackList.Remove (callback); + } + } +} diff --git a/src/Assets/UnityTestTools/UnitTesting/Editor/TestRunner/TestRunnerCallbackList.cs.meta b/src/Assets/UnityTestTools/UnitTesting/Editor/TestRunner/TestRunnerCallbackList.cs.meta new file mode 100644 index 0000000..83288fb --- /dev/null +++ b/src/Assets/UnityTestTools/UnitTesting/Editor/TestRunner/TestRunnerCallbackList.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b7a6cf1b9d1273d4187ba9d5bc91fc30 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/UnityTestTools/UnitTesting/Editor/TestRunner/UnitTestInfo.cs b/src/Assets/UnityTestTools/UnitTesting/Editor/TestRunner/UnitTestInfo.cs new file mode 100644 index 0000000..108e36c --- /dev/null +++ b/src/Assets/UnityTestTools/UnitTesting/Editor/TestRunner/UnitTestInfo.cs @@ -0,0 +1,97 @@ +using System; +using System.IO; +using System.Linq; +using NUnit.Core; +using System.Text.RegularExpressions; + +namespace UnityTest +{ + [Serializable] + public class UnitTestInfo + { + public string ParamName { get; private set; } + public string MethodName { get; private set; } + public string FullMethodName { get; private set; } + public string ClassName { get; private set; } + public string FullClassName { get; private set; } + public string Namespace { get; private set; } + public string FullName { get; private set; } + public string[] Categories { get; private set; } + public string AssemblyPath { get; private set; } + public string Id { get; private set; } + + public UnitTestInfo ( TestMethod testMethod ) + { + if (testMethod == null) + throw new ArgumentException(); + + MethodName = testMethod.MethodName; + FullMethodName = testMethod.Method.ToString (); + ClassName = testMethod.FixtureType.Name; + FullClassName = testMethod.ClassName; + Namespace = testMethod.Method.ReflectedType.Namespace; + FullName = testMethod.TestName.FullName; + ParamName = ExtractMethodCallParametersString (FullName); + Id = testMethod.TestName.TestID.ToString (); + + Categories = testMethod.Categories.Cast().ToArray(); + + AssemblyPath = GetAssemblyPath (testMethod); + } + + private string GetAssemblyPath (TestMethod testMethod) + { + var parent = testMethod as Test; + var assemblyPath = ""; + while (parent != null) + { + parent = parent.Parent; + if (!(parent is TestAssembly)) continue; + var path = (parent as TestAssembly).TestName.FullName; + if (!File.Exists (path)) continue; + assemblyPath = path; + break; + } + return assemblyPath; + } + + public UnitTestInfo (string id) + { + Id = id; + } + + public override bool Equals ( System.Object obj ) + { + if (!(obj is UnitTestInfo)) return false; + + var testInfo = (UnitTestInfo) obj; + return Id == testInfo.Id; + } + + public static bool operator == ( UnitTestInfo a, UnitTestInfo b ) + { + if (((object)a == null) || ((object)b == null)) return false; + return a.Id == b.Id; + } + + public static bool operator != (UnitTestInfo a, UnitTestInfo b) + { + return !(a == b); + } + + public override int GetHashCode () + { + return Id.GetHashCode (); + } + + static string ExtractMethodCallParametersString (string methodFullName) + { + var match = Regex.Match (methodFullName, @"\((.*)\)"); + string result = ""; + if (match.Groups [1].Success) { + result = match.Groups [1].Captures [0].Value; + } + return result; + } + } +} diff --git a/src/Assets/UnityTestTools/UnitTesting/Editor/TestRunner/UnitTestInfo.cs.meta b/src/Assets/UnityTestTools/UnitTesting/Editor/TestRunner/UnitTestInfo.cs.meta new file mode 100644 index 0000000..9198408 --- /dev/null +++ b/src/Assets/UnityTestTools/UnitTesting/Editor/TestRunner/UnitTestInfo.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 39d532431356ff74cb5a51afef8cc308 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/UnityTestTools/UnitTesting/Editor/TestRunner/UnitTestResult.cs b/src/Assets/UnityTestTools/UnitTesting/Editor/TestRunner/UnitTestResult.cs new file mode 100644 index 0000000..29b2671 --- /dev/null +++ b/src/Assets/UnityTestTools/UnitTesting/Editor/TestRunner/UnitTestResult.cs @@ -0,0 +1,60 @@ +using System; +using UnityEngine; + +namespace UnityTest +{ + [Serializable] + public class UnitTestResult : ITestResult + { + public bool Executed { get; set; } + public string Name { get { return Test.MethodName; } } + public string FullName { get { return Test.FullName; } } + public TestResultState ResultState { get; set; } + public UnitTestInfo Test { get; set; } + public string Id { get { return Test.Id; } } + public double Duration { get; set; } + public string Message { get; set; } + public string StackTrace { get; set; } + + public bool Outdated { get; set; } + + public void Update (ITestResult source, bool outdated) + { + this.ResultState = source.ResultState; + this.Duration = source.Duration; + this.Message = source.Message; + this.StackTrace = source.StackTrace; + this.Executed = source.Executed; + this.Outdated = outdated; + } + + #region Helper methods + + public bool IsFailure + { + get { return ResultState == TestResultState.Failure; } + } + + public bool IsError + { + get { return ResultState == TestResultState.Error; } + } + + public bool IsSuccess + { + get { return ResultState == TestResultState.Success; } + } + + public bool IsInconclusive + { + get { return ResultState == TestResultState.Inconclusive; } + } + + public bool IsIgnored + { + get { return ResultState == TestResultState.Ignored; } + } + + #endregion + } +} diff --git a/src/Assets/UnityTestTools/UnitTesting/Editor/TestRunner/UnitTestResult.cs.meta b/src/Assets/UnityTestTools/UnitTesting/Editor/TestRunner/UnitTestResult.cs.meta new file mode 100644 index 0000000..03d07e0 --- /dev/null +++ b/src/Assets/UnityTestTools/UnitTesting/Editor/TestRunner/UnitTestResult.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 925cf9f45ea32814da65f61c1ebd7e6f +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/UnityTestTools/UnitTesting/Editor/TestRunner/UnitTestView.cs b/src/Assets/UnityTestTools/UnitTesting/Editor/TestRunner/UnitTestView.cs new file mode 100644 index 0000000..df8d147 --- /dev/null +++ b/src/Assets/UnityTestTools/UnitTesting/Editor/TestRunner/UnitTestView.cs @@ -0,0 +1,320 @@ +using System; +using System.Linq; +using System.Collections.Generic; +using UnityEngine; +using UnityEditor; + +namespace UnityTest +{ + [Serializable] + public partial class UnitTestView : EditorWindow + { + private static UnitTestView Instance; + private static IUnitTestEngine testEngine = new NUnitTestEngine (); + + [SerializeField] private List resultList = new List (); + [SerializeField] private string[] availableCategories = null; + [SerializeField] private List foldMarkers = new List (); + [SerializeField] private List selectedLines = new List (); + UnitTestRendererLine testLines; + + #region runner steering vars + private Vector2 testListScroll, testInfoScroll; + private float horizontalSplitBarPosition = 200; + private float verticalSplitBarPosition = 300; + #endregion + + #region runner options vars + private bool optionsFoldout; + private bool filtersFoldout; + private bool runOnRecompilation; + private bool horizontalSplit = true; + private bool autoSaveSceneBeforeRun; + private bool runTestOnANewScene; + #endregion + + #region test filter vars + [SerializeField] private int categoriesMask; + private string testFilter = ""; + private bool showFailed = true; + private bool showIgnored = true; + private bool showNotRun = true; + private bool showSucceeded = true; + private Rect toolbarRect; + #endregion + + #region GUI Contents + private readonly GUIContent guiRunSelectedTestsIcon = new GUIContent (Icons.runImg, "Run selected tests"); + private readonly GUIContent guiRunAllTestsIcon = new GUIContent (Icons.runAllImg, "Run all tests"); + private readonly GUIContent guiRerunFailedTestsIcon = new GUIContent (Icons.runFailedImg, "Rerun failed tests"); + private readonly GUIContent guiOptionButton = new GUIContent ("Options", Icons.gearImg); + private readonly GUIContent guiHideButton = new GUIContent ("Hide", Icons.gearImg); + private readonly GUIContent guiRunOnRecompile = new GUIContent ("Run on recompile", "Run all tests after recompilation"); + private readonly GUIContent guiShowDetailsBelowTests = new GUIContent ("Show details below tests", "Show run details below test list"); + private readonly GUIContent guiRunTestsOnNewScene = new GUIContent ("Run tests on a new scene", "Run tests on a new scene"); + private readonly GUIContent guiAutoSaveSceneBeforeRun = new GUIContent ("Autosave scene", "The runner will automaticall save current scene changes before it starts"); + private readonly GUIContent guiShowSucceededTests = new GUIContent ("Succeeded", Icons.successImg, "Show tests that succeeded"); + private readonly GUIContent guiShowFailedTests = new GUIContent ("Failed", Icons.failImg, "Show tests that failed"); + private readonly GUIContent guiShowIgnoredTests = new GUIContent ("Ignored", Icons.ignoreImg, "Show tests that are ignored"); + private readonly GUIContent guiShowNotRunTests = new GUIContent ("Not Run", Icons.unknownImg, "Show tests that didn't run"); + #endregion + + public UnitTestView () + { + title = "Unit Tests Runner"; + resultList.Clear (); + if (EditorPrefs.HasKey ("UTR-runOnRecompilation")) + { + runOnRecompilation = EditorPrefs.GetBool ("UTR-runOnRecompilation"); + runTestOnANewScene = EditorPrefs.GetBool ("UTR-runTestOnANewScene"); + autoSaveSceneBeforeRun = EditorPrefs.GetBool ("UTR-autoSaveSceneBeforeRun"); + horizontalSplit = EditorPrefs.GetBool ("UTR-horizontalSplit"); + showFailed = EditorPrefs.GetBool ("UTR-showFailed"); + showIgnored = EditorPrefs.GetBool ("UTR-showIgnored"); + showNotRun = EditorPrefs.GetBool ("UTR-showNotRun"); + showSucceeded = EditorPrefs.GetBool ("UTR-showSucceeded"); + } + } + + public void SaveOptions() + { + EditorPrefs.SetBool("UTR-runOnRecompilation", runOnRecompilation); + EditorPrefs.SetBool("UTR-runTestOnANewScene", runTestOnANewScene); + EditorPrefs.SetBool("UTR-autoSaveSceneBeforeRun", autoSaveSceneBeforeRun); + EditorPrefs.SetBool("UTR-horizontalSplit", horizontalSplit); + EditorPrefs.SetBool("UTR-showFailed", showFailed); + EditorPrefs.SetBool("UTR-showIgnored", showIgnored); + EditorPrefs.SetBool("UTR-showNotRun", showNotRun); + EditorPrefs.SetBool("UTR-showSucceeded", showSucceeded); + } + + public void OnEnable () + { + Instance = this; + RefreshTests (); + EnableBackgroundRunner (runOnRecompilation); + } + + public void OnDestroy () + { + Instance = null; + EnableBackgroundRunner (false); + } + + public void Awake () + { + RefreshTests (); + } + + public void OnGUI () + { + GUILayout.Space (10); + EditorGUILayout.BeginVertical (); + + EditorGUILayout.BeginHorizontal (); + + var layoutOptions = new[] { + GUILayout.Width(32), + GUILayout.Height(24) + }; + if (GUILayout.Button (guiRunAllTestsIcon, Styles.buttonLeft, layoutOptions)) + { + RunTests(); + GUIUtility.ExitGUI (); + } + if (GUILayout.Button (guiRunSelectedTestsIcon, Styles.buttonMid, layoutOptions)) + { + testLines.RunSelectedTests (); + } + if (GUILayout.Button (guiRerunFailedTestsIcon, Styles.buttonRight, layoutOptions)) + { + testLines.RunTests (resultList.Where(result => result.IsFailure || result.IsError).Select (l => l.FullName).ToArray ()); + } + + GUILayout.FlexibleSpace (); + + if (GUILayout.Button (optionsFoldout ? guiHideButton : guiOptionButton, GUILayout.Height (24), GUILayout.Width (80))) + { + optionsFoldout = !optionsFoldout; + } + EditorGUILayout.EndHorizontal (); + + if (optionsFoldout) DrawOptions(); + + EditorGUILayout.BeginHorizontal (); + EditorGUILayout.LabelField("Filter:", GUILayout.Width(35)); + testFilter = EditorGUILayout.TextField(testFilter, EditorStyles.textField); + + if (availableCategories != null && availableCategories.Length > 1) + categoriesMask = EditorGUILayout.MaskField (categoriesMask, availableCategories, GUILayout.MaxWidth (90)); + + if (GUILayout.Button (filtersFoldout ? "Hide" : "Advanced", GUILayout.Width (80), GUILayout.Height (15))) + filtersFoldout = !filtersFoldout; + EditorGUILayout.EndHorizontal (); + + if (filtersFoldout) + DrawFilters (); + + if (horizontalSplit) + EditorGUILayout.BeginVertical (); + else + EditorGUILayout.BeginHorizontal (GUILayout.ExpandWidth (true)); + + RenderTestList (); + RenderTestInfo (); + + if (horizontalSplit) + EditorGUILayout.EndVertical (); + else + EditorGUILayout.EndHorizontal (); + + EditorGUILayout.EndVertical (); + } + + private string[] GetSelectedCategories () + { + var selectedCategories = new List (); + foreach (var availableCategory in availableCategories) + { + var idx = Array.FindIndex (availableCategories, ( a ) => a == availableCategory); + var mask = 1 << idx; + if ((categoriesMask & mask) != 0) selectedCategories.Add (availableCategory); + } + return selectedCategories.ToArray (); + } + + private void RenderTestList () + { + EditorGUILayout.BeginVertical (Styles.testList); + testListScroll = EditorGUILayout.BeginScrollView (testListScroll, + GUILayout.ExpandWidth (true), + GUILayout.MaxWidth (2000)); + if (testLines != null) + { + var options = new RenderingOptions (); + options.showSucceeded = showSucceeded; + options.showFailed = showFailed; + options.showIgnored = showIgnored; + options.showNotRunned = showNotRun; + options.nameFilter = testFilter; + options.categories = GetSelectedCategories (); + + if (testLines.Render (options)) Repaint (); + } + EditorGUILayout.EndScrollView (); + EditorGUILayout.EndVertical (); + } + + private void RenderTestInfo () + { + var ctrlId = EditorGUIUtility.GetControlID (FocusType.Passive); + var rect = GUILayoutUtility.GetLastRect (); + if (horizontalSplit) + { + rect.y = rect.height + rect.y - 1; + rect.height = 3; + } + else + { + rect.x = rect.width + rect.x - 1; + rect.width = 3; + } + + EditorGUIUtility.AddCursorRect (rect, horizontalSplit ? MouseCursor.ResizeVertical : MouseCursor.ResizeHorizontal); + var e = Event.current; + switch (e.type) + { + case EventType.MouseDown: + if (EditorGUIUtility.hotControl == 0 && rect.Contains (e.mousePosition)) + EditorGUIUtility.hotControl = ctrlId; + break; + case EventType.MouseDrag: + if (EditorGUIUtility.hotControl == ctrlId) + { + horizontalSplitBarPosition -= e.delta.y; + if (horizontalSplitBarPosition < 20) horizontalSplitBarPosition = 20; + verticalSplitBarPosition -= e.delta.x; + if (verticalSplitBarPosition < 20) verticalSplitBarPosition = 20; + Repaint (); + } + + break; + case EventType.MouseUp: + if (EditorGUIUtility.hotControl == ctrlId) + EditorGUIUtility.hotControl = 0; + break; + } + testInfoScroll = EditorGUILayout.BeginScrollView (testInfoScroll, horizontalSplit + ? GUILayout.MinHeight (horizontalSplitBarPosition) + : GUILayout.Width (verticalSplitBarPosition)); + + var text = ""; + if (selectedLines.Any ()) + { + text = selectedLines.First ().GetResultText (); + } + EditorGUILayout.TextArea (text, Styles.info); + + EditorGUILayout.EndScrollView (); + } + + private void DrawFilters () + { + EditorGUI.BeginChangeCheck(); + EditorGUILayout.BeginHorizontal (); + showSucceeded = GUILayout.Toggle (showSucceeded, guiShowSucceededTests, GUI.skin.FindStyle (GUI.skin.button.name + "left"), GUILayout.ExpandWidth (true)); + showFailed = GUILayout.Toggle (showFailed, guiShowFailedTests, GUI.skin.FindStyle (GUI.skin.button.name + "mid")); + showIgnored = GUILayout.Toggle (showIgnored, guiShowIgnoredTests, GUI.skin.FindStyle (GUI.skin.button.name + "mid")); + showNotRun = GUILayout.Toggle (showNotRun, guiShowNotRunTests, GUI.skin.FindStyle (GUI.skin.button.name + "right"), GUILayout.ExpandWidth (true)); + EditorGUILayout.EndHorizontal (); + if (EditorGUI.EndChangeCheck()) SaveOptions(); + } + + + + private void DrawOptions () + { + EditorGUI.BeginChangeCheck (); + + EditorGUI.BeginChangeCheck (); + runOnRecompilation = EditorGUILayout.Toggle (guiRunOnRecompile, runOnRecompilation); + if (EditorGUI.EndChangeCheck ()) EnableBackgroundRunner (runOnRecompilation); + + runTestOnANewScene = EditorGUILayout.Toggle (guiRunTestsOnNewScene, runTestOnANewScene); + EditorGUI.BeginDisabledGroup (!runTestOnANewScene); + autoSaveSceneBeforeRun = EditorGUILayout.Toggle (guiAutoSaveSceneBeforeRun, autoSaveSceneBeforeRun); + EditorGUI.EndDisabledGroup (); + horizontalSplit = EditorGUILayout.Toggle (guiShowDetailsBelowTests, horizontalSplit); + + if (EditorGUI.EndChangeCheck ()) + { + SaveOptions(); + } + EditorGUILayout.Space (); + } + + + + private void RefreshTests () + { + UnitTestResult[] newResults; + testLines = testEngine.GetTests (out newResults, out availableCategories); + + foreach (var newResult in newResults) + { + var result = resultList.Where (t => t.Test == newResult.Test && t.FullName == newResult.FullName).ToArray(); + if (result.Count () != 1) continue; + newResult.Update(result.Single(), true); + } + + UnitTestRendererLine.SelectedLines = selectedLines; + UnitTestRendererLine.RunTest = RunTests; + GroupLine.FoldMarkers = foldMarkers; + TestLine.GetUnitTestResult = FindTestResult; + + resultList = new List (newResults); + + Repaint (); + } + } +} diff --git a/src/Assets/UnityTestTools/UnitTesting/Editor/TestRunner/UnitTestView.cs.meta b/src/Assets/UnityTestTools/UnitTesting/Editor/TestRunner/UnitTestView.cs.meta new file mode 100644 index 0000000..55bd700 --- /dev/null +++ b/src/Assets/UnityTestTools/UnitTesting/Editor/TestRunner/UnitTestView.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ba152083ecc3cdb4a82881c6a9ae73c1 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/UnityTestTools/UnitTesting/Editor/UnityUnitTest.cs b/src/Assets/UnityTestTools/UnitTesting/Editor/UnityUnitTest.cs new file mode 100644 index 0000000..e6f4d7b --- /dev/null +++ b/src/Assets/UnityTestTools/UnitTesting/Editor/UnityUnitTest.cs @@ -0,0 +1,26 @@ +using NUnit.Framework; +using UnityEditor; +using UnityEngine; + +[TestFixture] +public abstract class UnityUnitTest +{ + public GameObject CreateGameObject () + { + return CreateGameObject (""); + } + + public GameObject CreateGameObject ( string name ) + { + var go = string.IsNullOrEmpty (name) ? new GameObject () : new GameObject (name); + Undo.RegisterCreatedObjectUndo (go,""); + return go; + } + + public GameObject CreatePrimitive ( PrimitiveType type ) + { + var p = GameObject.CreatePrimitive (type); + Undo.RegisterCreatedObjectUndo (p, ""); + return p; + } +} diff --git a/src/Assets/UnityTestTools/UnitTesting/Editor/UnityUnitTest.cs.meta b/src/Assets/UnityTestTools/UnitTesting/Editor/UnityUnitTest.cs.meta new file mode 100644 index 0000000..0185d4b --- /dev/null +++ b/src/Assets/UnityTestTools/UnitTesting/Editor/UnityUnitTest.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 3ec01611d948e574c99a1bd24650a4a9 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/UnityTestTools/changelog.txt b/src/Assets/UnityTestTools/changelog.txt new file mode 100644 index 0000000..3145e0b --- /dev/null +++ b/src/Assets/UnityTestTools/changelog.txt @@ -0,0 +1,109 @@ +Version 1.3.2 + +- Fixed integration tests performance issues + +Version 1.3.1 + +- Updated Japanese docs + +Version 1.3 + +Fixes: +(unit tests) +- nUnit will no longer change the Environment.CurrentDirectory when running tests +- fixed issues with asserting GameObject == null +(integration tests) +- fix the issue with passing or failing test in first frame +- fixed bug where ignored tests were still run in ITF +(assertion component) +- fixed resolving properties to include derived types + +Improvements: +(unit tests) +- refactored result renderer +- reenabled Random attribute +- added Category filter +- NSubstitute updated to version 1.7.2 +- result now will be dimmed after recompilation +- running tests in background will now work without having the window focused +- all assemblies in the project referencing 'nunit.framework' will now be included in the test list +(integration tests) +- updated platform exclusion mechanism +- refactored result renderer +- the runner should work even if the runner window is not focused +- added possibility to create integration tests from code +- the runner will now always run in background (if the window is not focused) +(assertion component) +- added API for creating assertions from code +- added new example +(common) +- GUI improvements +- you no longer need to change the path to icons when moving the tools to another directory +- made test details/results resizeable and scrollable +- added character escape for generated result XML + +Version 1.2.1 +- Fixed Unit Test Batch runner + +Version 1.2 +Fixes: +- Windows Store related compilation issues +- other +Improvements: +(unit tests) +- unit test runner can run in background now without having the runner window open +- unit test batch runner can take a result file path as a parameter +- changed undo system for unit test runner and UnityUnitTest base class +- execution time in now visible in test details +- fixed a bug with tests that inherit from a base test class +(integration tests) +- added hierarchical structure for integration tests +- added Player runner to automate running integration tests on platforms +- Integration tests batch runner can take a result directory as a parameter +- Integration tests batch runner can run tests on platforms +- results are rendered in a player +(assertion component) +- changed default failure messages +- it's possible to override failure action on comparer failure +- added code stripper for assertions. +- vast performance improvement +- fixed bugs +Other: +- "Hide in hierarchy" option was removed from integration test runner +- "Focus on selection" option was removed from integration test runner +- "Hide test runner" option was removed from integration test runner +- result files for unit tests and integration tests are now not generated when running tests from the editor +- UI improvements +- removed UnityScript and Boo examples +- WP8 compatibility fixes + +Version 1.1.1 +Other: +- Documentation in Japanese was added + +Version 1.1 +Fixes: +- fixed display error that happened when unit test class inherited from another TestFixture class +- fixed false positive result when "Succeed on assertions" was checked and no assertions were present in the test +- fixed XmlResultWriter to be generate XML file compatible with XSD scheme +- XmlResultWriter result writer was rewritten to remove XML libraries dependency +- Fixed an issue with a check that should be executed once after a specified frame in OnUpdate. +- added missing file UnityUnitTest.cs +Improvements: +- Added Japanese translation of the documentation +- ErrorPause value will be reverted to previous state after test run finishes +- Assertion Component will not copy reference to a GameObject if the GameObject is the same as the component is attached to. Instead, it will set the reference to the new GameObject. +- Integration tests batch runner can now run multiple scenes +- Unit test runner will now include tests written in UnityScript and Boo +- Unit tests will not run automatically if the compilation failes +- Added scene auto-save option to the Unit Test Runner +Other: +- changed icons +- restructured project files +- moved XmlResultWriter to Common folder +- added UnityScript and Boo unit tests examples +- added more unit tests examples +- Test runners visual adjustments + +Version 1.0 +- Initial release \ No newline at end of file diff --git a/src/Assets/UnityTestTools/changelog.txt.meta b/src/Assets/UnityTestTools/changelog.txt.meta new file mode 100644 index 0000000..8c28fef --- /dev/null +++ b/src/Assets/UnityTestTools/changelog.txt.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: 29b770d9107643740b69cb98b00430aa +TextScriptImporter: + userData: diff --git a/src/Assets/quickgraph4unity.meta b/src/Assets/quickgraph4unity.meta new file mode 100644 index 0000000..aeed3a7 --- /dev/null +++ b/src/Assets/quickgraph4unity.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: 65cd09552d83d4bd88d57e7cd286bf82 +folderAsset: yes +DefaultImporter: + userData: diff --git a/src/Assets/quickgraph4unity/Editor.meta b/src/Assets/quickgraph4unity/Editor.meta new file mode 100644 index 0000000..af54a4f --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: f6e6e086edcd7408a8a7f294e2c16ad8 +folderAsset: yes +DefaultImporter: + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests.meta b/src/Assets/quickgraph4unity/Editor/Tests.meta new file mode 100644 index 0000000..1e4c905 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: d95440520d3484083bedeacd296fa32c +folderAsset: yes +DefaultImporter: + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests.meta new file mode 100644 index 0000000..b8bb444 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: af4bc4c61b3ed46f0b8821afec1eaccd +folderAsset: yes +DefaultImporter: + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/AdjacencyGraphFactory.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/AdjacencyGraphFactory.cs new file mode 100755 index 0000000..71d8986 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/AdjacencyGraphFactory.cs @@ -0,0 +1,150 @@ +using System; +using QuickGraph.Unit; +using Microsoft.Pex.Framework; +using QuickGraph; + +namespace QuickGraph { + public class NamedVertex : IdentifiableVertex { + private string name; + public NamedVertex(string id) + : base(id) { } + + [System.Xml.Serialization.XmlAttribute] + public string Name { + get { return this.name; } + set { this.name = value; } + } + + public sealed class Factory : IIdentifiableVertexFactory { + public NamedVertex CreateVertex(string id) { + return new NamedVertex(id); + } + } + } + + public class NamedEdge : IdentifiableEdge { + private string name; + public NamedEdge(string id, NamedVertex source, NamedVertex target) + : base(id, source, target) { } + + [System.Xml.Serialization.XmlAttribute] + public string Name { + get { return this.name; } + set { this.name = value; } + } + + public sealed class Factory : IIdentifiableEdgeFactory { + public NamedEdge CreateEdge(string id, NamedVertex source, NamedVertex target) { + return new NamedEdge(id, source, target); + } + } + } + + public class AdjacencyGraphFactory + { + private static AdjacencyGraph> CreateGraph() + { + return new AdjacencyGraph>(false); + } + + public static Type CreateType() + { + return typeof(AdjacencyGraph>); + } + + [Factory] + public AdjacencyGraph> Empty() + { + return CreateGraph(); + } + + [Factory] + public AdjacencyGraph> NoEdges() + { + AdjacencyGraph> g = CreateGraph(); + GraphFactory.NoEdges(g); + return g; + } + + [Factory] + public AdjacencyGraph> Loop() + { + AdjacencyGraph> g = CreateGraph(); + GraphFactory.Loop(g); + return g; + } + + [Factory] + public AdjacencyGraph> LoopDouble() + { + AdjacencyGraph> g = CreateGraph(); + GraphFactory.LoopDouble(g); + return g; + } + + [Factory] + public AdjacencyGraph> FileDependency() + { + AdjacencyGraph> g = CreateGraph(); + GraphFactory.FileDependency(g); + return g; + } + + [Factory] + public AdjacencyGraph> RegularLattice10x10() + { + AdjacencyGraph> g = CreateGraph(); + GraphFactory.RegularLattice(10, 10, g); + return g; + } + + [Factory] + public AdjacencyGraph> Simple() + { + AdjacencyGraph> g = CreateGraph(); + GraphFactory.Simple(g); + return g; + } + + [Factory] + public AdjacencyGraph> UnBalancedFlow() + { + AdjacencyGraph> g = CreateGraph(); + GraphFactory.UnBalancedFlow(g); + return g; + } + + [Factory] + public AdjacencyGraph SimpleIdentifiable() + { + return Convert(Simple()); + } + + private static AdjacencyGraph Convert(AdjacencyGraph> g) + { + AdjacencyGraph cg = + new AdjacencyGraph(); + System.Collections.Generic.Dictionary vertices = new System.Collections.Generic.Dictionary(g.VertexCount); + foreach (string v in g.Vertices) + { + NamedVertex iv = new NamedVertex(v); + iv.Name = v; + vertices.Add(v, iv); + cg.AddVertex(iv); + } + int count = 0; + foreach(Edge e in g.Edges) + { + NamedEdge edge = new NamedEdge( + count.ToString(), + vertices[e.Source], + vertices[e.Target] + ); + edge.Name = edge.Source.Name + "->" + edge.Target.Name; + cg.AddEdge(edge); + count++; + } + return cg; + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/AdjacencyGraphFactory.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/AdjacencyGraphFactory.cs.meta new file mode 100644 index 0000000..52e2872 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/AdjacencyGraphFactory.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 54a8b300bedb542f4961c3df8140afad +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms.meta new file mode 100644 index 0000000..cf447bf --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: 2857065f179244e80a20e67ed424f736 +folderAsset: yes +DefaultImporter: + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/CentralityApproximationAlgorithmTest.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/CentralityApproximationAlgorithmTest.cs new file mode 100755 index 0000000..debd940 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/CentralityApproximationAlgorithmTest.cs @@ -0,0 +1,10 @@ +using System; +using QuickGraph.Unit; + +namespace QuickGraph.Algorithms +{ + [TestFixture] + public class CentralityApproximationAlgorithmTest + { + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/CentralityApproximationAlgorithmTest.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/CentralityApproximationAlgorithmTest.cs.meta new file mode 100644 index 0000000..98e2abd --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/CentralityApproximationAlgorithmTest.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 1345a7aef9b3643eabe2a9aef9d28db0 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/Condensation.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/Condensation.meta new file mode 100644 index 0000000..bf0eec3 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/Condensation.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: 4f092405f9d2542239adf313b18f0eec +folderAsset: yes +DefaultImporter: + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/Condensation/StronglyConnectedCondensationGraphAlgorithmTest.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/Condensation/StronglyConnectedCondensationGraphAlgorithmTest.cs new file mode 100755 index 0000000..b379bac --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/Condensation/StronglyConnectedCondensationGraphAlgorithmTest.cs @@ -0,0 +1,95 @@ +using System; +using System.IO; +using System.Collections.Generic; + +using QuickGraph.Unit; + +using QuickGraph.Algorithms.Condensation; +using Microsoft.Pex.Framework; + +namespace QuickGraph.Algorithms.Condensation +{ + [PexClass] + [TypeFixture(typeof(IMutableVertexAndEdgeListGraph>))] + [TypeFactory(typeof(AdjacencyGraphFactory))] + [TypeFactory(typeof(BidirectionalGraphFactory))] + public partial class StronglyConnectedCondensationGraphAlgorithmTest + { + private CondensationGraphAlgorithm,AdjacencyGraph>> algo; + [Test, PexMethod] + public void CondensateAndCheckVertexCount( + [PexAssumeNotNull]IVertexAndEdgeListGraph> g) + { + this.algo = new CondensationGraphAlgorithm, AdjacencyGraph>>(g); + algo.Compute(); + CheckVertexCount(g); + } + + [Test, PexMethod] + public void CondensateAndCheckEdgeCount( + [PexAssumeNotNull]IVertexAndEdgeListGraph> g) + { + this.algo = new CondensationGraphAlgorithm, AdjacencyGraph>>(g); + algo.Compute(); + CheckEdgeCount(g); + } + [Test, PexMethod] + public void CondensateAndCheckComponentCount( + [PexAssumeNotNull]IVertexAndEdgeListGraph> g) + { + this.algo = new CondensationGraphAlgorithm, AdjacencyGraph>>(g); + algo.Compute(); + CheckComponentCount(g); + } + [Test, PexMethod] + public void CondensateAndCheckDAG( + [PexAssumeNotNull]IVertexAndEdgeListGraph> g) + { + this.algo = new CondensationGraphAlgorithm, AdjacencyGraph>>(g); + algo.Compute(); + CheckDAG(g); + } + + private void CheckVertexCount( + IVertexAndEdgeListGraph> g) + { + int count = 0; + foreach (AdjacencyGraph> vertices in this.algo.CondensatedGraph.Vertices) + count += vertices.VertexCount; + Assert.AreEqual(g.VertexCount, count, "VertexCount does not match"); + } + + private void CheckEdgeCount(IVertexAndEdgeListGraph> g) + { + // check edge count + int count = 0; + foreach (CondensatedEdge, AdjacencyGraph>> edges in this.algo.CondensatedGraph.Edges) + count += edges.Edges.Count; + foreach (AdjacencyGraph> vertices in this.algo.CondensatedGraph.Vertices) + count += vertices.EdgeCount; + Assert.AreEqual(g.EdgeCount, count, "EdgeCount does not match"); + } + + + private void CheckComponentCount(IVertexAndEdgeListGraph> g) + { + // check number of vertices = number of storngly connected components + int components = AlgoUtility.StronglyConnectedComponents>(g, new Dictionary()); + Assert.AreEqual(components, algo.CondensatedGraph.VertexCount, "ComponentCount does not match"); + } + + private void CheckDAG(IVertexAndEdgeListGraph> g) + { + // check it's a dag + try + { + AlgoUtility.TopologicalSort(this.algo.CondensatedGraph); + } + catch (NonAcyclicGraphException) + { + Assert.Fail("Graph is not a DAG."); + } + + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/Condensation/StronglyConnectedCondensationGraphAlgorithmTest.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/Condensation/StronglyConnectedCondensationGraphAlgorithmTest.cs.meta new file mode 100644 index 0000000..75a5989 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/Condensation/StronglyConnectedCondensationGraphAlgorithmTest.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 13350b50ef88c4b9bb3755dfcd9282bf +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/Condensation/WeaklyConnectedCondensationGraphTest.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/Condensation/WeaklyConnectedCondensationGraphTest.cs new file mode 100755 index 0000000..10c210f --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/Condensation/WeaklyConnectedCondensationGraphTest.cs @@ -0,0 +1,70 @@ +using System; +using System.IO; +using System.Collections.Generic; + +using QuickGraph.Unit; + +using QuickGraph.Algorithms.Condensation; + +namespace QuickGraph.Algorithms.Condensation +{ + [TypeFixture(typeof(IMutableVertexAndEdgeListGraph>))] + [TypeFactory(typeof(AdjacencyGraphFactory))] + [TypeFactory(typeof(BidirectionalGraphFactory))] + public class WeaklyConnectedCondensationGraphAlgorithmTest + { + private CondensationGraphAlgorithm, AdjacencyGraph>> algo; + [Test] + public void CondensateAndCheckVertexCount(IVertexAndEdgeListGraph> g) + { + this.algo = new CondensationGraphAlgorithm, AdjacencyGraph>>(g); + this.algo.StronglyConnected = false; + algo.Compute(); + CheckVertexCount(g); + } + + [Test] + public void CondensateAndCheckEdgeCount(IVertexAndEdgeListGraph> g) + { + this.algo = new CondensationGraphAlgorithm, AdjacencyGraph>>(g); + this.algo.StronglyConnected = false; + algo.Compute(); + CheckEdgeCount(g); + } + [Test] + public void CondensateAndCheckComponentCount(IVertexAndEdgeListGraph> g) + { + this.algo = new CondensationGraphAlgorithm, AdjacencyGraph>>(g); + this.algo.StronglyConnected = false; + algo.Compute(); + CheckComponentCount(g); + } + + private void CheckVertexCount(IVertexAndEdgeListGraph> g) + { + int count = 0; + foreach (AdjacencyGraph> vertices in this.algo.CondensatedGraph.Vertices) + count += vertices.VertexCount; + Assert.AreEqual(g.VertexCount, count, "VertexCount does not match"); + } + + private void CheckEdgeCount(IVertexAndEdgeListGraph> g) + { + // check edge count + int count = 0; + foreach (CondensatedEdge, AdjacencyGraph>> edges in this.algo.CondensatedGraph.Edges) + count += edges.Edges.Count; + foreach (AdjacencyGraph> vertices in this.algo.CondensatedGraph.Vertices) + count += vertices.EdgeCount; + Assert.AreEqual(g.EdgeCount, count, "EdgeCount does not match"); + } + + + private void CheckComponentCount(IVertexAndEdgeListGraph> g) + { + // check number of vertices = number of storngly connected components + int components = AlgoUtility.WeaklyConnectedComponents>(g, new Dictionary()); + Assert.AreEqual(components, algo.CondensatedGraph.VertexCount, "ComponentCount does not match"); + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/Condensation/WeaklyConnectedCondensationGraphTest.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/Condensation/WeaklyConnectedCondensationGraphTest.cs.meta new file mode 100644 index 0000000..03ae468 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/Condensation/WeaklyConnectedCondensationGraphTest.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 46599d0997e094ccc8180a58a79f9c47 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/DoubleDenseMatrixFactory.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/DoubleDenseMatrixFactory.cs new file mode 100755 index 0000000..0108cbf --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/DoubleDenseMatrixFactory.cs @@ -0,0 +1,41 @@ +using System; +using QuickGraph.Unit; +using QuickGraph.Algorithms.Matrix; + +namespace QuickGraph.Algorithms +{ + public class DoubleDenseMatrixFactory + { + [Factory] + public DoubleDenseMatrix Identity2() + { + return DoubleDenseMatrix.Identity(2); + } + + [Factory] + public DoubleDenseMatrix Zero2() + { + return new DoubleDenseMatrix(2, 2); + } + + [Factory] + public DoubleDenseMatrix Chain() + { + DoubleDenseMatrix m = new DoubleDenseMatrix(3, 3); + m[0, 1] = 1; + m[1, 2] = 1; + return m; + } + + [Factory] + public DoubleDenseMatrix Evenly23() + { + DoubleDenseMatrix m = new DoubleDenseMatrix(2, 3); + int k = 0; + for (int i = 0; i < m.RowCount; ++i) + for (int j = 0; j < m.ColumnCount; ++j) + m[i, j] = k++; + return m; + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/DoubleDenseMatrixFactory.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/DoubleDenseMatrixFactory.cs.meta new file mode 100644 index 0000000..0724e26 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/DoubleDenseMatrixFactory.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: f4a809053e1904678af346c59a3f69e7 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/DoubleDenseMatrixTest.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/DoubleDenseMatrixTest.cs new file mode 100755 index 0000000..c772f64 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/DoubleDenseMatrixTest.cs @@ -0,0 +1,34 @@ +using System; +using QuickGraph.Unit; +using QuickGraph.Algorithms.Matrix; +using Microsoft.Pex.Framework; + +namespace QuickGraph.Algorithms +{ + [TestFixture, PexClass] + public partial class DoubleDenseMatrixTest + { + [PexMethod] + public void ToString([PexAssumeNotNull]DoubleDenseMatrix matrix) + { + Console.WriteLine(matrix); + } + + [PexMethod] + public void WriteMatrix([PexAssumeNotNull]DoubleDenseMatrix matrix) + { + matrix.WriteMatrix(Console.Out); + } + + [PexMethod] + public void SelfSimilarity([PexAssumeNotNull]DoubleDenseMatrix matrix) + { + Console.WriteLine("Matrix"); + matrix.WriteMatrix(Console.Out); + + Console.WriteLine("Similarity"); + DoubleDenseMatrix similarity = DoubleDenseMatrix.Similarity(matrix, matrix, 0.001); + similarity.WriteMatrix(Console.Out); + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/DoubleDenseMatrixTest.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/DoubleDenseMatrixTest.cs.meta new file mode 100644 index 0000000..01ac988 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/DoubleDenseMatrixTest.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e80a3d8fe35aa4143964ca36035bf41d +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/EulerianTrailAlgorithmTest.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/EulerianTrailAlgorithmTest.cs new file mode 100755 index 0000000..64874de --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/EulerianTrailAlgorithmTest.cs @@ -0,0 +1,55 @@ +using System; +using System.Collections.Generic; + +using QuickGraph.Unit; + +namespace QuickGraph.Algorithms +{ +// [TypeFixture(typeof(IVertexAndEdgeListGraph>))] +// [TypeFactory(typeof(AdjacencyGraphFactory))] +// [TypeFactory(typeof(BidirectionalGraphFactory))] + public class EulerianTrailAlgorithmTest + { + [Test] + public void ComputeTrail(IMutableVertexAndEdgeListGraph> g) + { + if (g.VertexCount == 0) + return; + + GraphConsoleSerializer.DisplayGraph(g); + + int oddCount = 0; + foreach (string v in g.Vertices) + if (g.OutDegree(v) % 2 == 0) + oddCount++; + + int circuitCount = EulerianTrailAlgorithm>.ComputeEulerianPathCount(g); + if (circuitCount == 0) + return; + + EulerianTrailAlgorithm> trail = new EulerianTrailAlgorithm>(g); + trail.AddTemporaryEdges(new EdgeFactory()); + trail.Compute(); + ICollection>> trails = trail.Trails(); + trail.RemoveTemporaryEdges(); + + Console.WriteLine("trails: {0}", trails.Count); + int index = 0; + foreach (ICollection> t in trails) + { + Console.WriteLine("trail {0}", index++); + foreach (Edge edge in t) + Console.WriteLine("\t{0}", t); + } + + // lets make sure all the edges are in the trail + Dictionary, GraphColor> edgeColors = new Dictionary, GraphColor>(g.EdgeCount); + foreach (Edge edge in g.Edges) + edgeColors.Add(edge, GraphColor.White); + foreach (ICollection> t in trails) + foreach (Edge edge in t) + CollectionAssert.ContainsKey(edgeColors, edge); + + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/EulerianTrailAlgorithmTest.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/EulerianTrailAlgorithmTest.cs.meta new file mode 100644 index 0000000..b240d8c --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/EulerianTrailAlgorithmTest.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 052a825892a71412aa31e7e2f65edfa2 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/MaximumFlow.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/MaximumFlow.meta new file mode 100644 index 0000000..dc5d9df --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/MaximumFlow.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: 630609d0f8091458bad5ffe2468cea1b +folderAsset: yes +DefaultImporter: + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/MaximumFlow/AllVerticesGraphAugmentorAlgorithmTest.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/MaximumFlow/AllVerticesGraphAugmentorAlgorithmTest.cs new file mode 100755 index 0000000..71c0fac --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/MaximumFlow/AllVerticesGraphAugmentorAlgorithmTest.cs @@ -0,0 +1,96 @@ +using System; +using QuickGraph.Unit; + +namespace QuickGraph.Algorithms.MaximumFlow +{ + [TypeFixture(typeof(IMutableVertexAndEdgeListGraph>))] + [TypeFactory(typeof(AdjacencyGraphFactory))] + [TypeFactory(typeof(BidirectionalGraphFactory))] + public class AllVerticesGraphAugmentorAlgorithmTest + { + private AllVerticesGraphAugmentorAlgorithm> augmentor; + + public void SetUp(IMutableVertexAndEdgeListGraph> g) + { + this.augmentor = new AllVerticesGraphAugmentorAlgorithm>( + g, + new StringVertexFactory(), + new EdgeFactory() + ); + } + + [TearDown] + public void TearDown() + { + if (this.augmentor != null) + { + this.augmentor.Rollback(); + this.augmentor = null; + } + } + + [Test] + public void AddSuperSourceAndSink(IMutableVertexAndEdgeListGraph> g) + { + SetUp(g); + int vertexCount = g.VertexCount; + this.augmentor.Compute(); + + Assert.AreEqual(vertexCount + 2, g.VertexCount); + Assert.IsTrue(g.ContainsVertex(this.augmentor.SuperSource)); + Assert.IsTrue(g.ContainsVertex(this.augmentor.SuperSink)); + } + + [Test] + public void AddAndRemove(IMutableVertexAndEdgeListGraph> g) + { + SetUp(g); + int vertexCount = g.VertexCount; + int edgeCount = g.EdgeCount; + this.augmentor.Compute(); + this.augmentor.Rollback(); + Assert.AreEqual(g.VertexCount, vertexCount); + Assert.AreEqual(g.EdgeCount, edgeCount); + } + + [Test] + public void AddAndVerifySourceConnected(IMutableVertexAndEdgeListGraph> g) + { + SetUp(g); + this.augmentor.Compute(); + foreach (string v in g.Vertices) + { + if (v == this.augmentor.SuperSource) + continue; + if (v == this.augmentor.SuperSink) + continue; + Assert.IsTrue(g.ContainsEdge(this.augmentor.SuperSource, v)); + } + } + + [Test] + public void AddAndVerifySinkConnected(IMutableVertexAndEdgeListGraph> g) + { + SetUp(g); + this.augmentor.Compute(); + foreach (string v in g.Vertices) + { + if (v == this.augmentor.SuperSink) + continue; + if (v == this.augmentor.SuperSink) + continue; + Assert.IsTrue(g.ContainsEdge(v, this.augmentor.SuperSink)); + } + } + + private sealed class StringVertexFactory : IVertexFactory + { + private int id = 0; + + public string CreateVertex() + { + return "Super"+(++id).ToString(); + } + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/MaximumFlow/AllVerticesGraphAugmentorAlgorithmTest.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/MaximumFlow/AllVerticesGraphAugmentorAlgorithmTest.cs.meta new file mode 100644 index 0000000..4437a05 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/MaximumFlow/AllVerticesGraphAugmentorAlgorithmTest.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 5167ef1785bdc456f8476fa8211c4f3e +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/MinimumSpanningTree.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/MinimumSpanningTree.meta new file mode 100644 index 0000000..b39ac2a --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/MinimumSpanningTree.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: 9c59136148ee84faeb7a5dd5da2af775 +folderAsset: yes +DefaultImporter: + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/MinimumSpanningTree/PrimMinimumSpanningTreeAlgorithmTest.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/MinimumSpanningTree/PrimMinimumSpanningTreeAlgorithmTest.cs new file mode 100755 index 0000000..6b892e5 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/MinimumSpanningTree/PrimMinimumSpanningTreeAlgorithmTest.cs @@ -0,0 +1,34 @@ +using System; +using System.Collections.Generic; +using QuickGraph.Unit; +using QuickGraph.Algorithms.Observers; + +namespace QuickGraph.Algorithms.MinimumSpanningTree +{ + [TypeFixture(typeof(IUndirectedGraph>))] + [TypeFactory(typeof(UndirectedGraphFactory))] + public class PrimMinimumSpanningTreeAlgorithmTest + { + [Test] + public void Compute(IUndirectedGraph> g) + { + Dictionary, double> distances = new Dictionary,double>(); + foreach(Edge edge in g.Edges) + distances.Add(edge, 1); + PrimMinimumSpanningTreeAlgorithm> prim = new PrimMinimumSpanningTreeAlgorithm>(g, distances); + + VertexPredecessorRecorderObserver> predecessors = new VertexPredecessorRecorderObserver>(); + predecessors.Attach(prim); + prim.Compute(); + + foreach (string v in g.Vertices) + { + Edge edge; + if (predecessors.VertexPredecessors.TryGetValue(v, out edge)) + Console.WriteLine("{0}: {1}", v, edge); + else + Console.WriteLine("{0}", v); + } + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/MinimumSpanningTree/PrimMinimumSpanningTreeAlgorithmTest.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/MinimumSpanningTree/PrimMinimumSpanningTreeAlgorithmTest.cs.meta new file mode 100644 index 0000000..dcd19eb --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/MinimumSpanningTree/PrimMinimumSpanningTreeAlgorithmTest.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e5d26f29409174e25a7e6663bab5253c +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/RandomWalks.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/RandomWalks.meta new file mode 100644 index 0000000..93d8e38 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/RandomWalks.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: eeca027c2f6a642c4a01dca6e21a9854 +folderAsset: yes +DefaultImporter: + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/RandomWalks/CyclePoppingRandomTreeAlgorithmTest.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/RandomWalks/CyclePoppingRandomTreeAlgorithmTest.cs new file mode 100755 index 0000000..22a3953 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/RandomWalks/CyclePoppingRandomTreeAlgorithmTest.cs @@ -0,0 +1,42 @@ +using System; +using QuickGraph.Unit; +using QuickGraph.Algorithms.RandomWalks; + +namespace QuickGraph.Algorithms.RandomWalks +{ + [TestFixture] + public class CyclePoppingRandomTreeAlgorithmTest + { + private CyclePoppingRandomTreeAlgorithm> target = null; + + [Test] + public void IsolatedVertex() + { + AdjacencyGraph> g = new AdjacencyGraph>(true); + g.AddVertex(0); + + target = new CyclePoppingRandomTreeAlgorithm>(g); + target.RandomTree(); + } + + [Test] + public void RootIsNotAccessible() + { + AdjacencyGraph> g = new AdjacencyGraph>(true); + g.AddVertex(0); + g.AddVertex(1); + g.AddEdge(new Edge(0, 1)); + + target = new CyclePoppingRandomTreeAlgorithm>(g); + target.RandomTreeWithRoot(0); + } + + [Test] + public void Loop() + { + CyclePoppingRandomTreeAlgorithm> target = new CyclePoppingRandomTreeAlgorithm>(new AdjacencyGraphFactory().Loop()); + target.RandomTree(); + } + + } +} \ No newline at end of file diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/RandomWalks/CyclePoppingRandomTreeAlgorithmTest.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/RandomWalks/CyclePoppingRandomTreeAlgorithmTest.cs.meta new file mode 100644 index 0000000..b3d5389 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/RandomWalks/CyclePoppingRandomTreeAlgorithmTest.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 693e216c502d94e38984b5fda768e296 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/RandomWalks/EdgeChainFactory.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/RandomWalks/EdgeChainFactory.cs new file mode 100755 index 0000000..d3f8d39 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/RandomWalks/EdgeChainFactory.cs @@ -0,0 +1,67 @@ +using System; +using System.Collections.Generic; +using QuickGraph.Unit; + +namespace QuickGraph.Algorithms.RandomWalks +{ + public class EdgeChainFactory + { + private IVertexAndEdgeListGraph> g = new BidirectionalGraphFactory().RegularLattice10x10(); + + [Factory] + public KeyValuePair< + IVertexAndEdgeListGraph>, + IEdgeChain>> + RoundRobin() + { + return new KeyValuePair>,IEdgeChain>>( + this.g, + new RoundRobinEdgeChain>() + ); + } + + [Factory] + public KeyValuePair< + IVertexAndEdgeListGraph>, + IEdgeChain>> + NormalizedMarkov() + { + return new KeyValuePair>,IEdgeChain>>( + this.g, + new NormalizedMarkovEdgeChain>() + ); + } + + [Factory] + public KeyValuePair< + IVertexAndEdgeListGraph>, + IEdgeChain>> + WeightedMarkov() + { + Dictionary, double> weights = new Dictionary, double>(); + int i=1; + foreach (Edge e in g.Edges) + weights.Add(e,1 + i / g.EdgeCount * 3.0); + return new KeyValuePair>,IEdgeChain>>( + this.g, + new WeightedMarkovEdgeChain>(weights) + ); + } + + [Factory] + public KeyValuePair< + IVertexAndEdgeListGraph>, + IEdgeChain>> + VanishingWeightedMarkov() + { + Dictionary, double> weights = new Dictionary, double>(); + int i = 1; + foreach (Edge e in g.Edges) + weights.Add(e, 1 + i / g.EdgeCount * 3.0); + return new KeyValuePair>,IEdgeChain>>( + this.g, + new VanishingWeightedMarkovEdgeChain>(weights) + ); + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/RandomWalks/EdgeChainFactory.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/RandomWalks/EdgeChainFactory.cs.meta new file mode 100644 index 0000000..0661348 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/RandomWalks/EdgeChainFactory.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 5179fe5ede845421aa6a4f1f3f6d7980 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/RandomWalks/EdgeChainTest.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/RandomWalks/EdgeChainTest.cs new file mode 100755 index 0000000..4174741 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/RandomWalks/EdgeChainTest.cs @@ -0,0 +1,39 @@ +using System; +using System.Collections.Generic; +using QuickGraph.Unit; +using QuickGraph.Algorithms.Observers; + +namespace QuickGraph.Algorithms.RandomWalks +{ + [TestFixture] + public class EdgeChainTest + { + [CombinatorialTest] + public void Generate( + [UsingFactories(typeof(EdgeChainFactory))] + KeyValuePair>,IEdgeChain>> eg + ) + { + RandomWalkAlgorithm> walker = + new RandomWalkAlgorithm>(eg.Key, eg.Value); + + walker.Generate(TraversalHelper.GetFirstVertex(eg.Key)); + } + + [CombinatorialTest] + public void GenerateWithVisitor( + [UsingFactories(typeof(EdgeChainFactory))] + KeyValuePair>,IEdgeChain>> eg + ) + { + RandomWalkAlgorithm> walker = + new RandomWalkAlgorithm>(eg.Key, eg.Value); + + EdgeRecorderObserver> vis = new EdgeRecorderObserver>(); + vis.Attach(walker); + walker.Generate(TraversalHelper.GetFirstVertex(eg.Key)); + vis.Detach(walker); + } + + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/RandomWalks/EdgeChainTest.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/RandomWalks/EdgeChainTest.cs.meta new file mode 100644 index 0000000..7706fdc --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/RandomWalks/EdgeChainTest.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ad18bad2cd126490a98f8b43383257ac +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/RandomWalks/RandomWalkAlgorithmTest.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/RandomWalks/RandomWalkAlgorithmTest.cs new file mode 100755 index 0000000..c75d6dc --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/RandomWalks/RandomWalkAlgorithmTest.cs @@ -0,0 +1,46 @@ +using System; +using QuickGraph.Unit; + +using QuickGraph.Algorithms.Observers; + +namespace QuickGraph.Algorithms.RandomWalks +{ + [TypeFixture(typeof(IVertexListGraph>))] + [TypeFactory(typeof(AdjacencyGraphFactory))] + [TypeFactory(typeof(BidirectionalGraphFactory))] + public class RandomWalkAlgorithmTest + { + [Test] + public void RoundRobinTest(IVertexListGraph> g) + { + if (g.VertexCount == 0) + return; + + RandomWalkAlgorithm> walker = + new RandomWalkAlgorithm>(g); + walker.EdgeChain = new NormalizedMarkovEdgeChain>(); + + string root = TraversalHelper.GetFirstVertex(g); + walker.Generate(root); + } + + [Test] + public void RoundRobinTestWithVisitor(IVertexListGraph> g) + { + if (g.VertexCount == 0) + return; + + RandomWalkAlgorithm> walker = + new RandomWalkAlgorithm>(g); + walker.EdgeChain = new NormalizedMarkovEdgeChain>(); + + string root = TraversalHelper.GetFirstVertex(g); + + EdgeRecorderObserver> vis = new EdgeRecorderObserver>(); + vis.Attach(walker); + walker.Generate(root); + vis.Detach(walker); + } + + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/RandomWalks/RandomWalkAlgorithmTest.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/RandomWalks/RandomWalkAlgorithmTest.cs.meta new file mode 100644 index 0000000..69dc64d --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/RandomWalks/RandomWalkAlgorithmTest.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 5d7ef2580616d4125b50701207439894 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/Search.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/Search.meta new file mode 100644 index 0000000..41e24de --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/Search.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: ebc1b21e2b2f44d05963ad0139efeb5c +folderAsset: yes +DefaultImporter: + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/Search/BidirectionalDepthFirstSearchAlgorithmTest.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/Search/BidirectionalDepthFirstSearchAlgorithmTest.cs new file mode 100755 index 0000000..9002479 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/Search/BidirectionalDepthFirstSearchAlgorithmTest.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; +using QuickGraph.Unit; + +namespace QuickGraph.Algorithms.Search +{ + [TypeFixture(typeof(IBidirectionalGraph>))] + [TypeFactory(typeof(BidirectionalGraphFactory))] + public class BidirectionalDepthFirstSearchAlgorithmTest + { + private BidirectionalDepthFirstSearchAlgorithm> dfs; + + [Test] + public void EmptyGraph(IBidirectionalGraph> g) + { + this.dfs = new BidirectionalDepthFirstSearchAlgorithm>(g); + this.dfs.Compute(); + + VerifyDfs(); + } + + private void VerifyDfs() + { + // let's make sure + foreach (string v in dfs.VisitedGraph.Vertices) + { + Assert.IsTrue(dfs.VertexColors.ContainsKey(v)); + Assert.AreEqual(dfs.VertexColors[v], GraphColor.Black); + } + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/Search/BidirectionalDepthFirstSearchAlgorithmTest.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/Search/BidirectionalDepthFirstSearchAlgorithmTest.cs.meta new file mode 100644 index 0000000..913d3b5 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/Search/BidirectionalDepthFirstSearchAlgorithmTest.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 9bff12e78551f43e68f827a6fc670672 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/Search/BreadthFirstSearchAlgirthmTest.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/Search/BreadthFirstSearchAlgirthmTest.cs new file mode 100755 index 0000000..734ccaf --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/Search/BreadthFirstSearchAlgirthmTest.cs @@ -0,0 +1,208 @@ +using System; +using System.Collections.Generic; +using QuickGraph.Unit; + +namespace QuickGraph.Algorithms.Search +{ + [TestFixture] + public class BreadthFirstAlgorithmSearchTest + { + private IDictionary parents; + private IDictionary distances; + private int currentVertex; + private int sourceVertex; + private int currentDistance; + private BreadthFirstSearchAlgorithm> algo; + private AdjacencyGraph> g; + + private void InitializeVertex(Object sender, VertexEventArgs args) + { + Assert.AreEqual(algo.VertexColors[args.Vertex], GraphColor.White); + } + + private void ExamineVertex(Object sender, VertexEventArgs args) + { + int u = args.Vertex; + currentVertex = u; + // Ensure that the distances monotonically increase. + Assert.IsTrue( + distances[u] == currentDistance + || distances[u] == currentDistance + 1 + ); + + if (distances[u] == currentDistance + 1) // new level + ++currentDistance; + } + + private void DiscoverVertex(Object sender, VertexEventArgs args) + { + int u = args.Vertex; + + Assert.AreEqual(algo.VertexColors[u], GraphColor.Gray); + if (u == sourceVertex) + currentVertex = sourceVertex; + else + { + Assert.AreEqual(parents[u], currentVertex); + Assert.AreEqual(distances[u], currentDistance + 1); + Assert.AreEqual(distances[u], distances[parents[u]] + 1); + } + } + + private void ExamineEdge(Object sender, EdgeEventArgs> args) + { + Assert.AreEqual(args.Edge.Source, currentVertex); + } + + private void TreeEdge(Object sender, EdgeEventArgs> args) + { + int u = args.Edge.Source; + int v = args.Edge.Target; + + Assert.AreEqual(algo.VertexColors[v], GraphColor.White); + Assert.AreEqual(distances[u], currentDistance); + parents[v] = u; + distances[v] = distances[u] + 1; + } + + private void NonTreeEdge(Object sender, EdgeEventArgs> args) + { + int u = args.Edge.Source; + int v = args.Edge.Target; + + Assert.IsFalse(algo.VertexColors[v] == GraphColor.White); + + if (algo.VisitedGraph.IsDirected) + { + // cross or back edge + Assert.IsTrue(distances[v] <= distances[u] + 1); + } + else + { + // cross edge (or going backwards on a tree edge) + Assert.IsTrue( + distances[v] == distances[u] + || distances[v] == distances[u] + 1 + || distances[v] == distances[u] - 1 + ); + } + } + + private void GrayTarget(Object sender, EdgeEventArgs> args) + { + Assert.AreEqual(algo.VertexColors[args.Edge.Target], GraphColor.Gray); + } + + private void BlackTarget(Object sender, EdgeEventArgs> args) + { + Assert.AreEqual(algo.VertexColors[args.Edge.Target], GraphColor.Black); + + foreach (Edge e in algo.VisitedGraph.OutEdges(args.Edge.Target)) + Assert.IsFalse(algo.VertexColors[e.Target] == GraphColor.White); + } + + private void FinishVertex(Object sender, VertexEventArgs args) + { + Assert.AreEqual(algo.VertexColors[args.Vertex], GraphColor.Black); + } + + [SetUp] + public void Init() + { + this.parents = new Dictionary(); + this.distances = new Dictionary(); + this.currentDistance = 0; + this.currentVertex = 0; + this.algo = null; + this.g = null; + } + + private class IntVertexFactory : IVertexFactory + { + private int id = 0; + public int CreateVertex() + { + return id++; + } + } + + [CombinatorialTest] + public void GraphWithSelfEdges( + [UsingLinear(2, 9)] int i, + [UsingLinear(0, 10)] int j + ) + { + if (i == 0 && j == 0) + return; + + Random rnd = new Random(); + + g = new AdjacencyGraph>(true); + RandomGraphFactory.Create>(g, + new IntVertexFactory(), + FactoryCompiler.GetEdgeFactory>(), + rnd, i, j, true); + + algo = new BreadthFirstSearchAlgorithm>(g); + try + { + algo.InitializeVertex += new VertexEventHandler(this.InitializeVertex); + algo.DiscoverVertex += new VertexEventHandler(this.DiscoverVertex); + algo.ExamineEdge += new EdgeEventHandler>(this.ExamineEdge); + algo.ExamineVertex += new VertexEventHandler(this.ExamineVertex); + algo.TreeEdge += new EdgeEventHandler>(this.TreeEdge); + algo.NonTreeEdge += new EdgeEventHandler>(this.NonTreeEdge); + algo.GrayTarget += new EdgeEventHandler>(this.GrayTarget); + algo.BlackTarget += new EdgeEventHandler>(this.BlackTarget); + algo.FinishVertex += new VertexEventHandler(this.FinishVertex); + + parents.Clear(); + distances.Clear(); + currentDistance = 0; + sourceVertex = RandomGraphFactory.GetVertex(g, rnd); + + foreach (int v in g.Vertices) + { + distances[v] = int.MaxValue; + parents[v] = v; + } + distances[sourceVertex] = 0; + algo.Compute(sourceVertex); + + CheckBfs(); + } + finally + { + algo.InitializeVertex -= new VertexEventHandler(this.InitializeVertex); + algo.DiscoverVertex -= new VertexEventHandler(this.DiscoverVertex); + algo.ExamineEdge -= new EdgeEventHandler>(this.ExamineEdge); + algo.ExamineVertex -= new VertexEventHandler(this.ExamineVertex); + algo.TreeEdge -= new EdgeEventHandler>(this.TreeEdge); + algo.NonTreeEdge -= new EdgeEventHandler>(this.NonTreeEdge); + algo.GrayTarget -= new EdgeEventHandler>(this.GrayTarget); + algo.BlackTarget -= new EdgeEventHandler>(this.BlackTarget); + algo.FinishVertex -= new VertexEventHandler(this.FinishVertex); + } + } + + protected void CheckBfs() + { + // All white vertices should be unreachable from the source. + foreach (int v in g.Vertices) + { + if (algo.VertexColors[v] == GraphColor.White) + { + //!IsReachable(start,u,g); + } + } + + // The shortest path to a child should be one longer than + // shortest path to the parent. + foreach (int v in g.Vertices) + { + if (parents[v] != v) // *ui not the root of the bfs tree + Assert.AreEqual(distances[v], distances[parents[v]] + 1); + } + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/Search/BreadthFirstSearchAlgirthmTest.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/Search/BreadthFirstSearchAlgirthmTest.cs.meta new file mode 100644 index 0000000..432f2b4 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/Search/BreadthFirstSearchAlgirthmTest.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 3faabe673f67540c0889d1037a30120f +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/Search/DepthFirstSearchAlgorithmTest.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/Search/DepthFirstSearchAlgorithmTest.cs new file mode 100755 index 0000000..18ee036 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/Search/DepthFirstSearchAlgorithmTest.cs @@ -0,0 +1,169 @@ +using System; +using System.Collections.Generic; +using QuickGraph.Unit; + +namespace QuickGraph.Algorithms.Search +{ + [TestFixture] + public class DepthFirstAlgorithmSearchTest + { + private Dictionary parents; + private Dictionary discoverTimes; + private Dictionary finishTimes; + private int time; + private AdjacencyGraph> g; + private DepthFirstSearchAlgorithm> dfs; + + private void StartVertex(Object sender, VertexEventArgs args) + { + Assert.AreEqual(dfs.VertexColors[args.Vertex], GraphColor.White); + } + + private void DiscoverVertex(Object sender, VertexEventArgs args) + { + Assert.AreEqual(dfs.VertexColors[args.Vertex], GraphColor.Gray); + Assert.AreEqual(dfs.VertexColors[parents[args.Vertex]], GraphColor.Gray); + + discoverTimes[args.Vertex] = time++; + } + + private void ExamineEdge(Object sender, EdgeEventArgs> args) + { + Assert.AreEqual(dfs.VertexColors[args.Edge.Source], GraphColor.Gray); + } + + private void TreeEdge(Object sender, EdgeEventArgs> args) + { + Assert.AreEqual(dfs.VertexColors[args.Edge.Target], GraphColor.White); + parents[args.Edge.Target] = args.Edge.Source; + } + + private void BackEdge(Object sender, EdgeEventArgs> args) + { + Assert.AreEqual(dfs.VertexColors[args.Edge.Target], GraphColor.Gray); + } + + private void FowardOrCrossEdge(Object sender, EdgeEventArgs> args) + { + Assert.AreEqual(dfs.VertexColors[args.Edge.Target], GraphColor.Black); + } + + private void FinishVertex(Object sender, VertexEventArgs args) + { + Assert.AreEqual(dfs.VertexColors[args.Vertex], GraphColor.Black); + finishTimes[args.Vertex] = time++; + } + + public bool IsDescendant(string u, string v) + { + string t = null; + string p = u; + do + { + t = p; + p = parents[t]; + if (p == v) + return true; + } + while (t != p); + + return false; + } + + [SetUp] + public void Init() + { + + parents = new Dictionary(); + discoverTimes = new Dictionary(); + finishTimes = new Dictionary(); + time = 0; + g = new AdjacencyGraph>(true); + dfs = new DepthFirstSearchAlgorithm>(g); + + dfs.StartVertex += new VertexEventHandler(this.StartVertex); + dfs.DiscoverVertex += new VertexEventHandler(this.DiscoverVertex); + dfs.ExamineEdge += new EdgeEventHandler>(this.ExamineEdge); + dfs.TreeEdge += new EdgeEventHandler>(this.TreeEdge); + dfs.BackEdge += new EdgeEventHandler>(this.BackEdge); + dfs.ForwardOrCrossEdge += new EdgeEventHandler>(this.FowardOrCrossEdge); + dfs.FinishVertex += new VertexEventHandler(this.FinishVertex); + } + + [TearDown] + public void TearDown() + { + dfs.StartVertex -= new VertexEventHandler(this.StartVertex); + dfs.DiscoverVertex -= new VertexEventHandler(this.DiscoverVertex); + dfs.ExamineEdge -= new EdgeEventHandler>(this.ExamineEdge); + dfs.TreeEdge -= new EdgeEventHandler>(this.TreeEdge); + dfs.BackEdge -= new EdgeEventHandler>(this.BackEdge); + dfs.ForwardOrCrossEdge -= new EdgeEventHandler>(this.FowardOrCrossEdge); + dfs.FinishVertex -= new VertexEventHandler(this.FinishVertex); + } + + [Test] + public void GraphWithSelfEdges() + { + AdjacencyGraph> g = new AdjacencyGraph>(false); + g.AddVertex("v1"); + g.AddEdge(new Edge("v1","v1")); + + foreach (string v in g.Vertices) + parents[v] = v; + + // compute + dfs.Compute(); + + CheckDfs(); + } + + [Test] + public void GraphWithoutSelfEdges() + { + AdjacencyGraph> g = new AdjacencyGraphFactory().FileDependency(); + + foreach (string v in g.Vertices) + parents[v] = v; + + // compute + dfs.Compute(); + CheckDfs(); + } + + protected void CheckDfs() + { + // check + // all vertices should be black + foreach (string v in g.Vertices) + { + Assert.IsTrue(dfs.VertexColors.ContainsKey(v)); + Assert.AreEqual(dfs.VertexColors[v], GraphColor.Black); + } + + foreach (string u in g.Vertices) + { + foreach (string v in g.Vertices) + { + if (u != v) + { + Assert.IsTrue( + finishTimes[u] < discoverTimes[v] + || finishTimes[v] < discoverTimes[u] + || ( + discoverTimes[v] < discoverTimes[u] + && finishTimes[u] < finishTimes[v] + && IsDescendant(u, v) + ) + || ( + discoverTimes[u] < discoverTimes[v] + && finishTimes[v] < finishTimes[u] + && IsDescendant(v, u) + ) + ); + } + } + } + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/Search/DepthFirstSearchAlgorithmTest.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/Search/DepthFirstSearchAlgorithmTest.cs.meta new file mode 100644 index 0000000..9273efd --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/Search/DepthFirstSearchAlgorithmTest.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 9866cf69251484682826f204b86737d9 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/Search/SearchingExamplesTest.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/Search/SearchingExamplesTest.cs new file mode 100755 index 0000000..4c9339e --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/Search/SearchingExamplesTest.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Text; +using QuickGraph.Unit; +using QuickGraph.Algorithms.Search; + +namespace QuickGraph.Tests.Algorithms.Search +{ + [TypeFixture(typeof(IVertexAndEdgeListGraph>))] + [TypeFactory(typeof(AdjacencyGraphFactory))] + public class SearchingExamplesTest + { + [Test] + public void BreadthFirstSearch(IVertexAndEdgeListGraph> g) + { + var bfs = new BreadthFirstSearchAlgorithm>(g); + bfs.Compute(); + } + + [Test] + public void DepthFirstSearch(IVertexAndEdgeListGraph> g) + { + var bfs = new DepthFirstSearchAlgorithm>(g); + bfs.Compute(); + } + } + +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/Search/SearchingExamplesTest.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/Search/SearchingExamplesTest.cs.meta new file mode 100644 index 0000000..6a00b8c --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/Search/SearchingExamplesTest.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 6b1fa8c1b1de74702834883a6cb3012d +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/Search/UndirectedBreathFirstSearchAlgorithmTest.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/Search/UndirectedBreathFirstSearchAlgorithmTest.cs new file mode 100755 index 0000000..54505b3 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/Search/UndirectedBreathFirstSearchAlgorithmTest.cs @@ -0,0 +1,229 @@ +using System; +using System.Collections.Generic; +using QuickGraph.Unit; + +namespace QuickGraph.Algorithms.Search +{ + [TypeFixture(typeof(IUndirectedGraph>))] + [TypeFactory(typeof(UndirectedGraphFactory))] + public class UndirectedBreadthFirstAlgorithmSearchTest + { + private IDictionary parents; + private IDictionary distances; + private string currentVertex; + private string sourceVertex; + private int currentDistance; + private UndirectedBreadthFirstSearchAlgorithm> algo; + + private void InitializeVertex(Object sender, VertexEventArgs args) + { + Assert.AreEqual(algo.VertexColors[args.Vertex], GraphColor.White); + } + + private void ExamineVertex(Object sender, VertexEventArgs args) + { + string u = args.Vertex; + currentVertex = u; + // Ensure that the distances monotonically increase. + Assert.IsTrue( + distances[u] == currentDistance + || distances[u] == currentDistance + 1 + ); + + if (distances[u] == currentDistance + 1) // new level + ++currentDistance; + } + + private void DiscoverVertex(Object sender, VertexEventArgs args) + { + string u = args.Vertex; + + Assert.AreEqual(algo.VertexColors[u], GraphColor.Gray); + if (u == sourceVertex) + currentVertex = sourceVertex; + else + { + Assert.AreEqual(parents[u], currentVertex); + Assert.AreEqual(distances[u], currentDistance + 1); + Assert.AreEqual(distances[u], distances[parents[u]] + 1); + } + } + + private void TreeEdge(Object sender, EdgeEventArgs> args) + { + string u, v; + if (args.Edge.Source == currentVertex) + { + u = args.Edge.Source; + v = args.Edge.Target; + } + else + { + v = args.Edge.Source; + u = args.Edge.Target; + } + + Assert.AreEqual(algo.VertexColors[v], GraphColor.White); + Assert.AreEqual(distances[u], currentDistance); + parents[v] = u; + distances[v] = distances[u] + 1; + } + + private void NonTreeEdge(Object sender, EdgeEventArgs> args) + { + string u, v; + if (args.Edge.Source == currentVertex) + { + u = args.Edge.Source; + v = args.Edge.Target; + } + else + { + v = args.Edge.Source; + u = args.Edge.Target; + } + + Assert.IsFalse(algo.VertexColors[v] == GraphColor.White); + + if (algo.VisitedGraph.IsDirected) + { + // cross or back edge + Assert.IsTrue(distances[v] <= distances[u] + 1); + } + else + { + // cross edge (or going backwards on a tree edge) + Assert.IsTrue( + distances[v] == distances[u] + || distances[v] == distances[u] + 1 + || distances[v] == distances[u] - 1 + ); + } + } + + private void GrayTarget(Object sender, EdgeEventArgs> args) + { + string v; + if (args.Edge.Source == currentVertex) + { + v = args.Edge.Target; + } + else + { + v = args.Edge.Source; + } + Assert.AreEqual(algo.VertexColors[v], GraphColor.Gray); + } + + private void BlackTarget(Object sender, EdgeEventArgs> args) + { + string u, v; + if (args.Edge.Source == currentVertex) + { + u = args.Edge.Source; + v = args.Edge.Target; + } + else + { + v = args.Edge.Source; + u = args.Edge.Target; + } + + Assert.AreEqual(algo.VertexColors[v], GraphColor.Black); + + foreach (Edge e in algo.VisitedGraph.AdjacentEdges(v)) + { + Assert.IsFalse(algo.VertexColors[ + (e.Source==v) ? e.Target : e.Source + ] == GraphColor.White); + } + } + + private void FinishVertex(Object sender, VertexEventArgs args) + { + Assert.AreEqual(algo.VertexColors[args.Vertex], GraphColor.Black); + } + + [SetUp] + public void Init() + { + this.parents = new Dictionary(); + this.distances = new Dictionary(); + this.currentDistance = 0; + this.currentVertex = null; + this.algo = null; + } + + [Test] + public void GraphWithSelfEdges(IUndirectedGraph> graph) + { + List vertices = new List(graph.Vertices); + + foreach (string v in vertices) + Search(graph, v); + } + + private void Search(IUndirectedGraph> graph, string rootVertex) + { + Console.WriteLine(rootVertex); + algo = new UndirectedBreadthFirstSearchAlgorithm>(graph); + try + { + algo.InitializeVertex += new VertexEventHandler(this.InitializeVertex); + algo.DiscoverVertex += new VertexEventHandler(this.DiscoverVertex); + algo.ExamineVertex += new VertexEventHandler(this.ExamineVertex); + algo.TreeEdge += new EdgeEventHandler>(this.TreeEdge); + algo.NonTreeEdge += new EdgeEventHandler>(this.NonTreeEdge); + algo.GrayTarget += new EdgeEventHandler>(this.GrayTarget); + algo.BlackTarget += new EdgeEventHandler>(this.BlackTarget); + algo.FinishVertex += new VertexEventHandler(this.FinishVertex); + + parents.Clear(); + distances.Clear(); + currentDistance = 0; + sourceVertex = rootVertex; + + foreach (string v in this.algo.VisitedGraph.Vertices) + { + distances[v] = int.MaxValue; + parents[v] = v; + } + distances[sourceVertex] = 0; + algo.Compute(sourceVertex); + + CheckBfs(); + } + finally + { + algo.InitializeVertex -= new VertexEventHandler(this.InitializeVertex); + algo.DiscoverVertex -= new VertexEventHandler(this.DiscoverVertex); + algo.ExamineVertex -= new VertexEventHandler(this.ExamineVertex); + algo.TreeEdge -= new EdgeEventHandler>(this.TreeEdge); + algo.NonTreeEdge -= new EdgeEventHandler>(this.NonTreeEdge); + algo.GrayTarget -= new EdgeEventHandler>(this.GrayTarget); + algo.BlackTarget -= new EdgeEventHandler>(this.BlackTarget); + algo.FinishVertex -= new VertexEventHandler(this.FinishVertex); + } + } + + protected void CheckBfs() + { + // All white vertices should be unreachable from the source. + foreach (string v in this.algo.VisitedGraph.Vertices) + { + if (algo.VertexColors[v] == GraphColor.White) + { + //!IsReachable(start,u,g); + } + } + + // The shortest path to a child should be one longer than + // shortest path to the parent. + foreach (string v in this.algo.VisitedGraph.Vertices) + { + if (parents[v] != v) // *ui not the root of the bfs tree + Assert.AreEqual(distances[v], distances[parents[v]] + 1); + } + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/Search/UndirectedBreathFirstSearchAlgorithmTest.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/Search/UndirectedBreathFirstSearchAlgorithmTest.cs.meta new file mode 100644 index 0000000..2968afc --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/Search/UndirectedBreathFirstSearchAlgorithmTest.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: f1de1ba3badfd4441bea393c5e6fb8f4 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/ShortestPath.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/ShortestPath.meta new file mode 100644 index 0000000..0430390 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/ShortestPath.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: ac185b66c24114eb5854af5dc42b903f +folderAsset: yes +DefaultImporter: + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/ShortestPath/DagShortestPathAlgorithmTest.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/ShortestPath/DagShortestPathAlgorithmTest.cs new file mode 100755 index 0000000..2629caa --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/ShortestPath/DagShortestPathAlgorithmTest.cs @@ -0,0 +1,116 @@ +using System; +using System.Collections.Generic; +using QuickGraph.Unit; +using QuickGraph.Algorithms.Observers; +using Microsoft.Pex.Framework; + +namespace QuickGraph.Algorithms.ShortestPath +{ + [TestFixture, PexClass] + public partial class DagShortestPathAlgorithmTest + { + [PexMethod] + public void Compute(IVertexListGraph> g) + { + // is this a dag ? + bool isDag = AlgoUtility.IsDirectedAcyclicGraph(g); + + IDistanceRelaxer relaxer = new ShortestDistanceRelaxer(); + List vertices = new List(g.Vertices); + foreach (string root in vertices) + { + if (isDag) + Search(g, root, relaxer); + else + { + try + { + Search(g, root, relaxer); + } + catch (NonAcyclicGraphException) + { + Console.WriteLine("NonAcyclicGraphException caught (as expected)"); + } + } + } + } + + [Test] + public void Simple() + { + AdjacencyGraph> g = new AdjacencyGraph>(); + GraphFactory.Simple(g); + this.Compute(g); + this.ComputeCriticalPath(g); + } + + [Test] + public void FileDependency() + { + AdjacencyGraph> g = new AdjacencyGraph>(); + GraphFactory.FileDependency(g); + this.Compute(g); + this.ComputeCriticalPath(g); + } + + [PexMethod] + public void ComputeCriticalPath(IVertexListGraph> g) + { + // is this a dag ? + bool isDag = AlgoUtility.IsDirectedAcyclicGraph(g); + + var relaxer = new CriticalDistanceRelaxer(); + var vertices = new List(g.Vertices); + foreach (string root in vertices) + { + if (isDag) + Search(g, root, relaxer); + else + { + try + { + Search(g, root, relaxer); + Assert.Fail("should have found the acyclic graph"); + } + catch (NonAcyclicGraphException) + { + Console.WriteLine("NonAcyclicGraphException caught (as expected)"); + } + } + } + } + + private void Search( + IVertexListGraph> g, + string root, IDistanceRelaxer relaxer) + { + DagShortestPathAlgorithm> algo = + new DagShortestPathAlgorithm>( + g, + DagShortestPathAlgorithm>.UnaryWeightsFromVertexList(g), + relaxer + ); + VertexPredecessorRecorderObserver> predecessors = new VertexPredecessorRecorderObserver>(); + predecessors.Attach(algo); + algo.Compute(root); + + Verify(algo, predecessors); + } + + private static void Verify(DagShortestPathAlgorithm> algo, VertexPredecessorRecorderObserver> predecessors) + { + // let's verify the result + foreach (string v in algo.VisitedGraph.Vertices) + { + Edge predecessor; + if (!predecessors.VertexPredecessors.TryGetValue(v, out predecessor)) + continue; + if (predecessor.Source == v) + continue; + Assert.AreEqual( + algo.Distances[v], algo.Distances[predecessor.Source] + 1 + ); + } + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/ShortestPath/DagShortestPathAlgorithmTest.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/ShortestPath/DagShortestPathAlgorithmTest.cs.meta new file mode 100644 index 0000000..7985395 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/ShortestPath/DagShortestPathAlgorithmTest.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 1596ccde901264e58ab798528f6cec5d +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/ShortestPath/DijkstraShortestPathAlgorithmTest.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/ShortestPath/DijkstraShortestPathAlgorithmTest.cs new file mode 100755 index 0000000..1cae9ae --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/ShortestPath/DijkstraShortestPathAlgorithmTest.cs @@ -0,0 +1,271 @@ +using System; +using System.Collections.Generic; + +using QuickGraph.Unit; + +using QuickGraph.Collections; +using QuickGraph.Predicates; +using QuickGraph.Algorithms.Observers; + +namespace QuickGraph.Algorithms.ShortestPath +{ + [TypeFixture(typeof(IVertexAndEdgeListGraph>))] + [TypeFactory(typeof(AdjacencyGraphFactory))] + public class DijkstraShortestPathExamplesTest + { + [Test] + public void Compute(IVertexAndEdgeListGraph> g) + { + if (g.VertexCount == 0) return; + + var rnd = new Random(); + var distances = new Dictionary, double>(); + foreach(var edge in g.Edges) + distances.Add(edge, rnd.Next(100)); + var bfs = new DijkstraShortestPathAlgorithm>(g, distances); + + bfs.Compute(TraversalHelper.GetFirstVertex(g)); + } + } + + [TestFixture, CurrentFixture] + public class DijkstraShortestPathTest + { + [Test] + [ExpectedException(typeof(ArgumentNullException))] + public void CreateAlgorithmWithNullGraph() + { + DijkstraShortestPathAlgorithm> dij = new + DijkstraShortestPathAlgorithm>(null, null); + } + + [Test] + [ExpectedException(typeof(ArgumentNullException))] + public void CreateAlgorithmWithNullWeights() + { + AdjacencyGraph> g = new AdjacencyGraph>(true); + DijkstraShortestPathAlgorithm> dij = + new DijkstraShortestPathAlgorithm>(g, null); + } + + [Test] + public void UnaryWeights() + { + AdjacencyGraph> g = new AdjacencyGraph>(true); + Dictionary, double> weights = + DijkstraShortestPathAlgorithm>.UnaryWeightsFromEdgeList(g); + } + + [Test] + public void RunOnLineGraph() + { + AdjacencyGraph> g = new AdjacencyGraph>(true); + g.AddVertex(1); + g.AddVertex(2); + g.AddVertex(3); + + g.AddEdge(new Edge(1,2)); + g.AddEdge(new Edge(2,3)); + + Dictionary,double> weights = + DijkstraShortestPathAlgorithm>.UnaryWeightsFromEdgeList(g); + DijkstraShortestPathAlgorithm> dij = new DijkstraShortestPathAlgorithm>(g, weights); + dij.Compute(1); + + Assert.AreEqual(0, dij.Distances[1]); + Assert.AreEqual(1, dij.Distances[2]); + Assert.AreEqual(2, dij.Distances[3]); + } + + [Test] + public void CheckPredecessorLineGraph() + { + AdjacencyGraph> g = new AdjacencyGraph>(true); + g.AddVertex(1); + g.AddVertex(2); + g.AddVertex(3); + + Edge e12 = new Edge(1, 2); g.AddEdge(e12); + Edge e23 = new Edge(2, 3); g.AddEdge(e23); + + Dictionary, double> weights = + DijkstraShortestPathAlgorithm>.UnaryWeightsFromEdgeList(g); + DijkstraShortestPathAlgorithm> dij = new DijkstraShortestPathAlgorithm>(g, weights); + VertexPredecessorRecorderObserver> vis = new VertexPredecessorRecorderObserver>(); + vis.Attach(dij); + dij.Compute(1); + + IList> col = vis.Path(2); + Assert.AreEqual(1, col.Count); + Assert.AreEqual(e12, col[0]); + + col = vis.Path(3); + Assert.AreEqual(2, col.Count); + Assert.AreEqual(e12, col[0]); + Assert.AreEqual(e23, col[1]); + } + + + [Test] + public void RunOnDoubleLineGraph() + { + AdjacencyGraph> g = new AdjacencyGraph>(true); + g.AddVertex(1); + g.AddVertex(2); + g.AddVertex(3); + + Edge e12 = new Edge(1, 2); g.AddEdge(e12); + Edge e23 = new Edge(2, 3); g.AddEdge(e23); + Edge e13 = new Edge(1, 3); g.AddEdge(e13); + + Dictionary,double> weights = DijkstraShortestPathAlgorithm>.UnaryWeightsFromEdgeList(g); + DijkstraShortestPathAlgorithm> dij = new DijkstraShortestPathAlgorithm>(g, weights); + dij.Compute(1); + + Assert.AreEqual(0.0, dij.Distances[1]); + Assert.AreEqual(1.0, dij.Distances[2]); + Assert.AreEqual(1.0, dij.Distances[3]); + } + + [Test] + public void CheckPredecessorDoubleLineGraph() + { + AdjacencyGraph> g = new AdjacencyGraph>(true); + g.AddVertex(1); + g.AddVertex(2); + g.AddVertex(3); + + Edge e12 = new Edge(1, 2); g.AddEdge(e12); + Edge e23 = new Edge(2, 3); g.AddEdge(e23); + Edge e13 = new Edge(1, 3); g.AddEdge(e13); + + Dictionary, double> weights = DijkstraShortestPathAlgorithm>.UnaryWeightsFromEdgeList(g); + DijkstraShortestPathAlgorithm> dij = new DijkstraShortestPathAlgorithm>(g, weights); + VertexPredecessorRecorderObserver> vis = new VertexPredecessorRecorderObserver>(); + vis.Attach(dij); + dij.Compute(1); + + IList> col = vis.Path(2); + Assert.AreEqual(1, col.Count); + Assert.AreEqual(e12, col[0]); + + col = vis.Path(3); + Assert.AreEqual(1, col.Count); + Assert.AreEqual(e13, col[0]); + } + } + + [TestFixture, CurrentFixture] + public class DijkstraAlgoTest + { + AdjacencyGraph> graph; + DijkstraShortestPathAlgorithm> algo; + List path; + VertexPredecessorRecorderObserver> predecessorObserver; + + [Test] + public void CreateGraph() + { + graph = new AdjacencyGraph>(true); + + // Add some vertices to the graph + graph.AddVertex("A"); + graph.AddVertex("B"); + + graph.AddVertex("D"); + graph.AddVertex("C"); + graph.AddVertex("E"); + + // Create the edges + var a_b = new Edge("A", "B"); + var a_c = new Edge("A", "C"); + var b_e = new Edge("B", "E"); + var c_d = new Edge("C", "D"); + var d_e = new Edge("D", "E"); + + // Add edges to the graph + graph.AddEdge(a_b); + graph.AddEdge(a_c); + graph.AddEdge(c_d); + graph.AddEdge(d_e); + graph.AddEdge(b_e); + + // Define some weights to the edges + var weight = new Dictionary, double>(graph.EdgeCount); + weight.Add(a_b, 30); + weight.Add(a_c, 30); + weight.Add(b_e, 60); + weight.Add(c_d, 40); + weight.Add(d_e, 4); + + algo = new DijkstraShortestPathAlgorithm>(graph, weight); + + // Attach a Vertex Predecessor Recorder Observer to give us the paths + predecessorObserver = new VertexPredecessorRecorderObserver>(); + + using (ObserverScope.Create>>(algo, predecessorObserver)) + { + // Run the algorithm with A set to be the source + algo.Compute("A"); + } + + path = new List(); + PopulatePath("E"); + + Assert.IsTrue(algo.Distances["E"] == 74); + path.Reverse(); + + Console.WriteLine(String.Join(" -> ", path.ToArray())); + } + + void PopulatePath(string vertex) + { + path.Add(vertex); + if (vertex == "A") + return; + PopulatePath(predecessorObserver.VertexPredecessors[vertex].Source); + } + } + + [TestFixture, CurrentFixture] + public class BoostDijkstraTest + { + [Test] + public void Compute() + { + var g = new AdjacencyGraph>(); + var distances = new Dictionary, double>(); + + g.AddVertexRange("ABCDE"); + AddEdge(g, distances, 'A', 'C', 1); + AddEdge(g, distances, 'B', 'B', 2); + AddEdge(g, distances, 'B', 'D', 1); + AddEdge(g, distances, 'B', 'E', 2); + AddEdge(g, distances, 'C', 'B', 7); + AddEdge(g, distances, 'C', 'D', 3); + AddEdge(g, distances, 'D', 'E', 1); + AddEdge(g, distances, 'E', 'A', 1); + AddEdge(g, distances, 'E', 'B', 1); + + var dijkstra = new DijkstraShortestPathAlgorithm>(g, distances); + var predecessors = new VertexPredecessorRecorderObserver>(); + + predecessors.Attach(dijkstra); + dijkstra.Compute('A'); + + Assert.AreEqual(0, dijkstra.Distances['A']); + Assert.AreEqual(6, dijkstra.Distances['B']); + Assert.AreEqual(1, dijkstra.Distances['C']); + Assert.AreEqual(4, dijkstra.Distances['D']); + Assert.AreEqual(5, dijkstra.Distances['E']); + } + + private static void AddEdge( + AdjacencyGraph> g, + Dictionary, double> distances, + char source, char target, double weight) + { + var ac = new Edge(source, target); distances[ac] = weight; g.AddEdge(ac); + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/ShortestPath/DijkstraShortestPathAlgorithmTest.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/ShortestPath/DijkstraShortestPathAlgorithmTest.cs.meta new file mode 100644 index 0000000..7670e5e --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/ShortestPath/DijkstraShortestPathAlgorithmTest.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e00b92d6ecaac4f25b35036c8df8f5ef +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/ShortestPath/DijkstraShortestPathAlgorithmTest2.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/ShortestPath/DijkstraShortestPathAlgorithmTest2.cs new file mode 100755 index 0000000..85027a2 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/ShortestPath/DijkstraShortestPathAlgorithmTest2.cs @@ -0,0 +1,50 @@ +using System; +using System.Collections.Generic; +using QuickGraph.Unit; +using QuickGraph.Algorithms.Observers; +using Microsoft.Pex.Framework; + +namespace QuickGraph.Algorithms.ShortestPath +{ + [TestFixture, PexClass] + public partial class DijkstraShortestPathAlgorithmTest2 + { + [PexMethod] + public void Compute([PexAssumeNotNull]IVertexAndEdgeListGraph> g) + { + List vertices = new List(g.Vertices); + foreach (string root in vertices) + { + Search(g, root); + } + } + + private void Search(IVertexAndEdgeListGraph> g, string root) + { + DijkstraShortestPathAlgorithm> algo = new DijkstraShortestPathAlgorithm>(g, + DijkstraShortestPathAlgorithm>.UnaryWeightsFromEdgeList(g) + ); + VertexPredecessorRecorderObserver> predecessors = new VertexPredecessorRecorderObserver>(); + predecessors.Attach(algo); + algo.Compute(root); + + Verify(algo, predecessors); + } + + private static void Verify(DijkstraShortestPathAlgorithm> algo, VertexPredecessorRecorderObserver> predecessors) + { + // let's verify the result + foreach (string v in algo.VisitedGraph.Vertices) + { + Edge predecessor; + if (!predecessors.VertexPredecessors.TryGetValue(v, out predecessor)) + continue; + if (predecessor.Source == v) + continue; + Assert.AreEqual( + algo.Distances[v], algo.Distances[predecessor.Source] + 1 + ); + } + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/ShortestPath/DijkstraShortestPathAlgorithmTest2.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/ShortestPath/DijkstraShortestPathAlgorithmTest2.cs.meta new file mode 100644 index 0000000..9f6bf5e --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/ShortestPath/DijkstraShortestPathAlgorithmTest2.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 3b4977fb687ec413487232366774076d +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/SourceFirstTopologicalSortAlgorithmTest.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/SourceFirstTopologicalSortAlgorithmTest.cs new file mode 100755 index 0000000..28040ce --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/SourceFirstTopologicalSortAlgorithmTest.cs @@ -0,0 +1,25 @@ +using System; +using QuickGraph.Unit; +using Microsoft.Pex.Framework; + +namespace QuickGraph.Algorithms +{ + [TestFixture, PexClass] + public partial class SourceFirstTopologicalSortAlgorithmTest + { + [Test] + [ExpectedException(typeof(NonAcyclicGraphException))] + public void SortCyclic() + { + IVertexAndEdgeListGraph> g = new AdjacencyGraphFactory().Loop(); + this.Sort(g); + } + + [PexMethod] + public void Sort([PexAssumeNotNull]IVertexAndEdgeListGraph> g) + { + SourceFirstTopologicalSortAlgorithm> topo = new SourceFirstTopologicalSortAlgorithm>(g); + topo.Compute(); + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/SourceFirstTopologicalSortAlgorithmTest.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/SourceFirstTopologicalSortAlgorithmTest.cs.meta new file mode 100644 index 0000000..c509e03 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/SourceFirstTopologicalSortAlgorithmTest.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 16b90d91df864451890938c1757d6f72 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/StronglyConnectedComponentsAlgorithmTest.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/StronglyConnectedComponentsAlgorithmTest.cs new file mode 100755 index 0000000..e0ce7f8 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/StronglyConnectedComponentsAlgorithmTest.cs @@ -0,0 +1,141 @@ +using System; +using System.Collections.Generic; +using QuickGraph.Unit; +using Microsoft.Pex.Framework; + +namespace QuickGraph.Algorithms +{ + [TestFixture, PexClass] + public partial class StronglyConnectedComponentAlgorithmTest + { + [Test, PexMethod] + public void EmptyGraph() + { + IVertexListGraph> g = new AdjacencyGraph>(true); + StronglyConnectedComponentsAlgorithm> strong = new StronglyConnectedComponentsAlgorithm>(g); + strong.Compute(); + Assert.AreEqual(0, strong.ComponentCount); + checkStrong(strong); + } + + [Test, PexMethod] + public void OneVertex() + { + AdjacencyGraph> g = new AdjacencyGraph>(true); + g.AddVertex("test"); + StronglyConnectedComponentsAlgorithm> strong = new StronglyConnectedComponentsAlgorithm>(g); + strong.Compute(); + Assert.AreEqual(1, strong.ComponentCount); + + checkStrong(strong); + } + + [Test, PexMethod] + public void TwoVertex() + { + AdjacencyGraph> g = new AdjacencyGraph>(true); + g.AddVertex("v1"); + g.AddVertex("v2"); + StronglyConnectedComponentsAlgorithm> strong = new StronglyConnectedComponentsAlgorithm>(g); + strong.Compute(); + Assert.AreEqual(2, strong.ComponentCount); + + checkStrong(strong); + } + + [Test, PexMethod] + public void TwoVertexOnEdge() + { + AdjacencyGraph> g = new AdjacencyGraph>(true); + g.AddVertex("v1"); + g.AddVertex("v2"); + g.AddEdge(new Edge("v1", "v2")); + StronglyConnectedComponentsAlgorithm> strong = new StronglyConnectedComponentsAlgorithm>(g); + strong.Compute(); + Assert.AreEqual(2, strong.ComponentCount); + + checkStrong(strong); + } + + + [Test, PexMethod] + public void TwoVertexCycle() + { + AdjacencyGraph> g = new AdjacencyGraph>(true); + g.AddVertex("v1"); + g.AddVertex("v2"); + g.AddEdge(new Edge("v1", "v2")); + g.AddEdge(new Edge("v2", "v1")); + StronglyConnectedComponentsAlgorithm> strong = new StronglyConnectedComponentsAlgorithm>(g); + strong.Compute(); + Assert.AreEqual(1, strong.ComponentCount); + + checkStrong(strong); + } + + [Test, PexMethod] + public void Loop() + { + IVertexListGraph> g = new AdjacencyGraphFactory().Loop(); + StronglyConnectedComponentsAlgorithm> strong = new StronglyConnectedComponentsAlgorithm>(g); + strong.Compute(); + Assert.AreEqual(1, strong.ComponentCount); + + checkStrong(strong); + } + + [Test, PexMethod] + public void Simple() + { + IVertexListGraph> g = new AdjacencyGraphFactory().Simple(); + StronglyConnectedComponentsAlgorithm> strong = new StronglyConnectedComponentsAlgorithm>(g); + + strong.Compute(); + checkStrong(strong); + } + + [Test, PexMethod] + public void FileDependency() + { + IVertexListGraph> g = new AdjacencyGraphFactory().FileDependency(); + StronglyConnectedComponentsAlgorithm> strong = new StronglyConnectedComponentsAlgorithm>(g); + + strong.Compute(); + checkStrong(strong); + } + + [Test, PexMethod] + public void RegularLattice() + { + IVertexListGraph> g = new AdjacencyGraphFactory().RegularLattice10x10(); + StronglyConnectedComponentsAlgorithm> strong = new StronglyConnectedComponentsAlgorithm>(g); + + strong.Compute(); + checkStrong(strong); + } + + private void checkStrong(StronglyConnectedComponentsAlgorithm> strong) + { + Assert.AreEqual(strong.VisitedGraph.VertexCount, strong.Components.Count); + Assert.AreEqual(strong.VisitedGraph.VertexCount, strong.DiscoverTimes.Count); + Assert.AreEqual(strong.VisitedGraph.VertexCount, strong.Roots.Count); + + foreach (string v in strong.VisitedGraph.Vertices) + { + Assert.IsTrue(strong.Components.ContainsKey(v)); + Assert.IsTrue(strong.DiscoverTimes.ContainsKey(v)); + } + + foreach (KeyValuePair de in strong.Components) + { + Assert.IsNotNull(de.Key); + Assert.LowerEqualThan(de.Value, strong.ComponentCount); + } + + foreach (KeyValuePair de in strong.DiscoverTimes) + { + Assert.IsNotNull(de.Key); + } + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/StronglyConnectedComponentsAlgorithmTest.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/StronglyConnectedComponentsAlgorithmTest.cs.meta new file mode 100644 index 0000000..bd9ba4f --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/StronglyConnectedComponentsAlgorithmTest.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 41133fb40930846dea15262d662a6022 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/TopologicalSortAlgorithmTest.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/TopologicalSortAlgorithmTest.cs new file mode 100755 index 0000000..5c2e0b1 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/TopologicalSortAlgorithmTest.cs @@ -0,0 +1,30 @@ +using System; +using QuickGraph.Unit; +using Microsoft.Pex.Framework; + +namespace QuickGraph.Algorithms +{ + [TestFixture, PexClass] + [CurrentFixture] + public partial class TopologicalSortAlgorithmTest + { + [PexMethod] + public void SortCyclic( + [PexAssumeNotNull]IVertexListGraph> g) + { + TopologicalSortAlgorithm> topo = new TopologicalSortAlgorithm>(g); + topo.Compute(); + } + + [Test] + public void OneTwo() + { + var graph = new AdjacencyGraph>(); + graph.AddVertex(1); + graph.AddVertex(2); + graph.AddEdge(new Edge(1, 2)); + var t = new TopologicalSortAlgorithm>(graph); + t.Compute(); + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/TopologicalSortAlgorithmTest.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/TopologicalSortAlgorithmTest.cs.meta new file mode 100644 index 0000000..a62ccd4 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/TopologicalSortAlgorithmTest.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: f4dc066b26de64569900ad241b1786fe +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/UndirectedFirstTopologicalSortAlgorithmTest.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/UndirectedFirstTopologicalSortAlgorithmTest.cs new file mode 100755 index 0000000..042237d --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/UndirectedFirstTopologicalSortAlgorithmTest.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using QuickGraph.Unit; +using Microsoft.Pex.Framework; + +namespace QuickGraph.Algorithms +{ + [TypeFixture(typeof(IUndirectedGraph>)), PexClass] + [TypeFactory(typeof(UndirectedGraphFactory))] + public partial class UndirectedFirstTopologicalSortAlgorithmTest + { + + [Test, PexMethod] + public void Compute([PexAssumeNotNull]IUndirectedGraph> g) + { + var topo = + new UndirectedFirstTopologicalSortAlgorithm>(g); + topo.AllowCyclicGraph = true; + topo.Compute(); + + Display(topo); + } + + private void Display(UndirectedFirstTopologicalSortAlgorithm> topo) + { + int index = 0; + foreach (string v in topo.SortedVertices) + Console.WriteLine("{0}: {1}", index++, v); + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/UndirectedFirstTopologicalSortAlgorithmTest.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/UndirectedFirstTopologicalSortAlgorithmTest.cs.meta new file mode 100644 index 0000000..ee3ac54 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/UndirectedFirstTopologicalSortAlgorithmTest.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 7ba8a716fc354471891469ecbc7da9cb +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/UndirectedTopologicalSortAlgorithmTest.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/UndirectedTopologicalSortAlgorithmTest.cs new file mode 100755 index 0000000..fba3fd1 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/UndirectedTopologicalSortAlgorithmTest.cs @@ -0,0 +1,29 @@ +using System; +using System.Collections.Generic; +using QuickGraph.Unit; +using Microsoft.Pex.Framework; + +namespace QuickGraph.Algorithms +{ + [TestFixture, PexClass] + public partial class UndirectedTopologicalSortAlgorithmTest + { + [PexMethod] + public void Compute([PexAssumeNotNull]IUndirectedGraph> g) + { + UndirectedTopologicalSortAlgorithm> topo = + new UndirectedTopologicalSortAlgorithm>(g); + topo.AllowCyclicGraph = true; + topo.Compute(); + + Display(topo); + } + + private void Display(UndirectedTopologicalSortAlgorithm> topo) + { + int index = 0; + foreach (string v in topo.SortedVertices) + Console.WriteLine("{0}: {1}", index++, v); + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/UndirectedTopologicalSortAlgorithmTest.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/UndirectedTopologicalSortAlgorithmTest.cs.meta new file mode 100644 index 0000000..7f14067 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/UndirectedTopologicalSortAlgorithmTest.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 5d16dd45f52954a028868beccbf02880 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/WeaklyConnectedComponentsAlgorithmTest.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/WeaklyConnectedComponentsAlgorithmTest.cs new file mode 100755 index 0000000..79c0740 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/WeaklyConnectedComponentsAlgorithmTest.cs @@ -0,0 +1,40 @@ +using System; +using System.Collections.Generic; +using QuickGraph.Unit; +using Microsoft.Pex.Framework; + +namespace QuickGraph.Algorithms +{ + [TestFixture, PexClass] + public partial class WeaklyConnectedComponentsAlgorithmTest + { + [PexMethod] + public void Compute([PexAssumeNotNull]IVertexListGraph> g) + { + GraphConsoleSerializer.DisplayGraph(g); + + WeaklyConnectedComponentsAlgorithm> dfs = + new WeaklyConnectedComponentsAlgorithm>(g); + dfs.Compute(); + + Console.WriteLine("Weak components: {0}", dfs.ComponentCount); + Assert.AreEqual(g.VertexCount, dfs.Components.Count); + foreach (KeyValuePair kv in dfs.Components) + { + Console.WriteLine("\t{0}: {1}", kv.Key, kv.Value); + } + + foreach(KeyValuePair kv in dfs.Components) + { + Assert.IsLowerEqual(0, kv.Value); + Assert.IsLower(kv.Value, dfs.ComponentCount); + } + + foreach(string vertex in g.Vertices) + foreach (Edge edge in g.OutEdges(vertex)) + { + Assert.AreEqual(dfs.Components[edge.Source], dfs.Components[edge.Target]); + } + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/WeaklyConnectedComponentsAlgorithmTest.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/WeaklyConnectedComponentsAlgorithmTest.cs.meta new file mode 100644 index 0000000..da35cf5 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Algorithms/WeaklyConnectedComponentsAlgorithmTest.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 6bb4b3a45b42342c3affd4ad906ceb18 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/BidirectionalGraphFactory.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/BidirectionalGraphFactory.cs new file mode 100755 index 0000000..a493d91 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/BidirectionalGraphFactory.cs @@ -0,0 +1,82 @@ +using System; +using QuickGraph.Unit; +using Microsoft.Pex.Framework; +using QuickGraph; + +namespace QuickGraph +{ + public class BidirectionalGraphFactory + { + private static BidirectionalGraph> CreateGraph() + { + return new BidirectionalGraph>(false); + } + + public static Type CreateType() + { + return typeof(BidirectionalGraph>); + } + + [Factory] + public BidirectionalGraph> Empty() + { + return CreateGraph(); + } + + [Factory] + public BidirectionalGraph> NoEdges() + { + BidirectionalGraph> g = CreateGraph(); + GraphFactory.NoEdges(g); + return g; + } + + [Factory] + public BidirectionalGraph> Loop() + { + BidirectionalGraph> g = CreateGraph(); + GraphFactory.Loop(g); + return g; + } + + [Factory] + public BidirectionalGraph> LoopDouble() + { + BidirectionalGraph> g = CreateGraph(); + GraphFactory.LoopDouble(g); + return g; + } + + [Factory] + public BidirectionalGraph> FileDependency() + { + BidirectionalGraph> g = CreateGraph(); + GraphFactory.FileDependency(g); + return g; + } + + [Factory] + public BidirectionalGraph> RegularLattice10x10() + { + BidirectionalGraph> g = CreateGraph(); + GraphFactory.RegularLattice(10, 10, g); + return g; + } + + [Factory] + public BidirectionalGraph> Simple() + { + BidirectionalGraph> g = CreateGraph(); + GraphFactory.Simple(g); + return g; + } + + [Factory] + public BidirectionalGraph> UnBalancedFlow() + { + BidirectionalGraph> g = CreateGraph(); + GraphFactory.UnBalancedFlow(g); + return g; + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/BidirectionalGraphFactory.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/BidirectionalGraphFactory.cs.meta new file mode 100644 index 0000000..e632b9e --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/BidirectionalGraphFactory.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ab2e7dafdbce241d599f3a36f599b53b +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/BidirectionalMatrixGraphFactory.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/BidirectionalMatrixGraphFactory.cs new file mode 100755 index 0000000..99b444c --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/BidirectionalMatrixGraphFactory.cs @@ -0,0 +1,60 @@ +using System; +using System.Collections.Generic; +using QuickGraph.Unit; +using QuickGraph; +using Microsoft.Pex.Framework; + +namespace QuickGraph +{ + public class BidirectionalMatrixGraphFactory + { + [Factory] + public BidirectionalMatrixGraph> Empty() + { + return new BidirectionalMatrixGraph>(10); + } + + [Factory] + public BidirectionalMatrixGraph> OneEdge() + { + BidirectionalMatrixGraph < Edge > g= new BidirectionalMatrixGraph>(10); + g.AddEdge(new Edge(0, 1)); + return g; + } + + [Factory] + public BidirectionalMatrixGraph> TwoDisjointEdges() + { + BidirectionalMatrixGraph> g = new BidirectionalMatrixGraph>(10); + g.AddEdge(new Edge(0, 1)); + g.AddEdge(new Edge(5, 6)); + return g; + } + + [Factory] + public BidirectionalMatrixGraph> TwoConnectedEdges() + { + BidirectionalMatrixGraph> g = new BidirectionalMatrixGraph>(10); + g.AddEdge(new Edge(0, 1)); + g.AddEdge(new Edge(1, 2)); + return g; + } + + [Factory] + public BidirectionalMatrixGraph> SelfEdge() + { + BidirectionalMatrixGraph> g = new BidirectionalMatrixGraph>(10); + g.AddEdge(new Edge(1, 1)); + return g; + } + + [Factory] + public BidirectionalMatrixGraph> Loop() + { + BidirectionalMatrixGraph> g = new BidirectionalMatrixGraph>(10); + g.AddEdge(new Edge(0, 1)); + g.AddEdge(new Edge(1, 0)); + return g; + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/BidirectionalMatrixGraphFactory.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/BidirectionalMatrixGraphFactory.cs.meta new file mode 100644 index 0000000..e6709d3 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/BidirectionalMatrixGraphFactory.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 82cc0b2740f004c42b951e5828640fb7 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Collections.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Collections.meta new file mode 100644 index 0000000..760dcd8 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Collections.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: 625bc1191c5f5430bbcd9fcfb05fb141 +folderAsset: yes +DefaultImporter: + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Collections/BinaryHeapTPriorityTValueEnumeratorTest.CurrentAfterMoveNextFinished.g.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Collections/BinaryHeapTPriorityTValueEnumeratorTest.CurrentAfterMoveNextFinished.g.cs new file mode 100755 index 0000000..638a5b2 Binary files /dev/null and b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Collections/BinaryHeapTPriorityTValueEnumeratorTest.CurrentAfterMoveNextFinished.g.cs differ diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Collections/BinaryHeapTPriorityTValueEnumeratorTest.CurrentAfterMoveNextFinished.g.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Collections/BinaryHeapTPriorityTValueEnumeratorTest.CurrentAfterMoveNextFinished.g.cs.meta new file mode 100644 index 0000000..ad75ba0 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Collections/BinaryHeapTPriorityTValueEnumeratorTest.CurrentAfterMoveNextFinished.g.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 558b4afa6e1c34c5aba04c95e74e2b8c +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Collections/BinaryHeapTPriorityTValueEnumeratorTest.CurrentBeforeMoveNext.g.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Collections/BinaryHeapTPriorityTValueEnumeratorTest.CurrentBeforeMoveNext.g.cs new file mode 100755 index 0000000..ef6dbaa Binary files /dev/null and b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Collections/BinaryHeapTPriorityTValueEnumeratorTest.CurrentBeforeMoveNext.g.cs differ diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Collections/BinaryHeapTPriorityTValueEnumeratorTest.CurrentBeforeMoveNext.g.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Collections/BinaryHeapTPriorityTValueEnumeratorTest.CurrentBeforeMoveNext.g.cs.meta new file mode 100644 index 0000000..62d0430 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Collections/BinaryHeapTPriorityTValueEnumeratorTest.CurrentBeforeMoveNext.g.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 4a9d48585aac845e78e512ebd3a26d5d +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Collections/BinaryHeapTPriorityTValueEnumeratorTest.InsertAndCurrentAndModify.g.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Collections/BinaryHeapTPriorityTValueEnumeratorTest.InsertAndCurrentAndModify.g.cs new file mode 100755 index 0000000..1583d28 Binary files /dev/null and b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Collections/BinaryHeapTPriorityTValueEnumeratorTest.InsertAndCurrentAndModify.g.cs differ diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Collections/BinaryHeapTPriorityTValueEnumeratorTest.InsertAndCurrentAndModify.g.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Collections/BinaryHeapTPriorityTValueEnumeratorTest.InsertAndCurrentAndModify.g.cs.meta new file mode 100644 index 0000000..476d46d --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Collections/BinaryHeapTPriorityTValueEnumeratorTest.InsertAndCurrentAndModify.g.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: f358810f27b954dcfa6932a21e0cb17b +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Collections/BinaryHeapTPriorityTValueEnumeratorTest.InsertAndMoveNextAndModify.g.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Collections/BinaryHeapTPriorityTValueEnumeratorTest.InsertAndMoveNextAndModify.g.cs new file mode 100755 index 0000000..cb3d226 Binary files /dev/null and b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Collections/BinaryHeapTPriorityTValueEnumeratorTest.InsertAndMoveNextAndModify.g.cs differ diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Collections/BinaryHeapTPriorityTValueEnumeratorTest.InsertAndMoveNextAndModify.g.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Collections/BinaryHeapTPriorityTValueEnumeratorTest.InsertAndMoveNextAndModify.g.cs.meta new file mode 100644 index 0000000..72ca7c3 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Collections/BinaryHeapTPriorityTValueEnumeratorTest.InsertAndMoveNextAndModify.g.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 27afb8f93f9af4a8997cb4101405b3c4 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Collections/BinaryHeapTPriorityTValueEnumeratorTest.InsertAndResetAndModify.g.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Collections/BinaryHeapTPriorityTValueEnumeratorTest.InsertAndResetAndModify.g.cs new file mode 100755 index 0000000..e7710d6 Binary files /dev/null and b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Collections/BinaryHeapTPriorityTValueEnumeratorTest.InsertAndResetAndModify.g.cs differ diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Collections/BinaryHeapTPriorityTValueEnumeratorTest.InsertAndResetAndModify.g.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Collections/BinaryHeapTPriorityTValueEnumeratorTest.InsertAndResetAndModify.g.cs.meta new file mode 100644 index 0000000..e7c66ed --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Collections/BinaryHeapTPriorityTValueEnumeratorTest.InsertAndResetAndModify.g.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: c1019afa7a13a44d3a9bd17722f9f055 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Collections/BinaryHeapTPriorityTValueEnumeratorTest.InsertManyAndDoubleForEach.g.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Collections/BinaryHeapTPriorityTValueEnumeratorTest.InsertManyAndDoubleForEach.g.cs new file mode 100755 index 0000000..3a07b62 Binary files /dev/null and b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Collections/BinaryHeapTPriorityTValueEnumeratorTest.InsertManyAndDoubleForEach.g.cs differ diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Collections/BinaryHeapTPriorityTValueEnumeratorTest.InsertManyAndDoubleForEach.g.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Collections/BinaryHeapTPriorityTValueEnumeratorTest.InsertManyAndDoubleForEach.g.cs.meta new file mode 100644 index 0000000..386c899 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Collections/BinaryHeapTPriorityTValueEnumeratorTest.InsertManyAndDoubleForEach.g.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ec949ec355248426aa89167a5db72f9a +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Collections/BinaryHeapTPriorityTValueEnumeratorTest.InsertManyAndEnumerateUntyped.g.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Collections/BinaryHeapTPriorityTValueEnumeratorTest.InsertManyAndEnumerateUntyped.g.cs new file mode 100755 index 0000000..2809c36 Binary files /dev/null and b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Collections/BinaryHeapTPriorityTValueEnumeratorTest.InsertManyAndEnumerateUntyped.g.cs differ diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Collections/BinaryHeapTPriorityTValueEnumeratorTest.InsertManyAndEnumerateUntyped.g.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Collections/BinaryHeapTPriorityTValueEnumeratorTest.InsertManyAndEnumerateUntyped.g.cs.meta new file mode 100644 index 0000000..c6c1a99 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Collections/BinaryHeapTPriorityTValueEnumeratorTest.InsertManyAndEnumerateUntyped.g.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 8cfd77f6614ca498388a5332e5edfce6 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Collections/BinaryHeapTPriorityTValueEnumeratorTest.InsertManyAndMoveNextAndReset.g.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Collections/BinaryHeapTPriorityTValueEnumeratorTest.InsertManyAndMoveNextAndReset.g.cs new file mode 100755 index 0000000..8fc987b Binary files /dev/null and b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Collections/BinaryHeapTPriorityTValueEnumeratorTest.InsertManyAndMoveNextAndReset.g.cs differ diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Collections/BinaryHeapTPriorityTValueEnumeratorTest.InsertManyAndMoveNextAndReset.g.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Collections/BinaryHeapTPriorityTValueEnumeratorTest.InsertManyAndMoveNextAndReset.g.cs.meta new file mode 100644 index 0000000..51ef277 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Collections/BinaryHeapTPriorityTValueEnumeratorTest.InsertManyAndMoveNextAndReset.g.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: f0181411533264bb4b75a01825a7f125 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Collections/BinaryHeapTPriorityTValueTest.Constructor.g.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Collections/BinaryHeapTPriorityTValueTest.Constructor.g.cs new file mode 100755 index 0000000..b9e18ee Binary files /dev/null and b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Collections/BinaryHeapTPriorityTValueTest.Constructor.g.cs differ diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Collections/BinaryHeapTPriorityTValueTest.Constructor.g.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Collections/BinaryHeapTPriorityTValueTest.Constructor.g.cs.meta new file mode 100644 index 0000000..f0bbc74 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Collections/BinaryHeapTPriorityTValueTest.Constructor.g.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 9374c4f00e726498ab44fad6dc6a5a9a +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Collections/BinaryHeapTPriorityTValueTest.Insert.g.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Collections/BinaryHeapTPriorityTValueTest.Insert.g.cs new file mode 100755 index 0000000..aa2ddd1 Binary files /dev/null and b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Collections/BinaryHeapTPriorityTValueTest.Insert.g.cs differ diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Collections/BinaryHeapTPriorityTValueTest.Insert.g.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Collections/BinaryHeapTPriorityTValueTest.Insert.g.cs.meta new file mode 100644 index 0000000..3d1c73b --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Collections/BinaryHeapTPriorityTValueTest.Insert.g.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 10e324ad3065b4728be4c5a2ea482f82 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Collections/BinaryHeapTPriorityTValueTest.InsertAndEnumerate.g.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Collections/BinaryHeapTPriorityTValueTest.InsertAndEnumerate.g.cs new file mode 100755 index 0000000..ed07367 Binary files /dev/null and b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Collections/BinaryHeapTPriorityTValueTest.InsertAndEnumerate.g.cs differ diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Collections/BinaryHeapTPriorityTValueTest.InsertAndEnumerate.g.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Collections/BinaryHeapTPriorityTValueTest.InsertAndEnumerate.g.cs.meta new file mode 100644 index 0000000..f8515d7 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Collections/BinaryHeapTPriorityTValueTest.InsertAndEnumerate.g.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 2813dcb33d8034f648677dd81ff19597 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Collections/BinaryHeapTPriorityTValueTest.InsertAndIndexOf.g.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Collections/BinaryHeapTPriorityTValueTest.InsertAndIndexOf.g.cs new file mode 100755 index 0000000..27fc7d6 Binary files /dev/null and b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Collections/BinaryHeapTPriorityTValueTest.InsertAndIndexOf.g.cs differ diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Collections/BinaryHeapTPriorityTValueTest.InsertAndIndexOf.g.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Collections/BinaryHeapTPriorityTValueTest.InsertAndIndexOf.g.cs.meta new file mode 100644 index 0000000..ec471b5 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Collections/BinaryHeapTPriorityTValueTest.InsertAndIndexOf.g.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: a3703d79495da420894901e301f7ff54 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Collections/BinaryHeapTPriorityTValueTest.InsertAndMinimum.g.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Collections/BinaryHeapTPriorityTValueTest.InsertAndMinimum.g.cs new file mode 100755 index 0000000..d811429 Binary files /dev/null and b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Collections/BinaryHeapTPriorityTValueTest.InsertAndMinimum.g.cs differ diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Collections/BinaryHeapTPriorityTValueTest.InsertAndMinimum.g.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Collections/BinaryHeapTPriorityTValueTest.InsertAndMinimum.g.cs.meta new file mode 100644 index 0000000..cbfd837 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Collections/BinaryHeapTPriorityTValueTest.InsertAndMinimum.g.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 5b01c10d5d355436db56ee1f0ecd6296 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Collections/BinaryHeapTPriorityTValueTest.InsertAndRemoveAt.g.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Collections/BinaryHeapTPriorityTValueTest.InsertAndRemoveAt.g.cs new file mode 100755 index 0000000..82accfc Binary files /dev/null and b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Collections/BinaryHeapTPriorityTValueTest.InsertAndRemoveAt.g.cs differ diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Collections/BinaryHeapTPriorityTValueTest.InsertAndRemoveAt.g.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Collections/BinaryHeapTPriorityTValueTest.InsertAndRemoveAt.g.cs.meta new file mode 100644 index 0000000..71a1180 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Collections/BinaryHeapTPriorityTValueTest.InsertAndRemoveAt.g.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 5e2aaa549c72f43a98aecefad6d69f7a +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Collections/BinaryHeapTPriorityTValueTest.InsertAndRemoveAtAll.g.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Collections/BinaryHeapTPriorityTValueTest.InsertAndRemoveAtAll.g.cs new file mode 100755 index 0000000..b428528 Binary files /dev/null and b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Collections/BinaryHeapTPriorityTValueTest.InsertAndRemoveAtAll.g.cs differ diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Collections/BinaryHeapTPriorityTValueTest.InsertAndRemoveAtAll.g.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Collections/BinaryHeapTPriorityTValueTest.InsertAndRemoveAtAll.g.cs.meta new file mode 100644 index 0000000..42ae697 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Collections/BinaryHeapTPriorityTValueTest.InsertAndRemoveAtAll.g.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 022e52dae42444e1498d5eab3cce99e6 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Collections/BinaryHeapTPriorityTValueTest.InsertAndRemoveMinimum.g.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Collections/BinaryHeapTPriorityTValueTest.InsertAndRemoveMinimum.g.cs new file mode 100755 index 0000000..45f0d34 Binary files /dev/null and b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Collections/BinaryHeapTPriorityTValueTest.InsertAndRemoveMinimum.g.cs differ diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Collections/BinaryHeapTPriorityTValueTest.InsertAndRemoveMinimum.g.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Collections/BinaryHeapTPriorityTValueTest.InsertAndRemoveMinimum.g.cs.meta new file mode 100644 index 0000000..671bd1d --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Collections/BinaryHeapTPriorityTValueTest.InsertAndRemoveMinimum.g.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 0d21015fb02784758aedf49f26c1e7b1 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Collections/BinaryHeapTest.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Collections/BinaryHeapTest.cs new file mode 100755 index 0000000..845039e --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Collections/BinaryHeapTest.cs @@ -0,0 +1,312 @@ +using Microsoft.Pex.Framework; +using Microsoft.Pex.Framework.Using; +using System; +using System.Collections.Generic; +using Microsoft.Pex.Framework.Validation; +using Microsoft.Pex.Framework.Wizard; +using System.Collections; +using QuickGraph.Unit; +using Microsoft.Pex.Framework.Factories; + +namespace QuickGraph.Collections +{ + [PexFactoryClass] + public partial class BinaryHeapFactory + { + [PexFactoryMethod(typeof(BinaryHeap))] + public static BinaryHeap Create(int capacity) + { + var heap = new BinaryHeap(capacity, (i, j) => i.CompareTo(j)); + heap.ObjectInvariant(); + return heap; + } + } + + /// + /// This class contains parameterized unit tests for BinaryHeap`2 + /// + [TestFixture] + [PexClass(typeof(BinaryHeap<,>))] + [PexUseGenericArguments(typeof(int), typeof(int))] + public partial class BinaryHeapTPriorityTValueTest + { + /// + /// Checks heap invariant + /// + private static void AssertInvariant( + BinaryHeap target + ) + { + Assert.IsTrue(target.Capacity >= 0); + Assert.IsTrue(target.Count >= 0); + Assert.IsTrue(target.Count <= target.Capacity); + target.ObjectInvariant(); + } + + [Test] + public void Constructor() + { + var target = new BinaryHeap(); + AssertInvariant(target); + } + + [Test] + [ExpectedException(typeof(ArgumentNullException))] + public void ConstructorWithNullComparison() + { + var target = new BinaryHeap(0, null); + } + + [PexMethod] + [PexAllowedExceptionFromTypeUnderTest(typeof(ArgumentNullException))] + [PexAllowedExceptionFromTypeUnderTest(typeof(ArgumentOutOfRangeException))] + public void Constructor(int capacity) + { + var target = new BinaryHeap(capacity, Comparer.Default.Compare); + Assert.AreEqual(target.Capacity, capacity); + AssertInvariant(target); + } + + [PexMethod(MaxRuns = 20)] + public void Insert( + [PexAssumeUnderTest]BinaryHeap target, + [PexAssumeNotNull] KeyValuePair[] kvs) + { + var count = target.Count; + foreach (var kv in kvs) + { + target.Add(kv.Key, kv.Value); + AssertInvariant(target); + } + Assert.IsTrue(count + kvs.Length == target.Count); + } + + [PexMethod(MaxRuns = 20)] + public void InsertAndIndexOf( + [PexAssumeUnderTest]BinaryHeap target, + [PexAssumeNotNull] KeyValuePair[] kvs) + { + foreach (var kv in kvs) + target.Add(kv.Key, kv.Value); + foreach (var kv in kvs) + Assert.IsTrue(target.IndexOf(kv.Value) > -1, "target.IndexOf(kv.Value) > -1"); + } + + [PexMethod(MaxRuns = 20)] + [PexAllowedExceptionFromTypeUnderTest(typeof(InvalidOperationException))] + [PexAllowedExceptionFromTypeUnderTest(typeof(ArgumentOutOfRangeException))] + public void InsertAndRemoveAt( + [PexAssumeUnderTest]BinaryHeap target, + [PexAssumeNotNull] KeyValuePair[] kvs, + int removeAtIndex) + { + foreach (var kv in kvs) + target.Add(kv.Key, kv.Value); + var count = target.Count; + var removed = target.RemoveAt(removeAtIndex); + Assert.AreEqual(count - 1, target.Count); + AssertInvariant(target); + } + + [PexMethod(MaxRuns = 20)] + [PexAllowedExceptionFromTypeUnderTest(typeof(ArgumentOutOfRangeException))] + public void InsertAndRemoveAtAll( + [PexAssumeUnderTest]BinaryHeap target, + [PexAssumeNotNull] KeyValuePair[] kvs) + { + foreach (var kv in kvs) + target.Add(kv.Key, kv.Value); + var call = PexChoose.FromCall(this); + for (int i = target.Count - 1; i > -1; ++i) + { + target.RemoveAt(call.ValueFromRange(i.ToString(), 0, target.Count - 1)); + AssertInvariant(target); + } + } + + [PexMethod(MaxRuns = 20)] + public void InsertAndEnumerate( + [PexAssumeUnderTest]BinaryHeap target, + [PexAssumeNotNull] KeyValuePair[] kvs) + { + var dic = new Dictionary(); + foreach (var kv in kvs) + { + target.Add(kv.Key, kv.Value); + dic[kv.Key] = kv.Value; + } + PexAssert.TrueForAll(target, kv => dic.ContainsKey(kv.Key)); + } + + [PexMethod(MaxRuns = 100)] + [PexAllowedExceptionFromTypeUnderTest(typeof(InvalidOperationException))] + public void InsertAndRemoveMinimum( + [PexAssumeUnderTest]BinaryHeap target, + [PexAssumeNotNull] KeyValuePair[] kvs) + { + var count = target.Count; + foreach (var kv in kvs) + target.Add(kv.Key, kv.Value); + + TPriority minimum = default(TPriority); + for (int i = 0; i < kvs.Length; ++i) + { + if (i == 0) + minimum = target.RemoveMinimum().Key; + else + { + var m = target.RemoveMinimum().Key; + Assert.IsTrue(target.PriorityComparison(minimum, m) <= 0); + minimum = m; + } + AssertInvariant(target); + } + + Assert.AreEqual(0, target.Count); + } + + [Test] + [ExpectedException(typeof(InvalidOperationException))] + public void RemoveMinimumOnEmpty() + { + new BinaryHeap().RemoveMinimum(); + } + + [PexMethod(MaxRuns = 40)] + [PexAllowedExceptionFromTypeUnderTest(typeof(InvalidOperationException))] + public void InsertAndMinimum( + [PexAssumeUnderTest]BinaryHeap target, + [PexAssumeNotNull] KeyValuePair[] kvs) + { + PexAssume.IsTrue(kvs.Length > 0); + + var count = target.Count; + TPriority minimum = default(TPriority); + for (int i = 0; i < kvs.Length; ++i) + { + var kv = kvs[i]; + if (i == 0) + minimum = kv.Key; + else + minimum = target.PriorityComparison(kv.Key, minimum) < 0 ? kv.Key : minimum; + target.Add(kv.Key, kv.Value); + // check minimum + var kvMin = target.Minimum(); + Assert.AreEqual(minimum, kvMin.Key); + } + AssertInvariant(target); + } + + [Test] + [ExpectedException(typeof(InvalidOperationException))] + public void MinimumOnEmpty() + { + new BinaryHeap().Minimum(); + } + } + + [TestFixture] + [PexClass(typeof(BinaryHeap<,>))] + [PexUseGenericArguments(typeof(int), typeof(int))] + public partial class BinaryHeapTPriorityTValueEnumeratorTest + { + [PexMethod(MaxRuns = 20)] + public void InsertManyAndEnumerateUntyped( + [PexAssumeUnderTest]BinaryHeap target, + [PexAssumeNotNull] KeyValuePair[] kvs) + { + foreach (var kv in kvs) + target.Add(kv.Key, kv.Value); + foreach (KeyValuePair kv in (IEnumerable)target) ; + } + + [PexMethod(MaxRuns = 20)] + public void InsertManyAndDoubleForEach( + [PexAssumeUnderTest]BinaryHeap target, + [PexAssumeNotNull] KeyValuePair[] kvs) + { + foreach (var kv in kvs) + target.Add(kv.Key, kv.Value); + PexEnumerablePatterns.DoubleForEach(target); + } + + [PexMethod(MaxRuns = 20)] + public void InsertManyAndMoveNextAndReset( + [PexAssumeUnderTest]BinaryHeap target, + [PexAssumeNotNull] KeyValuePair[] kvs) + { + foreach (var kv in kvs) + target.Add(kv.Key, kv.Value); + PexEnumerablePatterns.MoveNextAndReset(target); + } + + [PexMethod(MaxRuns = 20)] + public void InsertAndMoveNextAndModify( + [PexAssumeUnderTest]BinaryHeap target, + KeyValuePair kv) + { + target.Add(kv.Key, kv.Value); + PexAssert.Throws(delegate + { + var enumerator = target.GetEnumerator(); + target.Add(kv.Key, kv.Value); + enumerator.MoveNext(); + }); + } + + [PexMethod(MaxRuns = 20)] + public void InsertAndResetAndModify( + [PexAssumeUnderTest]BinaryHeap target, + KeyValuePair kv) + { + target.Add(kv.Key, kv.Value); + PexAssert.Throws(delegate + { + var enumerator = target.GetEnumerator(); + target.Add(kv.Key, kv.Value); + enumerator.Reset(); + }); + } + + [PexMethod(MaxRuns = 20)] + public void InsertAndCurrentAndModify( + [PexAssumeUnderTest]BinaryHeap target, + KeyValuePair kv) + { + target.Add(kv.Key, kv.Value); + PexAssert.Throws(delegate + { + var enumerator = target.GetEnumerator(); + target.Add(kv.Key, kv.Value); + var current = enumerator.Current; + }); + } + + [PexMethod(MaxRuns = 20)] + public void CurrentAfterMoveNextFinished( + [PexAssumeUnderTest]BinaryHeap target, + KeyValuePair kv) + { + target.Add(kv.Key, kv.Value); + PexAssert.Throws(delegate + { + var enumerator = target.GetEnumerator(); + while (enumerator.MoveNext()) ; + var current = enumerator.Current; + }); + } + + [PexMethod(MaxRuns = 20)] + public void CurrentBeforeMoveNext( + [PexAssumeUnderTest]BinaryHeap target, + KeyValuePair kv) + { + target.Add(kv.Key, kv.Value); + PexAssert.Throws(delegate + { + var enumerator = target.GetEnumerator(); + var current = enumerator.Current; + }); + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Collections/BinaryHeapTest.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Collections/BinaryHeapTest.cs.meta new file mode 100644 index 0000000..5c9ade9 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Collections/BinaryHeapTest.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: bbc2f693670e4479bbff8f0df928602b +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/DegreeTest.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/DegreeTest.cs new file mode 100755 index 0000000..eb14ca4 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/DegreeTest.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.Generic; +using System.Text; +using QuickGraph.Unit; +using Microsoft.Pex.Framework; + +namespace QuickGraph.Tests +{ + [TestFixture, PexClass] + public partial class DegreeTest + { + [PexMethod] + public void DegreeSumEqualsTwiceEdgeCount( + [PexAssumeNotNull]IBidirectionalGraph> graph) + { + int edgeCount = graph.EdgeCount; + int degCount = 0; + foreach (string v in graph.Vertices) + degCount += graph.Degree(v); + + Assert.AreEqual(edgeCount * 2, degCount); + } + + [PexMethod] + public void InDegreeSumEqualsEdgeCount([PexAssumeNotNull] IBidirectionalGraph> graph) + { + int edgeCount = graph.EdgeCount; + int degCount = 0; + foreach (string v in graph.Vertices) + degCount += graph.InDegree(v); + + Assert.AreEqual(edgeCount, degCount); + } + + [PexMethod] + public void OutDegreeSumEqualsEdgeCount([PexAssumeNotNull] IBidirectionalGraph> graph) + { + int edgeCount = graph.EdgeCount; + int degCount = 0; + foreach (string v in graph.Vertices) + degCount += graph.OutDegree(v); + + Assert.AreEqual(edgeCount, degCount); + } + + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/DegreeTest.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/DegreeTest.cs.meta new file mode 100644 index 0000000..9a54014 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/DegreeTest.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d4b8ea73cb1f0405fab62a872fd696ae +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/EdgeListGraphFactory.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/EdgeListGraphFactory.cs new file mode 100755 index 0000000..2dc1ba9 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/EdgeListGraphFactory.cs @@ -0,0 +1,52 @@ +using System; +using System.Collections.Generic; +using QuickGraph.Unit; +using Microsoft.Pex.Framework; +using QuickGraph; + +namespace QuickGraph +{ + public class EdgeListGraphFactory + { + [Factory] + public EdgeListGraph> Empty() + { + return new EdgeListGraph>(); + } + + [Factory] + public EdgeListGraph> OneEdge() + { + EdgeListGraph> g = new EdgeListGraph>(); + g.AddEdge(new Edge(0,1)); + return g; + } + + [Factory] + public EdgeListGraph> TwoEdges() + { + EdgeListGraph> g = new EdgeListGraph>(); + g.AddEdge(new Edge(0, 1)); + g.AddEdge(new Edge(2, 3)); + return g; + } + + [Factory] + public EdgeListGraph> Loop() + { + EdgeListGraph> g = new EdgeListGraph>(); + g.AddEdge(new Edge(0, 1)); + g.AddEdge(new Edge(1, 0)); + return g; + } + + [Factory] + public EdgeListGraph> ParralelEdges() + { + EdgeListGraph> g = new EdgeListGraph>(); + g.AddEdge(new Edge(0, 1)); + g.AddEdge(new Edge(0, 1)); + return g; + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/EdgeListGraphFactory.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/EdgeListGraphFactory.cs.meta new file mode 100644 index 0000000..7a46bd1 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/EdgeListGraphFactory.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 18fda315b8a9f4006b757b0fd647fbda +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/EdgeListGraphInvariant.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/EdgeListGraphInvariant.cs new file mode 100755 index 0000000..91b7643 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/EdgeListGraphInvariant.cs @@ -0,0 +1,35 @@ +using System; +using QuickGraph.Unit; +using Microsoft.Pex.Framework; + +namespace QuickGraph +{ + [TestFixture, PexClass] + public static class EdgeListGraphTest where E : IEdge + { + [PexMethod] + public static void Iteration([PexAssumeUnderTest]IEdgeListGraph g) + { + int n = g.EdgeCount; + int i = 0; + foreach (E e in g.Edges) + ++i; + } + + [PexMethod] + public static void Count([PexAssumeUnderTest]IEdgeListGraph g) + { + int n = g.EdgeCount; + if (n == 0) + Assert.IsTrue(g.IsEdgesEmpty); + + int i = 0; + foreach (E e in g.Edges) + { + e.ToString(); + ++i; + } + Assert.AreEqual(n, i); + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/EdgeListGraphInvariant.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/EdgeListGraphInvariant.cs.meta new file mode 100644 index 0000000..fd275ce --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/EdgeListGraphInvariant.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 58d033b28e9a64c349a40cbb64e34965 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/FactoryCompilerTest.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/FactoryCompilerTest.cs new file mode 100755 index 0000000..5817b1c --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/FactoryCompilerTest.cs @@ -0,0 +1,78 @@ +using System; +using System.Collections.Generic; +using System.Reflection; +using QuickGraph.Unit; +using Microsoft.Pex.Framework; + +namespace QuickGraph +{ + [TestFixture, PexClass] + public partial class FactoryCompilerTest + { + public interface IFoo + { + T Boo(); + } + public class Foo : IFoo + { + public int Boo() + { + return 0; + } + } + + [Test, PexMethod] + public void CreateVertexFactory() + { + MethodInfo boo = typeof(Foo).GetMethod("Boo"); + + IVertexFactory factory = FactoryCompiler.GetVertexFactory(); + Assert.IsNotNull(factory); + Foo foo = factory.CreateVertex(); + Assert.IsNotNull(foo); + } + + [Test, PexMethod] + public void CreateVertexFactoryTwice() + { + IVertexFactory factory = FactoryCompiler.GetVertexFactory(); + Assert.IsNotNull(factory); + Assert.IsNotNull(factory.CreateVertex()); + IVertexFactory factory2 = FactoryCompiler.GetVertexFactory(); + Assert.IsNotNull(factory2); + Assert.IsNotNull(factory2.CreateVertex()); + } + + [Test, PexMethod] + public void CreateEdgeFactory() + { + IEdgeFactory> factory = FactoryCompiler.GetEdgeFactory>(); + Assert.IsNotNull(factory); + Foo source = new Foo(); + Foo target = new Foo(); + Edge edge = factory.CreateEdge(source, target); + + Assert.IsNotNull(edge); + Assert.IsNotNull(edge.Source); + Assert.IsNotNull(edge.Target); + } + + [Test, PexMethod] + public void CreateEdgeFactoryTwice() + { + CreateEdgeFactory(); + CreateEdgeFactory(); + } + + [Test, PexMethod] + public void CreateDifferentFactories() + { + FactoryCompiler.GetEdgeFactory>(); + FactoryCompiler.GetEdgeFactory>(); + FactoryCompiler.GetEdgeFactory>(); + FactoryCompiler.GetEdgeFactory>(); + FactoryCompiler.GetEdgeFactory>(); + FactoryCompiler.GetEdgeFactory>(); + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/FactoryCompilerTest.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/FactoryCompilerTest.cs.meta new file mode 100644 index 0000000..1175891 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/FactoryCompilerTest.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 95df7ab65041244e781800ffaef1f019 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/GraphConsoleSerializer.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/GraphConsoleSerializer.cs new file mode 100755 index 0000000..d369b54 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/GraphConsoleSerializer.cs @@ -0,0 +1,16 @@ +using System; + +namespace QuickGraph +{ + public static class GraphConsoleSerializer + { + public static void DisplayGraph(IVertexListGraph g) + where Edge : IEdge + { + Console.WriteLine("{0} vertices", g.VertexCount); + foreach(Vertex v in g.Vertices) + foreach (Edge edge in g.OutEdges(v)) + Console.WriteLine("\t{0}", edge); + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/GraphConsoleSerializer.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/GraphConsoleSerializer.cs.meta new file mode 100644 index 0000000..8a8f19a --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/GraphConsoleSerializer.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 10397b63e092142468112091ef268087 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/GraphFactory.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/GraphFactory.cs new file mode 100755 index 0000000..420f137 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/GraphFactory.cs @@ -0,0 +1,195 @@ +using System; +using System.Collections.Generic; +using QuickGraph.Unit; + +namespace QuickGraph +{ + public static class GraphFactory + { + public static void NoEdges(IMutableVertexAndEdgeListGraph> g) + { + string x = "x"; g.AddVertex(x); + string y = "y"; g.AddVertex(y); + string z = "z"; g.AddVertex(z); + } + + public static void Loop(IMutableVertexAndEdgeListGraph> g) + { + string x = "x"; g.AddVertex(x); + string y = "y"; g.AddVertex(y); + string z = "z"; g.AddVertex(z); + + g.AddEdge(new Edge(x, y)); + g.AddEdge(new Edge(y, z)); + g.AddEdge(new Edge(z, x)); + } + + public static void LoopDouble(IMutableVertexAndEdgeListGraph> g) + { + string x = "x"; g.AddVertex(x); + string y = "y"; g.AddVertex(y); + string z = "z"; g.AddVertex(z); + + g.AddEdge(new Edge(x, y)); + g.AddEdge(new Edge(y, z)); + g.AddEdge(new Edge(z, x)); + g.AddEdge(new Edge(x, z)); + } + + + public static void UnBalancedFlow(IMutableVertexAndEdgeListGraph> g) + { + string x = "x"; g.AddVertex(x); + string y = "y"; g.AddVertex(y); + string z = "z"; g.AddVertex(z); + string w = "w"; g.AddVertex(w); + + g.AddEdge(new Edge(x, y)); + g.AddEdge(new Edge(x, z)); + g.AddEdge(new Edge(y, z)); + g.AddEdge(new Edge(x, w)); + g.AddEdge(new Edge(w, y)); + g.AddEdge(new Edge(w, z)); + } + + public static void Simple(IMutableVertexAndEdgeListGraph> g) + { + string x = "x"; g.AddVertex(x); + string y = "y"; g.AddVertex(y); + string z = "z"; g.AddVertex(z); + string w = "w"; g.AddVertex(w); + string u = "u"; g.AddVertex(u); + string v = "v"; g.AddVertex(v); + + g.AddEdge(new Edge(u, x)); + g.AddEdge(new Edge(u, v)); + g.AddEdge(new Edge(w, z)); + g.AddEdge(new Edge(w, y)); + g.AddEdge(new Edge(w, u)); + g.AddEdge(new Edge(x, v)); + g.AddEdge(new Edge(v, y)); + g.AddEdge(new Edge(y, x)); + g.AddEdge(new Edge(z, y)); + } + + public static void FileDependency(IMutableVertexAndEdgeListGraph> g) + { + // adding files and storing names + string zig_cpp = "zip.cpp"; g.AddVertex(zig_cpp); + string boz_h = "boz.h"; g.AddVertex(boz_h); + string zag_cpp = "zag.cpp"; g.AddVertex(zag_cpp); + string yow_h = "yow.h"; g.AddVertex(yow_h); + string dax_h = "dax.h"; g.AddVertex(dax_h); + string bar_cpp = "bar.cpp"; g.AddVertex(bar_cpp); + string zow_h = "zow.h"; g.AddVertex(zow_h); + string foo_cpp = "foo.cpp"; g.AddVertex(foo_cpp); + + string zig_o = "zig.o"; g.AddVertex(zig_o); + string zag_o = "zago"; g.AddVertex(zag_o); + string bar_o = "bar.o"; g.AddVertex(bar_o); + string foo_o = "foo.o"; g.AddVertex(foo_o); + string libzigzag_a = "libzigzig.a"; g.AddVertex(libzigzag_a); + string libfoobar_a = "libfoobar.a"; g.AddVertex(libfoobar_a); + + string killerapp = "killerapp.exe"; g.AddVertex(killerapp); + + // adding dependencies + g.AddEdge(new Edge(dax_h, foo_cpp)); + g.AddEdge(new Edge(dax_h, bar_cpp)); + g.AddEdge(new Edge(dax_h, yow_h)); + g.AddEdge(new Edge(yow_h, bar_cpp)); + g.AddEdge(new Edge(yow_h, zag_cpp)); + g.AddEdge(new Edge(boz_h, bar_cpp)); + g.AddEdge(new Edge(boz_h, zig_cpp)); + g.AddEdge(new Edge(boz_h, zag_cpp)); + g.AddEdge(new Edge(zow_h, foo_cpp)); + g.AddEdge(new Edge(foo_cpp, foo_o)); + g.AddEdge(new Edge(foo_o, libfoobar_a)); + g.AddEdge(new Edge(bar_cpp, bar_o)); + g.AddEdge(new Edge(bar_o, libfoobar_a)); + g.AddEdge(new Edge(libfoobar_a, libzigzag_a)); + g.AddEdge(new Edge(zig_cpp, zig_o)); + g.AddEdge(new Edge(zig_o, libzigzag_a)); + g.AddEdge(new Edge(zag_cpp, zag_o)); + g.AddEdge(new Edge(zag_o, libzigzag_a)); + g.AddEdge(new Edge(libzigzag_a, killerapp)); + } + + public static void RegularLattice(int rows, int columns, IMutableVertexAndEdgeListGraph> g) + { + string[,] latice = new string[rows, columns]; + // adding vertices + for (int i = 0; i < rows; ++i) + { + for (int j = 0; j < columns; ++j) + { + latice[i, j] = String.Format("{0},{1}", i.ToString(), j.ToString()); + g.AddVertex(latice[i, j]); + } + } + + // adding edges + for (int i = 0; i < rows - 1; ++i) + { + for (int j = 0; j < columns - 1; ++j) + { + g.AddEdge(new Edge(latice[i, j], latice[i, j + 1])); + g.AddEdge(new Edge(latice[i, j + 1], latice[i, j])); + + g.AddEdge(new Edge(latice[i, j], latice[i + 1, j])); + g.AddEdge(new Edge(latice[i + 1, j], latice[i, j])); + } + } + + for (int j = 0; j < columns - 1; ++j) + { + g.AddEdge(new Edge(latice[rows - 1, j], latice[rows - 1, j + 1])); + g.AddEdge(new Edge(latice[rows - 1, j + 1], latice[rows - 1, j])); + } + + for (int i = 0; i < rows - 1; ++i) + { + g.AddEdge(new Edge(latice[i, columns - 1], latice[i + 1, columns - 1])); + g.AddEdge(new Edge(latice[i + 1, columns - 1], latice[i, columns - 1])); + } + } + + public static void Fsm(IMutableVertexAndEdgeListGraph> g) + { + string s0 = "S0"; g.AddVertex(s0); + string s1 = "S1"; g.AddVertex(s1); + string s2 = "S2"; g.AddVertex(s2); + string s3 = "S3"; g.AddVertex(s3); + string s4 = "S4"; g.AddVertex(s4); + string s5 = "S5"; g.AddVertex(s5); + + g.AddEdge(new NamedEdge(s0, s1,"StartCalc")); + + g.AddEdge(new NamedEdge(s1, s0,"StopCalc")); + g.AddEdge(new NamedEdge(s1, s1,"SelectStandard")); + g.AddEdge(new NamedEdge(s1, s1,"ClearDisplay")); + g.AddEdge(new NamedEdge(s1, s2,"SelectScientific")); + g.AddEdge(new NamedEdge(s1, s3,"EnterDecNumber")); + + g.AddEdge(new NamedEdge(s2, s1,"SelectStandard")); + g.AddEdge(new NamedEdge(s2, s2,"SelectScientific")); + g.AddEdge(new NamedEdge(s2, s2,"ClearDisplay")); + g.AddEdge(new NamedEdge(s2, s4,"EnterDecNumber")); + g.AddEdge(new NamedEdge(s2, s5,"StopCalc")); + + g.AddEdge(new NamedEdge(s3, s0,"StopCalc")); + g.AddEdge(new NamedEdge(s3, s1,"ClearDisplay")); + g.AddEdge(new NamedEdge(s3, s3,"SelectStandard")); + g.AddEdge(new NamedEdge(s3, s3,"EnterDecNumber")); + g.AddEdge(new NamedEdge(s3, s4,"SelectScientific")); + + g.AddEdge(new NamedEdge(s4, s2,"ClearDisplay")); + g.AddEdge(new NamedEdge(s4, s3,"SelectStandard")); + g.AddEdge(new NamedEdge(s4, s4,"SelectScientific")); + g.AddEdge(new NamedEdge(s4, s4,"EnterDecNumber")); + g.AddEdge(new NamedEdge(s4, s5,"StopCalc")); + + g.AddEdge(new NamedEdge(s5, s2, "StartCalc")); + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/GraphFactory.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/GraphFactory.cs.meta new file mode 100644 index 0000000..4035dba --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/GraphFactory.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 38d3356ba1343493998e21ff6a4804d2 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Heap.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Heap.meta new file mode 100644 index 0000000..73ad1ee --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Heap.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: af91c64d7e5d447c9aa4c727d22ca88f +folderAsset: yes +DefaultImporter: + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Heap/HeapTest.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Heap/HeapTest.cs new file mode 100755 index 0000000..6360cb8 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Heap/HeapTest.cs @@ -0,0 +1,52 @@ +using System; +using System.Collections.Generic; +using System.Text; +using QuickGraph.Unit; +using QuickGraph.Heap; + +namespace QuickGraph.Tests.Heap +{ + [TestFixture] + public partial class HeapTest + { + private GcTypeHeap LoadHeap() + { + GcTypeHeap heap = GcTypeHeap.Load(@"heap\gcheap.xml"); + return heap; + } + [Test] + public void Roots() + { + GcTypeHeap heap = this.LoadHeap(); + Console.WriteLine(heap.Roots); + } + + [Test] + public void Types() + { + GcTypeHeap heap = this.LoadHeap(); + Console.WriteLine(heap.Types); + } + + [Test] + public void Size() + { + GcTypeHeap heap = this.LoadHeap(); + Console.WriteLine(heap.Size); + } + + [Test] + public void Touching() + { + GcTypeHeap heap = this.LoadHeap(); + Console.WriteLine(heap.Touching("Byte").Types); + } + + [Test] + public void Merge() + { + GcTypeHeap heap = this.LoadHeap(); + Console.WriteLine(heap.Merge(1000).Types); + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Heap/HeapTest.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Heap/HeapTest.cs.meta new file mode 100644 index 0000000..974ddc4 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Heap/HeapTest.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 9dd3c2ad231bc414d99b076608699ec7 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Heap/gcheap.xml b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Heap/gcheap.xml new file mode 100755 index 0000000..d5eeca5 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Heap/gcheap.xml @@ -0,0 +1,207636 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Heap/gcheap.xml.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Heap/gcheap.xml.meta new file mode 100644 index 0000000..d518350 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Heap/gcheap.xml.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: 1852ccd845c7c437c95726bc9cb6735a +TextScriptImporter: + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/MutableVertexAndEdgeListGraphTest.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/MutableVertexAndEdgeListGraphTest.cs new file mode 100755 index 0000000..d20b065 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/MutableVertexAndEdgeListGraphTest.cs @@ -0,0 +1,98 @@ +using System; +using QuickGraph.Unit; +using Microsoft.Pex.Framework; + +namespace QuickGraph +{ + [TestFixture, PexClass(MaxRuns = 50)] + public partial class MutableVertexAndEdgeListGraphTest + { + [PexMethod] + public void AddVertexOnly([PexAssumeNotNull]IMutableVertexAndEdgeListGraph> g, string v) + { + int vertexCount = g.VertexCount; + g.AddVertex(v); + Assert.AreEqual(vertexCount + 1, g.VertexCount); + Assert.IsTrue(g.ContainsVertex(v)); + VerifyCounts(g); + } + + [PexMethod] + public void AddAndRemoveVertex([PexAssumeNotNull]IMutableVertexAndEdgeListGraph> g, int v) + { + int vertexCount = g.VertexCount; + g.AddVertex(v); + Assert.AreEqual(vertexCount + 1, g.VertexCount); + Assert.IsTrue(g.ContainsVertex(v)); + g.RemoveVertex(v); + Assert.AreEqual(vertexCount, g.VertexCount); + Assert.IsFalse(g.ContainsVertex(v)); + //VerifyCounts(g); + } + + [PexMethod] + public void AddVertexAddEdgesAndRemoveTargetVertex([PexAssumeNotNull]IMutableVertexAndEdgeListGraph> g, string v1, string v2) + { + int vertexCount = g.VertexCount; + int edgeCount = g.EdgeCount; + + g.AddVertex(v1); + g.AddVertex(v2); + Assert.AreEqual(vertexCount + 2, g.VertexCount); + Assert.IsTrue(g.ContainsVertex(v1)); + Assert.IsTrue(g.ContainsVertex(v2)); + + g.AddEdge(new Edge(v1, v2)); + Assert.AreEqual(edgeCount + 1, g.EdgeCount); + + g.RemoveVertex(v2); + Assert.AreEqual(vertexCount + 1, g.VertexCount); + Assert.AreEqual(edgeCount, g.EdgeCount); + Assert.IsTrue(g.ContainsVertex(v1)); + Assert.IsFalse(g.ContainsVertex(v2)); + VerifyCounts(g); + } + + [PexMethod] + public void AddVertexAddEdgesAndRemoveSourceVertex([PexAssumeNotNull]IMutableVertexAndEdgeListGraph> g, string v1, string v2) + { + int vertexCount = g.VertexCount; + int edgeCount = g.EdgeCount; + + g.AddVertex(v1); + g.AddVertex(v2); + Assert.AreEqual(vertexCount + 2, g.VertexCount); + Assert.IsTrue(g.ContainsVertex(v1)); + Assert.IsTrue(g.ContainsVertex(v2)); + + g.AddEdge(new Edge(v1, v2)); + Assert.AreEqual(edgeCount + 1, g.EdgeCount); + + g.RemoveVertex(v1); + Assert.AreEqual(vertexCount + 1, g.VertexCount); + Assert.AreEqual(edgeCount, g.EdgeCount); + Assert.IsTrue(g.ContainsVertex(v2)); + Assert.IsFalse(g.ContainsVertex(v1)); + VerifyCounts(g); + } + + private void VerifyCounts(IMutableVertexAndEdgeListGraph> g) + { + int i = 0; + foreach (string v in g.Vertices) + i++; + Assert.AreEqual(g.VertexCount, i); + + i = 0; + foreach (string v in g.Vertices) + foreach (Edge e in g.OutEdges(v)) + i++; + Assert.AreEqual(g.EdgeCount, i); + + i = 0; + foreach (Edge e in g.Edges) + i++; + Assert.AreEqual(g.EdgeCount, i); + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/MutableVertexAndEdgeListGraphTest.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/MutableVertexAndEdgeListGraphTest.cs.meta new file mode 100644 index 0000000..8af8f3b --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/MutableVertexAndEdgeListGraphTest.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: a2a4f25545c4f46859b6040a0e04cbb7 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Program.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Program.cs new file mode 100755 index 0000000..666589a --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Program.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Text; +using QuickGraph.Unit; + +namespace QuickGraph.Tests +{ + class Program + { + static int Main(string[] args) + { + return TestRunner.TestMain(args); + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Program.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Program.cs.meta new file mode 100644 index 0000000..7d123e5 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Program.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 286b7c6cd03ad4579a733ab5129f8a0a +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Properties.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Properties.meta new file mode 100644 index 0000000..629e13c --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Properties.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: 1e67a21160d9144fab61ff2cf7746e6c +folderAsset: yes +DefaultImporter: + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Properties/AssemblyInfo.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Properties/AssemblyInfo.cs new file mode 100755 index 0000000..3004289 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Properties/AssemblyInfo.cs @@ -0,0 +1,23 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("QuickGraph.Tests")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("MSIT")] +[assembly: AssemblyProduct("QuickGraph.Tests")] +[assembly: AssemblyCopyright("Copyright © MSIT 2007")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("54248720-0e2d-43de-a8e8-731ced0c15c2")] diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Properties/AssemblyInfo.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Properties/AssemblyInfo.cs.meta new file mode 100644 index 0000000..cf4f641 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Properties/AssemblyInfo.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 7c4576500da2540a5ab65e81c1269a0d +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Properties/PexAssemblyInfo.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Properties/PexAssemblyInfo.cs new file mode 100755 index 0000000..eda4e83 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Properties/PexAssemblyInfo.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Microsoft.Pex.Framework; +using Microsoft.Pex.Framework.Instrumentation; +using Microsoft.Pex.Framework.Settings; +using Microsoft.Pex.Framework.Focus; +using Microsoft.Pex.Framework.Validation; +using QuickGraph.Unit.Pex; + +[assembly: PexAssemblyUnderTest(typeof(QuickGraph.GraphColor))] +[assembly: QuickGraphPackage] +[assembly: PexAssemblySettings( + TestFramework = "QuickGraph")] +[assembly: PexAllowedExceptionFromAssembly( + typeof(ArgumentException), + "QuickGraph", + AcceptExceptionSubtypes = true)] diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Properties/PexAssemblyInfo.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Properties/PexAssemblyInfo.cs.meta new file mode 100644 index 0000000..f65fdc6 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Properties/PexAssemblyInfo.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b29aa903a15a54bee846d1c3cff672fd +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/QuickGraph.Tests.csproj b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/QuickGraph.Tests.csproj new file mode 100755 index 0000000..19e1e1f --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/QuickGraph.Tests.csproj @@ -0,0 +1,193 @@ + + + Debug + AnyCPU + 9.0.30729 + 2.0 + {61DF76E1-DE2B-4DF1-AD5F-89939AB06693} + Exe + Properties + QuickGraph.Tests + QuickGraph.Tests + SAK + SAK + SAK + SAK + + + 2.0 + + + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + Off + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + Off + + + + False + + + + + + + + + Properties\version.cs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + BinaryHeapTest.cs + + + BinaryHeapTest.cs + + + BinaryHeapTest.cs + + + BinaryHeapTest.cs + + + BinaryHeapTest.cs + + + BinaryHeapTest.cs + + + BinaryHeapTest.cs + + + BinaryHeapTest.cs + + + BinaryHeapTest.cs + + + BinaryHeapTest.cs + + + BinaryHeapTest.cs + + + BinaryHeapTest.cs + + + BinaryHeapTest.cs + + + BinaryHeapTest.cs + + + BinaryHeapTest.cs + + + BinaryHeapTest.cs + + + + + + + + + + + + + + + + + + + + + + + {960C14D1-EDBD-40E5-8AE6-25E311551B87} + QuickGraph.Data + + + {ACDD0973-E5D9-4C2B-9EAF-B5B5DF44EDDD} + QuickGraph.Glee + + + {595D6322-637A-4A36-97F1-D53F3F9ECEA7} + QuickGraph.Graphviz + + + {2DEC7C6E-68DF-47EC-A75E-2C1238986B8E} + QuickGraph.Heap + + + {9FF2B839-743F-4A15-9D33-F11253BF6AE1} + QuickGraph.Unit + + + {A9A5C115-0680-44B3-A87E-5ECF4C93814E} + QuickGraph + + + + + Always + + + + + + + + \ No newline at end of file diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/QuickGraph.Tests.csproj.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/QuickGraph.Tests.csproj.meta new file mode 100644 index 0000000..dc15234 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/QuickGraph.Tests.csproj.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: eda10f293cb574ac690eac844d648b5b +DefaultImporter: + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/QuickGraph.Tests.csproj.vspscc b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/QuickGraph.Tests.csproj.vspscc new file mode 100755 index 0000000..feffdec --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/QuickGraph.Tests.csproj.vspscc @@ -0,0 +1,10 @@ +"" +{ +"FILE_VERSION" = "9237" +"ENLISTMENT_CHOICE" = "NEVER" +"PROJECT_FILE_RELATIVE_PATH" = "" +"NUMBER_OF_EXCLUDED_FILES" = "0" +"ORIGINAL_PROJECT_FILE_PATH" = "" +"NUMBER_OF_NESTED_PROJECTS" = "0" +"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROVIDER" +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/QuickGraph.Tests.csproj.vspscc.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/QuickGraph.Tests.csproj.vspscc.meta new file mode 100644 index 0000000..7fc03d3 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/QuickGraph.Tests.csproj.vspscc.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: f6ece3fda440440ec83ec13db4a3644d +DefaultImporter: + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Regression.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Regression.meta new file mode 100644 index 0000000..5e7a1e5 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Regression.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: 960b63c3b7c9f4809a526d48b942ee44 +folderAsset: yes +DefaultImporter: + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Regression/DijkstraTest.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Regression/DijkstraTest.cs new file mode 100755 index 0000000..8d77a49 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Regression/DijkstraTest.cs @@ -0,0 +1,127 @@ +using System; +using System.Collections.Generic; +using System.Text; +using QuickGraph.Unit; +using QuickGraph.Algorithms.ShortestPath; +using QuickGraph.Algorithms.Observers; +using QuickGraph.Algorithms; + +namespace QuickGraph.Tests.Regression { + [TestFixture] + class DijkstraTest { + [Test] + public void Scenario() { + AdjacencyGraph> graph = new AdjacencyGraph>(true); + + // Add some vertices to the graph + graph.AddVertex("A"); + graph.AddVertex("B"); + graph.AddVertex("C"); + graph.AddVertex("D"); + graph.AddVertex("E"); + graph.AddVertex("F"); + graph.AddVertex("G"); + graph.AddVertex("H"); + graph.AddVertex("I"); + graph.AddVertex("J"); + + // Create the edges + Edge a_b = new Edge("A", "B"); + Edge a_d = new Edge("A", "D"); + Edge b_a = new Edge("B", "A"); + Edge b_c = new Edge("B", "C"); + Edge b_e = new Edge("B", "E"); + Edge c_b = new Edge("C", "B"); + Edge c_f = new Edge("C", "F"); + Edge c_j = new Edge("C", "J"); + Edge d_e = new Edge("D", "E"); + Edge d_g = new Edge("D", "G"); + Edge e_d = new Edge("E", "D"); + Edge e_f = new Edge("E", "F"); + Edge e_h = new Edge("E", "H"); + Edge f_i = new Edge("F", "I"); + Edge f_j = new Edge("F", "J"); + Edge g_d = new Edge("G", "D"); + Edge g_h = new Edge("G", "H"); + Edge h_g = new Edge("H", "G"); + Edge h_i = new Edge("H", "I"); + Edge i_f = new Edge("I", "F"); + Edge i_j = new Edge("I", "J"); + Edge i_h = new Edge("I", "H"); + Edge j_f = new Edge("J", "F"); + + // Add the edges + graph.AddEdge(a_b); + graph.AddEdge(a_d); + graph.AddEdge(b_a); + graph.AddEdge(b_c); + graph.AddEdge(b_e); + graph.AddEdge(c_b); + graph.AddEdge(c_f); + graph.AddEdge(c_j); + graph.AddEdge(d_e); + graph.AddEdge(d_g); + graph.AddEdge(e_d); + graph.AddEdge(e_f); + graph.AddEdge(e_h); + graph.AddEdge(f_i); + graph.AddEdge(f_j); + graph.AddEdge(g_d); + graph.AddEdge(g_h); + graph.AddEdge(h_g); + graph.AddEdge(h_i); + graph.AddEdge(i_f); + graph.AddEdge(i_h); + graph.AddEdge(i_j); + graph.AddEdge(j_f); + + // Define some weights to the edges + Dictionary, double> edgeCost = new Dictionary, double>(graph.EdgeCount); + edgeCost.Add(a_b, 4); + edgeCost.Add(a_d, 1); + edgeCost.Add(b_a, 74); + edgeCost.Add(b_c, 2); + edgeCost.Add(b_e, 12); + edgeCost.Add(c_b, 12); + edgeCost.Add(c_f, 74); + edgeCost.Add(c_j, 12); + edgeCost.Add(d_e, 32); + edgeCost.Add(d_g, 22); + edgeCost.Add(e_d, 66); + edgeCost.Add(e_f, 76); + edgeCost.Add(e_h, 33); + edgeCost.Add(f_i, 11); + edgeCost.Add(f_j, 21); + edgeCost.Add(g_d, 12); + edgeCost.Add(g_h, 10); + edgeCost.Add(h_g, 2); + edgeCost.Add(h_i, 72); + edgeCost.Add(i_f, 31); + edgeCost.Add(i_h, 18); + edgeCost.Add(i_j, 7); + edgeCost.Add(j_f, 8); + + // We want to use Dijkstra on this graph + DijkstraShortestPathAlgorithm> dijkstra = new DijkstraShortestPathAlgorithm>(graph, edgeCost); + + // Attach a Vertex Predecessor Recorder Observer to give us the paths + VertexPredecessorRecorderObserver> predecessorObserver = new VertexPredecessorRecorderObserver>(); + using (ObserverScope.Create>>(dijkstra, predecessorObserver)) { + // Run the algorithm with A set to be the source + dijkstra.Compute("A"); + } + + foreach (KeyValuePair> kvp in predecessorObserver.VertexPredecessors) + Console.WriteLine("If you want to get to {0} you have to enter through the in edge {1}", kvp.Key, kvp.Value); + + foreach (string v in graph.Vertices) { + double distance = AlgoUtility.ComputePredecessorCost( + predecessorObserver.VertexPredecessors, + edgeCost, + v); + Console.WriteLine("A -> {0}: {1}", v, distance); + } + + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Regression/DijkstraTest.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Regression/DijkstraTest.cs.meta new file mode 100644 index 0000000..70cc20b --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Regression/DijkstraTest.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 026e3dd6bc59a4ce59216c99d4697b2e +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/ReversedBidirectionalGraphTest.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/ReversedBidirectionalGraphTest.cs new file mode 100755 index 0000000..59304f2 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/ReversedBidirectionalGraphTest.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Text; +using QuickGraph.Unit; + +namespace QuickGraph.Tests +{ + [TestFixture] + public class ReversedBidirectionalGraphTest + { + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/ReversedBidirectionalGraphTest.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/ReversedBidirectionalGraphTest.cs.meta new file mode 100644 index 0000000..c2a7e99 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/ReversedBidirectionalGraphTest.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 1c9c8b9112e0a448c905c78af1507a97 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Serialization.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Serialization.meta new file mode 100644 index 0000000..2d2bfe8 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Serialization.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: 26cae03a50b33430ba27c6f0fc8eb688 +folderAsset: yes +DefaultImporter: + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Serialization/GraphMLSerializerTest.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Serialization/GraphMLSerializerTest.cs new file mode 100755 index 0000000..70c68e1 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Serialization/GraphMLSerializerTest.cs @@ -0,0 +1,63 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Xml; +using QuickGraph.Unit; +using Microsoft.Pex.Framework; + +namespace QuickGraph.Serialization +{ + [TestFixture, PexClass] + public partial class GraphMLSerializerTest + { + [Test, PexMethod] + public void RoundTrip() + { + RoundTripGraph(new AdjacencyGraphFactory().SimpleIdentifiable()); + } + + [PexMethod] + public void RoundTripGraph([PexAssumeNotNull]IMutableVertexAndEdgeListGraph g) + { + GraphMLSerializer serializer = new GraphMLSerializer(); + AdjacencyGraph gd = new AdjacencyGraph(); + string baseLine; + string output; + + using (StringWriter writer = new StringWriter()) + { + serializer.Serialize(writer, g); + baseLine = writer.ToString(); + TestConsole.WriteLineBold("Original graph:"); + Console.WriteLine(writer.ToString()); + TestConsole.WriteLineBold("---"); + + using (XmlTextReader reader = new XmlTextReader(new StringReader(writer.ToString()))) + { + serializer.Deserialize( + reader, + gd, + new NamedVertex.Factory(), + new NamedEdge.Factory() + ); + } + } + + TestConsole.WriteLineBold("Roundtripped graph:"); + using (StringWriter sw = new StringWriter()) + { + serializer.Serialize(sw, gd); + output = sw.ToString(); + Console.WriteLine(sw.ToString()); + } + + Assert.AreEqual(g.VertexCount, gd.VertexCount); + Assert.AreEqual(g.EdgeCount, gd.EdgeCount); + StringAssert.AreEqual( + baseLine, + output, + StringComparison.InvariantCulture + ); + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Serialization/GraphMLSerializerTest.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Serialization/GraphMLSerializerTest.cs.meta new file mode 100644 index 0000000..effd4d2 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Serialization/GraphMLSerializerTest.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 5a3862419fe224549949445675ceaeb7 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Serialization/GraphMLSerializerWithArgumentsTest.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Serialization/GraphMLSerializerWithArgumentsTest.cs new file mode 100755 index 0000000..e73ce03 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Serialization/GraphMLSerializerWithArgumentsTest.cs @@ -0,0 +1,237 @@ +using System; +using System.Collections.Generic; +using System.Xml.Serialization; +using System.IO; +using System.Xml; +using QuickGraph.Unit; +using Microsoft.Pex.Framework; + +namespace QuickGraph.Serialization +{ + [TestFixture, PexClass] + public partial class GraphMLSerializerWithArgumentsTest + { + public sealed class TestVertex : IIdentifiable + { + private string id; + private string _string; + private int _int; + private long _long; + private float _float; + private double _double; + private bool _bool; + private object _object; + + public TestVertex( + string id, + string _string, + int _int, + long _long, + double _double, + float _float, + bool _bool, + object _object) + { + this.id = id; + this._string = _string; + this._int = _int; + this._long = _long; + this._float = _float; + this._double = _double; + this._bool = _bool; + this._object = _object; + } + + public string ID + { + get { return this.id; } + } + + [XmlAttribute("string")] + public string String + { + get { return this._string; } + } + [XmlAttribute("int")] + public int Int + { + get { return this._int; } + } + [XmlAttribute("long")] + public long Long + { + get { return this._long; } + } + [XmlAttribute("float")] + public float Float + { + get { return this._float; } + } + [XmlAttribute("double")] + public double Double + { + get { return this._double; } + } + [XmlAttribute("object")] + public object Object + { + get { return this._object; } + } + } + + public sealed class TestEdge : Edge, IIdentifiable + { + private string id; + private string _string; + private int _int; + private long _long; + private float _float; + private double _double; + private bool _bool; + private object _object; + + public TestEdge( + TestVertex source, + TestVertex target, + string id, + string _string, + int _int, + long _long, + double _double, + float _float, + bool _bool, + object _object) + : base(source, target) + { + this.id = id; + this._string = _string; + this._int = _int; + this._long = _long; + this._float = _float; + this._double = _double; + this._bool = _bool; + this._object = _object; + } + + public string ID + { + get { return this.id; } + } + + [XmlAttribute("string")] + public string String + { + get { return this._string; } + } + [XmlAttribute("int")] + public int Int + { + get { return this._int; } + } + [XmlAttribute("long")] + public long Long + { + get { return this._long; } + } + [XmlAttribute("float")] + public float Float + { + get { return this._float; } + } + [XmlAttribute("double")] + public double Double + { + get { return this._double; } + } + [XmlAttribute("object")] + public object Object + { + get { return this._object; } + } + } + + public sealed class TestAdjacencyGraph : AdjacencyGraph + { } + + [Test] + [Repeat(2)] + public void WriteVertex() + { + TestAdjacencyGraph g = new TestAdjacencyGraph(); + TestVertex v = new TestVertex( + "v1", + "string", + 1, + 2, + 3.0, + 4.0F, + true, + new Dummy() + ); + + g.AddVertex(v); + VerifySerialization(g); + } + + private void VerifySerialization(TestAdjacencyGraph g) + { + GraphMLSerializer serializer = new GraphMLSerializer(); + + using (StringWriter writer = new StringWriter()) + { + serializer.Serialize(writer, g); + String xml = writer.ToString(); + Console.WriteLine(xml); + XmlAssert.IsWellFormedXml(xml); + } + } + + [Test] + [Repeat(2)] + public void WriteEdge() + { + { + TestAdjacencyGraph g = new TestAdjacencyGraph(); + TestVertex v1 = new TestVertex( + "v1", + "string", + 1, + 2, + 3.0, + 4.0F, + true, + new Dummy() + ); + TestVertex v2 = new TestVertex( + "v2", + "string2", + 5, + 6, + 7.0, + 8.0F, + true, + new Dummy() + ); + + g.AddVertex(v1); + g.AddVertex(v2); + + TestEdge edge = new TestEdge( + v1,v2, + "e1", + "string", + 9, + 10, + 11.0, + 12.0F, + true, + new Dummy() + ); + g.AddEdge(edge); + VerifySerialization(g); + } + } + + public class Dummy { } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Serialization/GraphMLSerializerWithArgumentsTest.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Serialization/GraphMLSerializerWithArgumentsTest.cs.meta new file mode 100644 index 0000000..c0bbe0a --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/Serialization/GraphMLSerializerWithArgumentsTest.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 85c757df60dd2462f8e9b15ddb95ca70 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/UndirectedGraphFactory.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/UndirectedGraphFactory.cs new file mode 100755 index 0000000..a4808ab --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/UndirectedGraphFactory.cs @@ -0,0 +1,72 @@ +using System; +using QuickGraph.Unit; + +namespace QuickGraph +{ + public sealed class UndirectedGraphFactory + { + private static UndirectedGraph> CreateGraph() + { + return new UndirectedGraph>(false); + } + + [Factory] + public UndirectedGraph> Empty() + { + return CreateGraph(); + } + + [Factory] + public UndirectedGraph> NoEdges() + { + UndirectedGraph> g = CreateGraph(); + g.AddVertex("x"); + g.AddVertex("y"); + g.AddVertex("z"); + return g; + } + + [Factory] + public UndirectedGraph> Loop() + { + UndirectedGraph> g = CreateGraph(); + g.AddVertex("x"); + g.AddVertex("y"); + g.AddVertex("z"); + g.AddEdge(new Edge("x", "y")); + g.AddEdge(new Edge("y", "z")); + g.AddEdge(new Edge("z", "x")); + return g; + } + + [Factory] + public UndirectedGraph> LoopDouble() + { + UndirectedGraph> g = CreateGraph(); + g.AddVertex("x"); + g.AddVertex("y"); + g.AddVertex("z"); + + g.AddEdge(new Edge("x", "y")); + g.AddEdge(new Edge("y", "z")); + g.AddEdge(new Edge("z", "x")); + + g.AddEdge(new Edge("x", "y")); + g.AddEdge(new Edge("y", "z")); + g.AddEdge(new Edge("z", "x")); + return g; + } + + [Factory] + public UndirectedGraph> Simple() + { + UndirectedGraph> g = CreateGraph(); + g.AddVertex("x"); + g.AddVertex("y"); + g.AddVertex("z"); + g.AddEdge(new Edge("x", "y")); + g.AddEdge(new Edge("y", "z")); + return g; + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/UndirectedGraphFactory.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/UndirectedGraphFactory.cs.meta new file mode 100644 index 0000000..caa30fb --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/UndirectedGraphFactory.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 3d619fee2f2734c289385943df4a07ef +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/UndirectedGraphInvariant.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/UndirectedGraphInvariant.cs new file mode 100755 index 0000000..c3baf51 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/UndirectedGraphInvariant.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using QuickGraph.Unit; +using Microsoft.Pex.Framework; + +namespace QuickGraph +{ + [TestFixture, PexClass] + public partial class UndirectedGraphTest where E : IEdge + { + [PexMethod] + public static void IsAdjacentEdgesEmpty([PexAssumeUnderTest]IUndirectedGraph g) + { + foreach (T v in g.Vertices) + { + Assert.AreEqual( + g.IsAdjacentEdgesEmpty(v), + g.AdjacentDegree(v) == 0); + } + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/UndirectedGraphInvariant.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/UndirectedGraphInvariant.cs.meta new file mode 100644 index 0000000..c676db5 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/UndirectedGraphInvariant.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ad243900acf95458e9802ea3facf3e71 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/VertexListGraphInvariant.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/VertexListGraphInvariant.cs new file mode 100755 index 0000000..47522b3 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/VertexListGraphInvariant.cs @@ -0,0 +1,20 @@ +using System; +using QuickGraph.Unit; +using Microsoft.Pex.Framework; + +namespace QuickGraph +{ + [TestFixture, PexClass] + public static class VertexListGraphTest + where E : IEdge + { + [PexMethod] + public static void Iteration([PexAssumeUnderTest]IVertexListGraph g) + { + int i = 0; + foreach (T v in PexSymbolicValue.IgnoreEnumeration(g.Vertices)) + ++i; + Assert.AreEqual(g.VertexCount, i); + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/VertexListGraphInvariant.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/VertexListGraphInvariant.cs.meta new file mode 100644 index 0000000..9c85b65 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/VertexListGraphInvariant.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 660c88f2c292e4d33ba1c5b3300bd52d +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/testframework.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/testframework.cs new file mode 100755 index 0000000..5d34d37 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/testframework.cs @@ -0,0 +1,2055 @@ +#if PEX_NOT_AVAILABLE +namespace Microsoft.Pex.Framework +{ + + + [System.AttributeUsageAttribute(System.AttributeTargets.Method, AllowMultiple = false, Inherited = true)] + public class PexSequenceTestAttribute : System.Attribute + { + + public bool IgnoreFieldAccesses; + + public bool IgnoreStates; + + public bool IgnoreWeight; + + public bool MatchUncoveredBranches; + + public int MaxSuggestions; + + public string Categories; + + public int MaxBranches; + + public int MaxRounds; + + public int MaxRuns; + + public int MaxRunsWithUniqueBranchHits; + + public int MaxRunsWithUniquePaths; + + public int MaxCalls; + + public int MaxConditions; + + public int MaxBranchHits; + + public int MaxExceptions; + + public int ConstraintSolverTimeout; + + public int Timeout; + + public string CoverageFileFormat; + + public string TouchMyCode; + + public string TestClassName; + + public bool TestExcludeNonTermination; + + public bool TestDisableNonTermination; + + public Microsoft.Pex.Framework.PexTestEmissionFilter TestEmissionFilter; + + public bool PruneExceptions; + + public bool Joins; + + public bool NoSoftSubstitutions; + + public bool SymbolicCalls; + + public Microsoft.Pex.Framework.Strategies.PexSearchFrontier SearchFrontier; + + public string CustomSolver; + + public Microsoft.Pex.Framework.Strategies.PexCoverageGoal CoverageGoal; + + public string CssProjectStructure; + + public string CssIteration; + + public bool ContainsSettings; + + public System.Collections.Generic.IEnumerable ActiveSettings; + + public object TypeId; + + static PexSequenceTestAttribute() + { + } + } + + [System.AttributeUsageAttribute(((System.AttributeTargets.Assembly | System.AttributeTargets.Class) + | System.AttributeTargets.Method), AllowMultiple = true, Inherited = true)] + public class PexCreatableByMethodAndSettersAttribute : System.Attribute + { + + public Microsoft.ExtendedReflection.Metadata.TypeEx CreatableType; + + public object TypeId; + + static PexCreatableByMethodAndSettersAttribute() + { + } + + static PexCreatableByMethodAndSettersAttribute() + { + } + } + + [System.AttributeUsageAttribute(((System.AttributeTargets.Assembly | System.AttributeTargets.Class) + | System.AttributeTargets.Method), AllowMultiple = true, Inherited = true)] + public class PexCreatableByConstructorAndSettersAttribute : System.Attribute + { + + public Microsoft.ExtendedReflection.Metadata.TypeEx CreatableType; + + public object TypeId; + + static PexCreatableByConstructorAndSettersAttribute() + { + } + } + + [System.AttributeUsageAttribute(((System.AttributeTargets.Assembly | System.AttributeTargets.Class) + | System.AttributeTargets.Method), AllowMultiple = true, Inherited = true)] + public class PexCreatableAsWebDataAttribute : System.Attribute + { + + public Microsoft.ExtendedReflection.Metadata.TypeEx CreatableType; + + public object TypeId; + + static PexCreatableAsWebDataAttribute() + { + } + } + + [System.AttributeUsageAttribute(System.AttributeTargets.Method, AllowMultiple = true, Inherited = true)] + public class PexUseGenericArgumentsAttribute : System.Attribute + { + + public object TypeId; + + static PexUseGenericArgumentsAttribute() + { + } + } + + [System.AttributeUsageAttribute(System.AttributeTargets.Method, AllowMultiple = false, Inherited = true)] + public class PexTestAttribute : System.Attribute + { + + public string Categories; + + public int MaxBranches; + + public int MaxRounds; + + public int MaxRuns; + + public int MaxRunsWithUniqueBranchHits; + + public int MaxRunsWithUniquePaths; + + public int MaxCalls; + + public int MaxConditions; + + public int MaxBranchHits; + + public int MaxExceptions; + + public int ConstraintSolverTimeout; + + public int Timeout; + + public string CoverageFileFormat; + + public string TouchMyCode; + + public string TestClassName; + + public bool TestExcludeNonTermination; + + public bool TestDisableNonTermination; + + public Microsoft.Pex.Framework.PexTestEmissionFilter TestEmissionFilter; + + public bool PruneExceptions; + + public bool Joins; + + public bool NoSoftSubstitutions; + + public bool SymbolicCalls; + + public Microsoft.Pex.Framework.Strategies.PexSearchFrontier SearchFrontier; + + public string CustomSolver; + + public Microsoft.Pex.Framework.Strategies.PexCoverageGoal CoverageGoal; + + public string CssProjectStructure; + + public string CssIteration; + + public bool ContainsSettings; + + public System.Collections.Generic.IEnumerable ActiveSettings; + + public object TypeId; + + static PexTestAttribute() + { + } + } + + [System.AttributeUsageAttribute(((System.AttributeTargets.Assembly | System.AttributeTargets.Class) + | System.AttributeTargets.Method), AllowMultiple = true, Inherited = true)] + public class PexWorkItemAttribute : System.Attribute + { + + public int Id; + + public object TypeId; + + static PexWorkItemAttribute() + { + } + } + + [System.AttributeUsageAttribute((System.AttributeTargets.Class | System.AttributeTargets.Method), AllowMultiple = false, Inherited = true)] + public class PexIgnoreAttribute : System.Attribute + { + + public string Message; + + public int WorkItemId; + + public object TypeId; + + static PexIgnoreAttribute() + { + } + } + + [System.AttributeUsageAttribute(System.AttributeTargets.Method, AllowMultiple = false, Inherited = true)] + public class PexFactoryAttribute : System.Attribute + { + + public Microsoft.ExtendedReflection.Metadata.TypeEx FactoredType; + + public object TypeId; + + static PexFactoryAttribute() + { + } + + static PexFactoryAttribute() + { + } + } + + [System.AttributeUsageAttribute(((System.AttributeTargets.Assembly | System.AttributeTargets.Class) + | System.AttributeTargets.Method), AllowMultiple = true, Inherited = true)] + public class PexExpectedCoverageAttribute : System.Attribute + { + + public double ExpectedCoverage; + + public Microsoft.Pex.Framework.PexExpectedCoverageAttribute.CoverageOperator Operator; + + public Microsoft.Pex.Framework.PexCoverageUnit Unit; + + public bool DebugOnly; + + public bool ReleaseOnly; + + public object TypeId; + + static PexExpectedCoverageAttribute() + { + } + } + + [System.AttributeUsageAttribute(((System.AttributeTargets.Assembly | System.AttributeTargets.Class) + | System.AttributeTargets.Method), AllowMultiple = true, Inherited = true)] + public class PexFocusOnAssemblyAttribute : System.Attribute + { + + public Microsoft.Pex.Framework.PexSearchPriority SearchPriority; + + public bool DoNotReportCoverage; + + public object TypeId; + + static PexFocusOnAssemblyAttribute() + { + } + + static PexFocusOnAssemblyAttribute() + { + } + } + + [System.AttributeUsageAttribute(((((((((((((((System.AttributeTargets.Assembly | System.AttributeTargets.Module) + | System.AttributeTargets.Class) + | System.AttributeTargets.Struct) + | System.AttributeTargets.Enum) + | System.AttributeTargets.Constructor) + | System.AttributeTargets.Method) + | System.AttributeTargets.Property) + | System.AttributeTargets.Field) + | System.AttributeTargets.Event) + | System.AttributeTargets.Interface) + | System.AttributeTargets.Parameter) + | System.AttributeTargets.Delegate) + | System.AttributeTargets.ReturnValue) + | System.AttributeTargets.GenericParameter), AllowMultiple = false, Inherited = true)] + public class PexCrossProductExplorableStrategyAttribute : System.Attribute + { + + public object TypeId; + + static PexCrossProductExplorableStrategyAttribute() + { + } + } + + [System.AttributeUsageAttribute((((System.AttributeTargets.Assembly | System.AttributeTargets.Class) + | System.AttributeTargets.Method) + | System.AttributeTargets.Parameter), AllowMultiple = true, Inherited = true)] + public class PexUseValuesAttribute : System.Attribute + { + + public object TypeId; + + static PexUseValuesAttribute() + { + } + + static PexUseValuesAttribute() + { + } + + static PexUseValuesAttribute() + { + } + } + + [System.AttributeUsageAttribute(((System.AttributeTargets.Assembly | System.AttributeTargets.Class) + | System.AttributeTargets.Method), AllowMultiple = true, Inherited = true)] + public class PexCreatableByMethodAttribute : System.Attribute + { + + public Microsoft.ExtendedReflection.Metadata.TypeEx CreatableType; + + public object TypeId; + + static PexCreatableByMethodAttribute() + { + } + + static PexCreatableByMethodAttribute() + { + } + } + + [System.AttributeUsageAttribute(((((((((((((((System.AttributeTargets.Assembly | System.AttributeTargets.Module) + | System.AttributeTargets.Class) + | System.AttributeTargets.Struct) + | System.AttributeTargets.Enum) + | System.AttributeTargets.Constructor) + | System.AttributeTargets.Method) + | System.AttributeTargets.Property) + | System.AttributeTargets.Field) + | System.AttributeTargets.Event) + | System.AttributeTargets.Interface) + | System.AttributeTargets.Parameter) + | System.AttributeTargets.Delegate) + | System.AttributeTargets.ReturnValue) + | System.AttributeTargets.GenericParameter), AllowMultiple = true, Inherited = true)] + public class PexAssumeIsNotSharedAttribute : System.Attribute + { + + public object TypeId; + + static PexAssumeIsNotSharedAttribute() + { + } + + static PexAssumeIsNotSharedAttribute() + { + } + + static PexAssumeIsNotSharedAttribute() + { + } + } + + [System.AttributeUsageAttribute(((System.AttributeTargets.Assembly | System.AttributeTargets.Class) + | System.AttributeTargets.Method), AllowMultiple = true, Inherited = true)] + public class PexFocusOnNamespaceAttribute : System.Attribute + { + + public string NamespacePrefix; + + public bool Strict; + + public Microsoft.Pex.Framework.PexSearchPriority SearchPriority; + + public bool DoNotReportCoverage; + + public object TypeId; + + static PexFocusOnNamespaceAttribute() + { + } + } + + [System.AttributeUsageAttribute(System.AttributeTargets.Assembly, AllowMultiple = true, Inherited = true)] + public class PexInvariantAssemblyAttribute : System.Attribute + { + + public System.Reflection.AssemblyName TargetAssembly; + + public Microsoft.ExtendedReflection.Metadata.TypeEx InvariantClassAttributeType; + + public Microsoft.ExtendedReflection.Metadata.TypeEx InvariantMethodAttributeType; + + public Microsoft.ExtendedReflection.Metadata.TypeEx ValidationType; + + public object TypeId; + + static PexInvariantAssemblyAttribute() + { + } + + static PexInvariantAssemblyAttribute() + { + } + + static PexInvariantAssemblyAttribute() + { + } + + static PexInvariantAssemblyAttribute() + { + } + } + + [System.AttributeUsageAttribute(System.AttributeTargets.Property, AllowMultiple = false, Inherited = false)] + public class PexFieldBindingAttribute : System.Attribute + { + + public string FieldName; + + public object TypeId; + + static PexFieldBindingAttribute() + { + } + } + + [System.AttributeUsageAttribute(((System.AttributeTargets.Assembly | System.AttributeTargets.Class) + | System.AttributeTargets.Method), AllowMultiple = true, Inherited = true)] + public class PexCreatableByClassFactoryAttribute : System.Attribute + { + + public Microsoft.ExtendedReflection.Metadata.TypeEx FactoryType; + + public Microsoft.ExtendedReflection.Metadata.TypeEx CreatableType; + + public object TypeId; + + static PexCreatableByClassFactoryAttribute() + { + } + } + + [System.AttributeUsageAttribute(((System.AttributeTargets.Assembly | System.AttributeTargets.Class) + | System.AttributeTargets.Method), AllowMultiple = true, Inherited = true)] + public class PexAllowedExceptionAttribute : System.Attribute + { + + public Microsoft.ExtendedReflection.Metadata.TypeDefinition AllowedExceptionTypeDefinition; + + public string Description; + + public string UserAssemblies; + + public bool AcceptExceptionSubtypes; + + public bool AcceptInnerException; + + public object TypeId; + + static PexAllowedExceptionAttribute() + { + } + } + + [System.AttributeUsageAttribute(System.AttributeTargets.Class, AllowMultiple = false, Inherited = true)] + public class PexClassAttribute : System.Attribute + { + + public string Suite; + + public string Categories; + + public int MaxBranches; + + public int MaxRounds; + + public int MaxRuns; + + public int MaxRunsWithUniqueBranchHits; + + public int MaxRunsWithUniquePaths; + + public int MaxCalls; + + public int MaxConditions; + + public int MaxBranchHits; + + public int MaxExceptions; + + public int ConstraintSolverTimeout; + + public int Timeout; + + public string CoverageFileFormat; + + public string TouchMyCode; + + public string TestClassName; + + public bool TestExcludeNonTermination; + + public bool TestDisableNonTermination; + + public Microsoft.Pex.Framework.PexTestEmissionFilter TestEmissionFilter; + + public bool PruneExceptions; + + public bool Joins; + + public bool NoSoftSubstitutions; + + public bool SymbolicCalls; + + public Microsoft.Pex.Framework.Strategies.PexSearchFrontier SearchFrontier; + + public string CustomSolver; + + public Microsoft.Pex.Framework.Strategies.PexCoverageGoal CoverageGoal; + + public string CssProjectStructure; + + public string CssIteration; + + public bool ContainsSettings; + + public System.Collections.Generic.IEnumerable ActiveSettings; + + public object TypeId; + + static PexClassAttribute() + { + } + } + + [System.AttributeUsageAttribute(((System.AttributeTargets.Assembly | System.AttributeTargets.Class) + | System.AttributeTargets.Method), AllowMultiple = true, Inherited = true)] + public class PexCreatableAsSingletonAttribute : System.Attribute + { + + public Microsoft.ExtendedReflection.Metadata.TypeEx CreatableType; + + public object TypeId; + + static PexCreatableAsSingletonAttribute() + { + } + + static PexCreatableAsSingletonAttribute() + { + } + + static PexCreatableAsSingletonAttribute() + { + } + + static PexCreatableAsSingletonAttribute() + { + } + } + + [System.AttributeUsageAttribute(((((((((((((((System.AttributeTargets.Assembly | System.AttributeTargets.Module) + | System.AttributeTargets.Class) + | System.AttributeTargets.Struct) + | System.AttributeTargets.Enum) + | System.AttributeTargets.Constructor) + | System.AttributeTargets.Method) + | System.AttributeTargets.Property) + | System.AttributeTargets.Field) + | System.AttributeTargets.Event) + | System.AttributeTargets.Interface) + | System.AttributeTargets.Parameter) + | System.AttributeTargets.Delegate) + | System.AttributeTargets.ReturnValue) + | System.AttributeTargets.GenericParameter), AllowMultiple = true, Inherited = true)] + public class PexAssumeIsAcyclicAttribute : System.Attribute + { + + public object TypeId; + + static PexAssumeIsAcyclicAttribute() + { + } + + static PexAssumeIsAcyclicAttribute() + { + } + + static PexAssumeIsAcyclicAttribute() + { + } + } + + [System.AttributeUsageAttribute(((System.AttributeTargets.Assembly | System.AttributeTargets.Class) + | System.AttributeTargets.Method), AllowMultiple = true, Inherited = true)] + public class PexExplorableFromConstructorAttribute : System.Attribute + { + + public Microsoft.ExtendedReflection.Metadata.TypeEx ExplorableType; + + public Microsoft.ExtendedReflection.Metadata.Method ExplorationMethod; + + public object TypeId; + + static PexExplorableFromConstructorAttribute() + { + } + + static PexExplorableFromConstructorAttribute() + { + } + } + + [System.AttributeUsageAttribute(((System.AttributeTargets.Assembly | System.AttributeTargets.Class) + | System.AttributeTargets.Method), AllowMultiple = true, Inherited = true)] + public class PexExplorableFromMethodAttribute : System.Attribute + { + + public Microsoft.ExtendedReflection.Metadata.TypeEx ExplorableType; + + public Microsoft.ExtendedReflection.Metadata.Method ExplorationMethod; + + public object TypeId; + + static PexExplorableFromMethodAttribute() + { + } + + static PexExplorableFromMethodAttribute() + { + } + } + + [System.AttributeUsageAttribute(System.AttributeTargets.Assembly, AllowMultiple = false, Inherited = true)] + public class PexInvariantControllerAttribute : System.Attribute + { + + public System.Type ControllerType; + + public object TypeId; + + static PexInvariantControllerAttribute() + { + } + } + + [System.AttributeUsageAttribute(System.AttributeTargets.Method, AllowMultiple = false, Inherited = true)] + public class PexNotCompilableAttribute : System.Attribute + { + + public object TypeId; + + static PexNotCompilableAttribute() + { + } + } + + [System.AttributeUsageAttribute(System.AttributeTargets.Method, AllowMultiple = true, Inherited = true)] + public class PexInjectedExceptionAttribute : System.Attribute + { + + public System.Type ExceptionType; + + public string Reason; + + public object TypeId; + + static PexInjectedExceptionAttribute() + { + } + } + + [System.AttributeUsageAttribute(System.AttributeTargets.Method, AllowMultiple = false, Inherited = false)] + public class PexUnexpectedExceptionAttribute : System.Attribute + { + + public Microsoft.ExtendedReflection.Metadata.TypeEx ExceptionType; + + public object TypeId; + + static PexUnexpectedExceptionAttribute() + { + } + } + + [System.AttributeUsageAttribute(((System.AttributeTargets.Assembly | System.AttributeTargets.Class) + | System.AttributeTargets.Method), AllowMultiple = true, Inherited = true)] + public class PexCoverageFilterAssemblyAttribute : System.Attribute + { + + public System.Reflection.AssemblyName TargetAssemblyName; + + public Microsoft.Pex.Framework.PexCoverageDomain CoverageDomain; + + public object TypeId; + + static PexCoverageFilterAssemblyAttribute() + { + } + + static PexCoverageFilterAssemblyAttribute() + { + } + } + + [System.AttributeUsageAttribute(((System.AttributeTargets.Assembly | System.AttributeTargets.Class) + | System.AttributeTargets.Method), AllowMultiple = true, Inherited = true)] + public class PexCoverageFilterNamespaceAttribute : System.Attribute + { + + public string NamespaceSuffix; + + public Microsoft.Pex.Framework.PexCoverageDomain CoverageDomain; + + public object TypeId; + + static PexCoverageFilterNamespaceAttribute() + { + } + } + + [System.AttributeUsageAttribute(((System.AttributeTargets.Assembly | System.AttributeTargets.Class) + | System.AttributeTargets.Method), AllowMultiple = true, Inherited = true)] + public class PexCoverageFilterTypeAttribute : System.Attribute + { + + public Microsoft.ExtendedReflection.Metadata.TypeDefinition TargetType; + + public Microsoft.Pex.Framework.PexCoverageDomain CoverageDomain; + + public object TypeId; + + static PexCoverageFilterTypeAttribute() + { + } + } + + [System.AttributeUsageAttribute(((System.AttributeTargets.Assembly | System.AttributeTargets.Class) + | System.AttributeTargets.Method), AllowMultiple = true, Inherited = true)] + public class PexCoverageFilterTypesAttribute : System.Attribute + { + + public string NameSuffix; + + public Microsoft.Pex.Framework.PexCoverageDomain CoverageDomain; + + public object TypeId; + + static PexCoverageFilterTypesAttribute() + { + } + } + + [System.AttributeUsageAttribute(((System.AttributeTargets.Assembly | System.AttributeTargets.Class) + | System.AttributeTargets.Method), AllowMultiple = true, Inherited = true)] + public class PexCoverageFilterMarkedByAttribute : System.Attribute + { + + public System.Type AttributeType; + + public Microsoft.Pex.Framework.PexCoverageDomain CoverageDomain; + + public object TypeId; + + static PexCoverageFilterMarkedByAttribute() + { + } + } + + [System.AttributeUsageAttribute(((System.AttributeTargets.Assembly | System.AttributeTargets.Class) + | System.AttributeTargets.Method), AllowMultiple = true, Inherited = true)] + public class PexCoverageFilterMethodAttribute : System.Attribute + { + + public Microsoft.Pex.Framework.PexCoverageDomain CoverageDomain; + + public object TypeId; + + static PexCoverageFilterMethodAttribute() + { + } + } + + [System.AttributeUsageAttribute(((((((((((((((System.AttributeTargets.Assembly | System.AttributeTargets.Module) + | System.AttributeTargets.Class) + | System.AttributeTargets.Struct) + | System.AttributeTargets.Enum) + | System.AttributeTargets.Constructor) + | System.AttributeTargets.Method) + | System.AttributeTargets.Property) + | System.AttributeTargets.Field) + | System.AttributeTargets.Event) + | System.AttributeTargets.Interface) + | System.AttributeTargets.Parameter) + | System.AttributeTargets.Delegate) + | System.AttributeTargets.ReturnValue) + | System.AttributeTargets.GenericParameter), AllowMultiple = true, Inherited = true)] + public class PexAssumeEnumRangeAttribute : System.Attribute + { + + public object TypeId; + + static PexAssumeEnumRangeAttribute() + { + } + + static PexAssumeEnumRangeAttribute() + { + } + + static PexAssumeEnumRangeAttribute() + { + } + } + + [System.AttributeUsageAttribute((System.AttributeTargets.Class | System.AttributeTargets.Method), AllowMultiple = false, Inherited = true)] + public class PexExplicitAttribute : System.Attribute + { + + public object TypeId; + + static PexExplicitAttribute() + { + } + } + + [System.AttributeUsageAttribute(System.AttributeTargets.Method, AllowMultiple = false, Inherited = true)] + public class PexInvariantAttribute : System.Attribute + { + + public object TypeId; + + static PexInvariantAttribute() + { + } + } + + [System.AttributeUsageAttribute(((System.AttributeTargets.Assembly | System.AttributeTargets.Class) + | System.AttributeTargets.Method), AllowMultiple = true, Inherited = true)] + public class DecimalExplorableAttribute : System.Attribute + { + + public Microsoft.ExtendedReflection.Metadata.TypeEx ExplorableType; + + public Microsoft.ExtendedReflection.Metadata.Method ExplorationMethod; + + public object TypeId; + + static DecimalExplorableAttribute() + { + } + } + + [System.AttributeUsageAttribute(((System.AttributeTargets.Assembly | System.AttributeTargets.Class) + | System.AttributeTargets.Method), AllowMultiple = true, Inherited = true)] + public class DateTimeCreatableAttribute : System.Attribute + { + + public Microsoft.ExtendedReflection.Metadata.TypeEx CreatableType; + + public object TypeId; + + static DateTimeCreatableAttribute() + { + } + } + + [System.AttributeUsageAttribute(((System.AttributeTargets.Assembly | System.AttributeTargets.Class) + | System.AttributeTargets.Method), AllowMultiple = true, Inherited = true)] + public class ArrayListExplorableAttribute : System.Attribute + { + + public Microsoft.ExtendedReflection.Metadata.TypeEx ExplorableType; + + public Microsoft.ExtendedReflection.Metadata.Method ExplorationMethod; + + public object TypeId; + + static ArrayListExplorableAttribute() + { + } + } + + [System.AttributeUsageAttribute(((System.AttributeTargets.Assembly | System.AttributeTargets.Class) + | System.AttributeTargets.Method), AllowMultiple = true, Inherited = true)] + public class QueueExplorableAttribute : System.Attribute + { + + public Microsoft.ExtendedReflection.Metadata.TypeEx ExplorableType; + + public Microsoft.ExtendedReflection.Metadata.Method ExplorationMethod; + + public object TypeId; + + static QueueExplorableAttribute() + { + } + } + + [System.AttributeUsageAttribute(((System.AttributeTargets.Assembly | System.AttributeTargets.Class) + | System.AttributeTargets.Method), AllowMultiple = true, Inherited = true)] + public class StackExplorableAttribute : System.Attribute + { + + public Microsoft.ExtendedReflection.Metadata.TypeEx ExplorableType; + + public Microsoft.ExtendedReflection.Metadata.Method ExplorationMethod; + + public object TypeId; + + static StackExplorableAttribute() + { + } + } + + [System.AttributeUsageAttribute(System.AttributeTargets.Assembly, AllowMultiple = false, Inherited = true)] + public class PexAssemblySettingsAttribute : System.Attribute + { + + public string TestFramework; + + public string TestLanguage; + + public bool TestNoPartialClasses; + + public bool TestNoClassAttribute; + + public bool TestOverrideReadonly; + + public bool TestGenerateDuplicates; + + public string TestRootNamespace; + + public bool TestForceFixtureSetupTeardown; + + public string TestCopyright; + + public int RequiredCoveragePercentile; + + public bool NoSeparateAppDomain; + + public bool UseNoImplicitMocks; + + public string Categories; + + public int MaxBranches; + + public int MaxRounds; + + public int MaxRuns; + + public int MaxRunsWithUniqueBranchHits; + + public int MaxRunsWithUniquePaths; + + public int MaxCalls; + + public int MaxConditions; + + public int MaxBranchHits; + + public int MaxExceptions; + + public int ConstraintSolverTimeout; + + public int Timeout; + + public string CoverageFileFormat; + + public string TouchMyCode; + + public string TestClassName; + + public bool TestExcludeNonTermination; + + public bool TestDisableNonTermination; + + public Microsoft.Pex.Framework.PexTestEmissionFilter TestEmissionFilter; + + public bool PruneExceptions; + + public bool Joins; + + public bool NoSoftSubstitutions; + + public bool SymbolicCalls; + + public Microsoft.Pex.Framework.Strategies.PexSearchFrontier SearchFrontier; + + public string CustomSolver; + + public Microsoft.Pex.Framework.Strategies.PexCoverageGoal CoverageGoal; + + public string CssProjectStructure; + + public string CssIteration; + + public bool ContainsSettings; + + public System.Collections.Generic.IEnumerable ActiveSettings; + + public object TypeId; + + static PexAssemblySettingsAttribute() + { + } + } + + [System.AttributeUsageAttribute(System.AttributeTargets.Assembly, AllowMultiple = true, Inherited = true)] + public class PexSettingsMixAttribute : System.Attribute + { + + public string MixName; + + public int MixReportOrder; + + public string Categories; + + public int MaxBranches; + + public int MaxRounds; + + public int MaxRuns; + + public int MaxRunsWithUniqueBranchHits; + + public int MaxRunsWithUniquePaths; + + public int MaxCalls; + + public int MaxConditions; + + public int MaxBranchHits; + + public int MaxExceptions; + + public int ConstraintSolverTimeout; + + public int Timeout; + + public string CoverageFileFormat; + + public string TouchMyCode; + + public string TestClassName; + + public bool TestExcludeNonTermination; + + public bool TestDisableNonTermination; + + public Microsoft.Pex.Framework.PexTestEmissionFilter TestEmissionFilter; + + public bool PruneExceptions; + + public bool Joins; + + public bool NoSoftSubstitutions; + + public bool SymbolicCalls; + + public Microsoft.Pex.Framework.Strategies.PexSearchFrontier SearchFrontier; + + public string CustomSolver; + + public Microsoft.Pex.Framework.Strategies.PexCoverageGoal CoverageGoal; + + public string CssProjectStructure; + + public string CssIteration; + + public bool ContainsSettings; + + public System.Collections.Generic.IEnumerable ActiveSettings; + + public object TypeId; + + static PexSettingsMixAttribute() + { + } + } + + [System.AttributeUsageAttribute(((System.AttributeTargets.Assembly | System.AttributeTargets.Class) + | System.AttributeTargets.Method), AllowMultiple = true, Inherited = true)] + public class PexUseTypeAttribute : System.Attribute + { + + public Microsoft.ExtendedReflection.Metadata.TypeEx TargetType; + + public object TypeId; + + static PexUseTypeAttribute() + { + } + + static PexUseTypeAttribute() + { + } + } + + [System.AttributeUsageAttribute(((System.AttributeTargets.Assembly | System.AttributeTargets.Class) + | System.AttributeTargets.Method), AllowMultiple = true, Inherited = true)] + public class PexUseTypesFromFactoryAttribute : System.Attribute + { + + public object TypeId; + + static PexUseTypesFromFactoryAttribute() + { + } + } + + [System.AttributeUsageAttribute(((System.AttributeTargets.Assembly | System.AttributeTargets.Class) + | System.AttributeTargets.Method), AllowMultiple = true, Inherited = true)] + public class PexUseAssemblyAttribute : System.Attribute + { + + public Microsoft.ExtendedReflection.Metadata.AssemblyEx TargetAssembly; + + public object TypeId; + + static PexUseAssemblyAttribute() + { + } + + static PexUseAssemblyAttribute() + { + } + } + + [System.AttributeUsageAttribute(((System.AttributeTargets.Assembly | System.AttributeTargets.Class) + | System.AttributeTargets.Method), AllowMultiple = true, Inherited = true)] + public class PexUseImplementationsOfAttribute : System.Attribute + { + + public Microsoft.ExtendedReflection.Metadata.TypeEx TargetType; + + public Microsoft.ExtendedReflection.Metadata.AssemblyEx TargetAssembly; + + public object TypeId; + + static PexUseImplementationsOfAttribute() + { + } + + static PexUseImplementationsOfAttribute() + { + } + } + + [System.AttributeUsageAttribute(((System.AttributeTargets.Assembly | System.AttributeTargets.Class) + | System.AttributeTargets.Method), AllowMultiple = true, Inherited = true)] + public class PexUseNamespaceAttribute : System.Attribute + { + + public string NamespaceName; + + public bool Strict; + + public Microsoft.ExtendedReflection.Metadata.AssemblyEx TargetAssembly; + + public object TypeId; + + static PexUseNamespaceAttribute() + { + } + } + + [System.AttributeUsageAttribute(((System.AttributeTargets.Assembly | System.AttributeTargets.Class) + | System.AttributeTargets.Method), AllowMultiple = true, Inherited = true)] + public class PexUseMarkedByAttribute : System.Attribute + { + + public Microsoft.ExtendedReflection.Metadata.TypeEx AttributeType; + + public Microsoft.ExtendedReflection.Metadata.AssemblyEx TargetAssembly; + + public object TypeId; + + static PexUseMarkedByAttribute() + { + } + } + + [System.AttributeUsageAttribute(((System.AttributeTargets.Assembly | System.AttributeTargets.Class) + | System.AttributeTargets.Method), AllowMultiple = true, Inherited = true)] + public class PexCreatableByConstructorAttribute : System.Attribute + { + + public Microsoft.ExtendedReflection.Metadata.TypeEx CreatableType; + + public object TypeId; + + static PexCreatableByConstructorAttribute() + { + } + } + + [System.AttributeUsageAttribute((((System.AttributeTargets.Assembly | System.AttributeTargets.Class) + | System.AttributeTargets.Method) + | System.AttributeTargets.Parameter), AllowMultiple = true, Inherited = true)] + public class PexExplorableFromFactoryAttribute : System.Attribute + { + + public Microsoft.ExtendedReflection.Metadata.TypeEx FactoryType; + + public Microsoft.ExtendedReflection.Metadata.TypeEx ExplorableType; + + public Microsoft.ExtendedReflection.Metadata.Method ExplorationMethod; + + public object TypeId; + + static PexExplorableFromFactoryAttribute() + { + } + + static PexExplorableFromFactoryAttribute() + { + } + } + + [System.AttributeUsageAttribute(((System.AttributeTargets.Assembly | System.AttributeTargets.Class) + | System.AttributeTargets.Method), AllowMultiple = true, Inherited = true)] + public class PexCreatablesAsWebDataFromXmlNamespaceAttribute : System.Attribute + { + + public string XmlNamespace; + + public object TypeId; + + static PexCreatablesAsWebDataFromXmlNamespaceAttribute() + { + } + + static PexCreatablesAsWebDataFromXmlNamespaceAttribute() + { + } + } + + [System.AttributeUsageAttribute(((System.AttributeTargets.Assembly | System.AttributeTargets.Class) + | System.AttributeTargets.Method), AllowMultiple = true, Inherited = true)] + public class PexFromAssemblyAttribute : System.Attribute + { + + public System.Reflection.AssemblyName TargetAssembly; + + public bool DeriveSubtypes; + + public Microsoft.Pex.Framework.PexFromAction Action; + + public object TypeId; + + static PexFromAssemblyAttribute() + { + } + + static PexFromAssemblyAttribute() + { + } + + static PexFromAssemblyAttribute() + { + } + + static PexFromAssemblyAttribute() + { + } + } + + [System.AttributeUsageAttribute(((System.AttributeTargets.Assembly | System.AttributeTargets.Class) + | System.AttributeTargets.Method), AllowMultiple = true, Inherited = true)] + public class PexFromNamespaceAttribute : System.Attribute + { + + public string Namespace; + + public System.Reflection.AssemblyName TargetAssembly; + + public bool DeriveSubtypes; + + public Microsoft.Pex.Framework.PexFromAction Action; + + public object TypeId; + + static PexFromNamespaceAttribute() + { + } + + static PexFromNamespaceAttribute() + { + } + + static PexFromNamespaceAttribute() + { + } + + static PexFromNamespaceAttribute() + { + } + } + + [System.AttributeUsageAttribute(((System.AttributeTargets.Assembly | System.AttributeTargets.Class) + | System.AttributeTargets.Method), AllowMultiple = true, Inherited = true)] + public class PexFromTypeAttribute : System.Attribute + { + + public Microsoft.ExtendedReflection.Metadata.TypeDefinition Type; + + public bool DeriveSubtypes; + + public Microsoft.Pex.Framework.PexFromAction Action; + + public object TypeId; + + static PexFromTypeAttribute() + { + } + + static PexFromTypeAttribute() + { + } + } + + [System.AttributeUsageAttribute(((System.AttributeTargets.Assembly | System.AttributeTargets.Class) + | System.AttributeTargets.Method), AllowMultiple = true, Inherited = true)] + public class PexFromMarkedByAttribute : System.Attribute + { + + public Microsoft.ExtendedReflection.Metadata.TypeEx AttributeType; + + public System.Reflection.AssemblyName TargetAssembly; + + public bool DeriveSubtypes; + + public Microsoft.Pex.Framework.PexFromAction Action; + + public object TypeId; + + static PexFromMarkedByAttribute() + { + } + + static PexFromMarkedByAttribute() + { + } + } + + [System.AttributeUsageAttribute(((System.AttributeTargets.Assembly | System.AttributeTargets.Class) + | System.AttributeTargets.Method), AllowMultiple = true, Inherited = true)] + public class PexFromFieldAttribute : System.Attribute + { + + public Microsoft.ExtendedReflection.Metadata.Field Field; + + public Microsoft.Pex.Framework.PexFromAction Action; + + public object TypeId; + + static PexFromFieldAttribute() + { + } + } + + [System.AttributeUsageAttribute(((System.AttributeTargets.Assembly | System.AttributeTargets.Class) + | System.AttributeTargets.Method), AllowMultiple = true, Inherited = true)] + public class PexFromConstructorAttribute : System.Attribute + { + + public Microsoft.ExtendedReflection.Metadata.Method Constructor; + + public Microsoft.Pex.Framework.PexFromAction Action; + + public object TypeId; + + static PexFromConstructorAttribute() + { + } + } + + [System.AttributeUsageAttribute(((System.AttributeTargets.Assembly | System.AttributeTargets.Class) + | System.AttributeTargets.Method), AllowMultiple = true, Inherited = true)] + public class PexFromMethodAttribute : System.Attribute + { + + public Microsoft.ExtendedReflection.Metadata.Method Method; + + public Microsoft.Pex.Framework.PexFromAction Action; + + public object TypeId; + + static PexFromMethodAttribute() + { + } + } + + [System.AttributeUsageAttribute(System.AttributeTargets.Class, AllowMultiple = false, Inherited = true)] + public class PexAttributeFamilyAttribute : System.Attribute + { + + public Microsoft.Pex.Framework.PexAttributeFamily Family; + + public object TypeId; + + static PexAttributeFamilyAttribute() + { + } + } + + [System.AttributeUsageAttribute(((System.AttributeTargets.Assembly | System.AttributeTargets.Class) + | System.AttributeTargets.Method), AllowMultiple = true, Inherited = true)] + public class PexInvariantCheckAttribute : System.Attribute + { + + public object TypeId; + + static PexInvariantCheckAttribute() + { + } + } + + [System.AttributeUsageAttribute(System.AttributeTargets.Method, AllowMultiple = false, Inherited = true)] + public class PexKeepMeAttribute : System.Attribute + { + + public object TypeId; + + static PexKeepMeAttribute() + { + } + } + + [System.AttributeUsageAttribute(((System.AttributeTargets.Assembly | System.AttributeTargets.Class) + | System.AttributeTargets.Method), AllowMultiple = true, Inherited = true)] + public class PexInjectExceptionsOnWriteAttribute : System.Attribute + { + + public object TypeId; + + static PexInjectExceptionsOnWriteAttribute() + { + } + } + + [System.AttributeUsageAttribute(System.AttributeTargets.Assembly, AllowMultiple = true, Inherited = true)] + public class PexFixItEmitterFactoryAttribute : System.Attribute + { + + public System.Type FixItEmitterFactoryType; + + public object TypeId; + + static PexFixItEmitterFactoryAttribute() + { + } + } + + [System.AttributeUsageAttribute(((((((((((((((System.AttributeTargets.Assembly | System.AttributeTargets.Module) + | System.AttributeTargets.Class) + | System.AttributeTargets.Struct) + | System.AttributeTargets.Enum) + | System.AttributeTargets.Constructor) + | System.AttributeTargets.Method) + | System.AttributeTargets.Property) + | System.AttributeTargets.Field) + | System.AttributeTargets.Event) + | System.AttributeTargets.Interface) + | System.AttributeTargets.Parameter) + | System.AttributeTargets.Delegate) + | System.AttributeTargets.ReturnValue) + | System.AttributeTargets.GenericParameter), AllowMultiple = true, Inherited = true)] + public class PexUseRangeAttribute : System.Attribute + { + + public object TypeId; + + static PexUseRangeAttribute() + { + } + + static PexUseRangeAttribute() + { + } + + static PexUseRangeAttribute() + { + } + } + + [System.AttributeUsageAttribute(System.AttributeTargets.Class, AllowMultiple = false, Inherited = false)] + public class PexInstrumentedAttribute : System.Attribute + { + + public object TypeId; + + static PexInstrumentedAttribute() + { + } + } + + [System.AttributeUsageAttribute(System.AttributeTargets.Class, AllowMultiple = false, Inherited = false)] + public class PexMockAttribute : System.Attribute + { + + public object TypeId; + + static PexMockAttribute() + { + } + } + + [System.AttributeUsageAttribute(System.AttributeTargets.Assembly, AllowMultiple = true, Inherited = true)] + public class PexInstrumentMarkedByAttribute : System.Attribute + { + + public System.Reflection.Assembly TargetAssembly; + + public System.Type AttributeType; + + public Microsoft.Pex.Framework.PexInstrumentationLevel InstrumentationLevel; + + public bool NoNestedTypes; + + public object TypeId; + + static PexInstrumentMarkedByAttribute() + { + } + } + + [System.AttributeUsageAttribute(System.AttributeTargets.Assembly, AllowMultiple = true, Inherited = true)] + public class PexInstrumentMocksAttribute : System.Attribute + { + + public System.Reflection.Assembly TargetAssembly; + + public System.Type AttributeType; + + public Microsoft.Pex.Framework.PexInstrumentationLevel InstrumentationLevel; + + public bool NoNestedTypes; + + public object TypeId; + + static PexInstrumentMocksAttribute() + { + } + } + + [System.AttributeUsageAttribute(((System.AttributeTargets.Assembly | System.AttributeTargets.Class) + | System.AttributeTargets.Method), AllowMultiple = true, Inherited = true)] + public class PexUseMocksAttribute : System.Attribute + { + + public Microsoft.ExtendedReflection.Metadata.TypeEx AttributeType; + + public Microsoft.ExtendedReflection.Metadata.AssemblyEx TargetAssembly; + + public object TypeId; + + static PexUseMocksAttribute() + { + } + } + + [System.AttributeUsageAttribute(System.AttributeTargets.Assembly, AllowMultiple = true, Inherited = true)] + public class PexInstrumentAssemblyAttribute : System.Attribute + { + + public string TargetAssemblyName; + + public Microsoft.Pex.Framework.PexInstrumentationLevel InstrumentationLevel; + + public object TypeId; + + static PexInstrumentAssemblyAttribute() + { + } + + static PexInstrumentAssemblyAttribute() + { + } + } + + [System.AttributeUsageAttribute(System.AttributeTargets.Assembly, AllowMultiple = true, Inherited = true)] + public class PexInstrumentAssembliesFromAttribute : System.Attribute + { + + public string Path; + + public string SearchPattern; + + public Microsoft.Pex.Framework.PexInstrumentationLevel InstrumentationLevel; + + public object TypeId; + + static PexInstrumentAssembliesFromAttribute() + { + } + } + + [System.AttributeUsageAttribute(((((((((((((((System.AttributeTargets.Assembly | System.AttributeTargets.Module) + | System.AttributeTargets.Class) + | System.AttributeTargets.Struct) + | System.AttributeTargets.Enum) + | System.AttributeTargets.Constructor) + | System.AttributeTargets.Method) + | System.AttributeTargets.Property) + | System.AttributeTargets.Field) + | System.AttributeTargets.Event) + | System.AttributeTargets.Interface) + | System.AttributeTargets.Parameter) + | System.AttributeTargets.Delegate) + | System.AttributeTargets.ReturnValue) + | System.AttributeTargets.GenericParameter), AllowMultiple = true, Inherited = true)] + public class PexUseUnicodeStringsAttribute : System.Attribute + { + + public object TypeId; + + static PexUseUnicodeStringsAttribute() + { + } + + static PexUseUnicodeStringsAttribute() + { + } + } + + [System.AttributeUsageAttribute(((System.AttributeTargets.Assembly | System.AttributeTargets.Class) + | System.AttributeTargets.Method), AllowMultiple = true, Inherited = true)] + public class PexRollbackAttribute : System.Attribute + { + + public object TypeId; + + static PexRollbackAttribute() + { + } + } + + [System.AttributeUsageAttribute(((System.AttributeTargets.Assembly | System.AttributeTargets.Class) + | System.AttributeTargets.Method), AllowMultiple = true, Inherited = true)] + public class PexExpectedExceptionAttribute : System.Attribute + { + + public Microsoft.ExtendedReflection.Metadata.TypeEx ExpectedExceptionType; + + public string Description; + + public string UserAssemblies; + + public bool AcceptExceptionSubtypes; + + public bool AcceptInnerException; + + public object TypeId; + + static PexExpectedExceptionAttribute() + { + } + } + + [System.AttributeUsageAttribute(((((((((((((((System.AttributeTargets.Assembly | System.AttributeTargets.Module) + | System.AttributeTargets.Class) + | System.AttributeTargets.Struct) + | System.AttributeTargets.Enum) + | System.AttributeTargets.Constructor) + | System.AttributeTargets.Method) + | System.AttributeTargets.Property) + | System.AttributeTargets.Field) + | System.AttributeTargets.Event) + | System.AttributeTargets.Interface) + | System.AttributeTargets.Parameter) + | System.AttributeTargets.Delegate) + | System.AttributeTargets.ReturnValue) + | System.AttributeTargets.GenericParameter), AllowMultiple = true, Inherited = true)] + public class PexAssumeIsNotNullAttribute : System.Attribute + { + + public object TypeId; + + static PexAssumeIsNotNullAttribute() + { + } + + static PexAssumeIsNotNullAttribute() + { + } + + static PexAssumeIsNotNullAttribute() + { + } + } + + [System.AttributeUsageAttribute(System.AttributeTargets.Assembly, AllowMultiple = true, Inherited = true)] + public class PexInstrumentTypesByNameAttribute : System.Attribute + { + + public Microsoft.Pex.Framework.PexInstrumentationLevel InstrumentationLevel; + + public bool NoNestedTypes; + + public object TypeId; + + static PexInstrumentTypesByNameAttribute() + { + } + + static PexInstrumentTypesByNameAttribute() + { + } + } + + [System.AttributeUsageAttribute(System.AttributeTargets.Assembly, AllowMultiple = true, Inherited = true)] + public class PexInstrumentTypeAttribute : System.Attribute + { + + public System.Type TargetType; + + public Microsoft.Pex.Framework.PexInstrumentationLevel InstrumentationLevel; + + public bool NoNestedTypes; + + public object TypeId; + + static PexInstrumentTypeAttribute() + { + } + + static PexInstrumentTypeAttribute() + { + } + } + + [System.AttributeUsageAttribute(System.AttributeTargets.Assembly, AllowMultiple = true, Inherited = true)] + public class PexInstrumentNamespaceAttribute : System.Attribute + { + + public System.Reflection.Assembly TargetAssembly; + + public string Namespace; + + public bool IgnoreSubNamespaces; + + public Microsoft.Pex.Framework.PexInstrumentationLevel InstrumentationLevel; + + public bool NoNestedTypes; + + public object TypeId; + + static PexInstrumentNamespaceAttribute() + { + } + } + + [System.AttributeUsageAttribute(System.AttributeTargets.Assembly, AllowMultiple = true, Inherited = true)] + public class PexTestFrameworkAttribute : System.Attribute + { + + public System.Type TestFrameworkType; + + public object TypeId; + + static PexTestFrameworkAttribute() + { + } + } + + [System.AttributeUsageAttribute(((((((((((((((System.AttributeTargets.Assembly | System.AttributeTargets.Module) + | System.AttributeTargets.Class) + | System.AttributeTargets.Struct) + | System.AttributeTargets.Enum) + | System.AttributeTargets.Constructor) + | System.AttributeTargets.Method) + | System.AttributeTargets.Property) + | System.AttributeTargets.Field) + | System.AttributeTargets.Event) + | System.AttributeTargets.Interface) + | System.AttributeTargets.Parameter) + | System.AttributeTargets.Delegate) + | System.AttributeTargets.ReturnValue) + | System.AttributeTargets.GenericParameter), AllowMultiple = false, Inherited = true)] + public class PexGeneratedByAttribute : System.Attribute + { + + public Microsoft.ExtendedReflection.Metadata.TypeEx FixtureType; + + public string ExplorationName; + + public object TypeId; + + static PexGeneratedByAttribute() + { + } + } + + [System.AttributeUsageAttribute((((System.AttributeTargets.Assembly | System.AttributeTargets.Class) + | System.AttributeTargets.Method) + | System.AttributeTargets.Parameter), AllowMultiple = true, Inherited = true)] + public class PexUseValuesFromFactoryAttribute : System.Attribute + { + + public Microsoft.ExtendedReflection.Metadata.TypeEx FactoryType; + + public object TypeId; + + static PexUseValuesFromFactoryAttribute() + { + } + + static PexUseValuesFromFactoryAttribute() + { + } + + static PexUseValuesFromFactoryAttribute() + { + } + } + + [System.AttributeUsageAttribute(((System.AttributeTargets.Assembly | System.AttributeTargets.Class) + | System.AttributeTargets.Method), AllowMultiple = true, Inherited = true)] + public class PexExpectedTestsAttribute : System.Attribute + { + + public int TotalCount; + + public int DuplicateCount; + + public int FailureCount; + + public int NewCount; + + public object TypeId; + + static PexExpectedTestsAttribute() + { + } + } + + [System.AttributeUsageAttribute(((((((((((((((System.AttributeTargets.Assembly | System.AttributeTargets.Module) + | System.AttributeTargets.Class) + | System.AttributeTargets.Struct) + | System.AttributeTargets.Enum) + | System.AttributeTargets.Constructor) + | System.AttributeTargets.Method) + | System.AttributeTargets.Property) + | System.AttributeTargets.Field) + | System.AttributeTargets.Event) + | System.AttributeTargets.Interface) + | System.AttributeTargets.Parameter) + | System.AttributeTargets.Delegate) + | System.AttributeTargets.ReturnValue) + | System.AttributeTargets.GenericParameter), AllowMultiple = true, Inherited = true)] + public class PexAssumeRangeAttribute : System.Attribute + { + + public object TypeId; + + static PexAssumeRangeAttribute() + { + } + + static PexAssumeRangeAttribute() + { + } + + static PexAssumeRangeAttribute() + { + } + } + + [System.AttributeUsageAttribute(((System.AttributeTargets.Assembly | System.AttributeTargets.Class) + | System.AttributeTargets.Method), AllowMultiple = true, Inherited = true)] + public class PexInjectValuesAttribute : System.Attribute + { + + public object TypeId; + + static PexInjectValuesAttribute() + { + } + } + + [System.AttributeUsageAttribute(((System.AttributeTargets.Assembly | System.AttributeTargets.Class) + | System.AttributeTargets.Method), AllowMultiple = true, Inherited = true)] + public class PexInjectExceptionsOnXmlDocumentedCallAttribute : System.Attribute + { + + public bool IgnoreUncreatableExceptionTypes; + + public bool AllowExceptionSubtypes; + + public object TypeId; + + static PexInjectExceptionsOnXmlDocumentedCallAttribute() + { + } + + static PexInjectExceptionsOnXmlDocumentedCallAttribute() + { + } + + static PexInjectExceptionsOnXmlDocumentedCallAttribute() + { + } + } + + [System.AttributeUsageAttribute(System.AttributeTargets.Class, AllowMultiple = false, Inherited = true)] + public class PexInvariantClassAttribute : System.Attribute + { + + public object TypeId; + + static PexInvariantClassAttribute() + { + } + } + + [System.AttributeUsageAttribute(System.AttributeTargets.Method, AllowMultiple = false, Inherited = true)] + public class PexNotReproducibleAttribute : System.Attribute + { + + public object TypeId; + + static PexNotReproducibleAttribute() + { + } + } + + [System.AttributeUsageAttribute(System.AttributeTargets.Method, AllowMultiple = true, Inherited = true)] + public class PexInjectedValueAttribute : System.Attribute + { + + public string Value; + + public string Reason; + + public object TypeId; + + static PexInjectedValueAttribute() + { + } + } + + [System.AttributeUsageAttribute(((System.AttributeTargets.Assembly | System.AttributeTargets.Class) + | System.AttributeTargets.Method), AllowMultiple = true, Inherited = true)] + public class PexInjectExceptionsOnUnverifiableUnsafeMemoryAccessAttribute : System.Attribute + { + + public System.Type ExceptionType; + + public object TypeId; + + static PexInjectExceptionsOnUnverifiableUnsafeMemoryAccessAttribute() + { + } + } + + [System.AttributeUsageAttribute(((System.AttributeTargets.Assembly | System.AttributeTargets.Class) + | System.AttributeTargets.Method), AllowMultiple = true, Inherited = true)] + public class PexFocusOnTypeAttribute : System.Attribute + { + + public Microsoft.ExtendedReflection.Metadata.TypeDefinition TargetTypeDefinition; + + public bool NoNestedTypes; + + public Microsoft.Pex.Framework.PexSearchPriority SearchPriority; + + public bool DoNotReportCoverage; + + public object TypeId; + + static PexFocusOnTypeAttribute() + { + } + + static PexFocusOnTypeAttribute() + { + } + } + + [System.AttributeUsageAttribute(((System.AttributeTargets.Assembly | System.AttributeTargets.Class) + | System.AttributeTargets.Method), AllowMultiple = true, Inherited = true)] + public class PexExplorablesFromMocksAttribute : System.Attribute + { + + public object TypeId; + + static PexExplorablesFromMocksAttribute() + { + } + + static PexExplorablesFromMocksAttribute() + { + } + } + + [System.AttributeUsageAttribute(((System.AttributeTargets.Assembly | System.AttributeTargets.Class) + | System.AttributeTargets.Method), AllowMultiple = true, Inherited = true)] + public class PexUseMaxInstancesAttribute : System.Attribute + { + + public object TypeId; + + static PexUseMaxInstancesAttribute() + { + } + + static PexUseMaxInstancesAttribute() + { + } + } + + public sealed class AssertionViolationException : System.Exception + { + + public AssertionViolationException(string message) + : + base(message) + { + } + } +} +#endif \ No newline at end of file diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/testframework.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/testframework.cs.meta new file mode 100644 index 0000000..f30eb86 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Tests/testframework.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 64c1952446fe74d3ca2783e043d7ce74 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit.meta new file mode 100644 index 0000000..839e463 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: 1213fe9297e2e44858bf9d01801280e7 +folderAsset: yes +DefaultImporter: + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/AssemblySetUpAndTearDownAttribute.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/AssemblySetUpAndTearDownAttribute.cs new file mode 100755 index 0000000..a03b5ef --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/AssemblySetUpAndTearDownAttribute.cs @@ -0,0 +1,24 @@ +using System; + +namespace QuickGraph.Unit +{ + [AttributeUsage(AttributeTargets.Assembly, AllowMultiple=false)] + public sealed class AssemblySetUpAndTearDownAttribute : Attribute + { + private Type targetType; + public AssemblySetUpAndTearDownAttribute( + Type targetType + ) + { + if (targetType == null) + throw new ArgumentNullException("targetType"); + this.targetType = targetType; + } + + public Type TargetType + { + get { return this.targetType; } + set { this.targetType = value; } + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/AssemblySetUpAndTearDownAttribute.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/AssemblySetUpAndTearDownAttribute.cs.meta new file mode 100644 index 0000000..bc5e4b2 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/AssemblySetUpAndTearDownAttribute.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 55c59a74b8f2d4de28d1618135ac1449 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/AssemblySetUpAttribute.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/AssemblySetUpAttribute.cs new file mode 100755 index 0000000..8eaa15c --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/AssemblySetUpAttribute.cs @@ -0,0 +1,8 @@ +using System; + +namespace QuickGraph.Unit +{ + [AttributeUsage(AttributeTargets.Method, AllowMultiple=false, Inherited=false)] + public sealed class AssemblySetUpAttribute : Attribute + {} +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/AssemblySetUpAttribute.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/AssemblySetUpAttribute.cs.meta new file mode 100644 index 0000000..8530363 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/AssemblySetUpAttribute.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 48a02254a2535404193a4ba33eb36081 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/AssemblyTearDownAttribute.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/AssemblyTearDownAttribute.cs new file mode 100755 index 0000000..d517f20 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/AssemblyTearDownAttribute.cs @@ -0,0 +1,8 @@ +using System; + +namespace QuickGraph.Unit +{ + [AttributeUsage(AttributeTargets.Method, AllowMultiple=false, Inherited=false)] + public sealed class AssemblyTearDownAttribute : Attribute + {} +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/AssemblyTearDownAttribute.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/AssemblyTearDownAttribute.cs.meta new file mode 100644 index 0000000..630bbd0 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/AssemblyTearDownAttribute.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 59291871ef1634f3e885bcb94e38e393 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Assert.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Assert.cs new file mode 100755 index 0000000..2a8c35f --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Assert.cs @@ -0,0 +1,435 @@ +using System; +using System.Reflection; +using System.Collections; +using System.Collections.Generic; +using QuickGraph.Unit.Exceptions; + +namespace QuickGraph.Unit +{ + public static class Assert + { + #region Synching + private static volatile object syncRoot = new object(); + public static object SyncRoot + { + get { return syncRoot; } + } + #endregion + + #region Log + private static IServiceProvider serviceProvider = null; + public static IServiceProvider ServiceProvider + { + get + { + lock (syncRoot) + { + return serviceProvider; + } + } + set + { + lock (syncRoot) + { + serviceProvider = value; + } + } + } + public static ILoggerService Logger + { + get + { + return + ServiceProvider.GetService(typeof(ILoggerService)) + as ILoggerService; + } + } + #endregion + + #region IsLower, Greater + public static void IsLowerEqual(object left, object right, IComparer comparer) + { + if (comparer.Compare(left, right) > 0) + Fail("{0} must be lower or equal than {1} (comparing with {2})", + left, right, + comparer); + } + + public static void IsLowerEqual(T left, T right, IComparer comparer) + { + if (comparer.Compare(left, right) > 0) + Fail("{0} must be lower or equal than {1} (comparing with {2})", + left, right, + comparer); + } + + public static void IsLowerEqual(IComparable left, T right) + { + Assert.IsTrue(left.CompareTo(right)<=0, "{0} must be lower or equal to {1}", left, right); + } + public static void IsLowerEqual(IComparable left, IComparable right) + { + Assert.IsTrue(left.CompareTo(right) <= 0, "{0} must be lower or equal to {1}", left, right); + } + + public static void IsLower(object left, object right, IComparer comparer) + { + if (comparer.Compare(left, right) >= 0) + Fail("{0} must be lower than {1} (comparing with {2})", + left, right, + comparer); + } + + public static void IsLower(T left, T right, IComparer comparer) + { + if (comparer.Compare(left, right) >= 0) + Fail("{0} must be lower than {1} (comparing with {2})", + left, right, + comparer); + } + + public static void IsLower(IComparable left, T right) + { + Assert.IsTrue(left.CompareTo(right) < 0, "{0} must be lower to {1}", left, right); + } + public static void IsLower(IComparable left, IComparable right) + { + Assert.IsTrue(left.CompareTo(right) < 0, "{0} must be lower to {1}", left, right); + } + + public static void IsGreaterEqual(object left, object right, IComparer comparer) + { + if (comparer.Compare(left, right) < 0) + Fail("{0} must be greater or equal than {1} (comparing with {2})", + left, right, + comparer); + } + + public static void IsGreaterEqual(T left, T right, IComparer comparer) + { + if (comparer.Compare(left, right) < 0) + Fail("{0} must be greater or equal than {1} (comparing with {2})", + left, right, + comparer); + } + + public static void IsGreaterEqual(IComparable left, T right) + { + Assert.IsTrue(left.CompareTo(right) >= 0, "{0} must be greater or equal to {1}", left, right); + } + public static void IsGreaterEqual(IComparable left, IComparable right) + { + Assert.IsTrue(left.CompareTo(right) >= 0, "{0} must be greater or equal to {1}", left, right); + } + + public static void IsGreater(object left, object right, IComparer comparer) + { + if (comparer.Compare(left, right) <= 0) + Fail("{0} must be greater than {1} (comparing with {2})", + left, right, + comparer); + } + + public static void IsGreater(T left, T right, IComparer comparer) + { + if (comparer.Compare(left, right) <= 0) + Fail("{0} must be greater than {1} (comparing with {2})", + left, right, + comparer); + } + + public static void IsGreater(IComparable left, T right) + { + Assert.IsTrue(left.CompareTo(right) > 0, "{0} must be greater to {1}", left, right); + } + public static void IsGreater(IComparable left, IComparable right) + { + Assert.IsTrue(left.CompareTo(right) > 0, "{0} must be greater to {1}", left, right); + } + #endregion + + #region AreSame + public static void AreSame(object actual, object expected) + { + Assert.AreEqual(actual, expected); + } + + public static void AreSame(object actual, object expected, string message) + { + Assert.AreEqual(actual, expected, message); + } + + public static void AreSame(object actual, object expected, string format, params object[] args) + { + Assert.AreEqual(actual, expected, format, args); + } + #endregion + + #region AreNotEqual + public static void AreNotEqual(T left, T right, string format, params object[] args) + { + string message = String.Format(format,args); + AreNotEqual(left, right, message); + } + public static void AreNotEqual(T left, T right) + { + AreNotEqual(left, right, ""); + } + public static void AreNotEqual(T left, T right, string message) + { + if (left == null && right == null) + throw new AssertionException(String.Format("Objects are both nulls, {0}",message)); + if (left == null && right != null) + return; + if (right == null && left != null) + return; + + if (left.Equals(right)) + throw new AssertionException( + String.Format("[{0}]==[{1}], {2}", left, right, message) + ); + + } + #endregion + + #region AreEqual + public static void AreEqual(object left, object right, IComparer comparer) + { + if (comparer.Compare(left, right) != 0) + Fail("[{0}]!=[{1}] (comparing with {2})", + left, right, + comparer); + } + + public static void AreEqual(T left, T right, IComparer comparer) + { + if (comparer.Compare(left, right) != 0) + Fail("[{0}]!=[{1}] (comparing with {2})", + left, right, + comparer); + } + + public static void AreEqual(T left, T right, string message) + { + if (left == null && right == null) + return; + if (left == null && right != null) + throw new AssertionException( + String.Format("[{0}]!=[null], {1}", left, message) + ); + if (right == null && left != null) + throw new AssertionException( + String.Format("[{0}]!=null, {1}", right, message) + ); + + + if (!left.Equals(right)) + throw new AssertionException( + String.Format("[{0}]!=[{1}], {2}", left, right, message) + ); + } + + public static void AreEqual(T left, T right) + { + AreEqual(left, right, + "[{0}]!=[{1}]", left, right + ); + } + + public static void AreEqual(T left, T right, string format, params object[] args) + { + string message = String.Format(format, args); + AreEqual(left, right, message); + } +#endregion + + #region AreEqualNumeric + public static void AreEqual(double a, double b, double tolerance) + { + if (Math.Abs(a - b) > tolerance) + Assert.Fail("{0} not equal to {1} (tolerance {2})", + a, b, tolerance); + } + public static void AreEqual(float a, float b, float tolerance) + { + if (Math.Abs(a - b) > tolerance) + Assert.Fail("{0} not equal to {1} (tolerance {2})", + a, b, tolerance); + } + #endregion + + #region IsNull, IsNotNull + public static void IsNull(T o, string message) + { + if (o != null) + throw new AssertionException( + String.Format("{0} is not a null reference, {1}", o, message) + ); + } + + public static void IsNotNull(T o, string message) + { + if (o == null) + throw new AssertionException( + String.Format("{0} is a null reference", o, message) + ); + } + + public static void IsNull(T o) + { + IsNull(o,""); + } + + public static void IsNotNull(T o) + { + IsNotNull(o, ""); + } + + + public static void IsNull(T o, string format, params object[] args) + { + string message = String.Format(format, args); + IsNull(o, message); + } + + public static void IsNotNull(T o, string format, params object[] args) + { + string message = String.Format(format, args); + IsNotNull(o, message); + } +#endregion + + #region True, false + public static void IsTrue(bool value, string message) + { + if (!value) + throw new AssertionException( + String.Format("Expected true got false, {0}", message) + ); + } + + public static void IsFalse(bool value, string message) + { + if (value) + throw new AssertionException( + String.Format("Expected false, got true, {0}", message) + ); + } + + public static void IsTrue(bool o) + { + IsTrue(o, ""); + } + + public static void IsFalse(bool o) + { + IsFalse(o, ""); + } + + + public static void IsTrue(bool o, string format, params object[] args) + { + string message = String.Format(format, args); + IsTrue(o, message); + } + + public static void IsFalse(bool o, string format, params object[] args) + { + string message = String.Format(format, args); + IsFalse(o, message); + } + #endregion + + #region Lower, etc... + public static void LowerEqualThan(T left, T right) + where T : IComparable + { + LowerEqualThan(left, right, ""); + } + public static void LowerEqualThan(T left, T right, string format, params object[] args) + where T : IComparable + { + string message = String.Format(format, args); + LowerEqualThan(left, right, message); + } + public static void LowerEqualThan(T left, T right, string message) + where T : IComparable + { + if (left.CompareTo(right) > 0) + throw new AssertionException( + String.Format("[{0}]>[{1}], {2}", + left, right, message) + ); + } + #endregion + + #region Fail + public static void Fail() + { + throw new AssertionException(); + } + + public static void Fail(string message) + { + throw new AssertionException(message); + } + + public static void Fail(string format, params object[] args) + { + string message = String.Format(format, args); + Fail(message); + } + #endregion + + #region Ignore + public static void Ignore(string message) + { + throw new IgnoreException(message); + } + + public static void Ignore(string format, params object[] parameters) + { + Ignore(String.Format(format, parameters)); + } + #endregion + + #region Warning + public static void Warning(string message) + { + throw new NotImplementedException(); + } + + public static void Warning(string format, params object[] parameters) + { + Warning(String.Format(format, parameters)); + } + #endregion + + #region + public static void ExpectedException( + Type expectedException, Delegate test, params object[] args) + { + try + { + test.DynamicInvoke(args); + throw new ExceptionNotThrowedException(expectedException); + } + catch (Exception ex) + { + Exception current = ex; + // check if current expection is expecetd or ignored + while (current != null) + { + if (current.GetType() == expectedException) + return; + current = current.InnerException; + } + current = ex; + if (current is TargetInvocationException) + current = current.InnerException; + throw new ExceptionTypeMistmatchException(expectedException, current); + } + } + #endregion + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Assert.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Assert.cs.meta new file mode 100644 index 0000000..6865267 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Assert.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: abb9be8e37f0f4b7b99384514c2b505a +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Assume.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Assume.cs new file mode 100755 index 0000000..ab800d3 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Assume.cs @@ -0,0 +1,20 @@ +using System; +using QuickGraph.Unit.Exceptions; + +namespace QuickGraph.Unit +{ + public static class Assume + { + public static void IsTrue(bool value) + { + if (!value) + throw new AssumptionFailureException(); + } + + public static void IsFalse(bool value) + { + if (value) + throw new AssumptionFailureException(); + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Assume.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Assume.cs.meta new file mode 100644 index 0000000..7ba48d8 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Assume.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: bfa076b39e5fd426391a6d28a525637a +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CollectionAssert.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CollectionAssert.cs new file mode 100755 index 0000000..6162307 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CollectionAssert.cs @@ -0,0 +1,153 @@ +using System; +using System.Collections; +using System.Collections.Generic; + +namespace QuickGraph.Unit +{ + public static class CollectionAssert + { + public static void DoesNotContainKey(IDictionary dictionary, object key) + { + Assert.IsFalse(dictionary.Contains(key), + "Collection contains {0}", key); + } + + public static void DoesNotContainKey(IDictionary dictionary, K value) + { + Assert.IsFalse(dictionary.ContainsKey(value), + "Collection contains {0}", value); + } + + public static void ContainsKey(IDictionary dictionary, object key) + { + Assert.IsTrue(dictionary.Contains(key), + "Collection does not contain {0}", key); + } + + public static void ContainsKey(IDictionary dictionary, K value) + { + Assert.IsTrue(dictionary.ContainsKey(value), + "Collection does not contain {0}", value); + } + + public static void DoesNotContain(IEnumerable collection, object value) + { + foreach(object item in collection) + { + Assert.AreNotEqual(item, value,"Collection contains {0}", value); + } + } + + public static void DoesNotContain(ICollection collection, T value) + { + Assert.IsFalse(collection.Contains(value), + "Collection contains {0}", value); + } + + public static void Contains(ICollection collection, object value) + { + foreach(object item in collection) + { + if (item.Equals(value)) + return; + } + Assert.Fail("Collection does not contains {0}", value); + } + + public static void Contains(ICollection collection, T value) + { + Assert.IsTrue(collection.Contains(value), + "Collection does not contain {0}",value); + } + + public static void AreEqual(ICollection left, ICollection right) + { + AreCountEqual(left, right); + AreElementEqual(left, right); + } + + public static void AreEqual(ICollection left, ICollection right) + { + AreCountEqual(left, right); + AreElementEqual(left, right); + } + + public static void AreCountEqual(ICollection left, ICollection right) + { + Assert.AreEqual(left.Count, right.Count, + "Count is not equal"); + } + + public static void AreCountEqual(ICollection left, ICollection right) + { + Assert.AreEqual(left.Count, right.Count, + "Count is not equal"); + } + + public static void IsCountEqual(int count, ICollection collection) + { + Assert.AreEqual(count, collection.Count, + "collection.Count ({0}) is not equal to {1}", count, collection.Count); + } + + public static void IsCountEqual(int count, ICollection collection) + { + Assert.AreEqual(count, collection.Count, + "collection.Count ({0}) is not equal to {1}", count, collection.Count); + } + + public static void AreElementEqual(IEnumerable left, IEnumerable right) + { + IEnumerator leftEnumerator = left.GetEnumerator(); + IEnumerator rightEnumerator = right.GetEnumerator(); + try + { + int i = 0; + bool moveNext; + do + { + moveNext = leftEnumerator.MoveNext(); + Assert.AreEqual(moveNext, rightEnumerator.MoveNext(), + "Collection have not the same size"); + if (moveNext) + { + Assert.AreEqual(leftEnumerator.Current, rightEnumerator.Current, + "Element {0} is not equal", i); + } + i++; + } while (moveNext); + } + finally + { + IDisposable disposable = leftEnumerator as IDisposable; + if (disposable != null) + disposable.Dispose(); + disposable = rightEnumerator as IDisposable; + if (disposable != null) + disposable.Dispose(); + } + } + + public static void AreElementEqual(IEnumerable left, IEnumerable right) + { + using (IEnumerator leftEnumerator = left.GetEnumerator()) + using (IEnumerator rightEnumerator = right.GetEnumerator()) + { + int i=0; + bool moveNext; + do + { + moveNext = leftEnumerator.MoveNext(); + Assert.AreEqual(moveNext, rightEnumerator.MoveNext(), + "Collection have not the same size"); + if (moveNext) + { + Assert.AreEqual(leftEnumerator.Current, rightEnumerator.Current, + "Element {0} is not equal", i); + } + i++; + } while (moveNext); + } + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CollectionAssert.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CollectionAssert.cs.meta new file mode 100644 index 0000000..1b6de65 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CollectionAssert.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 849a7a1694b924f4bbf684099d76eb1c +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CombinatorialTestAttribute.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CombinatorialTestAttribute.cs new file mode 100755 index 0000000..39faeed --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CombinatorialTestAttribute.cs @@ -0,0 +1,137 @@ +using System; +using System.Collections.Generic; +using System.Reflection; +using QuickGraph.Operations; +using System.IO; +using QuickGraph.Unit.Core; + +namespace QuickGraph.Unit +{ + [AttributeUsage(AttributeTargets.Method, AllowMultiple =false, Inherited =true)] + public sealed class CombinatorialTestAttribute : TestAttributeBase + { + private CombinationType combination = CombinationType.PairWize; + + public CombinatorialTestAttribute() { } + public CombinatorialTestAttribute(CombinationType combination) + { + this.Combination = combination; + } + + public CombinationType Combination + { + get { return this.combination; } + set { this.combination = value; } + } + + public override IEnumerable CreateTests( + IFixture fixture, + MethodInfo method + ) + { + // check parameters + ParameterInfo[] parameters = method.GetParameters(); + if (parameters.Length < 1) + throw new InvalidOperationException("Method "+method.Name+" has not enough parameters"); + + // create the domains for each parameter + List domains = new List(); + Type[] parameterTypes = new Type[parameters.Length]; + for (int index = 0; index < parameters.Length; ++index) + { + ParameterInfo parameter = parameters[index]; + parameterTypes[index] = parameter.ParameterType; + + // get domains for parameter + List pdomains = new List(); + foreach (IParameterDomainFactory parameterDomainFactory + in parameter.GetCustomAttributes(typeof(UsingAttributeBase), true)) + { + try + { + parameterDomainFactory.CreateDomains(pdomains, parameter, fixture); + } + catch (Exception ex) + { + throw new ApplicationException("Failed while loading domains from parameter " + parameter.Name,ex); + } + } + if (pdomains.Count == 0) + throw new ApplicationException("Could not find domain for argument " + parameter.Name); + + domains.Add(Domains.ToDomain(pdomains)); + } + + // we make a cartesian product of all those + foreach (ITuple tuple in Products.Cartesian(domains)) + { + // create data domains + List tdomains = new List(); + for (int i = 0; i < tuple.Count; ++i) + { + IDomain dm = (IDomain)tuple[i]; + tdomains.Add(dm); + } + + // computing the pairwize product + IEnumerable ptproducts = Products.ComputeTupleProducts(tdomains, this.Combination); + + foreach (ITuple ptuple in ptproducts) + { + // tuple is valid, adding test + CombinatorialMethodTestCase test = + new CombinatorialMethodTestCase( + fixture.Name, + method, + tuple, + ptuple); + + yield return test; + } + } + } + + private sealed class CombinatorialMethodTestCase : MethodTestCase + { + private ITuple tupleDomains; + private ITuple tuple; + + public CombinatorialMethodTestCase( + string fixtureName, + MethodInfo method, + ITuple tupleDomains, + ITuple tuple + ) + : base(fixtureName, method) + { + if (tupleDomains == null) + throw new ArgumentNullException("tupleDomains"); + if (tuple == null) + throw new ArgumentNullException("tuple"); + + this.tupleDomains = tupleDomains; + this.tuple = tuple; + + foreach (Object parameter in tuple) + this.Parameters.Add(new TestCaseParameter(parameter)); + } + + public override string Name + { + get + { + StringWriter sw = new StringWriter(); + for (int i = 0; i < this.tupleDomains.Count; ++i) + { + IDomain dm = (IDomain)this.tupleDomains[i]; + if (dm.Name != null) + sw.Write("{0}({1}),", dm.Name, this.tuple[i]); + else + sw.Write("{0},", this.tuple[i]); + } + return String.Format("{0}({1})", this.Method.Name, sw.ToString().TrimEnd(',')); + } + } + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CombinatorialTestAttribute.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CombinatorialTestAttribute.cs.meta new file mode 100644 index 0000000..ad867a5 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CombinatorialTestAttribute.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 6a97e1f14437841fbb2c8261816622f5 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CommandLine.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CommandLine.meta new file mode 100644 index 0000000..f9f2922 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CommandLine.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: 53420897a3fa04aff97e2d3a3bfa7736 +folderAsset: yes +DefaultImporter: + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CommandLine/ArgumentAttribute.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CommandLine/ArgumentAttribute.cs new file mode 100755 index 0000000..b20dcac --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CommandLine/ArgumentAttribute.cs @@ -0,0 +1,49 @@ +using System; +using System.Xml.Serialization; +namespace QuickGraph.CommandLine +{ + [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false)] + public class ArgumentAttribute : Attribute + { + private string longName; + private string shortName; + private string description = ""; + + public ArgumentAttribute() + { } + + public ArgumentAttribute( + string longName, + string shortName, + string description + ) + { + this.longName = longName; + this.shortName = shortName; + this.description = description; + } + + public virtual bool IsDefault + { + get { return false; } + } + + public string LongName + { + get { return this.longName; } + set { this.longName = value; } + } + + public string ShortName + { + get { return this.shortName; } + set { this.shortName = value; } + } + + public string Description + { + get { return this.description; } + set { this.description = value; } + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CommandLine/ArgumentAttribute.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CommandLine/ArgumentAttribute.cs.meta new file mode 100644 index 0000000..05f8bfa --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CommandLine/ArgumentAttribute.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: fff70d57a547a4587ae078413968c87a +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CommandLine/ArgumentParserBase.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CommandLine/ArgumentParserBase.cs new file mode 100755 index 0000000..b9edd13 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CommandLine/ArgumentParserBase.cs @@ -0,0 +1,154 @@ +using System; +using System.Collections.Generic; +using System.Reflection; +using System.IO; + +namespace QuickGraph.CommandLine +{ + internal abstract class ArgumentParserBase : IArgumentParser + { + private string flags = "/-"; + private IMember member; + private ArgumentAttribute argument; + private bool isMultiple; + + public ArgumentParserBase( + IMember member, + ArgumentAttribute argument, + bool isMultiple) + { + if (member == null) + throw new ArgumentNullException("member"); + if (argument==null) + throw new ArgumentNullException("argument"); + this.member = member; + this.argument = argument; + this.isMultiple = isMultiple; + } + + public IMember Member + { + get { return this.member; } + } + public ArgumentAttribute Argument + { + get { return this.argument; } + } + + public bool IsMultiple + { + get { return this.isMultiple; } + } + + public Type ElementType + { + get + { + if (!this.IsMultiple) + return Member.MemberType; + else + return Member.MemberType.GetGenericArguments()[0]; + } + } + + public bool IsFlag(Char c) + { + return this.flags.IndexOf(c) > 0; + } + + public abstract bool Parse(object instance, string arg); + + protected string ExtractValue(string data) + { + if (IsFlag(data[0])) + { + if (this.Argument.IsDefault) + return data; + else + return null; + } + + int index = data.IndexOf(':'); + if (index < 0) + return null; + // check name is correct + string arg = data.Substring(1, index-1); + if (arg != this.Argument.LongName && + arg != this.Argument.ShortName) + return null; + + return data.Substring(index+1); + } + + protected void AssignValue(object instance, object value) + { + if (this.IsMultiple) + this.AddToList(instance, value); + else + this.Member.SetValue(instance, value); + } + + private void AddToList(object instance, object value) + { + MethodInfo addMethod = this.Member.MemberType.GetMethod( + "Add", new Type[] { this.ElementType } + ); + if (addMethod == null) + throw new ArgumentException("Could not find add method for field " + this.Member.Name); + addMethod.Invoke(this.Member.GetValue(instance), new object[] { value }); + } + + + public override string ToString() + { + return String.Format("P[{0}.{1}]", + this.Member.DeclaringType.FullName,this.Member.Name + ); + } + + public virtual void ShowHelp(TextWriter writer) + { + if (this.Argument.IsDefault) + { + writer.WriteLine("{0} (default)\n\tn: {1}\n\t{2}", + this.GetValidValues(), + (this.IsMultiple) ? "multiple" : "once", + this.Argument.Description + ); + } + else + { + writer.WriteLine("/{0}{2}\n/{1}{2}\n\tn: {3}\n\t{4}", + this.Argument.LongName, + this.Argument.ShortName, + this.GetValidValues(), + (this.IsMultiple) ? "multiple" : "once", + this.Argument.Description + ); + } + writer.WriteLine(); + } + + protected virtual string GetValidValues() + { + return String.Format(":<{0}>",this.Member.Name); + } + + public virtual void ShowData(object instance, TextWriter writer) + { + if (this.IsMultiple) + { + writer.WriteLine("{0}:", this.Member.Name); + foreach (object o in this.Member.GetValue(instance) as System.Collections.IEnumerable) + { + writer.WriteLine("\t{0}", o); + } + } + else + writer.WriteLine("{0}:\t{1}", + this.Member.Name, + this.Member.GetValue(instance) + ); + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CommandLine/ArgumentParserBase.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CommandLine/ArgumentParserBase.cs.meta new file mode 100644 index 0000000..2cd99a1 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CommandLine/ArgumentParserBase.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: c42a08566901842e090feaf0beaa8907 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CommandLine/ArgumentParserCollection.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CommandLine/ArgumentParserCollection.cs new file mode 100755 index 0000000..f078dde --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CommandLine/ArgumentParserCollection.cs @@ -0,0 +1,79 @@ +using System; +using System.Collections.Generic; + +namespace QuickGraph.CommandLine +{ + internal class ArgumentParserCollection : List + { + public IArgumentParser GetParserFromShortName(string name) + { + foreach (IArgumentParser parser in this) + { + if (parser.Argument.ShortName == name || + parser.Argument.LongName == name) + return parser; + } + return null; + } + + public IArgumentParser GetDefaultParser() + { + foreach (IArgumentParser parser in this) + { + if (parser.Argument.IsDefault) + return parser; + } + return null; + } + + public bool VerifyParsers() + { + Dictionary namedParsers = new Dictionary(); + IArgumentParser defaultParser = null; + int errorCount = 0; + foreach (IArgumentParser parser in this) + { + if (defaultParser!=null && parser.Argument.IsDefault) + { + Console.WriteLine("Duplicate default argument ({0}, {1})", + defaultParser.Member.Name, + parser.Member.Name); + errorCount++; + continue; + } + + if (parser.Argument.IsDefault) + { + defaultParser = parser; + continue; + } + + if (namedParsers.ContainsKey(parser.Argument.ShortName)) + { + Console.WriteLine("Short name {0} of {1} is a duplicate of {2}", + parser.Argument.ShortName, + parser.Member.Name, + namedParsers[parser.Argument.ShortName].Member.Name + ); + errorCount++; + continue; + } + + if (namedParsers.ContainsKey(parser.Argument.LongName)) + { + Console.WriteLine("Long name {0} of {1} is a duplicate of {2}", + parser.Argument.LongName, + parser.Member.Name, + namedParsers[parser.Argument.ShortName].Member.Name + ); + errorCount++; + continue; + } + } + + if (errorCount != 0) + Console.WriteLine("Found {0} errors", errorCount); + return errorCount == 0; + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CommandLine/ArgumentParserCollection.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CommandLine/ArgumentParserCollection.cs.meta new file mode 100644 index 0000000..a1a3bd9 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CommandLine/ArgumentParserCollection.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: a7abacea9096d46c0910b48f266f6d6a +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CommandLine/ArgumentParserFactory.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CommandLine/ArgumentParserFactory.cs new file mode 100755 index 0000000..5738d4b --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CommandLine/ArgumentParserFactory.cs @@ -0,0 +1,91 @@ +using System; +using System.Collections.Generic; +using System.Reflection; + +namespace QuickGraph.CommandLine +{ + internal static class ArgumentParserFactory + { + public static IArgumentParser Create( + PropertyInfo property, + ArgumentAttribute argument + ) + { + bool isMultiple = property.PropertyType.GetGenericArguments().Length != 0; + if (!isMultiple) + return CreateFromType(property, argument, property.PropertyType, isMultiple); + else + return CreateFromType(property, argument, + property.PropertyType.GetGenericArguments()[0], + isMultiple); + } + + private static IArgumentParser CreateFromType( + PropertyInfo property, + ArgumentAttribute argument, + Type propertyType, + bool isMultiple + ) + { + // is the field type an enum + if (propertyType.IsEnum) + return new EnumArgumentParser(new PropertyMember(property), argument, isMultiple); + if (propertyType == typeof(bool)) + return new BoolArgumentParser(new PropertyMember(property), argument, isMultiple); + if (propertyType == typeof(string)) + return new StringArgumentParser(new PropertyMember(property), argument, isMultiple); + if (propertyType == typeof(int)) + return new IntArgumentParser(new PropertyMember(property), argument, isMultiple); + if (propertyType == typeof(float)) + return new FloatArgumentParser(new PropertyMember(property), argument, isMultiple); + if (propertyType == typeof(long)) + return new LongArgumentParser(new PropertyMember(property), argument, isMultiple); + if (propertyType == typeof(DateTime)) + return new DateTimeArgumentParser(new PropertyMember(property), argument, isMultiple); + + Console.WriteLine("Type {0} is not supported", propertyType); + return null; + } + + public static IArgumentParser Create( + FieldInfo field, + ArgumentAttribute argument + ) + { + bool isMultiple = field.FieldType.GetGenericArguments().Length != 0; + if (!isMultiple) + return CreateFromType(field, argument, field.FieldType, isMultiple); + else + return CreateFromType(field, argument, + field.FieldType.GetGenericArguments()[0], + isMultiple); + } + + private static IArgumentParser CreateFromType( + FieldInfo field, + ArgumentAttribute argument, + Type fieldType, + bool isMultiple + ) + { + // is the field type an enum + if (fieldType.IsEnum) + return new EnumArgumentParser(new FieldMember(field), argument, isMultiple); + if (fieldType == typeof(bool)) + return new BoolArgumentParser(new FieldMember(field), argument, isMultiple); + if (fieldType == typeof(string)) + return new StringArgumentParser(new FieldMember(field), argument, isMultiple); + if (fieldType == typeof(int)) + return new IntArgumentParser(new FieldMember(field), argument, isMultiple); + if (fieldType == typeof(float)) + return new FloatArgumentParser(new FieldMember(field), argument, isMultiple); + if (fieldType == typeof(long)) + return new LongArgumentParser(new FieldMember(field), argument, isMultiple); + if (fieldType == typeof(DateTime)) + return new DateTimeArgumentParser(new FieldMember(field), argument, isMultiple); + + Console.WriteLine("Type {0} is not supported", fieldType); + return null; + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CommandLine/ArgumentParserFactory.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CommandLine/ArgumentParserFactory.cs.meta new file mode 100644 index 0000000..330f1e4 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CommandLine/ArgumentParserFactory.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 353a0b08f58914e3bb3b7b86457c5bf2 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CommandLine/ArgumentsBase.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CommandLine/ArgumentsBase.cs new file mode 100755 index 0000000..bffdcae --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CommandLine/ArgumentsBase.cs @@ -0,0 +1,19 @@ +using System; + +namespace QuickGraph.CommandLine +{ + public abstract class ArgumentsBase + { + [Argument( + ShortName="h", + LongName="help", + Description="display this message")] + public bool Help = false; + + [Argument( + ShortName="sd", + LongName="show-data", + Description="displays the parsed data")] + public bool ShowData = false; + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CommandLine/ArgumentsBase.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CommandLine/ArgumentsBase.cs.meta new file mode 100644 index 0000000..7ac73ff --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CommandLine/ArgumentsBase.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 0e375a3538ab64a0d91d20ae3e921e15 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CommandLine/BoolArgumentParser.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CommandLine/BoolArgumentParser.cs new file mode 100755 index 0000000..0cb37b9 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CommandLine/BoolArgumentParser.cs @@ -0,0 +1,53 @@ +using System; +using System.Reflection; + +namespace QuickGraph.CommandLine +{ + internal sealed class BoolArgumentParser : ArgumentParserBase + { + public BoolArgumentParser( + IMember member, + ArgumentAttribute argument, + bool isMultiple) + :base(member,argument,isMultiple) + { } + + public override bool Parse(object instance, string arg) + { + if (IsFlag(arg[0])) + return false; + + bool value = true; + int index = -1; + switch (arg[arg.Length - 1]) + { + case '+': + value = true; + index = arg.Length - 1; + break; + case '-': + value = false; + index = arg.Length - 1; + break; + default: + index = arg.Length; + break; + } + + // check name is correct + string name = arg.Substring(1, index - 1); + if (name != this.Argument.LongName && + name != this.Argument.ShortName) + return false; + + // assign value + this.AssignValue(instance, value); + return true; + } + + protected override string GetValidValues() + { + return "[+-]"; + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CommandLine/BoolArgumentParser.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CommandLine/BoolArgumentParser.cs.meta new file mode 100644 index 0000000..cc562fa --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CommandLine/BoolArgumentParser.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 4bf7e7b294dde49d4b4ccd9d9621ca55 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CommandLine/CommandLineParser.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CommandLine/CommandLineParser.cs new file mode 100755 index 0000000..663e7b4 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CommandLine/CommandLineParser.cs @@ -0,0 +1,144 @@ +using System; +using System.Reflection; +using System.Collections.Generic; +using System.IO; + +namespace QuickGraph.CommandLine +{ + public sealed class CommandLineParser + where T : new() + { + private ArgumentParserCollection argumentParsers = new ArgumentParserCollection(); + + public static CommandLineParser Create() + { + CommandLineParser parser = new CommandLineParser(); + if (parser.ArgumentParsers.VerifyParsers()) + return parser; + else + return null; + } + + private CommandLineParser() + { + this.ReflectCommandLineType(); + } + + public Type CommandLineType + { + get { return typeof(T); } + } + + internal ArgumentParserCollection ArgumentParsers + { + get { return this.argumentParsers; } + } + + private static ArgumentAttribute GetAttribute(ICustomAttributeProvider t) + { + if (t == null) + throw new ArgumentNullException("t"); + + // Gets the attributes for the property. + Object[] attributes = + t.GetCustomAttributes(typeof(ArgumentAttribute), true); + + if (attributes.Length == 0) + return null; + if (attributes.Length == 1) + return (ArgumentAttribute)attributes[0]; + + throw new ArgumentException("Attribute type must be AllowMultiple = false", typeof(T).FullName); + } + + private void ReflectCommandLineType() + { + // get fields + foreach (FieldInfo field in typeof(T).GetFields()) + { + ArgumentAttribute attribute = GetAttribute(field); + if (attribute == null) + continue; + IArgumentParser parser = ArgumentParserFactory.Create(field, attribute); + if (parser == null) + throw new ArgumentException("Could not reflect " + field.Name); + this.ArgumentParsers.Add(parser); + } + + foreach (PropertyInfo property in typeof(T).GetProperties()) + { + ArgumentAttribute attribute = GetAttribute(property); + if (attribute == null) + continue; + IArgumentParser parser = ArgumentParserFactory.Create(property, attribute); + if (parser == null) + throw new ArgumentException("Could not reflect " + property.Name); + this.ArgumentParsers.Add(parser); + } + } + + public void ShowHelp() + { + ShowHelp(Console.Out); + } + + public void ShowHelp(TextWriter writer) + { + foreach (IArgumentParser parser in this.ArgumentParsers) + parser.ShowHelp(writer); + } + + public bool Parse(T arguments, IEnumerable args) + { + if (arguments == null) + throw new ArgumentNullException("arguments"); + + Dictionary touchedParsers = new Dictionary(); + foreach (string arg in args) + { + bool foundparser = false; + foreach (IArgumentParser parser in this.ArgumentParsers) + { + if (parser.Parse(arguments, arg)) + { + foundparser = true; + if (!parser.IsMultiple) + { + // did we already see this value + if (touchedParsers.ContainsKey(parser)) + { + // we found twice a non multiple value + throw new ArgumentException("Multiple value found", arg); + } + else + { + touchedParsers.Add(parser, null); + } + } + break; + } + } + if (!foundparser) + { + Console.WriteLine("Could not interpret {0}", arg); + return false; + } + } + + return true; + } + + public void ShowData(T arguments) + { + ShowData(arguments, Console.Out); + } + + public void ShowData(T arguments, TextWriter writer) + { + if (arguments == null) + throw new ArgumentNullException("arguments"); + foreach (IArgumentParser parser in this.ArgumentParsers) + parser.ShowData(arguments, writer); + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CommandLine/CommandLineParser.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CommandLine/CommandLineParser.cs.meta new file mode 100644 index 0000000..91880f6 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CommandLine/CommandLineParser.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 4ecc8ab8cb4b34c30a6d754be3542d10 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CommandLine/ConsoleLog.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CommandLine/ConsoleLog.cs new file mode 100755 index 0000000..2c30c45 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CommandLine/ConsoleLog.cs @@ -0,0 +1,97 @@ +using System; + +namespace QuickGraph.CommandLine +{ + public static class ConsoleLog + { + private static ConsoleColor warningColor = ConsoleColor.Yellow; + private static ConsoleColor errorColor = ConsoleColor.Red; + private static ConsoleColor commentColor = ConsoleColor.DarkGray; + + public static ConsoleColor WarningColor + { + get { return warningColor; } + set { warningColor = value; } + } + + public static ConsoleColor ErrorColor + { + get { return errorColor; } + set { errorColor = value; } + } + + public static ConsoleColor CommentColor + { + get { return commentColor; } + set { commentColor = value; } + } + + public static void Message(string message) + { + Console.WriteLine(message); + } + + public static void Message(string format, params object[] args) + { + Console.WriteLine(format, args); + } + + public static void Warning(string message) + { + Log(WarningColor, message); + } + + public static void Warning(string format, params object[] args) + { + Log(WarningColor, format, args); + } + + public static void Error(string message) + { + Log(ErrorColor, message); + } + + public static void Error(string format, params object[] args) + { + Log(ErrorColor, format, args); + } + + public static void Comment(string message) + { + Log(CommentColor, message); + } + + public static void Comment(string format, params object[] args) + { + Log(CommentColor, format, args); + } + + public static void Log(ConsoleColor color, string message) + { + ConsoleColor currentColor = Console.ForegroundColor; + try + { + Console.ForegroundColor = color; + Console.WriteLine(message); + } + finally + { + Console.ForegroundColor = currentColor; + } + } + + public static void Log(ConsoleColor color, string format, params object[] args) + { + ConsoleColor currentColor = Console.ForegroundColor; + try + { + Console.ForegroundColor = color; + Console.WriteLine(format, args); + } + finally + { + Console.ForegroundColor = currentColor; + } + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CommandLine/ConsoleLog.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CommandLine/ConsoleLog.cs.meta new file mode 100644 index 0000000..d9a44b3 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CommandLine/ConsoleLog.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d15ab477532774213895bea9c80fa6d7 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CommandLine/DateTimeArgumentParser.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CommandLine/DateTimeArgumentParser.cs new file mode 100755 index 0000000..98286ea --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CommandLine/DateTimeArgumentParser.cs @@ -0,0 +1,24 @@ +using System; +using System.Reflection; + +namespace QuickGraph.CommandLine +{ + internal sealed class DateTimeArgumentParser : ArgumentParserBase + { + public DateTimeArgumentParser( + IMember member, + ArgumentAttribute argument, + bool isMultiple) + : base(member, argument, isMultiple) + { } + + public override bool Parse(object instance, string arg) + { + string value = this.ExtractValue(arg); + if (value == null) + return false; + this.AssignValue(instance, DateTime.Parse(value)); + return true; + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CommandLine/DateTimeArgumentParser.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CommandLine/DateTimeArgumentParser.cs.meta new file mode 100644 index 0000000..c16876b --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CommandLine/DateTimeArgumentParser.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: c2b39b3a0154f49bd9815c7ef0c3fdb2 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CommandLine/DefaultArgumentAttribute.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CommandLine/DefaultArgumentAttribute.cs new file mode 100755 index 0000000..870848b --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CommandLine/DefaultArgumentAttribute.cs @@ -0,0 +1,18 @@ +using System; + +namespace QuickGraph.CommandLine +{ + [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false)] + public sealed class DefaultArgumentAttribute : ArgumentAttribute + { + public DefaultArgumentAttribute(string description) + { + this.Description = description; + } + + public override bool IsDefault + { + get { return true; } + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CommandLine/DefaultArgumentAttribute.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CommandLine/DefaultArgumentAttribute.cs.meta new file mode 100644 index 0000000..1c53de8 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CommandLine/DefaultArgumentAttribute.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d3bd340d70bfb44658aab46496cfa49c +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CommandLine/EnumArgumentParser.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CommandLine/EnumArgumentParser.cs new file mode 100755 index 0000000..5b60546 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CommandLine/EnumArgumentParser.cs @@ -0,0 +1,44 @@ +using System; +using System.Reflection; +using System.IO; + +namespace QuickGraph.CommandLine +{ + internal sealed class EnumArgumentParser : ArgumentParserBase + { + public EnumArgumentParser( + IMember member, + ArgumentAttribute argument, + bool isMultiple) + :base(member,argument,isMultiple) + {} + + public override bool Parse(object instance, string arg) + { + string value = this.ExtractValue(arg); + if (value==null) + return false; + this.AssignValue(instance, Enum.Parse(this.ElementType,value,true)); + return true; + } + + protected override string GetValidValues() + { + StringWriter sw = new StringWriter(); + sw.Write(":["); + bool first = true; + foreach (Object value in Enum.GetValues(this.ElementType)) + { + if (!first) + sw.Write(",{0}",value); + else + { + sw.Write("{0}", value); + first = false; + } + } + sw.Write("]"); + return sw.ToString(); + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CommandLine/EnumArgumentParser.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CommandLine/EnumArgumentParser.cs.meta new file mode 100644 index 0000000..a34fa9a --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CommandLine/EnumArgumentParser.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: a9317e72c7f7a4399aec2aad9e80eec7 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CommandLine/FieldMember.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CommandLine/FieldMember.cs new file mode 100755 index 0000000..caa1b24 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CommandLine/FieldMember.cs @@ -0,0 +1,39 @@ +using System; +using System.Reflection; + +namespace QuickGraph.CommandLine +{ + internal sealed class FieldMember : IMember + { + private FieldInfo field; + public FieldMember(FieldInfo field) + { + this.field = field; + } + + public string Name + { + get { return this.field.Name; } + } + + public Type DeclaringType + { + get { return this.field.DeclaringType; } + } + + public Type MemberType + { + get { return this.field.FieldType; } + } + + public object GetValue(object instance) + { + return this.field.GetValue(instance); + } + + public void SetValue(object instance, object value) + { + this.field.SetValue(instance, value); + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CommandLine/FieldMember.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CommandLine/FieldMember.cs.meta new file mode 100644 index 0000000..319677f --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CommandLine/FieldMember.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 2ce5eeaf95f274564b0c6feb3afcd00a +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CommandLine/FloatArgumentParser.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CommandLine/FloatArgumentParser.cs new file mode 100755 index 0000000..e2ee515 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CommandLine/FloatArgumentParser.cs @@ -0,0 +1,24 @@ +using System; +using System.Reflection; + +namespace QuickGraph.CommandLine +{ + internal sealed class FloatArgumentParser : ArgumentParserBase + { + public FloatArgumentParser( + IMember member, + ArgumentAttribute argument, + bool isMultiple) + : base(member, argument, isMultiple) + { } + + public override bool Parse(object instance, string arg) + { + string value = this.ExtractValue(arg); + if (value == null) + return false; + this.AssignValue(instance, float.Parse(value)); + return true; + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CommandLine/FloatArgumentParser.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CommandLine/FloatArgumentParser.cs.meta new file mode 100644 index 0000000..664ab9d --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CommandLine/FloatArgumentParser.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b6a2f2a3f80ff4e9d928af31e89ba7ce +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CommandLine/IArgumentParser.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CommandLine/IArgumentParser.cs new file mode 100755 index 0000000..c41a2ef --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CommandLine/IArgumentParser.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Reflection; +using System.IO; + +namespace QuickGraph.CommandLine +{ + internal interface IArgumentParser + { + IMember Member { get;} + ArgumentAttribute Argument { get;} + bool IsMultiple { get;} + + bool Parse(object instance, string arg); + void ShowHelp(TextWriter writer); + void ShowData(object instance, TextWriter writer); + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CommandLine/IArgumentParser.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CommandLine/IArgumentParser.cs.meta new file mode 100644 index 0000000..8bcc511 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CommandLine/IArgumentParser.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 392fbf36ef3f643b09fb86a08f56baa3 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CommandLine/IMember.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CommandLine/IMember.cs new file mode 100755 index 0000000..fc96c62 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CommandLine/IMember.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace QuickGraph.CommandLine +{ + internal interface IMember + { + string Name { get;} + Type DeclaringType { get;} + Type MemberType { get;} + object GetValue(object instance); + void SetValue(object instance, object value); + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CommandLine/IMember.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CommandLine/IMember.cs.meta new file mode 100644 index 0000000..c2110f7 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CommandLine/IMember.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 1065426ca804440d9bc6019238d9cb0a +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CommandLine/IntArgumentParser.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CommandLine/IntArgumentParser.cs new file mode 100755 index 0000000..8a20cbf --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CommandLine/IntArgumentParser.cs @@ -0,0 +1,24 @@ +using System; +using System.Reflection; + +namespace QuickGraph.CommandLine +{ + internal sealed class IntArgumentParser : ArgumentParserBase + { + public IntArgumentParser( + IMember member, + ArgumentAttribute argument, + bool isMultiple) + :base(member,argument,isMultiple) + {} + + public override bool Parse(object instance, string arg) + { + string value = this.ExtractValue(arg); + if (value == null) + return false; + this.AssignValue(instance, int.Parse(value)); + return true; + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CommandLine/IntArgumentParser.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CommandLine/IntArgumentParser.cs.meta new file mode 100644 index 0000000..8e605b4 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CommandLine/IntArgumentParser.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 440a5cb6ed71f4526a89add7981ffea7 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CommandLine/LongArgumentParser.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CommandLine/LongArgumentParser.cs new file mode 100755 index 0000000..0642714 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CommandLine/LongArgumentParser.cs @@ -0,0 +1,24 @@ +using System; +using System.Reflection; + +namespace QuickGraph.CommandLine +{ + internal sealed class LongArgumentParser : ArgumentParserBase + { + public LongArgumentParser( + IMember member, + ArgumentAttribute argument, + bool isMultiple) + : base(member, argument, isMultiple) + { } + + public override bool Parse(object instance, string arg) + { + string value = this.ExtractValue(arg); + if (value == null) + return false; + this.AssignValue(instance, long.Parse(value)); + return true; + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CommandLine/LongArgumentParser.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CommandLine/LongArgumentParser.cs.meta new file mode 100644 index 0000000..e65afcd --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CommandLine/LongArgumentParser.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: a3ab7f555275b437db245c0280b4f324 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CommandLine/PropertyMember.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CommandLine/PropertyMember.cs new file mode 100755 index 0000000..e1f77fb --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CommandLine/PropertyMember.cs @@ -0,0 +1,40 @@ +using System; +using System.Reflection; + +namespace QuickGraph.CommandLine +{ + internal sealed class PropertyMember : IMember + { + private PropertyInfo property; + + public PropertyMember(PropertyInfo property) + { + this.property = property; + } + + public string Name + { + get { return this.property.Name; } + } + + public Type DeclaringType + { + get { return this.property.DeclaringType; } + } + + public Type MemberType + { + get { return this.property.PropertyType; } + } + + public object GetValue(object instance) + { + return this.property.GetValue(instance, null); + } + + public void SetValue(object instance, object value) + { + this.property.SetValue(instance, value, null); + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CommandLine/PropertyMember.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CommandLine/PropertyMember.cs.meta new file mode 100644 index 0000000..4557ec5 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CommandLine/PropertyMember.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 145275698c3cb4a04957adb72233eb5e +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CommandLine/StringArgumentParser.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CommandLine/StringArgumentParser.cs new file mode 100755 index 0000000..cf61820 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CommandLine/StringArgumentParser.cs @@ -0,0 +1,25 @@ +using System; +using System.Reflection; + +namespace QuickGraph.CommandLine +{ + internal sealed class StringArgumentParser : ArgumentParserBase + { + public StringArgumentParser( + IMember member, + ArgumentAttribute argument, + bool isMultiple) + :base(member,argument,isMultiple) + {} + + public override bool Parse(object instance, string arg) + { + string value = this.ExtractValue(arg); + if (value == null) + return false; + value = value.Trim('"'); + this.AssignValue(instance, value); + return true; + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CommandLine/StringArgumentParser.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CommandLine/StringArgumentParser.cs.meta new file mode 100644 index 0000000..4eff3c3 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CommandLine/StringArgumentParser.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 8351c8205e2444b64a5fe701257f3cbb +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CompilerAssert.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CompilerAssert.cs new file mode 100755 index 0000000..9966f61 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CompilerAssert.cs @@ -0,0 +1,365 @@ +using System; +using System.Collections; +using System.CodeDom.Compiler; +using System.IO; +using System.Collections.Specialized; +using System.Text.RegularExpressions; +using Microsoft.CSharp; +using Microsoft.VisualBasic; +using QuickGraph.Unit.Exceptions; + +namespace QuickGraph.Unit +{ + public static class CompilerAssert + { + #region Compilers + private static CodeDomProvider csharp; + private static CodeDomProvider vb; + /// + /// Gets the C# compiler from . + /// + /// + /// C# compiler. + /// + public static CodeDomProvider CSharpProvider + { + get + { + if (csharp==null) + csharp = new CSharpCodeProvider(); + return csharp; + } + } + + /// + /// Gets the VB.NET compiler from . + /// + /// + /// VB.NET compiler. + /// + public static CodeDomProvider VBProvider + { + get + { + if (vb==null) + vb = new VBCodeProvider(); + return vb; + } + } + #endregion + + /// + /// Verifies that compiles using the provided compiler. + /// + /// Compiler instance + /// Source code to compile + public static CompilerResults Compiles(CodeDomProvider provider, string source) + { + Assert.IsNotNull(provider); + Assert.IsNotNull(source); + CompilerParameters ps = new CompilerParameters(); + ps.GenerateInMemory = true; + return Compiles(provider, ps, source); + } + + /// + /// Verifies that compiles using the provided compiler. + /// + /// Compiler instance + /// Source code to compile + public static CompilerResults Compiles(CodeDomProvider provider, Stream source) + { + Assert.IsNotNull(provider); + Assert.IsNotNull(source); + CompilerParameters ps = new CompilerParameters(); + return Compiles(provider, ps, source); + } + + /// + /// Verifies that compiles using the provided compiler. + /// + /// Compiler instance + /// Referenced assemblies + /// Source code to compile + public static CompilerResults Compiles(CodeDomProvider provider, StringCollection references, string source) + { + Assert.IsNotNull(provider); + Assert.IsNotNull(references); + Assert.IsNotNull(source); + CompilerParameters ps = new CompilerParameters(); + foreach (string ra in references) + ps.ReferencedAssemblies.Add(ra); + + return Compiles(provider, ps, source); + } + + /// + /// Verifies that compiles using the provided compiler. + /// + /// + /// instance. + /// Compilation options + /// source to compile + public static CompilerResults Compiles(CodeDomProvider provider, CompilerParameters options, string source) + { + Assert.IsNotNull(provider); + Assert.IsNotNull(options); + Assert.IsNotNull(source); + return Compiles(provider, options, source, false); + } + + /// + /// Verifies that compiles using the provided compiler. + /// + /// + /// instance. + /// Compilation options + /// Source to compile + /// + /// true if assertion should throw if any warning. + /// + public static CompilerResults Compiles(CodeDomProvider provider, CompilerParameters options, string source, bool throwOnWarning) + { + Assert.IsNotNull(provider); + Assert.IsNotNull(options); + CompilerResults results = provider.CompileAssemblyFromSource(options, source); + if (results.Errors.HasErrors) + { + DisplaySource(source); + DisplayErrors(results, Console.Out); + throw new CompilationException(provider, options, results, source); + } + if (throwOnWarning && results.Errors.HasWarnings) + { + DisplaySource(source); + DisplayErrors(results, Console.Out); + throw new CompilationException(provider, options, results, source); + } + return results; + } + + /// + /// Verifies that compiles using the provided compiler. + /// + /// + /// instance. + /// Compilation options + /// Stream containing the source to compile + public static CompilerResults Compiles(CodeDomProvider provider, CompilerParameters options, Stream source) + { + return Compiles(provider, options, source, false); + } + + /// + /// Verifies that compiles using the provided compiler. + /// + /// + /// instance. + /// Compilation options + /// Stream containing the source to compile + /// + /// true if assertion should throw if any warning. + /// + public static CompilerResults Compiles(CodeDomProvider provider, CompilerParameters options, Stream source, bool throwOnWarning) + { + using (StreamReader sr = new StreamReader(source)) + { + return Compiles(provider, options, sr.ReadToEnd(), throwOnWarning); + } + } + + private static void RunResults(CompilerResults results, int expectedExitCode) + { + System.Reflection.MethodInfo main = results.CompiledAssembly.EntryPoint; + Assert.IsNotNull(main, + "Could not find entry point method"); + + int exitCode = (int)main.Invoke(null, new Object[] { new string[0] }); + Assert.AreEqual(expectedExitCode, exitCode); + } + + public static void CompilesAndRun( + CodeDomProvider provider, + CompilerParameters options, + string source, + int expectedExitCode + ) + { + options.GenerateInMemory = true; + options.GenerateExecutable = true; + CompilerResults results = Compiles(provider, options, source); + RunResults(results, expectedExitCode); + } + + + + public static void CompilesAndRun( + CodeDomProvider provider, + CompilerParameters options, + Stream source, + int expectedExitCode + ) + { + options.GenerateInMemory = true; + options.GenerateExecutable = true; + CompilerResults results = Compiles(provider, options, source); + RunResults(results, expectedExitCode); + } + + public static void CompilesAndRun( + CodeDomProvider provider, + string source, + int expectedExitCode + ) + { + CompilerParameters options = new CompilerParameters(); + options.GenerateInMemory = true; + options.GenerateExecutable = true; + + CompilerResults results = Compiles(provider, options, source); + RunResults(results,expectedExitCode); + } + + public static string InsertLineNumbers(string source) + { + Regex regex = new Regex("\n"); + LineCounter counter = new LineCounter(); + return "000 "+regex.Replace(source, new MatchEvaluator(counter.AddLineCount)); + } + + private sealed class LineCounter + { + public int lineCount = 0; + public string AddLineCount(Match m) + { + lineCount++; + return String.Format("{1}{0:000} ", lineCount, m); + } + } + + /// + /// Verifies that does not compile using the provided compiler. + /// + /// + /// instance. + /// Source to compile + public static void NotCompiles( + CodeDomProvider provider, + string source) + { + CompilerParameters options = new CompilerParameters(); + options.GenerateInMemory = false; + NotCompiles(provider, options, source); + } + + /// + /// Verifies that does not compile using the provided compiler. + /// + /// + /// instance. + /// Source to compile + public static void NotCompiles( + CodeDomProvider provider, + Stream source) + { + CompilerParameters options = new CompilerParameters(); + options.GenerateInMemory = false; + NotCompiles(provider, options, source); + } + + /// + /// Verifies that does not compile using the provided compiler. + /// + /// + /// instance. + /// Collection of referenced assemblies + /// Source to compile + public static void NotCompiles( + CodeDomProvider provider, + StringCollection referencedAssemblies, + string source) + { + CompilerParameters options = new CompilerParameters(); + CompilerParameters ps = new CompilerParameters(); + foreach (string ra in referencedAssemblies) + ps.ReferencedAssemblies.Add(ra); + NotCompiles(provider, options, source); + } + + /// + /// Verifies that does not compile using the provided compiler. + /// + /// + /// instance. + /// Compilation options + /// Source to compile + public static void NotCompiles( + CodeDomProvider provider, + CompilerParameters options, + string source) + { + if (provider == null) + throw new ArgumentNullException("provider"); + if (options == null) + throw new ArgumentNullException("options"); + CompilerResults results = provider.CompileAssemblyFromSource(options, source); + if (!results.Errors.HasErrors) + throw new CompilationException(provider, options, results, source); + } + + /// + /// Verifies that does not compile using the provided compiler. + /// + /// + /// instance. + /// Compilation options + /// Source to compile + public static void NotCompiles( + CodeDomProvider provider, + CompilerParameters options, + Stream source) + { + using (StreamReader sr = new StreamReader(source)) + { + NotCompiles(provider, options, sr.ReadToEnd()); + } + } + + public static void DisplaySource(string source) + { + Console.WriteLine(InsertLineNumbers(source)); + } + + public static void DisplayErrors(CompilerResults results, TextWriter writer) + { + Console.WriteLine("Errors"); + foreach (CompilerError error in results.Errors) + { + if (error.IsWarning) + continue; + writer.WriteLine( + "{0} ({1},{2}): {3} {4}", + error.FileName, + error.Line, + error.Column, + error.ErrorNumber, + error.ErrorText); + } + + Console.WriteLine(); + Console.WriteLine("Warnings"); + foreach (CompilerError error in results.Errors) + { + if (!error.IsWarning) + continue; + writer.WriteLine( + "{0} ({1},{2}): {3} {4}", + error.FileName, + error.Line, + error.Column, + error.ErrorNumber, + error.ErrorText); + } + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CompilerAssert.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CompilerAssert.cs.meta new file mode 100644 index 0000000..9733873 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CompilerAssert.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: a5f10e41e70b5486faeadcb53451bf59 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core.meta new file mode 100644 index 0000000..c2c2333 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: 4613df6d389584e4f9337fdecc1930cc +folderAsset: yes +DefaultImporter: + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/BadFixture.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/BadFixture.cs new file mode 100755 index 0000000..9587567 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/BadFixture.cs @@ -0,0 +1,56 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace QuickGraph.Unit.Core +{ + public sealed class BadFixture : FixtureBase + { + private string name; + private string message; + private Exception exception; + + public BadFixture(string name, Exception exception) + : this(name, exception.Message) + { + this.exception = exception; + } + + public BadFixture(string name, string message) + : base(System.Threading.ApartmentState.Unknown,1, message) + { + this.name = name; + this.message = message; + } + + public override object CreateInstance() + { + return null; + } + + public override string Name + { + get { return this.name; } + } + + public string Message + { + get { return this.message; } + } + + public Exception Exception + { + get { return this.exception; } + } + + public override IEnumerable CreateTestCases() + { + yield return new BadTestCase( + this.Name, + "ErrorLoadingFixture", + this.message, + this.Exception + ); + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/BadFixture.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/BadFixture.cs.meta new file mode 100644 index 0000000..b81b369 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/BadFixture.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 096e4cd287f5a4086b249243e91ae1f5 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/BadTestCase.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/BadTestCase.cs new file mode 100755 index 0000000..9799ba8 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/BadTestCase.cs @@ -0,0 +1,56 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace QuickGraph.Unit.Core +{ + public sealed class BadTestCase : ITestCase + { + private string fixtureName; + private string name; + private string message; + private Exception exception; + private List parameters = new List(); + + public BadTestCase( + string fixtureName, + string name, + string message, + Exception exception + ) + { + this.fixtureName = fixtureName; + this.name = name; + this.message = message; + this.exception = exception; + } + + public string FixtureName + { + get { return this.fixtureName; } + } + public string Name + { + get { return this.name; } + } + public string FullName + { + get { return String.Format("{0}.{1}", this.FixtureName, this.Name); } + } + public IList Parameters + { + get { return this.parameters; } + } + + public void Run(Object fixture) + { + if (this.exception!=null) + throw new Exceptions.FixtureReflectionFailedException( + this.message, + this.exception); + else + throw new Exceptions.FixtureReflectionFailedException( + this.message); + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/BadTestCase.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/BadTestCase.cs.meta new file mode 100644 index 0000000..454ff34 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/BadTestCase.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 11a92178e0b214e51b8b1d59dc80d08f +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/DataProviderAttributeBase.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/DataProviderAttributeBase.cs new file mode 100755 index 0000000..4d0351c --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/DataProviderAttributeBase.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Xml; +using System.Xml.XPath; + +namespace QuickGraph.Unit.Core +{ + [AttributeUsage(AttributeTargets.Class, AllowMultiple=true, Inherited=true)] + public abstract class DataProviderAttributeBase : Attribute, + IDataProvider + { + public abstract IXPathNavigable GetData(); + public abstract string Name { get;} + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/DataProviderAttributeBase.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/DataProviderAttributeBase.cs.meta new file mode 100644 index 0000000..92c00d2 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/DataProviderAttributeBase.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b0579e06b46bf4b1b9e3980a905cb27a +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/DataTestCase.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/DataTestCase.cs new file mode 100755 index 0000000..266f771 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/DataTestCase.cs @@ -0,0 +1,21 @@ +using System; +using System.Reflection; +using System.Xml.XPath; +using System.IO; + +namespace QuickGraph.Unit.Core +{ + public sealed class DataTestCase :MethodTestCase + { + public DataTestCase( + string fixtureName, + MethodInfo method, + XPathNavigator node, + string nodeName + ) + : base(fixtureName, method) + { + this.Parameters.Add(new TestCaseParameter(nodeName, node)); + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/DataTestCase.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/DataTestCase.cs.meta new file mode 100644 index 0000000..4d79df1 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/DataTestCase.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: dd1a243edf64a4f1fa1a61ba11a632ac +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/DecoratorTestCaseBase.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/DecoratorTestCaseBase.cs new file mode 100755 index 0000000..273461a --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/DecoratorTestCaseBase.cs @@ -0,0 +1,43 @@ +using System; +using System.Collections.Generic; + +namespace QuickGraph.Unit.Core +{ + public abstract class DecoratorTestCaseBase : ITestCase + { + private ITestCase testCase; + public DecoratorTestCaseBase(ITestCase testCase) + { + if (testCase == null) + throw new ArgumentNullException("testCase"); + this.testCase = testCase; + } + + public ITestCase TestCase + { + get { return this.testCase; } + } + + public string FullName + { + get { return String.Format("{0}.{1}", this.FixtureName, this.Name); } + } + + public virtual string Name + { + get { return this.TestCase.Name; } + } + + public string FixtureName + { + get { return this.testCase.FixtureName; } + } + + public IList Parameters + { + get { return this.TestCase.Parameters; } + } + + public abstract void Run(Object fixture); + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/DecoratorTestCaseBase.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/DecoratorTestCaseBase.cs.meta new file mode 100644 index 0000000..172437c --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/DecoratorTestCaseBase.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: a0bdc3867069a4c6a94eb86538c478d8 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/DelegateTestCase.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/DelegateTestCase.cs new file mode 100755 index 0000000..1e95407 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/DelegateTestCase.cs @@ -0,0 +1,34 @@ +using System; +using System.Collections.Generic; +using System.IO; + +namespace QuickGraph.Unit.Core +{ + public class DelegateTestCase : TestCaseBase + { + private Delegate testDelegate; + + public DelegateTestCase(string fixtureName, Delegate testDelegate, params object[] args) + : base(fixtureName) + { + this.testDelegate = testDelegate; + foreach (Object arg in args) + this.Parameters.Add(new TestCaseParameter(arg)); + } + + public Delegate TestDelegate + { + get { return this.testDelegate; } + } + + public override string UndecoratedName + { + get { return this.testDelegate.Method.Name; } + } + + public override void Run(Object fixture) + { + this.testDelegate.DynamicInvoke(TestCaseParameter.GetValues(this.Parameters)); + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/DelegateTestCase.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/DelegateTestCase.cs.meta new file mode 100644 index 0000000..f3a8565 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/DelegateTestCase.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: f956b616c48e443e38801c62ef43144c +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/FixtureBase.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/FixtureBase.cs new file mode 100755 index 0000000..7a3cf2d --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/FixtureBase.cs @@ -0,0 +1,90 @@ +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Threading; + +namespace QuickGraph.Unit.Core +{ + public abstract class FixtureBase : IFixture + { + private ApartmentState apartment; + private int timeOut; + private string description = null; + private bool isCurrent = false; + private List testCaseDecorators = new List(); + private List categories = new List(); + private MethodInfo fixtureSetup; + private MethodInfo fixtureTearDown; + private MethodInfo setUp; + private MethodInfo tearDown; + + public FixtureBase(ApartmentState apartment, int timeOut, string description) + { + this.apartment = apartment; + this.timeOut = timeOut; + this.description = description; + } + + public ApartmentState Apartment + { + get { return this.apartment; } + } + + public int TimeOut + { + get { return this.timeOut; } + } + + public string Description + { + get { return this.description; } + set { this.description = value; } + } + + public bool IsCurrent + { + get { return this.isCurrent; } + set { this.isCurrent = value; } + } + + public IList Categories + { + get { return this.categories; } + } + + public IList TestCaseDecorators + { + get { return this.testCaseDecorators; } + } + + public MethodInfo FixtureSetUp + { + get { return this.fixtureSetup; } + set { this.fixtureSetup = value; } + } + public MethodInfo SetUp + { + get { return this.setUp; } + set { this.setUp = value; } + } + public MethodInfo TearDown + { + get { return this.tearDown; } + set { this.tearDown = value; } + } + public MethodInfo FixtureTearDown + { + get { return this.fixtureTearDown; } + set { this.fixtureTearDown = value; } + } + + public abstract string Name {get;} + public abstract Object CreateInstance(); + public abstract IEnumerable CreateTestCases(); + + public override string ToString() + { + return this.Name; + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/FixtureBase.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/FixtureBase.cs.meta new file mode 100644 index 0000000..fbd8728 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/FixtureBase.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: cabd14386a9bc4ee3b376ad6a513fb59 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/FixtureRunner.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/FixtureRunner.cs new file mode 100755 index 0000000..8e65f59 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/FixtureRunner.cs @@ -0,0 +1,388 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Reflection; +using System.CodeDom.Compiler; +using QuickGraph.Unit.Exceptions; +using QuickGraph.Unit.Logging; +using System.Threading; + +namespace QuickGraph.Unit.Core +{ + public sealed class FixtureRunner : IDisposable + { + private ITestListener listener; + + private IFixture fixture; + private ICollection testCases; + + private Thread workerThread = null; + + public FixtureRunner( + IFixture fixture, + ICollection testCases, + ITestListener listener) + { + if (fixture == null) + throw new ArgumentNullException("fixture"); + if (testCases == null) + throw new ArgumentNullException("testCases"); + if (listener == null) + throw new ArgumentNullException("listener"); + + this.fixture = fixture; + this.testCases = testCases; + this.listener = listener; + } + + public ITestListener TestListener + { + get { return this.listener; } + } + + public IFixture Fixture + { + get { return this.fixture; } + } + + public ICollection TestCases + { + get { return this.testCases; } + } + + [System.Diagnostics.DebuggerStepThrough] + public void Run() + { + workerThread = null; + System.Runtime.CompilerServices.RuntimeHelpers.PrepareConstrainedRegions(); + try + { + using (FixtureWorker worker = new FixtureWorker(this)) + { + workerThread = new Thread(new ThreadStart(worker.RunAsync)); + workerThread.SetApartmentState(this.Fixture.Apartment); + workerThread.IsBackground = true; + workerThread.Priority = ThreadPriority.Lowest; + + int timeOut = + (this.Fixture.TimeOut==int.MaxValue) + ? int.MaxValue : 60 * 1000 * this.Fixture.TimeOut; + // if a debugger is attached, no time out + if (System.Diagnostics.Debugger.IsAttached) + timeOut = int.MaxValue; + + workerThread.Start(); + if (!workerThread.Join(timeOut)) + { + // cancel and wait for 10 sec + worker.CancelAsync(); + if (!workerThread.Join(10 * 1000)) + this.AbortWorkerThread(); + + // store result + TestResult result = new TestResult(Fixture.Name, "FixtureTimedOut"); + result.Start(); + result.Fail(new FixtureTimedOutException(this.Fixture.Name)); + this.TestListener.FixtureTearDown(result); + } + else + { + if (worker.UnhandledException != null) + throw new ApplicationException("Exception is runner", worker.UnhandledException); + } + } + } + finally + { + this.AbortWorkerThread(); + } + } + + private void AbortWorkerThread() + { + if (this.workerThread == null) + return; + + workerThread.Abort(); + workerThread = null; + } + + public void Dispose() + { + this.AbortWorkerThread(); + } + + private sealed class FixtureWorker : IDisposable + { + private int isCancelPending = 0; + private Object fixtureInstance; + private FixtureRunner owner; + private Exception unhandledException = null; + + public FixtureWorker(FixtureRunner owner) + { + this.owner = owner; + } + + public bool IsCancelPending + { + get + { + return this.isCancelPending > 0; + } + } + + public void CancelAsync() + { + Interlocked.Increment(ref this.isCancelPending); + } + + public FixtureRunner Owner + { + get { return this.owner; } + } + + public Exception UnhandledException + { + get { return this.unhandledException; } + } + + [System.Diagnostics.DebuggerStepThrough] + public void RunAsync() + { + System.Runtime.CompilerServices.RuntimeHelpers.PrepareConstrainedRegions(); + try + { + this.Owner.TestListener.BeforeFixture(this.Owner.Fixture, this.Owner.TestCases.Count); + + // fixture setup + if (!this.RunTestFixtureSetUp()) + return; + + System.Runtime.CompilerServices.RuntimeHelpers.PrepareConstrainedRegions(); + try + { + foreach (ITestCase test in this.Owner.TestCases) + { + if (this.IsCancelPending) + return; + if (test == null) + continue; + + this.Owner.TestListener.BeforeTestCase(test); + + // create instance + if (this.CreateFixtureInstance()) + { + if (this.RunSetUp()) + { + this.RunTest(test); + this.RunTearDown(); + } + // disposeinstance + this.DisposeFixtureInstance(); + } + + this.Owner.TestListener.AfterTestCase(test); + } + } + finally + { + this.RunTestFixtureTearDown(); + GC.Collect(); + GC.WaitForPendingFinalizers(); + this.Owner.TestListener.AfterFixture(this.Owner.Fixture); + } + } + catch (Exception ex) + { + this.unhandledException = ex; + } + } + + public void Dispose() + { + this.DisposeFixtureInstance(); + } + + private void DisposeFixtureInstance() + { + if (this.fixtureInstance != null) + { + IDisposable disposable = this.fixtureInstance as IDisposable; + if (disposable != null) + disposable.Dispose(); + this.fixtureInstance = null; + } + } + + private bool CreateFixtureInstance() + { + TestResult result = new TestResult(this.Owner.Fixture.Name, "Create"); + System.Runtime.CompilerServices.RuntimeHelpers.PrepareConstrainedRegions(); + try + { + this.fixtureInstance = this.Owner.Fixture.CreateInstance(); + return true; + } + catch (Exception ex) + { + Exception current = ex; + if (current is TargetInvocationException) + current = ex.InnerException; + result.Fail(current); + this.Owner.TestListener.SetUp(result); + return false; + } + } + + [System.Diagnostics.DebuggerStepThrough] + private bool RunTestFixtureSetUp() + { + TestResult result = null; ; + System.Runtime.CompilerServices.RuntimeHelpers.PrepareConstrainedRegions(); + try + { + if (this.Owner.Fixture.FixtureSetUp == null) + return true; + + result = new TestResult(this.Owner.Fixture.Name, this.Owner.Fixture.FixtureSetUp); + result.Start(); + this.Owner.Fixture.FixtureSetUp.Invoke(null, null); + result.Success(); + this.Owner.TestListener.FixtureSetUp(result); + + return true; + } + catch (Exception ex) + { + if (result != null) + { + Exception current = ex; + if (current is TargetInvocationException) + current = ex.InnerException; + result.Fail(current); + this.Owner.TestListener.FixtureSetUp(result); + } + return false; + } + } + + + [System.Diagnostics.DebuggerStepThrough] + private bool RunTestFixtureTearDown() + { + TestResult result = null; + System.Runtime.CompilerServices.RuntimeHelpers.PrepareConstrainedRegions(); + try + { + if (this.Owner.Fixture.FixtureTearDown == null) + return true; + + result = new TestResult(this.Owner.Fixture.Name, this.Owner.Fixture.FixtureTearDown); + result.Start(); + this.Owner.Fixture.FixtureTearDown.Invoke(null, null); + result.Success(); + return true; + } + catch (Exception ex) + { + if (result != null) + { + Exception current = ex; + if (current is TargetInvocationException) + current = ex.InnerException; + result.Fail(current); + this.Owner.TestListener.FixtureTearDown(result); + } + return false; + } + } + + [System.Diagnostics.DebuggerStepThrough] + private bool RunSetUp() + { + TestResult result = null; + try + { + if (this.Owner.Fixture.SetUp == null) + return true; + + result = new TestResult(this.Owner.Fixture.Name, this.Owner.Fixture.SetUp); + result.Start(); + this.Owner.Fixture.SetUp.Invoke(this.fixtureInstance,null); + result.Success(); + this.Owner.TestListener.SetUp(result); + + return true; + } + catch (Exception ex) + { + if (result != null) + { + Exception current = ex; + if (current is TargetInvocationException) + current = ex.InnerException; + result.Fail(current); + this.Owner.TestListener.SetUp(result); + } + return false; + } + } + + [System.Diagnostics.DebuggerStepThrough] + private void RunTearDown() + { + TestResult result = null; + System.Runtime.CompilerServices.RuntimeHelpers.PrepareConstrainedRegions(); + try + { + if (this.Owner.Fixture.TearDown == null) + return; + + result = new TestResult(this.Owner.Fixture.Name, this.Owner.Fixture.TearDown); + result.Start(); + this.Owner.Fixture.TearDown.Invoke(this.fixtureInstance,null); + result.Success(); + } + catch (Exception ex) + { + if (result != null) + { + Exception current = ex; + if (current is TargetInvocationException) + current = ex.InnerException; + result.Fail(current); + this.Owner.TestListener.TearDown(result); + } + } + } + + [System.Diagnostics.DebuggerStepThrough] + private void RunTest(ITestCase test) + { + TestResult result = new TestResult(test); + System.Runtime.CompilerServices.RuntimeHelpers.PrepareConstrainedRegions(); + try + { + result.Start(); + test.Run(this.fixtureInstance); + result.Success(); + } + catch (Exception ex) + { + Exception current = ex; + if (current is TargetInvocationException) + current = current.InnerException; + if (current is IgnoreException) + result.Ignore(); + else if (current is AssumptionFailureException) + result.Success(); + else + result.Fail(current); + } + this.Owner.TestListener.Test(result); + } + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/FixtureRunner.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/FixtureRunner.cs.meta new file mode 100644 index 0000000..6585b2e --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/FixtureRunner.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 7262a30eafa86471dbbfce68287202fa +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/LightweightReflection.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/LightweightReflection.cs new file mode 100755 index 0000000..3fd6e9e --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/LightweightReflection.cs @@ -0,0 +1,331 @@ +using System; +using System.Reflection; +using System.Reflection.Emit; +using System.Collections.Generic; + +namespace QuickGraph.Unit.Core +{ + public delegate void EmptyInvoker(); + public delegate T CoVariantInvoker(); + public delegate void ContraVariantInvoker(T value); + + public static class LightweightReflection + { + #region CreatePropertySetData + private static object syncPropertySetDataRoot = new object(); + private static Dictionary propertySetDatas = new Dictionary(); + + public static T CreateSetData(PropertyInfo property) + { + return (T)(Object)CreateSetData(property).CreateDelegate(typeof(T)); + } + + public static T CreateSetData(PropertyInfo property, object target) + { + return (T)(Object)CreateSetData(property).CreateDelegate(typeof(T), target); + } + + public static DynamicMethod CreateSetData(PropertyInfo property) + { + if (property == null) + throw new ArgumentNullException("property"); + if (!property.CanWrite) + throw new ArgumentException("property cannot set data"); + + DynamicMethod dynamicMethod; + lock (syncPropertySetDataRoot) + { + if (propertySetDatas.TryGetValue(property, out dynamicMethod)) + return dynamicMethod; + + string name = "Set" + property.MetadataToken.ToString(); + Module module = property.Module; + Type[] parameterTypes = GetParameterTypes(property.GetSetMethod()); + dynamicMethod = new DynamicMethod( + name, + null, + parameterTypes, + module); + GenerateInvokeBody(property.GetSetMethod(), + dynamicMethod.GetILGenerator(), + parameterTypes); + propertySetDatas.Add(property, dynamicMethod); + return dynamicMethod; + } + } + + private static void GeneratePropertySetDataBody( + PropertyInfo property, + ILGenerator gen, + Type[] parameters + ) + { + MethodInfo setMethod = property.GetSetMethod(); + + for (int i = 0; i < parameters.Length; ++i) + gen.Emit(OpCodes.Ldarg, i); + + OpCode callCode; + if (setMethod.IsVirtual) + callCode = OpCodes.Callvirt; + else + callCode = OpCodes.Call; + gen.Emit(callCode, setMethod); + gen.Emit(OpCodes.Ret); + } + #endregion + + #region CreatePropertyGetData + private static object syncPropertyGetDataRoot = new object(); + private static Dictionary propertyGetDatas = new Dictionary(); + + public static T CreateGetData(PropertyInfo property) + { + return (T)(Object)CreateGetData(property).CreateDelegate(typeof(T)); + } + + public static T CreateGetData(PropertyInfo property, object target) + { + return (T)(Object)CreateGetData(property).CreateDelegate(typeof(T), target); + } + + public static DynamicMethod CreateGetData(PropertyInfo property) + { + if (property == null) + throw new ArgumentNullException("property"); + if (!property.CanRead) + throw new ArgumentException("property cannot read"); + + DynamicMethod dynamicMethod; + lock (syncPropertyGetDataRoot) + { + if (propertyGetDatas.TryGetValue(property, out dynamicMethod)) + return dynamicMethod; + + string name = "Get" + property.MetadataToken.ToString(); + Module module = property.DeclaringType.Module; + Type returnType = property.PropertyType; + Type[] parameterTypes = GetParameterTypes(property.GetGetMethod()); + + dynamicMethod = new DynamicMethod( + name, + returnType, + parameterTypes, + module); + GenerateInvokeBody(property.GetGetMethod(), + dynamicMethod.GetILGenerator(), + parameterTypes); + propertyGetDatas.Add(property, dynamicMethod); + return dynamicMethod; + } + + } + #endregion + + #region CreateFieldSetData + private static object syncFieldSetDataRoot = new object(); + private static Dictionary fieldSetDatas = new Dictionary(); + + public static T CreateSetData(FieldInfo field) + { + return (T)(Object)CreateSetData(field).CreateDelegate(typeof(T)); + } + + public static T CreateSetData(FieldInfo field, object target) + { + return (T)(Object)CreateSetData(field).CreateDelegate(typeof(T), target); + } + + public static DynamicMethod CreateSetData(FieldInfo field) + { + if (field == null) + throw new ArgumentNullException("field"); + DynamicMethod dynamicMethod; + lock (syncFieldSetDataRoot) + { + if (fieldSetDatas.TryGetValue(field, out dynamicMethod)) + return dynamicMethod; + + string name = "Set" + field.MetadataToken.ToString(); + Module module = field.DeclaringType.Module; + Type[] parameterTypes = + (field.IsStatic) ? new Type[] { field.FieldType } + : new Type[] { field.DeclaringType, field.FieldType }; + + dynamicMethod = new DynamicMethod( + name, + null, + parameterTypes, + module); + GenerateFieldSetDataBody( + field, + dynamicMethod.GetILGenerator()); + fieldSetDatas.Add(field, dynamicMethod); + return dynamicMethod; + } + } + + private static void GenerateFieldSetDataBody( + FieldInfo field, + ILGenerator gen + ) + { + gen.Emit(OpCodes.Ldarg_0); + if (field.IsStatic) + { + gen.Emit(OpCodes.Stsfld, field); + } + else + { + gen.Emit(OpCodes.Ldarg_1); + gen.Emit(OpCodes.Stfld, field); + } + gen.Emit(OpCodes.Ret); + } + #endregion + + #region CreateFieldGetData + private static object syncFieldGetDataRoot = new object(); + private static Dictionary fieldGetDatas = new Dictionary(); + + public static T CreateGetData(FieldInfo field) + { + return (T)(Object)CreateGetData(field).CreateDelegate(typeof(T)); + } + + public static T CreateGetData(FieldInfo field, object target) + { + return (T)(Object)CreateGetData(field).CreateDelegate(typeof(T), target); + } + + public static DynamicMethod CreateGetData(FieldInfo field) + { + if (field == null) + throw new ArgumentNullException("field"); + DynamicMethod dynamicMethod; + lock (syncFieldGetDataRoot) + { + if (fieldGetDatas.TryGetValue(field, out dynamicMethod)) + return dynamicMethod; + + string name = "Get" + field.MetadataToken.ToString(); + Module module = field.DeclaringType.Module; + Type returnType = field.FieldType; + Type[] parameterTypes = (field.IsStatic) ? null : + new Type[] { field.DeclaringType }; + + dynamicMethod = new DynamicMethod( + name, + returnType, + parameterTypes, + module); + GenerateFieldGetDataBody( + field, + dynamicMethod.GetILGenerator()); + fieldGetDatas.Add(field, dynamicMethod); + return dynamicMethod; + } + + } + + private static void GenerateFieldGetDataBody( + FieldInfo field, + ILGenerator gen + ) + { + if (!field.IsStatic) + { + gen.Emit(OpCodes.Ldarg_0); + gen.Emit(OpCodes.Ldfld, field); + } + else + { + gen.Emit(OpCodes.Ldsfld, field); + } + gen.Emit(OpCodes.Ret); + } + + #endregion + + #region CreateInvoke + private static object syncMethodRoot = new object(); + private static Dictionary methods = new Dictionary(); + + public static T CreateInvoke(MethodInfo method) + { + return (T)(object)CreateInvoke(method).CreateDelegate(typeof(T)); + } + + public static T CreateInvoke(MethodInfo method, object target) + { + return (T)(object)CreateInvoke(method).CreateDelegate(typeof(T), target); + } + + public static DynamicMethod CreateInvoke(MethodInfo method) + { + if (method == null) + throw new ArgumentNullException("method"); + DynamicMethod dynamicMethod; + lock (syncMethodRoot) + { + if (methods.TryGetValue(method, out dynamicMethod)) + return dynamicMethod; + string name = method.Name+method.MetadataToken.ToString(); + Module module = method.DeclaringType.Module; + Type returnType = method.ReturnType; + Type[] parameterTypes = GetParameterTypes(method); + + dynamicMethod = new DynamicMethod( + name, + returnType, + parameterTypes, + module); + GenerateInvokeBody(method, dynamicMethod.GetILGenerator(), parameterTypes); + methods.Add(method, dynamicMethod); + return dynamicMethod; + } + } + + private static void GenerateInvokeBody( + MethodInfo method, + ILGenerator gen, + Type[] parameterTypes + ) + { + for (int i = 0; i < parameterTypes.Length; ++i) + gen.Emit(OpCodes.Ldarg, i); + + OpCode callCode; + if (method.IsVirtual) + callCode = OpCodes.Callvirt; + else + callCode = OpCodes.Call; + + gen.EmitCall(callCode, method, null); + + gen.Emit(OpCodes.Ret); + } + + private static Type[] GetParameterTypes(MethodInfo method) + { + ParameterInfo[] parameters = method.GetParameters(); + Type[] types; + if (method.IsStatic) + { + types = new Type[parameters.Length]; + for (int i = 0; i < parameters.Length; ++i) + types[i] = parameters[i].ParameterType; + } + else + { + types = new Type[parameters.Length + 1]; + types[0] = method.DeclaringType; + for (int i = 0; i < parameters.Length; ++i) + types[i + 1] = parameters[i].ParameterType; + } + + return types; + } + #endregion + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/LightweightReflection.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/LightweightReflection.cs.meta new file mode 100644 index 0000000..dec40c1 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/LightweightReflection.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 1fa381a0e40fe4036af78f48bc1b6cf9 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/MethodTestCase.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/MethodTestCase.cs new file mode 100755 index 0000000..23592f4 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/MethodTestCase.cs @@ -0,0 +1,42 @@ +using System; +using System.Collections.Generic; +using System.Reflection; +using System.IO; + +namespace QuickGraph.Unit.Core +{ + public class MethodTestCase : TestCaseBase + { + private MethodInfo method; + + public MethodTestCase(string fixtureName, MethodInfo method) + :base(fixtureName) + { + if (method == null) + throw new ArgumentNullException("method"); + this.method = method; + } + + public MethodInfo Method + { + get { return this.method; } + } + + public override string UndecoratedName + { + get { return this.Method.Name; } + } + + [System.Diagnostics.DebuggerStepThrough] + public override void Run(Object fixture) + { + if (this.Parameters.Count == 0) + this.method.Invoke(fixture, null); + else + { + Object[] array = TestCaseParameter.GetValues(this.Parameters); + this.method.Invoke(fixture, array); + } + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/MethodTestCase.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/MethodTestCase.cs.meta new file mode 100644 index 0000000..7267049 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/MethodTestCase.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ca008e6445eeb404d832e4f2b42807f9 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/ReflectionHelper.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/ReflectionHelper.cs new file mode 100755 index 0000000..b70a86c --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/ReflectionHelper.cs @@ -0,0 +1,152 @@ +using System; +using System.Reflection; +using System.Collections.Generic; +using System.ComponentModel; + +namespace QuickGraph.Unit.Core +{ + public static class ReflectionHelper + { + public static Object[] ToArray(ICollection parameters) + { + Object[] array = new object[parameters.Count]; + parameters.CopyTo(array, 0); + return array; + } + + public static T GetAttribute(ICustomAttributeProvider t) + where T : Attribute + { + if (t == null) + throw new ArgumentNullException("t"); + + // Gets the attributes for the property. + Object[] attributes = + t.GetCustomAttributes(typeof(T), true); + + if (attributes.Length == 0) + return null; + if (attributes.Length==1) + return (T)attributes[0]; + + throw new ArgumentException("Attribute type must be AllowMultiple = false",typeof(T).FullName); + } + + public static string GetCategory(ICustomAttributeProvider t) + { + if (t == null) + throw new ArgumentNullException("t"); + + System.ComponentModel.CategoryAttribute cat = ReflectionHelper.GetAttribute < System.ComponentModel.CategoryAttribute>(t); + if (cat == null) + return ""; + return cat.Category; + } + + public static MethodInfo GetMethod(Type t, string methodName,params Object[] parameters) + { + if (t == null) + throw new ArgumentNullException("t"); + if (methodName == null) + throw new ArgumentNullException("methodName"); + if (methodName.Length == 0) + throw new ArgumentException("Length is zero", "methodName"); + + Type[] types = new Type[parameters.Length]; + for (int i = 0; i < parameters.Length; ++i) + { + if (parameters[i] == null) + throw new ArgumentNullException("paramer[" + i.ToString() + "]"); + types[i] = parameters[i].GetType(); + } + + return t.GetMethod(methodName, + BindingFlags.Instance | + BindingFlags.Public | + BindingFlags.NonPublic, + null, + types, + null + ); + } + + public static MethodInfo GetMethod(Type t, Type customAttributeType, BindingFlags flags) + { + MethodInfo[] methods = GetMethods(t, customAttributeType, flags); + if (methods.Length == 0) + return null; + if (methods.Length > 1) + throw new ArgumentException("More that one method found"); + return methods[0]; + } + + public static MethodInfo[] GetMethods(Type t, Type customAttributeType) + { + return GetMethods(t, customAttributeType, BindingFlags.Public | BindingFlags.Instance); + } + + public static MethodInfo[] GetMethods(Type t, Type customAttributeType, BindingFlags flags) + { + if (t == null) + throw new ArgumentNullException("t"); + if (customAttributeType == null) + throw new ArgumentNullException("customAttributeType"); + + List list = new List(); + foreach (MethodInfo mi in t.GetMethods(flags)) + { + if (mi.GetCustomAttributes(customAttributeType, true).Length != 0) + list.Add(mi); + } + + MethodInfo[] methods = new MethodInfo[list.Count]; + list.CopyTo(methods); + return methods; + } + + + public static void VerifySignature(MethodInfo method, params Type[] argumentAssignableTypes) + { + if (method == null) + throw new ArgumentNullException("method"); + + ParameterInfo[] parameters = method.GetParameters(); + Assert.AreEqual( + argumentAssignableTypes.Length, + parameters.Length, + "Method {0} has not the right number of arguments ({1})", + method.Name, argumentAssignableTypes.Length); + + for (int i = 0; i < parameters.Length; ++i) + { + Assert.IsTrue(argumentAssignableTypes[i].IsAssignableFrom(parameters[i].ParameterType), + "Argument {0} is not assignable from {1}", + argumentAssignableTypes[i], + parameters[i] + ); + } + } + + public static void VerifySignature(MethodInfo method, params Object[] arguments) + { + if (method == null) + throw new ArgumentNullException("method"); + + if (arguments == null) + { + VerifySignature(method, new Type[]{}); + return; + } + Type[] types = new Type[arguments.Length]; + for (int i = 0; i < arguments.Length; ++i) + { + if (arguments[i] == null) + types[i] = typeof(object); + else + types[i] = arguments[i].GetType(); + } + + VerifySignature(method, types); + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/ReflectionHelper.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/ReflectionHelper.cs.meta new file mode 100644 index 0000000..6220c10 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/ReflectionHelper.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 137bfd0a06e204d6d930829f905e3adf +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/ReportGenerationScenario.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/ReportGenerationScenario.cs new file mode 100755 index 0000000..9f6d901 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/ReportGenerationScenario.cs @@ -0,0 +1,9 @@ +namespace QuickGraph.Unit.Core +{ + public enum ReportGenerationScenario + { + None, + OnFailure, + Always + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/ReportGenerationScenario.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/ReportGenerationScenario.cs.meta new file mode 100644 index 0000000..e3dd907 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/ReportGenerationScenario.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d9f3fb2357f734efbbf5d11acc94a871 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/Result.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/Result.cs new file mode 100755 index 0000000..2bf0fcc --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/Result.cs @@ -0,0 +1,103 @@ +using System; +using System.Diagnostics; +using QuickGraph.Unit.Monitoring; + +namespace QuickGraph.Unit.Core +{ + [Serializable] + public class Result + { + private TestState state = TestState.NotRun; + private string name; + private Exception exception = null; + private TestMonitor monitor; + + public Result(string name) + { + if (name == null) + throw new ArgumentNullException("name"); + this.name = name; + this.monitor = new TestMonitor(); + } + + public TestState State + { + get { return this.state; } + } + + public string Name + { + get { return this.name; } + } + + public virtual string FullName + { + get { return this.Name; } + } + + public string Out + { + get { return this.monitor.Console.Out; } + } + public string Error + { + get { return this.monitor.Console.Error; } + } + public double Duration + { + get { return this.monitor.Timer.Duration; } + } + public Exception Exception + { + get { return this.exception; } + } + public DateTime StartTime + { + get { return this.Monitor.Timer.StartTime; } + } + public DateTime StopTime + { + get { return this.Monitor.Timer.EndTime; } + } + + public TestMonitor Monitor + { + get { return this.monitor; } + } + + public void Start() + { + this.Monitor.Start(); + } + + private void Stop() + { + this.Monitor.Stop(); + + } + + [DebuggerStepThrough] + public void Fail(Exception exception) + { + if (exception == null) + throw new ArgumentNullException("exception"); + this.Stop(); + this.state = TestState.Failure; + this.exception = exception; + } + + [DebuggerStepThrough] + public void Success() + { + this.Stop(); + this.state = TestState.Success; + } + + [DebuggerStepThrough] + public void Ignore() + { + this.Stop(); + this.state = TestState.Ignore; + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/Result.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/Result.cs.meta new file mode 100644 index 0000000..86e2dc3 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/Result.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 0686047603e1d4c3698820629f8c451e +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/SynchronizedTestCase.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/SynchronizedTestCase.cs new file mode 100755 index 0000000..fcdae27 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/SynchronizedTestCase.cs @@ -0,0 +1,27 @@ +using System; + +namespace QuickGraph.Unit.Core +{ + public class SynchronizedTestCase : DecoratorTestCaseBase + { + private TestSynchronizer synchronizer; + public SynchronizedTestCase(ITestCase testCase, TestSynchronizer synchronizer) + : base(testCase) + { + this.synchronizer = synchronizer; + } + + public TestSynchronizer Synchronizer + { + get { return this.synchronizer; } + } + + public override void Run(object fixture) + { + // wait for barrier opening + this.Synchronizer.Synchronize(); + // run test + this.TestCase.Run(fixture); + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/SynchronizedTestCase.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/SynchronizedTestCase.cs.meta new file mode 100644 index 0000000..de7201f --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/SynchronizedTestCase.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 2b0c8e266dcfc4741b663a125309d175 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/TestAssembly.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/TestAssembly.cs new file mode 100755 index 0000000..4cf75ec --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/TestAssembly.cs @@ -0,0 +1,66 @@ +using System; +using System.Collections.Generic; +using System.Reflection; +using QuickGraph.Unit.Filters; + +namespace QuickGraph.Unit.Core +{ + public sealed class TestAssembly + { + private Assembly assembly; + private MethodInfo assemblySetUp; + private MethodInfo assemblyTearDown; + private Dictionary> fixtureTestCases = new Dictionary>(); + + public TestAssembly( + Assembly assembly + ) + { + this.assembly = assembly; + } + + public Assembly Assembly + { + get { return this.assembly; } + } + + public MethodInfo AssemblySetUp + { + get { return this.assemblySetUp; } + set { this.assemblySetUp = value; } + } + + public MethodInfo AssemblyTearDown + { + get { return this.assemblyTearDown; } + set { this.assemblyTearDown = value; } + } + + public ICollection Fixtures + { + get { return this.fixtureTestCases.Keys; } + } + + public ICollection GetTestCasesFromFixture(IFixture fixture) + { + return this.fixtureTestCases[fixture]; + } + + public void AddFixture(IFixture fixture, ICollection testCases) + { + if (fixture == null) + throw new ArgumentNullException("fixture"); + if (testCases == null) + throw new ArgumentNullException("testCases"); + this.fixtureTestCases.Add(fixture, testCases); + } + + public int GetTestCount() + { + int count = 0; + foreach (ICollection tests in this.fixtureTestCases.Values) + count += tests.Count; + return count; + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/TestAssembly.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/TestAssembly.cs.meta new file mode 100644 index 0000000..4666209 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/TestAssembly.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 429ecc37e75a440a09f37ae6245607ff +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/TestAttributeBase.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/TestAttributeBase.cs new file mode 100755 index 0000000..2afdc26 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/TestAttributeBase.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Reflection; + +namespace QuickGraph.Unit.Core +{ + [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)] + public abstract class TestAttributeBase : Attribute, ITestCaseFactory + { + public abstract IEnumerable CreateTests( + IFixture fixture, + MethodInfo method + ); + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/TestAttributeBase.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/TestAttributeBase.cs.meta new file mode 100644 index 0000000..e6c0044 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/TestAttributeBase.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 046214bc686af44d2934c2c60a147755 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/TestBatch.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/TestBatch.cs new file mode 100755 index 0000000..3756477 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/TestBatch.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.Generic; +using System.Reflection; +using QuickGraph.Unit.Filters; + +namespace QuickGraph.Unit.Core +{ + public sealed class TestBatch + { + private List testAssemblies = new List(); + + public TestBatch() + {} + + public ICollection TestAssemblies + { + get { return this.testAssemblies; } + } + + public TestAssembly MainTestAssembly + { + get + { + if (this.TestAssemblies.Count > 0) + return this.testAssemblies[0]; + else + return null; + } + } + + public int GetFixtureCount() + { + int count = 0; + foreach (TestAssembly testAssembly in this.TestAssemblies) + count += testAssembly.Fixtures.Count; + return count; + } + + public int GetTestCount() + { + int count = 0; + foreach (TestAssembly testAssembly in this.TestAssemblies) + count+=testAssembly.GetTestCount(); + return count; + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/TestBatch.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/TestBatch.cs.meta new file mode 100644 index 0000000..8d373de --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/TestBatch.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: de2ea3038e59a4bc1a7bbac35739881c +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/TestBatchFactory.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/TestBatchFactory.cs new file mode 100755 index 0000000..9fbdc1c --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/TestBatchFactory.cs @@ -0,0 +1,237 @@ +using System; +using System.Collections.Generic; +using System.Reflection; +using System.CodeDom.Compiler; +using QuickGraph.Unit.Exceptions; +using QuickGraph.Unit.Filters; +using System.ComponentModel; + +namespace QuickGraph.Unit.Core +{ + public sealed class TestBatchFactory + { + private List testAssemblies = new List(); + private TestBatch batch; + private IFixtureFilter fixtureFilter = new AnyFixtureFilter(); + private ITestCaseFilter testCaseFilter = new AnyTestCaseFilter(); + + public TestBatch Batch + { + get { return this.batch; } + } + + public IList TestAssemblies + { + get { return this.testAssemblies; } + } + + public string MainAssembly + { + get + { + if (this.testAssemblies.Count == 0) + return "NoAssemblies"; + else + return this.testAssemblies[0].GetName().Name; + } + } + + public IFixtureFilter FixtureFilter + { + get { return this.fixtureFilter; } + set { this.fixtureFilter = value; } + } + + public ITestCaseFilter TestCaseFilter + { + get { return this.testCaseFilter; } + set { this.testCaseFilter = value; } + } + + public TestBatch Create() + { + this.batch = new TestBatch(); + foreach (Assembly assembly in this.TestAssemblies) + { + TestAssembly testAssembly = CreateTestAssembly(assembly); + this.batch.TestAssemblies.Add(testAssembly); + } + return this.batch; + } + + public TestAssembly CreateTestAssembly(Assembly assembly) + { + if (assembly == null) + throw new ArgumentNullException("assembly"); + + TestAssembly testAssembly = new TestAssembly(assembly); + this.ReflectAssemblySetUpAndTearDown(testAssembly); + + foreach (Type type in assembly.GetExportedTypes()) + { + if (type.IsAbstract || type.IsInterface) + continue; + foreach (IFixture fixture in this.ReflectFixtures(type)) + AddFixture(testAssembly, fixture); + } + + return testAssembly; + } + + private void AddFixture(TestAssembly testAssembly, IFixture fixture) + { + List tests = new List(); + + System.Runtime.CompilerServices.RuntimeHelpers.PrepareConstrainedRegions(); + try + { + foreach (ITestCase test in fixture.CreateTestCases()) + { + if (test == null) + continue; + if (!testCaseFilter.Filter(fixture,test)) + continue; + ITestCase decoratedTest = DecorateTest(fixture, test); + tests.Add(decoratedTest); + } + testAssembly.AddFixture(fixture, tests); + } + catch (Exception ex) + { + BadFixture badFixture = new BadFixture(fixture.Name, ex); + tests.Clear(); + testAssembly.AddFixture(badFixture, tests); + } + } + + private static ITestCase DecorateTest(IFixture fixture, ITestCase test) + { + ITestCase current = test; + foreach (ITestCaseDecorator decorator in fixture.TestCaseDecorators) + current = decorator.Decorate(current); + return current; + } + + private IEnumerable ReflectFixtures(Type fixtureType) + { + foreach(TestFixtureAttributeBase fixtureAttribute in fixtureType.GetCustomAttributes(typeof(TestFixtureAttributeBase),true)) + { + foreach (IFixture fixture in fixtureAttribute.CreateFixtures(fixtureType)) + { + if (fixture == null) + continue; + if (!this.FixtureFilter.Filter(fixture)) + continue; + + BadFixture badFixture = VerifyFixture(fixtureType); + if (badFixture != null) + { + yield return badFixture; + continue; + } + + ReflectSetUpAndTearDown(fixtureType, fixture); + ReflectDecorators(fixtureType, fixture); + ReflectCategories(fixtureType, fixture); + + yield return fixture; + } + } + } + + private static BadFixture VerifyFixture(Type fixtureType) + { + foreach (MethodInfo method in fixtureType.GetMethods(BindingFlags.Instance | BindingFlags.Public)) + { + MethodInfo ms = FilterMethod(method, typeof(TestFixtureSetUpAttribute)); + if (ms != null) + return new BadFixture(fixtureType.FullName, "TestFixtureSetupAttribute must tag static methods"); + MethodInfo mt = FilterMethod(method, typeof(TestFixtureTearDownAttribute)); + if (mt != null) + return new BadFixture(fixtureType.FullName, "TestFixtureTearDownAttribute must tag static methods"); + } + return null; + } + + private void ReflectAssemblySetUpAndTearDown(TestAssembly testAssembly) + { + AssemblySetUpAndTearDownAttribute assemblySetUpAndTearDown = + ReflectionHelper.GetAttribute(testAssembly.Assembly); + if (assemblySetUpAndTearDown != null) + { + testAssembly.AssemblySetUp = ReflectionHelper.GetMethod( + assemblySetUpAndTearDown.TargetType, + typeof(AssemblySetUpAttribute), + BindingFlags.Static | BindingFlags.Public + ); + testAssembly.AssemblyTearDown = ReflectionHelper.GetMethod( + assemblySetUpAndTearDown.TargetType, + typeof(AssemblyTearDownAttribute), + BindingFlags.Static | BindingFlags.Public + ); + } + + } + + private void ReflectDecorators(Type fixtureType, IFixture fixture) + { + foreach (TestDecoratorAttributeBase attribute in fixtureType.GetCustomAttributes(typeof(TestDecoratorAttributeBase), true)) + fixture.TestCaseDecorators.Add(attribute); + } + + private void ReflectCategories(Type fixtureType, IFixture fixture) + { + CategoryAttribute category = ReflectionHelper.GetAttribute(fixtureType); + if (category != null) + { + foreach (string cat in category.Category.Split('.')) + fixture.Categories.Add(cat); + } + } + + private static void ReflectSetUpAndTearDown(Type fixtureType, IFixture fixture) + { + foreach (MethodInfo method in fixtureType.GetMethods(BindingFlags.Public | BindingFlags.Static)) + { + if (fixture.FixtureSetUp == null) + { + fixture.FixtureSetUp = FilterMethod(method, typeof(TestFixtureSetUpAttribute)); + if (fixture.FixtureSetUp != null) + continue; + } + if (fixture.FixtureTearDown == null) + { + fixture.FixtureTearDown = FilterMethod(method, typeof(TestFixtureTearDownAttribute)); + if (fixture.FixtureTearDown != null) + continue; + } + } + + // getting setup and teardown + foreach (MethodInfo method in fixtureType.GetMethods(BindingFlags.Instance | BindingFlags.Public)) + { + if (fixture.SetUp == null) + { + fixture.SetUp = FilterMethod(method, typeof(SetUpAttribute)); + if (fixture.SetUp != null) + continue; + } + if (fixture.TearDown == null) + { + fixture.TearDown = FilterMethod(method, typeof(TearDownAttribute)); + if (fixture.TearDown != null) + continue; + } + } + } + + private static MethodInfo FilterMethod(MethodInfo method, Type attributeType) + { + Object[] attributes = method.GetCustomAttributes(attributeType, true); + if (attributes.Length == 0) + return null; + + return method; + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/TestBatchFactory.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/TestBatchFactory.cs.meta new file mode 100644 index 0000000..d4d436a --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/TestBatchFactory.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 66493cf232b8743dd9b1fdd2541a8bb0 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/TestCaseBase.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/TestCaseBase.cs new file mode 100755 index 0000000..52b3ae8 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/TestCaseBase.cs @@ -0,0 +1,72 @@ +using System; +using System.Collections.Generic; +using System.Reflection; +using System.IO; + +namespace QuickGraph.Unit.Core +{ + public abstract class TestCaseBase : ITestCase + { + private string fixtureName; + private List parameters = new List(); + + public TestCaseBase(string fixtureName) + { + if (fixtureName == null) + throw new ArgumentNullException("fixtureName"); + this.fixtureName = fixtureName; + } + + public string FixtureName + { + get { return this.fixtureName; } + } + + public virtual string Name + { + get + { + if (this.Parameters.Count == 0) + { + return this.UndecoratedName; + } + else + { + using (StringWriter writer = new StringWriter()) + { + writer.Write(this.UndecoratedName); + writer.Write('('); + bool first = true; + foreach (TestCaseParameter parameter in this.Parameters) + { + if (first) + first = false; + else + writer.Write(", "); + writer.Write(parameter.Name); + } + writer.Write(')'); + return writer.ToString(); + } + } + } + } + + public abstract string UndecoratedName + { + get; + } + + public virtual string FullName + { + get { return String.Format("{0}.{1}", this.FixtureName, this.Name); } + } + + public IList Parameters + { + get { return this.parameters; } + } + + public abstract void Run(Object fixture); + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/TestCaseBase.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/TestCaseBase.cs.meta new file mode 100644 index 0000000..8b68de4 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/TestCaseBase.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: c60dc61ee2445429096787076f45b071 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/TestCaseWorker.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/TestCaseWorker.cs new file mode 100755 index 0000000..c2a9c3f --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/TestCaseWorker.cs @@ -0,0 +1,78 @@ +using System; +using System.Collections.Generic; +using System.Runtime.CompilerServices; +using System.Reflection; + +namespace QuickGraph.Unit.Core +{ + [Serializable] + public class TestCaseWorker + { + private ITestCase testCase; + private int index; + private Exception throwedException = null; + + public TestCaseWorker(ITestCase testCase, int index) + { + if (testCase == null) + throw new ArgumentNullException("testCase"); + this.testCase = testCase; + this.index = index; + } + + public ITestCase TestCase + { + get { return this.testCase; } + } + + public int Index + { + get { return this.index;} + } + + public Exception ThrowedException + { + get { return this.throwedException; } + } + + public string Name + { + get { return String.Format("{0}{1}", this.TestCase.Name, this.Index);} + } + + protected void Log(string format, params object[] args) + { + string message = String.Format(format, args); + Console.WriteLine("{0}: {1}", this.Name, message); + } + + public void Start(object fixture) + { + RuntimeHelpers.PrepareConstrainedRegions(); + try + { + this.RunTestCase(fixture); + } + catch (Exception ex) + { + Exception current = ex; + if (current is TargetInvocationException) + current = current.InnerException; + this.throwedException = current; + Log("Exception {0}, {1}", current.GetType().Name, current.Message); + } + finally + { + CleanTestCase(fixture); + } + } + + protected virtual void RunTestCase(object fixture) + { + this.TestCase.Run(fixture); + } + + protected virtual void CleanTestCase(object fixture) + { } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/TestCaseWorker.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/TestCaseWorker.cs.meta new file mode 100644 index 0000000..f004b39 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/TestCaseWorker.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 55e1fca8cce7d43968c2fc17c0aea14e +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/TestCaseWorkerCollection.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/TestCaseWorkerCollection.cs new file mode 100755 index 0000000..9e440a5 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/TestCaseWorkerCollection.cs @@ -0,0 +1,131 @@ +using System; +using System.Collections.Generic; +using System.Threading; + +namespace QuickGraph.Unit.Core +{ + public sealed class TestCaseWorkerCollection : IEnumerable + { + private List workerPairs = new List(); + + private class WorkerPair + { + public TestCaseWorker Worker; + public Thread WorkerThread; + public void SetWorkerThread(Thread thread) + { + this.WorkerThread = thread; + } + } + + public void Add(TestCaseWorker worker) + { + WorkerPair pair = new WorkerPair(); + pair.Worker = worker; + this.workerPairs.Add(pair); + } + + public void StartAll(object fixture) + { + // creating threads + foreach (WorkerPair pair in this.workerPairs) + { + if (pair.WorkerThread != null) + throw new InvalidOperationException("Thread were not terminated before starting"); + pair.SetWorkerThread(new Thread(new ParameterizedThreadStart(pair.Worker.Start))); + pair.WorkerThread.Name = pair.Worker.Name; + } + + // starting threads + foreach (WorkerPair pair in this.workerPairs) + { + pair.WorkerThread.Start(fixture); + } + } + + public void WaitAll() + { + while (IsAnyAlive()) + { + Thread.Sleep(1000); + } + } + + public bool IsAnyAlive() + { + bool isAlive = false; + foreach (WorkerPair pair in this.workerPairs) + { + if (pair.WorkerThread != null) + { + if (pair.WorkerThread.IsAlive) + isAlive = true; + else + pair.SetWorkerThread(null); + } + } + + return isAlive; + } + + public bool ContainsAll(ICollection threadNames) + { + // let's make sure not worker died + foreach (WorkerPair pair in this.workerPairs) + { + // did the thread fail ? + if (pair.Worker.ThrowedException!=null) + return true; + } + + foreach (WorkerPair pair in this.workerPairs) + { + if (!threadNames.Contains(pair.WorkerThread.Name)) + return false; + } + + return true; + } + + public void CloseAll() + { + foreach (WorkerPair pair in this.workerPairs) + { + if (pair.WorkerThread != null) + { + if (pair.WorkerThread.IsAlive) + pair.WorkerThread.Abort(); + pair.SetWorkerThread(null); + } + } + } + + public void Verify() + { + int exceptionCount = 0; + foreach (TestCaseWorker worker in this) + { + if (worker.ThrowedException != null) + { + exceptionCount++; + Console.WriteLine("Error in worker {0}",worker.Name); + Console.WriteLine(worker.ThrowedException); + } + } + + if (exceptionCount > 0) + Assert.Fail("There were {0} exceptions during the run.", exceptionCount); + } + + public IEnumerator GetEnumerator() + { + foreach (WorkerPair pair in this.workerPairs) + yield return pair.Worker; + } + + System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() + { + return this.GetEnumerator(); + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/TestCaseWorkerCollection.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/TestCaseWorkerCollection.cs.meta new file mode 100644 index 0000000..2ed7326 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/TestCaseWorkerCollection.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: dba35fe63c2d146a7b7f45a276b24629 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/TestCounter.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/TestCounter.cs new file mode 100755 index 0000000..878db5a --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/TestCounter.cs @@ -0,0 +1,116 @@ +using System; + +namespace QuickGraph.Unit.Core +{ + [Serializable] + public sealed class TestCounter + { + private int totalCount=0; + private int successCount; + private int failureCount; + private int ignoreCount; + + public TestCounter(int testCount) + { + this.totalCount = testCount; + } + + public int TotalCount + { + get { return this.totalCount; } + } + + public int RunCount + { + get { return this.successCount + this.failureCount + this.ignoreCount; } + } + + public int SuccessCount + { + get { return this.successCount; } + set { this.successCount = value; } + } + public int FailureCount + { + get { return this.failureCount; } + set { this.failureCount = value; } + } + public int IgnoreCount + { + get { return this.ignoreCount; } + set { this.ignoreCount = value; } + } + public bool HasFailures + { + get { return this.FailureCount>0; } + } + public bool Succeeded + { + get { return this.SuccessCount == this.TotalCount; } + } + + public void Success() + { + this.successCount++; + } + public void Failure() + { + this.failureCount++; + } + public void Ignore() + { + this.ignoreCount++; + } + public double PercentRun + { + get + { + if (this.TotalCount == 0) + return 0; + return (double)this.RunCount / this.TotalCount * 100; + } + } + + public double PercentSuccess + { + get + { + if (this.TotalCount == 0) + return 0; + return (double)this.SuccessCount / this.TotalCount * 100; + } + } + + + public void RollbackResults(TestCounter counter) + { + this.failureCount -= counter.FailureCount; + this.successCount -= counter.SuccessCount; + this.ignoreCount -= counter.IgnoreCount; + } + + public static TestCounter Add(TestCounter a, TestCounter b) + { + TestCounter c = new TestCounter(a.totalCount + b.totalCount); + c.successCount = a.successCount + b.successCount; + c.failureCount = a.failureCount + b.failureCount; + c.ignoreCount = a.ignoreCount + b.ignoreCount; + return c; + } + + public static TestCounter operator +(TestCounter a, TestCounter b) + { + return Add(a, b); + } + + public override string ToString() + { + return String.Format("{0:0.00}% ({1},+{2},-{3},~{4})", + this.PercentRun, + this.RunCount, + this.SuccessCount, + this.FailureCount, + this.IgnoreCount); + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/TestCounter.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/TestCounter.cs.meta new file mode 100644 index 0000000..015d562 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/TestCounter.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ec982c25ad1254287b7209a8c6338ced +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/TestDecoratorAttributeBase.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/TestDecoratorAttributeBase.cs new file mode 100755 index 0000000..d5ed12b --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/TestDecoratorAttributeBase.cs @@ -0,0 +1,21 @@ +using System; +using System.Reflection; + +namespace QuickGraph.Unit.Core +{ + [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, AllowMultiple = false, Inherited = true)] + public abstract class TestDecoratorAttributeBase : Attribute, ITestCaseDecorator + { + public abstract ITestCase Decorate(ITestCase testCase); + + public static ITestCase DecorateTest(ITestCase testCase, MethodInfo method) + { + ITestCase test = testCase; + foreach (TestDecoratorAttributeBase attribute in method.GetCustomAttributes(typeof(TestDecoratorAttributeBase), true)) + { + test = attribute.Decorate(test); + } + return test; + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/TestDecoratorAttributeBase.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/TestDecoratorAttributeBase.cs.meta new file mode 100644 index 0000000..1722b6e --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/TestDecoratorAttributeBase.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b8f34889cdbb44182a8599388896a4f2 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/TestFixtureAttributeBase.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/TestFixtureAttributeBase.cs new file mode 100755 index 0000000..ba809b2 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/TestFixtureAttributeBase.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Threading; + +namespace QuickGraph.Unit.Core +{ + [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)] + public abstract class TestFixtureAttributeBase : + Attribute, + IFixtureFactory + { + private ApartmentState apartment = ApartmentState.Unknown; + private int timeOut = 2; + private string description; + + public ApartmentState Apartment + { + get { return this.apartment; } + set { this.apartment = value; } + } + + public int TimeOut + { + get { return this.timeOut; } + set { this.timeOut = value; } + } + + public string Description + { + get { return this.description; } + set { this.description = value; } + } + + public abstract IEnumerable CreateFixtures(Type type); + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/TestFixtureAttributeBase.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/TestFixtureAttributeBase.cs.meta new file mode 100644 index 0000000..3601a18 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/TestFixtureAttributeBase.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 2b36e153fa339489dbbec6a757c97cd3 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/TestResult.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/TestResult.cs new file mode 100755 index 0000000..0e177f0 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/TestResult.cs @@ -0,0 +1,38 @@ +using System; +using System.Reflection; + +namespace QuickGraph.Unit.Core +{ + [Serializable] + public class TestResult : Result + { + private string fixtureName; + + public TestResult(string fixtureName, MethodInfo method) + :this(fixtureName,method.Name) + {} + + public TestResult(string fixtureName, string name) + :base(name) + { + if (fixtureName == null) + throw new ArgumentNullException("fixtureName"); + this.fixtureName = fixtureName; + } + + public TestResult(ITestCase testCase) + : this(testCase.FixtureName, testCase.Name) + { + } + + public string FixtureName + { + get { return this.fixtureName; } + } + + public override string FullName + { + get { return String.Format("{0}.{1}", this.FixtureName, this.Name); } + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/TestResult.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/TestResult.cs.meta new file mode 100644 index 0000000..61dcdd3 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/TestResult.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 0c713b188d203448e8a5353f6611c745 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/TestResultEventArgs.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/TestResultEventArgs.cs new file mode 100755 index 0000000..695a977 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/TestResultEventArgs.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace QuickGraph.Unit.Core +{ + [Serializable] + public sealed class TestResultEventArgs : EventArgs + { + private TestResult result; + public TestResultEventArgs(TestResult result) + { + if (result == null) + throw new ArgumentNullException("result"); + this.result = result; + } + public TestResult Result + { + get { return this.result; } + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/TestResultEventArgs.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/TestResultEventArgs.cs.meta new file mode 100644 index 0000000..57e25f9 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/TestResultEventArgs.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 23d04fa908a5a42819d8dd00117062db +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/TestState.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/TestState.cs new file mode 100755 index 0000000..bdbb7a9 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/TestState.cs @@ -0,0 +1,10 @@ +namespace QuickGraph.Unit.Core +{ + public enum TestState :short + { + NotRun = 0, + Success = 1, + Ignore = 2, + Failure = 3 + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/TestState.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/TestState.cs.meta new file mode 100644 index 0000000..41efdd7 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/TestState.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 2782083ceba604489af5a89f27f1e646 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/TypeDecoratorTestCaseBase.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/TypeDecoratorTestCaseBase.cs new file mode 100755 index 0000000..d9013a5 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/TypeDecoratorTestCaseBase.cs @@ -0,0 +1,23 @@ +using System; + +namespace QuickGraph.Unit.Core +{ + public abstract class TypeDecoratorTestCaseBase : DecoratorTestCaseBase + where A : Attribute + { + private A attribute; + + public TypeDecoratorTestCaseBase(ITestCase testCase, A attribute) + :base(testCase) + { + if (attribute == null) + throw new ArgumentNullException("attribute"); + this.attribute = attribute; + } + + public A Attribute + { + get { return this.attribute; } + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/TypeDecoratorTestCaseBase.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/TypeDecoratorTestCaseBase.cs.meta new file mode 100644 index 0000000..fd45823 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/TypeDecoratorTestCaseBase.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: f087d25c41fdb4b139abd1001c79c271 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/TypeFixtureBase.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/TypeFixtureBase.cs new file mode 100755 index 0000000..68a8c18 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/TypeFixtureBase.cs @@ -0,0 +1,52 @@ +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Threading; + +namespace QuickGraph.Unit.Core +{ + public abstract class TypeFixtureBase : FixtureBase + where A : TestFixtureAttributeBase + { + private A attribute; + private Type fixtureType; + public TypeFixtureBase(A attribute, Type fixtureType) + :base(attribute.Apartment, attribute.TimeOut, attribute.Description) + { + if (fixtureType == null) + throw new ArgumentNullException("fixtureType"); + + this.attribute = attribute; + this.fixtureType = fixtureType; + this.IsCurrent = ReflectionHelper.GetAttribute(this.FixtureType) != null; + } + + public A Attribute + { + get { return this.attribute; } + } + + public Type FixtureType + { + get { return this.fixtureType; } + } + + public override string Name + { + get { return this.FixtureType.FullName; } + } + + public override object CreateInstance() + { + return Activator.CreateInstance(fixtureType); + } + + protected ITestCase DecorateTest(Object[] decorators, ITestCase test) + { + ITestCase current= test; + foreach (ITestCaseDecorator decorator in decorators) + current = decorator.Decorate(current); + return current; + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/TypeFixtureBase.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/TypeFixtureBase.cs.meta new file mode 100644 index 0000000..ec51fc4 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/TypeFixtureBase.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: fa728351ef8b14670a86d29b04d2b045 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/TypeTestCaseBase.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/TypeTestCaseBase.cs new file mode 100755 index 0000000..b60d22f --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/TypeTestCaseBase.cs @@ -0,0 +1,21 @@ +using System; + +namespace QuickGraph.Unit.Core +{ + public abstract class TypeTestCaseBase : TestCaseBase + where A : Attribute + { + private A attribute; + + public TypeTestCaseBase(string fixtureName, A attribute) + : base(fixtureName) + { + this.attribute = attribute; + } + + public A Attribute + { + get { return this.attribute; } + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/TypeTestCaseBase.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/TypeTestCaseBase.cs.meta new file mode 100644 index 0000000..6a5ae6d --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/TypeTestCaseBase.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 274b79a4227194c9292e28840cfbc2f9 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/UnitContainer.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/UnitContainer.cs new file mode 100755 index 0000000..5073453 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/UnitContainer.cs @@ -0,0 +1,70 @@ +using System; +using System.ComponentModel; +using System.ComponentModel.Design; +using QuickGraph.Unit.Logging; + +namespace QuickGraph.Unit.Core +{ + public class UnitContainer : + Container, + IServiceContainer, + IUnitServices + { + private IServiceContainer services = new ServiceContainer(); + private ILoggerService loggerService = new LoggerService(); + + public UnitContainer() + { + this.AddService(typeof(ILoggerService), + this.loggerService + ); + Assert.ServiceProvider = this; + } + + public ILoggerService GetLoggerService() + { + return this.loggerService; + } + + #region IServiceContainer Members + public void AddService(Type serviceType, object serviceInstance) + { + this.services.AddService(serviceType, serviceInstance); + } + public void AddService(Type serviceType, ServiceCreatorCallback callback, bool promote) + { + this.services.AddService(serviceType, callback, promote); + } + public void AddService(Type serviceType, ServiceCreatorCallback callback) + { + this.services.AddService(serviceType, callback); + } + public void AddService(Type serviceType, object serviceInstance, bool promote) + { + this.services.AddService(serviceType, serviceInstance, promote); + } + public void RemoveService(Type serviceType, bool promote) + { + this.services.RemoveService(serviceType, promote); + } + public void RemoveService(Type serviceType) + { + this.services.RemoveService(serviceType); + } + #endregion + + #region IServiceProvider Members + protected override object GetService(Type serviceType) + { + object service = this.services.GetService(serviceType); + if (service != null) + return service; + return base.GetService(serviceType); + } + object IServiceProvider.GetService(Type serviceType) + { + return this.GetService(serviceType); + } + #endregion + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/UnitContainer.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/UnitContainer.cs.meta new file mode 100644 index 0000000..ce0606c --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/UnitContainer.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 67346a009a8b4444aa480f1f46ee4c5b +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/UnitImages.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/UnitImages.cs new file mode 100755 index 0000000..e590165 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/UnitImages.cs @@ -0,0 +1,15 @@ +using System; +using System.Drawing; +using System.Drawing.Imaging; + +namespace QuickGraph.Unit.Core +{ + public enum UnitImages + { + Fixture, + TestCase, + LogMessage, + LogWarning, + LogError + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/UnitImages.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/UnitImages.cs.meta new file mode 100644 index 0000000..8e50ee2 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/UnitImages.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: a39445d95478b45c394b88703ced4cdf +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/UnitResourceManager.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/UnitResourceManager.cs new file mode 100755 index 0000000..2157b4a --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/UnitResourceManager.cs @@ -0,0 +1,191 @@ +using System; +using System.Collections; +using System.Drawing; +using System.Drawing.Imaging; +using System.Reflection; +using System.IO; +using System.Xml; +using System.Xml.Xsl; +using System.Threading; + +namespace QuickGraph.Unit.Core +{ + public static class UnitResourceManager + { + private static volatile object syncRoot = new object(); + private static XslCompiledTransform htmlReport = null; + private static XslCompiledTransform htmlFixtureReport = null; + private static XslCompiledTransform htmlSummaryReport = null; + private static XslCompiledTransform htmlHistoryReport = null; + private static bool initialized = false; + private static DirectoryInfo directory; + + public static Object SyncRoot + { + get { return syncRoot; } + } + + public static XslCompiledTransform HtmlReport + { + get + { + lock (syncRoot) + { + if (htmlReport != null) + return htmlReport; + + htmlReport = new XslCompiledTransform(); + XsltSettings settings = new XsltSettings(); + settings.EnableScript = true; + htmlReport.Load( + Path.Combine(directory.FullName,"unittest.xslt"), + settings, + new XmlUrlResolver() + ); + return htmlReport; + } + } + } + + public static XslCompiledTransform HtmlFixtureReport + { + get + { + lock (syncRoot) + { + if (htmlFixtureReport != null) + return htmlFixtureReport; + + htmlFixtureReport = new XslCompiledTransform(); + XsltSettings settings = new XsltSettings(); + settings.EnableScript = true; + htmlFixtureReport.Load( + Path.Combine(directory.FullName,"fixturetest.xslt"), + settings, + new XmlUrlResolver() + ); + return htmlFixtureReport; + } + } + } + + public static XslCompiledTransform HtmlSummaryReport + { + get + { + lock (syncRoot) + { + if (htmlSummaryReport != null) + return htmlSummaryReport; + + htmlSummaryReport = new XslCompiledTransform(); + XsltSettings settings = new XsltSettings(); + settings.EnableScript = true; + htmlSummaryReport.Load( + Path.Combine(directory.FullName,"unittestframes.xslt"), + settings, + new XmlUrlResolver() + ); + return htmlSummaryReport; + } + } + } + + public static XslCompiledTransform HtmlHistoryReport + { + get + { + lock (syncRoot) + { + if (htmlHistoryReport != null) + return htmlHistoryReport; + + htmlHistoryReport = new XslCompiledTransform(); + htmlHistoryReport.Load( + Path.Combine(directory.FullName,"unittesthistory.xslt") + ); + return htmlHistoryReport; + } + } + } + + public static void DumpResources() + { + if (!initialized) + { + DumpResources(null); + initialized = true; + } + } + + public static void DumpResources(string path) + { + lock(syncRoot) + { + if (path == null) + path = "."; + + directory = new DirectoryInfo(path); + DumpResource("quickgraph.css", path); + DumpResource("common.xslt", path); + DumpResource("report.js", path); + DumpResource("unittest.xslt", path); + DumpResource("unittesthistory.xslt", path); + DumpResource("unittestframes.xslt", path); + DumpResource("fixturetest.xslt", path); + foreach (UnitImages ui in Enum.GetValues(typeof(UnitImages))) + DumpImage(ui.ToString(), path); + DumpImage("unit", path); + DumpImage("unit.banner", path); + QuickGraphResourceManager.DumpResources(path); + } + } + + private static void DumpResource(string resourceName, string path) + { + using (StreamWriter writer = new StreamWriter(Path.Combine(path, resourceName))) + { + string res = "QuickGraph.Unit." + resourceName; + Stream stream = typeof(UnitResourceManager).Assembly.GetManifestResourceStream(res); + if (stream == null) + throw new ApplicationException("Could not find resource " + res); + using (StreamReader reader = new StreamReader(stream)) + { + writer.Write(reader.ReadToEnd()); + } + } + } + + private static void DumpImage(string resourceName, string path) + { + using (Image image = GetImage(resourceName)) + { + string fileName = String.Format( + "{0}.png", Path.Combine(path, resourceName) + ); + image.Save(fileName, System.Drawing.Imaging.ImageFormat.Png); + } + } + + public static Image GetImage(string imageName) + { + string resource = String.Format("QuickGraph.Unit.{0}.png", imageName); + Stream stream = typeof(UnitResourceManager).Assembly + .GetManifestResourceStream(resource); + if (stream == null) + throw new ApplicationException("Could not find resource " + resource); + Image img = Image.FromStream(stream); + return img; + } + + public static Image GetLogo() + { + return GetImage("unit"); + } + + public static Image GetLogoBanner() + { + return GetImage("unit.banner"); + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/UnitResourceManager.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/UnitResourceManager.cs.meta new file mode 100644 index 0000000..b3e97b4 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Core/UnitResourceManager.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b04629b0600ff4a0bbdacb6f6ca8b9e0 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CulturesAttribute.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CulturesAttribute.cs new file mode 100755 index 0000000..06538a7 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CulturesAttribute.cs @@ -0,0 +1,57 @@ +using System; +using System.Threading; +using System.Globalization; +using QuickGraph.Unit.Core; + +namespace QuickGraph.Unit +{ + [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple=false, Inherited=true)] + public sealed class CulturesAttribute : TestDecoratorAttributeBase + { + private string cultures; + + public CulturesAttribute(string cultures) + { + if (String.IsNullOrEmpty(cultures)) + throw new ArgumentException("cultures"); + this.cultures = cultures; + } + + public string[] GetCultures() + { + return this.cultures.Split(';'); + } + + public override ITestCase Decorate(ITestCase testCase) + { + return new CulturesTestCase(testCase, this); + } + + private sealed class CulturesTestCase : TypeDecoratorTestCaseBase + { + public CulturesTestCase(ITestCase testCase, CulturesAttribute attribute) + : base(testCase, attribute) + { } + + public override void Run(object fixture) + { + CultureInfo oldCulture = Thread.CurrentThread.CurrentCulture; + System.Runtime.CompilerServices.RuntimeHelpers.PrepareConstrainedRegions(); + try + { + foreach (string cultureName in this.Attribute.GetCultures()) + { + Console.WriteLine("Setting culture: {0}", cultureName); + CultureInfo culture = new CultureInfo(cultureName); + Thread.CurrentThread.CurrentCulture = culture; + this.TestCase.Run(fixture); + } + } + finally + { + Thread.CurrentThread.CurrentCulture = oldCulture; + } + } + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CulturesAttribute.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CulturesAttribute.cs.meta new file mode 100644 index 0000000..8b0f040 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CulturesAttribute.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e23d2b4e1faf045a3a2adfacccaeb59b +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CurrentFixtureAttribute.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CurrentFixtureAttribute.cs new file mode 100755 index 0000000..e57ea38 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CurrentFixtureAttribute.cs @@ -0,0 +1,8 @@ +using System; + +namespace QuickGraph.Unit +{ + [AttributeUsage(AttributeTargets.Class,AllowMultiple =false, Inherited =false)] + public sealed class CurrentFixtureAttribute : Attribute + {} +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CurrentFixtureAttribute.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CurrentFixtureAttribute.cs.meta new file mode 100644 index 0000000..bf98c06 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/CurrentFixtureAttribute.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 65cd40d402d0e4b40901f5e63bb42439 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Data.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Data.meta new file mode 100644 index 0000000..185a5a8 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Data.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: 6f1e855c6862b4ccc9b21758cf7532cc +folderAsset: yes +DefaultImporter: + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Data/unit.sql b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Data/unit.sql new file mode 100755 index 0000000..e69de29 diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Data/unit.sql.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Data/unit.sql.meta new file mode 100644 index 0000000..77d2f7b --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Data/unit.sql.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: fbaff356d117c41eda433f9bbe12bcc6 +DefaultImporter: + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/DataFixtureAttribute.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/DataFixtureAttribute.cs new file mode 100755 index 0000000..31b36cc --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/DataFixtureAttribute.cs @@ -0,0 +1,79 @@ +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Xml.XPath; +using QuickGraph.Unit.Core; + +namespace QuickGraph.Unit +{ + [AttributeUsage(AttributeTargets.Class, AllowMultiple=false, Inherited=true)] + public sealed class DataFixtureAttribute : TestFixtureAttributeBase + { + public override IEnumerable CreateFixtures(Type fixtureType) + { + foreach(DataProviderAttributeBase dataProviderAttribute + in fixtureType.GetCustomAttributes(typeof(DataProviderAttributeBase),true)) + { + yield return new DataFixture( + this, + fixtureType, + dataProviderAttribute); + } + } + + private sealed class DataFixture : TypeFixtureBase + { + private IDataProvider dataProvider; + + public DataFixture( + DataFixtureAttribute attribute, + Type fixtureType, + IDataProvider dataProvider + ) + : base(attribute, fixtureType) + { + this.dataProvider = dataProvider; + } + + public IDataProvider DataProvider + { + get { return this.dataProvider; } + } + + public override IEnumerable CreateTestCases() + { + // load data + XPathNavigator navigator = this.DataProvider.GetData().CreateNavigator(); + + foreach(MethodInfo method in ReflectionHelper.GetMethods( + this.FixtureType, typeof(DataTestAttribute))) + { + foreach (DataTestAttribute dataTestAttribute in + method.GetCustomAttributes(typeof(DataTestAttribute), true)) + { + int i = 0; + foreach(XPathNavigator node in navigator.Select(dataTestAttribute.Select)) + { + DataTestCase test = new DataTestCase( + this.Name, + method, + node, + i.ToString() + ); + i++; + yield return test; + } + } + } + } + + public override String Name + { + get + { + return String.Format("{0}.{1}",base.Name, this.DataProvider.Name); + } + } + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/DataFixtureAttribute.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/DataFixtureAttribute.cs.meta new file mode 100644 index 0000000..c5e2e16 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/DataFixtureAttribute.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b5493c6aada504b6684515d95b7ae91a +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/DataTestAttribute.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/DataTestAttribute.cs new file mode 100755 index 0000000..b780686 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/DataTestAttribute.cs @@ -0,0 +1,41 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Reflection; +using QuickGraph.Unit.Core; + +namespace QuickGraph.Unit +{ + [AttributeUsage(AttributeTargets.Method, AllowMultiple=true, Inherited=true)] + public sealed class DataTestAttribute : TestAttributeBase + { + private string select = "//*"; + private Type dataType; + + public DataTestAttribute(string select) + { + if (String.IsNullOrEmpty(select)) + throw new ArgumentNullException("select"); + this.select = select; + } + + public string Select + { + get { return this.select; } + set { this.select = value; } + } + + public Type DataType + { + get { return this.dataType; } + set { this.dataType = value; } + } + + public override IEnumerable CreateTests( + IFixture fixture, + MethodInfo method) + { + yield return null; + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/DataTestAttribute.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/DataTestAttribute.cs.meta new file mode 100644 index 0000000..2c7578d --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/DataTestAttribute.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 1dbaee4dc3485456ea9d6f29625c72b7 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/DurationAttribute.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/DurationAttribute.cs new file mode 100755 index 0000000..260b439 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/DurationAttribute.cs @@ -0,0 +1,45 @@ +using System; +using QuickGraph.Unit.Monitoring; +using QuickGraph.Unit.Core; + +namespace QuickGraph.Unit +{ + [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, + AllowMultiple=false, Inherited=true)] + public sealed class DurationAttribute : TestDecoratorAttributeBase + { + private double maxDuration; + + public DurationAttribute(double maxDuration) + { + this.maxDuration = maxDuration; + } + + public double MaxDuration + { + get { return this.maxDuration; } + } + + public override ITestCase Decorate(ITestCase test) + { + return new DurationTestCase(test, this); + } + + private sealed class DurationTestCase : TypeDecoratorTestCaseBase + { + public DurationTestCase(ITestCase testCase, DurationAttribute attribute) + :base(testCase, attribute) + {} + + public override void Run(object fixture) + { + TimeMonitor monitor = new TimeMonitor(); + monitor.Start(); + this.TestCase.Run(fixture); + monitor.Stop(); + + Assert.IsLowerEqual(monitor.Duration, this.Attribute.MaxDuration); + } + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/DurationAttribute.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/DurationAttribute.cs.meta new file mode 100644 index 0000000..11a3f93 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/DurationAttribute.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 4d62be9b13fea4933ad7eb62311e3f84 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/DynamicTestAttribute.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/DynamicTestAttribute.cs new file mode 100755 index 0000000..0f3ceca --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/DynamicTestAttribute.cs @@ -0,0 +1,43 @@ +using System; +using System.Collections.Generic; +using System.Reflection; +using QuickGraph.Unit.Core; + +namespace QuickGraph.Unit +{ + [AttributeUsage(AttributeTargets.Method, AllowMultiple=false, Inherited=true)] + public sealed class DynamicTestAttribute : TestAttributeBase + { + public override IEnumerable CreateTests( + IFixture fixture, + MethodInfo method) + { + if (!typeof(IEnumerable).IsAssignableFrom(method.ReturnType)) + { + List tests = new List(); + tests.Add(new BadTestCase( + fixture.Name, + method.Name, + "A method tagged with DynamicTest must return IEnumerable", + null + )); + return tests; + } + + // the fixture does not exist yet. + Object fixtureInstance = null; + System.Runtime.CompilerServices.RuntimeHelpers.PrepareConstrainedRegions(); + try + { + fixtureInstance = fixture.CreateInstance(); + return (IEnumerable)method.Invoke(fixtureInstance, null); + } + finally + { + IDisposable disposable = fixtureInstance as IDisposable; + if (disposable != null) + disposable.Dispose(); + } + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/DynamicTestAttribute.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/DynamicTestAttribute.cs.meta new file mode 100644 index 0000000..7b8b95f --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/DynamicTestAttribute.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 53f9f4ab60f3c4000aed2373d86c4657 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Exceptions.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Exceptions.meta new file mode 100644 index 0000000..1a7889d --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Exceptions.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: a273535e3f01d461180ce8b75eb711eb +folderAsset: yes +DefaultImporter: + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Exceptions/AssertionException.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Exceptions/AssertionException.cs new file mode 100755 index 0000000..09e00a3 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Exceptions/AssertionException.cs @@ -0,0 +1,23 @@ +using System; +using System.IO; +using System.Reflection; +using System.Collections; +using System.Diagnostics; +using System.CodeDom.Compiler; +using System.Collections.Generic; +using System.Xml; + +namespace QuickGraph.Unit.Exceptions +{ + [Serializable] + public class AssertionException : ApplicationException + { + public AssertionException() { } + public AssertionException(string message) : base(message) { } + public AssertionException(string message, System.Exception inner) : base(message, inner) { } + public AssertionException( + System.Runtime.Serialization.SerializationInfo info, + System.Runtime.Serialization.StreamingContext context) + : base(info, context) { } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Exceptions/AssertionException.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Exceptions/AssertionException.cs.meta new file mode 100644 index 0000000..d6bd142 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Exceptions/AssertionException.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 7c79525c41fc847848cba0b9a8b64296 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Exceptions/AssumptionFailedException.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Exceptions/AssumptionFailedException.cs new file mode 100755 index 0000000..8f48d56 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Exceptions/AssumptionFailedException.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace QuickGraph.Unit.Exceptions +{ + [Serializable] + public class AssumptionFailureException : ApplicationException + { + public AssumptionFailureException() { } + public AssumptionFailureException(string message) : base(message) { } + public AssumptionFailureException(string message, Exception inner) : base(message, inner) { } + protected AssumptionFailureException( + System.Runtime.Serialization.SerializationInfo info, + System.Runtime.Serialization.StreamingContext context) + : base(info, context) { } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Exceptions/AssumptionFailedException.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Exceptions/AssumptionFailedException.cs.meta new file mode 100644 index 0000000..3d3f99b --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Exceptions/AssumptionFailedException.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: f511e320436f64e60bd98d0d3ac19e89 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Exceptions/CompilationException.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Exceptions/CompilationException.cs new file mode 100755 index 0000000..ce71434 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Exceptions/CompilationException.cs @@ -0,0 +1,50 @@ +using System; +using System.Runtime.Serialization; +using System.IO; +using System.CodeDom.Compiler; + +namespace QuickGraph.Unit.Exceptions +{ + [Serializable] + public class CompilationException : UnitException + { + private string body; + public CompilationException( + CodeDomProvider provider, + CompilerParameters parameters, + CompilerResults results, + params String[] sources + ) + { + StringWriter sw = new StringWriter(); + sw.WriteLine("Compilation: {0} errors", results.Errors.Count); + sw.WriteLine("Compiler: {0}", provider.FileExtension); + sw.WriteLine("CompilerParameters: {0}", parameters.ToString()); + foreach (CompilerError error in results.Errors) + { + sw.WriteLine(error.ToString()); + } + sw.WriteLine("Sources:"); + foreach (string source in sources) + sw.WriteLine(source); + + this.body = sw.ToString(); + } + + public override string Message + { + get + { + return "Compilation Error"; + } + } + + public override string ToString() + { + return String.Format("{0}\n{1}", + this.body, + base.ToString() + ); + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Exceptions/CompilationException.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Exceptions/CompilationException.cs.meta new file mode 100644 index 0000000..2fd5ab9 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Exceptions/CompilationException.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 0f5ec11007fa14740b6bf521e9b871fe +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Exceptions/DebugFailureException.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Exceptions/DebugFailureException.cs new file mode 100755 index 0000000..8ac20a5 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Exceptions/DebugFailureException.cs @@ -0,0 +1,15 @@ +using System; + +namespace QuickGraph.Unit.Exceptions +{ + [System.Serializable] + public sealed class DebugFailureException : System.ApplicationException + { + public DebugFailureException() { } + public DebugFailureException(string message) : base( message ) { } + public DebugFailureException(string message, System.Exception inner) : base( message, inner ) { } + public DebugFailureException( + System.Runtime.Serialization.SerializationInfo info, + System.Runtime.Serialization.StreamingContext context) : base( info, context ) { } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Exceptions/DebugFailureException.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Exceptions/DebugFailureException.cs.meta new file mode 100644 index 0000000..5cbae23 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Exceptions/DebugFailureException.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b2af4a56731bc40a7a73f430748cf963 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Exceptions/ExceptionMessageDoesNotMatchException.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Exceptions/ExceptionMessageDoesNotMatchException.cs new file mode 100755 index 0000000..852badc --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Exceptions/ExceptionMessageDoesNotMatchException.cs @@ -0,0 +1,17 @@ +using System; + +namespace QuickGraph.Unit.Exceptions +{ + [Serializable] + public sealed class ExceptionMessageDoesNotMatchException : Exception + { + public ExceptionMessageDoesNotMatchException( + INameMatcher matcher, + Exception innerException + ) + :base( + String.Format("Exception message {0} does not match {1}", innerException.Message, matcher), + innerException) + { } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Exceptions/ExceptionMessageDoesNotMatchException.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Exceptions/ExceptionMessageDoesNotMatchException.cs.meta new file mode 100644 index 0000000..a8232df --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Exceptions/ExceptionMessageDoesNotMatchException.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 4c75b5036a6d74053b6cbf616a1451e4 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Exceptions/ExceptionNotThrowedException.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Exceptions/ExceptionNotThrowedException.cs new file mode 100755 index 0000000..c1cd040 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Exceptions/ExceptionNotThrowedException.cs @@ -0,0 +1,12 @@ +using System; + +namespace QuickGraph.Unit.Exceptions +{ + [Serializable] + public sealed class ExceptionNotThrowedException : UnitException + { + public ExceptionNotThrowedException(Type expectedException) + : base("Expected " + expectedException.FullName) + { } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Exceptions/ExceptionNotThrowedException.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Exceptions/ExceptionNotThrowedException.cs.meta new file mode 100644 index 0000000..4a37e2b --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Exceptions/ExceptionNotThrowedException.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ba9806185f873466eb880ef80dc53606 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Exceptions/ExceptionTypeMistmatchException.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Exceptions/ExceptionTypeMistmatchException.cs new file mode 100755 index 0000000..ce63731 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Exceptions/ExceptionTypeMistmatchException.cs @@ -0,0 +1,18 @@ +using System; + +namespace QuickGraph.Unit.Exceptions +{ + [Serializable] + public sealed class ExceptionTypeMistmatchException : UnitException + { + public ExceptionTypeMistmatchException(Type expectedExceptionType, Exception actualException) + : base( + String.Format("Expected {0}, got {1}: {2}", + expectedExceptionType.Name, + actualException.GetType().Name, + actualException.Message + ), + actualException) + { } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Exceptions/ExceptionTypeMistmatchException.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Exceptions/ExceptionTypeMistmatchException.cs.meta new file mode 100644 index 0000000..7410aa0 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Exceptions/ExceptionTypeMistmatchException.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 7229fac9a9ce84be385f1906f460a8da +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Exceptions/FixtureReflectionFailedException.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Exceptions/FixtureReflectionFailedException.cs new file mode 100755 index 0000000..c523a95 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Exceptions/FixtureReflectionFailedException.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace QuickGraph.Unit.Exceptions +{ + [Serializable] + public sealed class FixtureReflectionFailedException : UnitException + { + public FixtureReflectionFailedException() { } + public FixtureReflectionFailedException(string message) : base(message) { } + public FixtureReflectionFailedException(string message, Exception inner) : base(message, inner) { } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Exceptions/FixtureReflectionFailedException.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Exceptions/FixtureReflectionFailedException.cs.meta new file mode 100644 index 0000000..4f5c5ea --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Exceptions/FixtureReflectionFailedException.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 4d06be5a23da84ee491d66b71502b230 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Exceptions/FixtureTimedOutException.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Exceptions/FixtureTimedOutException.cs new file mode 100755 index 0000000..7ba9900 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Exceptions/FixtureTimedOutException.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace QuickGraph.Unit.Exceptions +{ + [Serializable] + public sealed class FixtureTimedOutException : ApplicationException + { + public FixtureTimedOutException(string message) + : base(message) + { } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Exceptions/FixtureTimedOutException.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Exceptions/FixtureTimedOutException.cs.meta new file mode 100644 index 0000000..03b5c04 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Exceptions/FixtureTimedOutException.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e6d46ce19b2d44a15aa8ff4afc042d20 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Exceptions/IgnoreException.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Exceptions/IgnoreException.cs new file mode 100755 index 0000000..ac0f93b --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Exceptions/IgnoreException.cs @@ -0,0 +1,19 @@ +using System; + +namespace QuickGraph.Unit.Exceptions +{ + [Serializable] + public sealed class IgnoreException : UnitException + { + // + // For guidelines regarding the creationg of new exception types, see + // http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpgenref/html/cpconerrorraisinghandlingguidelines.asp + // and + // http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dncscol/html/csharp07192001.asp + // + + public IgnoreException() { } + public IgnoreException(string message) : base(message) { } + public IgnoreException(string message, Exception inner) : base(message, inner) { } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Exceptions/IgnoreException.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Exceptions/IgnoreException.cs.meta new file mode 100644 index 0000000..1b977ee --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Exceptions/IgnoreException.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e5e510ca7ea6f484f849648e4598f184 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Exceptions/UnitException.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Exceptions/UnitException.cs new file mode 100755 index 0000000..f91d7e7 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Exceptions/UnitException.cs @@ -0,0 +1,23 @@ +using System; +using System.IO; +using System.Reflection; +using System.Collections; +using System.Diagnostics; +using System.CodeDom.Compiler; +using System.Collections.Generic; +using System.Xml; + +namespace QuickGraph.Unit.Exceptions +{ + [Serializable] + public class UnitException : ApplicationException + { + public UnitException() { } + public UnitException(string message) : base(message) { } + public UnitException(string message, System.Exception inner) : base(message, inner) { } + public UnitException( + System.Runtime.Serialization.SerializationInfo info, + System.Runtime.Serialization.StreamingContext context) + : base(info, context) { } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Exceptions/UnitException.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Exceptions/UnitException.cs.meta new file mode 100644 index 0000000..1526122 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Exceptions/UnitException.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 68c498fc9ddc546f99242871f8891119 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/ExpectedArgumentExceptionAttribute.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/ExpectedArgumentExceptionAttribute.cs new file mode 100755 index 0000000..1fec87f --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/ExpectedArgumentExceptionAttribute.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace QuickGraph.Unit +{ + [AttributeUsage(AttributeTargets.Method, AllowMultiple =false, Inherited =true)] + public sealed class ExpectedArgumentExceptionAttribute : ExpectedExceptionAttribute + { + public ExpectedArgumentExceptionAttribute() + :base(typeof(ArgumentException)) + {} + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/ExpectedArgumentExceptionAttribute.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/ExpectedArgumentExceptionAttribute.cs.meta new file mode 100644 index 0000000..0ce7ed0 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/ExpectedArgumentExceptionAttribute.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: bf1a6bc0a6dcd4181bedecfa1d6dc764 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/ExpectedArgumentNullExceptionAttribute.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/ExpectedArgumentNullExceptionAttribute.cs new file mode 100755 index 0000000..4de5a0d --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/ExpectedArgumentNullExceptionAttribute.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace QuickGraph.Unit +{ + [AttributeUsage(AttributeTargets.Method, AllowMultiple =false, Inherited =true)] + public sealed class ExpectedArgumentNullExceptionAttribute : ExpectedExceptionAttribute + { + public ExpectedArgumentNullExceptionAttribute() + :base(typeof(ArgumentNullException)) + {} + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/ExpectedArgumentNullExceptionAttribute.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/ExpectedArgumentNullExceptionAttribute.cs.meta new file mode 100644 index 0000000..398fd22 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/ExpectedArgumentNullExceptionAttribute.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 2dfbb0a15324f4bcfae5340e0d4af947 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/FactoryAttribute.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/FactoryAttribute.cs new file mode 100755 index 0000000..cd27d86 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/FactoryAttribute.cs @@ -0,0 +1,30 @@ +using System; + +namespace QuickGraph.Unit +{ + [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)] + public sealed class FactoryAttribute : Attribute + { + private Type factoredType = null; + + public FactoryAttribute() { } + public FactoryAttribute(Type factoredType) + { + if (factoredType == null) + throw new ArgumentNullException("factoredType"); + this.factoredType = factoredType; + } + + public Type FactoredType + { + get + { + return this.factoredType; + } + set + { + this.factoredType = value; + } + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/FactoryAttribute.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/FactoryAttribute.cs.meta new file mode 100644 index 0000000..0ee4598 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/FactoryAttribute.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 0b2abbc4e0f3241b0804fb88921adc7b +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/FileAssert.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/FileAssert.cs new file mode 100755 index 0000000..8e5133a --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/FileAssert.cs @@ -0,0 +1,48 @@ +using System; +using System.IO; + +namespace QuickGraph.Unit +{ + public static class FileAssert + { + public static void Display(string fileName, bool showLineNumbers) + { + Exists(fileName); + using(StreamReader reader = new StreamReader(fileName)) + { + string source = reader.ReadToEnd(); + if (showLineNumbers) + source = CompilerAssert.InsertLineNumbers(source); + Console.WriteLine(source); + } + } + + public static void Exists(string fileName) + { + Assert.IsTrue(File.Exists(fileName), + "{0} does not exist", fileName); + } + + public static void AreEqual(string left, string right) + { + Exists(left); + Exists(right); + + FileInfo leftInfo = new FileInfo(left); + FileInfo rightInfo = new FileInfo(right); + + Assert.AreEqual(leftInfo.Length, rightInfo.Length, + "File lengths are not equal between [{0}] and [{1}]", + left, right); + + using (StreamReader leftReader = new StreamReader(left)) + using (StreamReader rightReader = new StreamReader(right)) + { + StreamAssert.AreEqual(leftReader, rightReader); + } + } + + + } +} + diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/FileAssert.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/FileAssert.cs.meta new file mode 100644 index 0000000..2fbdbdc --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/FileAssert.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 7a29f01c860594df693a512423bace5b +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Filters.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Filters.meta new file mode 100644 index 0000000..5d23410 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Filters.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: 1f8784b6b1c4d495fa612e85e1b48fbb +folderAsset: yes +DefaultImporter: + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Filters/AndFixtureFilter.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Filters/AndFixtureFilter.cs new file mode 100755 index 0000000..1764122 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Filters/AndFixtureFilter.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace QuickGraph.Unit.Filters +{ + public sealed class AndFixtureFilter : BinaryOperationFixtureFilterBase + { + public AndFixtureFilter( + IFixtureFilter left, + IFixtureFilter right) + : base(left, right) + { } + + public override bool Filter(IFixture fixture) + { + return this.Left.Filter(fixture) && this.Right.Filter(fixture); + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Filters/AndFixtureFilter.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Filters/AndFixtureFilter.cs.meta new file mode 100644 index 0000000..37e4e85 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Filters/AndFixtureFilter.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 9072b91d5ecb44717ab0c9bf44bdea43 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Filters/AndTestCaseFilter.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Filters/AndTestCaseFilter.cs new file mode 100755 index 0000000..f5e997a --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Filters/AndTestCaseFilter.cs @@ -0,0 +1,16 @@ +using System; + +namespace QuickGraph.Unit.Filters +{ + public sealed class AndTestCaseFilter : BinaryOperationTestCaseBase + { + public AndTestCaseFilter(ITestCaseFilter left, ITestCaseFilter right) + : base(left, right) + { } + + public override bool Filter(IFixture fixture, ITestCase testCase) + { + return Left.Filter(fixture, testCase) && Right.Filter(fixture, testCase); + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Filters/AndTestCaseFilter.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Filters/AndTestCaseFilter.cs.meta new file mode 100644 index 0000000..ce58bdd --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Filters/AndTestCaseFilter.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: bd1e55f8b942c4ed8a7ec1996d5936b5 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Filters/AnyFixtureFilter.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Filters/AnyFixtureFilter.cs new file mode 100755 index 0000000..cfca514 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Filters/AnyFixtureFilter.cs @@ -0,0 +1,11 @@ +using System; +namespace QuickGraph.Unit.Filters +{ + public sealed class AnyFixtureFilter : IFixtureFilter + { + public bool Filter(IFixture fixture) + { + return true; + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Filters/AnyFixtureFilter.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Filters/AnyFixtureFilter.cs.meta new file mode 100644 index 0000000..18aaab4 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Filters/AnyFixtureFilter.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 0fb1ed8c4d81d4db38c82e44bb5331ee +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Filters/AnyTestCaseFilter.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Filters/AnyTestCaseFilter.cs new file mode 100755 index 0000000..f6183e9 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Filters/AnyTestCaseFilter.cs @@ -0,0 +1,12 @@ +using System; + +namespace QuickGraph.Unit.Filters +{ + public sealed class AnyTestCaseFilter : ITestCaseFilter + { + public bool Filter(IFixture fixture, ITestCase test) + { + return true; + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Filters/AnyTestCaseFilter.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Filters/AnyTestCaseFilter.cs.meta new file mode 100644 index 0000000..380309f --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Filters/AnyTestCaseFilter.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 8521a95299d864ac0b02bb133b37ff79 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Filters/BinaryOperationFixtureFilterBase.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Filters/BinaryOperationFixtureFilterBase.cs new file mode 100755 index 0000000..c8b3e33 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Filters/BinaryOperationFixtureFilterBase.cs @@ -0,0 +1,30 @@ +using System; + +namespace QuickGraph.Unit.Filters +{ + public abstract class BinaryOperationFixtureFilterBase : IFixtureFilter + { + private IFixtureFilter left; + private IFixtureFilter right; + + public BinaryOperationFixtureFilterBase( + IFixtureFilter left, + IFixtureFilter right) + { + this.left = left; + this.right = right; + } + + public IFixtureFilter Left + { + get { return this.left; } + } + + public IFixtureFilter Right + { + get { return this.right; } + } + + public abstract bool Filter(IFixture fixture); + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Filters/BinaryOperationFixtureFilterBase.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Filters/BinaryOperationFixtureFilterBase.cs.meta new file mode 100644 index 0000000..62bebb1 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Filters/BinaryOperationFixtureFilterBase.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 8f1c9554d3c6c4d4b9c13217cbfaaacf +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Filters/BinaryOperationTestCaseFilterBase.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Filters/BinaryOperationTestCaseFilterBase.cs new file mode 100755 index 0000000..9bc52ae --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Filters/BinaryOperationTestCaseFilterBase.cs @@ -0,0 +1,30 @@ +using System; + +namespace QuickGraph.Unit.Filters +{ + public abstract class BinaryOperationTestCaseBase : ITestCaseFilter + { + private ITestCaseFilter left; + private ITestCaseFilter right; + + public BinaryOperationTestCaseBase( + ITestCaseFilter left, + ITestCaseFilter right) + { + this.left = left; + this.right = right; + } + + public ITestCaseFilter Left + { + get { return this.left; } + } + + public ITestCaseFilter Right + { + get { return this.right; } + } + + public abstract bool Filter(IFixture fixture, ITestCase testCase); + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Filters/BinaryOperationTestCaseFilterBase.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Filters/BinaryOperationTestCaseFilterBase.cs.meta new file mode 100644 index 0000000..73bf179 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Filters/BinaryOperationTestCaseFilterBase.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 6908200c889cc42e79d60dce488831f2 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Filters/CategoryFixtureFilter.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Filters/CategoryFixtureFilter.cs new file mode 100755 index 0000000..74edf4a --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Filters/CategoryFixtureFilter.cs @@ -0,0 +1,29 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace QuickGraph.Unit.Filters +{ + public sealed class CategoryFixtureFilter : IFixtureFilter + { + private string categories; + + public CategoryFixtureFilter(IEnumerable categories) + { + this.categories = ""; + foreach (string category in categories) + this.categories += ";"+category.ToLower(); + } + + public bool Filter(IFixture fixture) + { + foreach (string category in fixture.Categories) + { + if (this.categories.Contains(category.ToLower())) + return true; + } + + return false; + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Filters/CategoryFixtureFilter.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Filters/CategoryFixtureFilter.cs.meta new file mode 100644 index 0000000..bda12b1 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Filters/CategoryFixtureFilter.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: de898c1ace94e4a91b28db6450fbc345 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Filters/CurrentFixtureFilter.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Filters/CurrentFixtureFilter.cs new file mode 100755 index 0000000..e4c5efe --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Filters/CurrentFixtureFilter.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; + +namespace QuickGraph.Unit.Filters +{ + public sealed class CurrentFixtureFilter : IFixtureFilter + { + public bool Filter(IFixture fixture) + { + return fixture.IsCurrent; + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Filters/CurrentFixtureFilter.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Filters/CurrentFixtureFilter.cs.meta new file mode 100644 index 0000000..b42063a --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Filters/CurrentFixtureFilter.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 027bdc3686eb2425c8c286f60ac9648e +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Filters/FailureFilter.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Filters/FailureFilter.cs new file mode 100755 index 0000000..9bad7ed --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Filters/FailureFilter.cs @@ -0,0 +1,42 @@ +using System; +using QuickGraph.Unit.Serialization; +using QuickGraph.Unit.Core; + +namespace QuickGraph.Unit.Filters +{ + public sealed class FailureFilter : IFixtureFilter, ITestCaseFilter + { + private XmlTestBatchSearcher searcher; + + public FailureFilter(XmlTestBatch testBatch) + { + if (testBatch == null) + throw new ArgumentNullException("testBatch"); + this.searcher = new XmlTestBatchSearcher(testBatch); + } + + public XmlTestBatchSearcher Searcher + { + get { return this.searcher; } + } + + public bool Filter(IFixture fixture) + { + XmlFixture xfixture = this.Searcher.GetFixture(fixture.Name); + + if (xfixture == null) + return false; + else + return xfixture.Counter.FailureCount > 0; + } + + public bool Filter(IFixture fixture, ITestCase testCase) + { + XmlTestCase xtestCase = this.Searcher.GetTestCase(fixture.Name, testCase.Name); + if (xtestCase == null) + return false; + else + return xtestCase.State == TestState.Failure; + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Filters/FailureFilter.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Filters/FailureFilter.cs.meta new file mode 100644 index 0000000..b6d3c0b --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Filters/FailureFilter.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: f0849321aa0b34088831f3e1c3e82cc6 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Filters/ScopeFixtureFilter.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Filters/ScopeFixtureFilter.cs new file mode 100755 index 0000000..5901a84 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Filters/ScopeFixtureFilter.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; + +namespace QuickGraph.Unit.Filters +{ + public sealed class ScopeFixtureFilter : IFixtureFilter + { + private List scopes = new List(); + + public ScopeFixtureFilter(IEnumerable scopes) + { + this.scopes.AddRange(scopes); + } + + public IList Scopes + { + get { return this.scopes; } + } + + public bool Filter(IFixture fixture) + { + foreach (string scope in scopes) + if (fixture.Name.ToLower().StartsWith(scope.ToLower())) + return true; + return false; + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Filters/ScopeFixtureFilter.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Filters/ScopeFixtureFilter.cs.meta new file mode 100644 index 0000000..3137456 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Filters/ScopeFixtureFilter.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 8d2088fb495b24265bb728bc49ec5b3d +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Filters/ScopeTestCaseFilter.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Filters/ScopeTestCaseFilter.cs new file mode 100755 index 0000000..ce347c8 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Filters/ScopeTestCaseFilter.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; + +namespace QuickGraph.Unit.Filters +{ + public sealed class ScopeTestCaseFilter : ITestCaseFilter + { + private List scopes = new List(); + + public ScopeTestCaseFilter(IEnumerable scopes) + { + this.scopes.AddRange(scopes); + } + + public IList Scopes + { + get { return this.scopes; } + } + + public bool Filter(IFixture fixture, ITestCase test) + { + foreach (string scope in scopes) + if (test.Name.ToLower().StartsWith(scope.ToLower())) + return true; + return false; + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Filters/ScopeTestCaseFilter.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Filters/ScopeTestCaseFilter.cs.meta new file mode 100644 index 0000000..ff05d5b --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Filters/ScopeTestCaseFilter.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: f8f9c5dc54f2e441b9face0b0455dc54 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Fixture.png b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Fixture.png new file mode 100755 index 0000000..9af539a Binary files /dev/null and b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Fixture.png differ diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Fixture.png.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Fixture.png.meta new file mode 100644 index 0000000..673827f --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Fixture.png.meta @@ -0,0 +1,46 @@ +fileFormatVersion: 2 +guid: 55de30eae58ff4a2bb8d18dec1d186cd +TextureImporter: + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + linearTexture: 0 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: -1 + mipBias: -1 + wrapMode: -1 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 0 + textureType: -1 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/IDataProvider.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/IDataProvider.cs new file mode 100755 index 0000000..67bd212 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/IDataProvider.cs @@ -0,0 +1,11 @@ +using System; +using System.Xml.XPath; + +namespace QuickGraph.Unit +{ + public interface IDataProvider + { + string Name { get;} + IXPathNavigable GetData(); + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/IDataProvider.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/IDataProvider.cs.meta new file mode 100644 index 0000000..d1d77c2 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/IDataProvider.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 60734716500ec4a93995aa5b7fc2ec66 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/IFixture.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/IFixture.cs new file mode 100755 index 0000000..3313986 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/IFixture.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Threading; + +namespace QuickGraph.Unit +{ + public interface IFixture + { + string Name { get;} + ApartmentState Apartment { get;} + int TimeOut { get;} + string Description { get;} + bool IsCurrent { get;} + + IEnumerable CreateTestCases(); + IList TestCaseDecorators { get;} + IList Categories { get;} + + Object CreateInstance(); + + MethodInfo FixtureSetUp { get;set;} + MethodInfo SetUp { get;set;} + MethodInfo TearDown { get;set;} + MethodInfo FixtureTearDown { get;set;} + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/IFixture.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/IFixture.cs.meta new file mode 100644 index 0000000..fcf4296 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/IFixture.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b972b7c7f0fc2472fb3466d2100689f3 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/IFixtureFactory.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/IFixtureFactory.cs new file mode 100755 index 0000000..62bed3c --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/IFixtureFactory.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; +using System.Reflection; + +namespace QuickGraph.Unit +{ + public interface IFixtureFactory + { + IEnumerable CreateFixtures(Type type); + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/IFixtureFactory.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/IFixtureFactory.cs.meta new file mode 100644 index 0000000..fadc9a0 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/IFixtureFactory.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 934c5da9a19ac4a3e9bd1251ea0021ba +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/IFixtureFilter.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/IFixtureFilter.cs new file mode 100755 index 0000000..99e3005 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/IFixtureFilter.cs @@ -0,0 +1,9 @@ +using System; + +namespace QuickGraph.Unit +{ + public interface IFixtureFilter + { + bool Filter(IFixture fixture); + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/IFixtureFilter.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/IFixtureFilter.cs.meta new file mode 100644 index 0000000..4793516 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/IFixtureFilter.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 7d2702fb4e167458d8202748f50433b1 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/ILoggerListener.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/ILoggerListener.cs new file mode 100755 index 0000000..7655423 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/ILoggerListener.cs @@ -0,0 +1,12 @@ +using System; + +namespace QuickGraph.Unit +{ + public interface ILoggerListener + { + void Log( + LogLevel level, + string message + ); + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/ILoggerListener.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/ILoggerListener.cs.meta new file mode 100644 index 0000000..1633d70 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/ILoggerListener.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 3a899bb9762eb41d5937cc850158de94 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/ILoggerService.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/ILoggerService.cs new file mode 100755 index 0000000..aaacdad --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/ILoggerService.cs @@ -0,0 +1,41 @@ +using System; +using System.Collections.Generic; + +namespace QuickGraph.Unit +{ + public interface ILoggerService + { + IList Listeners { get;} + + void Log( + LogLevel level, + string message); + void Log( + LogLevel level, + string format, + params object[] args + ); + void LogMessage( + string message + ); + void LogMessage( + string format, + params object[] args + ); + void LogWarning( + string message + ); + void LogWarning( + string format, + params object[] args + ); + void LogError(Exception ex); + void LogError( + string message + ); + void LogError( + string format, + params object[] args + ); + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/ILoggerService.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/ILoggerService.cs.meta new file mode 100644 index 0000000..cf0c78a --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/ILoggerService.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: c413e15eb21234c46950c15f3cdf2ec8 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/IParameterDomainFactory.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/IParameterDomainFactory.cs new file mode 100755 index 0000000..376b709 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/IParameterDomainFactory.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Reflection; +using QuickGraph.Operations; + +namespace QuickGraph.Unit +{ + public interface IParameterDomainFactory + { + void CreateDomains( + IList domains, + ParameterInfo parameter, + IFixture fixture); + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/IParameterDomainFactory.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/IParameterDomainFactory.cs.meta new file mode 100644 index 0000000..72e0569 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/IParameterDomainFactory.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 17a62bc83b2cf4dab8f7ce968a39490b +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/ITestCase.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/ITestCase.cs new file mode 100755 index 0000000..b6c0157 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/ITestCase.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; + +namespace QuickGraph.Unit +{ + public interface ITestCase + { + string FixtureName { get;} + string Name { get;} + string FullName { get;} + + IList Parameters { get;} + + void Run(Object fixture); + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/ITestCase.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/ITestCase.cs.meta new file mode 100644 index 0000000..8ba782c --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/ITestCase.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 604ee154bfeb3416eb953a649b30ba8e +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/ITestCaseDecorator.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/ITestCaseDecorator.cs new file mode 100755 index 0000000..9e266a4 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/ITestCaseDecorator.cs @@ -0,0 +1,7 @@ +namespace QuickGraph.Unit +{ + public interface ITestCaseDecorator + { + ITestCase Decorate(ITestCase test); + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/ITestCaseDecorator.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/ITestCaseDecorator.cs.meta new file mode 100644 index 0000000..40f7062 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/ITestCaseDecorator.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 019d032d9a84c4dd8abdd74a0792c0ab +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/ITestCaseFactory.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/ITestCaseFactory.cs new file mode 100755 index 0000000..a6662d7 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/ITestCaseFactory.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Reflection; + +namespace QuickGraph.Unit +{ + public interface ITestCaseFactory + { + IEnumerable CreateTests( + IFixture fixture, + MethodInfo method + ); + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/ITestCaseFactory.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/ITestCaseFactory.cs.meta new file mode 100644 index 0000000..be6a5e4 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/ITestCaseFactory.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 448614c4c568c4c2e9276a28617ec8f9 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/ITestCaseFilter.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/ITestCaseFilter.cs new file mode 100755 index 0000000..2f09aff --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/ITestCaseFilter.cs @@ -0,0 +1,7 @@ +namespace QuickGraph.Unit +{ + public interface ITestCaseFilter + { + bool Filter(IFixture fixture, ITestCase test); + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/ITestCaseFilter.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/ITestCaseFilter.cs.meta new file mode 100644 index 0000000..25197da --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/ITestCaseFilter.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 86b99a52088dc47a28be155a8b4251fc +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/ITestCaseParameterFactory.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/ITestCaseParameterFactory.cs new file mode 100755 index 0000000..6a8177a --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/ITestCaseParameterFactory.cs @@ -0,0 +1,10 @@ +using System; +using System.Collections.Generic; + +namespace QuickGraph.Unit +{ + public interface ITestCaseParameterFactory + { + IEnumerable CreateInstances(Type targetType); + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/ITestCaseParameterFactory.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/ITestCaseParameterFactory.cs.meta new file mode 100644 index 0000000..c2ef348 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/ITestCaseParameterFactory.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ec278b88757c64eb1a9cb5e52dee6bb1 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/ITestListener.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/ITestListener.cs new file mode 100755 index 0000000..f7f327b --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/ITestListener.cs @@ -0,0 +1,41 @@ +using System; +using System.Reflection; +using QuickGraph.Unit.Core; + +namespace QuickGraph.Unit +{ + public interface ITestListener + { + void Message(MessageImportance importance, string message); + void Warning(string message); + void Error(string message); + void Error(Exception ex); + void ReportsGenerated( + string historyXml, + string historyHtml, + string batchXml, + string batchHtml); + + void BeforeBatch(TestBatch batch); + void AfterBatch(TestBatch batch); + + void BeforeAssembly(TestAssembly testAssembly); + void AfterAssembly(TestAssembly testAssembly); + + void AssemblySetUp(Result result); + void AssemblyTearDown(Result result); + + void BeforeFixture(IFixture fixture, int testCaseCount); + void AfterFixture(IFixture fixture); + + void FixtureSetUp(TestResult result); + void FixtureTearDown(TestResult result); + + void BeforeTestCase(ITestCase testCase); + void AfterTestCase(ITestCase testCase); + + void SetUp(TestResult result); + void Test(TestResult result); + void TearDown(TestResult result); + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/ITestListener.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/ITestListener.cs.meta new file mode 100644 index 0000000..3afce5d --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/ITestListener.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 7bea5879d1394465d9b97717921f38e4 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/IUnitServices.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/IUnitServices.cs new file mode 100755 index 0000000..da6696c --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/IUnitServices.cs @@ -0,0 +1,10 @@ +using System.Reflection; +using System.ComponentModel; + +namespace QuickGraph.Unit +{ + public interface IUnitServices + { + ILoggerService GetLoggerService(); + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/IUnitServices.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/IUnitServices.cs.meta new file mode 100644 index 0000000..594dfcb --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/IUnitServices.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 17c6c257a66e54b04a8ff74d9c85add3 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/IgnoreAttribute.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/IgnoreAttribute.cs new file mode 100755 index 0000000..418e662 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/IgnoreAttribute.cs @@ -0,0 +1,44 @@ +using System; +using QuickGraph.Unit.Exceptions; +using QuickGraph.Unit.Core; + +namespace QuickGraph.Unit +{ + [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, AllowMultiple = false, Inherited = true)] + public sealed class IgnoreAttribute : TestDecoratorAttributeBase + { + private string message; + + public IgnoreAttribute(string message) + { + if (message == null) + throw new ArgumentNullException("message"); + this.message = message; + } + + public string Message + { + get { return this.message; } + } + + public override ITestCase Decorate(ITestCase testCase) + { + return new IgnoredTestCase(testCase, this.Message); + } + + private sealed class IgnoredTestCase : DecoratorTestCaseBase + { + private string message; + public IgnoredTestCase(ITestCase testCase, string message) + : base(testCase) + { + this.message = message; + } + + public override void Run(Object fixture) + { + throw new IgnoreException(this.message); + } + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/IgnoreAttribute.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/IgnoreAttribute.cs.meta new file mode 100644 index 0000000..37ca4c1 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/IgnoreAttribute.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 78d3ea16a66864604b38b8cf67e41c2f +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/KillProcessAttribute.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/KillProcessAttribute.cs new file mode 100755 index 0000000..ce8a657 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/KillProcessAttribute.cs @@ -0,0 +1,68 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using QuickGraph.Unit.Core; + +namespace QuickGraph.Unit +{ + [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, + AllowMultiple=true, Inherited=true)] + public sealed class KillProcessAttribute : TestDecoratorAttributeBase + { + private string name; + private NameMatchType matchType = NameMatchType.Exact; + + public KillProcessAttribute(string name) + { + if (string.IsNullOrEmpty(name)) + throw new ArgumentNullException("name"); + this.name = name; + } + + public string Name + { + get { return this.name; } + set { this.name = value; } + } + + public NameMatchType MatchType + { + get { return this.matchType; } + set { this.matchType = value; } + } + + public override ITestCase Decorate(ITestCase testCase) + { + return new KillProcessDecoratorTestCase(testCase, this); + } + + private sealed class KillProcessDecoratorTestCase : TypeDecoratorTestCaseBase + { + public KillProcessDecoratorTestCase(ITestCase testCase, KillProcessAttribute attribute) + : base(testCase,attribute) + { } + + public override void Run(object fixture) + { + System.Runtime.CompilerServices.RuntimeHelpers.PrepareConstrainedRegions(); + try + { + this.TestCase.Run(fixture); + } + finally + { + // looking for processes to kill + INameMatcher matcher = NameMatcherFactory.CreateMatcher(this.Attribute.MatchType, this.Attribute.Name); + foreach (Process p in Process.GetProcesses()) + { + if (matcher.IsMatch(p.ProcessName)) + { + Console.WriteLine("Killing {0} {1}", p.Id, p.ProcessName); + p.Kill(); + } + } + } + } + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/KillProcessAttribute.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/KillProcessAttribute.cs.meta new file mode 100644 index 0000000..f18601a --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/KillProcessAttribute.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d2e1284d0e01e415fa6bc34090b3ccf1 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Listeners.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Listeners.meta new file mode 100644 index 0000000..67163c9 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Listeners.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: c44958a027c214709b43acf86408e696 +folderAsset: yes +DefaultImporter: + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Listeners/ConsoleTestListener.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Listeners/ConsoleTestListener.cs new file mode 100755 index 0000000..a0512cc --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Listeners/ConsoleTestListener.cs @@ -0,0 +1,331 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Threading; +using System.Reflection; +using QuickGraph.Unit.Core; + +namespace QuickGraph.Unit.Listeners +{ + public sealed class ConsoleTestListener : CounterTestListener + { + private bool silent = false; + private TextWriter _out; + private IFixture currentFixture = null; + private TestResult currentResult = null; + private bool useColors = true; + private bool usePosition = true; + private bool showProgress = true; + + public ConsoleTestListener() + : this(Console.Out) + { } + + public ConsoleTestListener(TextWriter writer) + { + if (writer==null) + throw new ArgumentNullException("writer"); + this._out = writer; + this.UsePosition = !System.Diagnostics.Debugger.IsAttached; + } + + public TextWriter Out + { + get { return this._out; } + } + + public bool Silent + { + get { return this.silent; } + set { this.silent = value; } + } + + public bool UseColors + { + get { return this.useColors; } + set { this.useColors = value; } + } + + public bool UsePosition + { + get { return this.usePosition; } + set { this.usePosition = value; } + } + + public bool ShowProgress + { + get { return this.showProgress; } + set { this.showProgress = value; } + } + + public override void Message(MessageImportance importance, string message) + { + base.Message(importance, message); + if (silent) + return; + if (importance== MessageImportance.Normal || !this.UseColors) + Console.WriteLine(message); + else + { + ConsoleColor color = Console.ForegroundColor; + try + { + if (importance == MessageImportance.Low) + Console.ForegroundColor = ConsoleColor.DarkGray; + else + Console.ForegroundColor = ConsoleColor.White; + Console.WriteLine(message); + } + finally + { + SetConsoleDefaultColor(); + } + } + } + + public override void Warning(string message) + { + base.Warning(message); + if (silent) + return; + try + { + SetConsoleColor(TestState.Ignore); + Console.WriteLine(message); + } + finally + { + SetConsoleDefaultColor(); + } + } + + public override void Error(string message) + { + base.Error(message); + if (silent) + return; + System.Runtime.CompilerServices.RuntimeHelpers.PrepareConstrainedRegions(); + try + { + SetConsoleColor(TestState.Failure); + Console.WriteLine(message); + } + finally + { + SetConsoleDefaultColor(); + } + } + + public override void Error(Exception ex) + { + base.Error(ex); + if (silent) + return; + System.Runtime.CompilerServices.RuntimeHelpers.PrepareConstrainedRegions(); + try + { + Console.WriteLine(ex); + } + finally + { + SetConsoleDefaultColor(); + } + } + + public override void BeforeBatch(TestBatch batch) + { + base.BeforeBatch(batch); + if (silent) + return; + this.Out.WriteLine("{0}: Starting tests", DateTime.Now.ToLongTimeString()); + this.Out.Flush(); + } + + public override void AfterBatch(TestBatch batch) + { + base.AfterBatch(batch); + if (silent) + return; + this.Out.WriteLine(); + this.Out.WriteLine("{0}: Tests finished", DateTime.Now.ToLongTimeString()); + this.Out.Flush(); + } + + public override void BeforeAssembly(TestAssembly testAssembly) + { + base.BeforeAssembly(testAssembly); + if (silent) + return; + } + + public override void AfterAssembly(TestAssembly testAssembly) + { + base.AfterAssembly(testAssembly); + } + + public override void AssemblySetUp(Result result) + { + base.AssemblySetUp(result); + if (silent) + return; + if (result.State == TestState.Success) + return; + + this.Out.WriteLine("AssemblySetUp FAILED!"); + this.Out.Flush(); + } + + public override void AssemblyTearDown(Result result) + { + base.AssemblyTearDown(result); + if (silent) + return; + if (result.State == TestState.Success) + return; + + this.Out.WriteLine("AssemblyTearDown FAILED!"); + this.Out.Flush(); + } + + public override void BeforeFixture(IFixture fixture, int testCaseCount) + { + base.BeforeFixture(fixture, testCaseCount); + this.currentFixture = fixture; + } + + public override void AfterFixture(IFixture fixture) + { + base.AfterFixture(fixture); + this.currentFixture = null; + } + + public override void FixtureSetUp(TestResult result) + { + base.FixtureSetUp(result); + } + + public override void FixtureTearDown(TestResult result) + { + base.FixtureTearDown(result); + } + + public override void SetUp(TestResult result) + { + base.SetUp(result); + this.currentResult = result; + } + + public override void Test(TestResult result) + { + base.Test(result); + if (this.currentResult==null || this.currentResult.State== TestState.Success) + this.currentResult = result; + } + + public override void TearDown(TestResult result) + { + base.TearDown(result); + if (this.currentResult.State== TestState.Success) + this.currentResult = result; + } + + public override void BeforeTestCase(ITestCase test) + { + base.BeforeTestCase(test); + if (silent) + return; + this.WriteCounter(test); + } + + + public override void AfterTestCase(ITestCase test) + { + base.AfterTestCase(test); + if (silent) + return; + this.WriteCounter(test); + } + + private void WriteLine(string category, Result result, string format, params object[] args) + { + SetConsoleColor(result.State); + string message = String.Format(format, args); + Out.WriteLine("[{0}][{1}] {2}", result.State, category, message); + this.Out.Flush(); + SetConsoleDefaultColor(); + } + + private void SetConsoleDefaultColor() + { + if (!this.UseColors) + return; + Console.ForegroundColor = ConsoleColor.Gray; + } + + private void SetConsoleColor(TestState state) + { + if (!this.UseColors) + return; + switch (state) + { + case TestState.Success: + Console.ForegroundColor = ConsoleColor.Gray; break; + case TestState.Failure: + Console.ForegroundColor = ConsoleColor.Red; break; + case TestState.Ignore: + Console.ForegroundColor = ConsoleColor.Yellow; break; + default: + Console.ForegroundColor = ConsoleColor.Gray; break; + } + } + + private void SetCounterColor() + { + if (!this.UseColors) + return; + + if (this.Counter.HasFailures) + Console.ForegroundColor = ConsoleColor.Red; + else + Console.ForegroundColor = ConsoleColor.Green; + } + + private void WriteCounter(ITestCase test) + { + if (silent) + return; + if (!this.ShowProgress) + return; + + if (this.UsePosition) + { + int position = Console.CursorLeft; + string white = new string(' ', position+1); + Console.SetCursorPosition(0, Console.CursorTop); + // write blanks + Out.Write(white); + } + + this.SetCounterColor(); + + if (this.UsePosition) + Console.SetCursorPosition(0, Console.CursorTop); + // write test name + string fixtureName = test.FixtureName; + int index = fixtureName.LastIndexOf('.'); + if (index > 0) + fixtureName = fixtureName.Substring(index + 1); + string name = String.Format("{0}.{1}",fixtureName, test.Name); + if (name.Length > 40) + name = name.Substring(0, 40) + "..."; + Out.Write("{0}: {1}, {2}", + DateTime.Now.ToLongTimeString(), + this.Counter, + name); + if (!this.UsePosition) + Console.WriteLine(); + this.Out.Flush(); + SetConsoleDefaultColor(); + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Listeners/ConsoleTestListener.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Listeners/ConsoleTestListener.cs.meta new file mode 100644 index 0000000..87c26c4 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Listeners/ConsoleTestListener.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 932cea48a78e847a984269404fbfee73 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Listeners/CounterTestListener.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Listeners/CounterTestListener.cs new file mode 100755 index 0000000..5620f61 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Listeners/CounterTestListener.cs @@ -0,0 +1,157 @@ +using System; +using System.Collections.Generic; +using System.Text; +using QuickGraph.Unit.Serialization; +using QuickGraph.Unit.Core; + +namespace QuickGraph.Unit.Listeners +{ + public class CounterTestListener : ITestListener + { + private TestCounter counter; + private TestCounter assemblyCounter; + private TestCounter fixtureCounter; + private TestState testState; + + public TestCounter Counter + { + get { return this.counter; } + } + + public virtual void ReportsGenerated( + string historyXml, + string historyHtml, + string batchXml, + string batchHtml) + { } + + public virtual void Message(MessageImportance importance, string message) + { } + public virtual void Warning(string message) + { } + public virtual void Error(string message) + { } + public virtual void Error(Exception ex) + { } + + public virtual void BeforeBatch(TestBatch batch) + { + this.counter = new TestCounter(batch.GetTestCount()); + } + + public virtual void AfterBatch(TestBatch batch) + { + } + + public virtual void BeforeAssembly(TestAssembly testAssembly) + { + this.assemblyCounter = new TestCounter(testAssembly.GetTestCount()); + } + + public virtual void AfterAssembly(TestAssembly testAssembly) + { + this.assemblyCounter = null; + } + + public virtual void AssemblySetUp(Result result) + { + if (result.State == TestState.Success) + return; + + this.counter.FailureCount += this.assemblyCounter.TotalCount; + this.assemblyCounter = null; + } + + public virtual void AssemblyTearDown(Result result) + { + if (result.State == TestState.Success || this.assemblyCounter==null) + return; + + this.counter.RollbackResults(this.assemblyCounter); + this.counter.FailureCount += this.assemblyCounter.TotalCount; + this.assemblyCounter = null; + } + + public virtual void BeforeFixture(IFixture fixture, int testCaseCount) + { + this.fixtureCounter = new TestCounter(testCaseCount); + } + + public virtual void AfterFixture(IFixture fixture) + { + } + + public virtual void FixtureSetUp(TestResult result) + { + if (result.State == TestState.Success) + return; + + + this.counter.FailureCount += this.fixtureCounter.TotalCount; + this.assemblyCounter.FailureCount += this.fixtureCounter.TotalCount; + this.fixtureCounter = null; + } + + public virtual void FixtureTearDown(TestResult result) + { + if (result.State == TestState.Success || this.fixtureCounter==null) + return; + + this.counter.RollbackResults(this.fixtureCounter); + this.assemblyCounter.RollbackResults(this.fixtureCounter); + + this.counter.FailureCount += this.fixtureCounter.TotalCount; + this.assemblyCounter.FailureCount += this.fixtureCounter.TotalCount; + + this.fixtureCounter = null; + } + + public virtual void BeforeTestCase(ITestCase testCase) + { + this.testState = TestState.NotRun; + } + + public virtual void AfterTestCase(ITestCase testCase) + { + switch (this.testState) + { + case TestState.NotRun: + throw new InvalidProgramException(); + case TestState.Failure: + this.counter.FailureCount++; + this.assemblyCounter.FailureCount++; + this.fixtureCounter.FailureCount++; + break; + case TestState.Ignore: + this.counter.IgnoreCount++; + this.assemblyCounter.IgnoreCount++; + this.fixtureCounter.IgnoreCount++; + break; + case TestState.Success: + this.counter.SuccessCount++; + this.assemblyCounter.SuccessCount++; + this.fixtureCounter.SuccessCount++; + break; + default: + throw new NotSupportedException(); + } + } + + public virtual void SetUp(TestResult result) + { + testState = result.State; + } + + public virtual void Test(TestResult result) + { + if ((short)testState < (short)result.State) + testState = result.State; + } + + public virtual void TearDown(TestResult result) + { + if ((short)testState < (short)result.State) + testState = result.State; + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Listeners/CounterTestListener.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Listeners/CounterTestListener.cs.meta new file mode 100644 index 0000000..fca7e19 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Listeners/CounterTestListener.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 48ee4ba91c03f43ec977cbb20350f833 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Listeners/TestListenerCollection.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Listeners/TestListenerCollection.cs new file mode 100755 index 0000000..e2d3aa4 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Listeners/TestListenerCollection.cs @@ -0,0 +1,159 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Reflection; +using QuickGraph.Unit.Core; + +namespace QuickGraph.Unit.Listeners +{ + public sealed class TestListenerCollection : List, + ITestListener + { + public void ReportsGenerated( + string historyXml, + string historyHtml, + string batchXml, + string batchHtml) + { + foreach(ITestListener listener in this) + listener.ReportsGenerated(historyXml, historyHtml, batchXml, batchHtml); + } + + public void Message(string format, params object[] args) + { + Message(MessageImportance.Normal, format, args); + } + + public void Message(string message) + { + Message(MessageImportance.Normal, message); + } + + public void Message(MessageImportance importance, string format, params object[] args) + { + Message(importance, string.Format(format, args)); + } + + public void Message(MessageImportance importance, string message) + { + foreach (ITestListener testListener in this) + testListener.Message(importance, message); + } + + public void Warning(string format, params object[] args) + { + Warning(string.Format(format, args)); + } + + public void Warning(string message) + { + foreach (ITestListener testListener in this) + testListener.Warning(message); + } + + public void Error(string format, params object[] args) + { + Error(string.Format(format, args)); + } + + public void Error(string message) + { + foreach (ITestListener testListener in this) + testListener.Error(message); + } + + public void Error(Exception ex) + { + foreach (ITestListener testListener in this) + testListener.Error(ex); + } + + public void BeforeBatch(TestBatch batch) + { + foreach (ITestListener testListener in this) + testListener.BeforeBatch(batch); + } + + public void AfterBatch(TestBatch batch) + { + foreach (ITestListener testListener in this) + testListener.AfterBatch(batch); + } + + public void BeforeAssembly(TestAssembly testAssembly) + { + foreach (ITestListener testListener in this) + testListener.BeforeAssembly(testAssembly); + } + + public void AfterAssembly(TestAssembly testAssembly) + { + foreach (ITestListener testListener in this) + testListener.AfterAssembly(testAssembly); + } + + public void AssemblySetUp(Result result) + { + foreach (ITestListener testListener in this) + testListener.AssemblySetUp(result); + } + + public void AssemblyTearDown(Result result) + { + foreach (ITestListener testListener in this) + testListener.AssemblyTearDown(result); + } + + public void BeforeFixture(IFixture fixture, int testCaseCount) + { + foreach (ITestListener testListener in this) + testListener.BeforeFixture(fixture, testCaseCount); + } + + public void AfterFixture(IFixture fixture) + { + foreach (ITestListener testListener in this) + testListener.AfterFixture(fixture); + } + + public void FixtureSetUp(TestResult result) + { + foreach (ITestListener testListener in this) + testListener.FixtureSetUp(result); + } + public void FixtureTearDown(TestResult result) + { + foreach (ITestListener testListener in this) + testListener.FixtureTearDown(result); + } + + public void SetUp(TestResult result) + { + foreach (ITestListener testListener in this) + testListener.SetUp(result); + } + public void TearDown(TestResult result) + { + foreach (ITestListener testListener in this) + testListener.TearDown(result); + } + + public void Test(TestResult result) + { + foreach (ITestListener testListener in this) + testListener.Test(result); + } + + public void BeforeTestCase(ITestCase test) + { + foreach (ITestListener testListener in this) + testListener.BeforeTestCase(test); + } + + public void AfterTestCase(ITestCase test) + { + foreach (ITestListener testListener in this) + testListener.AfterTestCase(test); + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Listeners/TestListenerCollection.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Listeners/TestListenerCollection.cs.meta new file mode 100644 index 0000000..4967427 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Listeners/TestListenerCollection.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b6c6045d9939f49dd9bdace4e713dff6 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Listeners/XmlTestListener.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Listeners/XmlTestListener.cs new file mode 100755 index 0000000..0725677 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Listeners/XmlTestListener.cs @@ -0,0 +1,257 @@ +using System; +using System.Collections.Generic; +using System.Reflection; + +using QuickGraph.Unit.Serialization; +using QuickGraph.Unit.Reports; +using QuickGraph.Unit.Core; + +namespace QuickGraph.Unit.Listeners +{ + public sealed class XmlTestListener : ITestListener + { + private XmlTestBatchSearcher testBatchSearcher = null; + private XmlTestBatch testBatch = new XmlTestBatch(); + private bool showTestCaseOnSuccess = false; + private XmlTestAssembly currentTestAssembly = null; + private XmlFixture currentFixture = null; + private XmlTestCase currentTest = null; + + public bool ShowTestCaseOnSuccess + { + get { return this.showTestCaseOnSuccess; } + set { this.showTestCaseOnSuccess = value; } + } + + public XmlTestBatch TestBatch + { + get { return this.testBatch; } + } + + public void SetPreviousTestBatch(string fileName) + { + XmlTestBatch testBatch = UnitSerializer.Deserialize(fileName); + if (testBatch != null) + SetPreviousTestBatch(testBatch); + } + + public void SetPreviousTestBatch(XmlTestBatch testBatch) + { + if (testBatch == null) + throw new ArgumentNullException("testBatch"); + this.testBatchSearcher = new XmlTestBatchSearcher(testBatch); + } + + public XmlTestBatchSearcher TestBatchSearcher + { + get { return this.testBatchSearcher; } + } + + public void ReportsGenerated( + string historyXml, + string historyHtml, + string batchXml, + string batchHtml) + {} + + public void Message(MessageImportance importance, string message) + { + if (this.TestBatch != null) + this.TestBatch.Log.LogEntries.Add(new XmlLogEntry(LogLevel.Message, message)); + } + + public void Message(string message) + { + if (this.TestBatch!=null) + this.TestBatch.Log.LogEntries.Add(new XmlLogEntry(LogLevel.Message, message)); + } + + public void Warning(string message) + { + if (this.TestBatch != null) + this.TestBatch.Log.LogEntries.Add(new XmlLogEntry(LogLevel.Warning, message)); + } + + public void Error(string message) + { + if (this.TestBatch != null) + this.TestBatch.Log.LogEntries.Add(new XmlLogEntry(LogLevel.Error, message)); + } + + public void Error(Exception ex) + { + if (this.TestBatch != null) + this.TestBatch.Log.LogEntries.Add(new XmlLogEntry(ex)); + } + + public void BeforeBatch(TestBatch batch) + { + this.testBatch.SetMainAssembly(batch.MainTestAssembly.Assembly); + if (this.testBatchSearcher!=null) + this.testBatch.HasHistory = true; + this.testBatch.StartTime = DateTime.Now.ToString("u"); + } + + public void AfterBatch(TestBatch batch) + { + if (this.testBatch != null) + { + this.testBatch.EndTime = DateTime.Now.ToString("u"); + this.testBatch.UpdateCounter(); + } + } + + public void BeforeAssembly(TestAssembly testAssembly) + { + this.currentTestAssembly = new XmlTestAssembly(testAssembly.Assembly.GetName(), testAssembly.Assembly.Location); + this.currentTestAssembly.StartTime = DateTime.Now; + this.testBatch.TestAssemblies.Add(this.currentTestAssembly); + } + + public void AfterAssembly(TestAssembly testAssembly) + { + if (this.currentTestAssembly != null) + { + this.currentTestAssembly.EndTime = DateTime.Now; + this.currentTestAssembly = null; + } + } + + public void AssemblySetUp(Result result) + { + if (this.currentTestAssembly!=null) + this.currentTestAssembly.AssemblySetUp = new XmlResult(result); + } + + public void AssemblyTearDown(Result result) + { + if (this.currentTestAssembly != null) + this.currentTestAssembly.AssemblyTearDown = new XmlResult(result); + } + + public void BeforeFixture(IFixture fixture, int testCaseCount) + { + this.currentFixture = new XmlFixture(fixture, testCaseCount, + GetCategories(fixture), this.currentTestAssembly.Fixtures.Count); + this.currentTestAssembly.Fixtures.Add(this.currentFixture); + } + + private static string GetCategories(IFixture fixture) + { + using (System.IO.StringWriter sw = new System.IO.StringWriter()) + { + bool first = true; + foreach (string category in fixture.Categories) + { + if (first) + { + sw.Write(category); + first = false; + } + else + sw.Write(";{0}", category); + } + return sw.ToString(); + } + } + + public void AfterFixture(IFixture fixture) + { + if (this.currentFixture != null) + { + this.currentFixture.UpdateCounter(); + this.currentFixture = null; + } + } + + public void FixtureSetUp(TestResult result) + { + if (this.currentFixture != null) + { + this.currentFixture.FixtureSetUp = new XmlResult(result); + this.currentFixture.Duration += result.Duration; + } + } + + public void FixtureTearDown(TestResult result) + { + if (this.currentFixture != null) + { + this.currentFixture.FixtureTearDown = new XmlResult(result); + this.currentFixture.Duration += result.Duration; + } + } + + public void SetUp(TestResult result) + { + if (this.currentTest != null) + { + this.currentTest.SetUp = new XmlResult(result); + this.currentFixture.Duration += result.Duration; + } + } + + public void Test(TestResult result) + { + if (this.currentTest != null) + { + this.currentTest.Test = new XmlResult(result); + this.currentFixture.Duration += result.Duration; + } + } + + public void TearDown(TestResult result) + { + if (this.currentTest != null) + { + this.currentTest.TearDown = new XmlResult(result); + this.currentFixture.Duration += result.Duration; + } + } + + public void BeforeTestCase(ITestCase test) + { + this.currentTest = new XmlTestCase(String.Format("{0}t{1}", + this.currentFixture.ID, + this.currentFixture.TestCases.Count), + test.Name); + this.currentFixture.TestCases.Add(this.currentTest); + } + + public void AfterTestCase(ITestCase test) + { + if (this.TestBatchSearcher != null) + { + XmlTestCase previous = this.TestBatchSearcher.GetTestCase(this.currentFixture, this.currentTest); + if (previous == null) + { + this.currentTest.History = XmlTestHistory.New; + } + else + { + if ( + this.currentTest.State == TestState.Success + && previous.State != TestState.Success) + { + this.currentTest.History = XmlTestHistory.Fixed; + } + else if ( + this.currentTest.State == TestState.Failure && + previous.State != TestState.Failure + ) + { + this.currentTest.History = XmlTestHistory.Failure; + } + } + } + + if (!this.ShowTestCaseOnSuccess && this.currentTest.State == TestState.Success) + { + this.currentTest.SetUp = null; + this.currentTest.Test = null; + this.currentTest.TearDown = null; + } + this.currentTest = null; + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Listeners/XmlTestListener.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Listeners/XmlTestListener.cs.meta new file mode 100644 index 0000000..1f71746 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Listeners/XmlTestListener.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b70f7ccd2f4694224ac6dd3e99ad42d8 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/LogError.png b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/LogError.png new file mode 100755 index 0000000..6394bb7 Binary files /dev/null and b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/LogError.png differ diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/LogError.png.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/LogError.png.meta new file mode 100644 index 0000000..7cdb0b0 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/LogError.png.meta @@ -0,0 +1,46 @@ +fileFormatVersion: 2 +guid: 4f9a192ad0c0449748ec5d2207339694 +TextureImporter: + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + linearTexture: 0 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: -1 + mipBias: -1 + wrapMode: -1 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 0 + textureType: -1 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/LogLevel.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/LogLevel.cs new file mode 100755 index 0000000..007176f --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/LogLevel.cs @@ -0,0 +1,10 @@ +using System; +namespace QuickGraph.Unit +{ + public enum LogLevel + { + Message, + Warning, + Error + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/LogLevel.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/LogLevel.cs.meta new file mode 100644 index 0000000..d4d7de4 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/LogLevel.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 447db32586b90477d9239aefe6583a50 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/LogMessage.png b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/LogMessage.png new file mode 100755 index 0000000..143347b Binary files /dev/null and b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/LogMessage.png differ diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/LogMessage.png.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/LogMessage.png.meta new file mode 100644 index 0000000..3958ea5 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/LogMessage.png.meta @@ -0,0 +1,46 @@ +fileFormatVersion: 2 +guid: 5fef4d179982a464191af244f0de38f6 +TextureImporter: + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + linearTexture: 0 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: -1 + mipBias: -1 + wrapMode: -1 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 0 + textureType: -1 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/LogWarning.png b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/LogWarning.png new file mode 100755 index 0000000..d849bdd Binary files /dev/null and b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/LogWarning.png differ diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/LogWarning.png.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/LogWarning.png.meta new file mode 100644 index 0000000..7b877fa --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/LogWarning.png.meta @@ -0,0 +1,46 @@ +fileFormatVersion: 2 +guid: 91db4d529e12c49798f6eb354688a446 +TextureImporter: + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + linearTexture: 0 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: -1 + mipBias: -1 + wrapMode: -1 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 0 + textureType: -1 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Logging.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Logging.meta new file mode 100644 index 0000000..35bb477 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Logging.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: f2cf07a8f51ae4679a7405b6b6069f51 +folderAsset: yes +DefaultImporter: + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Logging/ConsoleLoggerListener.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Logging/ConsoleLoggerListener.cs new file mode 100755 index 0000000..dbf925a --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Logging/ConsoleLoggerListener.cs @@ -0,0 +1,17 @@ +using System; +using System.IO; + +namespace QuickGraph.Unit.Logging +{ + public sealed class ConsoleLoggerListener : ILoggerListener + { + public void Log(LogLevel level, string message) + { + Console.WriteLine( + "[{0}] {1}", + level, + message + ); + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Logging/ConsoleLoggerListener.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Logging/ConsoleLoggerListener.cs.meta new file mode 100644 index 0000000..fc7b972 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Logging/ConsoleLoggerListener.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 75ada08075e5043529b85caa33057ed0 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Logging/LoggerService.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Logging/LoggerService.cs new file mode 100755 index 0000000..e3caaf4 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Logging/LoggerService.cs @@ -0,0 +1,79 @@ +using System; +using System.Collections.Generic; + +namespace QuickGraph.Unit.Logging +{ + [Serializable] + internal sealed class LoggerService : ILoggerService + { + private volatile object syncRoot = new object(); + private List listeners = new List(); + public object SyncRoot + { + get { return this.syncRoot;} + } + + public IList Listeners + { + get + { + lock(this.SyncRoot) + { + return this.listeners; + } + } + } + + public void Log(LogLevel level, string message) + { + lock (this.SyncRoot) + { + foreach (ILoggerListener listener in this.listeners) + listener.Log(level, message); + } + } + + public void Log(LogLevel level, string format, params object[] args) + { + if (this.Listeners.Count == 0) + return; + string message = string.Format(format, args); + this.Log(level, message); + } + + public void LogMessage(string message) + { + this.Log(LogLevel.Message, message); + } + + public void LogMessage(string format, params object[] args) + { + this.Log(LogLevel.Message, format, args); + } + + public void LogWarning(string message) + { + this.Log(LogLevel.Warning, message); + } + + public void LogWarning(string format, params object[] args) + { + this.Log(LogLevel.Warning, format, args); + } + + public void LogError(string message) + { + this.Log(LogLevel.Error, message); + } + + public void LogError(string format, params object[] args) + { + this.Log(LogLevel.Error, format, args); + } + + public void LogError(Exception ex) + { + this.Log(LogLevel.Error, ex.ToString()); + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Logging/LoggerService.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Logging/LoggerService.cs.meta new file mode 100644 index 0000000..720e245 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Logging/LoggerService.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 10e67d67020384187bbd28beb30b88a5 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Logging/XmlLoggerListener.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Logging/XmlLoggerListener.cs new file mode 100755 index 0000000..d422c19 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Logging/XmlLoggerListener.cs @@ -0,0 +1,24 @@ +using System; +using QuickGraph.Unit.Serialization; + +namespace QuickGraph.Unit.Logging +{ + public sealed class XmlLoggerListener : ILoggerListener + { + private XmlLog log = new XmlLog(); + + public XmlLog GetLog() + { + return this.log; + } + + public void Log(LogLevel level, string message) + { + XmlLogEntry entry = new XmlLogEntry(); + entry.Level = level; + entry.Message = message; + + this.log.LogEntries.Add(entry); + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Logging/XmlLoggerListener.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Logging/XmlLoggerListener.cs.meta new file mode 100644 index 0000000..c8bb178 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Logging/XmlLoggerListener.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d1b50908409c74990bab1b1e010c253b +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/MessageImportance.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/MessageImportance.cs new file mode 100755 index 0000000..d07d49c --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/MessageImportance.cs @@ -0,0 +1,12 @@ +using System; + +namespace QuickGraph.Unit +{ + [Serializable] + public enum MessageImportance + { + Low, + Normal, + High + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/MessageImportance.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/MessageImportance.cs.meta new file mode 100644 index 0000000..9862e8c --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/MessageImportance.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d0b3a7d4ad8714d9eb006945a40ba9f2 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Monitoring.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Monitoring.meta new file mode 100644 index 0000000..01122ff --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Monitoring.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: 1889fdbd1b31542ef8b85f4942c06afc +folderAsset: yes +DefaultImporter: + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Monitoring/ConsoleLoggerMonitor.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Monitoring/ConsoleLoggerMonitor.cs new file mode 100755 index 0000000..72b2195 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Monitoring/ConsoleLoggerMonitor.cs @@ -0,0 +1,33 @@ +using System; +using QuickGraph.Unit.Logging; + +namespace QuickGraph.Unit.Monitoring +{ + public sealed class ConsoleLoggerMonitor : IMonitor + { + private ILoggerService logger; + private ConsoleLoggerListener listener = new ConsoleLoggerListener(); + + public ConsoleLoggerMonitor(ILoggerService logger) + { + if (logger == null) + throw new ArgumentNullException("logger"); + this.logger = logger; + } + + public void Start() + { + this.logger.Listeners.Add(this.listener); + } + + public void Stop() + { + this.logger.Listeners.Remove(this.listener); + } + + public void Dispose() + { + this.Stop(); + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Monitoring/ConsoleLoggerMonitor.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Monitoring/ConsoleLoggerMonitor.cs.meta new file mode 100644 index 0000000..9cf5f86 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Monitoring/ConsoleLoggerMonitor.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: c149d3af890364f839a47fa999947446 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Monitoring/ConsoleMonitor.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Monitoring/ConsoleMonitor.cs new file mode 100755 index 0000000..9953d6f --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Monitoring/ConsoleMonitor.cs @@ -0,0 +1,56 @@ +using System; +using System.IO; + +namespace QuickGraph.Unit.Monitoring +{ + public sealed class ConsoleMonitor : IMonitor + { + private TextWriter consoleOut; + private TextWriter consoleError; + private StringWriter _out = new StringWriter(); + private StringWriter _error = new StringWriter(); + + public ConsoleMonitor() + {} + + public void Start() + { + this.consoleOut = Console.Out; + this.consoleError = Console.Error; + + this._out = new StringWriter(); + this._error = new StringWriter(); + Console.SetOut(this._out); + Console.SetError(this._out); + } + + public string Out + { + get { return this._out.ToString(); } + } + + public string Error + { + get { return this._error.ToString(); } + } + + public void Stop() + { + if (this.consoleOut != null) + { + Console.SetOut(this.consoleOut); + this.consoleOut = null; + } + if (this.consoleError != null) + { + Console.SetError(this.consoleError); + this.consoleError = null; + } + } + + public void Dispose() + { + this.Stop(); + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Monitoring/ConsoleMonitor.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Monitoring/ConsoleMonitor.cs.meta new file mode 100644 index 0000000..b4ebfa2 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Monitoring/ConsoleMonitor.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 76d9e132258544b6c8433e5b1cc30fba +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Monitoring/DebugMonitor.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Monitoring/DebugMonitor.cs new file mode 100755 index 0000000..d15bf06 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Monitoring/DebugMonitor.cs @@ -0,0 +1,116 @@ +using System; +using System.Diagnostics; +using QuickGraph.Unit.Exceptions; + +namespace QuickGraph.Unit.Monitoring +{ + public sealed class DebugMonitor : IMonitor + { + private DefaultTraceListener defaultListener; + private DebugMonitorTraceListener listener; + + public DebugMonitor(ILoggerService logger) + { + if (logger == null) + throw new ArgumentNullException("logger"); + this.listener = new DebugMonitorTraceListener(logger); + } + + public void Start() + { + // find default listnerer + foreach (TraceListener tc in Debug.Listeners) + { + this.defaultListener = tc as DefaultTraceListener; + if (defaultListener != null) + break; + } + + // remove default listener + if (this.defaultListener != null) + Debug.Listeners.Remove(this.defaultListener); + + // adding custom + Debug.Listeners.Add(this.listener); + } + + public void Stop() + { + if (this.defaultListener != null) + { + Debug.Listeners.Add(this.defaultListener); + this.defaultListener = null; + } + Debug.Listeners.Remove(this.listener); + } + + public void Dispose() + { + this.Stop(); + } + + private sealed class DebugMonitorTraceListener : TraceListener + { + private ILoggerService logger; + private DefaultTraceListener defaultListener; + + public DebugMonitorTraceListener(ILoggerService logger) + { + this.logger = logger; + foreach (TraceListener tc in Debug.Listeners) + { + this.defaultListener = tc as DefaultTraceListener; + if (defaultListener != null) + break; + } + } + + private void WriteLine(string format, params object[] args) + { + this.logger.LogMessage("Debug", format, args); + if (this.defaultListener != null) + this.defaultListener.WriteLine(String.Format(format, args)); + } + + public override void Fail(string message) + { + this.logger.LogError("Debug", message); + throw new DebugFailureException(message); + } + + public override void Fail(string message, string messageDetail) + { + this.logger.LogError("Debug", "{0}\n{1}", message, messageDetail); + throw new DebugFailureException(message + messageDetail); + } + + public override void Write(string message) + { + this.logger.LogMessage("Debug", message); + if (this.defaultListener != null) + this.defaultListener.Write(message); + } + + public override void WriteLine(string message) + { + this.logger.LogMessage("Debug", message); + if (this.defaultListener != null) + this.defaultListener.WriteLine(message); + } + + public override void Write(string message, string category) + { + this.logger.LogMessage(category, message); + if (this.defaultListener != null) + this.defaultListener.Write(message,category); + } + + public override void WriteLine(string message, string category) + { + this.logger.LogMessage(category, message); + if (this.defaultListener != null) + this.defaultListener.WriteLine(message, category); + } + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Monitoring/DebugMonitor.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Monitoring/DebugMonitor.cs.meta new file mode 100644 index 0000000..26a577d --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Monitoring/DebugMonitor.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: c564ce30fc0ce4cf3b9d0ff1a392d5d6 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Monitoring/EnvironmentMonitor.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Monitoring/EnvironmentMonitor.cs new file mode 100755 index 0000000..ee6a386 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Monitoring/EnvironmentMonitor.cs @@ -0,0 +1,29 @@ +using System; +using System.Threading; +using System.Collections.Generic; + +namespace QuickGraph.Unit.Monitoring +{ + internal sealed class EnvironmentMonitor : IMonitor + { + private string currentDirectory; + + public void Start() + { + this.currentDirectory = Environment.CurrentDirectory; + + } + + public void Stop() + { + if (this.currentDirectory!=null) + Environment.CurrentDirectory = this.currentDirectory; + this.currentDirectory = null; + } + + public void Dispose() + { + Stop(); + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Monitoring/EnvironmentMonitor.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Monitoring/EnvironmentMonitor.cs.meta new file mode 100644 index 0000000..065af12 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Monitoring/EnvironmentMonitor.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 92b4f21c473724cc4b2216f1b94de0a6 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Monitoring/IMonitor.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Monitoring/IMonitor.cs new file mode 100755 index 0000000..17eb745 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Monitoring/IMonitor.cs @@ -0,0 +1,10 @@ +using System; + +namespace QuickGraph.Unit.Monitoring +{ + public interface IMonitor : IDisposable + { + void Start(); + void Stop(); + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Monitoring/IMonitor.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Monitoring/IMonitor.cs.meta new file mode 100644 index 0000000..32783c4 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Monitoring/IMonitor.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 01b8c355fe66a469daa30062267c08bc +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Monitoring/MonitorCollection.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Monitoring/MonitorCollection.cs new file mode 100755 index 0000000..0837a55 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Monitoring/MonitorCollection.cs @@ -0,0 +1,55 @@ +using System; +using System.Collections.Generic; + +namespace QuickGraph.Unit.Monitoring +{ + public sealed class MonitorCollection : List, IDisposable + { + private ILoggerService logger; + public MonitorCollection(ILoggerService logger) + { + if (logger == null) + throw new ArgumentNullException("logger"); + this.logger = logger; + } + + public void Start() + { + foreach (IMonitor monitor in this) + { + monitor.Start(); + } + } + + public void Stop() + { + foreach (IMonitor monitor in this) + { + System.Runtime.CompilerServices.RuntimeHelpers.PrepareConstrainedRegions(); + try + { + monitor.Stop(); + } + catch (Exception ex) + { + this.logger.LogError("Monitoring", ex, "monitor {0} failed to stop", monitor); + } + } + } + + public void Dispose() + { + this.Stop(); + System.Runtime.CompilerServices.RuntimeHelpers.PrepareConstrainedRegions(); + try + { + foreach (IMonitor monitor in this) + monitor.Dispose(); + } + finally + { + this.Clear(); + } + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Monitoring/MonitorCollection.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Monitoring/MonitorCollection.cs.meta new file mode 100644 index 0000000..bbb05e0 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Monitoring/MonitorCollection.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 6eb312ea77cc443ad8602edf260d1971 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Monitoring/ThreadExceptionMonitor.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Monitoring/ThreadExceptionMonitor.cs new file mode 100755 index 0000000..1d9843a --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Monitoring/ThreadExceptionMonitor.cs @@ -0,0 +1,53 @@ +using System; +using System.Windows.Forms; +using System.Collections.Generic; + +namespace QuickGraph.Unit.Monitoring +{ + public sealed class ThreadExceptionMonitor: IMonitor + { + private ILoggerService logger; + private List exceptions = new List(); + + public ThreadExceptionMonitor(ILoggerService logger) + { + if (logger==null) + throw new ArgumentNullException("logger"); + this.logger = logger; + } + + public IList Exceptions + { + get { return this.exceptions; } + } + + public void Start() + { + System.Windows.Forms.Application.ThreadException += new System.Threading.ThreadExceptionEventHandler(Application_ThreadException); + } + + public void Clear() + { + this.exceptions.Clear(); + } + + public void Stop() + { + System.Windows.Forms.Application.ThreadException -= new System.Threading.ThreadExceptionEventHandler(Application_ThreadException); + } + + public void Dispose() + { + this.Stop(); + } + + void Application_ThreadException(object sender, System.Threading.ThreadExceptionEventArgs e) + { + this.exceptions.Add(e.Exception); + this.logger.LogError( + "Thread", + e.Exception, + "Exception occured in concurrent thread"); + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Monitoring/ThreadExceptionMonitor.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Monitoring/ThreadExceptionMonitor.cs.meta new file mode 100644 index 0000000..32cd24d --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Monitoring/ThreadExceptionMonitor.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 858e4040d68c14cae84980efb6884194 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Monitoring/ThreadMonitor.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Monitoring/ThreadMonitor.cs new file mode 100755 index 0000000..36dfce0 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Monitoring/ThreadMonitor.cs @@ -0,0 +1,46 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using System.Globalization; +using System.Security.Principal; + +namespace QuickGraph.Unit.Monitoring +{ + internal sealed class ThreadMonitor : IMonitor + { + private CultureInfo cultureInfo; + private CultureInfo uiCulture; + private IPrincipal principal; + + public void Start() + { + this.cultureInfo = Thread.CurrentThread.CurrentCulture; + this.uiCulture = Thread.CurrentThread.CurrentUICulture; + this.principal = Thread.CurrentPrincipal; + } + + public void Stop() + { + if (this.cultureInfo != null) + { + Thread.CurrentThread.CurrentCulture = this.cultureInfo; + this.cultureInfo = null; + } + if (this.uiCulture != null) + { + Thread.CurrentThread.CurrentUICulture = this.uiCulture; + this.uiCulture = null; + } + if (this.principal != null) + { + Thread.CurrentPrincipal = this.principal; + this.principal = null; + } + } + + public void Dispose() + { + Stop(); + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Monitoring/ThreadMonitor.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Monitoring/ThreadMonitor.cs.meta new file mode 100644 index 0000000..c1f6f3c --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Monitoring/ThreadMonitor.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 37c3cce3bfce3416eb733a7a015a84c9 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Monitoring/TimeMonitor.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Monitoring/TimeMonitor.cs new file mode 100755 index 0000000..dfafec6 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Monitoring/TimeMonitor.cs @@ -0,0 +1,50 @@ +using System; + +namespace QuickGraph.Unit.Monitoring +{ + public sealed class TimeMonitor : IMonitor + { + private DateTime startTime; + private DateTime endTime; + private bool running; + + public TimeMonitor() + {} + + public void Start() + { + this.startTime = this.endTime = DateTime.Now; + this.running = true; + } + + public void Stop() + { + if (running) + { + this.endTime = DateTime.Now; + this.running = false; + } + } + + public DateTime StartTime + { + get { return this.startTime; } + } + + public DateTime EndTime + { + get { return this.endTime; } + } + + public double Duration + { + get + { + TimeSpan ts = this.endTime - this.startTime; + return ts.TotalSeconds; + } + } + + public void Dispose() { } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Monitoring/TimeMonitor.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Monitoring/TimeMonitor.cs.meta new file mode 100644 index 0000000..963eae1 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Monitoring/TimeMonitor.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ec936bad68514473daf01dbd77b117fd +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Monitoring/UnhandledExceptionMonitor.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Monitoring/UnhandledExceptionMonitor.cs new file mode 100755 index 0000000..0f9b346 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Monitoring/UnhandledExceptionMonitor.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using System.Threading; + +namespace QuickGraph.Unit.Monitoring +{ + public sealed class UnhandledExceptionMonitor : IMonitor + { + private bool disposed = false; + public void Start() + { + AppDomain.CurrentDomain.UnhandledException+=new UnhandledExceptionEventHandler(UnhandledException); + } + + public void Stop() + { + AppDomain.CurrentDomain.UnhandledException -= new UnhandledExceptionEventHandler(UnhandledException); + } + + public void Dispose() + { + if (!disposed) + { + this.Stop(); + GC.SuppressFinalize(this); + this.disposed = true; + } + } + + private void UnhandledException(Object sender, UnhandledExceptionEventArgs args) + { + if (args.IsTerminating) + return; + + Assert.Fail("Unhandled Exception was catched\n", args.ExceptionObject); + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Monitoring/UnhandledExceptionMonitor.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Monitoring/UnhandledExceptionMonitor.cs.meta new file mode 100644 index 0000000..a79bc3a --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Monitoring/UnhandledExceptionMonitor.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 4d5e2d0b64e274ecd90b06e6946667c7 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Monitoring/testmonitor.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Monitoring/testmonitor.cs new file mode 100755 index 0000000..4d2496b --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Monitoring/testmonitor.cs @@ -0,0 +1,106 @@ +using System; +using System.Collections.Generic; +using QuickGraph.Unit.Logging; +using QuickGraph.Unit.Serialization; + +namespace QuickGraph.Unit.Monitoring +{ + public class TestMonitor : IMonitor + { + private ILoggerService loggerService; + private MonitorCollection monitors; + private ConsoleMonitor consoleMonitor; + private TimeMonitor timeMonitor; + private UnhandledExceptionMonitor unhandledExceptionMonitor; + private ThreadExceptionMonitor threadExceptionMonitor; + private DebugMonitor debugMonitor; + private XmlLoggerListener loggerListener = null; + + public TestMonitor() + :this(Assert.Logger) + { } + + public TestMonitor(ILoggerService loggerService) + { + this.loggerService = loggerService; + this.consoleMonitor = new ConsoleMonitor(); + this.timeMonitor = new TimeMonitor(); + this.unhandledExceptionMonitor = new UnhandledExceptionMonitor(); + this.threadExceptionMonitor = new ThreadExceptionMonitor(loggerService); + this.debugMonitor = new DebugMonitor(loggerService); + this.loggerListener = new XmlLoggerListener(); + + this.monitors = new MonitorCollection(loggerService); + this.monitors.Add(this.consoleMonitor); + this.monitors.Add(this.timeMonitor); + this.monitors.Add(this.unhandledExceptionMonitor); + this.monitors.Add(this.threadExceptionMonitor); + this.monitors.Add(this.debugMonitor); + this.monitors.Add(new EnvironmentMonitor()); + this.monitors.Add(new ThreadMonitor()); + } + + public ILoggerService LoggerService + { + get { return this.loggerService; } + } + + public MonitorCollection Monitors + { + get { return this.monitors; } + } + + public ConsoleMonitor Console + { + get { return this.consoleMonitor; } + } + + public TimeMonitor Timer + { + get { return this.timeMonitor; } + } + + public UnhandledExceptionMonitor UnhandledException + { + get { return this.unhandledExceptionMonitor; } + } + + public ThreadExceptionMonitor ThreadException + { + get { return this.threadExceptionMonitor; } + } + + public DebugMonitor Debug + { + get { return this.debugMonitor; } + } + + public XmlLog GetLog() + { + return this.loggerListener.GetLog(); + } + + public void Start() + { + this.loggerListener = new XmlLoggerListener(); + this.LoggerService.Listeners.Add(this.loggerListener); + this.monitors.Start(); + } + + public void Stop() + { + this.monitors.Stop(); + this.LoggerService.Listeners.Remove(this.loggerListener); + } + + public void Dispose() + { + this.Stop(); + if (this.monitors != null) + { + this.monitors.Dispose(); + this.monitors = null; + } + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Monitoring/testmonitor.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Monitoring/testmonitor.cs.meta new file mode 100644 index 0000000..bd5f9ea --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Monitoring/testmonitor.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 1b33bbd03f6404aa69fc5aa191c9cb5e +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/MultiThreadedTestAttribute.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/MultiThreadedTestAttribute.cs new file mode 100755 index 0000000..e726c38 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/MultiThreadedTestAttribute.cs @@ -0,0 +1,35 @@ +using System; +using System.Reflection; +using System.Collections.Generic; +using QuickGraph.Unit.Core; + +namespace QuickGraph.Unit +{ + [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)] + public sealed class MultiThreadedTestAttribute : TestAttributeBase + { + private int threadCount = 1; + + public MultiThreadedTestAttribute() + { } + + public MultiThreadedTestAttribute(int threadCount) + { + this.threadCount = threadCount; + } + + public int ThreadCount + { + get { return this.threadCount; } + set { this.threadCount = value; } + } + + public override IEnumerable CreateTests(IFixture fixture, MethodInfo method) + { + for (int i = 0; i < this.ThreadCount; ++i) + { + yield return new MethodTestCase(fixture.Name, method); + } + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/MultiThreadedTestAttribute.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/MultiThreadedTestAttribute.cs.meta new file mode 100644 index 0000000..94fe07f --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/MultiThreadedTestAttribute.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: cb0bec47b36e441408740361c8777c02 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/MultiThreadedTestFixtureAttribute.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/MultiThreadedTestFixtureAttribute.cs new file mode 100755 index 0000000..3570b03 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/MultiThreadedTestFixtureAttribute.cs @@ -0,0 +1,164 @@ +using System; +using System.Collections.Generic; +using System.Runtime.CompilerServices; +using System.Reflection; +using System.Threading; +using QuickGraph.Unit.Monitoring; +using QuickGraph.Unit.Core; + +namespace QuickGraph.Unit +{ + [AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = true)] + public sealed class MultiThreadedTestFixtureAttribute : TestFixtureAttributeBase + { + private int retryCount = 1; + + public int RetryCount + { + get { return this.retryCount; } + set { this.retryCount = value; } + } + + public override IEnumerable CreateFixtures(Type type) + { + foreach (MultiThreadedTestFixtureAttribute attribute in + type.GetCustomAttributes(typeof(MultiThreadedTestFixtureAttribute), true)) + { + yield return new MultiThreadedTestFixture(attribute, type); + } + } + + private sealed class MultiThreadedTestFixture : TypeFixtureBase + { + public MultiThreadedTestFixture(MultiThreadedTestFixtureAttribute attribute, Type fixtureType) + :base(attribute,fixtureType) + {} + + public override IEnumerable CreateTestCases() + { + // we create only 1 test case for this type of + // fixture + MultiThreadedTestCase testCase = new MultiThreadedTestCase(this); + + // populate with threaded tests + foreach (MethodInfo method in this.FixtureType.GetMethods()) + { + Object[] decorators = method.GetCustomAttributes(typeof(TestDecoratorAttributeBase), true); + foreach (MultiThreadedTestAttribute attribute in method.GetCustomAttributes(typeof(MultiThreadedTestAttribute), true)) + { + // let's make sure the method takes a TestSynchronizer argument + if (!VerifyMethod(method)) + { + yield return new BadTestCase( + this.Name, + method.Name, + "MultiThreadTest method requires TestSynchronizer arugment", + new Exception() + ); + break; + } + + int index = 0; + foreach (ITestCase test in attribute.CreateTests(this, method)) + { + // we get the test case + ITestCase decoratedTest = DecorateTest(decorators, test); + // we add the synchronizer parameter + decoratedTest.Parameters.Add(new TestCaseParameter(testCase.Synchronizer)); + // we add a worker for the test + TestCaseWorker worker = new TestCaseWorker(decoratedTest, index); + testCase.Workers.Add(worker); + index++; + } + } + } + + yield return testCase; + } + + private bool VerifyMethod(MethodInfo method) + { + ParameterInfo[] parameters = method.GetParameters(); + return parameters.Length == 1 + && parameters[0].ParameterType == typeof(TestSynchronizer); + } + } + + private sealed class MultiThreadedTestCase : TestCaseBase + { + private volatile TestSynchronizer synchronizer; + private int retryCount; + private TestCaseWorkerCollection workers = new TestCaseWorkerCollection(); + + public MultiThreadedTestCase(MultiThreadedTestFixture fixture) + : base(fixture.Name) + { + this.retryCount = fixture.Attribute.RetryCount; + this.synchronizer = new TestSynchronizer(this.Name); + } + + public TestSynchronizer Synchronizer + { + get { return this.synchronizer; } + } + + public override string UndecoratedName + { + get { return "Multi"; } + } + + public TestCaseWorkerCollection Workers + { + get { return this.workers; } + } + + public override void Run(object fixture) + { + System.Runtime.CompilerServices.RuntimeHelpers.PrepareConstrainedRegions(); + for (int i = 0; i < this.retryCount; ++i) + { + if (i != 0) + Console.WriteLine("Multithread test retry {0}/{1}", i, retryCount); + this.InternalRun(fixture); + } + } + + private void InternalRun(object fixture) + { + // block barrier + this.synchronizer.Block(); + + RuntimeHelpers.PrepareConstrainedRegions(); + try + { + RuntimeHelpers.PrepareConstrainedRegions(); + try + { + this.Workers.StartAll(fixture); + } + finally + { + // make sure the barrier is hit + while(!this.Workers.ContainsAll(this.synchronizer.GetThreadNames())) + { + Thread.Sleep(100); + } + // this will launch all the threads... + this.synchronizer.Release(); + } + + // runs threads + this.Workers.WaitAll(); + } + finally + { + // aborting thread if not dead yet + this.Workers.CloseAll(); + } + + // verifying execution + this.Workers.Verify(); + } + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/MultiThreadedTestFixtureAttribute.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/MultiThreadedTestFixtureAttribute.cs.meta new file mode 100644 index 0000000..f1a1f1b --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/MultiThreadedTestFixtureAttribute.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 6350ff3a13c3b404985ff4e890fbdde0 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/NameMatch.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/NameMatch.cs new file mode 100755 index 0000000..0b646a1 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/NameMatch.cs @@ -0,0 +1,74 @@ +using System; +using System.Text.RegularExpressions; + +namespace QuickGraph.Unit +{ + public enum NameMatchType + { + Exact, + Contains, + Regex + } + + public interface INameMatcher + { + bool IsMatch(string value); + } + + public static class NameMatcherFactory + { + public static INameMatcher CreateMatcher(NameMatchType matchType, string name) + { + switch (matchType) + { + case NameMatchType.Exact: return new ExactNameMatcher(name); + case NameMatchType.Contains: return new ContainsNameMatcher(name); + case NameMatchType.Regex: return new RegexNameMatcher(name); + default: throw new NotSupportedException(matchType.ToString()); + } + } + + private sealed class ExactNameMatcher : INameMatcher + { + string name; + public ExactNameMatcher(string name) + { + this.name = name; + } + + public bool IsMatch(string value) + { + return this.name.Equals(value); + } + } + + + private sealed class ContainsNameMatcher : INameMatcher + { + string name; + public ContainsNameMatcher(string name) + { + this.name = name; + } + + public bool IsMatch(string value) + { + return this.name.Contains(value); + } + } + + private sealed class RegexNameMatcher : INameMatcher + { + private Regex rx; + public RegexNameMatcher(string name) + { + rx = new Regex(name, RegexOptions.IgnoreCase | RegexOptions.Singleline); + } + + public bool IsMatch(string name) + { + return rx.IsMatch(name); + } + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/NameMatch.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/NameMatch.cs.meta new file mode 100644 index 0000000..0b6274f --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/NameMatch.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ac83b71a4b9ef47f296d77d79e82c999 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations.meta new file mode 100644 index 0000000..4abed9d --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: ef2da35880fa34598831e61f31222120 +folderAsset: yes +DefaultImporter: + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/ArrayDomain.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/ArrayDomain.cs new file mode 100755 index 0000000..5f7fe3d --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/ArrayDomain.cs @@ -0,0 +1,59 @@ +using System; +using System.Collections; + +namespace QuickGraph.Operations +{ + public sealed class ArrayDomain : DomainBase + { + private Array array; + + public ArrayDomain(Array array) + { + if (array == null) + throw new ArgumentNullException("array"); + this.array = array; + } + + public override int Count + { + get { return array.Length; } + } + + public override IEnumerator GetEnumerator() + { + return array.GetEnumerator(); + } + + public override Object this[int index] + { + get { return this.array.GetValue(index); } + } + } + + public sealed class ArrayDomain : DomainBase + { + private T[] array; + + public ArrayDomain(T[] array) + { + if (array == null) + throw new ArgumentNullException("array"); + this.array = array; + } + + public override int Count + { + get { return array.Length; } + } + + public override IEnumerator GetEnumerator() + { + return array.GetEnumerator(); + } + + public override Object this[int index] + { + get { return this.array.GetValue(index); } + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/ArrayDomain.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/ArrayDomain.cs.meta new file mode 100644 index 0000000..6777bb3 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/ArrayDomain.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: f01d9a316e350405b8007624e96cc17c +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/BooleanDomain.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/BooleanDomain.cs new file mode 100755 index 0000000..706fbf4 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/BooleanDomain.cs @@ -0,0 +1,35 @@ +using System; + +namespace QuickGraph.Operations +{ + public sealed class BooleanDomain : DomainBase + { + private bool[] values = new bool[] { true, false }; + public BooleanDomain() + {} + + public override int Count + { + get { return 2; } + } + + public override System.Collections.IEnumerator GetEnumerator() + { + return values.GetEnumerator(); + } + + public override Object this[int index] + { + get + { + switch (index) + { + case 0: return this.values[0]; + case 1: return this.values[1]; + default: + throw new ArgumentOutOfRangeException("index"); + } + } + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/BooleanDomain.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/BooleanDomain.cs.meta new file mode 100644 index 0000000..1ea6668 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/BooleanDomain.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 23483340c3ce64b02b97563a8a4f9d1c +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/CartesianProductDomainTupleEnumerable.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/CartesianProductDomainTupleEnumerable.cs new file mode 100755 index 0000000..8b62fcb --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/CartesianProductDomainTupleEnumerable.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; + +namespace QuickGraph.Operations +{ + internal sealed class CartesianProductDomainTupleEnumerable : IEnumerable + { + private IList domains; + public CartesianProductDomainTupleEnumerable(IList domains) + { + this.domains = domains; + } + + public IEnumerator GetEnumerator() + { + return new CartesianProductDomainTupleEnumerator(this.domains); + } + + System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() + { + return this.GetEnumerator(); + } + + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/CartesianProductDomainTupleEnumerable.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/CartesianProductDomainTupleEnumerable.cs.meta new file mode 100644 index 0000000..f5a5275 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/CartesianProductDomainTupleEnumerable.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: dde0115292fe941cc9854ffda2a11e9a +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/CartesianProductDomainTupleEnumerator.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/CartesianProductDomainTupleEnumerator.cs new file mode 100755 index 0000000..64a1fe0 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/CartesianProductDomainTupleEnumerator.cs @@ -0,0 +1,67 @@ +using System; +using System.Collections; +using System.Collections.Generic; + +namespace QuickGraph.Operations +{ + internal sealed class CartesianProductDomainTupleEnumerator : DomainTupleEnumeratorBase + { + private ITuple tuple = null; + private int[] indices = null; + + public CartesianProductDomainTupleEnumerator(IList domains) + :base(domains) + { + this.indices=new int[this.Domains.Count]; + this.Reset(); + } + + public override void Reset() + { + for (int i = 0; i < this.indices.Length; ++i) + { + if (i==this.indices.Length-1) + this.indices[i] = -1; + else + this.indices[i] = 0; + } + this.tuple=null; + } + + public override bool MoveNext() + { + for (int i = this.indices.Length - 1; i >= 0; i--) + { + if (this.indices[i] < this.Domains[i].Count - 1) + { + // updating index + this.indices[i]++; + // reseting the other to zero + for(int j = i+1 ; j < this.indices.Length;++j) + this.indices[j] = 0; + + // getting the tuple + tuple = new Tuple(); + for (int k = 0; k < this.indices.Length; ++k) + { + object item = this.Domains[k][this.indices[k]]; + tuple.Add(item); + } + + return true; + } + } + + + return false; + } + + public override ITuple Current + { + get + { + return this.tuple; + } + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/CartesianProductDomainTupleEnumerator.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/CartesianProductDomainTupleEnumerator.cs.meta new file mode 100644 index 0000000..1bb3344 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/CartesianProductDomainTupleEnumerator.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: f0c3e91211eb64aae91b2782ed6a49c6 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/CollectionDomain.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/CollectionDomain.cs new file mode 100755 index 0000000..cb33a18 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/CollectionDomain.cs @@ -0,0 +1,59 @@ +using System; +using System.Collections; + +namespace QuickGraph.Operations +{ + public sealed class CollectionDomain : CollectionBase, IDomain + { + private string name = null; + + public CollectionDomain() + { } + + public CollectionDomain(ICollection collection) + { + foreach (Object item in collection) + this.List.Add(item); + } + public CollectionDomain(IEnumerable enumerable) + { + foreach(Object item in enumerable) + this.List.Add(item); + } + + public string Name + { + get + { + return this.name; + } + set + { + this.name = value; + } + } + + public object this[int i] + { + get + { + return this.List[i]; + } + } + + public void AddDomain(IDomain domain) + { + if (domain == null) + throw new ArgumentNullException("domain"); + this.AddRange(domain); + } + + public void AddRange(IEnumerable enumerable) + { + if (enumerable == null) + throw new ArgumentNullException("enumerable"); + foreach (Object o in enumerable) + this.List.Add(o); + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/CollectionDomain.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/CollectionDomain.cs.meta new file mode 100644 index 0000000..7cb2556 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/CollectionDomain.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 050c7b902865a4d3487d3513d83ccb86 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/CombinationType.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/CombinationType.cs new file mode 100755 index 0000000..b96c2a7 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/CombinationType.cs @@ -0,0 +1,10 @@ +using System; + +namespace QuickGraph.Operations +{ + public enum CombinationType + { + PairWize, + Cartesian + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/CombinationType.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/CombinationType.cs.meta new file mode 100644 index 0000000..d77c35b --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/CombinationType.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 6f849fef4fe034768b1c8133493dba77 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/DomainBase.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/DomainBase.cs new file mode 100755 index 0000000..91b847e --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/DomainBase.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections; + +namespace QuickGraph.Operations +{ + public abstract class DomainBase : IDomain + { + private string name = null; + + public string Name + { + get + { + return this.name; + } + set + { + this.name = value; + } + } + + public abstract int Count { get;} + public abstract IEnumerator GetEnumerator(); + public abstract Object this[int index] { get;} + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/DomainBase.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/DomainBase.cs.meta new file mode 100644 index 0000000..5afc7f4 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/DomainBase.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 6ae5e419f657c4cb7bfdbcacc5b7a27c +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/DomainTupleEnumeratorBase.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/DomainTupleEnumeratorBase.cs new file mode 100755 index 0000000..7105608 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/DomainTupleEnumeratorBase.cs @@ -0,0 +1,49 @@ +using System; +using System.Collections; +using System.Collections.Generic; + +namespace QuickGraph.Operations +{ + internal abstract class DomainTupleEnumeratorBase : + IEnumerator, + IEnumerator + { + private IList domains; + public DomainTupleEnumeratorBase(IList domains) + { + if (domains == null) + throw new ArgumentNullException("domains"); + this.domains = domains; + foreach(IDomain domain in domains) + { + if (domain.Count == 0) + throw new ArgumentException("A domain is empty"); + } + } + + public IList Domains + { + get + { + return this.domains; + } + } + + public abstract void Reset(); + public abstract bool MoveNext(); + public abstract ITuple Current {get;} + + Object IEnumerator.Current + { + get + { + return this.Current; + } + } + + public virtual void Dispose() + { + this.domains = null; + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/DomainTupleEnumeratorBase.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/DomainTupleEnumeratorBase.cs.meta new file mode 100644 index 0000000..3fbf29b --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/DomainTupleEnumeratorBase.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: bbafa5dfeb40e46808c7a1153f7cde0f +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/Domains.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/Domains.cs new file mode 100755 index 0000000..1e40f5a --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/Domains.cs @@ -0,0 +1,171 @@ +using System; +using System.Collections; +using System.Collections.Generic; + +namespace QuickGraph.Operations +{ + public static class Domains + { + public static EmptyDomain Empty + { + get + { + return new EmptyDomain(); + } + } + + public static BooleanDomain Boolean + { + get { return new BooleanDomain(); } + } + + public static bool IsUniform(IList domains) + { + if (domains == null) + throw new ArgumentNullException("domains"); + + int maxCount = int.MinValue; + int minCount = int.MaxValue; + foreach (IDomain domain in domains) + { + maxCount = Math.Max(maxCount, domain.Count); + minCount = Math.Max(minCount, domain.Count); + if (maxCount != minCount) + return false; + } + return true; + } + + public static IList Uniformize(params Object[] domains) + { + return Uniformize(ToDomains(domains)); + } + + public static IList Uniformize(params ICollection[] domains) + { + return Uniformize(ToDomains(domains)); + } + + public static IList Uniformize(params IEnumerable[] domains) + { + return Uniformize(ToDomains(domains)); + } + + public static IList Uniformize(IList domains) + { + if (domains == null) + throw new ArgumentNullException("domains"); + + Random rnd = new Random((int)DateTime.Now.Ticks); + // find max + int maxCount = int.MinValue; + int minCount = int.MaxValue; + foreach (IDomain domain in domains) + { + maxCount = Math.Max(maxCount, domain.Count); + minCount = Math.Max(minCount, domain.Count); + } + + if (minCount == maxCount) + return domains; + + IList udomains = new List(); + foreach (IDomain domain in domains) + { + if (domain.Count == maxCount) + { + udomains.Add(domain); + continue; + } + + Object[] udomain = new Object[maxCount]; + int i; + for(i = 0;i ToDomains(Array array) + { + if (array == null) + throw new ArgumentNullException("array"); + if (array.Length == 0) + throw new ArgumentException("Length is zero", "array"); + IDomain[] domains = new IDomain[array.Length]; + for (int i = 0; i < array.Length; ++i) + domains[i] = ToDomain(array.GetValue(i)); + return new List(domains); + } + + public static IList ToDomains(params Object[] items) + { + if (items.Length == 0) + throw new ArgumentException("Length is zero", "items"); + IList ds = new List(); + foreach (Object domain in items) + ds.Add(ToDomain(domain)); + return ds; + } + + public static IDomain ToDomain(Object item) + { + IDomain domain = item as IDomain; + if (domain != null) + return domain; + + String s = item as String; + if (s != null) + return ToDomain(s); + + Array array = item as Array; + if (array != null) + return ToDomain(array); + + ICollection collection = item as ICollection; + if (collection != null) + return ToDomain(collection); + + IEnumerable enumerable = item as IEnumerable; + if (enumerable != null) + return ToDomain(enumerable); + + return new CollectionDomain(new object[]{item}); + } + + public static IDomain ToDomain(string s) + { + return new StringDomain(s); + } + + public static CollectionDomain ToDomain(ICollection collection) + { + if (collection == null) + throw new ArgumentNullException("collection"); + if (collection.Count == 0) + throw new ArgumentException("Collection is emtpy"); + return new CollectionDomain(collection); + } + + public static CollectionDomain ToDomain(IEnumerable enumerable) + { + if (enumerable == null) + throw new ArgumentNullException("enumerable"); + return new CollectionDomain(enumerable); + } + + public static ArrayDomain ToDomain(T[] items) + { + if (items == null) + throw new ArgumentNullException("items"); + if (items.Length == 0) + throw new ArgumentException("No arguments"); + return new ArrayDomain(items); + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/Domains.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/Domains.cs.meta new file mode 100644 index 0000000..3a6d4e6 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/Domains.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 773687409f9e84f60b5365183031cb20 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/EmptyDomain.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/EmptyDomain.cs new file mode 100755 index 0000000..ce6fc7a --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/EmptyDomain.cs @@ -0,0 +1,53 @@ +using System.Collections; +using System; + +namespace QuickGraph.Operations +{ + public sealed class EmptyDomain : IDomain + { + private string name = null; + public EmptyDomain() + {} + + public string Name + { + get + { + return this.name; + } + set + { + this.name=value; + } + } + + public IDomain Boundary + { + get + { + return this; + } + } + + public int Count + { + get + { + return 0; + } + } + + public object this[int i] + { + get + { + throw new InvalidOperationException("Empty domain"); + } + } + + public IEnumerator GetEnumerator() + { + return new ArrayList().GetEnumerator(); + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/EmptyDomain.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/EmptyDomain.cs.meta new file mode 100644 index 0000000..bfae1cd --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/EmptyDomain.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 698f0b4c8adef47c396b1477903d0a24 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/GreedyTupleEnumerator.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/GreedyTupleEnumerator.cs new file mode 100755 index 0000000..b2111a2 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/GreedyTupleEnumerator.cs @@ -0,0 +1,78 @@ +using System; +using System.Collections.Generic; + +namespace QuickGraph.Operations +{ + internal sealed class GreedyTupleEnumerable : IEnumerable + { + private IEnumerable enumerable; + public GreedyTupleEnumerable(IEnumerable enumerable) + { + if (enumerable == null) + throw new ArgumentNullException("enumerable"); + this.enumerable = enumerable; + } + + public IEnumerator GetEnumerator() + { + return new GreedyTupleEnumerator(this.enumerable.GetEnumerator()); + } + + + System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() + { + return this.GetEnumerator(); + } + + private sealed class GreedyTupleEnumerator : IEnumerator + { + private Dictionary tuples = new Dictionary(); + private IEnumerator enumerator; + + public GreedyTupleEnumerator(IEnumerator enumerator) + { + this.enumerator = enumerator; + } + + public void Reset() + { + throw new NotSupportedException(); + } + + public bool MoveNext() + { + while (this.enumerator.MoveNext()) + { + if (this.tuples.ContainsKey(this.Current)) + continue; + this.tuples.Add(this.Current, null); + return true; + } + return false; + } + + public ITuple Current + { + get + { + return this.enumerator.Current; + } + } + + Object System.Collections.IEnumerator.Current + { + get { return this.Current; } + } + + public void Dispose() + { + if (this.enumerator != null) + { + this.enumerator.Dispose(); + this.enumerator = null; + } + this.tuples = null; + } + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/GreedyTupleEnumerator.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/GreedyTupleEnumerator.cs.meta new file mode 100644 index 0000000..7c32599 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/GreedyTupleEnumerator.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ef66e85fd3a134614a8c2cb2bb095a9d +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/IDomain.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/IDomain.cs new file mode 100755 index 0000000..ab891c8 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/IDomain.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections; + +namespace QuickGraph.Operations +{ + public interface IDomain : IEnumerable + { + string Name { get;set;} + int Count { get;} + Object this[int i] {get;} + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/IDomain.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/IDomain.cs.meta new file mode 100644 index 0000000..3af810c --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/IDomain.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 57090d0765cc44cf3b06b28a37da8eaa +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/ITuple.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/ITuple.cs new file mode 100755 index 0000000..cb01fe6 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/ITuple.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections; + +namespace QuickGraph.Operations +{ + public interface ITuple : IEnumerable, IComparable + { + int Count { get;} + Object this[int i] { get;} + void Add(Object item); + void Concat(ITuple tuple); + + Object[] ToObjectArray(); + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/ITuple.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/ITuple.cs.meta new file mode 100644 index 0000000..2b65204 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/ITuple.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: f6e1cf3ef652941d3b6ed071e0c96274 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/ITupleEnumeratorFactory.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/ITupleEnumeratorFactory.cs new file mode 100755 index 0000000..60e1b3d --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/ITupleEnumeratorFactory.cs @@ -0,0 +1,10 @@ +using System; +using System.Collections.Generic; + +namespace QuickGraph.Operations +{ + public interface ITupleEnumeratorFactory + { + IEnumerator Create(ITuple tuple); + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/ITupleEnumeratorFactory.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/ITupleEnumeratorFactory.cs.meta new file mode 100644 index 0000000..d68457c --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/ITupleEnumeratorFactory.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 6c44b161f99524a47b39c6482fda981e +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/LinearInt32Domain.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/LinearInt32Domain.cs new file mode 100755 index 0000000..e660e03 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/LinearInt32Domain.cs @@ -0,0 +1,124 @@ +using System; +using System.Collections; + +namespace QuickGraph.Operations +{ + public sealed class LinearInt32Domain : IDomain + { + private IDomain boundary = null; + private string name = null; + private int start; + private int stepCount; + private int step; + + public LinearInt32Domain(int start, int stepCount) + :this(start,stepCount,1) + {} + public LinearInt32Domain(int start, int stepCount,int step) + { + this.start = start; + this.step = step; + this.stepCount = stepCount; + } + + public string Name + { + get + { + return name; + } + + set + { + name = value; + } + } + + public int Count + { + get + { + return this.stepCount; + } + } + + public IDomain Boundary + { + get + { + if (this.boundary == null) + { + this.boundary = new CollectionDomain(new int[] { this[0], this[this.stepCount - 1] }); + } + return this.boundary; + } + } + + public int this[int index] + { + get + { + if (index >= this.stepCount) + throw new ArgumentOutOfRangeException("Index is greater or equal to count"); + return this.start + index * this.step; + } + } + Object IDomain.this[int index] + { + get + { + return this[index]; + } + } + + public IEnumerator GetEnumerator() + { + return new LinearIntEnumerator(this.stepCount, this.stepCount, this.step); + } + + public class LinearIntEnumerator : IEnumerator + { + private int start; + private int step; + private int stepCount; + private int index = -1; + public LinearIntEnumerator(int start, int stepCount,int step) + { + this.start = start; + this.step = step; + this.stepCount = stepCount; + } + + public void Reset() + { + this.index = -1; + } + + public bool MoveNext() + { + this.index++; + return this.index < this.stepCount; + } + + public int Current + { + get + { + if (this.index < 0) + throw new InvalidOperationException("MoveNext was not called"); + if (this.index >= this.stepCount) + throw new InvalidOperationException("Enumeration out of range"); + return this.start + this.index * this.step; + } + } + + Object IEnumerator.Current + { + get + { + return this.Current; + } + } + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/LinearInt32Domain.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/LinearInt32Domain.cs.meta new file mode 100644 index 0000000..7155374 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/LinearInt32Domain.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 50815a066f93f48ec9c9839b07f3266f +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/NamespaceDoc.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/NamespaceDoc.cs new file mode 100755 index 0000000..3488d17 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/NamespaceDoc.cs @@ -0,0 +1,23 @@ +using System; + +namespace QuickGraph.Tests.Operations +{ + /// + /// + /// The QuickGraph.Operations namespace contains classes for building + /// Combinatorial Test suites. + /// + /// + /// The algorithms for generating the covergate suites are extracted + /// from Efficient Algorithms for Generation of Combinatorial Covering Suites, + /// by Adrian Dumitrescu. + /// + /// + internal sealed class NamespaceDoc + { + private NamespaceDoc() + { + + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/NamespaceDoc.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/NamespaceDoc.cs.meta new file mode 100644 index 0000000..8fc6972 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/NamespaceDoc.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e515f893fa4c342a5bf81814a1c920c4 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/OperationsResourceManager.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/OperationsResourceManager.cs new file mode 100755 index 0000000..0add0da --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/OperationsResourceManager.cs @@ -0,0 +1,51 @@ +using System; +using System.Collections; +using System.Drawing; +using System.Drawing.Imaging; +using System.Reflection; +using System.IO; + +namespace QuickGraph.Operations +{ + public static class OperationsResourceManager + { + public static Image GetImage(string imageName) + { + string resource = String.Format("QuickGraph.Unit.Operations.{0}.png", imageName); + Stream stream = typeof(OperationsResourceManager).Assembly + .GetManifestResourceStream(resource); + if (stream == null) + throw new Exception("Could not find resource " + resource); + Image img = Image.FromStream(stream); + return img; + } + + public static Image GetLogo() + { + return GetImage("operations"); + } + + public static Image GetLogoBanner() + { + return GetImage("operations.banner"); + } + + public static void DumpResources(string path) + { + if (path == null) + path = "."; + + using (Image logo = GetLogo()) + { + logo.Save(Path.Combine(path, "operations.png"), + System.Drawing.Imaging.ImageFormat.Png); + } + + using (Image logo = GetLogoBanner()) + { + logo.Save(Path.Combine(path, "operations.banner.png"), + System.Drawing.Imaging.ImageFormat.Png); + } + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/OperationsResourceManager.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/OperationsResourceManager.cs.meta new file mode 100644 index 0000000..a009df2 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/OperationsResourceManager.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e7b39f33846494963b565b4fcd793f33 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/PairWizeProductDomainTupleEnumerable.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/PairWizeProductDomainTupleEnumerable.cs new file mode 100755 index 0000000..c4c9f41 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/PairWizeProductDomainTupleEnumerable.cs @@ -0,0 +1,61 @@ +using System; +using System.Collections.Generic; + +namespace QuickGraph.Operations +{ + internal sealed class PairWizeProductDomainTupleEnumerable : IEnumerable + { + private IList domains; + public PairWizeProductDomainTupleEnumerable(IList domains) + { + if (domains==null) + throw new ArgumentNullException("domains"); + this.domains = domains; + } + + public IList Domains + { + get + { + return this.domains; + } + } + + public IEnumerator GetEnumerator() + { + return new PairWizeProductDomainTupleEnumerator(this.Domains); + } + + System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() + { + return this.GetEnumerator(); + } + + private sealed class PairWizeProductDomainTupleEnumerator : DomainTupleEnumeratorBase + { + public PairWizeProductDomainTupleEnumerator(IList domains) + :base(domains) + { + this.Reset(); + } + + public override void Reset() + { + throw new NotImplementedException(); + } + + public override bool MoveNext() + { + throw new NotImplementedException(); + } + + public override ITuple Current + { + get + { + throw new NotImplementedException(); + } + } + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/PairWizeProductDomainTupleEnumerable.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/PairWizeProductDomainTupleEnumerable.cs.meta new file mode 100644 index 0000000..a5bd8eb --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/PairWizeProductDomainTupleEnumerable.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 9a364ebbe9bf648f492d156bb12d72ea +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/Permutation.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/Permutation.cs new file mode 100755 index 0000000..8a1844c --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/Permutation.cs @@ -0,0 +1,282 @@ +using System; +using System.IO; +using System.Collections; +using System.Collections.Generic; + +namespace QuickGraph.Operations +{ + /// + /// A class to generate permutations. + /// + /// + /// + /// This class can generate any sequence of permutation of order . + /// The method returns the next permutation, while + /// can be used to iterates all the rest of the permutations. + /// + /// + /// The permutation can be applied to an array using , it can also + /// be inverted using . + /// + /// + /// This class was extracted from + /// + /// Using Permutations in .NET for Improved Systems Security by + /// Dr. James McCaffrey. + /// + /// + /// + public sealed class Permutation + { + private int[] data = null; + private int order = 0; + + /// + /// Creates a new idenity permutation + /// + /// + /// order of the new permutation + /// + public Permutation(int n) + { + if (n <= 0) + throw new ArgumentOutOfRangeException("n cannot be negative or zero"); + this.data = new int[n]; + for (int i = 0; i < n; ++i) + { + this.data[i] = i; + } + this.order = n; + } + + /// + /// Creates the -th permutation of + /// order . + /// + /// + /// + public Permutation(int n, int k) + { + if (n <= 0) + throw new ArgumentOutOfRangeException("n cannot be negative or zero"); + if (k <= 0) + throw new ArgumentOutOfRangeException("k cannot be negative or zero"); + + this.data = new int[n]; + this.order = this.data.Length; + + // Step #1 - Find factoradic of k + int[] factoradic = new int[n]; + + for (int j = 1; j <= n; ++j) + { + factoradic[n - j] = k % j; + k /= j; + } + + // Step #2 - Convert factoradic to permuatation + int[] temp = new int[n]; + + for (int i = 0; i < n; ++i) + { + temp[i] = ++factoradic[i]; + } + + this.data[n - 1] = 1; // right-most element is set to 1. + + for (int i = n - 2; i >= 0; --i) + { + this.data[i] = temp[i]; + for (int j = i + 1; j < n; ++j) + { + if (this.data[j] >= this.data[i]) + ++this.data[j]; + } + } + for (int i = 0; i < n; ++i) // put in 0-based form + { + --this.data[i]; + } + } // Permutation(n,k) + + private Permutation(int[] a) + { + if (a.Length == 0) + throw new ArgumentException("Order cannot be zero"); + this.data = new int[a.Length]; + a.CopyTo(this.data, 0); + this.order = a.Length; + + this.CheckPermutation(); + } + + /// + /// Gets the order of the permutation + /// + /// + public int Order + { + get + { + return this.order; + } + } + + /// + /// Checks that the permutation is correct + /// + private void CheckPermutation() + { + if (this.data.Length != this.order) + throw new Exception("Data.Length is not equal to the Order"); + + bool[] checks = new bool[this.data.Length]; + for (int i = 0; i < this.order; ++i) + { + if (this.data[i] < 0 || this.data[i] >= this.order) + throw new Exception("Value out of range at index " + i.ToString()); // value out of range + + if (checks[this.data[i]] == true) + throw new Exception("Duplicate value at index " + i.ToString()); // value out of range + checks[this.data[i]] = true; + } + } + + /// + /// Converts the permutation to a string representation. + /// + /// + public override string ToString() + { + StringWriter sb = new StringWriter(); + sb.Write("("); + for (int i = 0; i < this.order; ++i) + { + sb.Write("{0} ", this.data[i]); + } + sb.Write(")"); + + return sb.ToString(); + } + + /// + /// Applis the permutation to the array + /// + /// + /// A array of Length equal + /// to . + /// + /// A new array containing the permutated element of + /// + public T[] ApplyTo(T[] arr) + { + if (arr.Length != this.order) + throw new ArgumentException("array Length is equal to the permutation order"); + + T[] result = new T[arr.Length]; + for (int i = 0; i < result.Length; ++i) + { + result[i] = arr[this.data[i]]; + } + + return result; + } + + public void ApplyTo(IList arr) + { + if (arr.Count != this.order) + throw new ArgumentException("array Count is equal to the permutation order"); + + T[] result = new T[arr.Count]; + for (int i = 0; i < result.Length; ++i) + { + result[i] = arr[this.data[i]]; + } + + for (int i = 0; i < result.Length; ++i) + { + arr[i] = result[i]; + } + } + + /// + /// Creates the inverse of the permutation. + /// + /// + public Permutation Inverse() + { + int[] inverse = new int[this.order]; + + for (int i = 0; i < inverse.Length; ++i) + { + inverse[this.data[i]] = i; + } + + return new Permutation(inverse); + } + + /// + /// Creates the next permutation in lexicographic order. + /// + /// + /// The next instance if there remain any; + /// otherwize a null reference. + /// + public Permutation GetSuccessor() + { + Permutation result = new Permutation(this.order); + + int left, right; + + for (int k = 0; k < result.order; ++k) // Step #0 - copy current data into result + { + result.data[k] = this.data[k]; + } + + left = result.order - 2; // Step #1 - Find left value + while ((result.data[left] > result.data[left + 1]) && (left >= 1)) + { + --left; + } + if ((left == 0) && (this.data[left] > this.data[left + 1])) + return null; + + right = result.order - 1; // Step #2 - find right; first value > left + while (result.data[left] > result.data[right]) + { + --right; + } + + int temp = result.data[left]; // Step #3 - swap [left] and [right] + result.data[left] = result.data[right]; + result.data[right] = temp; + + + int i = left + 1; // Step #4 - order the tail + int j = result.order - 1; + + while (i < j) + { + temp = result.data[i]; + result.data[i++] = result.data[j]; + result.data[j--] = temp; + } + + return result; + } + + /// + /// Gets an enumerable collection of successors. + /// + /// + public IEnumerable GetSuccessors() + { + Permutation current = this.GetSuccessor(); + while (current != null) + { + yield return current; + current = current.GetSuccessor(); + } + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/Permutation.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/Permutation.cs.meta new file mode 100644 index 0000000..add99a6 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/Permutation.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 1c5e236d1e54e412a85cd258aa1a8e08 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/Products.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/Products.cs new file mode 100755 index 0000000..d12bc7b --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/Products.cs @@ -0,0 +1,111 @@ +using System; +using System.Collections; +using System.Collections.Generic; + +namespace QuickGraph.Operations +{ + public static class Products + { + #region Helpers + private static void CheckDomains(IList domains) + { + if (domains == null) + throw new ArgumentNullException("domains"); + if (domains.Count == 0) + throw new ArgumentException("domains is empty"); + for (int i = 0; i < domains.Count; ++i) + { + if (domains[i] == null) + throw new ArgumentNullException("Domain[" + i.ToString() + "] is null"); + if (domains[i].Count==0) + throw new ArgumentNullException("Domain[" + i.ToString() + "] is empty"); + } + } + #endregion + + #region Cartesian + public static IEnumerable Cartesian(IList domains) + { + CheckDomains(domains); + + return new CartesianProductDomainTupleEnumerable(domains); + } + + public static IEnumerable Cartesian(params IDomain[] domains) + { + return Cartesian(new List(domains)); + } + + public static IEnumerable Cartesian(params Object[] domains) + { + return Cartesian(Domains.ToDomains(domains)); + } + #endregion + + #region PairWize + public static IEnumerable PairWize(IList domains) + { + CheckDomains(domains); + if (domains.Count <= 2) + return Cartesian(domains); + + if (Domains.IsUniform(domains)) + return new UniformPairWizeProductDomainTupleEnumerable(domains); + else + { + IList udomains = Domains.Uniformize(domains); + return Greedy(new UniformPairWizeProductDomainTupleEnumerable(udomains)); + } + } + public static IEnumerable PairWize(params IDomain[] domains) + { + return PairWize(new List(domains)); + } + public static IEnumerable PairWize(params Object[] domains) + { + return PairWize(Domains.ToDomains(domains)); + } + #endregion + + #region TWize + public static IEnumerable TWize(int tupleSize, IList domains) + { + CheckDomains(domains); + + IList udomains = Domains.Uniformize(domains); + return new UniformTWizeProductDomainTupleEnumerable(udomains, tupleSize); + } + public static IEnumerable TWize(int tupleSize, params IDomain[] domains) + { + return TWize(tupleSize, new List(domains)); + } + public static IEnumerable TWize(int tupleSize, params Object[] domains) + { + return TWize(tupleSize, Domains.ToDomains(domains)); + } + #endregion + + public static IEnumerable Greedy(IEnumerable tuples) + { + if (tuples == null) + throw new ArgumentNullException("tuples"); + return new GreedyTupleEnumerable(tuples); + } + + + public static IEnumerable ComputeTupleProducts( + IList domains, + CombinationType combinationType) + { + switch (combinationType) + { + case CombinationType.PairWize: + return Products.PairWize(domains); + case CombinationType.Cartesian: + return Products.Cartesian(domains); + default: + throw new NotSupportedException(combinationType.ToString()); + } + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/Products.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/Products.cs.meta new file mode 100644 index 0000000..46af4db --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/Products.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: c0716967c37e14096a08712ad51b2442 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/StringDomain.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/StringDomain.cs new file mode 100755 index 0000000..6014581 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/StringDomain.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections; + +namespace QuickGraph.Operations +{ + internal sealed class StringDomain : DomainBase + { + private string value; + public StringDomain(string value) + { + this.value = value; + } + public override int Count + { + get { return 1; } + } + public override Object this[int i] + { + get + { + if (i != 0) + throw new ArgumentOutOfRangeException("index out of range"); + return this.value; + } + } + public override IEnumerator GetEnumerator() + { + ArrayList list = new ArrayList(); + list.Add(this.value); + return list.GetEnumerator(); + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/StringDomain.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/StringDomain.cs.meta new file mode 100644 index 0000000..95fd871 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/StringDomain.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 2b512920955924d3bbe3f6611f980dd8 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/Tuple.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/Tuple.cs new file mode 100755 index 0000000..bc99220 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/Tuple.cs @@ -0,0 +1,92 @@ +using System; +using System.Collections; +using System.IO; + +namespace QuickGraph.Operations +{ + public sealed class Tuple : CollectionBase, + ITuple, + IEquatable, + IComparable + { + public Tuple() + {} + + public object this[int index] + { + get + { + return this.List[index]; + } + } + + public void Add(Object o) + { + this.InnerList.Add(o); + } + + public void Concat(ITuple tuple) + { + foreach (Object o in tuple) + this.Add(o); + } + + public override string ToString() + { + StringWriter sw = new StringWriter(); + foreach (object item in this) + sw.Write("{0}, ", item); + return sw.ToString().TrimEnd(',',' '); + } + + // override object.Equals + public bool Equals(ITuple tuple) + { + if (tuple == null) + return false; + return this.CompareTo(tuple) == 0; + } + + // override object.GetHashCode + public override int GetHashCode() + { + int hash = 0; + foreach (object o in this) + { + if (o != null) + hash += o.GetHashCode(); + } + return hash; + } + + public int CompareTo(object tuple) + { + return this.CompareTo(tuple as ITuple); + } + + public int CompareTo(ITuple tuple) + { + if (((object)tuple) == null) + return -1; + if (this.Count < tuple.Count) + return -1; + else if (this.Count > tuple.Count) + return 1; + for (int i = 0; i < this.Count; ++i) + { + int c = Comparer.Default.Compare(this[i], tuple[i]); + if (c != 0) + return c; + } + return 0; + } + + public Object[] ToObjectArray() + { + object[] objs = new object[this.Count]; + this.List.CopyTo(objs, 0); + return objs; + } + } +} + diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/Tuple.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/Tuple.cs.meta new file mode 100644 index 0000000..136abdf --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/Tuple.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: a848add65a005410da63aa80d82ad835 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/UniformPairWizeProductDomainTupleEnumerable.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/UniformPairWizeProductDomainTupleEnumerable.cs new file mode 100755 index 0000000..d71d362 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/UniformPairWizeProductDomainTupleEnumerable.cs @@ -0,0 +1,206 @@ +using System; +using System.IO; +using System.Security.Cryptography; +using System.Text; +using System.Collections.Generic; + +namespace QuickGraph.Operations +{ + public sealed class UniformPairWizeProductDomainTupleEnumerable : + IEnumerable + { + private IList domains; + public UniformPairWizeProductDomainTupleEnumerable(IList domains) + { + if (domains == null) + throw new ArgumentNullException("domains"); + this.domains = domains; + int count = -1; + for (int i = 0; i < domains.Count; ++i) + { + if (domains[i].Count == 0) + throw new ArgumentException("domain count empty", i.ToString()); + if (i == 0) + count = domains[i].Count; + else + { + if (count != domains[i].Count) + throw new ArgumentException("Domains have not uniform size"); + } + } + } + + public IList Domains + { + get + { + return this.domains; + } + } + + public IEnumerator GetEnumerator() + { + return new UniformPairWizeProductDomainTupleEnumerator(this.Domains); + } + + System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() + { + return this.GetEnumerator(); + } + + private sealed class UniformPairWizeProductDomainTupleEnumerator : + DomainTupleEnumeratorBase + { + private int m = -1; + private int domainCount=-1; + private List bipartiteGraphs = null; + private int bipartiteGraphIndex = -1; + private int leftIndex = 0; + private int rightIndex = -1; + private Tuple tuple = null; + + public UniformPairWizeProductDomainTupleEnumerator(IList domains) + :base(domains) + { + this.domainCount = this.Domains[0].Count; + this.Reset(); + } + + public override void Reset() + { + // get number of bipartite graphs + m = (int)Math.Ceiling(Math.Log(this.Domains.Count, 2)); + + // create bipartite graphs + this.bipartiteGraphs = new List(m); + for (int i = 0; i < m; ++i) + { + // create bipartie graph + BipartiteGraph bg = new BipartiteGraph(this.Domains.Count); + this.bipartiteGraphs.Add(bg); + + // do some swapping + if (i>0) + bg.Swap(i-1, bg.Left.Count+i-1); + } + + + this.bipartiteGraphIndex = -1; + this.leftIndex = 0; + this.rightIndex = 0; + this.tuple = null; + } + + public override bool MoveNext() + { + do + { + if (this.leftIndex == this.rightIndex && this.bipartiteGraphIndex < this.bipartiteGraphs.Count) + { + this.bipartiteGraphIndex++; + this.CreateTuple(); + this.bipartiteGraphIndex = this.bipartiteGraphs.Count; + return true; + } + else + { + this.bipartiteGraphIndex++; + if (this.bipartiteGraphIndex < this.bipartiteGraphs.Count) + { + this.CreateTuple(); + return true; + } + } + + // increasing index + this.rightIndex++; + if (this.rightIndex >= this.domainCount) + { + this.leftIndex++; + this.rightIndex = 0; + } + this.bipartiteGraphIndex = -1; + } while (this.leftIndex < this.domainCount && this.rightIndex < this.domainCount); + + return false; + } + + private void CreateTuple() + { + // get bipartite graph + BipartiteGraph bg = (BipartiteGraph)this.bipartiteGraphs[this.bipartiteGraphIndex]; + + this.tuple = new Tuple(); + for (int i = 0; i < this.Domains.Count; ++i) + { + if (bg.Left.ContainsKey(i)) + this.tuple.Add(this.Domains[i][leftIndex]); + else + this.tuple.Add(this.Domains[i][rightIndex]); + } + } + + public override ITuple Current + { + get + { + return this.tuple; + } + } + + private sealed class BipartiteGraph + { + private SortedList left = new SortedList(); + private SortedList right = new SortedList(); + + public BipartiteGraph(int count) + { + int middle = count / 2 + count%2; + int i = 0; + for (i = 0; i < middle; ++i) + { + left.Add(i, i); + } + for (; i < count; ++i) + right.Add(i, i); + } + + public void Swap(int i, int j) + { + left.Remove(i); + right.Remove(j); + left.Add(j, j); + right.Add(i, i); + } + + public SortedList Left + { + get + { + return this.left; + } + } + public SortedList Right + { + get + { + return this.right; + } + } + + public override string ToString() + { + StringWriter sw = new StringWriter(); + sw.Write("["); + foreach (object o in this.Left.Keys) + sw.Write("{0} ",o); + sw.Write("] ["); + foreach (object o in this.Right.Keys) + sw.Write("{0} ", o); + sw.Write("]"); + return sw.ToString(); + } + } + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/UniformPairWizeProductDomainTupleEnumerable.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/UniformPairWizeProductDomainTupleEnumerable.cs.meta new file mode 100644 index 0000000..94305e7 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/UniformPairWizeProductDomainTupleEnumerable.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: cc8c3b202bb794c859f89c05b3463c86 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/UniformTWizeProductDomainTupleEnumerable.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/UniformTWizeProductDomainTupleEnumerable.cs new file mode 100755 index 0000000..e51d63f --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/UniformTWizeProductDomainTupleEnumerable.cs @@ -0,0 +1,81 @@ +using System; +using System.Collections.Generic; + +namespace QuickGraph.Operations +{ + public sealed class UniformTWizeProductDomainTupleEnumerable : + IEnumerable + { + private IList domains; + private int tupleSize; + public UniformTWizeProductDomainTupleEnumerable(IList domains, int tupleSize) + { + if (domains == null) + throw new ArgumentNullException("domains"); + if (tupleSize <= 0) + throw new ArgumentOutOfRangeException("tupleSize is negative or zero"); + + this.domains = domains; + this.tupleSize = tupleSize; + + int count = -1; + for (int i = 0; i < domains.Count; ++i) + { + if (i == 0) + count = domains[i].Count; + else + { + if (count != domains[i].Count) + throw new ArgumentException("Domains have not uniform size"); + } + } + } + + public IList Domains + { + get + { + return this.domains; + } + } + + public IEnumerator GetEnumerator() + { + return new UniformTWizeProductDomainTupleEnumerator(this.Domains, this.tupleSize); + } + + System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() + { + return this.GetEnumerator(); + } + + internal sealed class UniformTWizeProductDomainTupleEnumerator : + DomainTupleEnumeratorBase + { + private int tupleSize; + public UniformTWizeProductDomainTupleEnumerator(IList domains, int tupleSize) + :base(domains) + { + this.tupleSize = tupleSize; + this.CreateColoring(); + } + + public override void Reset() + { + throw new NotImplementedException(); + } + public override bool MoveNext() + { + throw new NotImplementedException(); + } + public override ITuple Current + { + get { throw new NotImplementedException(); } + } + + private void CreateColoring() + { + } + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/UniformTWizeProductDomainTupleEnumerable.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/UniformTWizeProductDomainTupleEnumerable.cs.meta new file mode 100644 index 0000000..93c2e72 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/UniformTWizeProductDomainTupleEnumerable.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 52e558d5ed1554b34a6192e7f5c91fb5 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/operations.banner.png b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/operations.banner.png new file mode 100755 index 0000000..672a2eb Binary files /dev/null and b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/operations.banner.png differ diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/operations.banner.png.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/operations.banner.png.meta new file mode 100644 index 0000000..951798b --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/operations.banner.png.meta @@ -0,0 +1,46 @@ +fileFormatVersion: 2 +guid: 3e1c3b0e167e04d7cbcff2fe80670509 +TextureImporter: + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + linearTexture: 0 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: -1 + mipBias: -1 + wrapMode: -1 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 0 + textureType: -1 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/operations.png b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/operations.png new file mode 100755 index 0000000..bc145f4 Binary files /dev/null and b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/operations.png differ diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/operations.png.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/operations.png.meta new file mode 100644 index 0000000..d25a259 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Operations/operations.png.meta @@ -0,0 +1,46 @@ +fileFormatVersion: 2 +guid: d01713dfddf994b7392cef6a2fc8d3ce +TextureImporter: + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + linearTexture: 0 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: -1 + mipBias: -1 + wrapMode: -1 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 0 + textureType: -1 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/PerfMonitorAttribute.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/PerfMonitorAttribute.cs new file mode 100755 index 0000000..48072be --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/PerfMonitorAttribute.cs @@ -0,0 +1,101 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using QuickGraph.Unit.Core; + +namespace QuickGraph.Unit +{ + [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, Inherited=true, AllowMultiple=true)] + public sealed class PerfMonitorAttribute : TestDecoratorAttributeBase + { + private string categoryName; + private string counterName; + private float valueDelta; + private bool relativeDelta = true; + + public PerfMonitorAttribute( + string categoryName, + string counterName, + float valueDelta + ) + { + this.categoryName = categoryName; + this.counterName = counterName; + this.valueDelta = valueDelta; + } + + public string CategoryName + { + get { return this.categoryName; } + set { this.categoryName = value; } + } + + public string CounterName + { + get { return this.counterName; } + set { this.counterName = value; } + } + + public float ValueDelta + { + get { return this.valueDelta; } + set { this.valueDelta = value; } + } + + public bool RelativeDelta + { + get { return this.relativeDelta; } + set { this.relativeDelta = value; } + } + + public override ITestCase Decorate(ITestCase testCase) + { + return new PerfMonitorTestCase(testCase, this); + } + + private sealed class PerfMonitorTestCase : TypeDecoratorTestCaseBase + { + public PerfMonitorTestCase(ITestCase testCase, PerfMonitorAttribute attribute) + :base(testCase, attribute) + {} + + public override void Run(object fixture) + { + using(PerformanceCounter counter = new PerformanceCounter( + this.Attribute.CategoryName, + this.Attribute.CounterName, + true)) + { + float startValue = counter.NextValue(); + Console.WriteLine( + "[start] {0}/{1}: {2} [{3}]", + this.Attribute.CategoryName, + this.Attribute.CounterName, + startValue, + counter.CounterType + ); + this.TestCase.Run(fixture); + float endValue = counter.NextValue(); + Console.WriteLine( + "[end] {0}/{1}: {2} [{3}]", + this.Attribute.CategoryName, + this.Attribute.CounterName, + endValue, + counter.CounterType + ); + + float delta = Math.Abs(endValue - startValue) ; + if (this.Attribute.RelativeDelta) + delta /= Math.Abs(startValue); + + if (delta > this.Attribute.ValueDelta) + Assert.Fail("{0}/{1} value delta ({2}) is greater than accepted threshold ({3})", + this.Attribute.CategoryName, + this.Attribute.CounterName, + this.Attribute.ValueDelta, + delta); + } + } + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/PerfMonitorAttribute.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/PerfMonitorAttribute.cs.meta new file mode 100644 index 0000000..bf39266 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/PerfMonitorAttribute.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 5a984c64a8eb3483084a219d08ac898f +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Pex.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Pex.meta new file mode 100644 index 0000000..8d4502e --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Pex.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: 514502fe4eb32445792adb6e0ada3eb7 +folderAsset: yes +DefaultImporter: + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Pex/QuickGraphPackageAttribute.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Pex/QuickGraphPackageAttribute.cs new file mode 100755 index 0000000..5ad18db --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Pex/QuickGraphPackageAttribute.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Microsoft.Pex.Framework.Packages; +using QuickGraph.Unit.Pex; + +[assembly: QuickGraphTestFramework] + +namespace QuickGraph.Unit.Pex +{ + public sealed class QuickGraphPackageAttribute : + PexPackageAssemblyAttribute + { + public QuickGraphPackageAttribute() + :base(typeof(QuickGraphPackageAttribute)) + { } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Pex/QuickGraphPackageAttribute.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Pex/QuickGraphPackageAttribute.cs.meta new file mode 100644 index 0000000..416e386 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Pex/QuickGraphPackageAttribute.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 404e4b573b9264bff9213f7d310a05b1 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Pex/QuickGraphTestFramework.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Pex/QuickGraphTestFramework.cs new file mode 100755 index 0000000..6c3afb4 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Pex/QuickGraphTestFramework.cs @@ -0,0 +1,152 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Microsoft.Pex.Framework.TestFrameworks; +using Microsoft.Pex.Engine.TestFrameworks; +using Microsoft.Pex.Engine.ComponentModel; +using Microsoft.ExtendedReflection.Metadata.Names; +using Microsoft.ExtendedReflection.Metadata; +using QuickGraph.Unit.Core; + +namespace QuickGraph.Unit.Pex +{ + class QuickGraphTestFrameworkAttribute : + PexTestFrameworkAttributeBase + { + protected override IPexTestFramework CreateTestFramework(IPexComponent host) + { + return new TestFramework(host); + } + + class TestFramework : + AttributeBasedTestFrameworkBase + { + public TestFramework(IPexComponent host) + :base(host) + {} + + public override ShortAssemblyName AssemblyName + { + get { return ShortAssemblyName.FromAssembly(typeof(QuickGraph.IEdge<>).Assembly); } + } + + public override TypeName AssertionExceptionType + { + get { return Metadata.SerializableName; } + } + + public override TypeName FixtureAttribute + { + get { return Metadata.SerializableName; } + } + + public override TypeName FixtureSetUpAttribute + { + get { return Metadata.SerializableName; } + } + + protected override string GetHintPath(string assemblyName) + { + return null; + } + + public override string RootNamespace + { + get { return "QuickGraph.Unit"; } + } + + public override bool FixtureSetUpTearDownInstance + { + get { return false; } + } + + public override bool SupportsPartialClasses + { + get { return true; } + } + + public override TypeName FixtureTearDownAttribute + { + get { return Metadata.SerializableName; } + } + + public override TypeName IgnoreAttribute + { + get { return Metadata.SerializableName; } + } + + public override TypeName AssumptionExceptionType + { + get { return Metadata.SerializableName; } + } + + public override TypeName ExpectedExceptionAttribute + { + get { return Metadata.SerializableName; } + } + + protected override string IgnoreMessageProperty + { + get { return "Message"; } + } + + public override string Name + { + get { return "QuickGraph"; } + } + + public override TypeName SetUpAttribute + { + get { return Metadata.SerializableName; } + } + + public override bool IsFixture(TypeDefinition target) + { + return AttributeHelper.IsDefined( + target, + Metadata.Type); + } + + public override bool IsTest(MethodDefinition method) + { + return AttributeHelper.IsDefined( + method, + Metadata.Type); + } + + public override TypeName TearDownAttribute + { + get { return Metadata.SerializableName; } + } + + public override TypeName TestAttribute + { + get { return Metadata.SerializableName; } + } + + protected override bool TryGetCategories( + ICustomAttributeProviderEx element, + out IEnumerable names) + { + names = new string[] { }; + return false; + } + + public override bool TryGetAssemblySetupTeardownMethods(AssemblyEx assembly, out Method setup, out Method teardown) + { + setup = teardown = null; + return false; + } + + protected override string ExpectedExceptionProperty + { + get { return "ExpectedExceptionType"; } + } + + protected override bool HasIgnoreAttributeMessage + { + get { return true; } + } + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Pex/QuickGraphTestFramework.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Pex/QuickGraphTestFramework.cs.meta new file mode 100644 index 0000000..4a44795 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Pex/QuickGraphTestFramework.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: afbb58fe197fe4372ba76c81b04fd46c +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/ProcessTester.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/ProcessTester.cs new file mode 100755 index 0000000..25fd16c --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/ProcessTester.cs @@ -0,0 +1,228 @@ +using System.Collections; +using System.Collections.Specialized; +using System; +using System.Diagnostics; +using System.IO; + +namespace QuickGraph.Unit +{ + public class ProcessTester : IDisposable + { + private string fileName; + private string[] args; + private int expectedExitCode = 0; + private int exitCode; + private bool throwOnWrongExitCode = true; + private int timeOut = int.MaxValue; + private Process process; + private bool useShellExecute = false; + private bool redirectConsole = true; + private string consoleOut; + private string consoleError; + private bool dumpConsoleOnSuccess = false; + private StringDictionary environmentVariables = new StringDictionary(); + + public static void StartAndRun(string fileName, params string[] args) + { + using (ProcessTester tester = new ProcessTester(fileName, args)) + { + tester.ThrowOnWrongExitCode = false; + tester.Run(); + } + } + + public static void StartAndRun(string fileName, int exitCode, params string[] args) + { + using (ProcessTester tester = new ProcessTester(fileName, args)) + { + tester.ExpectedExitCode = exitCode; + tester.Run(); + } + } + + public ProcessTester() + { } + + public ProcessTester( + string fileName, + params string[] args) + { + if (fileName == null) + throw new ArgumentNullException("fileName"); + this.fileName = fileName; + this.args = args; + } + + public void Dispose() + { + if (this.process != null) + { + if (!this.process.HasExited) + this.process.Kill(); + this.process.Dispose(); + this.process = null; + GC.SuppressFinalize(this); + } + } + + public string ConsoleOut + { + get + { + return this.consoleOut; + } + } + + public string ConsoleError + { + get + { + return this.consoleError; + } + } + + public bool UseShellExecute + { + get { return this.useShellExecute; } + set { this.useShellExecute = value; } + } + + public bool DumpConsoleOnSuccess + { + get { return this.dumpConsoleOnSuccess; } + set { this.dumpConsoleOnSuccess = value; } + } + + public StringDictionary EnvironmentVariables + { + get { return this.environmentVariables; } + } + + public bool ThrowOnWrongExitCode + { + get { return this.throwOnWrongExitCode; } + set { this.throwOnWrongExitCode = value; } + } + + public int ExitCode + { + get { return this.exitCode; } + } + + public int ExpectedExitCode + { + get { return this.expectedExitCode; } + set { this.expectedExitCode = value; } + } + + public int TimeOut + { + get { return this.timeOut; } + set { this.timeOut = value; } + } + + public bool RedirectConsole + { + get { return this.redirectConsole; } + set { this.redirectConsole = value; } + } + + public string GetArguments() + { + StringWriter sw = new StringWriter(); + foreach (string arg in this.args) + sw.Write(" {0} ", arg); + return sw.ToString(); + } + + public bool Run(string fileName, params string[] args) + { + if (string.IsNullOrEmpty(fileName)) + throw new ArgumentNullException("fileName"); + this.fileName = fileName; + this.args = args; + + return this.Run(); + } + + public bool Run() + { + ProcessStartInfo info = new ProcessStartInfo( + this.fileName, + this.GetArguments() + ); + info.CreateNoWindow = true; + info.UseShellExecute = this.UseShellExecute; + if (!this.UseShellExecute && this.RedirectConsole) + { + info.RedirectStandardOutput = true; + info.RedirectStandardError = true; + this.consoleError = ""; + this.consoleOut = ""; + } + else + { + info.RedirectStandardOutput = false; + info.RedirectStandardError = false; + } + foreach (DictionaryEntry de in this.EnvironmentVariables) + info.EnvironmentVariables.Add((string)de.Key, (string)de.Value); + + Console.WriteLine("\"{0}\" {1}", info.FileName, info.Arguments); + + this.process = Process.Start(info); + this.process.Start(); + + // getting console output + if (!this.UseShellExecute && this.RedirectConsole) + { + this.consoleOut += this.process.StandardOutput.ReadToEnd(); + this.consoleError += this.process.StandardError.ReadToEnd(); + } + + bool timedOut = process.WaitForExit(this.TimeOut); + this.process.Refresh(); + + // kill process if necessary + if (!process.HasExited) + process.Kill(); + + // getting console output + if (!this.UseShellExecute && this.RedirectConsole) + { + this.consoleOut += this.process.StandardOutput.ReadToEnd(); + this.consoleError += this.process.StandardError.ReadToEnd(); + } + + // check time out + if (!timedOut) + { + this.DumpConsoles(); + Assert.Fail("Process timed out"); + } + + // check return value + this.exitCode = process.ExitCode; + + if (this.ExitCode!= this.ExpectedExitCode || this.DumpConsoleOnSuccess) + this.DumpConsoles(); + + if (this.ThrowOnWrongExitCode) + { + Assert.AreEqual(this.ExpectedExitCode, this.ExitCode, + "Process ExitCode ({0}) does not match expected ExitCode ({1})", + this.ExitCode, this.ExpectedExitCode); + } + + return this.ExitCode == this.ExpectedExitCode; + } + + private void DumpConsoles() + { + if (!string.IsNullOrEmpty(this.ConsoleOut)) + Console.Out.WriteLine(this.ConsoleOut); + if (!string.IsNullOrEmpty(this.ConsoleError)) + Console.Error.WriteLine(this.ConsoleError); + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/ProcessTester.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/ProcessTester.cs.meta new file mode 100644 index 0000000..ed95fa9 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/ProcessTester.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 82faf2b596a3f4ef1ab3eaf2c8c0be52 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Properties.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Properties.meta new file mode 100644 index 0000000..24b250b --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Properties.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: 8bf43ae52321446e08721156c83c91c5 +folderAsset: yes +DefaultImporter: + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Properties/AssemblyInfo.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Properties/AssemblyInfo.cs new file mode 100755 index 0000000..96d9a15 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Properties/AssemblyInfo.cs @@ -0,0 +1,27 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Xml.Serialization; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("QuickGraph.Unit")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Home")] +[assembly: AssemblyProduct("QuickGraph.Unit")] +[assembly: AssemblyCopyright("Copyright Microsoft 2005")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Revision and Build Numbers +// by using the '*' as shown below: +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Properties/AssemblyInfo.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Properties/AssemblyInfo.cs.meta new file mode 100644 index 0000000..6f15f63 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Properties/AssemblyInfo.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b6425ec2682f548b587d2c01a8266e25 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/QuickGraph.Unit.csproj b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/QuickGraph.Unit.csproj new file mode 100755 index 0000000..21411ed --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/QuickGraph.Unit.csproj @@ -0,0 +1,354 @@ + + + Debug + AnyCPU + 9.0.30729 + 2.0 + {9FF2B839-743F-4A15-9D33-F11253BF6AE1} + Library + Properties + QuickGraph.Unit + QuickGraph.Unit + quickgraph.snk + File + true + SAK + SAK + SAK + SAK + + + 2.0 + + + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + true + Off + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + Off + + + + False + + + False + + + + + + + + + + + + + Properties\version.cs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Component + + + + + + Component + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Component + + + Component + + + Component + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Component + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + True + + + + + True + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {A9A5C115-0680-44B3-A87E-5ECF4C93814E} + QuickGraph + + + + + + + \ No newline at end of file diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/QuickGraph.Unit.csproj.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/QuickGraph.Unit.csproj.meta new file mode 100644 index 0000000..3ec09f5 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/QuickGraph.Unit.csproj.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: 513f9685eb9534da4aa15534eaad73c6 +DefaultImporter: + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/QuickGraph.Unit.csproj.vspscc b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/QuickGraph.Unit.csproj.vspscc new file mode 100755 index 0000000..feffdec --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/QuickGraph.Unit.csproj.vspscc @@ -0,0 +1,10 @@ +"" +{ +"FILE_VERSION" = "9237" +"ENLISTMENT_CHOICE" = "NEVER" +"PROJECT_FILE_RELATIVE_PATH" = "" +"NUMBER_OF_EXCLUDED_FILES" = "0" +"ORIGINAL_PROJECT_FILE_PATH" = "" +"NUMBER_OF_NESTED_PROJECTS" = "0" +"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROVIDER" +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/QuickGraph.Unit.csproj.vspscc.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/QuickGraph.Unit.csproj.vspscc.meta new file mode 100644 index 0000000..6d270be --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/QuickGraph.Unit.csproj.vspscc.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: 54d12a41335dc45d692a0c7b4ba13420 +DefaultImporter: + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/ReflectionAssert.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/ReflectionAssert.cs new file mode 100755 index 0000000..eddd47a --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/ReflectionAssert.cs @@ -0,0 +1,86 @@ +using System; +using System.Collections.Generic; +using System.Reflection; +using System.IO; + +namespace QuickGraph.Unit +{ + public static class ReflectionAssert + { + public static void IsInstanceOfType(Type left, object value) + { + Assert.IsTrue(left.IsInstanceOfType(value), + "{0} is not an instance of type {1}", left, value.GetType()); + } + + public static void IsAssignableFrom(Type left, Type right) + { + Assert.IsTrue(left.IsAssignableFrom(right), + "Type {0} is not assignable from {1}", left,right); + } + + public static void IsSealed(Type type) + { + Assert.IsTrue(type.IsSealed, + "Type {0} is not sealed", type); + } + + public static void HasConstructor(Type type, params Type[] parameterTypes) + { + Assert.IsNotNull( + type.GetConstructor(parameterTypes), + "Type {0} has no suitable constructor", type); + } + + public static void IsTaggedWithAttribute( + ICustomAttributeProvider type, + Type attributeType, + bool inherit) + { + Object[] attributes = type.GetCustomAttributes(attributeType, inherit); + if (attributes == null || attributes.Length == 0) + Assert.Fail( + "{0} is not tagged with {1}", type, attributeType); + } + + public static void DisplayType(Type type) + { + Console.WriteLine("FullName: {0}", type.FullName); + Console.WriteLine("Base: {0}", type.BaseType); + Type[] interfaceTypes = type.GetInterfaces(); + Console.WriteLine("Interfaces ({0}):", interfaceTypes.Length); + foreach (Type interfaceType in interfaceTypes) + Console.WriteLine("\t{0}", interfaceType); + + ConstructorInfo[] constructors = type.GetConstructors(); + Console.WriteLine("Constructors ({0}):", constructors.Length); + foreach (ConstructorInfo constructor in constructors) + { + Console.WriteLine("\t{0}({1})", constructor.Name, + ParametersToString(constructor.GetParameters()) + ); + } + + MethodInfo[] methods = type.GetMethods(); + Console.WriteLine("Methods ({0}):", methods.Length); + foreach (MethodInfo method in methods) + { + Console.WriteLine("\t{0}({1})", method.Name, + ParametersToString(method.GetParameters()) + ); + } + } + + public static string ParametersToString(ParameterInfo[] parameters) + { + using (StringWriter writer = new StringWriter()) + { + foreach (ParameterInfo parameter in parameters) + writer.Write(",{0} {1}", parameter.ParameterType, parameter.Name); + + return String.Format("{0}", writer.ToString().TrimStart(',')); + } + } + + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/ReflectionAssert.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/ReflectionAssert.cs.meta new file mode 100644 index 0000000..34b3f16 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/ReflectionAssert.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: c2625c8e48c2d49c49f195a4b7d75aa7 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/RepeatAttribute.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/RepeatAttribute.cs new file mode 100755 index 0000000..c78d6a4 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/RepeatAttribute.cs @@ -0,0 +1,46 @@ +using System; +using System.Collections.Generic; +using QuickGraph.Unit.Core; + +namespace QuickGraph.Unit +{ + [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, AllowMultiple=true, Inherited=true)] + public sealed class RepeatAttribute : TestDecoratorAttributeBase + { + private int count = 1; + + public RepeatAttribute() + { } + + public RepeatAttribute(int count) + { + this.count = count; + } + + public int Count + { + get { return this.count; } + set { this.count = value; } + } + + public override ITestCase Decorate(ITestCase testCase) + { + return new RepeatTestCase(testCase, this); + } + + private sealed class RepeatTestCase : TypeDecoratorTestCaseBase + { + public RepeatTestCase(ITestCase testCase, RepeatAttribute attribute) + : base(testCase, attribute) + { } + + public override void Run(object fixture) + { + for (int i = 0; i < this.Attribute.count; ++i) + { + this.TestCase.Run(fixture); + } + } + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/RepeatAttribute.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/RepeatAttribute.cs.meta new file mode 100644 index 0000000..57207fa --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/RepeatAttribute.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 0fa097940f9aa4f909d9f05bebb42d66 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Reports.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Reports.meta new file mode 100644 index 0000000..19e0828 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Reports.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: f891b7cc385814b439cbb14ba586fd5c +folderAsset: yes +DefaultImporter: + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Reports/FileReportBase.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Reports/FileReportBase.cs new file mode 100755 index 0000000..6d4e071 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Reports/FileReportBase.cs @@ -0,0 +1,97 @@ +using System; +using System.IO; +using System.Diagnostics; +using System.ComponentModel; +using System.Xml; + +namespace QuickGraph.Unit.Reports +{ + public abstract class FileReportBase : ReportBase + { + private string outputFolderName = null; + private string defaultFileExtension; + private string outputFileName; + private bool displayOnDisposed = false; + + public FileReportBase( + IContainer container, + string defaultFileExtension + ) + : base(container) + { + this.defaultFileExtension = defaultFileExtension.ToLower(); + } + + public bool DisplayOnDisposed + { + get { return this.displayOnDisposed; } + set { this.displayOnDisposed = value; } + } + + public string OutputFolderName + { + get { return this.outputFolderName; } + } + + public void SetOutputFolderName(string path, string testAssemblyName) + { + string folderName = ReportPath.GetName(testAssemblyName,this.CreationTime); + SetOutputFolderName(Path.Combine(path, folderName)); + } + + public void SetOutputFolderName(string outputFolderName) + { + this.outputFolderName = Path.GetFullPath(outputFolderName); + } + + public string DefaultFileExtension + { + get { return this.defaultFileExtension; } + } + + public string OutputFileName + { + get { return this.outputFileName; } + } + + public override void Generate() + { + Directory.CreateDirectory(Path.GetDirectoryName(this.OutputFileName)); + using (StreamWriter swriter = new StreamWriter(this.OutputFileName)) + { + this.Generate(swriter); + } + } + + public abstract void Generate(TextWriter writer); + + public virtual void SetOutputFileName(string outputFileName) + { + this.outputFileName = outputFileName.Replace('.', '_'); + if (!this.OutputFileName.ToLower().EndsWith('.' + this.DefaultFileExtension)) + this.outputFileName += '.' + this.DefaultFileExtension; + + this.outputFileName = ReportPath.EscapeFileName(this.outputFileName); + if (!String.IsNullOrEmpty(this.OutputFolderName)) + this.outputFileName = Path.Combine( + this.OutputFolderName, + this.OutputFileName); + + this.outputFileName = Path.GetFullPath(this.OutputFileName); + } + + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + if (disposing) + { + if (this.DisplayOnDisposed && this.OutputFileName != null) + { + System.Diagnostics.Process.Start(this.OutputFileName); + this.DisplayOnDisposed = false; + } + } + } + + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Reports/FileReportBase.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Reports/FileReportBase.cs.meta new file mode 100644 index 0000000..0a97567 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Reports/FileReportBase.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b27f0a7cd85654e31a9b6dc7278054d7 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Reports/ReportBase.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Reports/ReportBase.cs new file mode 100755 index 0000000..5ec6e95 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Reports/ReportBase.cs @@ -0,0 +1,44 @@ +using System; +using System.IO; +using System.Diagnostics; +using System.ComponentModel; + +namespace QuickGraph.Unit.Reports +{ + public abstract class ReportBase : Component + { + private bool generateOnDisposed = false; + private DateTime creationTime = DateTime.Now; + + public ReportBase(IContainer container) + { + container.Add(this); + } + + public DateTime CreationTime + { + get + { + return this.creationTime; + } + } + + public abstract void Generate(); + + public bool GenerateOnDisposed + { + get { return this.generateOnDisposed; } + set { this.generateOnDisposed = value; } + } + + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + if (disposing && this.GenerateOnDisposed) + { + this.Generate(); + this.GenerateOnDisposed = false; + } + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Reports/ReportBase.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Reports/ReportBase.cs.meta new file mode 100644 index 0000000..a805422 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Reports/ReportBase.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 87ab06c7bfb3f43c390700e5bcbecd90 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Reports/ReportCleaner.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Reports/ReportCleaner.cs new file mode 100755 index 0000000..1526caf --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Reports/ReportCleaner.cs @@ -0,0 +1,29 @@ +using System; +using System.IO; +using System.Text.RegularExpressions; +using System.Collections.Generic; + +namespace QuickGraph.Unit.Reports +{ + public sealed class ReportCleaner + { + private Regex pattern; + private int maxReportCount = 25; + + public ReportCleaner(string testAssemblyName) + { + this.pattern = ReportPath.GetRegex(testAssemblyName); + } + + public int MaxReportCount + { + get { return this.maxReportCount; } + set { this.maxReportCount = value; } + } + + public void Clean(string path, TestRunner runner) + { + // to do implement + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Reports/ReportCleaner.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Reports/ReportCleaner.cs.meta new file mode 100644 index 0000000..e7854f0 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Reports/ReportCleaner.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: dc2517e30c7b34bdeb47d2487b049095 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Reports/ReportHistory.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Reports/ReportHistory.cs new file mode 100755 index 0000000..5227884 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Reports/ReportHistory.cs @@ -0,0 +1,99 @@ +using System; +using System.IO; +using System.Collections.Generic; +using System.Xml; +using System.Xml.XPath; + +namespace QuickGraph.Unit.Reports +{ + public sealed class ReportHistory + { + private string reportOutputPath; + private string testAssemblyName; + + public ReportHistory(string reportOutputPath, string testAssemblyName) + { + this.reportOutputPath = reportOutputPath; + this.testAssemblyName = testAssemblyName; + } + + public string ReportOutputPath + { + get { return this.reportOutputPath; } + } + + public string TestAssemblyName + { + get { return this.testAssemblyName; } + } + + public string GetLatestXmlReport() + { + List reports = new List(GetPreviousXmlReports()); + if (reports.Count == 0) + return null; + reports.Sort(new CreationTimeComparer()); + return reports[reports.Count - 1]; + } + + public IEnumerable GetPreviousXmlReports() + { + string searchPattern = String.Format("{0}.html.xml", ReportPath.EscapeAssemblyName(TestAssemblyName)); + searchPattern = ReportPath.EscapeFileName(searchPattern); + // look for the report file + foreach (string xmlreport in Directory.GetFiles( + this.ReportOutputPath, + searchPattern, + SearchOption.AllDirectories + )) + { + yield return xmlreport; + } + } + + public XmlDocument LoadReportHistory() + { + XmlDocument document = new XmlDocument(); + XmlElement root = document.CreateElement("MergedBatch"); + document.AppendChild(root); + XmlElement testBatches = document.CreateElement("TestBatches"); + root.AppendChild(testBatches); + + foreach (string previousResult in this.GetPreviousXmlReports()) + { + try + { + using (StreamReader reader = new StreamReader(previousResult)) + { + XmlDocument previousDocument = new XmlDocument(); + previousDocument.Load(reader); + string path = Path.GetFullPath(previousResult); + path = path.Substring(0, path.Length - ".xml".Length); + previousDocument.DocumentElement.SetAttribute("Path", path); + testBatches.AppendChild( + document.ImportNode(previousDocument.DocumentElement, true) + ); + } + } + catch (XmlException ex) + { + Assert.Logger.LogWarning("Error while loading {0}: {1}", + previousResult, + ex.Message); + } + } + + return document; + } + + private sealed class CreationTimeComparer : IComparer + { + public int Compare(string x, string y) + { + FileInfo fx = new FileInfo(x); + FileInfo fy = new FileInfo(y); + return fx.CreationTime.CompareTo(fy.CreationTime); + } + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Reports/ReportHistory.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Reports/ReportHistory.cs.meta new file mode 100644 index 0000000..3eb25b3 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Reports/ReportHistory.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 51fc9e30f33674a19b9fb80b9ede7db6 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Reports/ReportPath.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Reports/ReportPath.cs new file mode 100755 index 0000000..616553a --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Reports/ReportPath.cs @@ -0,0 +1,44 @@ +using System; +using System.IO; +using System.Text.RegularExpressions; +using System.Collections.Generic; + +namespace QuickGraph.Unit.Reports +{ + public static class ReportPath + { + public static string GetName(string testAssemblyName, DateTime time) + { + return String.Format("{0}_{1}", + EscapeAssemblyName(testAssemblyName), + time.ToString("HHmmss") + ); + } + + internal static Regex GetRegex(string testAssemblyName) + { + string etan = EscapeAssemblyName(testAssemblyName).ToLower(); + return new Regex(etan + @"_\d{5}_\d{6}"); + } + + public static string EscapeFileName(string fileName) + { + return fileName + .Replace(' ', '_') + .Replace('/', '_') + .Replace(':', '_') + .Replace('(', '_') + .Replace(')', '_') + .Replace('[', '_') + .Replace(']', '_') + .Replace('{', '_') + .Replace('}', '_') + ; + } + + public static string EscapeAssemblyName(string assemblyName) + { + return EscapeFileName(assemblyName).Replace('.', '_'); + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Reports/ReportPath.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Reports/ReportPath.cs.meta new file mode 100644 index 0000000..ad6866d --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Reports/ReportPath.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 29546e0d4c4c144e5887f12a6eef0469 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Reports/UnitTestHistoryHtmlReport.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Reports/UnitTestHistoryHtmlReport.cs new file mode 100755 index 0000000..6d155fd --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Reports/UnitTestHistoryHtmlReport.cs @@ -0,0 +1,47 @@ +using System; +using System.IO; +using System.Xml; +using System.Xml.XPath; +using System.Xml.Xsl; +using System.ComponentModel; +using QuickGraph.Unit.Core; + +namespace QuickGraph.Unit.Reports +{ + public sealed class UnitTestHistoryHtmlReport : XslReportBase + { + private string entryAssemblyName; + + public UnitTestHistoryHtmlReport(IContainer container) + :base(container,"html") + {} + + public string EntryAssemblyName + { + get { return this.entryAssemblyName; } + set { this.entryAssemblyName = value; } + } + + protected override void GenerateXml(XmlTextWriter writer) + { + QuickGraph.Operations.OperationsResourceManager.DumpResources( + Path.GetDirectoryName(this.OutputFileName) + ); + UnitResourceManager.DumpResources( + Path.GetDirectoryName(this.OutputFileName) + ); + ReportHistory history = new ReportHistory( + this.OutputFolderName, this.EntryAssemblyName); + XmlDocument doc = history.LoadReportHistory(); + doc.Save(writer); + } + + protected override void TransformXml(XPathDocument document, XmlTextWriter writer) + { + XsltArgumentList args = new XsltArgumentList(); + + UnitResourceManager.HtmlHistoryReport.Transform(document, args, writer); + writer.Close(); + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Reports/UnitTestHistoryHtmlReport.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Reports/UnitTestHistoryHtmlReport.cs.meta new file mode 100644 index 0000000..69aa35e --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Reports/UnitTestHistoryHtmlReport.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 49846ad7dc5de427691ccb8a01f4b978 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Reports/UnitTestHtmlReport.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Reports/UnitTestHtmlReport.cs new file mode 100755 index 0000000..a1a108a --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Reports/UnitTestHtmlReport.cs @@ -0,0 +1,106 @@ +using System; +using System.IO; +using System.Xml; +using System.Xml.Xsl; +using System.Xml.XPath; +using System.Collections.Generic; +using System.ComponentModel; +using QuickGraph.Unit.Serialization; +using QuickGraph.Unit.Listeners; +using QuickGraph.Unit.Core; + +namespace QuickGraph.Unit.Reports +{ + public sealed class UnitTestHtmlReport : XslReportBase + { + private XmlTestListener testListener = new XmlTestListener(); + private string entryAssemblyName; + private bool generateFixtureInSeparateFile = false; + private bool showFixturesSummary = true; + + public UnitTestHtmlReport(IContainer container) + :base(container,"html") + {} + + public bool GenerateFixtureInSeparateFile + { + get { return this.generateFixtureInSeparateFile; } + set { this.generateFixtureInSeparateFile = value; } + } + + public bool ShowFixturesSummary + { + get { return this.showFixturesSummary; } + set { this.showFixturesSummary = value; } + } + + public string EntryAssemblyName + { + get { return this.entryAssemblyName; } + set { this.entryAssemblyName = value; } + } + + public XmlTestListener TestListener + { + get { return this.testListener; } + set { this.testListener = value; } + } + + protected override void GenerateXml(XmlTextWriter writer) + { + QuickGraph.Operations.OperationsResourceManager.DumpResources(Path.GetDirectoryName(this.OutputFileName)); + UnitResourceManager.DumpResources(Path.GetDirectoryName(this.OutputFileName)); + UnitSerializer.TestBatchSerializer.Serialize( + writer, + this.TestListener.TestBatch); + } + + protected override void TransformXml(XPathDocument document, XmlTextWriter writer) + { + XsltArgumentList args = new XsltArgumentList(); + args.AddParam("separate-fixtures", "", (this.GenerateFixtureInSeparateFile) ? 1 : 0); + args.AddParam("show-fixtures-summary", "", (this.ShowFixturesSummary) ? 1 : 0); + args.AddParam("creation-time", "", this.CreationTime.ToString("u")); + + if (this.GenerateFixtureInSeparateFile) + this.GenerateFixtureReports(document, args); + + UnitResourceManager.HtmlReport.Transform(document, args, writer); + writer.Close(); + + } + + private void GenerateFixtureReports(XPathDocument document, XsltArgumentList args) + { + Console.WriteLine("Generating fixture reports"); + XPathNavigator navi = document.CreateNavigator(); + foreach (XPathNavigator node in navi.Select("//Fixture")) + { + Console.Write('.'); + string fileName = string.Format( + "{0}_{1}.html", + this.EntryAssemblyName.Replace('.', '_'), + node.GetAttribute("Name", "").Replace('.', '_') + ); + fileName = ReportPath.EscapeFileName(fileName); + fileName = Path.Combine(this.OutputFolderName, fileName); + + System.Runtime.CompilerServices.RuntimeHelpers.PrepareConstrainedRegions(); + try + { + using (StreamWriter fixtureWriter = new StreamWriter(fileName)) + { + UnitResourceManager.HtmlFixtureReport.Transform(node, args, fixtureWriter); + } + } + catch (Exception ex) + { + Console.WriteLine("Failed generating {0}", fileName); + Console.WriteLine(ex.Message); + } + } + + Console.WriteLine(); + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Reports/UnitTestHtmlReport.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Reports/UnitTestHtmlReport.cs.meta new file mode 100644 index 0000000..34c11f8 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Reports/UnitTestHtmlReport.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: a9bbae41db87d4569958eca396cca9b9 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Reports/XslReportBase.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Reports/XslReportBase.cs new file mode 100755 index 0000000..33a4e0a --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Reports/XslReportBase.cs @@ -0,0 +1,53 @@ +using System; +using System.IO; +using System.Diagnostics; +using System.ComponentModel; +using System.Xml; +using System.Xml.XPath; + +namespace QuickGraph.Unit.Reports +{ + public abstract class XslReportBase : FileReportBase + { + private string outputXmlFileName; + + public XslReportBase( + IContainer container, + string defaultFileExtension) + :base(container,defaultFileExtension) + {} + + public string OutputXmlFileName + { + get { return this.outputXmlFileName; } + } + + public override void SetOutputFileName(string outputFileName) + { + base.SetOutputFileName(outputFileName); + this.outputXmlFileName = this.OutputFileName + ".xml"; + } + + public sealed override void Generate(TextWriter writer) + { + using (StreamWriter xwriter = new StreamWriter(this.OutputXmlFileName)) + { + using (XmlTextWriter xxwriter = new XmlTextWriter(xwriter)) + { + xxwriter.Formatting = Formatting.Indented; + GenerateXml(xxwriter); + } + } + + XPathDocument doc = new XPathDocument(this.OutputXmlFileName); + using (XmlTextWriter xwriter = new XmlTextWriter(writer)) + { + xwriter.Formatting = Formatting.Indented; + TransformXml(doc,xwriter); + } + } + + protected abstract void GenerateXml(XmlTextWriter writer); + protected abstract void TransformXml(XPathDocument document, XmlTextWriter writer); + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Reports/XslReportBase.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Reports/XslReportBase.cs.meta new file mode 100644 index 0000000..32259ca --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Reports/XslReportBase.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 7e2e3021a03b4468cbcf64a2a4c91dbe +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/RollbackAttribute.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/RollbackAttribute.cs new file mode 100755 index 0000000..361ab64 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/RollbackAttribute.cs @@ -0,0 +1,30 @@ +using System; +using System.Transactions; +using QuickGraph.Unit.Core; + +namespace QuickGraph.Unit +{ + [AttributeUsage(AttributeTargets.Method,AllowMultiple=false, Inherited=true)] + public sealed class RollbackAttribute : TestDecoratorAttributeBase + { + public override ITestCase Decorate(ITestCase testCase) + { + return new RolledbackTestCase(testCase); + } + + private sealed class RolledbackTestCase : DecoratorTestCaseBase + { + public RolledbackTestCase(ITestCase testCase) + :base(testCase) + {} + + public override void Run(Object fixture) + { + using (TransactionScope transactionScope = new TransactionScope()) + { + this.TestCase.Run(fixture); + } + } + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/RollbackAttribute.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/RollbackAttribute.cs.meta new file mode 100644 index 0000000..d43e274 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/RollbackAttribute.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: af958a6e9c3634c4d984e922c695fe55 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/RowTestAttribute.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/RowTestAttribute.cs new file mode 100755 index 0000000..66c7bb5 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/RowTestAttribute.cs @@ -0,0 +1,75 @@ +using System; +using System.Collections.Generic; +using System.Reflection; +using QuickGraph.Unit.Core; + +namespace QuickGraph.Unit +{ + [AttributeUsage(AttributeTargets.Method, AllowMultiple=true, Inherited=true)] + public sealed class RowAttribute : Attribute + { + private object[] arguments; + + public RowAttribute(object a1) + { + this.arguments = new object[] { a1 }; + } + public RowAttribute(object a1, object a2) + { + this.arguments = new object[] { a1 , a2}; + } + public RowAttribute(object a1, object a2, object a3) + { + this.arguments = new object[] { a1, a2, a3 }; + } + public RowAttribute(object a1, object a2, object a3, object a4) + { + this.arguments = new object[] { a1, a2, a3,a4 }; + } + public RowAttribute(object a1, object a2, object a3, object a4, object a5) + { + this.arguments = new object[] { a1, a2, a3, a4,a5 }; + } + public RowAttribute(object a1, object a2, object a3, object a4, object a5, object a6) + { + this.arguments = new object[] { a1, a2, a3, a4, a5,a6 }; + } + public RowAttribute(object a1, object a2, object a3, object a4, object a5, object a6, object a7) + { + this.arguments = new object[] { a1, a2, a3, a4, a5, a6,a7 }; + } + public RowAttribute(object a1, object a2, object a3, object a4, object a5, object a6, object a7, object a8) + { + this.arguments = new object[] { a1, a2, a3, a4, a5, a6, a7, a8 }; + } + + public object[] GetArguments() + { + return arguments; + } + } + + [AttributeUsage(AttributeTargets.Method, AllowMultiple=false, Inherited=true)] + public sealed class RowTestAttribute : TestAttributeBase + { + public override IEnumerable CreateTests(IFixture fixture, System.Reflection.MethodInfo method) + { + foreach (RowAttribute rowAttribute in method.GetCustomAttributes(typeof(RowAttribute), true)) + { + yield return new RowTestCase(fixture.Name, method, rowAttribute); + } + } + + public sealed class RowTestCase : MethodTestCase + { + public RowTestCase(string fixtureName, MethodInfo method, RowAttribute row) + :base(fixtureName, method) + { + foreach (object parameter in row.GetArguments()) + { + this.Parameters.Add(new TestCaseParameter(parameter)); + } + } + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/RowTestAttribute.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/RowTestAttribute.cs.meta new file mode 100644 index 0000000..b50b8e3 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/RowTestAttribute.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 184e8e3faecb54bb999dd757f4a25c68 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Serialization.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Serialization.meta new file mode 100644 index 0000000..9a49124 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Serialization.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: f6b7c621e47574d878eee3234c899fac +folderAsset: yes +DefaultImporter: + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Serialization/UnitSerializer.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Serialization/UnitSerializer.cs new file mode 100755 index 0000000..022dd28 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Serialization/UnitSerializer.cs @@ -0,0 +1,71 @@ +using System; +using System.Xml.Serialization; +using System.IO; +using System.Xml; +using System.Threading; + +namespace QuickGraph.Unit.Serialization +{ + public static class UnitSerializer + { + private static volatile object syncRoot = new object(); + private static XmlSerializer testBatchSerializer = null; + + public static object SyncRoot + { + get { return syncRoot; } + } + + public static string XmlSerializerEscapeWorkAround(string s) + { + char[] array = s.ToCharArray(); + for (int i = 0; i < s.Length; ++i) + { + //#x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF] + char c = array[i]; + if ( + !( + (c>=0x20 && c<=0xD7FF) + ||(c>=0xE000 && c<=0xFFFD) + || c == 0x9 || c==0xA || c==0xD + ) + ) + array[i] = 'x'; + } + return new string(array); + } + + public static XmlSerializer TestBatchSerializer + { + get + { + lock (SyncRoot) + { + if (testBatchSerializer == null) + testBatchSerializer = new XmlSerializer(typeof(XmlTestBatch)); + return testBatchSerializer; + } + } + } + + public static void Serialize(XmlTestBatch instance, string outputFileName) + { + using (StreamWriter sw = new StreamWriter(outputFileName)) + { + using (XmlTextWriter xw = new XmlTextWriter(sw)) + { + xw.Formatting = Formatting.Indented; + TestBatchSerializer.Serialize(xw, instance); + } + } + } + + public static XmlTestBatch Deserialize(string fileName) + { + using (StreamReader reader = new StreamReader(fileName)) + { + return (XmlTestBatch)TestBatchSerializer.Deserialize(reader); + } + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Serialization/UnitSerializer.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Serialization/UnitSerializer.cs.meta new file mode 100644 index 0000000..ff84919 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Serialization/UnitSerializer.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 3e65bfda9be7e415a882cbdd5448194b +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Serialization/XmlCounter.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Serialization/XmlCounter.cs new file mode 100755 index 0000000..d7fb626 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Serialization/XmlCounter.cs @@ -0,0 +1,83 @@ +using System; +using System.Xml.Serialization; + +namespace QuickGraph.Unit.Serialization +{ + [Serializable] + public sealed class XmlCounter + { + private int totalCount = 0; + private int successCount = 0; + private int failureCount = 0; + private int ignoreCount = 0; + private int notRunCount = 0; + + public XmlCounter() + { } + + public static XmlCounter Add(XmlCounter left, XmlCounter right) + { + XmlCounter counter = new XmlCounter(); + counter.TotalCount = left.TotalCount + right.TotalCount; + counter.SuccessCount = left.SuccessCount + right.SuccessCount; + counter.FailureCount = left.FailureCount + right.FailureCount; + counter.IgnoreCount = left.IgnoreCount + right.IgnoreCount; + counter.notRunCount = left.notRunCount + right.notRunCount; + return counter; + } + + public void Update() + { + this.totalCount = this.successCount + this.ignoreCount + this.failureCount + this.notRunCount; + } + + public static XmlCounter operator +(XmlCounter left, XmlCounter right) + { + return Add(left, right); + } + + [XmlAttribute] + public int TotalCount + { + get { return this.totalCount; } + set { this.totalCount = value; } + } + + [XmlAttribute] + public int SuccessCount + { + get { return this.successCount; } + set { this.successCount = value; } + } + + [XmlAttribute] + public int FailureCount + { + get { return this.failureCount; } + set { this.failureCount = value; } + } + + [XmlAttribute] + public int IgnoreCount + { + get { return this.ignoreCount; } + set { this.ignoreCount = value; } + } + + [XmlAttribute] + public int NotRunCount + { + get { return this.notRunCount; } + set { this.notRunCount = value; } + } + + public override string ToString() + { + return String.Format("{0} tests, {1} success, {2} failures, {3} ignored", + this.TotalCount, + this.SuccessCount, + this.FailureCount, + this.IgnoreCount); + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Serialization/XmlCounter.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Serialization/XmlCounter.cs.meta new file mode 100644 index 0000000..b55f57c --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Serialization/XmlCounter.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: c1101705f386846f4a65c0e33beaef39 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Serialization/XmlException.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Serialization/XmlException.cs new file mode 100755 index 0000000..03681d0 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Serialization/XmlException.cs @@ -0,0 +1,118 @@ +using System; +using System.Collections.Generic; +using System.Xml.Serialization; + +namespace QuickGraph.Unit.Serialization +{ + [Serializable] + public sealed class XmlException + { + private string exceptionType; + private string message; + private string stackTrace; + private string source; + private PropertyCollection properties = new PropertyCollection(); + private XmlException innerException = null; + + public XmlException() + {} + + public static XmlException FromException(Exception exception) + { + if (exception == null) + throw new ArgumentNullException("exception"); + if (exception is System.Reflection.TargetInvocationException) + return FromException(exception.InnerException); + + XmlException xex = new XmlException(); + xex.ExceptionType = exception.GetType().FullName; + xex.Message = UnitSerializer.XmlSerializerEscapeWorkAround(exception.Message); + xex.StackTrace = exception.StackTrace; + xex.Source = exception.Source; + if (exception.InnerException!=null) + xex.InnerException = FromException(exception.InnerException); + + foreach (System.Collections.DictionaryEntry de in exception.Data) + { + xex.Properties.Add(de); + } + + return xex; + } + + [XmlAttribute] + public string Source + { + get { return this.source; } + set { this.source = value; } + } + + [XmlAttribute] + public string ExceptionType + { + get { return this.exceptionType; } + set { this.exceptionType = value; } + } + + [XmlAttribute] + public string Message + { + get { return this.message; } + set { this.message = value; } + } + + [XmlElement] + public string StackTrace + { + get { return this.stackTrace; } + set { this.stackTrace = value; } + } + + [XmlElement] + public XmlException InnerException + { + get { return this.innerException; } + set { this.innerException = value; } + } + + [XmlArray("Properties")] + [XmlArrayItem(typeof(XmlException.Property))] + public PropertyCollection Properties + { + get { return this.properties;} + } + + [Serializable] + public sealed class Property + { + private string name; + private string value; + + [XmlAttribute] + public string Name + { + get { return this.name; } + set { this.name = value; } + } + + [XmlAttribute] + public string Value + { + get { return this.value; } + set { this.value = value; } + } + } + + [Serializable] + public sealed class PropertyCollection : List + { + public void Add(System.Collections.DictionaryEntry de) + { + Property p = new Property(); + p.Name = String.Format("{0}",de.Key); + p.Value = String.Format("{0}",de.Value); + this.Add(p); + } + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Serialization/XmlException.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Serialization/XmlException.cs.meta new file mode 100644 index 0000000..4f77d11 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Serialization/XmlException.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: fc9fe251544f54d6bbcceca75f2004a7 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Serialization/XmlFixture.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Serialization/XmlFixture.cs new file mode 100755 index 0000000..4764575 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Serialization/XmlFixture.cs @@ -0,0 +1,146 @@ +using System; +using System.Xml.Serialization; +using System.Threading; +using QuickGraph.Unit.Core; + +namespace QuickGraph.Unit.Serialization +{ + [Serializable] + public sealed class XmlFixture + { + private string id; + private string name; + private string description; + private string categories; + private double duration=0; + private ApartmentState apartment = ApartmentState.Unknown; + private int timeOut = 1; + private XmlCounter counter = new XmlCounter(); + private XmlResult fixtureSetUp = null; + private XmlResult fixtureTearDown = null; + private XmlTestCaseCollection testCases = new XmlTestCaseCollection(); + private int testCaseCount; + + public XmlFixture() + { } + + internal XmlFixture(IFixture fixture, int testCaseCount, string categories, int fixtureIndex) + { + this.Name = fixture.Name; + this.testCaseCount = testCaseCount; + this.Categories = categories; + this.TimeOut = fixture.TimeOut; + this.Apartment = fixture.Apartment; + this.Description = fixture.Description; + this.ID = + String.Format("fix{0}", fixtureIndex); + } + + [XmlAttribute("id")] + public string ID + { + get { return this.id; } + set { this.id = value; } + } + + [XmlElement] + public XmlCounter Counter + { + get { return this.counter; } + set { this.counter = value; } + } + + [XmlAttribute] + public string Name + { + get { return this.name; } + set { this.name = value; } + } + + [XmlAttribute] + public ApartmentState Apartment + { + get { return this.apartment; } + set { this.apartment = value; } + } + + [XmlAttribute] + public int TimeOut + { + get { return this.timeOut; } + set { this.timeOut = value; } + } + + [XmlAttribute] + public string Description + { + get { return this.description; } + set { this.description = value; } + } + + [XmlAttribute] + public string Categories + { + get { return this.categories; } + set { this.categories = value; } + } + + [XmlAttribute] + public double Duration + { + get { return this.duration; } + set { this.duration=value; } + } + + [XmlElement] + public XmlResult FixtureSetUp + { + get { return this.fixtureSetUp; } + set { this.fixtureSetUp = value; } + } + + [XmlElement] + public XmlResult FixtureTearDown + { + get { return this.fixtureTearDown; } + set { this.fixtureTearDown = value; } + } + + [XmlArray("TestCases")] + [XmlArrayItem("TestCase",typeof(XmlTestCase))] + public XmlTestCaseCollection TestCases + { + get { return this.testCases; } + } + + public void UpdateCounter() + { + this.counter = new XmlCounter(); + // the fixture setup/teardown run and failed ? + if ((this.FixtureSetUp != null && this.FixtureSetUp.State != TestState.Success) + || (this.FixtureTearDown != null && this.FixtureTearDown.State != TestState.Success) + ) + { + this.counter.FailureCount = this.testCaseCount; + } + else + { + foreach (XmlTestCase test in this.TestCases) + { + switch (test.State) + { + case TestState.Success: this.counter.SuccessCount++; + break; + case TestState.Failure: this.counter.FailureCount++; + break; + case TestState.Ignore: this.counter.IgnoreCount++; + break; + case TestState.NotRun: this.counter.NotRunCount++; + break; + } + } + } + this.counter.Update(); + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Serialization/XmlFixture.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Serialization/XmlFixture.cs.meta new file mode 100644 index 0000000..5a3cd37 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Serialization/XmlFixture.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 640479c625af14dd4b53e1051b75f3bb +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Serialization/XmlFixtureCollection.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Serialization/XmlFixtureCollection.cs new file mode 100755 index 0000000..6becf99 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Serialization/XmlFixtureCollection.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Xml.Serialization; + +namespace QuickGraph.Unit.Serialization +{ + [Serializable] + public sealed class XmlFixtureCollection : List + { + private XmlCounter counter = new XmlCounter(); + + [XmlElement] + public XmlCounter Counter + { + get { return this.counter; } + set { this.counter = value; } + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Serialization/XmlFixtureCollection.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Serialization/XmlFixtureCollection.cs.meta new file mode 100644 index 0000000..fd56e5c --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Serialization/XmlFixtureCollection.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 048c4cdbba9664c26a8e1acde3289999 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Serialization/XmlLog.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Serialization/XmlLog.cs new file mode 100755 index 0000000..ab149ad --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Serialization/XmlLog.cs @@ -0,0 +1,18 @@ +using System; +using System.Xml.Serialization; + +namespace QuickGraph.Unit.Serialization +{ + [Serializable] + public sealed class XmlLog + { + private XmlLogEntryCollection logEntries = new XmlLogEntryCollection(); + + [XmlArray] + [XmlArrayItem("LogEntry")] + public XmlLogEntryCollection LogEntries + { + get { return this.logEntries; } + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Serialization/XmlLog.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Serialization/XmlLog.cs.meta new file mode 100644 index 0000000..9817088 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Serialization/XmlLog.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 9b475be0b4be34f7aa373ce21102c33c +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Serialization/XmlLogEntry.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Serialization/XmlLogEntry.cs new file mode 100755 index 0000000..3f3a7c3 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Serialization/XmlLogEntry.cs @@ -0,0 +1,63 @@ +using System; +using System.Xml.Serialization; + +namespace QuickGraph.Unit.Serialization +{ + [Serializable] + public sealed class XmlLogEntry + { + private LogLevel level = LogLevel.Message; + private DateTime time; + private string message; + private XmlException exception; + + public XmlLogEntry() + { + this.time = DateTime.Now; + } + + public XmlLogEntry( + LogLevel level, + string message + ) + { + this.level = level; + this.message = message; + } + + public XmlLogEntry(Exception ex) + { + this.level = LogLevel.Error; + this.message = ex.Message; + this.exception = XmlException.FromException(ex); + } + + [XmlAttribute] + public LogLevel Level + { + get { return this.level; } + set { this.level = value; } + } + + [XmlAttribute] + public DateTime Time + { + get { return this.time; } + set { this.time = value; } + } + + [XmlAttribute] + public string Message + { + get { return this.message; } + set { this.message = value; } + } + + [XmlElement] + public XmlException Exception + { + get { return this.exception; } + set { this.exception = value; } + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Serialization/XmlLogEntry.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Serialization/XmlLogEntry.cs.meta new file mode 100644 index 0000000..340e487 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Serialization/XmlLogEntry.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: f397b40a3d98d412dad8c07cc44f96e4 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Serialization/XmlLogEntryCollection.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Serialization/XmlLogEntryCollection.cs new file mode 100755 index 0000000..6274aa4 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Serialization/XmlLogEntryCollection.cs @@ -0,0 +1,10 @@ +using System; +using System.Collections.Generic; + +namespace QuickGraph.Unit.Serialization +{ + [Serializable] + public sealed class XmlLogEntryCollection : List + { + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Serialization/XmlLogEntryCollection.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Serialization/XmlLogEntryCollection.cs.meta new file mode 100644 index 0000000..c62a2ae --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Serialization/XmlLogEntryCollection.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 96a7205423b644cbfbdf2010e37bd355 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Serialization/XmlMachine.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Serialization/XmlMachine.cs new file mode 100755 index 0000000..df10036 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Serialization/XmlMachine.cs @@ -0,0 +1,97 @@ +using System; +using System.Xml.Serialization; +using System.Diagnostics; +using System.Collections.Generic; + +namespace QuickGraph.Unit.Serialization +{ + [Serializable] + public sealed class XmlMachine + { + private string machineName; + private string frameworkVersion; + private string operatingSystem; + private EnvironmentVariableCollection environmentVariables = new EnvironmentVariableCollection(); + + public static XmlMachine Create() + { + XmlMachine machine = new XmlMachine(); + + machine.MachineName = Environment.MachineName; + machine.FrameworkVersion = Environment.Version.ToString(); + machine.OperatingSystem = Environment.OSVersion.VersionString; + + foreach (System.Collections.DictionaryEntry de in Environment.GetEnvironmentVariables()) + { + machine.EnvironmentVariables.Add( + new EnvironmentVariable(String.Format("{0}",de.Key), String.Format("{0}",de.Value)) + ); + } + + return machine; + } + + [XmlAttribute] + public string MachineName + { + get { return this.machineName; } + set { this.machineName = value; } + } + + [XmlAttribute] + public string FrameworkVersion + { + get { return this.frameworkVersion; } + set { this.frameworkVersion = value; } + } + + [XmlAttribute] + public string OperatingSystem + { + get { return this.operatingSystem; } + set { this.operatingSystem = value; } + } + + [XmlArray("EnvironmentVariables")] + [XmlArrayItem("EnvironmentVariable")] + public EnvironmentVariableCollection EnvironmentVariables + { + get { return this.environmentVariables; } + } + + [Serializable] + public sealed class EnvironmentVariableCollection : List + {} + + [Serializable] + public sealed class EnvironmentVariable + { + private string name; + private string value; + + public EnvironmentVariable() { } + public EnvironmentVariable( + string name, + string value + ) + { + this.name = name; + this.value = value; + } + + [XmlAttribute] + public string Name + { + get { return this.name; } + set { this.name = value; } + } + + [XmlAttribute] + public string Value + { + get { return this.value; } + set { this.value = value; } + } + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Serialization/XmlMachine.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Serialization/XmlMachine.cs.meta new file mode 100644 index 0000000..0f83792 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Serialization/XmlMachine.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: fe8cceaa6e700424d86babed4ceb6f4c +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Serialization/XmlMonitor.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Serialization/XmlMonitor.cs new file mode 100755 index 0000000..be8e287 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Serialization/XmlMonitor.cs @@ -0,0 +1,78 @@ +using System; +using System.IO; +using System.Xml.Serialization; +using QuickGraph.Unit.Monitoring; + +namespace QuickGraph.Unit.Serialization +{ + [Serializable] + public class XmlMonitor + { + private string consoleOut; + private string consoleError; + private string startTime; + private string endTime; + private double duration; + private XmlLog log = new XmlLog(); + + public XmlMonitor() + {} + + public XmlMonitor(TestMonitor monitor) + { + this.Update(monitor); + } + + public void Update(TestMonitor monitor) + { + this.consoleError = UnitSerializer.XmlSerializerEscapeWorkAround(monitor.Console.Error); + this.consoleOut = UnitSerializer.XmlSerializerEscapeWorkAround(monitor.Console.Out); + this.startTime = monitor.Timer.StartTime.ToString("u"); + this.endTime = monitor.Timer.EndTime.ToString("u"); + this.duration = monitor.Timer.Duration; + this.log = monitor.GetLog(); + } + + [XmlAttribute] + public string StartTime + { + get { return this.startTime; } + set { this.startTime = value; } + } + + [XmlAttribute] + public string EndTime + { + get { return this.endTime; } + set { this.endTime = value; } + } + + [XmlAttribute] + public double Duration + { + get { return this.duration; } + set { this.duration = value; } + } + + [XmlElement] + public XmlLog Log + { + get { return this.log; } + set { this.log = value; } + } + + [XmlElement] + public string ConsoleOut + { + get { return this.consoleOut; } + set { this.consoleOut = value; } + } + + [XmlElement] + public string ConsoleError + { + get { return this.consoleError; } + set { this.consoleError = value; } + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Serialization/XmlMonitor.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Serialization/XmlMonitor.cs.meta new file mode 100644 index 0000000..8d0de0c --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Serialization/XmlMonitor.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 23f6ab64aa054468297432ba4eef079b +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Serialization/XmlResult.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Serialization/XmlResult.cs new file mode 100755 index 0000000..9d01e33 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Serialization/XmlResult.cs @@ -0,0 +1,62 @@ +using System; +using System.IO; +using System.Xml.Serialization; +using QuickGraph.Unit.Monitoring; +using QuickGraph.Unit.Core; + +namespace QuickGraph.Unit.Serialization +{ + [Serializable] + public class XmlResult : XmlMonitor + { + private string id; + private TestState state = TestState.NotRun; + private XmlException exception = null; + + public XmlResult() + { } + + public XmlResult(Result result) + : base(result.Monitor) + { + this.Update(result); + } + + public void Update(Result result) + { + if (result == null) + throw new ArgumentNullException("result"); + this.state = result.State; + if (result.Exception != null) + this.exception = XmlException.FromException(result.Exception); + this.Update(result.Monitor); + } + + [XmlAttribute("id")] + public string ID + { + get { return this.id; } + set { this.id = value; } + } + + [XmlAttribute] + public TestState State + { + get + { + return this.state; + } + set + { + this.state = value; + } + } + + [XmlElement] + public XmlException Exception + { + get { return this.exception; } + set { this.exception = value; } + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Serialization/XmlResult.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Serialization/XmlResult.cs.meta new file mode 100644 index 0000000..6994fea --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Serialization/XmlResult.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 59b226c4fbecc4c889c24552d4729102 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Serialization/XmlTestAssembly.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Serialization/XmlTestAssembly.cs new file mode 100755 index 0000000..c9266d8 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Serialization/XmlTestAssembly.cs @@ -0,0 +1,116 @@ +using System; +using System.Collections.Generic; +using System.Xml.Serialization; +using System.Xml; +using System.Reflection; + +namespace QuickGraph.Unit.Serialization +{ + [Serializable] + public sealed class XmlTestAssembly + { + private XmlCounter counter = new XmlCounter(); + private XmlFixtureCollection fixtures = new XmlFixtureCollection(); + private XmlResult assemblySetUp = null; + private XmlResult assemblyTearDown = null; + private string assemblyName = null; + private string assemblyFullName = null; + private string assemblyLocation = null; + private DateTime startTime; + private DateTime endTime; + private double duration; + + public XmlTestAssembly() + {} + + public XmlTestAssembly(AssemblyName assemblyName, string location) + : this() + { + this.assemblyName = assemblyName.Name; + this.assemblyFullName = assemblyName.FullName; + this.assemblyLocation = location; + } + + [XmlAttribute] + public string AssemblyName + { + get { return this.assemblyName; } + set { this.assemblyName = value; } + } + + [XmlAttribute] + public string AssemblyFullName + { + get { return this.assemblyFullName; } + set { this.assemblyFullName = value; } + } + + [XmlAttribute] + public string AssemblyLocation + { + get { return this.assemblyLocation; } + set { this.assemblyLocation = value; } + } + + [XmlAttribute] + public DateTime StartTime + { + get { return this.startTime; } + set { this.startTime = value; } + } + + [XmlAttribute] + public DateTime EndTime + { + get { return this.endTime; } + set { this.endTime = value; } + } + + [XmlAttribute] + public double Duration + { + get { return this.duration; } + set { this.duration = value; } + } + + [XmlElement] + public XmlCounter Counter + { + get { return this.counter; } + set { this.counter = value; } + } + + [XmlElement] + public XmlResult AssemblySetUp + { + get { return this.assemblySetUp; } + set { this.assemblySetUp = value; } + } + + [XmlElement] + public XmlResult AssemblyTearDown + { + get { return this.assemblyTearDown; } + set { this.assemblyTearDown = value; } + } + + [XmlArray("Fixtures")] + [XmlArrayItem("Fixture")] + public XmlFixtureCollection Fixtures + { + get { return this.fixtures; } + } + + public void UpdateCounter() + { + this.counter = new XmlCounter(); + this.duration = 0; + foreach (XmlFixture fixture in this.Fixtures) + { + fixture.UpdateCounter(); + this.counter = this.counter + fixture.Counter; + this.duration += fixture.Duration; + } + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Serialization/XmlTestAssembly.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Serialization/XmlTestAssembly.cs.meta new file mode 100644 index 0000000..81378a5 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Serialization/XmlTestAssembly.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: fa419f592f7eb4df7bf9f48e1741db2b +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Serialization/XmlTestAssemblyCollection.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Serialization/XmlTestAssemblyCollection.cs new file mode 100755 index 0000000..bdaf53a --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Serialization/XmlTestAssemblyCollection.cs @@ -0,0 +1,9 @@ +using System; +using System.Collections.Generic; + +namespace QuickGraph.Unit.Serialization +{ + [Serializable] + public sealed class XmlTestAssemblyCollection : List + {} +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Serialization/XmlTestAssemblyCollection.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Serialization/XmlTestAssemblyCollection.cs.meta new file mode 100644 index 0000000..290d4b2 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Serialization/XmlTestAssemblyCollection.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e5885269221d247f38ab29bb42dbf467 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Serialization/XmlTestBatch.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Serialization/XmlTestBatch.cs new file mode 100755 index 0000000..beec230 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Serialization/XmlTestBatch.cs @@ -0,0 +1,129 @@ +using System; +using System.Collections.Generic; +using System.Xml.Serialization; +using System.Reflection; +using System.IO; + +namespace QuickGraph.Unit.Serialization +{ + [XmlRoot("TestBatch")] + [Serializable] + public sealed class XmlTestBatch + { + private XmlMachine machine; + private string entryAssemblyName = null; + private string entryAssemblyLocation = null; + private XmlCounter counter = new XmlCounter(); + private XmlTestAssemblyCollection testAssemblies = new XmlTestAssemblyCollection(); + private string commandLine = null; + private string startTime = DateTime.Now.ToString("u"); + private string endTime = DateTime.Now.ToString("u"); + private double duration; + private bool hasHistory = false; + private XmlLog log = new XmlLog(); + + public XmlTestBatch() + { } + + public void SetMainAssembly(Assembly entryAssembly) + { + this.machine = XmlMachine.Create(); + this.commandLine = Environment.CommandLine; + if (entryAssembly != null) + { + this.entryAssemblyLocation = Path.GetFileName(entryAssembly.Location); + this.entryAssemblyName = entryAssembly.GetName().Name; + } + } + + [XmlAttribute] + public bool HasHistory + { + get { return this.hasHistory; } + set { this.hasHistory = value; } + } + + [XmlAttribute] + public string CommandLine + { + get { return this.commandLine; } + set { this.commandLine = value; } + } + + [XmlAttribute] + public string EntryAssemblyLocation + { + get { return this.entryAssemblyLocation; } + set { this.entryAssemblyLocation = value; } + } + + [XmlAttribute] + public string EntryAssemblyName + { + get { return this.entryAssemblyName; } + set { this.entryAssemblyName = value; } + } + + [XmlAttribute] + public string StartTime + { + get { return this.startTime; } + set { this.startTime = value; } + } + + [XmlAttribute] + public string EndTime + { + get { return this.endTime; } + set { this.endTime = value; } + } + + [XmlAttribute] + public double Duration + { + get { return this.duration; } + set { this.duration = value; } + } + + [XmlElement] + public XmlCounter Counter + { + get { return this.counter; } + set { this.counter = value; } + } + + [XmlElement] + public XmlMachine Machine + { + get { return this.machine; } + set { this.machine = value; } + } + + [XmlElement] + public XmlLog Log + { + get { return this.log; } + set { this.log = value; } + } + + [XmlArray("TestAssemblies")] + [XmlArrayItem("TestAssembly")] + public XmlTestAssemblyCollection TestAssemblies + { + get { return this.testAssemblies; } + } + + public void UpdateCounter() + { + this.counter = new XmlCounter(); + this.duration = 0; + + foreach (XmlTestAssembly testAssembly in this.TestAssemblies) + { + testAssembly.UpdateCounter(); + this.counter = this.counter + testAssembly.Counter; + this.duration += testAssembly.Duration; + } + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Serialization/XmlTestBatch.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Serialization/XmlTestBatch.cs.meta new file mode 100644 index 0000000..cc0e20a --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Serialization/XmlTestBatch.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: f488747bf97bf449a83cb3608fcd8b84 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Serialization/XmlTestBatchSearcher.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Serialization/XmlTestBatchSearcher.cs new file mode 100755 index 0000000..bd2942d --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Serialization/XmlTestBatchSearcher.cs @@ -0,0 +1,77 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace QuickGraph.Unit.Serialization +{ + public sealed class XmlTestBatchSearcher + { + private XmlTestBatch testBatch; + private Dictionary testCases = new Dictionary(); + private Dictionary fixtures = new Dictionary(); + + public XmlTestBatchSearcher(XmlTestBatch testBatch) + { + this.testBatch = testBatch; + + foreach (XmlTestAssembly testAssembly in this.testBatch.TestAssemblies) + { + foreach (XmlFixture fixture in testAssembly.Fixtures) + { + this.fixtures[fixture.Name]=fixture; + foreach (XmlTestCase testCase in fixture.TestCases) + { + string testName = testCase.GetFullName(fixture); + if (this.testCases.ContainsKey(testName)) + Console.WriteLine("Warning: duplicate test {0}", testName); + else + this.testCases.Add(testName,testCase); + } + } + } + } + + public IDictionary TestCases + { + get { return this.testCases; } + } + + public IDictionary Fixtures + { + get { return this.fixtures; } + } + + public XmlFixture GetFixture(XmlFixture fixture) + { + if (fixture == null) + throw new ArgumentNullException("fixture"); + return GetFixture(fixture.Name); + } + + public XmlFixture GetFixture(string fixtureName) + { + XmlFixture tc = null; + this.fixtures.TryGetValue(fixtureName, out tc); + return tc; + } + + public XmlTestCase GetTestCase(string fixtureName, string testCaseName) + { + XmlTestCase tc = null; + this.testCases.TryGetValue( + XmlTestCase.GetTestCaseFullName(fixtureName,testCaseName), + out tc); + return tc; + } + + public XmlTestCase GetTestCase(XmlFixture fixture, XmlTestCase testCase) + { + if (fixture == null) + throw new ArgumentNullException("fixture"); + if (testCase == null) + throw new ArgumentNullException("testCase"); + + return GetTestCase(fixture.Name, testCase.Name); + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Serialization/XmlTestBatchSearcher.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Serialization/XmlTestBatchSearcher.cs.meta new file mode 100644 index 0000000..8446710 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Serialization/XmlTestBatchSearcher.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: a5e3a4d6fffac4fc8ae9b9c8d3349e8c +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Serialization/XmlTestCase.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Serialization/XmlTestCase.cs new file mode 100755 index 0000000..06a26e5 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Serialization/XmlTestCase.cs @@ -0,0 +1,140 @@ +using System; +using System.IO; +using System.Xml.Serialization; +using QuickGraph.Unit.Monitoring; +using QuickGraph.Unit.Core; + +namespace QuickGraph.Unit.Serialization +{ + [Serializable] + public sealed class XmlTestCase + { + private string id; + private TestState state = TestState.NotRun; + private string name; + private double duration=0; + private XmlResult setUp = null; + private XmlResult tearDown = null; + private XmlResult test = null; + private XmlTestHistory history = XmlTestHistory.NoChange; + + public XmlTestCase() + { } + + public XmlTestCase(string id,string name) + { + this.id = id; + this.name = name; + } + + [XmlAttribute("id")] + public string ID + { + get { return this.id; } + set { this.id = value; } + } + + [XmlAttribute] + public string Name + { + get { return this.name; } + set { this.name = value; } + } + + public static string GetTestCaseFullName(string fixtureName, string testName) + { + return string.Format("{0}.{1}", fixtureName, testName); + } + public string GetFullName(XmlFixture fixture) + { + return GetTestCaseFullName(fixture.Name, this.Name); + } + + [XmlAttribute] + public double Duration + { + get { return this.duration; } + set { this.duration = value; } + } + + [XmlAttribute] + public XmlTestHistory History + { + get { return this.history; } + set + { + this.history = value; + } + } + + [XmlElement] + public XmlResult SetUp + { + get { return this.setUp; } + set + { + this.setUp = value; + this.Update(); + } + } + + [XmlElement] + public XmlResult TearDown + { + get { return this.tearDown; } + set + { + this.tearDown=value; + this.Update(); + } + } + + [XmlElement] + public XmlResult Test + { + get { return this.test; } + set + { + this.test = value; + this.Update(); + } + } + + [XmlAttribute] + public TestState State + { + get { return this.state; } + set { this.state = value; } + } + + public void Update() + { + this.duration = 0; + if (this.SetUp != null) + { + this.state = MaxState(this.state, this.SetUp.State); + this.duration += this.SetUp.Duration; + } + + if (this.Test != null) + { + this.state = MaxState(this.state, this.Test.State); + this.duration += this.Test.Duration; + } + + if (this.TearDown != null) + { + this.state = MaxState(this.state, this.TearDown.State); + this.duration += this.TearDown.Duration; + } + } + + private static TestState MaxState(TestState left, TestState right) + { + if ((short)left > (short)right) + return left; + else + return right; + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Serialization/XmlTestCase.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Serialization/XmlTestCase.cs.meta new file mode 100644 index 0000000..a5063c0 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Serialization/XmlTestCase.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 5be67a8a8967c41d7ade0fabaf1ca757 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Serialization/XmlTestCaseCollection.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Serialization/XmlTestCaseCollection.cs new file mode 100755 index 0000000..edcc545 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Serialization/XmlTestCaseCollection.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; + +namespace QuickGraph.Unit.Serialization +{ + [Serializable] + public sealed class XmlTestCaseCollection : List + { + public XmlTestCaseCollection() { } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Serialization/XmlTestCaseCollection.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Serialization/XmlTestCaseCollection.cs.meta new file mode 100644 index 0000000..999cbf9 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Serialization/XmlTestCaseCollection.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 152293c88986845e897031013d7a56a9 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Serialization/XmlTestHistory.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Serialization/XmlTestHistory.cs new file mode 100755 index 0000000..b52de99 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Serialization/XmlTestHistory.cs @@ -0,0 +1,12 @@ +using System; + +namespace QuickGraph.Unit +{ + public enum XmlTestHistory + { + NoChange, + New, + Fixed, + Failure + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Serialization/XmlTestHistory.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Serialization/XmlTestHistory.cs.meta new file mode 100644 index 0000000..3093ae1 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/Serialization/XmlTestHistory.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 41700096ec8374713a6639e974c4d692 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/SerializationAssert.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/SerializationAssert.cs new file mode 100755 index 0000000..4316755 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/SerializationAssert.cs @@ -0,0 +1,23 @@ +using System; +using System.Runtime.CompilerServices; +using System.Collections.Generic; +using System.Xml.Serialization; +using QuickGraph.Unit.Core; + +namespace QuickGraph.Unit +{ + public static class SerializationAssert + { + public static void IsSerializable(Type type) + { + SerializableAttribute attribute = ReflectionHelper.GetAttribute(type); + Assert.IsNotNull(attribute, + "{0} is not tagged with [SerializableAttribute]", type); + } + + public static void IsXmlSerializable(Type type) + { + new XmlSerializer(type); + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/SerializationAssert.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/SerializationAssert.cs.meta new file mode 100644 index 0000000..43a7d23 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/SerializationAssert.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 049d15a0e5f4a4809bc28b594cfa58ab +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/SetEnvironmentVariableAttribute.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/SetEnvironmentVariableAttribute.cs new file mode 100755 index 0000000..261a85a --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/SetEnvironmentVariableAttribute.cs @@ -0,0 +1,70 @@ +using System; +using QuickGraph.Unit.Core; + +namespace QuickGraph.Unit +{ + [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple=true, Inherited=true)] + public sealed class SetEnvironmentVariableAttribute : TestDecoratorAttributeBase + { + private string name; + private string value; + + public SetEnvironmentVariableAttribute( + string name, + string value) + { + if (string.IsNullOrEmpty(name)) + throw new ArgumentNullException("name"); + this.name = name; + this.value = value; + } + + public string Name + { + get { return this.name; } + } + + public string Value + { + get { return this.value; } + } + + public override ITestCase Decorate(ITestCase test) + { + return new SetEnvironmentVariableTestCase(test, this); + } + + private sealed class SetEnvironmentVariableTestCase : TypeDecoratorTestCaseBase + { + public SetEnvironmentVariableTestCase( + ITestCase testCase, + SetEnvironmentVariableAttribute attribute) + :base(testCase,attribute) + {} + + public override void Run(object fixture) + { + string value = null; + System.Runtime.CompilerServices.RuntimeHelpers.PrepareConstrainedRegions(); + try + { + value = Environment.GetEnvironmentVariable(this.Attribute.Name); + Console.WriteLine("Setting {0}={1}", + this.Attribute.Name, + this.Attribute.Value); + Environment.SetEnvironmentVariable( + this.Attribute.Name, + this.Attribute.Name); + + this.TestCase.Run(fixture); + } + finally + { + Environment.SetEnvironmentVariable( + this.Attribute.Name, + value); + } + } + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/SetEnvironmentVariableAttribute.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/SetEnvironmentVariableAttribute.cs.meta new file mode 100644 index 0000000..b4dbfab --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/SetEnvironmentVariableAttribute.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 5c60f437f6f7a414c9e4481ab0ad331e +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/SetUpAttribute.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/SetUpAttribute.cs new file mode 100755 index 0000000..05b358e --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/SetUpAttribute.cs @@ -0,0 +1,9 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace QuickGraph.Unit +{ + [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)] + public sealed class SetUpAttribute : Attribute { } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/SetUpAttribute.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/SetUpAttribute.cs.meta new file mode 100644 index 0000000..3a27f4c --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/SetUpAttribute.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: da16e55ef173a4159a966002da2f13b9 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/StreamAssert.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/StreamAssert.cs new file mode 100755 index 0000000..dbddea9 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/StreamAssert.cs @@ -0,0 +1,47 @@ +using System; +using System.IO; + +namespace QuickGraph.Unit +{ + public static class StreamAssert + { + public static void AreEqual(Stream leftStream, Stream rightStream) + { + Assert.AreEqual(leftStream.CanRead, rightStream.CanRead, + "CanRead property is not the same"); + Assert.AreEqual(leftStream.CanSeek, rightStream.CanSeek, + "CanSeek property is not the same"); + Assert.AreEqual(leftStream.CanTimeout, rightStream.CanTimeout, + "CanTimeOut property is not the same"); + Assert.AreEqual(leftStream.CanWrite, rightStream.CanWrite, + "CanWriteProperty is not the same"); + + if (leftStream.CanRead) + { + using (StreamReader leftReader = new StreamReader(leftStream)) + using (StreamReader rightReader = new StreamReader(rightStream)) + { + AreEqual(leftReader, rightReader); + } + } + } + + public static void AreEqual(StreamReader leftReader, StreamReader rightReader) + { + Assert.AreEqual(leftReader.EndOfStream, rightReader.EndOfStream, + "The end of the streams do not match"); + int lineNumber = 0; + while (!leftReader.EndOfStream) + { + string leftLine = leftReader.ReadLine(); + string rightLine = rightReader.ReadLine(); + Assert.AreEqual(leftLine, rightLine, + "Line {0} are different: [[{1}]], [[{2}]]", + lineNumber, leftLine, rightLine); + Assert.AreEqual(leftReader.EndOfStream, rightReader.EndOfStream, + "The end of the streams do not match"); + lineNumber++; + } + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/StreamAssert.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/StreamAssert.cs.meta new file mode 100644 index 0000000..6a2852c --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/StreamAssert.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 0caf9a2424e024fa3810026c88644cdf +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/StringAssert.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/StringAssert.cs new file mode 100755 index 0000000..034b8e2 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/StringAssert.cs @@ -0,0 +1,62 @@ +using System; +using System.Text; + +namespace QuickGraph.Unit +{ + public static class StringAssert + { + public static void AreEqual(string expected, string value, StringComparison comparaison) + { + Assert.IsTrue(expected.Equals(value, comparaison), + "[{0}]!=[{1}] using comparaison {2}", + expected, value, comparaison); + } + + public static void AreNotEqual(string expected, string value, StringComparison comparaison) + { + Assert.IsFalse(expected.Equals(value, comparaison), + "[{0}]==[{1}] using comparaison {2}", + expected, value, comparaison); + } + + public static void Contains(string value, string match) + { + Assert.IsTrue(value.Contains(match), + "[{0}] does not contain [{1}]", value, match); + } + + public static void EndsWith(string value, string match) + { + EndsWith(value, match, StringComparison.CurrentCulture); + } + + public static void EndsWith(string value, string match, StringComparison stringComparaison) + { + Assert.IsTrue(value.EndsWith(match, stringComparaison), + "[{0}] does not end with [{1}]", value, match); + } + + public static void StartsWith(string value, string match) + { + StartsWith(value, match, StringComparison.CurrentCulture); + } + + public static void StartsWith(string value, string match, StringComparison stringComparaison) + { + Assert.IsTrue(value.StartsWith(match,stringComparaison), + "[{0}] does not end with [{1}]", value, match); + } + + public static void IsNullOrEmpty(string value) + { + Assert.IsTrue(String.IsNullOrEmpty(value), + "[[{0}]] is not null or empty", value); + } + + public static void IsNotNullOrEmpty(string value) + { + Assert.IsFalse(String.IsNullOrEmpty(value), + "[[{0}]] is not null or empty", value); + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/StringAssert.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/StringAssert.cs.meta new file mode 100644 index 0000000..c196723 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/StringAssert.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e0612e511b73d4b2ab2535a01dcef258 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/TearDownAttribute.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/TearDownAttribute.cs new file mode 100755 index 0000000..6e9d66b --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/TearDownAttribute.cs @@ -0,0 +1,9 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace QuickGraph.Unit +{ + [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)] + public sealed class TearDownAttribute : Attribute { } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/TearDownAttribute.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/TearDownAttribute.cs.meta new file mode 100644 index 0000000..b799b2e --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/TearDownAttribute.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 9c8f222deaa8d42ea8742ebd8a65bc54 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/TestAttribute.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/TestAttribute.cs new file mode 100755 index 0000000..5039fe2 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/TestAttribute.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Reflection; +using QuickGraph.Unit.Core; + +namespace QuickGraph.Unit +{ + [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)] + public sealed class TestAttribute : TestAttributeBase + { + public override IEnumerable CreateTests( + IFixture fixture, + MethodInfo method + ) + { + yield return new MethodTestCase(fixture.Name, method); + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/TestAttribute.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/TestAttribute.cs.meta new file mode 100644 index 0000000..1928a1d --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/TestAttribute.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 1929ee663cab641aca49eabb0190d97c +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/TestCase.png b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/TestCase.png new file mode 100755 index 0000000..c1cdf1a Binary files /dev/null and b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/TestCase.png differ diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/TestCase.png.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/TestCase.png.meta new file mode 100644 index 0000000..683cd36 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/TestCase.png.meta @@ -0,0 +1,46 @@ +fileFormatVersion: 2 +guid: 4d46c6b5591fc43e696498030514f4ad +TextureImporter: + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + linearTexture: 0 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: -1 + mipBias: -1 + wrapMode: -1 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 0 + textureType: -1 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/TestCaseParameter.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/TestCaseParameter.cs new file mode 100755 index 0000000..3e2e5ab --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/TestCaseParameter.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.Generic; + +namespace QuickGraph.Unit +{ + public sealed class TestCaseParameter + { + private string name; + private object value; + + public TestCaseParameter(string name, object value) + { + this.name = name; + this.value = value; + } + + public TestCaseParameter(object value) + { + this.name = String.Format("{0}", value); + this.value = value; + } + + public string Name + { + get { return this.name; } + } + + public object Value + { + get { return this.value; } + } + + public override string ToString() + { + return this.Name; + } + + public static object[] GetValues(ICollection parameters) + { + object[] objs = new object[parameters.Count]; + int i =0; + foreach(TestCaseParameter parameter in parameters) + objs[i++] = parameter.Value; + return objs; + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/TestCaseParameter.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/TestCaseParameter.cs.meta new file mode 100644 index 0000000..ee15090 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/TestCaseParameter.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e9ae8708286e34e47a1fae7b3b1b1266 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/TestCaseParameterFactoryAttributeBase.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/TestCaseParameterFactoryAttributeBase.cs new file mode 100755 index 0000000..831bdd3 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/TestCaseParameterFactoryAttributeBase.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace QuickGraph.Unit +{ + public abstract class TestCaseParameterFactoryAttributeBase : Attribute, + ITestCaseParameterFactory + { + public abstract IEnumerable CreateInstances(Type targetType); + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/TestCaseParameterFactoryAttributeBase.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/TestCaseParameterFactoryAttributeBase.cs.meta new file mode 100644 index 0000000..c3d6247 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/TestCaseParameterFactoryAttributeBase.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: fde25a74f258745a69d7a64733bed3b0 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/TestConsole.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/TestConsole.cs new file mode 100755 index 0000000..a63cbc3 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/TestConsole.cs @@ -0,0 +1,57 @@ +using System; +using System.Collections.Generic; + +namespace QuickGraph.Unit +{ + public static class TestConsole + { + private static string reportDirectoryName = ""; + + public static string ReportDirectoryName + { + get { return reportDirectoryName; } + } + + internal static void SetReportDirectoryName(string directoryName) + { + reportDirectoryName = directoryName; + } + + public static void WriteImage(string url) + { + Console.WriteLine("[img src=\"{0}\" /]", url); + } + + public static void WriteUri(string uriString) + { + WriteUri(new Uri(System.IO.Path.GetFullPath(uriString))); + } + + public static void WriteUri(Uri uri) + { + Console.WriteLine(uri.AbsoluteUri); + } + + public static void WriteBold(string message) + { + Console.Write("**{0}**", message); + } + + public static void WriteBold(string format, params object[] args) + { + WriteBold(string.Format(format, args)); + } + + public static void WriteLineBold(string message) + { + WriteBold(message); + Console.WriteLine(); + } + + public static void WriteLineBold(string format, params object[] args) + { + WriteLineBold(string.Format(format, args)); + } + + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/TestConsole.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/TestConsole.cs.meta new file mode 100644 index 0000000..f83ffb7 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/TestConsole.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 69ec0be44fa0545fa8e9a84337bc8c85 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/TestFixtureAttribute.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/TestFixtureAttribute.cs new file mode 100755 index 0000000..fb75d1a --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/TestFixtureAttribute.cs @@ -0,0 +1,41 @@ +using System; +using System.Collections.Generic; +using System.Reflection; +using QuickGraph.Unit.Core; + +namespace QuickGraph.Unit +{ + [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)] + public sealed class TestFixtureAttribute : TestFixtureAttributeBase + { + public TestFixtureAttribute() + : base() + { } + + public override IEnumerable CreateFixtures(Type fixture) + { + yield return new TestFixture(this, fixture); + } + + private sealed class TestFixture : TypeFixtureBase + { + public TestFixture(TestFixtureAttribute attribute, Type fixtureType) + :base(attribute, fixtureType) + {} + + public override IEnumerable CreateTestCases() + { + foreach (MethodInfo method in this.FixtureType.GetMethods()) + { + Object[] decorators = method.GetCustomAttributes(typeof(TestDecoratorAttributeBase), true); + + foreach (TestAttributeBase attribute in method.GetCustomAttributes(typeof(TestAttributeBase), true)) + { + foreach (ITestCase test in attribute.CreateTests(this, method)) + yield return DecorateTest(decorators, test); + } + } + } + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/TestFixtureAttribute.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/TestFixtureAttribute.cs.meta new file mode 100644 index 0000000..e5f3b77 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/TestFixtureAttribute.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 03d3bf1eed1ac4896beb7751e48da0c1 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/TestFixtureSetUpAttribute.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/TestFixtureSetUpAttribute.cs new file mode 100755 index 0000000..4bb1b8e --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/TestFixtureSetUpAttribute.cs @@ -0,0 +1,9 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace QuickGraph.Unit +{ + [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)] + public sealed class TestFixtureSetUpAttribute : Attribute { } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/TestFixtureSetUpAttribute.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/TestFixtureSetUpAttribute.cs.meta new file mode 100644 index 0000000..449a1e0 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/TestFixtureSetUpAttribute.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 2ff4bd850e9d5493baf8cd43eec03557 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/TestFixtureTearDownAttribute.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/TestFixtureTearDownAttribute.cs new file mode 100755 index 0000000..9c1f91d --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/TestFixtureTearDownAttribute.cs @@ -0,0 +1,7 @@ +using System; + +namespace QuickGraph.Unit +{ + [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)] + public sealed class TestFixtureTearDownAttribute : Attribute { } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/TestFixtureTearDownAttribute.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/TestFixtureTearDownAttribute.cs.meta new file mode 100644 index 0000000..693098d --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/TestFixtureTearDownAttribute.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 48c2f2a27ca9c4faf9a59940dafbe8f0 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/TestRunner.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/TestRunner.cs new file mode 100755 index 0000000..abf33f9 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/TestRunner.cs @@ -0,0 +1,565 @@ +using System; +using System.Diagnostics; +using System.ComponentModel; +using System.Collections.Generic; +using System.Reflection; +using System.IO; +using System.Threading; +using System.Xml; +using QuickGraph.Unit.Serialization; +using QuickGraph.Unit.Listeners; +using QuickGraph.Unit.Filters; +using QuickGraph.CommandLine; +using QuickGraph.Unit.Reports; +using QuickGraph.Unit.Core; + +namespace QuickGraph.Unit +{ + public sealed class TestRunner : Component + { + private readonly object syncRoot = new object(); + private int successExitCode = 100; + private int failureExitCode = 101; + private TestRunnerArguments arguments = new TestRunnerArguments(); + private TestBatchFactory batchFactory = new TestBatchFactory(); + private ConsoleTestListener consoleListener = new ConsoleTestListener(); + private TestListenerCollection testListeners = new TestListenerCollection(); + private UnitTestHtmlReport report = null; + private string historyReportHtml = null; + private string historyReportXml = null; + + public TestRunner(IContainer container) + : this(container, Assembly.GetEntryAssembly()) + {} + + public TestRunner(IContainer container, Assembly assembly) + { + if (container == null) + throw new ArgumentNullException("container"); + container.Add(this); + if (assembly != null) + this.BatchFactory.TestAssemblies.Add(assembly); + + this.TestListeners.Add(this.consoleListener); + } + + public ConsoleTestListener ConsoleListener + { + get { return this.consoleListener; } + } + + public TestBatchFactory BatchFactory + { + get { return this.batchFactory; } + } + + public TestRunnerArguments Arguments + { + get { return this.arguments; } + set + { + if (value == null) + throw new ArgumentNullException("Arguments"); + this.arguments = value; + } + } + + public int SuccessExitCode + { + get { return this.successExitCode; } + set { this.successExitCode = value; } + } + + public int FailureExitCode + { + get { return this.failureExitCode; } + set { this.failureExitCode = value; } + } + + public UnitTestHtmlReport Report + { + get { return this.report; } + } + + [System.Diagnostics.DebuggerStepThrough] + public int Run(IEnumerable args) + { + this.TestListeners.Message("QuickGraph.Unit v{0}", + typeof(TestRunner).Assembly.GetName().Version); + this.TestListeners.Message( + MessageImportance.High, + "Test Assembly: {0}", Assembly.GetEntryAssembly().FullName); + + CommandLineParser parser = CommandLineParser.Create(); + if (!parser.Parse(this.arguments, args)) + { + this.TestListeners.Error("Error while parsing arguments"); + parser.ShowHelp(); + return this.FailureExitCode; + } + + if (this.Arguments.Help) + { + parser.ShowHelp(); + return this.SuccessExitCode; + } + + // run tests + return Run(); + } + + public TestListenerCollection TestListeners + { + get { return this.testListeners; } + } + + [System.Diagnostics.DebuggerStepThrough] + public int Run() + { + if (this.Arguments.BreakOnStart) + Debugger.Break(); + + System.Runtime.CompilerServices.RuntimeHelpers.PrepareConstrainedRegions(); + try + { + AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve); + return this.InternalRun(); + } + finally + { + AppDomain.CurrentDomain.AssemblyResolve -= new ResolveEventHandler(CurrentDomain_AssemblyResolve); + } + } + + Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args) + { + string name = args.Name.Split(',')[0]; + + // handling System.Xml.Serializer + if (name.EndsWith("XmlSerializers")) + return null; + + this.TestListeners.Message( + MessageImportance.Low, + "Resolving Assembly name: {0}", name); + foreach (Assembly testAssembly in this.BatchFactory.TestAssemblies) + { + string directory = Path.GetDirectoryName(testAssembly.Location); + this.TestListeners.Message( + MessageImportance.Low, + "Probing in directory {0}", directory); + + string path = null; + System.Runtime.CompilerServices.RuntimeHelpers.PrepareConstrainedRegions(); + try + { + this.TestListeners.Message( + MessageImportance.Low, + "Probing {0}", path); + path = Path.Combine(directory, name + ".dll"); + return Assembly.LoadFrom(path); + } + catch (Exception) + { + this.TestListeners.Message( + MessageImportance.Low, + "Failed to load {0}", path); + } + + System.Runtime.CompilerServices.RuntimeHelpers.PrepareConstrainedRegions(); + try + { + this.TestListeners.Message( + MessageImportance.Low, + "Probing {0}", path); + path = Path.Combine(directory, name + ".exe"); + return Assembly.LoadFrom(path); + } + catch (Exception) + { + this.TestListeners.Message( + MessageImportance.Low, + "Failed to load {0}", path); + return null; + } + } + + return null; + } + + private int InternalRun() + { + if (!this.InitializeTestBatch()) + return this.ExitCode; + + // reflect + this.TestListeners.Message( + MessageImportance.Low, + "Loading tests"); + this.BatchFactory.Create(); + this.TestListeners.Message( + MessageImportance.Low, + "Found {0} fixtures, {1} tests", + this.BatchFactory.Batch.GetFixtureCount(), + this.BatchFactory.Batch.GetTestCount() + ); + + System.Runtime.CompilerServices.RuntimeHelpers.PrepareConstrainedRegions(); + string currentDirectory = Environment.CurrentDirectory; + try + { + // execute + this.TestListeners.BeforeBatch(this.BatchFactory.Batch); + foreach (TestAssembly testAssembly in this.BatchFactory.Batch.TestAssemblies) + { + // set current directory as assembly location + Environment.CurrentDirectory = Path.GetDirectoryName(testAssembly.Assembly.Location); + this.ExecuteTestAssembly(testAssembly); + } + } + catch (Exception ex) + { + this.TestListeners.Error("Error in Test Harness!"); + this.TestListeners.Error(ex); + } + finally + { + Environment.CurrentDirectory = currentDirectory; + this.EndTestExecution(); + } + return this.ExitCode; + } + + private void PrepareReports() + { + if (this.Arguments.GenerateReport == ReportGenerationScenario.None) + return; + + this.report = new UnitTestHtmlReport(this.Container); + this.report.GenerateOnDisposed = false; + this.report.GenerateFixtureInSeparateFile = this.Arguments.GenerateFixtureReportInSeparateFiles; + this.report.ShowFixturesSummary = this.Arguments.ShowFixturesSummary; + this.report.EntryAssemblyName = this.BatchFactory.MainAssembly; + if (this.Arguments.ForceReportOutputPath) + this.report.SetOutputFolderName(this.Arguments.ReportOutputPath); + else + this.report.SetOutputFolderName(this.Arguments.ReportOutputPath, this.BatchFactory.MainAssembly); + this.report.TestListener.ShowTestCaseOnSuccess = this.Arguments.ShowTestCaseOnSuccess; + this.TestListeners.Add(this.report.TestListener); + + // we precreate the directory name + if (!Directory.Exists(this.report.OutputFolderName)) + Directory.CreateDirectory(this.report.OutputFolderName); + TestConsole.SetReportDirectoryName(this.report.OutputFolderName); + + this.LoadPreviousResult(); + } + + private void LoadPreviousResult() + { + if (!this.Arguments.UseLatestHistory) + return; + if (!System.IO.Directory.Exists(this.Arguments.ReportOutputPath)) + return; + do + { + string latestResultFile = new ReportHistory( + this.Arguments.ReportOutputPath, + this.BatchFactory.MainAssembly).GetLatestXmlReport(); + if (latestResultFile != null) + { + this.TestListeners.Message( + MessageImportance.Low, + "Found previous report: {0}", latestResultFile); + System.Runtime.CompilerServices.RuntimeHelpers.PrepareConstrainedRegions(); + try + { + this.report.TestListener.SetPreviousTestBatch(latestResultFile); + this.TestListeners.Message( + MessageImportance.Low, + "Loaded {0} fixtures and {1} tests in previous report", + this.report.TestListener.TestBatchSearcher.Fixtures.Count, + this.report.TestListener.TestBatchSearcher.TestCases.Count); + break; + } + catch (Exception ex) + { + this.TestListeners.Warning("Failure while loading previous report"); + this.TestListeners.Message( + MessageImportance.Low, + "Error: {0}", ex.Message); + // deleting previous report + ReportCleaner cleaner = new ReportCleaner(this.BatchFactory.MainAssembly); + cleaner.Clean(Path.GetDirectoryName(latestResultFile), this); + } + } + else + { + this.TestListeners.Message( + MessageImportance.Low, + "Could not find previous result"); + break; + } + } while (true); + } + + private void CleanOldReports() + { + if (!this.Arguments.CleanOldReports) + return; + + this.TestListeners.Message( + MessageImportance.Low, + "Cleaning old reports"); + ReportCleaner cleaner = new ReportCleaner(this.BatchFactory.MainAssembly); + cleaner.MaxReportCount = this.Arguments.MaxReportCount; + cleaner.Clean(this.Arguments.ReportOutputPath, this); + } + + private void GenerateReportHistory() + { + if (!this.Arguments.GenerateReportHistory) + return; + + using (UnitTestHistoryHtmlReport historyReport = new UnitTestHistoryHtmlReport(this.Container)) + { + historyReport.SetOutputFolderName(this.Arguments.ReportOutputPath); + historyReport.EntryAssemblyName = this.BatchFactory.MainAssembly; + historyReport.SetOutputFileName("test_history"); + historyReport.Generate(); + this.historyReportHtml = historyReport.OutputFileName; + this.historyReportXml = historyReport.OutputXmlFileName; + this.TestListeners.Message( + MessageImportance.High, + "History: {0}", new Uri(historyReport.OutputFileName).AbsoluteUri); + + if (this.Arguments.OpenReportHistory) + { + Thread thread = new Thread(delegate(object name) { Process.Start(name.ToString()); }); + thread.Start(historyReport.OutputFileName); + } + } + } + + private bool InitializeTestBatch() + { + this.BatchFactory.FixtureFilter = this.Arguments.GetFixtureFilter(); + this.BatchFactory.TestCaseFilter = this.Arguments.GetTestCaseFilter(); + + this.CleanOldReports(); + this.PrepareReports(); + + // adding assemblies + foreach (string assemblyName in this.Arguments.TestAssemblies) + { + if (!this.LoadTestAssembly(assemblyName)) + return false; + } + return true; + } + + private bool LoadTestAssembly(string assemblyName) + { + System.Runtime.CompilerServices.RuntimeHelpers.PrepareConstrainedRegions(); + try + { + Assembly testAssembly = Assembly.LoadFile(assemblyName); + this.BatchFactory.TestAssemblies.Add(testAssembly); + return true; + } + catch (Exception ex) + { + this.TestListeners.Error("Error while loading {0}", assemblyName); + this.TestListeners.Error(ex); + return false; + } + } + + [System.Diagnostics.DebuggerStepThrough] + private void ExecuteTestAssembly(TestAssembly testAssembly) + { + this.TestListeners.BeforeAssembly(testAssembly); + + // run assemblysetup + System.Runtime.CompilerServices.RuntimeHelpers.PrepareConstrainedRegions(); + try + { + if (this.RunAssemblySetUp(testAssembly)) + { + foreach (IFixture fixture in testAssembly.Fixtures) + { + using (FixtureRunner runner = + new FixtureRunner( + fixture, + testAssembly.GetTestCasesFromFixture(fixture), + this.TestListeners) + ) + { + runner.Run(); + } + // collect GC + GC.WaitForPendingFinalizers(); + GC.Collect(); + } + } + } + finally + { + // run assembly teardown + this.RunAssemblyTearDown(testAssembly); + this.TestListeners.AfterAssembly(testAssembly); + } + } + + private void EndTestExecution() + { + // finish + this.TestListeners.AfterBatch(this.BatchFactory.Batch); + + // generate report + this.GenerateReport(); + this.GenerateReportHistory(); + + this.TestListeners.ReportsGenerated( + this.historyReportXml, + this.historyReportHtml, + this.report.OutputXmlFileName, + this.report.OutputFileName + ); + + if (!this.Counter.Succeeded) + this.TestListeners.Message( + MessageImportance.High, + "Test FAILED"); + else + this.TestListeners.Message( + MessageImportance.High, + "Test SUCCESS"); + } + + private bool RunAssemblySetUp(TestAssembly testAssembly) + { + if (testAssembly.AssemblySetUp == null) + return true; + + Result result = new Result(testAssembly.AssemblySetUp.Name); + System.Runtime.CompilerServices.RuntimeHelpers.PrepareConstrainedRegions(); + try + { + result.Start(); + testAssembly.AssemblySetUp.Invoke(null, null); + result.Success(); + } + catch (Exception ex) + { + Exception current = ex; + if (current is TargetInvocationException) + current = current.InnerException; + if (current is QuickGraph.Unit.Exceptions.IgnoreException) + result.Ignore(); + else + result.Fail(current); + } + this.TestListeners.AssemblySetUp(result); + + return result.State == TestState.Success; + } + + private void RunAssemblyTearDown(TestAssembly testAssembly) + { + if (testAssembly.AssemblyTearDown == null) + return; + + Result result = new Result(testAssembly.AssemblyTearDown.Name); + System.Runtime.CompilerServices.RuntimeHelpers.PrepareConstrainedRegions(); + try + { + result.Start(); + testAssembly.AssemblyTearDown.Invoke(null, null); + result.Success(); + } + catch (Exception ex) + { + Exception current = ex; + if (current is TargetInvocationException) + current = current.InnerException; + if (current is QuickGraph.Unit.Exceptions.IgnoreException) + result.Ignore(); + else + result.Fail(current); + } + this.TestListeners.AssemblyTearDown(result); + } + + public TestCounter Counter + { + get { return this.consoleListener.Counter; } + } + + public int ExitCode + { + get + { + if (this.consoleListener.Counter == null) + return this.FailureExitCode; + return (this.consoleListener.Counter.HasFailures) ? + this.FailureExitCode: this.SuccessExitCode; + } + } + + private void GenerateReport() + { + switch (this.Arguments.GenerateReport) + { + case ReportGenerationScenario.None: + return; + case ReportGenerationScenario.OnFailure: + if (!this.Counter.HasFailures) + return; + else + break; + } + + if (this.Arguments.ForceReportOutputPath) + this.report.SetOutputFileName("TestWithResults"); + else + this.report.SetOutputFileName(this.BatchFactory.MainAssembly); + this.report.Generate(); + this.TestListeners.Message( + MessageImportance.High, + "Test report: {0}", new Uri(this.report.OutputFileName).AbsoluteUri); + if (this.Arguments.OpenReport) + { + Thread thread = new Thread(new ThreadStart(this.OpenReport)); + thread.Start(); + } + } + + private void OpenReport() + { + System.Diagnostics.Process.Start(report.OutputFileName); + } + + public static int TestMain(IEnumerable args) + { + System.Runtime.CompilerServices.RuntimeHelpers.PrepareConstrainedRegions(); + try + { + using (UnitContainer container = new UnitContainer()) + { + using (TestRunner runner = new TestRunner(container)) + { + runner.Run(args); + return runner.ExitCode; + } + } + } + catch (Exception ex) + { + Console.WriteLine("Error in Test Harness!"); + Console.WriteLine(ex.ToString()); + return 101; + } + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/TestRunner.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/TestRunner.cs.meta new file mode 100644 index 0000000..def10ed --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/TestRunner.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 155982f2d7cd645a9b2677c55c2b3a24 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/TestRunnerArguments.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/TestRunnerArguments.cs new file mode 100755 index 0000000..6802603 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/TestRunnerArguments.cs @@ -0,0 +1,252 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Xml.Serialization; +using QuickGraph.CommandLine; +using QuickGraph.Unit.Filters; +using QuickGraph.Unit.Reports; +using QuickGraph.Unit.Serialization; +using QuickGraph.Unit.Core; + +namespace QuickGraph.Unit +{ + [XmlRoot("unit")] + public sealed class TestRunnerArguments + { + [Argument( + ShortName = "h", + LongName = "help", + Description = "Display help")] + [XmlAttribute("help")] + public bool Help = false; + + [Argument( + ShortName = "gr", + LongName = "generate-report", + Description = "specify if a report has to be generated" + )] + [XmlAttribute("generate-report")] + public ReportGenerationScenario GenerateReport = ReportGenerationScenario.Always; + + [Argument( + ShortName="stcos", + LongName="show-test-case-on-success", + Description="Show test case on success in the reports" + )] + [XmlAttribute("show-test-case-on-success")] + public bool ShowTestCaseOnSuccess = true; + + [Argument( + ShortName = "or", + LongName = "open-report", + Description = "open report after created" + )] + [XmlAttribute("open-report")] + public bool OpenReport = false; + + [Argument( + ShortName = "rf", + LongName = "report-folder", + Description = "specify report folder" + )] + [XmlAttribute("report-folder")] + public string ReportOutputPath = "Reports"; + + [Argument( + ShortName="frop", + LongName="force-report-folder", + Description="Disable automatic report folder name generation" + )] + public bool ForceReportOutputPath = false; + + [Argument( + ShortName = "gfrisf", + LongName="generate-fixture-report-in-separate-files", + Description="Generates fixture reports in separate HTML files" + )] + [XmlAttribute("generate-fixture-report-in-separate-files")] + public bool GenerateFixtureReportInSeparateFiles = false; + + [Argument( + ShortName="sfs", + LongName="show-fixtures-summary", + Description="Shows a summary of the fixtures")] + public bool ShowFixturesSummary = true; + + [Argument( + ShortName = "ulh", + LongName="use-latest-history", + Description="Use latest test report to determine new failures, fixed tests" + )] + [XmlAttribute("use-latest-history")] + public bool UseLatestHistory = true; + + [Argument( + ShortName="cor", + LongName="clean-old-reports", + Description="Automatically deletes old report folders" + )] + [XmlAttribute("clean-old-reports")] + public bool CleanOldReports = true; + + [Argument( + ShortName="mrc", + LongName="max-report-count", + Description="Number of old report stored on disk. Older reports are automatically deleted (if clean-reports is true)" + )] + [XmlAttribute("max-report-count")] + public int MaxReportCount = 25; + + [Argument( + ShortName="grh", + LongName="generate-report-history", + Description="Generates an history of the previous and current results" + )] + [XmlAttribute("generate-report-history")] + public bool GenerateReportHistory = true; + + [Argument( + ShortName="orh", + LongName="open-report-history", + Description="Opens the report history on completion" + )] + [XmlAttribute("open-report-history")] + public bool OpenReportHistory = true; + + [Argument( + ShortName = "bs", + LongName = "break-on-start", + Description = "Debugger break on start" + )] + [XmlAttribute("break-on-start")] + public bool BreakOnStart = false; + + [Argument( + ShortName ="rfa", + LongName = "run-failures", + Description="Run failures from report" + )] + [XmlArray("run-failures")] + [XmlArrayItem("run-failure")] + public List RunFailures = new List(); + + [Argument( + ShortName = "ff", + LongName = "fixture-filter", + Description = "fixture name filters (fixture name must contain the filter string)" + )] + [XmlArray("fixture-filters")] + [XmlArrayItem("fixture-filter")] + public List FixtureFilters = new List(); + + [Argument( + ShortName = "tcf", + LongName = "test-case-filter", + Description = "test case name filters (test case name must contain the filter string" + )] + [XmlArray("test-case-filters")] + [XmlArrayItem("test-case-filter")] + public List TestCaseFilters = new List(); + + [Argument( + ShortName="c", + LongName="category", + Description="Test categories to run" + )] + [XmlArray("categories")] + [XmlArrayItem("category")] + public List Categories = new List(); + + [Argument( + ShortName = "ta", + LongName = "test-assembly", + Description = "Test assemblies")] + [XmlArray("test-assemblies")] + [XmlArrayItem("test-assembly")] + public List TestAssemblies = new List(); + + [Argument( + ShortName="ucf", + LongName="use-current-fixures", + Description="Run fixture tagged with [CurrentFixture] only")] + public bool UseCurrentFixtures = false; + + public IFixtureFilter GetFixtureFilter() + { + IFixtureFilter filter=null; + if (this.FixtureFilters.Count != 0) + filter = new ScopeFixtureFilter(this.FixtureFilters); + + if (this.Categories.Count != 0) + { + if (filter == null) + filter = new CategoryFixtureFilter(this.Categories); + else + filter = new AndFixtureFilter( + filter, + new CategoryFixtureFilter(this.Categories) + ); + } + + if (this.RunFailures.Count != 0) + { + foreach (string runFailureReport in this.RunFailures) + { + if (!File.Exists(runFailureReport)) + throw new ArgumentException("Could not find failure file "+ runFailureReport); + XmlTestBatch testBatch = UnitSerializer.Deserialize(runFailureReport); + if (testBatch != null) + { + FailureFilter failureFilter = new FailureFilter(testBatch); + if (filter == null) + filter = failureFilter; + else + filter = new AndFixtureFilter(filter, failureFilter); + } + } + } + + if (this.UseCurrentFixtures) + { + if (filter == null) + filter = new CurrentFixtureFilter(); + else + filter = new AndFixtureFilter(filter, new CurrentFixtureFilter()); + } + + if (filter == null) + filter = new AnyFixtureFilter(); + return filter; + } + + public ITestCaseFilter GetTestCaseFilter() + { + ITestCaseFilter filter = null; + + if (this.TestCaseFilters.Count != 0) + return new ScopeTestCaseFilter(this.TestCaseFilters); + + if (this.RunFailures.Count != 0) + { + foreach (string runFailureReport in this.RunFailures) + { + if (!File.Exists(runFailureReport)) + throw new ArgumentException("Could not find failure file " + runFailureReport); + XmlTestBatch testBatch = UnitSerializer.Deserialize(runFailureReport); + if (testBatch != null) + { + FailureFilter failureFilter = new FailureFilter(testBatch); + if (filter == null) + filter = failureFilter; + else + filter = new AndTestCaseFilter(filter, failureFilter); + } + } + } + + if (filter==null) + filter = new AnyTestCaseFilter(); + return filter; + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/TestRunnerArguments.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/TestRunnerArguments.cs.meta new file mode 100644 index 0000000..faf88cb --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/TestRunnerArguments.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 236250fee053347d4a84f81f58a628ed +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/TestSynchronizer.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/TestSynchronizer.cs new file mode 100755 index 0000000..aa5cfce --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/TestSynchronizer.cs @@ -0,0 +1,82 @@ +using System; +using System.Collections.Generic; +using System.Threading; + +namespace QuickGraph.Unit +{ + [Serializable] + public sealed class TestSynchronizer : IDisposable + { + private readonly object syncRoot = new object(); + private String name; + private ManualResetEvent barrier; + private List threadNames = new List(); + + public TestSynchronizer(string name) + { + if (String.IsNullOrEmpty(name)) + throw new ArgumentNullException("name"); + this.name = name; + } + + public ICollection GetThreadNames() + { + lock(syncRoot) + { + return new List(this.threadNames); + } + } + + public String Name + { + get { return this.name; } + } + + public void Block() + { + // make sure we cleaned up + this.Close(); + this.barrier = new ManualResetEvent(false); + } + + public void Release() + { + if (this.barrier == null) + throw new InvalidOperationException("Block must be called first"); + this.barrier.Set(); + } + + public void Synchronize() + { + if (this.barrier == null) + throw new InvalidOperationException("Block must be called first"); + // add thread name + lock (syncRoot) + { + this.threadNames.Add(Thread.CurrentThread.Name); + } + this.barrier.WaitOne(); + } + + public void Close() + { + if (this.barrier != null) + { + IDisposable disposable = this.barrier as IDisposable; + if (disposable != null) + disposable.Dispose(); + this.barrier = null; + } + } + + public void Dispose() + { + this.Close(); + } + + public override string ToString() + { + return this.Name; + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/TestSynchronizer.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/TestSynchronizer.cs.meta new file mode 100644 index 0000000..481c451 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/TestSynchronizer.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: a2581e84044624565b738cc601a407b5 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/ThreadedRepeatAttribute.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/ThreadedRepeatAttribute.cs new file mode 100755 index 0000000..fd3732f --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/ThreadedRepeatAttribute.cs @@ -0,0 +1,69 @@ +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Runtime.CompilerServices; +using QuickGraph.Unit.Core; + +namespace QuickGraph.Unit +{ + [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited=true, AllowMultiple=true)] + public sealed class MultiThreadedRepeatAttribute : TestDecoratorAttributeBase + { + private int threadCount = 1; + + public MultiThreadedRepeatAttribute(int threadCount) + { + this.threadCount = threadCount; + } + + public int ThreadCount + { + get { return this.threadCount; } + set { this.threadCount = value; } + } + + public override ITestCase Decorate(ITestCase testCase) + { + return new MultiThreadedRepeatTestCase(testCase, this); + } + + private sealed class MultiThreadedRepeatTestCase : TypeDecoratorTestCaseBase + { + private TestSynchronizer synchronizer; + private TestCaseWorkerCollection workers = new TestCaseWorkerCollection(); + + public MultiThreadedRepeatTestCase(ITestCase testCase, MultiThreadedRepeatAttribute attribute) + :base(testCase, attribute) + { + this.synchronizer = new TestSynchronizer(this.Name); + } + + public override void Run(object fixture) + { + // we block the synchronizer + try + { + this.synchronizer.Block(); + // create the pool of threads + for (int i = 0; i < this.Attribute.ThreadCount; ++i) + { + SynchronizedTestCase synchronizedTest = new SynchronizedTestCase(this.TestCase, this.synchronizer); + workers.Add(new TestCaseWorker(synchronizedTest, i)); + } + // starting threads + this.workers.StartAll(fixture); + // release barrier + this.synchronizer.Release(); + // wait for finish and verify + this.workers.WaitAll(); + this.workers.Verify(); + } + finally + { + // shutting down the synchronizer + this.synchronizer.Close(); + } + } + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/ThreadedRepeatAttribute.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/ThreadedRepeatAttribute.cs.meta new file mode 100644 index 0000000..203c59c --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/ThreadedRepeatAttribute.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 86a01533f2ec443a19d05aa7f239566a +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/TypeFactoryAttribute.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/TypeFactoryAttribute.cs new file mode 100755 index 0000000..648810e --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/TypeFactoryAttribute.cs @@ -0,0 +1,103 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Reflection; +using QuickGraph.Unit.Core; + +namespace QuickGraph.Unit +{ + [AttributeUsage(AttributeTargets.Class, AllowMultiple =true, Inherited =true)] + public sealed class TypeFactoryAttribute : TestCaseParameterFactoryAttributeBase + { + private Type factoryType; + + public TypeFactoryAttribute(Type factoryType) + { + if (factoryType == null) + throw new ArgumentNullException("factoryType"); + this.factoryType = factoryType; + } + + public Type FactoryType + { + get { return this.factoryType; } + } + + public override IEnumerable CreateInstances(Type targetType) + { + System.Runtime.CompilerServices.RuntimeHelpers.PrepareConstrainedRegions(); + foreach (MethodInfo method in ReflectionHelper.GetMethods(this.FactoryType, typeof(FactoryAttribute))) + { + if (method.GetParameters().Length > 0) + continue; + + FactoryAttribute factoryAttribute = ReflectionHelper.GetAttribute(method); + + // the method returns the type or a enumerable collection + if (targetType.IsAssignableFrom(method.ReturnType)) + yield return CreateSingleInstance(method); + else if ( + targetType.IsAssignableFrom(typeof(IEnumerable<>).MakeGenericType(targetType)) + || ( + targetType.IsAssignableFrom(typeof(IEnumerable)) + && targetType.IsAssignableFrom(factoryAttribute.FactoredType) + ) + ) + { + foreach (TestCaseParameter parameter in CreateMultipleInstances(method)) + yield return parameter; + } + } + } + + private TestCaseParameter CreateSingleInstance(MethodInfo method) + { + object instance = null; + object factory = null; + System.Runtime.CompilerServices.RuntimeHelpers.PrepareConstrainedRegions(); + try + { + factory = Activator.CreateInstance(this.FactoryType); + instance = method.Invoke(factory, null); + } + finally + { + IDisposable disposable = factory as IDisposable; + if (disposable != null) + disposable.Dispose(); + } + + return new TestCaseParameter( + String.Format("{0}.{1}",this.FactoryType.Name,method.Name), + instance + ); + } + + private IEnumerable CreateMultipleInstances(MethodInfo method) + { + System.Collections.IEnumerable instances = null; + object factory = null; + System.Runtime.CompilerServices.RuntimeHelpers.PrepareConstrainedRegions(); + try + { + factory = Activator.CreateInstance(this.FactoryType); + instances = method.Invoke(factory, null) as IEnumerable; + + int index = 0; + foreach (object instance in instances) + { + yield return new TestCaseParameter( + String.Format("{0}.{1}.{2}", this.FactoryType.Name, method.Name, index++), + instance + ); + } + } + finally + { + IDisposable disposable = factory as IDisposable; + if (disposable != null) + disposable.Dispose(); + } + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/TypeFactoryAttribute.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/TypeFactoryAttribute.cs.meta new file mode 100644 index 0000000..620d859 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/TypeFactoryAttribute.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 0de4d812c65ea4fb193863fab9f42793 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/TypeFixtureAttribute.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/TypeFixtureAttribute.cs new file mode 100755 index 0000000..cd7948a --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/TypeFixtureAttribute.cs @@ -0,0 +1,102 @@ +using System; +using System.Reflection; +using System.Collections.Generic; +using QuickGraph.Unit.Core; + +namespace QuickGraph.Unit +{ + [AttributeUsage(AttributeTargets.Class, AllowMultiple =true, Inherited =true)] + public sealed class TypeFixtureAttribute : TestFixtureAttributeBase + { + private Type testedType; + + public TypeFixtureAttribute(Type testedType) + { + if (testedType == null) + throw new ArgumentNullException("testedType"); + this.testedType = testedType; + } + + public Type TestedType + { + get { return this.testedType; } + } + + public override IEnumerable CreateFixtures(Type fixtureType) + { + yield return new TypeFixture(this, fixtureType); + } + + private sealed class TypeFixture : TypeFixtureBase + { + public TypeFixture(TypeFixtureAttribute attribute, Type fixtureType) + :base(attribute, fixtureType) + {} + + public override IEnumerable CreateTestCases() + { + Object[] attributes = this.FixtureType.GetCustomAttributes(typeof(TestCaseParameterFactoryAttributeBase),true); + List> instances = new List>(); + List> tests = new List>(); + + // first get the number of instances + instances.Add(new List(this.CreateAllInstances(attributes))); + int instanceCount = instances[0].Count; + + // get the number of tests + tests.Add(new List(CreateTestCaseInstances())); + int testCount = tests[0].Count; + + // prepare for cross product + for(int i=1;i ToList(IEnumerable en, int capacity) + { + List list = new List(capacity); + list.AddRange(en); + return list; + } + + private IEnumerable CreateAllInstances(Object[] attributes) + { + foreach (TestCaseParameterFactoryAttributeBase atr in attributes) + { + foreach (TestCaseParameter instance in atr.CreateInstances( + this.Attribute.TestedType + )) + yield return instance; + } + } + + private IEnumerable CreateTestCaseInstances() + { + foreach (MethodInfo method in this.FixtureType.GetMethods()) + { + Object[] decorators = method.GetCustomAttributes(typeof(TestDecoratorAttributeBase), true); + + foreach (TestAttributeBase attribute in method.GetCustomAttributes(typeof(TestAttributeBase), true)) + { + foreach (ITestCase test in attribute.CreateTests(this, method)) + yield return DecorateTest(decorators, test); + } + } + } + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/TypeFixtureAttribute.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/TypeFixtureAttribute.cs.meta new file mode 100644 index 0000000..80b3cfc --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/TypeFixtureAttribute.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 9d1fc2f14e24041dc80b24b7a33f3e4a +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/UsingAttributeBase.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/UsingAttributeBase.cs new file mode 100755 index 0000000..d60594f --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/UsingAttributeBase.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Reflection; +using QuickGraph.Operations; + +namespace QuickGraph.Unit +{ + [AttributeUsage(AttributeTargets.Parameter,AllowMultiple =true,Inherited =true)] + public abstract class UsingAttributeBase : + Attribute, + IParameterDomainFactory + { + public abstract void CreateDomains( + IList domains, + ParameterInfo parameter, + IFixture fixture); + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/UsingAttributeBase.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/UsingAttributeBase.cs.meta new file mode 100644 index 0000000..2c7bbd0 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/UsingAttributeBase.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 4f8227b89b8984e098cc5a713d7e666a +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/UsingBooleanAttribute.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/UsingBooleanAttribute.cs new file mode 100755 index 0000000..353c200 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/UsingBooleanAttribute.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Reflection; +using QuickGraph.Operations; + +namespace QuickGraph.Unit +{ + [AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = true)] + public sealed class UsingBooleanAttribute : UsingAttributeBase + { + public UsingBooleanAttribute() + { } + + public override void CreateDomains( + IList domains, + ParameterInfo parameter, + IFixture fixture) + { + domains.Add(Domains.Boolean); + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/UsingBooleanAttribute.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/UsingBooleanAttribute.cs.meta new file mode 100644 index 0000000..f0f139d --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/UsingBooleanAttribute.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 9cf622f9953e0493a83054266c4ac150 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/UsingEnumAttribute.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/UsingEnumAttribute.cs new file mode 100755 index 0000000..751b867 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/UsingEnumAttribute.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Reflection; +using QuickGraph.Operations; + +namespace QuickGraph.Unit +{ + [AttributeUsage(AttributeTargets.Parameter, AllowMultiple = true, Inherited = true)] + public sealed class UsingEnumAttribute : UsingAttributeBase + { + public override void CreateDomains( + IList domains, + ParameterInfo parameter, + IFixture fixture) + { + Assert.IsTrue(parameter.ParameterType.IsEnum, + "Parameter {0} must be an enum", parameter.Name); + ArrayDomain domain = new ArrayDomain(Enum.GetValues(parameter.ParameterType)); + domains.Add(domain); + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/UsingEnumAttribute.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/UsingEnumAttribute.cs.meta new file mode 100644 index 0000000..b585990 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/UsingEnumAttribute.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 920bfc5dee2884103bbb430c06e9cb20 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/UsingFactoriesAttribute.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/UsingFactoriesAttribute.cs new file mode 100755 index 0000000..012ab1e --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/UsingFactoriesAttribute.cs @@ -0,0 +1,123 @@ +using System; +using System.Collections.Generic; +using QuickGraph.Operations; +using System.Reflection; +using QuickGraph.Unit.Core; + +namespace QuickGraph.Unit +{ + [AttributeUsage( + AttributeTargets.Parameter, + AllowMultiple = true, + Inherited = true)] + public sealed class UsingFactoriesAttribute : UsingAttributeBase + { + private Type factoryType = null; + public UsingFactoriesAttribute(Type factoryType) + { + if (factoryType == null) + throw new ArgumentNullException("factoryType"); + this.factoryType = factoryType; + } + + public Type FactoryType + { + get + { + return this.factoryType; + } + set + { + this.factoryType = value; + } + } + + public override void CreateDomains( + IList domains, + ParameterInfo parameter, + IFixture fixture) + { + Object factory = null; + System.Runtime.CompilerServices.RuntimeHelpers.PrepareConstrainedRegions(); + try + { + factory = Activator.CreateInstance(this.FactoryType); + this.GetAllDomains(domains, parameter, factory); + } + finally + { + IDisposable disposable = factory as IDisposable; + if (disposable != null) + disposable.Dispose(); + } + } + + private void GetAllDomains( + IList domains, + ParameterInfo parameter, + object factory) + { + foreach (MethodInfo factoryMethod in ReflectionHelper.GetMethods(factory.GetType(), typeof(FactoryAttribute))) + { + if (factoryMethod.GetParameters().Length > 0) + continue; + Type returnType = factoryMethod.ReturnType; + + // check single object return + if (parameter.ParameterType.IsAssignableFrom(returnType)) + { + object result = factoryMethod.Invoke(factory, null); + IDomain domain = Domains.ToDomain(result); + domain.Name = factoryMethod.Name; + domains.Add(domain); + continue; + } + + // check array + if (returnType.HasElementType) + { + Type elementType = returnType.GetElementType(); + if (parameter.ParameterType == elementType) + { + object result = factoryMethod.Invoke(factory,null); + IDomain domain = Domains.ToDomain(result); + domain.Name = factoryMethod.Name; + domains.Add(domain); + continue; + } + } + + // check IEnumerable + if (returnType.IsGenericType) + { + if (typeof(IEnumerable<>).IsAssignableFrom(returnType.GetGenericTypeDefinition())) + { + if (parameter.ParameterType.IsAssignableFrom(returnType.GetGenericArguments()[0])) + { + object result = factoryMethod.Invoke(factory, null); + IDomain domain = Domains.ToDomain(result); + domain.Name = factoryMethod.Name; + domains.Add(domain); + continue; + } + } + } + + // check factory type + FactoryAttribute factoryAttribute = ReflectionHelper.GetAttribute(factoryMethod); + if (factoryAttribute != null) + { + Type factoredType = factoryAttribute.FactoredType; + if (parameter.ParameterType == factoredType) + { + object result = factoryMethod.Invoke(factory, null); + IDomain domain = Domains.ToDomain(result); + domain.Name = factoryMethod.Name; + domains.Add(domain); + continue; + } + } + } + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/UsingFactoriesAttribute.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/UsingFactoriesAttribute.cs.meta new file mode 100644 index 0000000..de7e78a --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/UsingFactoriesAttribute.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e2ac88e6f5bb1448195492e3bf5a3831 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/UsingImplementationsAttribute.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/UsingImplementationsAttribute.cs new file mode 100755 index 0000000..53d27da --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/UsingImplementationsAttribute.cs @@ -0,0 +1,44 @@ +using System; +using System.Collections.Generic; +using System.Reflection; +using QuickGraph.Operations; + +namespace QuickGraph.Unit +{ + [AttributeUsage(AttributeTargets.Parameter, AllowMultiple = true, Inherited = true)] + public sealed class UsingImplementationsAttribute : UsingAttributeBase + { + private Type typeFromAssembly; + + public UsingImplementationsAttribute(Type typeFromAssembly) + { + if (typeFromAssembly == null) + throw new ArgumentNullException("typeFromAssembly"); + this.typeFromAssembly = typeFromAssembly; + } + + public override void CreateDomains( + IList domains, + ParameterInfo parameter, + IFixture fixture) + { + List types = new List(); + foreach (Type type in typeFromAssembly.Assembly.GetExportedTypes()) + { + if (type.IsAbstract || type.IsInterface || !type.IsClass) + continue; + + if (!parameter.ParameterType.IsAssignableFrom(type)) + continue; + + // create instance + Object instance = Activator.CreateInstance(type); + types.Add(instance); + } + + CollectionDomain domain = new CollectionDomain(types); + domain.Name = typeFromAssembly.Assembly.GetName().Name; + domains.Add(domain); + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/UsingImplementationsAttribute.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/UsingImplementationsAttribute.cs.meta new file mode 100644 index 0000000..79623e7 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/UsingImplementationsAttribute.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 1fb8b1192be4a46dcaf9b583a2be1b65 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/UsingLinearAttribute.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/UsingLinearAttribute.cs new file mode 100755 index 0000000..b49bb8b --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/UsingLinearAttribute.cs @@ -0,0 +1,51 @@ +using System; +using System.Collections.Generic; +using System.Reflection; +using QuickGraph.Operations; + +namespace QuickGraph.Unit +{ + [AttributeUsage(AttributeTargets.Parameter, AllowMultiple = true, Inherited = true)] + public sealed class UsingLinearAttribute : UsingAttributeBase + { + private int start; + private int step; + private int stepCount; + + public UsingLinearAttribute(int start, int stepCount) + :this(start,stepCount,1) + { + } + + public UsingLinearAttribute(int start, int stepCount, int step) + { + this.start = start; + this.stepCount = stepCount; + this.step = step; + } + + public int Start + { + get { return this.start; } + } + + public int StepCount + { + get { return this.stepCount; } + } + + public int Step + { + get { return this.step; } + } + + public override void CreateDomains( + IList domains, + ParameterInfo parameter, + IFixture fixture) + { + LinearInt32Domain domain = new LinearInt32Domain(start, stepCount, step); + domains.Add(domain); + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/UsingLinearAttribute.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/UsingLinearAttribute.cs.meta new file mode 100644 index 0000000..0b96f06 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/UsingLinearAttribute.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 4220fdaecf0214831b2f061f681a4f35 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/UsingLiteralsAttribute.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/UsingLiteralsAttribute.cs new file mode 100755 index 0000000..8782cb8 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/UsingLiteralsAttribute.cs @@ -0,0 +1,53 @@ +using System; +using System.Reflection; +using System.Collections.Generic; +using QuickGraph.Operations; + +namespace QuickGraph.Unit +{ + [AttributeUsage(AttributeTargets.Parameter, AllowMultiple = true, Inherited = true)] + public sealed class UsingLiteralsAttribute : UsingAttributeBase + { + private string values; + + public UsingLiteralsAttribute(string values) + { + this.values = values; + } + + /// + /// Gets a list of values separated by ; + /// + /// + public string Values + { + get + { + return this.values; + } + } + + public override void CreateDomains( + IList domains, + ParameterInfo parameter, + IFixture fixture) + { + bool isString = parameter.ParameterType.IsAssignableFrom(typeof(string)); + List data = new List(); + foreach (string memberName in this.Values.Split(';')) + { + object cresult = null; + if (isString) + cresult = memberName.ToString(); + else + cresult = Convert.ChangeType(memberName, parameter.ParameterType); + data.Add(cresult); + } + if (data.Count == 0) + return; + + CollectionDomain domain = new CollectionDomain(data); + domains.Add(domain); + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/UsingLiteralsAttribute.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/UsingLiteralsAttribute.cs.meta new file mode 100644 index 0000000..0ea4779 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/UsingLiteralsAttribute.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 1e90486b19aa948dd97ace6e108ab66a +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/UsingXmlAttribute.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/UsingXmlAttribute.cs new file mode 100755 index 0000000..227de7c --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/UsingXmlAttribute.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using QuickGraph.Operations; +using System.Reflection; + +namespace QuickGraph.Unit +{ + public sealed class UsingXmlAttribute : UsingAttributeBase + { + private string resourceName; + private string xPath; + + public UsingXmlAttribute(string resourceName, string xPath) + { + this.resourceName = resourceName; + this.xPath = xPath; + } + + public override void CreateDomains(IList domains, ParameterInfo parameter, IFixture fixture) + { + throw new NotImplementedException(); + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/UsingXmlAttribute.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/UsingXmlAttribute.cs.meta new file mode 100644 index 0000000..dcc0b0d --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/UsingXmlAttribute.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 763138ed95b624a8589436fb32ae8b64 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/XmlAssert.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/XmlAssert.cs new file mode 100755 index 0000000..72dba7f --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/XmlAssert.cs @@ -0,0 +1,197 @@ +using System; +using System.Collections.Generic; +using System.Xml; +using System.Xml.Schema; +using System.IO; + +namespace QuickGraph.Unit +{ + public static class XmlAssert + { + public static XmlDocument IsWellFormedXml(string xml) + { + Assert.IsNotNull(xml); + XmlDocument doc = new XmlDocument(); + doc.LoadXml(xml); + return doc; + } + + public static XmlDocument IsWellFormed(string fileName) + { + Assert.IsNotNull(fileName); + XmlDocument doc = new XmlDocument(); + doc.Load(fileName); + return doc; + } + + public static XmlDocument IsWellFormed(TextReader reader) + { + Assert.IsNotNull(reader); + XmlDocument doc = new XmlDocument(); + doc.Load(reader); + return doc; + } + + public static XmlDocument IsWellFormed(XmlReader reader) + { + Assert.IsNotNull(reader); + XmlDocument doc = new XmlDocument(); + doc.Load(reader); + return doc; + } + + public static XmlDocument IsWellFormed(Stream stream) + { + Assert.IsNotNull(stream); + XmlDocument doc = new XmlDocument(); + doc.Load(stream); + return doc; + } + + public static XmlSchema IsSchemaValid(Stream stream, bool warningsAsError) + { + Assert.IsNotNull(stream); + SchemaValidator validator = new SchemaValidator(warningsAsError); + return validator.ValidateSchema(stream); + } + + public static XmlSchema IsSchemaValid(TextReader reader, bool warningsAsError) + { + Assert.IsNotNull(reader); + SchemaValidator validator = new SchemaValidator(warningsAsError); + return validator.ValidateSchema(reader); + } + + public static XmlSchema IsSchemaValid(XmlReader reader, bool warningsAsError) + { + Assert.IsNotNull(reader); + SchemaValidator validator = new SchemaValidator(warningsAsError); + return validator.ValidateSchema(reader); + } + + public static XmlSchema IsSchemaValid(string fileName, bool warningsAsError) + { + Assert.IsNotNull(fileName); + using (StreamReader reader = new StreamReader(fileName)) + { + return IsSchemaValid(reader, warningsAsError); + } + } + + public static XmlSchema IsSchemaValidXml(string xml, bool warningsAsError) + { + Assert.IsNotNull(xml); + using (StringReader reader = new StringReader(xml)) + { + return IsSchemaValid(reader, warningsAsError); + } + } + + public static XmlDocument IsValidXml(string xml, bool warningsAsError) + { + Assert.IsNotNull(xml); + SchemaValidator validator = new SchemaValidator(warningsAsError); + return validator.Validate(IsWellFormedXml(xml)); + } + + public static XmlDocument IsValid(string fileName, bool warningsAsError) + { + Assert.IsNotNull(fileName); + SchemaValidator validator = new SchemaValidator(warningsAsError); + return validator.Validate(IsWellFormed(fileName)); + } + + public static XmlDocument IsValid(XmlReader reader, bool warningsAsError) + { + Assert.IsNotNull(reader); + SchemaValidator validator = new SchemaValidator(warningsAsError); + return validator.Validate(IsWellFormed(reader)); + } + + public static XmlDocument IsValid(TextReader reader, bool warningsAsError) + { + Assert.IsNotNull(reader); + SchemaValidator validator = new SchemaValidator(warningsAsError); + return validator.Validate(IsWellFormed(reader)); + } + + private sealed class SchemaValidator + { + private int errorCount = 0; + private int warningCount = 0; + private bool warningsAsError = false; + + public SchemaValidator(bool warningsAsError) + { + this.warningsAsError = warningsAsError; + } + + public XmlDocument Validate(XmlDocument document) + { + document.Validate(new ValidationEventHandler(this.ValidationEvent)); + this.ValidateResults(); + return document; + } + + public XmlDocument Validate(XmlDocument document, XmlNode nodeToValidate) + { + document.Validate(new ValidationEventHandler(this.ValidationEvent), nodeToValidate); + this.ValidateResults(); + return document; + } + + public XmlSchema ValidateSchema(Stream stream) + { + XmlSchema schema = XmlSchema.Read( + stream, + new ValidationEventHandler(ValidationEvent)); + this.ValidateResults(); + return schema; + } + + public XmlSchema ValidateSchema(TextReader reader) + { + XmlSchema schema = XmlSchema.Read( + reader, + new ValidationEventHandler(ValidationEvent)); + this.ValidateResults(); + return schema; + } + + public XmlSchema ValidateSchema(XmlReader reader) + { + XmlSchema schema = XmlSchema.Read( + reader, + new ValidationEventHandler(ValidationEvent)); + this.ValidateResults(); + return schema; + } + + private void ValidateResults() + { + Console.WriteLine("Validation: {0} errors, {1} warnings", + this.errorCount, + this.warningCount); + if (this.errorCount > 0) + Assert.Fail("{0} error in schema", this.errorCount); + if (this.warningsAsError && this.warningCount > 0) + Assert.Fail("{0} warnings in schema", this.warningCount); + } + + private void ValidationEvent(Object sender, ValidationEventArgs e) + { + switch (e.Severity) + { + case XmlSeverityType.Error: + errorCount++; break; + case XmlSeverityType.Warning: + warningCount++; break; + } + + Console.WriteLine("{0}: {1}", e.Severity, e.Message); + Console.WriteLine(e.Exception); + Console.WriteLine(); + } + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/XmlAssert.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/XmlAssert.cs.meta new file mode 100644 index 0000000..1474119 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/XmlAssert.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 211839295ed914a2fa3052fac43b308d +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/XmlDataProviderAttribute.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/XmlDataProviderAttribute.cs new file mode 100755 index 0000000..ea7bcb8 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/XmlDataProviderAttribute.cs @@ -0,0 +1,37 @@ +using System; +using System.Xml.XPath; +using QuickGraph.Unit.Core; + +namespace QuickGraph.Unit +{ + [AttributeUsage(AttributeTargets.Class, AllowMultiple=true, Inherited=true)] + public sealed class XmlDataProviderAttribute : DataProviderAttributeBase + { + private string fileName; + private XPathDocument data; + + public XmlDataProviderAttribute(string fileName) + { + if (String.IsNullOrEmpty(fileName)) + throw new ArgumentException("fileName"); + this.fileName = fileName; + } + + public string FileName + { + get { return this.fileName; } + } + + public override IXPathNavigable GetData() + { + if (this.data == null) + this.data = new XPathDocument(this.FileName); + return this.data; + } + + public override string Name + { + get { return System.IO.Path.GetFileName(this.FileName); } + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/XmlDataProviderAttribute.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/XmlDataProviderAttribute.cs.meta new file mode 100644 index 0000000..2e5c3ca --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/XmlDataProviderAttribute.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 9b216b0f8e2f04106836fe9ca6b22bd4 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/common.xslt b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/common.xslt new file mode 100755 index 0000000..55881e1 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/common.xslt @@ -0,0 +1,851 @@ + + + + + + + + + + + + + + SUCCESS + + + FAILURE + + + + + s + + + + + + : + : + + + + showToolTip() + hideToolTip() + + + + javascript:mark('') + + + + + tg + javascript:toggle('tg','')[-] + + + + + tg + javascript:toggle('tg','')[+] + + + + odd + even + + + + + log + Odd + + log + Even + + + + + + successOdd + successEven + + + + + failureOdd + failureEven + + + + + ignoreOdd + ignoreEven + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + tests, +success, -failures, ~ignored, *new failure, !fixed + + + , + + + , + - + , + ~ + + , + * + , + + ! + + + + + + + + 100.00 + + + + % + + + + + + + + + + + + + Log.png + + + + + + + + + + + + w + + + + + + + + + +
+
+
+ + + + + + + + + + + + + + + Type: + + + + + + Source: + + + + + + + + + : + + + + + + + +
+ +
+						
+					
+
+ + + + + +
+ + + + + + Console Output + + + + + Console Output + + +
+
+
+ + + + + + + + + + + + + + + + +
+ +
+							
+						
+
+ + +
+
+ + + \w+):\/\/\/?(?[\w.]+\/?)\S*", + RegexOptions.IgnoreCase + | RegexOptions.CultureInvariant + | RegexOptions.IgnorePatternWhitespace + | RegexOptions.Compiled + ); + private static Regex imgRegex = new Regex(@"\[img\s*src=\""(?.*?)\""\s*/\]", + RegexOptions.IgnoreCase + | RegexOptions.CultureInvariant + | RegexOptions.IgnorePatternWhitespace + | RegexOptions.Compiled + ); + private static Regex boldRegex = new Regex(@"\*\*(?.+?)\*\*", + RegexOptions.IgnoreCase + | RegexOptions.CultureInvariant + | RegexOptions.IgnorePatternWhitespace + | RegexOptions.Compiled + ); + + // XML-escapes a string + private string EscapeString(string value) + { + using(StringWriter sw = new StringWriter()) + { + foreach(char c in value) + { + if (c >= 0 && c <= 0x1F && c!=9 && c!=10 && c!=13) + { + sw.Write("&#{0};", (int)c); + } + else + { + switch(c) + { + case '<': sw.Write("<"); break; + case '>': sw.Write(">"); break; + case '&': sw.Write("&"); break; + default: sw.Write(c); break; + } + } + } + return sw.ToString(); + } + } + + // processes console text to + // add Url higlighting, image embedding, etc... + public string FormatConsole(string value) + { + string result = EscapeString(value); + result = urlRegex.Replace(result, "$&"); + result = imgRegex.Replace(result, "\"${Url}\""); + result = boldRegex.Replace(result, "${Value}"); + return result; + } +]]> + + + +
+

Machine details

+ + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
Machine description
Machine name + +
Framework + +
OS + +
+ + + +
+
+ + + + + + + + + + +
Log + + + errors, + + + + warnings, + + + + messages +
+
+
+
+ + + + + + + + + +
+ + +
+
+ + +
+ + + + + + + + _ + + + .html + + + + + + + + + + _blank + + + + + # + + + + + + + + + + + + + + + + + + + + +

Fixtures summary

+ + + + + + +
+
+
+ + + +

+ + newfailures + New failures () +

+
+ + + + + + + +
+ +
+ +
+
+
+ + + + +

+ + fixedtests + Fixed tests () +

+
+ + + + + + + +
+ +
+ +
+
+
+ + + +

+ + newtests + New tests () +

+
+ + + + + + + +
+ +
+ +
+
+
+ + + + + +
+

Throwed exceptions

+ + + + + + + + + + +
+ + + + , + exceptions +
+ + + + + + + + +
+ +
+
+
+ +
+
+
+ + + + + + + + + rf + div +

+ + + + + + + , + + + + +

+
+ + + + + + + + +
+ + + + +
+ + , + + Categories= + + ,ApartementState. + + ,TimeOut= + [min] +
+
+ + + + + + + +
+ +
+ + + + + + +
+
+ + + + javascript:copyToClipboad('') + Repro + + + + + /ff:"" + /or+ + + + + /ff:"" + /tcf:"" /or+ /orh- + + +
+

+ 10 longuest tests +

+ + + + + + + + + + + +
+ + + +
+
+
+ +
+

+ 10 longuest fixtures +

+ + + + + + + +
+
+
+ + + + + + + + + + + + + # + + + + + # + _blank + + + + + + + + + + + New Failure! + + + Fixed! + + + New! + + + + + + td + rt + + + + + + + + + , + + + + +
+
+ closedToggle + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ + + + + + + + + + + + + + + +
+
+ + + + + + +
+
+ + +
+ +
+ + +
+
\ No newline at end of file diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/common.xslt.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/common.xslt.meta new file mode 100644 index 0000000..f092f5f --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/common.xslt.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: dcf27b113715147a9a24252d1aef7ad7 +DefaultImporter: + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/expectedexceptionattribute.cs b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/expectedexceptionattribute.cs new file mode 100755 index 0000000..534ecec --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/expectedexceptionattribute.cs @@ -0,0 +1,104 @@ +using System; +using System.IO; +using System.Reflection; +using QuickGraph.Unit.Exceptions; +using QuickGraph.Unit.Core; + +namespace QuickGraph.Unit +{ + [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, AllowMultiple = true, Inherited = true)] + public class ExpectedExceptionAttribute : TestDecoratorAttributeBase + { + private Type expectedExceptionType; + private NameMatchType messageMatchType = NameMatchType.Contains; + private string messagePattern = null; + + public ExpectedExceptionAttribute(Type expectedExceptionType) + { + if (expectedExceptionType == null) + throw new ArgumentNullException("expectedExceptionType"); + this.expectedExceptionType = expectedExceptionType; + } + + public Type ExpectedExceptionType + { + get { return this.expectedExceptionType; } + } + + public NameMatchType MessageMatchType + { + get { return this.messageMatchType; } + set { this.messageMatchType = value; } + } + + public string MessagePattern + { + get { return this.messagePattern; } + set { this.messagePattern = value; } + } + + public override ITestCase Decorate(ITestCase testCase) + { + return new ExpectedExceptionTestCase(testCase, this); + } + + private sealed class ExpectedExceptionTestCase : TypeDecoratorTestCaseBase + { + public ExpectedExceptionTestCase(ITestCase testCase, ExpectedExceptionAttribute attribute) + : base(testCase, attribute) + {} + + public override string Name + { + get { return String.Format("{0}({1})", + this.TestCase.Name, + this.Attribute.ExpectedExceptionType.Name); } + } + + public override void Run(Object fixture) + { + System.Runtime.CompilerServices.RuntimeHelpers.PrepareConstrainedRegions(); + try + { + this.TestCase.Run(fixture); + } + catch (Exception ex) + { + Exception current = ex; + // check if current expection is expecetd or ignored + while (current != null) + { + if (current.GetType() == this.Attribute.ExpectedExceptionType) + { + VerifyException(current); + return; + } + if (current.GetType() == typeof(IgnoreException)) + { + VerifyException(current); + return; + } + current = current.InnerException; + } + current = ex; + if (current is TargetInvocationException) + current = current.InnerException; + throw new ExceptionTypeMistmatchException(this.Attribute.ExpectedExceptionType, current); + } + throw new ExceptionNotThrowedException(this.Attribute.ExpectedExceptionType); + } + + private void VerifyException(Exception ex) + { + if (String.IsNullOrEmpty(this.Attribute.MessagePattern)) + return; + + INameMatcher matcher = NameMatcherFactory.CreateMatcher( + this.Attribute.MessageMatchType, + this.Attribute.MessagePattern); + if (!matcher.IsMatch(ex.Message)) + throw new ExceptionMessageDoesNotMatchException(matcher, ex); + } + } + } +} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/expectedexceptionattribute.cs.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/expectedexceptionattribute.cs.meta new file mode 100644 index 0000000..f902a27 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/expectedexceptionattribute.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 83122e885fbb34a548a3a130614a625b +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/fixturetest.xslt b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/fixturetest.xslt new file mode 100755 index 0000000..e6bb408 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/fixturetest.xslt @@ -0,0 +1,20 @@ + + + + + + saved from url=(0028)http://blog.dotnetwiki.org/ + + + <xsl:value-of select="@Name"/>, + <xsl:call-template name="counter-figures"/> + + + + + + + + + + \ No newline at end of file diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/fixturetest.xslt.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/fixturetest.xslt.meta new file mode 100644 index 0000000..2788834 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/fixturetest.xslt.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: 54a024fadda8f4ed6a5d5f88b0854545 +DefaultImporter: + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/quickgraph.css b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/quickgraph.css new file mode 100755 index 0000000..3620fd8 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/quickgraph.css @@ -0,0 +1,41 @@ +h1 { font-family:Verdana; font-weight:Bold; font-size:14pt; color:#BB5500; margin-bottom:0pt; vertical-align:bottom; } +h2 { font-family:Verdana; font-weight:Bold; font-size:12pt; color:#BB5500;margin-bottom:0pt; } +h3 { font-family:Verdana; font-weight:Bold; font-size:10pt; color:#BB5500;margin-bottom:0pt; } +h4 { font-family:Verdana; font-size:10pt; margin-bottom:0pt; } +a { color:#660000;} +span.toggle { cursor:pointer; font-size:6pt;} +div.toggle { display:block; background-color:White;} +div.closedToggle{ display:none; background-color:White;} +body,p,li { font-family:Verdana; font-size:9pt;} +p.menu { font-size:8pt; font-family:Verdana; font-weight:bold} +p.copyright { font-size:7pt; font-family:Verdana;} +p.repro { font-size: 7pt; font-family:Verdana;background-color:#FEFEFE; border-width:thin; border-style:dashed; border-color:Gray;} +table { font-family:Verdana; font-weight:normal; font-size:8pt; color:black; } +table.indented { text-indent:10pt;} +tr.heading { background-color:#CCCCFF; font-weight:bold; color:black;} +tr.repro { background-color:#FFFFAF; font-size:7pt;} +tr.even { background-color:#FFFFDF;} +tr.odd { background-color:#FFFFA9;} +tr.successEven { background-color:#EFFFEF; } +tr.successOdd { background-color:#C0FFC0; } +tr.ignoreEven { background-color:#FFCC33; } +tr.ignoreOdd { background-color:#FFBB33; } +tr.failureTitle { background-color:#FF6000; color:White; font-weight:bold; } +tr.failureEven { background-color:#FFEEDE; } +tr.failureOdd { background-color:#FFD0C0; } +tr.logMessageEven { background-color:#FFFFDF; } +tr.logMessageOdd { background-color:#FFFFA9; } +tr.logWarningEven { background-color:#FFFEEE; } +tr.logWarningOdd { background-color:#FFE0D0; } +tr.logErrorEven { background-color:#FFEEDE; } +tr.logErrorOdd { background-color:#FFD0C0; } +tr.consoleTitle { background-color:#777777; color:White; font-weight:bold; } +td.smallLeft { font-size:7pt; font-weight: normal; text-align:left; vertical-align:top; } +td.smallRight { font-size:7pt; font-weight: normal; text-align:right; vertical-align:top; } +pre.console { border-color:#DDDDDD; border-style:dashed; border-width:thin; background-color:White;} +pre.stackTrace { border-color:#FF8686; border-style:dashed; border-width:thin; background-color:White;} +div.tooltip { border-width: 2;background-color: #dddddd; padding: 0;} +span.newFailure { color:#FF0000; font-size:7pt; font-weight: normal; text-align:left; vertical-align:super; font-weight:bold;} +span.fixed { color:#008F00; font-size:7pt; font-weight: normal; text-align:left; vertical-align:super; font-weight:bold;} +span.newTest { color:black; font-size:7pt; font-weight: normal; text-align:left; vertical-align:super; font-weight:bold;} +span.button { color:Navy; cursor:pointer; font-size:6.5pt; vertical-align:super; font-weight:normal;} diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/quickgraph.css.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/quickgraph.css.meta new file mode 100644 index 0000000..b880e21 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/quickgraph.css.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: a83b074158f104c93abeb3538cf86401 +DefaultImporter: + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/quickgraph.snk b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/quickgraph.snk new file mode 100755 index 0000000..a630ef5 Binary files /dev/null and b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/quickgraph.snk differ diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/quickgraph.snk.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/quickgraph.snk.meta new file mode 100644 index 0000000..3badac7 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/quickgraph.snk.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: 3b9c6297d313745c1bb9619217e797d6 +DefaultImporter: + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/report.js b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/report.js new file mode 100755 index 0000000..fa2780f --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/report.js @@ -0,0 +1,78 @@ +function toggle(toggleId, divId) +{ + var tog=document.getElementById(toggleId); + var div=document.getElementById(divId); + + if (tog.innerText == "[-]") + { + div.style.display = "none"; + tog.innerText = "[+]"; + } + else + { + div.style.display= "block"; + tog.innerText = "[-]"; + } +} + +function copyToClipboad(id) +{ + var el = document.getElementById(id); + window.clipboardData.setData( + "Text", + el.innerText + ); +} + +function mark(id) +{ + var element = document.getElementById(id); + + if (element.oldBackgroundColor == null) + { + element.oldBackgroundColor = element.style.backgroundColor; + element.style.backgroundColor = "#F0F0F0"; + } + else + { + element.style.backgroundColor = element.oldBackgroundColor; + element.style.oldBackgroundColor = null; + } +} + +var timerId = null; +var toolTipId = null; + +function showToolTip() +{ + toolTipId = this.tooltip; + document.onmousemove = checkEl; + checkToolTip(); +} + +function hideToolTip() +{ + var whichEl = document.all[toolTipId].style; + whichEl.visibility = "hidden"; + toolTipId = null; + + if (timerId) clearTimeout(timerId); + document.onmousemove = null; +} + +function checkToolTip() +{ + if (timerId) clearTimeout(timerID); + var left = event.clientX + document.body.scrollLeft; + var top = event.clientY + document.body.scrollTop + 20; + timerId = setTimeout("displayToolTip(" + left + ", " + top + ")", 300); +} + +function displayToolTip(left, top) +{ + document.onmousemove = null; + var whichEl = document.all[active].style; + whichEl.left = left; + whichEl.top = top; + whichEl.visibility = "visible"; +} \ No newline at end of file diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/report.js.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/report.js.meta new file mode 100644 index 0000000..90afc53 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/report.js.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d5d294ef3864744f29bc804b438bf83f +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/unit.banner.png b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/unit.banner.png new file mode 100755 index 0000000..26ccc99 Binary files /dev/null and b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/unit.banner.png differ diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/unit.banner.png.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/unit.banner.png.meta new file mode 100644 index 0000000..bfe969c --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/unit.banner.png.meta @@ -0,0 +1,46 @@ +fileFormatVersion: 2 +guid: bdbba7e14dc424f2ebcc0efa97d65ee3 +TextureImporter: + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + linearTexture: 0 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: -1 + mipBias: -1 + wrapMode: -1 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 0 + textureType: -1 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/unit.png b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/unit.png new file mode 100755 index 0000000..13fe0bd Binary files /dev/null and b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/unit.png differ diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/unit.png.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/unit.png.meta new file mode 100644 index 0000000..5d49c40 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/unit.png.meta @@ -0,0 +1,46 @@ +fileFormatVersion: 2 +guid: 49d172c24b15743fabda3f7296621b0d +TextureImporter: + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + linearTexture: 0 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: -1 + mipBias: -1 + wrapMode: -1 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 0 + textureType: -1 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/unittest.xslt b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/unittest.xslt new file mode 100755 index 0000000..e9b9c8f --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/unittest.xslt @@ -0,0 +1,159 @@ + + + + + + saved from url=(0027)http://blog.dotnetwiki.org/ + + + <xsl:value-of select="@EntryAssemblyLocation"/> Test Report + + + + +

+ + Test Report: + ,
+

+

+ + + () + +

+ + + + +
+ + + + + New failures: , + Fixed tests: , + Start Time: , + End Time: , + Duration: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + batchLog +
+

Log

+ + +
+
+ + + +

Assembly setup and teardown

+ + + + + + + +
+
+
+ + + a +

+ + + + , +

+
+ + + + + + + + + + + + + + + + + + +
FullName + +
Location + +
StartTime + +
StartTime + +
+
+ + + + +
+
\ No newline at end of file diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/unittest.xslt.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/unittest.xslt.meta new file mode 100644 index 0000000..c5cde16 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/unittest.xslt.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: 795dbb6ee89da46fd853f567c6012093 +DefaultImporter: + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/unittestframes.xslt b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/unittestframes.xslt new file mode 100755 index 0000000..accdd85 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/unittestframes.xslt @@ -0,0 +1,26 @@ + + + + + + saved from url=(0027)http://blog.dotnetwiki.org/ + + + <xsl:value-of select="@EntryAssemblyLocation"/> Test Report + + + + + + + + + +This document is designed to be viewed using the frames feature. +If you see this message, you are using a +non-frame-capable web client. + + + + + \ No newline at end of file diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/unittestframes.xslt.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/unittestframes.xslt.meta new file mode 100644 index 0000000..db770be --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/unittestframes.xslt.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: b5955fcabe74e4b7e869bc827213bf5f +DefaultImporter: + userData: diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/unittesthistory.xslt b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/unittesthistory.xslt new file mode 100755 index 0000000..a7bf8e5 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/unittesthistory.xslt @@ -0,0 +1,253 @@ + + + + + + + + + + saved from url=(0027)http://blog.dotnetwiki.org/ + + Test Summary + + + +

+ + Test Summary +

+ + + + + + + +
+ + + + + + + + + + + + + +
NameSuccess (average)Duration
+
+ + + + + + + + + #sec + + + + + + ( + + + + ) + + + + + + + + + + + + + + + + + + + + +

+ sec + +

+

+ + batchhistory + + Batch History

+
+ + + + + + + + + + + + + + + + + +
+ Time (yMMdd_hhmmss) + + Success + + + + Duration +
+ + + + + + + + + + +
+
+
+ + + + + + + 100.00 + + + + % + + + + + + + + + + + + + + + + + + +

+ + fixtureHistory + + Fixture history

+
+ + + + + + + + + + +
+ Name + Run count + Success average +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + +

+ + machines + + Machines +

+
+ + + + + + + + + +
+ Name + .NET + OS +
+
+
+ + + + + + + + + + +
+ + +
+ + + + + + + + +
+ +
\ No newline at end of file diff --git a/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/unittesthistory.xslt.meta b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/unittesthistory.xslt.meta new file mode 100644 index 0000000..1d7a368 --- /dev/null +++ b/src/Assets/quickgraph4unity/Editor/Tests/QuickGraph.Unit/unittesthistory.xslt.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: 70912547dd1294f86b83dd04b7807b6a +DefaultImporter: + userData: diff --git a/src/Assets/quickgraph4unity/License.txt b/src/Assets/quickgraph4unity/License.txt new file mode 100644 index 0000000..da3dc93 --- /dev/null +++ b/src/Assets/quickgraph4unity/License.txt @@ -0,0 +1,31 @@ +Microsoft Public License (Ms-PL) + +This license governs use of the accompanying software. If you use the software, you accept this license. If you do not accept the license, do not use the software. + +1. Definitions + +The terms "reproduce," "reproduction," "derivative works," and "distribution" have the same meaning here as under U.S. copyright law. + +A "contribution" is the original software, or any additions or changes to the software. + +A "contributor" is any person that distributes its contribution under this license. + +"Licensed patents" are a contributor's patent claims that read directly on its contribution. + +2. Grant of Rights + +(A) Copyright Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free copyright license to reproduce its contribution, prepare derivative works of its contribution, and distribute its contribution or any derivative works that you create. + +(B) Patent Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free license under its licensed patents to make, have made, use, sell, offer for sale, import, and/or otherwise dispose of its contribution in the software or derivative works of the contribution in the software. + +3. Conditions and Limitations + +(A) No Trademark License- This license does not grant you rights to use any contributors' name, logo, or trademarks. + +(B) If you bring a patent claim against any contributor over patents that you claim are infringed by the software, your patent license from such contributor to the software ends automatically. + +(C) If you distribute any portion of the software, you must retain all copyright, patent, trademark, and attribution notices that are present in the software. + +(D) If you distribute any portion of the software in source code form, you may do so only under this license by including a complete copy of this license with your distribution. If you distribute any portion of the software in compiled or object code form, you may only do so under a license that complies with this license. + +(E) The software is licensed "as-is." You bear the risk of using it. The contributors give no express warranties, guarantees or conditions. You may have additional consumer rights under your local laws which this license cannot change. To the extent permitted under your local laws, the contributors exclude the implied warranties of merchantability, fitness for a particular purpose and non-infringement. \ No newline at end of file diff --git a/src/Assets/quickgraph4unity/License.txt.meta b/src/Assets/quickgraph4unity/License.txt.meta new file mode 100644 index 0000000..c3f3872 --- /dev/null +++ b/src/Assets/quickgraph4unity/License.txt.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: e291f9596344f4a2986a7d4d0d809c58 +TextScriptImporter: + userData: diff --git a/src/Assets/quickgraph4unity/Runtime.meta b/src/Assets/quickgraph4unity/Runtime.meta new file mode 100644 index 0000000..67f5246 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: 6ec3abd72777142dab2310a2b92fc228 +folderAsset: yes +DefaultImporter: + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Data.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Data.meta new file mode 100644 index 0000000..d35c12b --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Data.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: c617cce6056bc4376a7447f1c2192355 +folderAsset: yes +DefaultImporter: + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Data/DataRelationEdge.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Data/DataRelationEdge.cs new file mode 100755 index 0000000..94efca5 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Data/DataRelationEdge.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Data; + +namespace QuickGraph.Data +{ + public sealed class DataRelationEdge : IEdge + { + private readonly DataRelation relation; + public DataRelationEdge(DataRelation relation) + { + if (relation == null) + throw new ArgumentNullException("relation"); + this.relation = relation; + } + + public DataRelation Relation + { + get { return this.relation; } + } + + public DataTable Source + { + get { return this.relation.ParentTable;} + } + + public DataTable Target + { + get { return this.relation.ChildTable; } + } + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Data/DataRelationEdge.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Data/DataRelationEdge.cs.meta new file mode 100644 index 0000000..268aedf --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Data/DataRelationEdge.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 39bd74b12b8fd4aaab376010d7d7e3ff +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Data/DataSetGraphPopulatorAlgorithm.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Data/DataSetGraphPopulatorAlgorithm.cs new file mode 100755 index 0000000..58121a6 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Data/DataSetGraphPopulatorAlgorithm.cs @@ -0,0 +1,40 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Data; +using QuickGraph.Algorithms; + +namespace QuickGraph.Data +{ + public sealed class DataSetGraphPopulatorAlgorithm : + AlgorithmBase> + { + private readonly DataSet dataSet; + + public DataSetGraphPopulatorAlgorithm( + IMutableVertexAndEdgeListGraph visitedGraph, + DataSet dataSet + ) + : base(visitedGraph) + { + if (dataSet == null) + throw new ArgumentNullException("dataSet"); + + this.dataSet = dataSet; + } + + public DataSet DataSet + { + get { return this.dataSet; } + } + + protected override void InternalCompute() + { + foreach (DataTable table in this.DataSet.Tables) + this.VisitedGraph.AddVertex(table); + + foreach (DataRelation relation in this.DataSet.Relations) + this.VisitedGraph.AddEdge(new DataRelationEdge(relation)); + } + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Data/DataSetGraphPopulatorAlgorithm.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Data/DataSetGraphPopulatorAlgorithm.cs.meta new file mode 100644 index 0000000..9ce1abb --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Data/DataSetGraphPopulatorAlgorithm.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 6a5a3e533069c4dd7a427a43d22629f8 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Data/Properties.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Data/Properties.meta new file mode 100644 index 0000000..cff9037 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Data/Properties.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: 47508c611e5bd46bcb2b68daadb64387 +folderAsset: yes +DefaultImporter: + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Data/Properties/AssemblyInfo.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Data/Properties/AssemblyInfo.cs new file mode 100755 index 0000000..c6d3569 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Data/Properties/AssemblyInfo.cs @@ -0,0 +1,19 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("QuickGraph.Data")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("dc10088a-bf22-4a42-b15e-47c9fd314f7a")] diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Data/Properties/AssemblyInfo.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Data/Properties/AssemblyInfo.cs.meta new file mode 100644 index 0000000..a22822d --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Data/Properties/AssemblyInfo.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 7c78b8f5644294dcaaaf1479fb4c63f8 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Data/QuickGraph.Data.csproj b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Data/QuickGraph.Data.csproj new file mode 100755 index 0000000..4ace50c --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Data/QuickGraph.Data.csproj @@ -0,0 +1,71 @@ + + + Debug + AnyCPU + 9.0.30729 + 2.0 + {960C14D1-EDBD-40E5-8AE6-25E311551B87} + Library + Properties + QuickGraph.Data + QuickGraph.Data + SAK + SAK + SAK + SAK + + + 2.0 + + + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + Off + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + Off + + + + + + + + + Properties\version.cs + + + + + + + + {A9A5C115-0680-44B3-A87E-5ECF4C93814E} + QuickGraph + + + + + + + + \ No newline at end of file diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Data/QuickGraph.Data.csproj.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Data/QuickGraph.Data.csproj.meta new file mode 100644 index 0000000..640b911 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Data/QuickGraph.Data.csproj.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: dbcae02b5a1cf438690d54dc79bc92c1 +DefaultImporter: + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Data/QuickGraph.Data.csproj.vspscc b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Data/QuickGraph.Data.csproj.vspscc new file mode 100755 index 0000000..feffdec --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Data/QuickGraph.Data.csproj.vspscc @@ -0,0 +1,10 @@ +"" +{ +"FILE_VERSION" = "9237" +"ENLISTMENT_CHOICE" = "NEVER" +"PROJECT_FILE_RELATIVE_PATH" = "" +"NUMBER_OF_EXCLUDED_FILES" = "0" +"ORIGINAL_PROJECT_FILE_PATH" = "" +"NUMBER_OF_NESTED_PROJECTS" = "0" +"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROVIDER" +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Data/QuickGraph.Data.csproj.vspscc.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Data/QuickGraph.Data.csproj.vspscc.meta new file mode 100644 index 0000000..e8db203 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Data/QuickGraph.Data.csproj.vspscc.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: 3ccc58af676ff4f1ea34e7fff536a03e +DefaultImporter: + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz.meta new file mode 100644 index 0000000..7bc6436 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: 017451d781c6845e2ab05c6728b2a7b5 +folderAsset: yes +DefaultImporter: + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/CondensatedGraphRenderer.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/CondensatedGraphRenderer.cs new file mode 100755 index 0000000..4addb7b --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/CondensatedGraphRenderer.cs @@ -0,0 +1,45 @@ +using System; +using System.IO; +using QuickGraph.Algorithms.Condensation; + +namespace QuickGraph.Graphviz +{ + public class CondensatedGraphRenderer : + GraphRendererBase> + where TEdge : IEdge + where TGraph : IMutableVertexAndEdgeListGraph, new() + { + public CondensatedGraphRenderer( + IVertexAndEdgeListGraph> visitedGraph) + :base(visitedGraph) + {} + + protected override void Initialize() + { + base.Initialize(); + this.Graphviz.FormatVertex+=new FormatVertexEventHandler(Graphviz_FormatVertex); + this.Graphviz.FormatEdge += new FormatEdgeEventHandler>(Graphviz_FormatEdge); + } + + + void Graphviz_FormatVertex(Object sender, FormatVertexEventArgs e) + { + StringWriter sw = new StringWriter(); + sw.WriteLine("{0}-{1}", e.Vertex.VertexCount, e.Vertex.EdgeCount); + foreach (var v in e.Vertex.Vertices) + sw.WriteLine(" {0}", v); + foreach(TEdge edge in e.Vertex.Edges) + sw.WriteLine(" {0}", edge); + e.VertexFormatter.Label = this.Graphviz.Escape(sw.ToString()); + } + + void Graphviz_FormatEdge(object sender, FormatEdgeEventArgs> e) + { + StringWriter sw = new StringWriter(); + sw.WriteLine("{0}", e.Edge.Edges.Count); + foreach (var edge in e.Edge.Edges) + sw.WriteLine(" {0}", edge); + e.EdgeFormatter.Label.Value = this.Graphviz.Escape(sw.ToString()); + } + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/CondensatedGraphRenderer.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/CondensatedGraphRenderer.cs.meta new file mode 100644 index 0000000..3dcd665 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/CondensatedGraphRenderer.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b33120b322cb246d3a9e11f9462403e4 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot.meta new file mode 100644 index 0000000..a537765 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: 2b8bfd4de5f6e4c3aa6129d46f386a62 +folderAsset: yes +DefaultImporter: + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizArrow.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizArrow.cs new file mode 100755 index 0000000..92fce1f --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizArrow.cs @@ -0,0 +1,91 @@ +namespace QuickGraph.Graphviz.Dot +{ + using System; + using System.IO; + + public class GraphvizArrow + { + private GraphvizArrowClipping clipping; + private GraphvizArrowFilling filling; + private GraphvizArrowShape shape; + + public GraphvizArrow(GraphvizArrowShape shape) + { + this.shape = shape; + this.clipping = GraphvizArrowClipping.None; + this.filling = GraphvizArrowFilling.Close; + } + + public GraphvizArrow(GraphvizArrowShape shape, GraphvizArrowClipping clip, GraphvizArrowFilling fill) + { + this.shape = shape; + this.clipping = clip; + this.filling = fill; + } + + public string ToDot() + { + using (StringWriter writer = new StringWriter()) + { + if (this.filling == GraphvizArrowFilling.Open) + { + writer.Write('o'); + } + switch (this.clipping) + { + case GraphvizArrowClipping.Left: + writer.Write('l'); + break; + + case GraphvizArrowClipping.Right: + writer.Write('r'); + break; + } + writer.Write(this.shape.ToString().ToLower()); + return writer.ToString(); + } + } + + public override string ToString() + { + return this.ToDot(); + } + + public GraphvizArrowClipping Clipping + { + get + { + return this.clipping; + } + set + { + this.clipping = value; + } + } + + public GraphvizArrowFilling Filling + { + get + { + return this.filling; + } + set + { + this.filling = value; + } + } + + public GraphvizArrowShape Shape + { + get + { + return this.shape; + } + set + { + this.shape = value; + } + } + } +} + diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizArrow.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizArrow.cs.meta new file mode 100644 index 0000000..e976a50 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizArrow.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: dfe1a8eaf409f4dbbab23a67ee7221bd +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizArrowClipping.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizArrowClipping.cs new file mode 100755 index 0000000..87b3fc6 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizArrowClipping.cs @@ -0,0 +1,12 @@ +namespace QuickGraph.Graphviz.Dot +{ + using System; + + public enum GraphvizArrowClipping + { + None, + Left, + Right + } +} + diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizArrowClipping.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizArrowClipping.cs.meta new file mode 100644 index 0000000..d6bb846 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizArrowClipping.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 324b91d72fde14a9a8d71d12583cb475 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizArrowFilling.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizArrowFilling.cs new file mode 100755 index 0000000..b03dc49 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizArrowFilling.cs @@ -0,0 +1,11 @@ +namespace QuickGraph.Graphviz.Dot +{ + using System; + + public enum GraphvizArrowFilling + { + Close, + Open + } +} + diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizArrowFilling.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizArrowFilling.cs.meta new file mode 100644 index 0000000..10d1a15 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizArrowFilling.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 3d3d040cfb7814349873c2fd3fd86fc4 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizArrowShape.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizArrowShape.cs new file mode 100755 index 0000000..58ccae5 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizArrowShape.cs @@ -0,0 +1,18 @@ +namespace QuickGraph.Graphviz.Dot +{ + using System; + + public enum GraphvizArrowShape + { + Box, + Crow, + Diamond, + Dot, + Inv, + None, + Normal, + Tee, + Vee + } +} + diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizArrowShape.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizArrowShape.cs.meta new file mode 100644 index 0000000..e6306fa --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizArrowShape.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: bd07ed306c32043c9a61a27a1c739281 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizClusterMode.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizClusterMode.cs new file mode 100755 index 0000000..1b96388 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizClusterMode.cs @@ -0,0 +1,12 @@ +namespace QuickGraph.Graphviz.Dot +{ + using System; + + public enum GraphvizClusterMode + { + Local, + Global, + None + } +} + diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizClusterMode.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizClusterMode.cs.meta new file mode 100644 index 0000000..97420d0 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizClusterMode.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d59e2dc9eb44c422189dfee09cd59d24 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizEdge.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizEdge.cs new file mode 100755 index 0000000..103bb6e --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizEdge.cs @@ -0,0 +1,361 @@ +namespace QuickGraph.Graphviz.Dot +{ + using System; + using System.Collections; + using System.Drawing; + using System.IO; + + public class GraphvizEdge + { + private string comment = null; + private GraphvizEdgeDirection dir = GraphvizEdgeDirection.Forward; + private System.Drawing.Font font = null; + private Color fontColor = Color.Black; + private GraphvizEdgeExtremity head = new GraphvizEdgeExtremity(true); + private GraphvizArrow headArrow = null; + private bool isConstrained = true; + private bool isDecorated = false; + private GraphvizEdgeLabel label = new GraphvizEdgeLabel(); + private GraphvizLayer layer = null; + private int minLength = 1; + private Color strokeColor = Color.Black; + private GraphvizEdgeStyle style = GraphvizEdgeStyle.Unspecified; + private GraphvizEdgeExtremity tail = new GraphvizEdgeExtremity(false); + private GraphvizArrow tailArrow = null; + private string tooltip = null; + private string url = null; + private double weight = 1; + + internal string GenerateDot(Hashtable pairs) + { + bool flag = false; + StringWriter writer = new StringWriter(); + foreach (DictionaryEntry entry in pairs) + { + if (flag) + { + writer.Write(", "); + } + else + { + flag = true; + } + if (entry.Value is string) + { + writer.Write("{0}=\"{1}\"", entry.Key.ToString(), entry.Value.ToString()); + continue; + } + if (entry.Value is GraphvizEdgeDirection) + { + writer.Write("{0}={1}", entry.Key.ToString(), ((GraphvizEdgeDirection) entry.Value).ToString().ToLower()); + continue; + } + if (entry.Value is GraphvizEdgeStyle) + { + writer.Write("{0}={1}", entry.Key.ToString(), ((GraphvizEdgeStyle) entry.Value).ToString().ToLower()); + continue; + } + if (entry.Value is Color) + { + Color color = (Color) entry.Value; + writer.Write("{0}=\"#{1}{2}{3}{4}\"", new object[] { entry.Key.ToString(), color.R.ToString("x2").ToUpper(), color.G.ToString("x2").ToUpper(), color.B.ToString("x2").ToUpper(), color.A.ToString("x2").ToUpper() }); + continue; + } + writer.Write(" {0}={1}", entry.Key.ToString(), entry.Value.ToString().ToLower()); + } + return writer.ToString(); + } + + public string ToDot() + { + Hashtable dic = new Hashtable(); + if (this.Comment != null) + { + dic["comment"] = this.Comment; + } + if (this.Dir != GraphvizEdgeDirection.Forward) + { + dic["dir"] = this.Dir.ToString().ToLower(); + } + if (this.Font != null) + { + dic["fontname"] = this.Font.Name; + dic["fontsize"] = this.Font.SizeInPoints; + } + if (this.FontColor != Color.Black) + { + dic["fontcolor"] = this.FontColor; + } + this.Head.AddParameters(dic); + if (this.HeadArrow != null) + { + dic["arrowhead"] = this.HeadArrow.ToDot(); + } + if (!this.IsConstrained) + { + dic["constraint"] = this.IsConstrained; + } + if (this.IsDecorated) + { + dic["decorate"] = this.IsDecorated; + } + this.Label.AddParameters(dic); + if (this.Layer != null) + { + dic["layer"] = this.Layer.Name; + } + if (this.MinLength != 1) + { + dic["minlen"] = this.MinLength; + } + if (this.StrokeColor != Color.Black) + { + dic["color"] = this.StrokeColor; + } + if (this.Style != GraphvizEdgeStyle.Unspecified) + { + dic["style"] = this.Style.ToString().ToLower(); + } + this.Tail.AddParameters(dic); + if (this.TailArrow != null) + { + dic["arrowtail"] = this.TailArrow.ToDot(); + } + if (this.ToolTip != null) + { + dic["tooltip"] = this.ToolTip; + } + if (this.Url != null) + { + dic["URL"] = this.Url; + } + if (this.Weight != 1) + { + dic["weight"] = this.Weight; + } + return this.GenerateDot(dic); + } + + public override string ToString() + { + return this.ToDot(); + } + + public string Comment + { + get + { + return this.comment; + } + set + { + this.comment = value; + } + } + + public GraphvizEdgeDirection Dir + { + get + { + return this.dir; + } + set + { + this.dir = value; + } + } + + public System.Drawing.Font Font + { + get + { + return this.font; + } + set + { + this.font = value; + } + } + + public Color FontColor + { + get + { + return this.fontColor; + } + set + { + this.fontColor = value; + } + } + + public GraphvizEdgeExtremity Head + { + get + { + return this.head; + } + set + { + this.head = value; + } + } + + public GraphvizArrow HeadArrow + { + get + { + return this.headArrow; + } + set + { + this.headArrow = value; + } + } + + public bool IsConstrained + { + get + { + return this.isConstrained; + } + set + { + this.isConstrained = value; + } + } + + public bool IsDecorated + { + get + { + return this.isDecorated; + } + set + { + this.isDecorated = value; + } + } + + public GraphvizEdgeLabel Label + { + get + { + return this.label; + } + set + { + this.label = value; + } + } + + public GraphvizLayer Layer + { + get + { + return this.layer; + } + set + { + this.layer = value; + } + } + + public int MinLength + { + get + { + return this.minLength; + } + set + { + this.minLength = value; + } + } + + public Color StrokeColor + { + get + { + return this.strokeColor; + } + set + { + this.strokeColor = value; + } + } + + public GraphvizEdgeStyle Style + { + get + { + return this.style; + } + set + { + this.style = value; + } + } + + public GraphvizEdgeExtremity Tail + { + get + { + return this.tail; + } + set + { + this.tail = value; + } + } + + public GraphvizArrow TailArrow + { + get + { + return this.tailArrow; + } + set + { + this.tailArrow = value; + } + } + + public string ToolTip + { + get + { + return this.tooltip; + } + set + { + this.tooltip = value; + } + } + + public string Url + { + get + { + return this.url; + } + set + { + this.url = value; + } + } + + public double Weight + { + get + { + return this.weight; + } + set + { + this.weight = value; + } + } + } +} + diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizEdge.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizEdge.cs.meta new file mode 100644 index 0000000..725017d --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizEdge.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 03e7be2a799e04f839881ecd901d48fb +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizEdgeDirection.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizEdgeDirection.cs new file mode 100755 index 0000000..46e8703 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizEdgeDirection.cs @@ -0,0 +1,13 @@ +namespace QuickGraph.Graphviz.Dot +{ + using System; + + public enum GraphvizEdgeDirection + { + None, + Forward, + Back, + Both + } +} + diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizEdgeDirection.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizEdgeDirection.cs.meta new file mode 100644 index 0000000..0b29ce0 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizEdgeDirection.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 76febed9b6457431f9d64a94f5230065 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizEdgeExtremity.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizEdgeExtremity.cs new file mode 100755 index 0000000..e3640c1 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizEdgeExtremity.cs @@ -0,0 +1,149 @@ +namespace QuickGraph.Graphviz.Dot +{ + using System; + using System.Collections; + + public class GraphvizEdgeExtremity + { + private bool isClipped; + private bool isHead; + private string label; + private string logical; + private string same; + private string tooltip; + private string url; + + public GraphvizEdgeExtremity(bool isHead) + { + this.isHead = isHead; + this.url = null; + this.isClipped = true; + this.label = null; + this.tooltip = null; + this.logical = null; + this.same = null; + } + + public void AddParameters(IDictionary dic) + { + if (dic == null) + { + throw new ArgumentNullException("dic"); + } + string text = null; + if (this.IsHead) + { + text = "head"; + } + else + { + text = "tail"; + } + if (this.Url != null) + { + dic.Add(text + "URL", this.Url); + } + if (!this.IsClipped) + { + dic.Add(text + "clip", this.IsClipped); + } + if (this.Label != null) + { + dic.Add(text + "label", this.Label); + } + if (this.ToolTip != null) + { + dic.Add(text + "tooltip", this.ToolTip); + } + if (this.Logical != null) + { + dic.Add("l" + text, this.Logical); + } + if (this.Same != null) + { + dic.Add("same" + text, this.Same); + } + } + + public bool IsClipped + { + get + { + return this.isClipped; + } + set + { + this.isClipped = value; + } + } + + public bool IsHead + { + get + { + return this.isHead; + } + } + + public string Label + { + get + { + return this.label; + } + set + { + this.label = value; + } + } + + public string Logical + { + get + { + return this.logical; + } + set + { + this.logical = value; + } + } + + public string Same + { + get + { + return this.same; + } + set + { + this.same = value; + } + } + + public string ToolTip + { + get + { + return this.tooltip; + } + set + { + this.tooltip = value; + } + } + + public string Url + { + get + { + return this.url; + } + set + { + this.url = value; + } + } + } +} + diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizEdgeExtremity.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizEdgeExtremity.cs.meta new file mode 100644 index 0000000..bfa04cc --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizEdgeExtremity.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e2a9f944591d745718fba2929655c8f3 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizEdgeLabel.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizEdgeLabel.cs new file mode 100755 index 0000000..f3b6e30 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizEdgeLabel.cs @@ -0,0 +1,114 @@ +namespace QuickGraph.Graphviz.Dot +{ + using System; + using System.Collections; + using System.Drawing; + + public class GraphvizEdgeLabel + { + private double angle = -25; + private double distance = 1; + private bool @float = true; + private System.Drawing.Font font = null; + private Color fontColor = Color.Black; + private string value = null; + + public void AddParameters(IDictionary dic) + { + if (this.Value != null) + { + dic["label"] = this.Value; + if (this.Angle != -25) + { + dic["labelangle"] = this.Angle; + } + if (this.Distance != 1) + { + dic["labeldistance"] = this.Distance; + } + if (!this.Float) + { + dic["labelfloat"] = this.Float; + } + if (this.Font != null) + { + dic["labelfontname"] = this.Font.Name; + dic["labelfontsize"] = this.Font.SizeInPoints; + } + } + } + + public double Angle + { + get + { + return this.angle; + } + set + { + this.angle = value; + } + } + + public double Distance + { + get + { + return this.distance; + } + set + { + this.distance = value; + } + } + + public bool Float + { + get + { + return this.@float; + } + set + { + this.@float = value; + } + } + + public System.Drawing.Font Font + { + get + { + return this.font; + } + set + { + this.font = value; + } + } + + public Color FontColor + { + get + { + return this.fontColor; + } + set + { + this.fontColor = value; + } + } + + public string Value + { + get + { + return this.value; + } + set + { + this.value = value; + } + } + } +} + diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizEdgeLabel.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizEdgeLabel.cs.meta new file mode 100644 index 0000000..faa4d13 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizEdgeLabel.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: deadb86f1415f4bc9a22d738f4a1fab6 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizEdgeStyle.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizEdgeStyle.cs new file mode 100755 index 0000000..8804f40 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizEdgeStyle.cs @@ -0,0 +1,15 @@ +namespace QuickGraph.Graphviz.Dot +{ + using System; + + public enum GraphvizEdgeStyle + { + Unspecified, + Invis, + Dashed, + Dotted, + Bold, + Solid + } +} + diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizEdgeStyle.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizEdgeStyle.cs.meta new file mode 100644 index 0000000..d4f5f8b --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizEdgeStyle.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 2cdc83e1727a9415c9d224a90224ee76 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizGraph.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizGraph.cs new file mode 100755 index 0000000..d1f499b --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizGraph.cs @@ -0,0 +1,616 @@ +namespace QuickGraph.Graphviz.Dot +{ + using System; + using System.Collections; + using System.Drawing; + using System.IO; + + public class GraphvizGraph + { + private Color backgroundColor = Color.White; + private GraphvizClusterMode clusterRank = GraphvizClusterMode.Local; + private string comment = null; + private System.Drawing.Font font = null; + private Color fontColor = Color.Black; + private bool isCentered = false; + private bool isCompounded = false; + private bool isConcentrated = false; + private bool isLandscape = false; + private bool isNormalized = false; + private bool isReMinCross = false; + private string label = null; + private GraphvizLabelJustification labelJustification = GraphvizLabelJustification.C; + private GraphvizLabelLocation labelLocation = GraphvizLabelLocation.B; + private readonly GraphvizLayerCollection layers = new GraphvizLayerCollection(); + private double mcLimit = 1; + private double nodeSeparation = 0.25; + private int nsLimit = -1; + private int nsLimit1 = -1; + private GraphvizOutputMode outputOrder = GraphvizOutputMode.BreadthFirst; + private GraphvizPageDirection pageDirection = GraphvizPageDirection.BL; + private System.Drawing.Size pageSize = new System.Drawing.Size(0, 0); + private double quantum = 0; + private GraphvizRankDirection rankDirection = GraphvizRankDirection.TB; + private double rankSeparation = 0.5; + private GraphvizRatioMode ratio = GraphvizRatioMode.Auto; + private double resolution = 0.96; + private int rotate = 0; + private int samplePoints = 8; + private int searchSize = 30; + private System.Drawing.Size size = new System.Drawing.Size(0, 0); + private string styleSheet = null; + private string url = null; + + internal string GenerateDot(Hashtable pairs) + { + bool flag = false; + StringWriter writer = new StringWriter(); + foreach (DictionaryEntry entry in pairs) + { + if (flag) + { + writer.Write(", "); + } + else + { + flag = true; + } + if (entry.Value is string) + { + writer.Write("{0}=\"{1}\"", entry.Key.ToString(), entry.Value.ToString()); + continue; + } + if (entry.Value is Color) + { + Color color = (Color) entry.Value; + writer.Write("{0}=\"#{1}{2}{3}{4}\"", new object[] { entry.Key.ToString(), color.R.ToString("x2").ToUpper(), color.G.ToString("x2").ToUpper(), color.B.ToString("x2").ToUpper(), color.A.ToString("x2").ToUpper() }); + continue; + } + if ((entry.Value is GraphvizRankDirection) || (entry.Value is GraphvizPageDirection)) + { + writer.Write("{0}={1};", entry.Key.ToString(), entry.Value.ToString()); + continue; + } + writer.Write(" {0}={1}", entry.Key.ToString(), entry.Value.ToString().ToLower()); + } + return writer.ToString(); + } + + public string ToDot() + { + Hashtable pairs = new Hashtable(); + if (this.Url != null) + { + pairs["URL"] = this.Url; + } + if (this.BackgroundColor != Color.White) + { + pairs["bgcolor"] = this.BackgroundColor; + } + if (this.IsCentered) + { + pairs["center"] = true; + } + if (this.ClusterRank != GraphvizClusterMode.Local) + { + pairs["clusterrank"] = this.ClusterRank.ToString().ToLower(); + } + if (this.Comment != null) + { + pairs["comment"] = this.Comment; + } + if (this.IsCompounded) + { + pairs["compound"] = this.IsCompounded; + } + if (this.IsConcentrated) + { + pairs["concentrated"] = this.IsConcentrated; + } + if (this.Font != null) + { + pairs["fontname"] = this.Font.Name; + pairs["fontsize"] = this.Font.SizeInPoints; + } + if (this.FontColor != Color.Black) + { + pairs["fontcolor"] = this.FontColor; + } + if (this.Label != null) + { + pairs["label"] = this.Label; + } + if (this.LabelJustification != GraphvizLabelJustification.C) + { + pairs["labeljust"] = this.LabelJustification.ToString().ToLower(); + } + if (this.LabelLocation != GraphvizLabelLocation.B) + { + pairs["labelloc"] = this.LabelLocation.ToString().ToLower(); + } + if (this.Layers.Count != 0) + { + pairs["layers"] = this.Layers.ToDot(); + } + if (this.McLimit != 1) + { + pairs["mclimit"] = this.McLimit; + } + if (this.NodeSeparation != 0.25) + { + pairs["nodesep"] = this.NodeSeparation; + } + if (this.IsNormalized) + { + pairs["normalize"] = this.IsNormalized; + } + if (this.NsLimit > 0) + { + pairs["nslimit"] = this.NsLimit; + } + if (this.NsLimit1 > 0) + { + pairs["nslimit1"] = this.NsLimit1; + } + if (this.OutputOrder != GraphvizOutputMode.BreadthFirst) + { + pairs["outputorder"] = this.OutputOrder.ToString().ToLower(); + } + if (!this.PageSize.IsEmpty) + { + pairs["page"] = string.Format("({0},{1})", this.PageSize.Width, this.PageSize.Height); + } + if (this.PageDirection != GraphvizPageDirection.BL) + { + pairs["pagedir"] = this.PageDirection.ToString().ToLower(); + } + if (this.Quantum > 0) + { + pairs["quantum"] = this.Quantum; + } + if (this.RankSeparation != 0.5) + { + pairs["ranksep"] = this.RankSeparation; + } + if (this.Ratio != GraphvizRatioMode.Auto) + { + pairs["ratio"] = this.Ratio.ToString().ToLower(); + } + if (this.IsReMinCross) + { + pairs["remincross"] = this.IsReMinCross; + } + if (this.Resolution != 0.96) + { + pairs["resolution"] = this.Resolution; + } + if (this.Rotate != 0) + { + pairs["rotate"] = this.Rotate; + } + else if (this.IsLandscape) + { + pairs["orientation"] = "[1L]*"; + } + if (this.SamplePoints != 8) + { + pairs["samplepoints"] = this.SamplePoints; + } + if (this.SearchSize != 30) + { + pairs["searchsize"] = this.SearchSize; + } + if (!this.Size.IsEmpty) + { + pairs["size"] = string.Format("({0},{1})", this.Size.Width, this.Size.Height); + } + if (this.StyleSheet != null) + { + pairs["stylesheet"] = this.StyleSheet; + } + if (this.RankDirection != GraphvizRankDirection.TB) + { + pairs["rankdir"] = this.RankDirection; + } + return this.GenerateDot(pairs); + } + + public override string ToString() + { + return this.ToDot(); + } + + public Color BackgroundColor + { + get + { + return this.backgroundColor; + } + set + { + this.backgroundColor = value; + } + } + + public GraphvizClusterMode ClusterRank + { + get + { + return this.clusterRank; + } + set + { + this.clusterRank = value; + } + } + + public string Comment + { + get + { + return this.comment; + } + set + { + this.comment = value; + } + } + + public System.Drawing.Font Font + { + get + { + return this.font; + } + set + { + this.font = value; + } + } + + public Color FontColor + { + get + { + return this.fontColor; + } + set + { + this.fontColor = value; + } + } + + public bool IsCentered + { + get + { + return this.isCentered; + } + set + { + this.isCentered = value; + } + } + + public bool IsCompounded + { + get + { + return this.isCompounded; + } + set + { + this.isCompounded = value; + } + } + + public bool IsConcentrated + { + get + { + return this.isConcentrated; + } + set + { + this.isConcentrated = value; + } + } + + public bool IsLandscape + { + get + { + return this.isLandscape; + } + set + { + this.isLandscape = value; + } + } + + public bool IsNormalized + { + get + { + return this.isNormalized; + } + set + { + this.isNormalized = value; + } + } + + public bool IsReMinCross + { + get + { + return this.isReMinCross; + } + set + { + this.isReMinCross = value; + } + } + + public string Label + { + get + { + return this.label; + } + set + { + this.label = value; + } + } + + public GraphvizLabelJustification LabelJustification + { + get + { + return this.labelJustification; + } + set + { + this.labelJustification = value; + } + } + + public GraphvizLabelLocation LabelLocation + { + get + { + return this.labelLocation; + } + set + { + this.labelLocation = value; + } + } + + public GraphvizLayerCollection Layers + { + get + { + return this.layers; + } + } + + public double McLimit + { + get + { + return this.mcLimit; + } + set + { + this.mcLimit = value; + } + } + + public double NodeSeparation + { + get + { + return this.nodeSeparation; + } + set + { + this.nodeSeparation = value; + } + } + + public int NsLimit + { + get + { + return this.nsLimit; + } + set + { + this.nsLimit = value; + } + } + + public int NsLimit1 + { + get + { + return this.nsLimit1; + } + set + { + this.nsLimit1 = value; + } + } + + public GraphvizOutputMode OutputOrder + { + get + { + return this.outputOrder; + } + set + { + this.outputOrder = value; + } + } + + public GraphvizPageDirection PageDirection + { + get + { + return this.pageDirection; + } + set + { + this.pageDirection = value; + } + } + + public System.Drawing.Size PageSize + { + get + { + return this.pageSize; + } + set + { + this.pageSize = value; + } + } + + public double Quantum + { + get + { + return this.quantum; + } + set + { + this.quantum = value; + } + } + + public GraphvizRankDirection RankDirection + { + get + { + return this.rankDirection; + } + set + { + this.rankDirection = value; + } + } + + public double RankSeparation + { + get + { + return this.rankSeparation; + } + set + { + this.rankSeparation = value; + } + } + + public GraphvizRatioMode Ratio + { + get + { + return this.ratio; + } + set + { + this.ratio = value; + } + } + + public double Resolution + { + get + { + return this.resolution; + } + set + { + this.resolution = value; + } + } + + public int Rotate + { + get + { + return this.rotate; + } + set + { + this.rotate = value; + } + } + + public int SamplePoints + { + get + { + return this.samplePoints; + } + set + { + this.samplePoints = value; + } + } + + public int SearchSize + { + get + { + return this.searchSize; + } + set + { + this.searchSize = value; + } + } + + public System.Drawing.Size Size + { + get + { + return this.size; + } + set + { + this.size = value; + } + } + + public string StyleSheet + { + get + { + return this.styleSheet; + } + set + { + this.styleSheet = value; + } + } + + public string Url + { + get + { + return this.url; + } + set + { + this.url = value; + } + } + } +} + diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizGraph.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizGraph.cs.meta new file mode 100644 index 0000000..f15cab7 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizGraph.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 6eccec881ba2845fdba888b9c573c476 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizImageType.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizImageType.cs new file mode 100755 index 0000000..e9a88df --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizImageType.cs @@ -0,0 +1,52 @@ +namespace QuickGraph.Graphviz.Dot +{ + using System; + using System.ComponentModel; + + public enum GraphvizImageType + { + [Description("Client-side imagemaps")] + Cmap = 6, + [Description("Figure format")] + Fig = 0, + [Description("Gd format")] + Gd = 1, + [Description("Gd2 format")] + Gd2 = 2, + [Description("GIF format")] + Gif = 3, + [Description("HP-GL/2 format")] + Hpgl = 4, + [Description("Server-side imagemaps")] + Imap = 5, + [Description("JPEG format")] + Jpeg = 7, + [Description("FrameMaker MIF format")] + Mif = 8, + [Description("MetaPost")] + Mp = 9, + [Description("PCL format")] + Pcl = 10, + [Description("PIC format")] + Pic = 11, + [Description("plain text format")] + PlainText = 12, + [Description("Portable Network Graphics format")] + Png = 13, + [Description("Postscript")] + Ps = 14, + [Description("PostScript for PDF")] + Ps2 = 15, + [Description("Scalable Vector Graphics")] + Svg = 0x10, + [Description("Scalable Vector Graphics, gzipped")] + Svgz = 0x11, + [Description("VRML")] + Vrml = 0x12, + [Description("Visual Thought format")] + Vtx = 0x13, + [Description("Wireless BitMap format")] + Wbmp = 20 + } +} + diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizImageType.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizImageType.cs.meta new file mode 100644 index 0000000..66cf2be --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizImageType.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 357e7b8455f214844beff6ae8c73dd8d +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizLabelJustification.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizLabelJustification.cs new file mode 100755 index 0000000..91423d4 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizLabelJustification.cs @@ -0,0 +1,12 @@ +namespace QuickGraph.Graphviz.Dot +{ + using System; + + public enum GraphvizLabelJustification + { + L, + R, + C + } +} + diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizLabelJustification.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizLabelJustification.cs.meta new file mode 100644 index 0000000..acb1dc3 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizLabelJustification.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b46c056b0a92244f7a13964fdaba69b4 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizLabelLocation.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizLabelLocation.cs new file mode 100755 index 0000000..a6bd802 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizLabelLocation.cs @@ -0,0 +1,11 @@ +namespace QuickGraph.Graphviz.Dot +{ + using System; + + public enum GraphvizLabelLocation + { + T, + B + } +} + diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizLabelLocation.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizLabelLocation.cs.meta new file mode 100644 index 0000000..ce6cf8d --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizLabelLocation.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e49b9dfdb1ddd47cc8db80ce9bf20ba5 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizLayer.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizLayer.cs new file mode 100755 index 0000000..5daa3f5 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizLayer.cs @@ -0,0 +1,35 @@ +namespace QuickGraph.Graphviz.Dot +{ + using System; + + public class GraphvizLayer + { + private string name; + + public GraphvizLayer(string name) + { + if ((name == null) || (name.Length == 0)) + { + throw new ArgumentNullException("name"); + } + if (name.Length == 0) + { + throw new ArgumentException("name is empty"); + } + this.name = name; + } + + public string Name + { + get + { + return this.name; + } + set + { + this.name = value; + } + } + } +} + diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizLayer.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizLayer.cs.meta new file mode 100644 index 0000000..55c9b3c --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizLayer.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 9b863f8cf92134466980f9d45d12b9ff +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizLayerCollection.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizLayerCollection.cs new file mode 100755 index 0000000..14cc593 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizLayerCollection.cs @@ -0,0 +1,72 @@ +namespace QuickGraph.Graphviz.Dot +{ + using System; + using System.IO; + using System.Reflection; + using System.Collections.ObjectModel; + + public class GraphvizLayerCollection : Collection + { + private string m_Separators = ":"; + + public GraphvizLayerCollection() + {} + + public GraphvizLayerCollection(GraphvizLayer[] items) + :base(items) + {} + + public GraphvizLayerCollection(GraphvizLayerCollection items) + :base(items) + {} + + public string ToDot() + { + if (base.Count == 0) + { + return null; + } + using (StringWriter writer = new StringWriter()) + { + writer.Write("layers=\""); + bool flag = false; + foreach (GraphvizLayer layer in this) + { + if (flag) + { + writer.Write(this.Separators); + } + else + { + flag = true; + } + writer.Write(layer.Name); + } + writer.WriteLine("\";"); + writer.WriteLine("layersep=\"{0}\"", this.Separators); + return writer.ToString(); + } + } + + public string Separators + { + get + { + return this.m_Separators; + } + set + { + if (value == null) + { + throw new ArgumentNullException("separator is null"); + } + if (value.Length == 0) + { + throw new ArgumentException("separator is empty"); + } + this.m_Separators = value; + } + } + } +} + diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizLayerCollection.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizLayerCollection.cs.meta new file mode 100644 index 0000000..0012731 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizLayerCollection.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 2a01c5b7be85a4170a69f3e97d7aa3ac +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizOutputMode.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizOutputMode.cs new file mode 100755 index 0000000..aa79e89 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizOutputMode.cs @@ -0,0 +1,12 @@ +namespace QuickGraph.Graphviz.Dot +{ + using System; + + public enum GraphvizOutputMode + { + BreadthFirst, + NodesFirst, + EdgesFirst + } +} + diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizOutputMode.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizOutputMode.cs.meta new file mode 100644 index 0000000..1741ba9 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizOutputMode.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ed23e5418aede44d995a4dd54f49e7cd +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizPageDirection.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizPageDirection.cs new file mode 100755 index 0000000..8e3a19e --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizPageDirection.cs @@ -0,0 +1,17 @@ +namespace QuickGraph.Graphviz.Dot +{ + using System; + + public enum GraphvizPageDirection + { + BL, + BR, + TL, + TR, + RB, + RT, + LB, + LT + } +} + diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizPageDirection.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizPageDirection.cs.meta new file mode 100644 index 0000000..1c2753c --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizPageDirection.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 3b3677c5b03c949ec9943343e74e6ca9 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizRankDirection.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizRankDirection.cs new file mode 100755 index 0000000..9d673de --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizRankDirection.cs @@ -0,0 +1,11 @@ +namespace QuickGraph.Graphviz.Dot +{ + using System; + + public enum GraphvizRankDirection + { + LR, + TB + } +} + diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizRankDirection.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizRankDirection.cs.meta new file mode 100644 index 0000000..86f85cb --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizRankDirection.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 0c464faf3822845af934718e48bd1c19 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizRatioMode.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizRatioMode.cs new file mode 100755 index 0000000..85211e7 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizRatioMode.cs @@ -0,0 +1,12 @@ +namespace QuickGraph.Graphviz.Dot +{ + using System; + + public enum GraphvizRatioMode + { + Fill, + Compress, + Auto + } +} + diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizRatioMode.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizRatioMode.cs.meta new file mode 100644 index 0000000..2782c57 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizRatioMode.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 34d7b75ac4a9f4097b6a3cbd43341393 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizRecord.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizRecord.cs new file mode 100755 index 0000000..6d0c30f --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizRecord.cs @@ -0,0 +1,45 @@ +namespace QuickGraph.Graphviz.Dot +{ + using System; + using System.Text; + + public class GraphvizRecord + { + private readonly GraphvizRecordCellCollection cells = new GraphvizRecordCellCollection(); + + public string ToDot() + { + if (this.Cells.Count == 0) + { + return ""; + } + StringBuilder builder = new StringBuilder(); + bool flag = false; + foreach (GraphvizRecordCell cell in this.Cells) + { + if (flag) + { + builder.AppendFormat(" | {0}", cell.ToDot()); + continue; + } + builder.Append(cell.ToDot()); + flag = true; + } + return builder.ToString(); + } + + public override string ToString() + { + return this.ToDot(); + } + + public GraphvizRecordCellCollection Cells + { + get + { + return this.cells; + } + } + } +} + diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizRecord.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizRecord.cs.meta new file mode 100644 index 0000000..ed5d523 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizRecord.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: c3d48b75b0d43446f9be7aed61a13be3 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizRecordCell.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizRecordCell.cs new file mode 100755 index 0000000..aaaa510 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizRecordCell.cs @@ -0,0 +1,113 @@ +namespace QuickGraph.Graphviz.Dot +{ + using System; + using System.Text; + + public class GraphvizRecordCell + { + private readonly GraphvizRecordCellCollection cells = new GraphvizRecordCellCollection(); + private GraphvizRecordEscaper escaper = new GraphvizRecordEscaper(); + private string port = null; + private string text = null; + + public string ToDot() + { + StringBuilder builder = new StringBuilder(); + if (this.HasPort) + { + builder.AppendFormat("<{0}> ", this.Escaper.Escape(this.Port)); + } + if (this.HasText) + { + builder.AppendFormat("{0}", this.Escaper.Escape(this.Text)); + } + if (this.Cells.Count > 0) + { + builder.Append(" { "); + bool flag = false; + foreach (GraphvizRecordCell cell in this.Cells) + { + if (flag) + { + builder.AppendFormat(" | {0}", cell.ToDot()); + continue; + } + builder.Append(cell.ToDot()); + flag = true; + } + builder.Append(" } "); + } + return builder.ToString(); + } + + public override string ToString() + { + return this.ToDot(); + } + + public GraphvizRecordCellCollection Cells + { + get + { + return this.cells; + } + } + + protected GraphvizRecordEscaper Escaper + { + get + { + return this.escaper; + } + } + + public bool HasPort + { + get + { + if (this.Port != null) + { + return (this.Port.Length > 0); + } + return false; + } + } + + public bool HasText + { + get + { + if (this.text != null) + { + return (this.text.Length > 0); + } + return false; + } + } + + public string Port + { + get + { + return this.port; + } + set + { + this.port = value; + } + } + + public string Text + { + get + { + return this.text; + } + set + { + this.text = value; + } + } + } +} + diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizRecordCell.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizRecordCell.cs.meta new file mode 100644 index 0000000..4bb21e8 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizRecordCell.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 1073b5222cbcb4774b9514be3e6c77fb +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizRecordCellCollection.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizRecordCellCollection.cs new file mode 100755 index 0000000..3498d2d --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizRecordCellCollection.cs @@ -0,0 +1,21 @@ +namespace QuickGraph.Graphviz.Dot +{ + using System; + using System.Reflection; + using System.Collections.ObjectModel; + + public sealed class GraphvizRecordCellCollection : Collection + { + public GraphvizRecordCellCollection() + {} + + public GraphvizRecordCellCollection(GraphvizRecordCell[] items) + :base(items) + {} + + public GraphvizRecordCellCollection(GraphvizRecordCellCollection items) + :base(items) + {} + } +} + diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizRecordCellCollection.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizRecordCellCollection.cs.meta new file mode 100644 index 0000000..53d0352 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizRecordCellCollection.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 5893afdcdc59047b2a1a138a2c634efa +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizRecordEscaper.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizRecordEscaper.cs new file mode 100755 index 0000000..8b1ae05 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizRecordEscaper.cs @@ -0,0 +1,29 @@ +namespace QuickGraph.Graphviz.Dot +{ + using System; + using System.Text.RegularExpressions; + + public sealed class GraphvizRecordEscaper + { + private Regex escapeRegExp = new Regex("(?\\n)|(?\\[|\\]|\\||<|>|\"| )", RegexOptions.Compiled | RegexOptions.ExplicitCapture | RegexOptions.Multiline); + + public string Escape(string text) + { + if (text == null) + { + throw new ArgumentNullException("text"); + } + return this.escapeRegExp.Replace(text, new System.Text.RegularExpressions.MatchEvaluator(this.MatchEvaluator)); + } + + public string MatchEvaluator(Match m) + { + if (m.Groups["Common"] != null) + { + return string.Format(@"\{0}", m.Value); + } + return @"\n"; + } + } +} + diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizRecordEscaper.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizRecordEscaper.cs.meta new file mode 100644 index 0000000..9c4a9dd --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizRecordEscaper.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 63f78a066da214d84ae8a23a83de6d0b +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizVertex.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizVertex.cs new file mode 100755 index 0000000..dece249 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizVertex.cs @@ -0,0 +1,487 @@ +namespace QuickGraph.Graphviz.Dot +{ + using System; + using System.Collections; + using System.Drawing; + using System.IO; + + public class GraphvizVertex + { + private string bottomLabel = null; + private string comment = null; + private double distorsion = 0; + private Color fillColor = Color.White; + private bool fixedSize = false; + private System.Drawing.Font font = null; + private Color fontColor = Color.Black; + private string group = null; + private string label = null; + private GraphvizLayer layer = null; + private double orientation = 0; + private int peripheries = -1; + private GraphvizRecord record = new GraphvizRecord(); + private bool regular = false; + private GraphvizVertexShape shape = GraphvizVertexShape.Unspecified; + private int sides = 4; + private SizeF size = new SizeF(0f, 0f); + private double skew = 0; + private Color strokeColor = Color.Black; + private GraphvizVertexStyle style = GraphvizVertexStyle.Unspecified; + private string toolTip = null; + private string topLabel = null; + private string url = null; + private double z = -1; + + internal string GenerateDot(Hashtable pairs) + { + bool flag = false; + StringWriter writer = new StringWriter(); + foreach (DictionaryEntry entry in pairs) + { + if (flag) + { + writer.Write(", "); + } + else + { + flag = true; + } + if (entry.Value is string) + { + writer.Write("{0}=\"{1}\"", entry.Key.ToString(), entry.Value.ToString()); + continue; + } + if (entry.Value is GraphvizVertexShape) + { + writer.Write("{0}={1}", entry.Key.ToString(), ((GraphvizVertexShape) entry.Value).ToString().ToLower()); + continue; + } + if (entry.Value is GraphvizVertexStyle) + { + writer.Write("{0}={1}", entry.Key.ToString(), ((GraphvizVertexStyle) entry.Value).ToString().ToLower()); + continue; + } + if (entry.Value is Color) + { + Color color = (Color) entry.Value; + writer.Write("{0}=\"#{1}{2}{3}{4}\"", new object[] { entry.Key.ToString(), color.R.ToString("x2").ToUpper(), color.G.ToString("x2").ToUpper(), color.B.ToString("x2").ToUpper(), color.A.ToString("x2").ToUpper() }); + continue; + } + if (entry.Value is GraphvizRecord) + { + writer.WriteLine("{0}=\"{1}\"", entry.Key.ToString(), ((GraphvizRecord) entry.Value).ToDot()); + continue; + } + writer.Write(" {0}={1}", entry.Key.ToString(), entry.Value.ToString().ToLower()); + } + return writer.ToString(); + } + + public string ToDot() + { + Hashtable pairs = new Hashtable(); + if (this.Font != null) + { + pairs["fontname"] = this.Font.Name; + pairs["fontsize"] = this.Font.SizeInPoints; + } + if (this.FontColor != Color.Black) + { + pairs["fontcolor"] = this.FontColor; + } + if (this.Shape != GraphvizVertexShape.Unspecified) + { + pairs["shape"] = this.Shape; + } + if (this.Style != GraphvizVertexStyle.Unspecified) + { + pairs["style"] = this.Style; + } + if (this.Shape == GraphvizVertexShape.Record) + { + pairs["label"] = this.Record; + } + else if (this.Label != null) + { + pairs["label"] = this.Label; + } + if (this.FixedSize) + { + pairs["fixedsize"] = true; + if (this.Size.Height > 0f) + { + pairs["height"] = this.Size.Height; + } + if (this.Size.Width > 0f) + { + pairs["width"] = this.Size.Width; + } + } + if (this.StrokeColor != Color.Black) + { + pairs["color"] = this.StrokeColor; + } + if (this.FillColor != Color.White) + { + pairs["fillcolor"] = this.FillColor; + } + if (this.Regular) + { + pairs["regular"] = this.Regular; + } + if (this.Url != null) + { + pairs["URL"] = this.Url; + } + if (this.ToolTip != null) + { + pairs["tooltip"] = this.ToolTip; + } + if (this.Comment != null) + { + pairs["comment"] = this.Comment; + } + if (this.Group != null) + { + pairs["group"] = this.Group; + } + if (this.Layer != null) + { + pairs["layer"] = this.Layer.Name; + } + if (this.Orientation > 0) + { + pairs["orientation"] = this.Orientation; + } + if (this.Peripheries >= 0) + { + pairs["peripheries"] = this.Peripheries; + } + if (this.Z > 0) + { + pairs["z"] = this.Z; + } + if (((this.Style == GraphvizVertexStyle.Diagonals) || (this.Shape == GraphvizVertexShape.MCircle)) || ((this.Shape == GraphvizVertexShape.MDiamond) || (this.Shape == GraphvizVertexShape.MSquare))) + { + if (this.TopLabel != null) + { + pairs["toplabel"] = this.TopLabel; + } + if (this.BottomLabel != null) + { + pairs["bottomlable"] = this.BottomLabel; + } + } + if (this.Shape == GraphvizVertexShape.Polygon) + { + if (this.Sides != 0) + { + pairs["sides"] = this.Sides; + } + if (this.Skew != 0) + { + pairs["skew"] = this.Skew; + } + if (this.Distorsion != 0) + { + pairs["distorsion"] = this.Distorsion; + } + } + return this.GenerateDot(pairs); + } + + public override string ToString() + { + return this.ToDot(); + } + + public string BottomLabel + { + get + { + return this.bottomLabel; + } + set + { + this.bottomLabel = value; + } + } + + public string Comment + { + get + { + return this.comment; + } + set + { + this.comment = value; + } + } + + public double Distorsion + { + get + { + return this.distorsion; + } + set + { + this.distorsion = value; + } + } + + public Color FillColor + { + get + { + return this.fillColor; + } + set + { + this.fillColor = value; + } + } + + public bool FixedSize + { + get + { + return this.fixedSize; + } + set + { + this.fixedSize = value; + } + } + + public System.Drawing.Font Font + { + get + { + return this.font; + } + set + { + this.font = value; + } + } + + public Color FontColor + { + get + { + return this.fontColor; + } + set + { + this.fontColor = value; + } + } + + public string Group + { + get + { + return this.group; + } + set + { + this.group = value; + } + } + + public string Label + { + get + { + return this.label; + } + set + { + this.label = value; + } + } + + public GraphvizLayer Layer + { + get + { + return this.layer; + } + set + { + this.layer = value; + } + } + + public double Orientation + { + get + { + return this.orientation; + } + set + { + this.orientation = value; + } + } + + public int Peripheries + { + get + { + return this.peripheries; + } + set + { + this.peripheries = value; + } + } + + public GraphvizRecord Record + { + get + { + return this.record; + } + set + { + this.record = value; + } + } + + public bool Regular + { + get + { + return this.regular; + } + set + { + this.regular = value; + } + } + + public GraphvizVertexShape Shape + { + get + { + return this.shape; + } + set + { + this.shape = value; + } + } + + public int Sides + { + get + { + return this.sides; + } + set + { + this.sides = value; + } + } + + public SizeF Size + { + get + { + return this.size; + } + set + { + this.size = value; + } + } + + public double Skew + { + get + { + return this.skew; + } + set + { + this.skew = value; + } + } + + public Color StrokeColor + { + get + { + return this.strokeColor; + } + set + { + this.strokeColor = value; + } + } + + public GraphvizVertexStyle Style + { + get + { + return this.style; + } + set + { + this.style = value; + } + } + + public string ToolTip + { + get + { + return this.toolTip; + } + set + { + this.toolTip = value; + } + } + + public string TopLabel + { + get + { + return this.topLabel; + } + set + { + this.topLabel = value; + } + } + + public string Url + { + get + { + return this.url; + } + set + { + this.url = value; + } + } + + public double Z + { + get + { + return this.z; + } + set + { + this.z = value; + } + } + } +} + diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizVertex.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizVertex.cs.meta new file mode 100644 index 0000000..af7ff5f --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizVertex.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 894af1cb17e7b4970b163fb493fdd1b8 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizVertexShape.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizVertexShape.cs new file mode 100755 index 0000000..cda007a --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizVertexShape.cs @@ -0,0 +1,38 @@ +namespace QuickGraph.Graphviz.Dot +{ + using System; + + public enum GraphvizVertexShape + { + Unspecified, + Box, + Polygon, + Ellipse, + Circle, + Point, + Egg, + Triangle, + Plaintext, + Diamond, + Trapezium, + Parallelogram, + House, + Pentagon, + Hexagon, + Septagon, + Octagon, + DoubleCircle, + DoubleOctagon, + TripleOctagon, + InvTriangle, + InvTrapezium, + InvHouse, + MDiamond, + MSquare, + MCircle, + Rect, + Rectangle, + Record + } +} + diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizVertexShape.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizVertexShape.cs.meta new file mode 100644 index 0000000..987a313 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizVertexShape.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 5748259e4140c46febee177b59066283 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizVertexStyle.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizVertexStyle.cs new file mode 100755 index 0000000..d47dd43 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizVertexStyle.cs @@ -0,0 +1,18 @@ +namespace QuickGraph.Graphviz.Dot +{ + using System; + + public enum GraphvizVertexStyle + { + Unspecified, + Filled, + Diagonals, + Rounded, + Invis, + Dashed, + Dotted, + Bold, + Solid + } +} + diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizVertexStyle.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizVertexStyle.cs.meta new file mode 100644 index 0000000..6f7ae56 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/Dot/GraphvizVertexStyle.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 9d0ca4736d3cf46e6a81afe352df990e +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/EdgeMergeCondensatedGraphRenderer.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/EdgeMergeCondensatedGraphRenderer.cs new file mode 100755 index 0000000..aa9f761 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/EdgeMergeCondensatedGraphRenderer.cs @@ -0,0 +1,37 @@ +using System; +using System.IO; +using QuickGraph.Algorithms.Condensation; + +namespace QuickGraph.Graphviz +{ + public class EdgeMergeCondensatedGraphRenderer : + GraphRendererBase> + where TEdge : IEdge + { + public EdgeMergeCondensatedGraphRenderer( + IVertexAndEdgeListGraph> visitedGraph) + :base(visitedGraph) + { } + + protected override void Initialize() + { + base.Initialize(); + this.Graphviz.FormatVertex += new FormatVertexEventHandler(Graphviz_FormatVertex); + this.Graphviz.FormatEdge += new FormatEdgeEventHandler>(Graphviz_FormatEdge); + } + + void Graphviz_FormatEdge(object sender, FormatEdgeEventArgs> e) + { + StringWriter sw = new StringWriter(); + sw.WriteLine("{0}", e.Edge.Edges.Count); + foreach (var edge in e.Edge.Edges) + sw.WriteLine(" {0}", edge); + e.EdgeFormatter.Label.Value = this.Graphviz.Escape(sw.ToString()); + } + + void Graphviz_FormatVertex(Object sender, FormatVertexEventArgs e) + { + e.VertexFormatter.Label = e.Vertex.ToString(); + } + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/EdgeMergeCondensatedGraphRenderer.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/EdgeMergeCondensatedGraphRenderer.cs.meta new file mode 100644 index 0000000..91106db --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/EdgeMergeCondensatedGraphRenderer.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e9a64c9ffbdad4f17b4b2fcc05b18674 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/FileDotEngine.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/FileDotEngine.cs new file mode 100755 index 0000000..2400145 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/FileDotEngine.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Text; +using QuickGraph.Graphviz.Dot; +using System.IO; + +namespace QuickGraph.Graphviz +{ + /// + /// Default dot engine implementation, writes dot code to disk + /// + public sealed class FileDotEngine : IDotEngine + { + public string Run(GraphvizImageType imageType, string dot, string outputFileName) + { + string output = outputFileName + ".dot"; + File.WriteAllText(output, dot); + return output; + } + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/FileDotEngine.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/FileDotEngine.cs.meta new file mode 100644 index 0000000..dbbb207 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/FileDotEngine.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 0750f6e22b0394f039345116b3ff2588 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/FormatEdgeEventArgs.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/FormatEdgeEventArgs.cs new file mode 100755 index 0000000..53585b2 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/FormatEdgeEventArgs.cs @@ -0,0 +1,35 @@ +using System; +using QuickGraph.Graphviz.Dot; + +namespace QuickGraph.Graphviz +{ + public sealed class FormatEdgeEventArgs : EdgeEventArgs + where E : IEdge + { + private GraphvizEdge edgeFormatter; + + public FormatEdgeEventArgs(GraphvizEdge edgeFormatter, E e) + : base(e) + { + if (edgeFormatter == null) + throw new ArgumentNullException("edgeFormatter"); + this.edgeFormatter = edgeFormatter; + } + + /// + /// Edge formatter + /// + public GraphvizEdge EdgeFormatter + { + get + { + return edgeFormatter; + } + } + } + + public delegate void FormatEdgeEventHandler( + object sender, + FormatEdgeEventArgs e) + where TEdge : IEdge; +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/FormatEdgeEventArgs.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/FormatEdgeEventArgs.cs.meta new file mode 100644 index 0000000..b46cfd3 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/FormatEdgeEventArgs.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 4a975a28380cd424f8c71ec9eb987cca +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/FormatVertexEventArgs.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/FormatVertexEventArgs.cs new file mode 100755 index 0000000..dd542cc --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/FormatVertexEventArgs.cs @@ -0,0 +1,30 @@ +using System; +using QuickGraph.Graphviz.Dot; + +namespace QuickGraph.Graphviz +{ + public sealed class FormatVertexEventArgs : VertexEventArgs + { + private GraphvizVertex vertexFormatter; + + public FormatVertexEventArgs(GraphvizVertex vertexFormatter, V v) + : base(v) + { + if (vertexFormatter == null) + throw new ArgumentNullException("vertexFormatter"); + this.vertexFormatter = vertexFormatter; + } + + public GraphvizVertex VertexFormatter + { + get + { + return vertexFormatter; + } + } + } + + public delegate void FormatVertexEventHandler( + Object sender, + FormatVertexEventArgs e); +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/FormatVertexEventArgs.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/FormatVertexEventArgs.cs.meta new file mode 100644 index 0000000..ff72aac --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/FormatVertexEventArgs.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 607ce1dc3ac0343459fc883904f63155 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/GraphRendererBase.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/GraphRendererBase.cs new file mode 100755 index 0000000..4eafb11 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/GraphRendererBase.cs @@ -0,0 +1,44 @@ +using System; +using System.Drawing; +using QuickGraph.Graphviz.Dot; + +namespace QuickGraph.Graphviz +{ + public abstract class GraphRendererBase + where TEdge : IEdge + { + private GraphvizAlgorithm graphviz; + + public GraphRendererBase( + IVertexAndEdgeSet visitedGraph) + { + this.graphviz = new GraphvizAlgorithm(visitedGraph); + this.Initialize(); + } + + protected virtual void Initialize() + { + this.graphviz.CommonVertexFormat.Style = GraphvizVertexStyle.Filled; + this.graphviz.CommonVertexFormat.FillColor = System.Drawing.Color.LightYellow; + this.graphviz.CommonVertexFormat.Font = new System.Drawing.Font("Tahoma", 8.25F); + this.graphviz.CommonVertexFormat.Shape = GraphvizVertexShape.Box; + + this.graphviz.CommonEdgeFormat.Font = new System.Drawing.Font("Tahoma", 8.25F); + } + + public GraphvizAlgorithm Graphviz + { + get { return this.graphviz; } + } + + public IVertexAndEdgeSet VisitedGraph + { + get { return this.graphviz.VisitedGraph; } + } + + public string Generate(IDotEngine dot, string fileName) + { + return this.graphviz.Generate(dot, fileName); + } + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/GraphRendererBase.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/GraphRendererBase.cs.meta new file mode 100644 index 0000000..55376ff --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/GraphRendererBase.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 20fe7f72aa5b44d56a76dfb99e42b2f7 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/GraphvizAlgorithm.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/GraphvizAlgorithm.cs new file mode 100755 index 0000000..fc0551f --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/GraphvizAlgorithm.cs @@ -0,0 +1,236 @@ +using System; +using System.IO; +using System.Text.RegularExpressions; +using System.Collections.Generic; +using QuickGraph.Graphviz.Dot; + +namespace QuickGraph.Graphviz +{ + public sealed class GraphvizAlgorithm + where TEdge : IEdge + { + private readonly static Regex writeLineReplace = new Regex("\n", RegexOptions.Compiled | RegexOptions.Multiline); + private IVertexAndEdgeSet visitedGraph; + private StringWriter output; + private GraphvizImageType imageType; + private readonly Dictionary vertexIds = new Dictionary(); + + private GraphvizGraph graphFormat; + private GraphvizVertex commonVertexFormat; + private GraphvizEdge commonEdgeFormat; + + public GraphvizAlgorithm(IVertexAndEdgeSet g) + :this(g,".",GraphvizImageType.Png) + {} + + public GraphvizAlgorithm( + IVertexAndEdgeSet g, + String path, + GraphvizImageType imageType + ) + { + if (g == null) + throw new ArgumentNullException("g"); + if (path == null) + throw new ArgumentNullException("path"); + this.visitedGraph = g; + this.imageType = imageType; + this.graphFormat = new GraphvizGraph(); + this.commonVertexFormat = new GraphvizVertex(); + this.commonEdgeFormat = new GraphvizEdge(); + } + + public string Escape(string value) + { + return writeLineReplace.Replace(value, "\\n"); + } + + public GraphvizGraph GraphFormat + { + get + { + return graphFormat; + } + } + + public GraphvizVertex CommonVertexFormat + { + get + { + return commonVertexFormat; + } + } + + public GraphvizEdge CommonEdgeFormat + { + get + { + return commonEdgeFormat; + } + } + + public IVertexAndEdgeSet VisitedGraph + { + get + { + return visitedGraph; + } + set + { + if (value == null) + throw new ArgumentNullException("graph"); + visitedGraph = value; + } + } + + /// + /// Dot output stream. + /// + public StringWriter Output + { + get + { + return output; + } + } + + /// + /// Current image output type + /// + public GraphvizImageType ImageType + { + get + { + return imageType; + } + set + { + imageType = value; + } + } +/* + /// + /// Event raised while drawing a cluster + /// + public event FormatClusterEventHandler FormatCluster; + private void OnFormatCluster(IVertexAndEdgeListGraph cluster) + { + if (FormatCluster != null) + { + FormatClusterEventArgs args = + new FormatClusterEventArgs(cluster, new GraphvizGraph()); + FormatCluster(this, args); + string s = args.GraphFormat.ToDot(); + if (s.Length != 0) + Output.WriteLine(s); + } + } +*/ + public event FormatVertexEventHandler FormatVertex; + private void OnFormatVertex(TVertex v) + { + Output.Write("{0} ", this.vertexIds[v]); + if (FormatVertex != null) + { + GraphvizVertex gv = new GraphvizVertex(); + gv.Label = v.ToString(); + FormatVertex(this, new FormatVertexEventArgs(gv, v)); + + string s = gv.ToDot(); + if (s.Length != 0) + Output.Write("[{0}]", s); + } + Output.WriteLine(";"); + } + + public event FormatEdgeEventHandler FormatEdge; + private void OnFormatEdge(TEdge e) + { + if (FormatEdge != null) + { + GraphvizEdge ev = new GraphvizEdge(); + FormatEdge(this, new FormatEdgeEventArgs(ev, e)); + Output.Write(" {0}", ev.ToDot()); + } + } + + public string Generate(IDotEngine dot, string outputFileName) + { + if (dot == null) + throw new ArgumentNullException("dot"); + if (outputFileName == null) + throw new ArgumentNullException("outputFileName"); + + this.vertexIds.Clear(); + + this.output = new StringWriter(); + + // build vertex id map + int i=0; + foreach(TVertex v in this.VisitedGraph.Vertices) + this.vertexIds.Add(v,i++); + + Output.WriteLine("digraph G {"); + + String gf = GraphFormat.ToDot(); + if (gf.Length > 0) + Output.WriteLine(gf); + String vf = CommonVertexFormat.ToDot(); + if (vf.Length > 0) + Output.WriteLine("node [{0}];", vf); + String ef = CommonEdgeFormat.ToDot(); + if (ef.Length > 0) + Output.WriteLine("edge [{0}];", ef); + + // initialize vertex map + IDictionary colors = new Dictionary(); + foreach (var v in VisitedGraph.Vertices) + colors[v] = GraphColor.White; + IDictionary edgeColors = new Dictionary(); + foreach (var e in VisitedGraph.Edges) + edgeColors[e] = GraphColor.White; + + WriteVertices(colors, VisitedGraph.Vertices); + WriteEdges(edgeColors, VisitedGraph.Edges); + + Output.WriteLine("}"); + + return dot.Run(ImageType, Output.ToString(), outputFileName); + } + + private void WriteVertices( + IDictionary colors, + IEnumerable vertices) + { + foreach (var v in vertices) + { + if (colors[v] == GraphColor.White) + { + OnFormatVertex(v); + colors[v] = GraphColor.Black; + } + } + } + + private void WriteEdges( + IDictionary edgeColors, + IEnumerable edges) + { + foreach (var e in edges) + { + if (edgeColors[e] != GraphColor.White) + continue; + + Output.Write("{0} -> {1} [", + this.vertexIds[e.Source], + this.vertexIds[e.Target] + ); + + OnFormatEdge(e); + Output.WriteLine("];"); + + edgeColors[e] = GraphColor.Black; + } + } + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/GraphvizAlgorithm.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/GraphvizAlgorithm.cs.meta new file mode 100644 index 0000000..83aead3 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/GraphvizAlgorithm.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 133f65bbc0db04d38bfb9d7a93da4a53 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/IDotEngine.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/IDotEngine.cs new file mode 100755 index 0000000..e69e651 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/IDotEngine.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Text; +using QuickGraph.Graphviz.Dot; + +namespace QuickGraph.Graphviz +{ + public interface IDotEngine + { + string Run( + GraphvizImageType imageType, + string dot, + string outputFileName); + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/IDotEngine.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/IDotEngine.cs.meta new file mode 100644 index 0000000..7b0e987 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/IDotEngine.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 24892f975659a4ea3ae986f9275af5ea +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/QuickGraph.Graphviz.csproj b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/QuickGraph.Graphviz.csproj new file mode 100755 index 0000000..32d274e --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/QuickGraph.Graphviz.csproj @@ -0,0 +1,111 @@ + + + Debug + AnyCPU + 9.0.30729 + 2.0 + {595D6322-637A-4A36-97F1-D53F3F9ECEA7} + Library + Properties + QuickGraph.Graphviz + QuickGraph.Graphviz + SAK + SAK + SAK + SAK + true + quickgraph.snk + + + 2.0 + + + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + Off + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + Off + + + + + + + + + + Properties\version.cs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {A9A5C115-0680-44B3-A87E-5ECF4C93814E} + QuickGraph + + + + + + + + + + + \ No newline at end of file diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/QuickGraph.Graphviz.csproj.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/QuickGraph.Graphviz.csproj.meta new file mode 100644 index 0000000..be59cf6 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/QuickGraph.Graphviz.csproj.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: 7914e1131f4bf4b4c9fa8130cef18240 +DefaultImporter: + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/QuickGraph.Graphviz.csproj.vspscc b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/QuickGraph.Graphviz.csproj.vspscc new file mode 100755 index 0000000..feffdec --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/QuickGraph.Graphviz.csproj.vspscc @@ -0,0 +1,10 @@ +"" +{ +"FILE_VERSION" = "9237" +"ENLISTMENT_CHOICE" = "NEVER" +"PROJECT_FILE_RELATIVE_PATH" = "" +"NUMBER_OF_EXCLUDED_FILES" = "0" +"ORIGINAL_PROJECT_FILE_PATH" = "" +"NUMBER_OF_NESTED_PROJECTS" = "0" +"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROVIDER" +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/QuickGraph.Graphviz.csproj.vspscc.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/QuickGraph.Graphviz.csproj.vspscc.meta new file mode 100644 index 0000000..79ddeb4 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/QuickGraph.Graphviz.csproj.vspscc.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: a20eeb04951d649db802d159d7484e8b +DefaultImporter: + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/SvgHtmlWrapper.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/SvgHtmlWrapper.cs new file mode 100755 index 0000000..be98aa7 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/SvgHtmlWrapper.cs @@ -0,0 +1,65 @@ +using System; +using System.Drawing; +using System.IO; +using System.Text.RegularExpressions; + +namespace QuickGraph.Graphviz +{ + public static class SvgHtmlWrapper + { + private readonly static Regex sizeRegex = new Regex("\\d+)px\" height=\"(?\\d+)px", + RegexOptions.ExplicitCapture + | RegexOptions.Multiline + | RegexOptions.Compiled + ); + + /// + /// Creates a HTML file that wraps the SVG and returns the file name + /// + /// + /// + public static string WrapSvg(string svgFileName) + { + using (StreamReader reader = new StreamReader(svgFileName)) + { + Size size = ParseSize(reader.ReadToEnd()); + reader.Close(); + return DumpHtml(size, svgFileName); + } + } + + public static Size ParseSize(string svg) + { + Match m = sizeRegex.Match(svg); + if (!m.Success) + return new Size(400, 400); + else + { + int size = int.Parse(m.Groups["Width"].Value); + int height = int.Parse(m.Groups["Height"].Value); + return new Size(size, height); + } + } + + public static string DumpHtml(Size size, string svgFileName) + { + string outputFile = String.Format("{0}.html",svgFileName); + using (StreamWriter html = new StreamWriter(outputFile)) + { + html.WriteLine(""); + html.WriteLine(""); + html.WriteLine("", + svgFileName,size.Width,size.Height); + html.WriteLine(" ", + svgFileName,size.Width,size.Height); + html.WriteLine("If you see this, you need to install a SVG viewer"); + html.WriteLine(" "); + html.WriteLine(""); + html.WriteLine(""); + html.WriteLine(""); + } + + return outputFile; + } + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/SvgHtmlWrapper.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/SvgHtmlWrapper.cs.meta new file mode 100644 index 0000000..4b4d37b --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/SvgHtmlWrapper.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 7884a021a52454423bd82448feaf9634 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/quickgraph.snk b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/quickgraph.snk new file mode 100755 index 0000000..a630ef5 Binary files /dev/null and b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/quickgraph.snk differ diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/quickgraph.snk.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/quickgraph.snk.meta new file mode 100644 index 0000000..34d5ef4 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Graphviz/quickgraph.snk.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: 0436fcef465f04d0e89f62c92301d59c +DefaultImporter: + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Heap.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Heap.meta new file mode 100644 index 0000000..30bf12d --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Heap.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: 31d7cdec45c8648d0a04c06442c9736f +folderAsset: yes +DefaultImporter: + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Heap/Data.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Heap/Data.meta new file mode 100644 index 0000000..76c1d6f --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Heap/Data.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: 989bd6703eb104c29a2d2c7011f49f5c +folderAsset: yes +DefaultImporter: + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Heap/Data/GcHeapParser.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Heap/Data/GcHeapParser.cs new file mode 100755 index 0000000..23d637c --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Heap/Data/GcHeapParser.cs @@ -0,0 +1,73 @@ +using System; +using System.Collections.Generic; +using System.IO; + +namespace QuickGraph.Heap.Data +{ + public sealed class GcHeapParser + { + private readonly GcObjectGraph objectGraph; + + public GcHeapParser(GcObjectGraph objectGraph) + { + this.objectGraph = objectGraph; + } + + public GcObjectGraph ObjectGraph + { + get { return this.objectGraph; } + } + + public void Parse(string fileName) + { + if (string.IsNullOrEmpty(fileName)) + throw new ArgumentNullException("fileName"); + + using (StreamReader reader = new StreamReader(fileName)) + { + while (!reader.EndOfStream) + { + string line = reader.ReadLine(); + ParseLine(line); + } + } + } + + private IEnumerable SplitLine(string line) + { + foreach (string item in line.Split(' ')) + { + string trimmed = item.Trim(); + if (!String.IsNullOrEmpty(trimmed)) + yield return trimmed; + } + } + + public void ParseLine(string line) + { + if (line == null) + return; + string l = line.Trim(); + if (string.IsNullOrEmpty(l)) + return; + + // this should contain the address + List elements = new List(SplitLine(l)); + if (!elements[0].ToLowerInvariant().StartsWith("0x")) + return; + int address = int.Parse(elements[0].Substring(2), System.Globalization.NumberStyles.AllowHexSpecifier); + + // element[3] contains the gen + int gen; + if (!int.TryParse(elements[3], out gen)) + return; + + // we can update the object + GcObjectVertex v = this.ObjectGraph.FromAddress(address); + if (v == null) + return; + + v.Gen = gen; + } + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Heap/Data/GcHeapParser.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Heap/Data/GcHeapParser.cs.meta new file mode 100644 index 0000000..8068e4f --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Heap/Data/GcHeapParser.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 825d1d3e26bce438fab763d3488737be +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Heap/Data/GcObject.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Heap/Data/GcObject.cs new file mode 100755 index 0000000..1104d05 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Heap/Data/GcObject.cs @@ -0,0 +1,57 @@ +using System; +using System.Collections.Generic; + +namespace QuickGraph.Heap.Data +{ + public sealed class AddressList : List + { + public AddressList() + : base(0) + { } + } + + public sealed class GcObject + { + private readonly long address; + private readonly int typeID; + private readonly int size; + private AddressList members; + + public GcObject(long address, int typeID, int size) + { + this.address = address; + this.typeID = typeID; + this.size = size; + } + + public long Address + { + get { return this.address; } + } + + public int TypeID + { + get { return this.typeID; } + } + + public int Size + { + get { return this.size; } + } + + public AddressList Members + { + get + { + if (this.members == null) + this.members = new AddressList(); + return this.members; + } + } + + public override string ToString() + { + return String.Format("{0}({1})", this.address, this.TypeID); + } + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Heap/Data/GcObject.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Heap/Data/GcObject.cs.meta new file mode 100644 index 0000000..b4c223f --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Heap/Data/GcObject.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 55b5020150e5e4477957f7fe786909ca +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Heap/Data/GcRoot.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Heap/Data/GcRoot.cs new file mode 100755 index 0000000..b12e846 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Heap/Data/GcRoot.cs @@ -0,0 +1,31 @@ +using System; + +namespace QuickGraph.Heap.Data +{ + public struct GcRoot + { + private readonly long address; + private readonly string kind; + + public GcRoot(long address, string kind) + { + this.address = address; + this.kind = kind; + } + + public long Address + { + get { return this.address; } + } + + public string Kind + { + get { return this.kind; } + } + + public override string ToString() + { + return String.Format("{0}({1})", this.Address, this.Kind); + } + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Heap/Data/GcRoot.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Heap/Data/GcRoot.cs.meta new file mode 100644 index 0000000..0b26a8f --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Heap/Data/GcRoot.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 5aa4a886d374b46d7bce540632032c6b +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Heap/Data/GcType.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Heap/Data/GcType.cs new file mode 100755 index 0000000..2f563d0 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Heap/Data/GcType.cs @@ -0,0 +1,32 @@ +using System; +using System.Xml.Serialization; + +namespace QuickGraph.Heap.Data +{ + public struct GcType + { + private readonly int id; + private readonly string name; + + public GcType(int id, string name) + { + this.id = id; + this.name = name; + } + + public int ID + { + get { return this.id; } + } + + public string Name + { + get { return this.name; } + } + + public override string ToString() + { + return string.Format("{0}({1})", this.Name, this.ID); + } + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Heap/Data/GcType.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Heap/Data/GcType.cs.meta new file mode 100644 index 0000000..89027eb --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Heap/Data/GcType.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 3a87c8394e89e4d1594c5b1b7003e022 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Heap/FilterHelper.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Heap/FilterHelper.cs new file mode 100755 index 0000000..e9e6d01 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Heap/FilterHelper.cs @@ -0,0 +1,116 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Text.RegularExpressions; + +namespace QuickGraph.Heap +{ + /// + /// A generic string filtering interface + /// + internal interface IFilter + { + /// + /// Gets a value indicating wheter the value is matched by + /// the filter + /// + /// The value. + /// + bool Match(string value); + } + + /// + /// Static helper methods to create simple string filters + /// + internal static class FilterHelper + { + /// + /// Creates a regex from a string, supporting + /// * and ? wildcards. + /// + /// + /// + public static IFilter ToFilter(string name) + { + if (String.IsNullOrEmpty(name)) + return new AnyFilter(); + + foreach (char c in name) + switch (c) + { + case ',': + case ';': + case '?': + case '*': + // this code will trigger a lot of jitting/computation + string rx = Regex.Escape(name); + // ,; -> | + rx = rx.Replace(',', '|').Replace(';', '|'); + // ? -> . + rx = Regex.Replace(rx, @"\?", "."); + // * -> .*? + rx = Regex.Replace(rx, @"\*", ".*?"); + return new RegexFilter(new Regex(rx)); + } + return new ContainsFilter(name); + } + + private sealed class AnyFilter : IFilter + { + public bool Match(string value) + { + return true; + } + + public override string ToString() + { + return "any"; + } + } + + private sealed class RegexFilter : IFilter + { + private readonly Regex rx; + public RegexFilter(Regex rx) + { + this.rx = rx; + } + + public bool Match(string value) + { + if (String.IsNullOrEmpty(value)) + return false; + + Match m = rx.Match(value); + return m.Success; + } + + public override string ToString() + { + return String.Format("regex {0}", rx); + } + } + + private sealed class ContainsFilter : IFilter + { + private readonly string substring; + public ContainsFilter(string substring) + { + this.substring = substring; + } + + public bool Match(string value) + { + if (String.IsNullOrEmpty(value)) + return false; + + return value.Contains(substring); + } + + public override string ToString() + { + return String.Format("substring '{0}'", this.substring); + } + } + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Heap/FilterHelper.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Heap/FilterHelper.cs.meta new file mode 100644 index 0000000..85bf021 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Heap/FilterHelper.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b1d18c30e25e84251a481e7feaf82913 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Heap/FormatHelper.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Heap/FormatHelper.cs new file mode 100755 index 0000000..32b215d --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Heap/FormatHelper.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace QuickGraph.Heap +{ + internal static class FormatHelper + { + public static string ToSize(int size) + { + if (size < 1000) + return String.Format("{0}b", size); + else if (size < 1000000) + return String.Format("{0}Kb", size / 1000); + else + return String.Format("{0}Mb", size / 1000000); + } + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Heap/FormatHelper.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Heap/FormatHelper.cs.meta new file mode 100644 index 0000000..8cbf61f --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Heap/FormatHelper.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 10e5ec77a2eea42edb6b99e75d2c5c19 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Heap/GcObjectGraph.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Heap/GcObjectGraph.cs new file mode 100755 index 0000000..7dc7ac5 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Heap/GcObjectGraph.cs @@ -0,0 +1,70 @@ +using System; +using System.Collections.Generic; +using System.Globalization; + +namespace QuickGraph.Heap +{ + public sealed class GcObjectGraph : + BidirectionalGraph> + { + private readonly Dictionary addressObjects; + private readonly List roots; + + public GcObjectGraph(int objectCount, int rootCount) + : base(false, objectCount) + { + this.addressObjects = new Dictionary(objectCount); + this.roots = new List(rootCount); + } + + public ICollection Roots + { + get { return this.roots; } + } + + public GcObjectVertex FromAddress(int address) + { + GcObjectVertex vertex; + if (this.addressObjects.TryGetValue(address, out vertex)) + return vertex; + else + return null; + } + + public GcObjectVertex AddVertex( + GcType type, + int address, + int size + ) + { + GcObjectVertex v = new GcObjectVertex( + type, + address, + size); + this.AddVertex(v); + return v; + } + + public override void AddVertex(GcObjectVertex v) + { + base.AddVertex(v); + this.addressObjects.Add(v.Address, v); + } + + public void SetAsRoot(GcRoot root) + { + GcObjectVertex v = this.FromAddress(root.Address); + if (v != null) + { + v.Kind = root.Kind; + this.roots.Add(v); + } + } + + public override bool RemoveVertex(GcObjectVertex v) + { + this.addressObjects.Remove(v.Address); + return base.RemoveVertex(v); + } + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Heap/GcObjectGraph.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Heap/GcObjectGraph.cs.meta new file mode 100644 index 0000000..3dc01e0 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Heap/GcObjectGraph.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 5aeba8cf6b3664852b346b18566eb3b4 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Heap/GcObjectVertex.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Heap/GcObjectVertex.cs new file mode 100755 index 0000000..905d487 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Heap/GcObjectVertex.cs @@ -0,0 +1,71 @@ +using System; +using QuickGraph.Heap.Data; + +namespace QuickGraph.Heap +{ + public struct GcObjectVertex + { + private readonly GcType type; + private readonly long address; + private readonly int size; + private readonly string kind; + private readonly int gen; + private readonly string value; + + public GcObjectVertex( + GcType type, + long address, + int size, + string kind, + int gen, + string value + ) + { + this.type = type; + this.address = address; + this.size = size; + this.kind = kind; + this.gen = gen; + this.value = value; + } + + public GcType Type + { + get { return this.type; } + } + + public long Address + { + get { return this.address; } + } + + public int Size + { + get { return this.size; } + } + + public string Kind + { + get { return this.kind; } + } + + public int Gen + { + get { return this.gen; } + } + + public string Value + { + get { return this.value; } + } + + public override string ToString() + { + return String.Format("0x{0:x}-{1}-{2}", + this.Address, + this.Type.Name, + this.Size + ); + } + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Heap/GcObjectVertex.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Heap/GcObjectVertex.cs.meta new file mode 100644 index 0000000..dc72bc4 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Heap/GcObjectVertex.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: bac1ba01342ed407cb50eddcc06d63c4 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Heap/GcType.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Heap/GcType.cs new file mode 100755 index 0000000..23f02c0 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Heap/GcType.cs @@ -0,0 +1,133 @@ +using System; +using System.Collections.Generic; +using System.Text; +using QuickGraph; + +namespace QuickGraph.Heap +{ + public sealed class GcType : IEquatable + { + public readonly int ID; + public readonly string Name; + public bool Root; + public int Count; + public int Size; + private int genCount; + private int genSum; + + + internal GcType(int id, string name) + { + this.ID = id; + this.Name = name; + this.Root = false; + this.Count = 0; + this.Size = 0; + } + + public bool Equals(GcType other) + { + return this.ID == other.ID; + } + + public override int GetHashCode() + { + return this.ID; + } + + public override bool Equals(object obj) + { + return (object)obj != null && this.Equals(obj as GcType); + } + + public override string ToString() + { + return String.Format("{0}\t{1}\t{2:0.0}\t{3}", + this.Count, + FormatHelper.ToSize(this.Size), + this.Gen, + this.Name); + } + + public double Gen + { + get + { + if (this.genCount == 0) + return -1; + else + return this.genSum / (double)this.genCount; + } + } + + public void AddObjectGeneration(int gen) + { + this.genCount++; + this.genSum += gen; + } + } + + public sealed class GcTypeCollection : QueryableList + { + internal GcTypeCollection(int capacity) + :base(capacity) + { + } + internal GcTypeCollection(IEnumerable types) + : base(types) + { } + + protected override QueryableList Create(int capacity) + { + return new GcTypeCollection(capacity); + } + + public GcTypeCollection SortSize() + { + GcTypeCollection clone = new GcTypeCollection(this); + clone.Sort((left, right) => -left.Size.CompareTo(right.Size)); + return clone; + } + + public GcTypeCollection SortCount() + { + GcTypeCollection clone = new GcTypeCollection(this); + clone.Sort((left, right) => -left.Count.CompareTo(right.Count)); + return clone; + } + + public GcTypeCollection SortGen() + { + GcTypeCollection clone = new GcTypeCollection(this); + clone.Sort((left, right) => left.Gen.CompareTo(right.Gen)); + return clone; + } + + public GcTypeCollection MinimumSize(int size) + { + GcTypeCollection clone = new GcTypeCollection(this.Count); + foreach (GcType type in this) + if (type.Size >= size) + clone.Add(type); + clone.TrimExcess(); + return clone; + } + } + + public sealed class GcTypeEdge : Edge + { + public int Count; + + internal GcTypeEdge(GcType source, GcType target) + : base(source, target) + { } + + public override string ToString() + { + return String.Format("{0}\t{1} -> {2}", + this.Count, + this.Source.Name, + this.Target.Name); + } + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Heap/GcType.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Heap/GcType.cs.meta new file mode 100644 index 0000000..75f7631 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Heap/GcType.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 4fc1943a2828e4cca8759aab6eb4f57c +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Heap/GcTypeGraphReader.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Heap/GcTypeGraphReader.cs new file mode 100755 index 0000000..e8aa298 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Heap/GcTypeGraphReader.cs @@ -0,0 +1,149 @@ +using System; +using System.Collections.Generic; +using System.Text; +using QuickGraph; +using System.IO; + +namespace QuickGraph.Heap +{ + internal sealed class GcTypeGraphReader : GcHeapXmlReader + { + readonly BidirectionalGraph graph = new BidirectionalGraph(); + // id -> type + readonly Dictionary types = new Dictionary(); + // adress -> root + readonly Dictionary roots = new Dictionary(); + // adress -> type + readonly Dictionary objectTypes = new Dictionary(); + readonly List unresolvedMembers = new List(); + + public GcTypeGraphReader() + {} + + public BidirectionalGraph Graph + { + get { return this.graph; } + } + + // remeber type and roots + protected override void VisitType(int id, string name) + { + GcType type = new GcType(id, name); + + this.types.Add(type.ID, type); + this.graph.AddVertex(type); + } + + protected override void VisitRoot(string kind, int address) + { + if (kind == "stack") return; // skip stack roots + this.roots[address] = new GcRoot(kind, address); + } + + GcType current; + protected override void VisitStartObject(int address, int typeid, int size) + { + if (!this.types.TryGetValue(typeid, out this.current)) + throw new InvalidOperationException("unknown typeid " + typeid); + + this.current.Count++; + this.current.Size += size; + if (!this.current.Root) // lazy check if rooted + this.current.Root = this.roots.ContainsKey(address); + + this.objectTypes.Add(address, this.current); + } + + protected override void VisitMember(int address) + { + GcType target; + if (!this.objectTypes.TryGetValue(address, out target)) + { + // object type not loaded yet, + // store member + this.unresolvedMembers.Add(new GcMember(this.current, address)); + } + else + { + AddTypeEdge(target, this.current); + } + } + + private void AddTypeEdge(GcType source, GcType target) + { + GcTypeEdge edge; + if (!this.graph.TryGetEdge(source, target, out edge)) + this.graph.AddEdge(edge = new GcTypeEdge(source, target)); + edge.Count++; + } + + // process unresolved members + protected override void VisitEndObjects() + { + FlushUnresolvedMembers(); + } + + private void FlushUnresolvedMembers() + { + foreach (GcMember member in this.unresolvedMembers) + { + GcType target = member.Referer; + GcType source; + if (this.objectTypes.TryGetValue(member.Address, out source)) + this.AddTypeEdge(source, target); + } + this.unresolvedMembers.Clear(); + } + + public void ParseDump(StreamReader reader) + { + if (reader == null) + throw new ArgumentNullException("reader"); + while (!reader.EndOfStream) + this.ParseDumpLine(reader.ReadLine()); + } + + private static IEnumerable SplitLine(string line) + { + foreach (string item in line.Split(' ')) + { + string trimmed = item.Trim(); + if (!String.IsNullOrEmpty(trimmed)) + yield return trimmed; + } + } + + private void ParseDumpLine(string line) + { + if (line == null) + return; + string l = line.Trim(); + if (string.IsNullOrEmpty(l)) + return; + + // this should contain the address + List elements = new List(SplitLine(l)); + if (!elements[0].ToLowerInvariant().StartsWith("0x")) + return; + int address; + if (!TryParseAddress(elements[0].Substring(2), out address)) + { + Console.WriteLine("failed to parse address {0}", elements[0].Substring(2)); + return; + } + + // element[3] contains the gen + int gen; + if (!int.TryParse(elements[3], out gen)) + { + Console.WriteLine("failed to parse gen {0}", elements[3]); + return; + } + + // we can update the object + GcType type; + if (this.objectTypes.TryGetValue(address, out type)) + type.AddObjectGeneration(gen); + } + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Heap/GcTypeGraphReader.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Heap/GcTypeGraphReader.cs.meta new file mode 100644 index 0000000..214a3ec --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Heap/GcTypeGraphReader.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ac79ecd4c354043eab93aa154d70f95d +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Heap/GcTypeHeap.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Heap/GcTypeHeap.cs new file mode 100755 index 0000000..2940bc7 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Heap/GcTypeHeap.cs @@ -0,0 +1,346 @@ +using System; +using System.Collections.Generic; +using System.Text; +using QuickGraph; +using System.IO; +using System.Xml; +using QuickGraph.Algorithms.Search; +using QuickGraph.Glee; +using Microsoft.Glee.GraphViewerGdi; +using QuickGraph.Algorithms; +using QuickGraph.Algorithms.Condensation; +using System.Windows.Forms; +using System.Text.RegularExpressions; + +namespace QuickGraph.Heap +{ + /// + /// + /// + /// + /// http://www.cs.utexas.edu/users/speedway/DaCapo/papers/cork-popl-2007.pdf + /// + public sealed class GcTypeHeap + { + private readonly BidirectionalGraph graph; + private int size = -1; + private Form viewerForm; + private GViewer viewer; + + internal GcTypeHeap(BidirectionalGraph graph) + { + if (graph == null) + throw new ArgumentNullException("graph"); + + this.graph = graph; + } + + public int Size + { + get + { + if (this.size < 0) + { + int s = 0; + foreach (GcType type in this.graph.Vertices) + s += type.Size; + this.size = s; + } + return this.size; + } + } + + /// + /// Loads the specified heap XML file name. + /// + /// Name of the heap XML file. + /// + public static GcTypeHeap Load(string heapXmlFileName) + { + return Load(heapXmlFileName, null); + } + + private readonly static Regex regex = new Regex( + "name=\"(?[^\"]*)\"", + RegexOptions.IgnoreCase + | RegexOptions.CultureInvariant + | RegexOptions.IgnorePatternWhitespace + | RegexOptions.Compiled + ); + + private static string EscapeXmlAttribute(Match m) + { + string value = m.Groups["Type"].Value; + return String.Format("name=\"{0}\"", + value.Replace("<", "<") + .Replace(">", ">") + ); + } + + /// + /// Loads the specified heap XML file name. + /// + /// Name of the heap XML file. + /// Name of the dump file. + /// + public static GcTypeHeap Load(string heapXmlFileName, string dumpFileName) + { + if (String.IsNullOrEmpty(heapXmlFileName)) + throw new ArgumentNullException("heapXmlFileName"); + if (!File.Exists(heapXmlFileName)) + throw new FileNotFoundException("could not find heap file", heapXmlFileName); + + Console.WriteLine("loading {0}", heapXmlFileName); + GcTypeGraphReader greader = new GcTypeGraphReader(); + + try + { + using (XmlReader reader = XmlReader.Create(heapXmlFileName)) + greader.Read(reader); + } + catch (XmlException) + { + Console.WriteLine("fixing up xml file (incorrect xml with generics)"); + // fix the xml and save back to disk. + File.WriteAllText( + heapXmlFileName, + regex.Replace( + File.ReadAllText(heapXmlFileName), + EscapeXmlAttribute) + ); + // try again + greader = new GcTypeGraphReader(); + using (XmlReader reader = XmlReader.Create(heapXmlFileName)) + greader.Read(reader); + } + + if (!String.IsNullOrEmpty(dumpFileName)) + { + if (!File.Exists(dumpFileName)) + throw new FileNotFoundException("could not find dump file", dumpFileName); + using (StreamReader reader = new StreamReader(File.OpenRead(dumpFileName))) + greader.ParseDump(reader); + } + + GcTypeHeap heap = new GcTypeHeap(greader.Graph).RemoveDefault(); ; + Console.WriteLine("heap: {0}", heap); + return heap; + } + + public override string ToString() + { + return String.Format("{0} types, {1} edges, {2}", + this.graph.VertexCount, + this.graph.EdgeCount, + FormatHelper.ToSize(this.Size)); + } + + /// + /// Gets the list of types in the graph + /// + public GcTypeCollection Types + { + get + { + return new GcTypeCollection(this.graph.Vertices).SortSize(); + } + } + + /// + /// Gets the list of root types + /// + public GcTypeCollection Roots + { + get + { + GcTypeCollection roots = new GcTypeCollection(this.graph.Vertices); + foreach (GcType type in this.graph.Vertices) + if (type.Root) + roots.Add(type); + return roots; + } + } + + public GcTypeHeap Clone() + { + return new GcTypeHeap(this.graph.Clone()); + } + + #region Rendering + public GcTypeHeap Render() + { + Console.WriteLine("rendering..."); + if (this.graph.VertexCount > 500) + { + Console.WriteLine("too many vertices "); + return this; + } + + GleeGraphPopulator populator = GleeGraphUtility.Create(this.graph); + try + { + populator.NodeAdded += new GleeVertexNodeEventHandler(populator_NodeAdded); + populator.EdgeAdded += new GleeEdgeEventHandler(populator_EdgeAdded); + populator.Compute(); + + if (viewer == null) + { + viewerForm = new Form(); + viewer = new GViewer(); + viewer.Dock = DockStyle.Fill; + viewerForm.Controls.Add(viewer); + } + viewer.Graph = populator.GleeGraph; + viewerForm.ShowDialog(); + } + finally + { + populator.NodeAdded -= new GleeVertexNodeEventHandler(populator_NodeAdded); + populator.EdgeAdded -= new GleeEdgeEventHandler(populator_EdgeAdded); + } + + return this; + } + + void populator_EdgeAdded(object sender, GleeEdgeEventArgs e) + { + e.GEdge.Attr.Label = e.Edge.Count.ToString(); + } + + void populator_NodeAdded(object sender, GleeVertexEventArgs args) + { + args.Node.Attr.Shape = Microsoft.Glee.Drawing.Shape.Box; + double gen = args.Vertex.Gen; + if (gen > 2) + args.Node.Attr.Fillcolor = Microsoft.Glee.Drawing.Color.LightBlue; + else if (gen > 1) + args.Node.Attr.Fillcolor = Microsoft.Glee.Drawing.Color.LightGoldenrodYellow; + else if (gen >= 0) + args.Node.Attr.Fillcolor = Microsoft.Glee.Drawing.Color.LightPink; + else + args.Node.Attr.Fillcolor = Microsoft.Glee.Drawing.Color.LightSalmon; + + // root -> other color + if (args.Vertex.Root) + args.Node.Attr.AddStyle(Microsoft.Glee.Drawing.Style.Dashed); + + // label + args.Node.Attr.Label = + String.Format("{0}\nc:{1} g:{2:0.0} s:{3}", + args.Vertex.Name, + args.Vertex.Count, + args.Vertex.Gen, + FormatHelper.ToSize(args.Vertex.Size) + ); + } + #endregion + + #region Filtering + private GcTypeHeap RemoveDefault() + { + // remove default types + this.graph.RemoveVertexIf( + delegate(GcType type) + { + switch (type.Name) + { + case "System.OutOfMemoryException": + case "System.StackOverflowException": + case "System.ExecutionEngineException": + case "System.RuntimeType": + case "System.Reflection.Missing": + case "System.IO.TextReader/SyncTextReader": + case "System.AppDomain": + case "System.AppDomainSetup": + case "System.IO.Stream/NullStream": + case "System.Text.UTF8Encoding": + case "System.__Filters": + case "System.Reflection.MemberFilter": + case "System.Text.CodePageEncoding": + case "System.IO.TextWriter/NullTextWriter": + case "System.Text.UTF8Encoding/UTF8Encoder": + case "System.IO.TextReader/NullTextReader": + case "System.IO.StreamReader/NullStreamReader": + case "System.Text.CodePageEncoding/Decoder": + case "System.IO.__ConsoleStream": + case "System.Text.Encoding/DefaultEncoder": + case "System.IO.TextWriter/SyncTextWriter": + return true; + default: + return false; + } + }); + return this; + } + + public GcTypeHeap Touching(string typeNames) + { + if (String.IsNullOrEmpty(typeNames)) + throw new ArgumentNullException("typeNames"); + + return this.Clone().TouchingInPlace(typeNames); + } + + private GcTypeHeap TouchingInPlace(string typeNames) + { + if (String.IsNullOrEmpty(typeNames)) + throw new ArgumentNullException("typeNames"); + + var filter = FilterHelper.ToFilter(typeNames); + Console.WriteLine("filtering nodes not connected to type matching '{0}'", filter); + var colors = new Dictionary(this.graph.VertexCount); + foreach (var type in this.graph.Vertices) + colors.Add(type, GraphColor.White); + + var rgraph = new ReversedBidirectionalGraph(graph); + foreach (var type in this.graph.Vertices) + { + if (filter.Match(type.Name)) + { + { // parents + var dfs = + new DepthFirstSearchAlgorithm>(rgraph, colors); + dfs.Visit(type, -1); + } + { // children + var dfs = new DepthFirstSearchAlgorithm(graph, colors); + dfs.Visit(type, -1); + } + } + } + // remove all white vertices + this.graph.RemoveVertexIf(t => colors[t] == GraphColor.White); + Console.WriteLine("resulting {0} types, {1} edges", graph.VertexCount, graph.EdgeCount); + return this; + } + + public GcTypeHeap Merge(int minimumSize) + { + var merged = new BidirectionalGraph>(false, this.graph.VertexCount); + var merger = new EdgeMergeCondensationGraphAlgorithm( + this.graph, + merged, + delegate(GcType type) + { + return type.Size >= minimumSize; + }); + merger.Compute(); + var clone = new BidirectionalGraph( + false, + merged.VertexCount); + foreach (var type in merged.Vertices) + clone.AddVertex(type); + foreach (var medge in merged.Edges) + { + GcTypeEdge edge = new GcTypeEdge(medge.Source, medge.Target); + foreach (GcTypeEdge e in medge.Edges) + edge.Count += e.Count; + clone.AddEdge(edge); + } + + Console.WriteLine("resulting {0} types, {1} edges", clone.VertexCount, clone.EdgeCount); + return new GcTypeHeap(clone); + } + #endregion + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Heap/GcTypeHeap.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Heap/GcTypeHeap.cs.meta new file mode 100644 index 0000000..723dfd7 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Heap/GcTypeHeap.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d0b841e517ab24bbbb6059c95f66b60a +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Heap/HeapXmlReader.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Heap/HeapXmlReader.cs new file mode 100755 index 0000000..f12885d --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Heap/HeapXmlReader.cs @@ -0,0 +1,189 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Xml; +using System.Globalization; + +namespace QuickGraph.Heap +{ + internal struct GcRoot + { + public readonly string Kind; + public readonly int Address; + public GcRoot(string kind, int address) + { + this.Kind = kind; + this.Address = address; + } + } + + internal struct GcMember + { + public readonly GcType Referer; + public readonly int Address; + public GcMember(GcType referer, int address) + { + this.Referer = referer; + this.Address = address; + } + } + + internal abstract class GcHeapXmlReader + { + public void Read(XmlReader reader) + { + if (reader == null) + throw new ArgumentNullException("reader"); + + while (reader.Read()) + { + switch (reader.NodeType) + { + case XmlNodeType.Element: + this.ReadElement(reader); + break; + case XmlNodeType.EndElement: + this.ReadEndElement(reader); + break; + default: // skip the rest + break; + } + } + } + + private void ReadElement(XmlReader reader) + { + switch (reader.Name) + { + case "gcheap": + // top level element, continue + this.VisitStartGcHeap(); + break; + case "types": + // top level types, + this.VisitStartTypes(); + break; + case "type": + { + int id; + // type element + if (!int.TryParse(reader.GetAttribute("id"), out id)) + throw new XmlException("could not parse gcheap/types/type/@id"); + string name = reader.GetAttribute("name"); + this.VisitType(id, name); + + // move to next + reader.Skip(); + break; + } + case "roots": + this.VisitStartRoots(); + break; + case "root": + { + string kind = reader.GetAttribute("kind"); + int address; + if (!TryParseAddress(reader.GetAttribute("address"), out address)) + throw new XmlException("could not parse gcheap/roots/root/@address"); + + this.VisitRoot(kind, address); + + // move to next + reader.Skip(); + break; + } + case "objects": + this.VisitStartObjects(); + break; + case "object": + { + int size; + int typeid; + int address; + if (!TryParseAddress(reader.GetAttribute("address"), out address)) + throw new XmlException("could not parse gcheap/objects/object/@address"); + if (!int.TryParse(reader.GetAttribute("typeid"), out typeid)) + throw new XmlException("could not parse gcheap/objects/object/@typeid"); + if (!int.TryParse(reader.GetAttribute("size"), out size)) + throw new XmlException("could not parse gcheap/objects/object/@size"); + this.VisitStartObject(address, typeid, size); + break; + } + case "member": + { + int address; + if (!TryParseAddress(reader.GetAttribute("address"), out address)) + throw new XmlException("could not parse gcheap/objects/object/member/@address"); + this.VisitMember(address); + // read node + reader.Skip(); + break; + } + default: + throw new XmlException("unknown element " + reader.Name); + } + } + + private void ReadEndElement(XmlReader reader) + { + switch (reader.Name) + { + case "gcheap": + // top level element, continue + this.VisitEndGcHeap(); + break; + case "types": + // top level types, + this.VisitEndTypes(); + break; + case "roots": + this.VisitEndRoots(); + break; + case "objects": + this.VisitEndObjects(); + break; + case "object": + this.VisitEndObject(); + break; + case "member": + default: + throw new XmlException("unexpected end element " + reader.Name); + } + } + + protected static bool TryParseAddress(string value, out int address) + { + address = 0; + return + value != null && + value.StartsWith("0x") && + int.TryParse(value.Substring(2), NumberStyles.HexNumber, null, out address); + } + + protected virtual void VisitStartGcHeap() {} + + protected virtual void VisitEndGcHeap() {} + + protected virtual void VisitStartTypes() {} + + protected virtual void VisitEndTypes() {} + + protected virtual void VisitType(int id, string name) {} + + protected virtual void VisitRoot(string kind, int address) {} + + protected virtual void VisitEndRoots() {} + + protected virtual void VisitStartRoots() {} + + protected virtual void VisitStartObjects() {} + + protected virtual void VisitEndObjects() {} + + protected virtual void VisitStartObject(int address, int typeid, int size) {} + + protected virtual void VisitEndObject() { } + + protected virtual void VisitMember(int address) {} + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Heap/HeapXmlReader.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Heap/HeapXmlReader.cs.meta new file mode 100644 index 0000000..c01b835 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Heap/HeapXmlReader.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 05370d0ccf1b145eb958e9fc45c7af85 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Heap/QueryableList.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Heap/QueryableList.cs new file mode 100755 index 0000000..a860075 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Heap/QueryableList.cs @@ -0,0 +1,54 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.IO; + +namespace QuickGraph.Heap +{ + public abstract class QueryableList : List + { + protected QueryableList(IEnumerable items) + : base(items) + { } + + protected QueryableList(int capacity) + : base(capacity) + { } + + protected abstract QueryableList Create(int capacity); + + public QueryableList Top(int count) + { + if (count <= 0) + throw new ArgumentOutOfRangeException("must be posivite", "count"); + + QueryableList list = this.Create(count); + int len = Math.Min(count, this.Count); + for (int i = 0; i < len; ++i) + list.Add(this[i]); + return list; + } + + public QueryableList Bottom(int count) + { + if (count <= 0) + throw new ArgumentOutOfRangeException("must be posivite", "count"); + + QueryableList list = this.Create(count); + int len = Math.Max(this.Count - count, 0); + for (int i = this.Count - 1; i >= len; --i) + list.Add(this[i]); + return list; + } + + public override string ToString() + { + using (StringWriter writer = new StringWriter()) + { + for(int i = this.Count -1;i>=0;--i) + writer.WriteLine(this[i]); + return writer.ToString(); + } + } + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Heap/QueryableList.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Heap/QueryableList.cs.meta new file mode 100644 index 0000000..138db45 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Heap/QueryableList.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 099aa5eac85d0436c9c33e386d94b049 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Heap/QuickGraph.Heap.csproj b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Heap/QuickGraph.Heap.csproj new file mode 100755 index 0000000..eca272c --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Heap/QuickGraph.Heap.csproj @@ -0,0 +1,109 @@ + + + Debug + AnyCPU + 9.0.30729 + 2.0 + {2DEC7C6E-68DF-47EC-A75E-2C1238986B8E} + Library + Properties + QuickGraph.Heap + QuickGraph.Heap + SAK + SAK + SAK + SAK + true + quickgraph.snk + + + 2.0 + + + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + Off + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + Off + + + + False + ..\external\Glee\Microsoft.GLEE.dll + + + False + ..\external\Glee\Microsoft.GLEE.Drawing.dll + + + False + ..\external\Glee\Microsoft.GLEE.GraphViewerGDI.dll + + + + + + + + + Properties\version.cs + + + + + + + + + + + + + Always + + + + + {ACDD0973-E5D9-4C2B-9EAF-B5B5DF44EDDD} + QuickGraph.Glee + + + {A9A5C115-0680-44B3-A87E-5ECF4C93814E} + QuickGraph + + + + + Always + + + Always + + + + + + + + + \ No newline at end of file diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Heap/QuickGraph.Heap.csproj.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Heap/QuickGraph.Heap.csproj.meta new file mode 100644 index 0000000..f6489e5 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Heap/QuickGraph.Heap.csproj.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: 8fd87fbca4d984a9cbf667f258ed75fd +DefaultImporter: + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Heap/QuickGraph.Heap.csproj.vspscc b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Heap/QuickGraph.Heap.csproj.vspscc new file mode 100755 index 0000000..feffdec --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Heap/QuickGraph.Heap.csproj.vspscc @@ -0,0 +1,10 @@ +"" +{ +"FILE_VERSION" = "9237" +"ENLISTMENT_CHOICE" = "NEVER" +"PROJECT_FILE_RELATIVE_PATH" = "" +"NUMBER_OF_EXCLUDED_FILES" = "0" +"ORIGINAL_PROJECT_FILE_PATH" = "" +"NUMBER_OF_NESTED_PROJECTS" = "0" +"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROVIDER" +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Heap/QuickGraph.Heap.csproj.vspscc.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Heap/QuickGraph.Heap.csproj.vspscc.meta new file mode 100644 index 0000000..d6c3687 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Heap/QuickGraph.Heap.csproj.vspscc.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: 1ac6b1240dbe94a8d826a80b80fbb44a +DefaultImporter: + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Heap/dumpheap.cmd b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Heap/dumpheap.cmd new file mode 100755 index 0000000..e1a199a --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Heap/dumpheap.cmd @@ -0,0 +1,2 @@ +rem usage: dumpheap PID +cdb -p %1 -c "$$>< dumpheap.txt" \ No newline at end of file diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Heap/dumpheap.cmd.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Heap/dumpheap.cmd.meta new file mode 100644 index 0000000..9146426 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Heap/dumpheap.cmd.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: b65f713509c8148429dda47211a9cb08 +DefaultImporter: + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Heap/dumpheap.txt b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Heap/dumpheap.txt new file mode 100755 index 0000000..8fc96f8 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Heap/dumpheap.txt @@ -0,0 +1,7 @@ +.echo dumping process managed heap, this might take a while... +.loadby sos mscorwks +!TraverseHeap -xml heap.xml +!TraverseHeap heap.txt +.detach +q + diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Heap/dumpheap.txt.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Heap/dumpheap.txt.meta new file mode 100644 index 0000000..cbc481d --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Heap/dumpheap.txt.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: 1431df0e1ac814d07b56baedbe71800e +TextScriptImporter: + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Heap/heap.py b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Heap/heap.py new file mode 100755 index 0000000..5feea11 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Heap/heap.py @@ -0,0 +1,4 @@ +import clr +clr.AddReferenceToFile("QuickGraph.Heap") +import QuickGraph.Heap +from QuickGraph.Heap import GcTypeHeap diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Heap/heap.py.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Heap/heap.py.meta new file mode 100644 index 0000000..28fea42 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Heap/heap.py.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: 51997ea1921d2456ebedbdb4ab4ab592 +DefaultImporter: + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Heap/quickgraph.snk b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Heap/quickgraph.snk new file mode 100755 index 0000000..a630ef5 Binary files /dev/null and b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Heap/quickgraph.snk differ diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.Heap/quickgraph.snk.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Heap/quickgraph.snk.meta new file mode 100644 index 0000000..23e3064 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph.Heap/quickgraph.snk.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: 1fa4820fcd1f4464ab17329c67c2bccc +DefaultImporter: + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph.meta new file mode 100644 index 0000000..e5b61fb --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: 27bec876861c64bfaa58419bdc7cdd44 +folderAsset: yes +DefaultImporter: + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/AdjacencyGraph.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/AdjacencyGraph.cs new file mode 100755 index 0000000..6e24def --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/AdjacencyGraph.cs @@ -0,0 +1,467 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; + +namespace QuickGraph +{ + [Serializable] + public class AdjacencyGraph : + IVertexAndEdgeListGraph, + IEdgeListAndIncidenceGraph, + IMutableEdgeListGraph, + IMutableIncidenceGraph, + IMutableVertexListGraph, + IMutableVertexAndEdgeListGraph + where TEdge : IEdge + { + private readonly bool isDirected = true; + private readonly bool allowParallelEdges; + private readonly VertexEdgeDictionary vertexEdges; + private int edgeCount = 0; + private int edgeCapacity = -1; + + public AdjacencyGraph() + :this(true) + {} + + public AdjacencyGraph(bool allowParallelEdges) + :this(allowParallelEdges,-1) + { + } + + public AdjacencyGraph(bool allowParallelEdges, int capacity) + { + this.allowParallelEdges = allowParallelEdges; + if (capacity > -1) + this.vertexEdges = new VertexEdgeDictionary(capacity); + else + this.vertexEdges = new VertexEdgeDictionary(); + } + + public bool IsDirected + { + get { return this.isDirected; } + } + + public bool AllowParallelEdges + { + get { return this.allowParallelEdges; } + } + + public int EdgeCapacity + { + get { return this.edgeCapacity; } + set { this.edgeCapacity = value; } + } + + public static Type VertexType + { + get { return typeof(TVertex); } + } + + public static Type EdgeType + { + get { return typeof(TEdge); } + } + + public bool IsVerticesEmpty + { + get { return this.vertexEdges.Count == 0; } + } + + public int VertexCount + { + get { return this.vertexEdges.Count; } + } + + public IEnumerable Vertices + { + get { return this.vertexEdges.Keys; } + } + + public bool ContainsVertex(TVertex v) + { + GraphContracts.AssumeNotNull(v, "v"); + return this.vertexEdges.ContainsKey(v); + } + + public bool IsOutEdgesEmpty(TVertex v) + { + GraphContracts.AssumeInVertexSet(this, v, "v"); + return this.vertexEdges[v].Count == 0; + } + + public int OutDegree(TVertex v) + { + GraphContracts.AssumeInVertexSet(this, v, "v"); + return this.vertexEdges[v].Count; + } + + public IEnumerable OutEdges(TVertex v) + { + GraphContracts.AssumeInVertexSet(this, v, "v"); + return this.vertexEdges[v]; + } + + public TEdge OutEdge(TVertex v, int index) + { + GraphContracts.AssumeInVertexSet(this, v, "v"); + return this.vertexEdges[v][index]; + } + + /// + /// Gets a value indicating whether this instance is edges empty. + /// + /// + /// true if this instance is edges empty; otherwise, false. + /// + public bool IsEdgesEmpty + { + get { return this.edgeCount == 0; } + } + + /// + /// Gets the edge count. + /// + /// The edge count. + public int EdgeCount + { + get + { + GraphContracts.Assert(this.edgeCount >= 0); + return this.edgeCount; + } + } + + /// + /// Gets the edges. + /// + /// The edges. + public IEnumerable Edges + { + get + { + foreach (EdgeList edges in this.vertexEdges.Values) + foreach (var edge in edges) + yield return edge; + } + } + + public bool ContainsEdge(TVertex source, TVertex target) + { + GraphContracts.AssumeInVertexSet(this, source, "source"); + GraphContracts.AssumeInVertexSet(this, target, "target"); + foreach (var outEdge in this.OutEdges(source)) + if (outEdge.Target.Equals(target)) + return true; + return false; + } + + public bool ContainsEdge(TEdge edge) + { + GraphContracts.AssumeInVertexSet(this, edge, "edge"); + return this.vertexEdges[edge.Source].Contains(edge); + } + + public bool TryGetEdge( + TVertex source, + TVertex target, + out TEdge edge) + { + GraphContracts.AssumeInVertexSet(this, source, "source"); + GraphContracts.AssumeInVertexSet(this, target, "target"); + + EdgeList edgeList; + if (this.vertexEdges.TryGetValue(source, out edgeList) && + edgeList.Count > 0) + { + foreach (var e in edgeList) + { + if (e.Target.Equals(target)) + { + edge = e; + return true; + } + } + } + edge = default(TEdge); + return false; + } + + public bool TryGetEdges( + TVertex source, + TVertex target, + out IEnumerable edges) + { + GraphContracts.AssumeInVertexSet(this, source, "source"); + GraphContracts.AssumeInVertexSet(this, target, "target"); + + EdgeList outEdges; + if (this.vertexEdges.TryGetValue(source, out outEdges)) + { + List list = new List(outEdges.Count); + foreach (var edge in outEdges) + if (edge.Target.Equals(target)) + list.Add(edge); + + edges = list; + return true; + } + else + { + edges = null; + return false; + } + } + + public virtual void AddVertex(TVertex v) + { + GraphContracts.AssumeNotInVertexSet(this, v, "v"); + if (this.EdgeCapacity>0) + this.vertexEdges.Add(v, new EdgeList(this.EdgeCapacity)); + else + this.vertexEdges.Add(v, new EdgeList()); + this.OnVertexAdded(new VertexEventArgs(v)); + } + + public virtual void AddVertexRange(IEnumerable vertices) + { + GraphContracts.AssumeNotNull(vertices, "vertices"); + foreach (var v in vertices) + this.AddVertex(v); + } + + public event VertexEventHandler VertexAdded; + protected virtual void OnVertexAdded(VertexEventArgs args) + { + VertexEventHandler eh = this.VertexAdded; + if (eh != null) + eh(this, args); + } + + public virtual bool RemoveVertex(TVertex v) + { + GraphContracts.AssumeNotNull(v, "v"); + if (!this.ContainsVertex(v)) + return false; + // remove outedges + { + EdgeList edges = this.vertexEdges[v]; + if (this.EdgeRemoved != null) // lazily notify + { + foreach (var edge in edges) + this.OnEdgeRemoved(new EdgeEventArgs(edge)); + } + this.edgeCount -= edges.Count; + edges.Clear(); + } + + // iterage over edges and remove each edge touching the vertex + EdgeList edgeToRemove = new EdgeList(); + foreach (var kv in this.vertexEdges) + { + if (kv.Key.Equals(v)) continue; // we've already + // collect edge to remove + foreach(var edge in kv.Value) + { + if (edge.Target.Equals(v)) + edgeToRemove.Add(edge); + } + + // remove edges + foreach (var edge in edgeToRemove) + { + kv.Value.Remove(edge); + this.OnEdgeRemoved(new EdgeEventArgs(edge)); + } + // update count + this.edgeCount -= edgeToRemove.Count; + edgeToRemove.Clear(); + } + + System.Diagnostics.Debug.Assert(this.edgeCount >= 0); + this.vertexEdges.Remove(v); + this.OnVertexRemoved(new VertexEventArgs(v)); + + return true; + } + + public event VertexEventHandler VertexRemoved; + protected virtual void OnVertexRemoved(VertexEventArgs args) + { + VertexEventHandler eh = this.VertexRemoved; + if (eh != null) + eh(this, args); + } + + public int RemoveVertexIf(VertexPredicate predicate) + { + GraphContracts.AssumeNotNull(predicate, "predicate"); + VertexList vertices = new VertexList(); + foreach (var v in this.Vertices) + if (predicate(v)) + vertices.Add(v); + + foreach (var v in vertices) + this.RemoveVertex(v); + + return vertices.Count; + } + + public virtual bool AddVerticesAndEdge(TEdge e) + { + GraphContracts.AssumeNotNull(e, "e"); + if (!this.ContainsVertex(e.Source)) + this.AddVertex(e.Source); + if (!this.ContainsVertex(e.Target)) + this.AddVertex(e.Target); + + return this.AddEdge(e); + } + + public virtual bool AddEdge(TEdge e) + { + GraphContracts.AssumeInVertexSet(this, e, "e"); + if (!this.AllowParallelEdges) + { + if (this.ContainsEdge(e.Source, e.Target)) + return false; + } + this.vertexEdges[e.Source].Add(e); + this.edgeCount++; + + this.OnEdgeAdded(new EdgeEventArgs(e)); + + return true; + } + + public void AddEdgeRange(IEnumerable edges) + { + GraphContracts.AssumeNotNull(edges, "edges"); + foreach (var edge in edges) + this.AddEdge(edge); + } + + public event EdgeEventHandler EdgeAdded; + protected virtual void OnEdgeAdded(EdgeEventArgs args) + { + var eh = this.EdgeAdded; + if (eh != null) + eh(this, args); + } + + public virtual bool RemoveEdge(TEdge e) + { + GraphContracts.AssumeInVertexSet(this, e, "e"); + if (this.vertexEdges[e.Source].Remove(e)) + { + this.edgeCount--; + System.Diagnostics.Debug.Assert(this.edgeCount >= 0); + this.OnEdgeRemoved(new EdgeEventArgs(e)); + return true; + } + else + return false; + } + + public event EdgeEventHandler EdgeRemoved; + protected virtual void OnEdgeRemoved(EdgeEventArgs args) + { + EdgeEventHandler eh = this.EdgeRemoved; + if (eh != null) + eh(this, args); + } + + public int RemoveEdgeIf(EdgePredicate predicate) + { + GraphContracts.AssumeNotNull(predicate, "predicate"); + + var edges = new EdgeList(); + foreach (var edge in this.Edges) + if (predicate(edge)) + edges.Add(edge); + + foreach (var edge in edges) + this.RemoveEdge(edge); + + GraphContracts.Assert(this.edgeCount >= 0); + return edges.Count; + } + + public void ClearOutEdges(TVertex v) + { + GraphContracts.AssumeInVertexSet(this, v, "v"); + + var edges = this.vertexEdges[v]; + int count = edges.Count; + if (this.EdgeRemoved != null) // call only if someone is listening + { + foreach (var edge in edges) + this.OnEdgeRemoved(new EdgeEventArgs(edge)); + } + edges.Clear(); + this.edgeCount -= count; + GraphContracts.Assert(this.edgeCount >= 0); + } + + public int RemoveOutEdgeIf(TVertex v, EdgePredicate predicate) + { + GraphContracts.AssumeInVertexSet(this, v, "v"); + GraphContracts.AssumeNotNull(predicate, "predicate"); + + var edges = this.vertexEdges[v]; + var edgeToRemove = new EdgeList(edges.Count); + foreach (var edge in edges) + if (predicate(edge)) + edgeToRemove.Add(edge); + + foreach (var edge in edgeToRemove) + { + edges.Remove(edge); + this.OnEdgeRemoved(new EdgeEventArgs(edge)); + } + this.edgeCount -= edgeToRemove.Count; + GraphContracts.Assert(this.edgeCount >= 0); + + return edgeToRemove.Count; + } + + public void TrimEdgeExcess() + { + foreach (var edges in this.vertexEdges.Values) + edges.TrimExcess(); + } + + public void Clear() + { + this.vertexEdges.Clear(); + this.edgeCount = 0; + } + + [Serializable] + public sealed class VertexList : List + { + internal VertexList() { } + internal VertexList(int capacity) + : base(capacity) { } + } + + [Serializable] + public sealed class EdgeList : List + { + internal EdgeList() { } + internal EdgeList(int capacity) + : base(capacity) + { } + } + + [Serializable] + public sealed class VertexEdgeDictionary : Dictionary + { + internal VertexEdgeDictionary() { } + internal VertexEdgeDictionary(int capacity) + : base(capacity) + { } + } + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/AdjacencyGraph.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/AdjacencyGraph.cs.meta new file mode 100644 index 0000000..9807e7c --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/AdjacencyGraph.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b45a62cffe9a3443286a86a6108aa7bc +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms.meta new file mode 100644 index 0000000..d977ce3 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: 8efbc7acf46fa45b585beefac447a361 +folderAsset: yes +DefaultImporter: + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/AlgoUtility.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/AlgoUtility.cs new file mode 100755 index 0000000..06e4588 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/AlgoUtility.cs @@ -0,0 +1,331 @@ +using System; +using System.Collections.Generic; +using QuickGraph.Algorithms.Condensation; +using QuickGraph.Algorithms.Search; +using QuickGraph.Algorithms.Observers; + +namespace QuickGraph.Algorithms +{ + public static class AlgoUtility + { + public static IDictionary ConstantCapacities( + IEdgeSet g, double value) + where TEdge : IEdge + { + GraphContracts.AssumeNotNull(g, "g"); + + var capacities = new Dictionary(g.EdgeCount); + foreach (var e in g.Edges) + capacities.Add(e, value); + return capacities; + } + + public static IEnumerable Sinks( + IVertexListGraph visitedGraph) + where TEdge : IEdge + { + GraphContracts.AssumeNotNull(visitedGraph, "visitedGraph"); + + foreach (var v in visitedGraph.Vertices) + if (visitedGraph.IsOutEdgesEmpty(v)) + yield return v; + } + + public static IEnumerable Roots( + IBidirectionalGraph visitedGraph) + where TEdge : IEdge + { + GraphContracts.AssumeNotNull(visitedGraph, "visitedGraph"); + + foreach (var v in visitedGraph.Vertices) + if (visitedGraph.IsInEdgesEmpty(v)) + yield return v; + } + + public static IEnumerable IsolatedVertices( + IBidirectionalGraph visitedGraph) + where TEdge : IEdge + { + GraphContracts.AssumeNotNull(visitedGraph, "visitedGraph"); + + foreach (var v in visitedGraph.Vertices) + if (visitedGraph.Degree(v) == 0) + yield return v; + } + + public static IEnumerable Roots( + IUndirectedGraph visitedGraph) + where TEdge : IEdge + { + GraphContracts.AssumeNotNull(visitedGraph, "visitedGraph"); + + var dfs = new UndirectedDepthFirstSearchAlgorithm(visitedGraph); + var vis = new VertexPredecessorRecorderObserver(); + vis.Attach(dfs); + + foreach (var predecessor in vis.VertexPredecessors) + { + if (predecessor.Value.Equals(default(TEdge))) + yield return predecessor.Key; + } + } + + public static IEnumerable Roots( + IVertexListGraph visitedGraph) + where TEdge : IEdge + { + GraphContracts.AssumeNotNull(visitedGraph, "visitedGraph"); + + var dfs = new DepthFirstSearchAlgorithm(visitedGraph); + var vis = new VertexPredecessorRecorderObserver(); + vis.Attach(dfs); + + foreach (var predecessor in vis.VertexPredecessors) + { + if (predecessor.Value.Equals(default(TEdge))) + yield return predecessor.Key; + } + } + + public static ICollection TopologicalSort( + IUndirectedGraph visitedGraph) + where TEdge : IEdge + { + GraphContracts.AssumeNotNull(visitedGraph, "visitedGraph"); + + var vertices = new List(visitedGraph.VertexCount); + TopologicalSort(visitedGraph, vertices); + return vertices; + } + + public static void TopologicalSort( + IUndirectedGraph visitedGraph, + IList vertices + ) + where TEdge : IEdge + { + GraphContracts.AssumeNotNull(visitedGraph, "visitedGraph"); + GraphContracts.AssumeNotNull(vertices, "vertices"); + + var topo = new UndirectedTopologicalSortAlgorithm(visitedGraph); + topo.Compute(vertices); + } + + public static ICollection TopologicalSort( + IVertexListGraph visitedGraph) + where TEdge : IEdge + { + GraphContracts.AssumeNotNull(visitedGraph, "visitedGraph"); + + var vertices = new List(visitedGraph.VertexCount); + TopologicalSort(visitedGraph, vertices); + return vertices; + } + + public static void TopologicalSort( + IVertexListGraph visitedGraph, + IList vertices) + where TEdge : IEdge + { + GraphContracts.AssumeNotNull(visitedGraph, "visitedGraph"); + GraphContracts.AssumeNotNull(vertices, "vertices"); + + var topo = new TopologicalSortAlgorithm(visitedGraph); + topo.Compute(vertices); + } + + public static ICollection SourceFirstTopologicalSort( + IVertexAndEdgeListGraph visitedGraph) + where TEdge : IEdge + { + GraphContracts.AssumeNotNull(visitedGraph, "visitedGraph"); + + var vertices = new List(visitedGraph.VertexCount); + SourceFirstTopologicalSort(visitedGraph, vertices); + return vertices; + } + + public static void SourceFirstTopologicalSort( + IVertexAndEdgeListGraph visitedGraph, + IList vertices) + where TEdge : IEdge + { + GraphContracts.AssumeNotNull(visitedGraph, "visitedGraph"); + GraphContracts.AssumeNotNull(vertices, "vertices"); + + var topo = new SourceFirstTopologicalSortAlgorithm(visitedGraph); + topo.Compute(vertices); + } + + public static int ConnectedComponents( + IUndirectedGraph g, + TVertex startVertex, + IDictionary components) + where TEdge : IEdge + { + GraphContracts.AssumeNotNull(g, "g"); + GraphContracts.Assume(g.ContainsVertex(startVertex), "g.ContainsVertex(startVertex)"); + GraphContracts.AssumeNotNull(components, "components"); + + var conn = new ConnectedComponentsAlgorithm(g, components); + conn.Compute(startVertex); + return conn.ComponentCount; + } + + public static int WeaklyConnectedComponents( + IVertexListGraph g, + IDictionary components) + where TEdge : IEdge + { + GraphContracts.AssumeNotNull(g, "g"); + GraphContracts.AssumeNotNull(components, "components"); + + var conn = new WeaklyConnectedComponentsAlgorithm(g, components); + conn.Compute(); + return conn.ComponentCount; + } + + public static int StronglyConnectedComponents( + IVertexListGraph g, + IDictionary components) + where TEdge : IEdge + { + GraphContracts.AssumeNotNull(g, "g"); + GraphContracts.AssumeNotNull(components, "components"); + + var conn = new StronglyConnectedComponentsAlgorithm(g, components); + conn.Compute(); + return conn.ComponentCount; + } + + public static void Clone( + IVertexAndEdgeListGraph g, + IMutableVertexAndEdgeListGraph clone) + where TVertex : ICloneable + where TEdge : ICloneableEdge + { + GraphContracts.AssumeNotNull(g, "g"); + GraphContracts.AssumeNotNull(clone, "clone"); + + var vertexClones = new Dictionary(); + + foreach (var v in g.Vertices) + { + var vc = (TVertex)v.Clone(); + clone.AddVertex(vc); + vertexClones.Add(v, vc); + } + + foreach (var edge in g.Edges) + { + var ec = (TEdge)edge.Clone( + vertexClones[edge.Source], + vertexClones[edge.Target]); + clone.AddEdge(ec); + } + } + + public static IMutableBidirectionalGraph> Condensate( + IVertexAndEdgeListGraph g) + where TEdge : IEdge + where TGraph : IMutableVertexAndEdgeListGraph, new() + { + if (g == null) + throw new ArgumentNullException("g"); + + var condensator = new CondensationGraphAlgorithm(g); + condensator.Compute(); + return condensator.CondensatedGraph; + } + + /// + /// Create a collection of odd vertices + /// + /// graph to visit + /// colleciton of odd vertices + /// g is a null reference + public static List OddVertices(IVertexAndEdgeListGraph g) + where TEdge : IEdge + { + if (g == null) + throw new ArgumentNullException("g"); + + var counts = new Dictionary(g.VertexCount); + foreach (var v in g.Vertices) + counts.Add(v,0); + + foreach (var e in g.Edges) + { + ++counts[e.Source]; + --counts[e.Target]; + } + + var odds = new List(); + foreach (var de in counts) + { + if (de.Value % 2 != 0) + odds.Add(de.Key); + } + + return odds; + } + + public static bool IsDirectedAcyclicGraph(IVertexListGraph g) + where TEdge : IEdge + { + GraphContracts.AssumeNotNull(g, "g"); + + return new DagTester().IsDag(g); + } + + private sealed class DagTester + { + private bool isDag = true; + + public bool IsDag(IVertexListGraph g) + where TEdge : IEdge + { + var dfs = new DepthFirstSearchAlgorithm(g); + try + { + dfs.BackEdge += new EdgeEventHandler(dfs_BackEdge); + isDag = true; + dfs.Compute(); + return isDag; + } + finally + { + dfs.BackEdge -= new EdgeEventHandler(dfs_BackEdge); + } + } + + void dfs_BackEdge(object sender, EdgeEventArgs e) + where Edge : IEdge + { + isDag = false; + } + } + + public static double ComputePredecessorCost( + IDictionary predecessors, + IDictionary edgeCosts, + TVertex target + ) + where TEdge : IEdge + { + GraphContracts.AssumeNotNull(predecessors, "predecessors"); + GraphContracts.AssumeNotNull(edgeCosts, "edgeCosts"); + + double cost = 0; + TVertex current = target; + TEdge edge; + + while (predecessors.TryGetValue(current, out edge)) { + cost += edgeCosts[edge]; + current = edge.Source; + } + + return cost; + } + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/AlgoUtility.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/AlgoUtility.cs.meta new file mode 100644 index 0000000..795dce5 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/AlgoUtility.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 89fbc26e814864e8c9f087e5b704f188 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/AlgorithmBase.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/AlgorithmBase.cs new file mode 100755 index 0000000..7fbd4fd --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/AlgorithmBase.cs @@ -0,0 +1,202 @@ +using System; +using QuickGraph.Algorithms.Services; +using System.Collections.Generic; + +namespace QuickGraph.Algorithms +{ + public abstract class AlgorithmBase : + IAlgorithm, + IAlgorithmComponent + { + private readonly TGraph visitedGraph; + private readonly AlgorithmServices services; + private volatile object syncRoot = new object(); + private volatile ComputationState state = ComputationState.NotRunning; + + /// + /// Creates a new algorithm with an (optional) host. + /// + /// if null, host is set to the this reference + /// + protected AlgorithmBase(IAlgorithmComponent host, TGraph visitedGraph) + { + if (host == null) + host = this; + if (visitedGraph == null) + throw new ArgumentNullException("visitedGraph"); + this.visitedGraph = visitedGraph; + this.services = new AlgorithmServices(host); + } + + protected AlgorithmBase(TGraph visitedGraph) + { + if (visitedGraph == null) + throw new ArgumentNullException("visitedGraph"); + this.visitedGraph = visitedGraph; + this.services = new AlgorithmServices(this); + } + + public TGraph VisitedGraph + { + get { return this.visitedGraph; } + } + + public IAlgorithmServices Services + { + get { return this.services; } + } + + public Object SyncRoot + { + get { return this.syncRoot; } + } + + public ComputationState State + { + get + { + lock (this.syncRoot) + { + return this.state; + } + } + } + + public void Compute() + { + this.BeginComputation(); + this.InternalCompute(); + this.EndComputation(); + } + + protected abstract void InternalCompute(); + + public void Abort() + { + bool raise = false; + lock (this.syncRoot) + { + if (this.state == ComputationState.Running) + { + this.state = ComputationState.PendingAbortion; + this.Services.CancelManager.Cancel(); + raise = true; + } + } + if (raise) + this.OnStateChanged(EventArgs.Empty); + } + + public event EventHandler StateChanged; + protected virtual void OnStateChanged(EventArgs e) + { + EventHandler eh = this.StateChanged; + if (eh!=null) + eh(this, e); + } + + public event EventHandler Started; + protected virtual void OnStarted(EventArgs e) + { + EventHandler eh = this.Started; + if (eh != null) + eh(this, e); + } + + public event EventHandler Finished; + protected virtual void OnFinished(EventArgs e) + { + EventHandler eh = this.Finished; + if (eh != null) + eh(this, e); + } + + public event EventHandler Aborted; + protected virtual void OnAborted(EventArgs e) + { + EventHandler eh = this.Aborted; + if (eh != null) + eh(this, e); + } + + protected void BeginComputation() + { + lock (this.syncRoot) + { + if (this.state != ComputationState.NotRunning) + throw new InvalidOperationException(); + + this.state = ComputationState.Running; + this.Services.CancelManager.ResetCancel(); + this.OnStarted(EventArgs.Empty); + this.OnStateChanged(EventArgs.Empty); + } + } + + protected void EndComputation() + { + lock (this.syncRoot) + { + switch (this.state) + { + case ComputationState.Running: + this.state = ComputationState.Finished; + this.OnFinished(EventArgs.Empty); + break; + case ComputationState.PendingAbortion: + this.state = ComputationState.Aborted; + this.OnAborted(EventArgs.Empty); + break; + default: + throw new InvalidOperationException(); + } + this.Services.CancelManager.ResetCancel(); + this.OnStateChanged(EventArgs.Empty); + } + } + + public T GetService() + where T : IService + { + T service; + if (!this.TryGetService(out service)) + throw new InvalidOperationException("service not found"); + return service; + } + + public bool TryGetService(out T service) + where T : IService + { + object serviceObject; + if (this.TryGetService(typeof(T), out serviceObject)) + { + service = (T)serviceObject; + return true; + } + + service = default(T); + return false; + } + + Dictionary _services; + protected virtual bool TryGetService(Type serviceType, out object service) + { + GraphContracts.AssumeNotNull(serviceType, "serviceType"); + lock (this.SyncRoot) + { + if (this._services == null) + this._services = new Dictionary(); + if (!this._services.TryGetValue(serviceType, out service)) + { + if (serviceType == typeof(ICancelManager)) + this._services[serviceType] = service = new CancelManager(); + else + this._services[serviceType] = service = null; + } + + return service != null; + + } + } + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/AlgorithmBase.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/AlgorithmBase.cs.meta new file mode 100644 index 0000000..3107698 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/AlgorithmBase.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: cee0824fd2f8543189ed0fcc274de2f4 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/AlgorithmEventHandler.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/AlgorithmEventHandler.cs new file mode 100755 index 0000000..d7f5f49 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/AlgorithmEventHandler.cs @@ -0,0 +1,10 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace QuickGraph.Algorithms +{ + public delegate void AlgorithmEventHandler( + IAlgorithm sender, + EventArgs e); +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/AlgorithmEventHandler.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/AlgorithmEventHandler.cs.meta new file mode 100644 index 0000000..dd58f75 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/AlgorithmEventHandler.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 67be721f58b044638a65be46c4e9e9a4 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/CentralityApproximationAlgorithm.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/CentralityApproximationAlgorithm.cs new file mode 100755 index 0000000..d14ea2d --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/CentralityApproximationAlgorithm.cs @@ -0,0 +1,82 @@ +using System; +using System.Collections.Generic; + +using QuickGraph.Algorithms.ShortestPath; +using QuickGraph.Algorithms.Observers; + +namespace QuickGraph.Algorithms +{ + [Serializable] + public sealed class CentralityApproximationAlgorithm : + AlgorithmBase> + where TEdge : IEdge + { + private Random rand = new Random(); + private DijkstraShortestPathAlgorithm dijkstra; + private VertexPredecessorRecorderObserver predecessorRecorder; + private int maxIterationCount = 50; + private IDictionary centralities = new Dictionary(); + + public CentralityApproximationAlgorithm( + IVertexListGraph visitedGraph, + IDictionary distances + ) + :base(visitedGraph) + { + if (distances==null) + throw new ArgumentNullException("distances"); + this.dijkstra = new DijkstraShortestPathAlgorithm( + this.VisitedGraph, + distances, + new ShortestDistanceRelaxer() + ); + this.predecessorRecorder = new VertexPredecessorRecorderObserver(); + this.predecessorRecorder.Attach(this.dijkstra); + } + + public IDictionary Distances + { + get { return this.dijkstra.Weights; } + } + + public Random Rand + { + get { return this.rand; } + set { this.rand = value; } + } + + public int MaxIterationCount + { + get { return this.maxIterationCount; } + set { this.maxIterationCount = value; } + } + + private void Initialize() + { + this.centralities.Clear(); + foreach (var v in this.VisitedGraph.Vertices) + this.centralities.Add(v, 0); + } + + protected override void InternalCompute() + { + if (this.VisitedGraph.VertexCount == 0) + return; + + // compute temporary values + int n = this.VisitedGraph.VertexCount; + for(int i = 0;i(this.VisitedGraph, this.Rand); + this.dijkstra.Compute(v); + + foreach (var u in this.VisitedGraph.Vertices) + this.centralities[u] += n * this.dijkstra.Distances[u] / (this.MaxIterationCount * (n - 1)); + } + + // update + foreach (var v in this.VisitedGraph.Vertices) + this.centralities[v] = 1.0/this.centralities[v]; + } + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/CentralityApproximationAlgorithm.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/CentralityApproximationAlgorithm.cs.meta new file mode 100644 index 0000000..fb66180 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/CentralityApproximationAlgorithm.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 19512a09eb387494f938ab982fbf2e77 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/ComputationState.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/ComputationState.cs new file mode 100755 index 0000000..99ccb63 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/ComputationState.cs @@ -0,0 +1,14 @@ +using System; + +namespace QuickGraph.Algorithms +{ + [Serializable] + public enum ComputationState + { + NotRunning, + Running, + PendingAbortion, + Finished, + Aborted + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/ComputationState.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/ComputationState.cs.meta new file mode 100644 index 0000000..619566a --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/ComputationState.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 5d8efbe7dc2294f068a7030f3fb06a26 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Condensation.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Condensation.meta new file mode 100644 index 0000000..a3bfa83 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Condensation.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: 55ef485efbff643cc8984c6e972e9381 +folderAsset: yes +DefaultImporter: + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Condensation/CondensatedEdge.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Condensation/CondensatedEdge.cs new file mode 100755 index 0000000..a837be6 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Condensation/CondensatedEdge.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using QuickGraph.Collections; + +namespace QuickGraph.Algorithms.Condensation +{ + [Serializable] + public sealed class CondensatedEdge : Edge + where TEdge : IEdge + where TGraph : IMutableVertexAndEdgeListGraph, new() + { + private List edges = new List(); + public CondensatedEdge(TGraph source, TGraph target) + :base(source,target) + { } + + public IList Edges + { + get { return this.edges; } + } + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Condensation/CondensatedEdge.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Condensation/CondensatedEdge.cs.meta new file mode 100644 index 0000000..d7b43b2 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Condensation/CondensatedEdge.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 93f7a6ea0b1b748ae95cfd44628c122b +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Condensation/CondensationGraphAlgorithm.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Condensation/CondensationGraphAlgorithm.cs new file mode 100755 index 0000000..9b0d873 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Condensation/CondensationGraphAlgorithm.cs @@ -0,0 +1,149 @@ +using System; +using System.Collections.Generic; +using QuickGraph.Collections; + +namespace QuickGraph.Algorithms.Condensation +{ + public sealed class CondensationGraphAlgorithm : + AlgorithmBase> + where TEdge : IEdge + where TGraph : IMutableVertexAndEdgeListGraph, new() + { + private bool stronglyConnected = true; + + private IMutableBidirectionalGraph< + TGraph, + CondensatedEdge + > condensatedGraph; + + public CondensationGraphAlgorithm(IVertexAndEdgeListGraph visitedGraph) + :base(visitedGraph) + {} + + public IMutableBidirectionalGraph< + TGraph, + CondensatedEdge + > CondensatedGraph + { + get { return this.condensatedGraph; } + } + + public bool StronglyConnected + { + get { return this.stronglyConnected; } + set { this.stronglyConnected = value; } + } + + protected override void InternalCompute() + { + // create condensated graph + this.condensatedGraph = new BidirectionalGraph< + TGraph, + CondensatedEdge + >(false); + if (this.VisitedGraph.VertexCount == 0) + return; + + // compute strongly connected components + var components = new Dictionary(this.VisitedGraph.VertexCount); + int componentCount = ComputeComponentCount(components); + + var cancelManager = this.Services.CancelManager; + if (cancelManager.IsCancelling) return; + + // create list vertices + var condensatedVertices = new Dictionary(componentCount); + for (int i = 0; i < componentCount; ++i) + { + if (cancelManager.IsCancelling) return; + + TGraph v = new TGraph(); + condensatedVertices.Add(i, v); + this.condensatedGraph.AddVertex(v); + } + + // addingvertices + foreach (var v in this.VisitedGraph.Vertices) + { + condensatedVertices[components[v]].AddVertex(v); + } + if (cancelManager.IsCancelling) return; + + // condensated edges + var condensatedEdges = new Dictionary>(componentCount); + + // iterate over edges and condensate graph + foreach (var edge in this.VisitedGraph.Edges) + { + if (cancelManager.IsCancelling) return; + + // get component ids + int sourceID = components[edge.Source]; + int targetID = components[edge.Target]; + + // get vertices + TGraph sources = condensatedVertices[sourceID]; + if (sourceID == targetID) + { + sources.AddEdge(edge); + continue; + } + + // + TGraph targets = condensatedVertices[targetID]; + + // at last add edge + var edgeKey = new EdgeKey(sourceID, targetID); + CondensatedEdge condensatedEdge; + if (!condensatedEdges.TryGetValue(edgeKey, out condensatedEdge)) + { + condensatedEdge = new CondensatedEdge(sources, targets); + condensatedEdges.Add(edgeKey, condensatedEdge); + this.condensatedGraph.AddEdge(condensatedEdge); + } + condensatedEdge.Edges.Add(edge); + } + } + + private int ComputeComponentCount(Dictionary components) + { + IConnectedComponentAlgorithm> componentAlgorithm; + if (this.StronglyConnected) + componentAlgorithm = new StronglyConnectedComponentsAlgorithm( + this, + this.VisitedGraph, + components); + else + componentAlgorithm = new WeaklyConnectedComponentsAlgorithm( + this, + this.VisitedGraph, + components); + componentAlgorithm.Compute(); + return componentAlgorithm.ComponentCount; + } + + private struct EdgeKey : IEquatable + { + int SourceID; + int TargetID; + + public EdgeKey(int sourceID, int targetID) + { + SourceID = sourceID; + TargetID = targetID; + } + + public bool Equals(EdgeKey other) + { + return + SourceID == other.SourceID + && TargetID == other.TargetID; + } + + public override int GetHashCode() + { + return HashCodeHelper.Combine(this.SourceID, this.TargetID); + } + } + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Condensation/CondensationGraphAlgorithm.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Condensation/CondensationGraphAlgorithm.cs.meta new file mode 100644 index 0000000..ca79d84 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Condensation/CondensationGraphAlgorithm.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 837e6a695ed574f06a9fbc378d47b4e3 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Condensation/EdgeMergeCondensationGraphAlgorithm.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Condensation/EdgeMergeCondensationGraphAlgorithm.cs new file mode 100755 index 0000000..bf69757 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Condensation/EdgeMergeCondensationGraphAlgorithm.cs @@ -0,0 +1,106 @@ +using System; +using System.Collections.Generic; + +namespace QuickGraph.Algorithms.Condensation +{ + public sealed class EdgeMergeCondensationGraphAlgorithm : + AlgorithmBase> + where TEdge : IEdge + { + private IMutableBidirectionalGraph< + TVertex, + MergedEdge + > condensatedGraph; + private VertexPredicate vertexPredicate; + + public EdgeMergeCondensationGraphAlgorithm( + IBidirectionalGraph visitedGraph, + IMutableBidirectionalGraph> condensatedGraph, + VertexPredicate vertexPredicate + ) + :base(visitedGraph) + { + if (condensatedGraph == null) + throw new ArgumentNullException("condensatedGraph"); + if (vertexPredicate == null) + throw new ArgumentNullException("vertexPredicate"); + + this.condensatedGraph = condensatedGraph; + this.vertexPredicate = vertexPredicate; + } + + public IMutableBidirectionalGraph + > CondensatedGraph + { + get { return this.condensatedGraph; } + } + + public VertexPredicate VertexPredicate + { + get { return this.vertexPredicate; } + } + + protected override void InternalCompute() + { + // adding vertices to the new graph + // and pusing filtered vertices in queue + Queue filteredVertices = new Queue(); + foreach (var v in this.VisitedGraph.Vertices) + { + this.CondensatedGraph.AddVertex(v); + if (!this.VertexPredicate(v)) + filteredVertices.Enqueue(v); + } + + // adding all edges + foreach (var edge in this.VisitedGraph.Edges) + { + MergedEdge mergedEdge = new MergedEdge(edge.Source, edge.Target); + mergedEdge.Edges.Add(edge); + + this.CondensatedGraph.AddEdge(mergedEdge); + } + + // remove vertices + while (filteredVertices.Count > 0) + { + TVertex filteredVertex = filteredVertices.Dequeue(); + + // do the cross product between inedges and outedges + MergeVertex(filteredVertex); + } + } + + private void MergeVertex(TVertex v) + { + // get in edges and outedge + List> inEdges = + new List>(this.CondensatedGraph.InEdges(v)); + List> outEdges = + new List>(this.CondensatedGraph.OutEdges(v)); + + // remove vertex + this.CondensatedGraph.RemoveVertex(v); + + // add condensated edges + for (int i = 0; i < inEdges.Count; ++i) + { + MergedEdge inEdge = inEdges[i]; + if (inEdge.Source.Equals(v)) + continue; + + for (int j = 0; j < outEdges.Count; ++j) + { + MergedEdge outEdge = outEdges[j]; + if (outEdge.Target.Equals(v)) + continue; + + MergedEdge newEdge = + MergedEdge.Merge(inEdge, outEdge); + this.CondensatedGraph.AddEdge(newEdge); + } + } + } + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Condensation/EdgeMergeCondensationGraphAlgorithm.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Condensation/EdgeMergeCondensationGraphAlgorithm.cs.meta new file mode 100644 index 0000000..e3c1970 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Condensation/EdgeMergeCondensationGraphAlgorithm.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 95ba75344ded843e289c04b133cc8629 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Condensation/MergedEdge.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Condensation/MergedEdge.cs new file mode 100755 index 0000000..2a00cb4 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Condensation/MergedEdge.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using QuickGraph.Collections; + +namespace QuickGraph.Algorithms.Condensation +{ + [Serializable] + public sealed class MergedEdge : Edge + where TEdge : IEdge + { + private List edges = new List(); + + public MergedEdge(TVertex source, TVertex target) + :base(source,target) + { } + + public IList Edges + { + get { return this.edges; } + } + + public static MergedEdge Merge( + MergedEdge inEdge, + MergedEdge outEdge + ) + { + MergedEdge newEdge = new MergedEdge( + inEdge.Source, outEdge.Target); + newEdge.edges = new List(inEdge.Edges.Count + outEdge.Edges.Count); + newEdge.edges.AddRange(inEdge.Edges); + newEdge.edges.AddRange(outEdge.edges); + + return newEdge; + } + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Condensation/MergedEdge.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Condensation/MergedEdge.cs.meta new file mode 100644 index 0000000..fd653e4 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Condensation/MergedEdge.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 17b0e3b604249468f9afd303dbfe7b6a +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/ConnectedComponentsAlgorithm.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/ConnectedComponentsAlgorithm.cs new file mode 100755 index 0000000..420e5b8 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/ConnectedComponentsAlgorithm.cs @@ -0,0 +1,100 @@ +using System; +using System.Collections.Generic; + +using QuickGraph.Algorithms.Search; +using QuickGraph.Algorithms.Services; + +namespace QuickGraph.Algorithms +{ + [Serializable] + public sealed class ConnectedComponentsAlgorithm : + RootedAlgorithmBase>, + IConnectedComponentAlgorithm> + where TEdge : IEdge + { + private IDictionary components; + private int componentCount=0; + + public ConnectedComponentsAlgorithm(IUndirectedGraph g) + :this(g, new Dictionary()) + { } + + public ConnectedComponentsAlgorithm( + IUndirectedGraph visitedGraph, + IDictionary components) + : this(null, visitedGraph, components) + { } + + public ConnectedComponentsAlgorithm( + IAlgorithmComponent host, + IUndirectedGraph visitedGraph, + IDictionary components) + :base(host, visitedGraph) + { + if (components == null) + throw new ArgumentNullException("components"); + + this.components = components; + } + + public IDictionary Components + { + get + { + return this.components; + } + } + + public int ComponentCount + { + get { return this.componentCount; } + } + + private void StartVertex(Object sender, VertexEventArgs args) + { + ++this.componentCount; + } + + private void DiscoverVertex(Object sender, VertexEventArgs args) + { + Components[args.Vertex] = this.componentCount; + } + + protected override void InternalCompute() + { + this.componentCount = -1; + this.components.Clear(); + + UndirectedDepthFirstSearchAlgorithm dfs = null; + try + { + dfs = new UndirectedDepthFirstSearchAlgorithm( + this, + this.VisitedGraph, + new Dictionary(this.VisitedGraph.VertexCount) + ); + + dfs.StartVertex += new VertexEventHandler(this.StartVertex); + dfs.DiscoverVertex += new VertexEventHandler(this.DiscoverVertex); + + if (this.VisitedGraph.VertexCount != 0) + { + TVertex rootVertex; + if (!this.TryGetRootVertex(out rootVertex)) + rootVertex = TraversalHelper.GetFirstVertex(this.VisitedGraph); + dfs.Compute(rootVertex); + } + + ++this.componentCount; + } + finally + { + if (dfs != null) + { + dfs.StartVertex -= new VertexEventHandler(this.StartVertex); + dfs.DiscoverVertex -= new VertexEventHandler(this.DiscoverVertex); + } + } + } + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/ConnectedComponentsAlgorithm.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/ConnectedComponentsAlgorithm.cs.meta new file mode 100644 index 0000000..9aa7a64 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/ConnectedComponentsAlgorithm.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 3f74b052c713f4263a0c0d6bfb8171cf +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/EulerianTrailAlgorithm.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/EulerianTrailAlgorithm.cs new file mode 100755 index 0000000..02b1069 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/EulerianTrailAlgorithm.cs @@ -0,0 +1,465 @@ +using System; +using System.Collections.Generic; + +using QuickGraph.Algorithms.Search; +using QuickGraph.Algorithms.Observers; +using QuickGraph.Algorithms.Services; + +namespace QuickGraph.Algorithms +{ + [Serializable] + public sealed class EulerianTrailAlgorithm : + RootedAlgorithmBase>, + ITreeBuilderAlgorithm + where TEdge : IEdge + { + private List circuit; + private List temporaryCircuit; + private TVertex currentVertex; + private List temporaryEdges; + + public EulerianTrailAlgorithm( + IMutableVertexAndEdgeListGraph visitedGraph) + : this(null, visitedGraph) + { } + + /// + /// Construct an eulerian trail builder + /// + /// + public EulerianTrailAlgorithm( + IAlgorithmComponent host, + IMutableVertexAndEdgeListGraph visitedGraph) + :base(host, visitedGraph) + { + this.circuit = new List(); + this.temporaryCircuit = new List(); + this.currentVertex = default(TVertex); + this.temporaryEdges = new List(); + } + + public List Circuit + { + get + { + return circuit; + } + } + + private bool NotInCircuit(TEdge edge) + { + return !this.circuit.Contains(edge) + && !this.temporaryCircuit.Contains(edge); + } + + private IEnumerable SelectOutEdgesNotInCircuit(TVertex v) + { + foreach (var edge in VisitedGraph.OutEdges(v)) + if (this.NotInCircuit(edge)) + yield return edge; + } + + private TEdge SelectSingleOutEdgeNotInCircuit(TVertex v) + { + IEnumerable en = this.SelectOutEdgesNotInCircuit(v); + IEnumerator eor = en.GetEnumerator(); + if (!eor.MoveNext()) + return default(TEdge); + else + return eor.Current; + } + + public event EdgeEventHandler TreeEdge; + private void OnTreeEdge(TEdge e) + { + if (TreeEdge != null) + TreeEdge(this, new EdgeEventArgs(e)); + } + + public event EdgeEventHandler CircuitEdge; + private void OnCircuitEdge(TEdge e) + { + if (CircuitEdge != null) + CircuitEdge(this, new EdgeEventArgs(e)); + } + + public event EdgeEventHandler VisitEdge; + private void OnVisitEdge(TEdge e) + { + if (VisitEdge != null) + VisitEdge(this, new EdgeEventArgs(e)); + } + + private bool Search(TVertex u) + { + foreach (var e in SelectOutEdgesNotInCircuit(u)) + { + OnTreeEdge(e); + TVertex v = e.Target; + // add edge to temporary path + this.temporaryCircuit.Add(e); + // e.Target should be equal to CurrentVertex. + if (e.Target.Equals(this.currentVertex)) + return true; + + // continue search + if (Search(v)) + return true; + else + // remove edge + this.temporaryCircuit.Remove(e); + } + + // it's a dead end. + return false; + } + + + /// + /// Looks for a new path to add to the current vertex. + /// + /// true if found a new path, false otherwize + private bool Visit() + { + // find a vertex that needs to be visited + foreach (var e in Circuit) + { + TEdge fe = SelectSingleOutEdgeNotInCircuit(e.Source); + if (fe != null) + { + OnVisitEdge(fe); + this.currentVertex = e.Source; + if (Search(currentVertex)) + return true; + } + } + + // Could not augment circuit + return false; + } + + /// + /// Computes the number of eulerian trail in the graph. + /// + /// + /// number of eulerian trails + public static int ComputeEulerianPathCount(IVertexAndEdgeListGraph g) + { + if (g == null) + throw new ArgumentNullException("g"); + + if (g.EdgeCount < g.VertexCount) + return 0; + + int odd = AlgoUtility.OddVertices(g).Count; + if (odd == 0) + return 1; + else if (odd % 2 != 0) + return 0; + else + return odd / 2; + } + + /// + /// Merges the temporary circuit with the current circuit + /// + /// true if all the graph edges are in the circuit + private bool CircuitAugmentation() + { + List newC = new List(this.circuit.Count + this.temporaryCircuit.Count); + int i, j; + + // follow C until w is found + for (i = 0; i < Circuit.Count; ++i) + { + TEdge e = Circuit[i]; + if (e.Source.Equals(currentVertex)) + break; + newC.Add(e); + } + + // follow D until w is found again + for (j = 0; j < this.temporaryCircuit.Count; ++j) + { + TEdge e = this.temporaryCircuit[j]; + newC.Add(e); + OnCircuitEdge(e); + if (e.Target.Equals(this.currentVertex)) + break; + } + this.temporaryCircuit.Clear(); + + // continue C + for (; i < Circuit.Count; ++i) + { + TEdge e = this.Circuit[i]; + newC.Add(e); + } + + // set as new circuit + circuit = newC; + + // check if contains all edges + if (this.circuit.Count == this.VisitedGraph.EdgeCount) + return true; + + return false; + } + + protected override void InternalCompute() + { + if (this.VisitedGraph.VertexCount == 0) + return; + + TVertex rootVertex; + if (!this.TryGetRootVertex(out rootVertex)) + rootVertex = TraversalHelper.GetFirstVertex(this.VisitedGraph); + + this.currentVertex = rootVertex; + // start search + Search(this.currentVertex); + if (CircuitAugmentation()) + return; // circuit is found + + do + { + if (!Visit()) + break; // visit edges and build path + if (CircuitAugmentation()) + break; // circuit is found + } while (true); + } + + /// + /// Adds temporary edges to the graph to make all vertex even. + /// + /// + /// + public List AddTemporaryEdges(IEdgeFactory edgeFactory) + { + // first gather odd edges. + List oddVertices = AlgoUtility.OddVertices(this.VisitedGraph); + + // check that there are an even number of them + if (oddVertices.Count % 2 != 0) + throw new Exception("number of odd vertices in not even!"); + + // add temporary edges to create even edges: + this.temporaryEdges = new List(); + + bool found, foundbe, foundadjacent; + while (oddVertices.Count > 0) + { + TVertex u = oddVertices[0]; + // find adjacent odd vertex. + found = false; + foundadjacent = false; + foreach (var e in this.VisitedGraph.OutEdges(u)) + { + TVertex v = e.Target; + if (!v.Equals(u) && oddVertices.Contains(v)) + { + foundadjacent = true; + // check that v does not have an out-edge towards u + foundbe = false; + foreach (var be in this.VisitedGraph.OutEdges(v)) + { + if (be.Target.Equals(u)) + { + foundbe = true; + break; + } + } + if (foundbe) + continue; + // add temporary edge + TEdge tempEdge = edgeFactory.CreateEdge(v, u); + if (!this.VisitedGraph.AddEdge(tempEdge)) + throw new InvalidOperationException(); + // add to collection + temporaryEdges.Add(tempEdge); + // remove u,v from oddVertices + oddVertices.Remove(u); + oddVertices.Remove(v); + // set u to null + found = true; + break; + } + } + + if (!foundadjacent) + { + // pick another vertex + if (oddVertices.Count < 2) + throw new Exception("Eulerian trail failure"); + TVertex v = oddVertices[1]; + TEdge tempEdge = edgeFactory.CreateEdge(u, v); + if (!this.VisitedGraph.AddEdge(tempEdge)) + throw new InvalidOperationException(); + // add to collection + temporaryEdges.Add(tempEdge); + // remove u,v from oddVertices + oddVertices.Remove(u); + oddVertices.Remove(v); + // set u to null + found = true; + + } + + if (!found) + { + oddVertices.Remove(u); + oddVertices.Add(u); + } + } + return this.temporaryEdges; + } + + /// + /// Removes temporary edges + /// + /// + public void RemoveTemporaryEdges() + { + // remove from graph + foreach (var e in temporaryEdges) + this.VisitedGraph.RemoveEdge(e); + this.temporaryEdges.Clear(); + } + + /// + /// Computes the set of eulerian trails that traverse the edge set. + /// + /// + /// This method returns a set of disjoint eulerian trails. This set + /// of trails spans the entire set of edges. + /// + /// Eulerian trail set + public ICollection> Trails() + { + List> trails = new List>(); + + List trail = new List(); + foreach (var e in this.Circuit) + { + if (this.temporaryEdges.Contains(e)) + { + // store previous trail and start new one. + if (trail.Count != 0) + trails.Add(trail); + // start new trail + trail = new List(); + } + else + trail.Add(e); + } + if (trail.Count != 0) + trails.Add(trail); + + return trails; + } + + /// + /// Computes a set of eulerian trail, starting at + /// that spans the entire graph. + /// + /// + /// + /// This method computes a set of eulerian trail starting at + /// that spans the entire graph.The algorithm outline is as follows: + /// + /// + /// The algorithms iterates throught the Eulerian circuit of the augmented + /// graph (the augmented graph is the graph with additional edges to make + /// the number of odd vertices even). + /// + /// + /// If the current edge is not temporary, it is added to the current trail. + /// + /// + /// If the current edge is temporary, the current trail is finished and + /// added to the trail collection. The shortest path between the + /// start vertex and the target vertex of the + /// temporary edge is then used to start the new trail. This shortest + /// path is computed using the . + /// + /// + /// start vertex + /// eulerian trail set, all starting at s + /// s is a null reference. + /// Eulerian trail not computed yet. + public ICollection> Trails(TVertex s) + { + if (s == null) + throw new ArgumentNullException("s"); + if (this.Circuit.Count == 0) + throw new Exception("Circuit is empty"); + + // find the first edge in the circuit. + int i = 0; + for (i = 0; i < this.Circuit.Count; ++i) + { + TEdge e = this.Circuit[i]; + if (this.temporaryEdges.Contains(e)) + continue; + if (e.Source.Equals(s)) + break; + } + if (i == this.Circuit.Count) + throw new Exception("Did not find vertex in eulerian trail?"); + + // create collections + List> trails = new List>(); + List trail = new List(); + BreadthFirstSearchAlgorithm bfs = + new BreadthFirstSearchAlgorithm(VisitedGraph); + VertexPredecessorRecorderObserver vis = + new VertexPredecessorRecorderObserver(); + vis.Attach(bfs); + bfs.Compute(s); + + // go throught the edges and build the predecessor table. + int start = i; + for (; i < this.Circuit.Count; ++i) + { + TEdge e = this.Circuit[i]; + if (this.temporaryEdges.Contains(e)) + { + // store previous trail and start new one. + if (trail.Count != 0) + trails.Add(trail); + // start new trail + // take the shortest path from the start vertex to + // the target vertex + trail = vis.Path(e.Target); + } + else + trail.Add(e); + } + + // starting again on the circuit + for (i = 0; i < start; ++i) + { + TEdge e = this.Circuit[i]; + if (this.temporaryEdges.Contains(e)) + { + // store previous trail and start new one. + if (trail.Count != 0) + trails.Add(trail); + // start new trail + // take the shortest path from the start vertex to + // the target vertex + trail = vis.Path(e.Target); + } + else + trail.Add(e); + } + + // adding the last element + if (trail.Count != 0) + trails.Add(trail); + + return trails; + } + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/EulerianTrailAlgorithm.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/EulerianTrailAlgorithm.cs.meta new file mode 100644 index 0000000..9e6463e --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/EulerianTrailAlgorithm.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: a940e93d8117f4284a84d4f30c98b8bd +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Exploration.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Exploration.meta new file mode 100644 index 0000000..f5b6705 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Exploration.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: f3524a21373dc4caa93b0111d51c0890 +folderAsset: yes +DefaultImporter: + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Exploration/CloneableVertexGraphExplorerAlgorithm.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Exploration/CloneableVertexGraphExplorerAlgorithm.cs new file mode 100755 index 0000000..46dad20 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Exploration/CloneableVertexGraphExplorerAlgorithm.cs @@ -0,0 +1,213 @@ +using System; +using System.Collections.Generic; + +using QuickGraph.Predicates; +using QuickGraph.Algorithms.Services; + +namespace QuickGraph.Algorithms.Exploration +{ + public sealed class CloneableVertexGraphExplorerAlgorithm : + RootedAlgorithmBase>, + ITreeBuilderAlgorithm + where TVertex : ICloneable, IComparable + where TEdge : IEdge + { + private IList> transitionFactories = new List>(); + + private Queue unexploredVertices = new Queue(); + + private VertexPredicate addVertexPredicate = new AnyVertexPredicate().Test; + private VertexPredicate exploreVertexPredicate = new AnyVertexPredicate().Test; + private EdgePredicate addEdgePredicate = new AnyEdgePredicate().Test; + private IPredicate> finishedPredicate = + new DefaultFinishedPredicate(); + private bool finishedSuccessfully; + + public CloneableVertexGraphExplorerAlgorithm( + IMutableVertexAndEdgeListGraph visitedGraph + ) + : this(null, visitedGraph) + { } + + public CloneableVertexGraphExplorerAlgorithm( + IAlgorithmComponent host, + IMutableVertexAndEdgeListGraph visitedGraph + ) + :base(host, visitedGraph) + {} + + public IList> TransitionFactories + { + get { return this.transitionFactories; } + } + + public VertexPredicate AddVertexPredicate + { + get { return this.addVertexPredicate; } + set { this.addVertexPredicate = value; } + } + + public VertexPredicate ExploreVertexPredicate + { + get { return this.exploreVertexPredicate; } + set { this.exploreVertexPredicate = value; } + } + + public EdgePredicate AddEdgePredicate + { + get { return this.addEdgePredicate; } + set { this.addEdgePredicate = value; } + } + + public IPredicate> FinishedPredicate + { + get { return this.finishedPredicate; } + set { this.finishedPredicate = value; } + } + + public IEnumerable UnexploredVertices + { + get { return this.unexploredVertices; } + } + + public bool FinishedSuccessfully + { + get { return this.finishedSuccessfully; } + } + + public event VertexEventHandler DiscoverVertex; + private void OnDiscoverVertex(TVertex v) + { + this.VisitedGraph.AddVertex(v); + this.unexploredVertices.Enqueue(v); + if (this.DiscoverVertex != null) + this.DiscoverVertex(this, new VertexEventArgs(v)); + } + public event EdgeEventHandler TreeEdge; + private void OnTreeEdge(TEdge e) + { + if (this.TreeEdge != null) + this.TreeEdge(this, new EdgeEventArgs(e)); + } + public event EdgeEventHandler BackEdge; + private void OnBackEdge(TEdge e) + { + if (this.BackEdge != null) + this.BackEdge(this, new EdgeEventArgs(e)); + } + public event EdgeEventHandler EdgeSkipped; + private void OnEdgeSkipped(TEdge e) + { + if (this.EdgeSkipped != null) + this.EdgeSkipped(this, new EdgeEventArgs(e)); + } + + protected override void InternalCompute() + { + TVertex rootVertex; + if (!this.TryGetRootVertex(out rootVertex)) + throw new InvalidOperationException("RootVertex is not specified"); + + this.VisitedGraph.Clear(); + this.unexploredVertices.Clear(); + this.finishedSuccessfully = false; + + if (!this.AddVertexPredicate(rootVertex)) + throw new ArgumentException("StartVertex does not satisfy AddVertexPredicate"); + this.OnDiscoverVertex(rootVertex); + + while (unexploredVertices.Count > 0) + { + // are we done yet ? + if (!this.FinishedPredicate.Test(this)) + { + this.finishedSuccessfully = false; + return; + } + + TVertex current = unexploredVertices.Dequeue(); + TVertex clone = (TVertex)current.Clone(); + + // let's make sure we want to explore this one + if (!this.ExploreVertexPredicate(clone)) + continue; + + foreach (ITransitionFactory transitionFactory in this.TransitionFactories) + { + GenerateFromTransitionFactory(clone, transitionFactory); + } + } + + this.finishedSuccessfully = true; + } + + private void GenerateFromTransitionFactory( + TVertex current, + ITransitionFactory transitionFactory + ) + { + if (!transitionFactory.IsValid(current)) + return; + + foreach (var transition in transitionFactory.Apply(current)) + { + if ( + !this.AddVertexPredicate(transition.Target) + || !this.AddEdgePredicate(transition)) + { + this.OnEdgeSkipped(transition); + continue; + } + + bool backEdge = this.VisitedGraph.ContainsVertex(transition.Target); + if (!backEdge) + this.OnDiscoverVertex(transition.Target); + + this.VisitedGraph.AddEdge(transition); + if (backEdge) + this.OnBackEdge(transition); + else + this.OnTreeEdge(transition); + } + } + + public sealed class DefaultFinishedPredicate : + IPredicate> + { + private int maxVertexCount = 1000; + private int maxEdgeCount = 1000; + + public DefaultFinishedPredicate() + { } + + public DefaultFinishedPredicate( + int maxVertexCount, + int maxEdgeCount) + { + this.maxVertexCount = maxVertexCount; + this.maxEdgeCount = maxEdgeCount; + } + + public int MaxVertexCount + { + get { return this.maxVertexCount; } + set { this.maxVertexCount = value; } + } + + public int MaxEdgeCount + { + get { return this.maxEdgeCount; } + set { this.maxEdgeCount = value; } + } + + public bool Test(CloneableVertexGraphExplorerAlgorithm t) + { + if (t.VisitedGraph.VertexCount > this.MaxVertexCount) + return false; + if (t.VisitedGraph.EdgeCount > this.MaxEdgeCount) + return false; + return true; + } + } + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Exploration/CloneableVertexGraphExplorerAlgorithm.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Exploration/CloneableVertexGraphExplorerAlgorithm.cs.meta new file mode 100644 index 0000000..a3792e7 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Exploration/CloneableVertexGraphExplorerAlgorithm.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 02dff452d0e0a44298315814928be32f +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Exploration/ITransitionFactory.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Exploration/ITransitionFactory.cs new file mode 100755 index 0000000..5e8f7ae --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Exploration/ITransitionFactory.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; + +namespace QuickGraph.Algorithms.Exploration +{ + public interface ITransitionFactory + where TVertex : ICloneable + where TEdge : IEdge + { + bool IsValid(TVertex v); + IEnumerable Apply(TVertex source); + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Exploration/ITransitionFactory.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Exploration/ITransitionFactory.cs.meta new file mode 100644 index 0000000..df4fc01 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Exploration/ITransitionFactory.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 7d36da0bf200c46dabc3deb6a4c1df18 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Exploration/TransitionFactoryImplicitGraph.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Exploration/TransitionFactoryImplicitGraph.cs new file mode 100755 index 0000000..a688abd --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Exploration/TransitionFactoryImplicitGraph.cs @@ -0,0 +1,90 @@ +using System; +using System.Collections.Generic; +using System.Web; + +using QuickGraph.Predicates; + +namespace QuickGraph.Algorithms.Exploration +{ + public sealed class TransitionFactoryImplicitGraph : + IImplicitGraph + where TVertex : ICloneable + where TEdge : IEdge + { + private IList> transitionFactories + = new List>(); + private VertexPredicate successorVertexPredicate + = new AnyVertexPredicate().Test; + private EdgePredicate successorEdgePredicate + = new AnyEdgePredicate().Test; + + public TransitionFactoryImplicitGraph() + {} + + public IList> TransitionFactories + { + get { return this.transitionFactories; } + } + + public VertexPredicate SuccessorVertexPredicate + { + get { return this.successorVertexPredicate; } + set { this.successorVertexPredicate = value; } + } + + public EdgePredicate SuccessorEdgePredicate + { + get { return this.successorEdgePredicate; } + set { this.successorEdgePredicate = value; } + } + + public bool IsOutEdgesEmpty(TVertex v) + { + return this.OutDegree(v) == 0; + } + + public int OutDegree(TVertex v) + { + int i = 0; + foreach(TEdge edge in this.OutEdges(v)) + i++; + return i; + } + + public IEnumerable OutEdges(TVertex v) + { + foreach (ITransitionFactory transitionFactory + in this.TransitionFactories) + { + if (!transitionFactory.IsValid(v)) + continue; + + foreach (var edge in transitionFactory.Apply(v)) + { + if (this.SuccessorVertexPredicate(edge.Target) && + this.SuccessorEdgePredicate(edge)) + yield return edge; + } + } + } + + public TEdge OutEdge(TVertex v, int index) + { + int i = 0; + foreach (var e in this.OutEdges(v)) + if (i++ == index) + return e; + throw new ArgumentOutOfRangeException("index"); + } + + public bool IsDirected + { + get { return true; } + } + + public bool AllowParallelEdges + { + get { return true; } + } + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Exploration/TransitionFactoryImplicitGraph.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Exploration/TransitionFactoryImplicitGraph.cs.meta new file mode 100644 index 0000000..6feef29 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Exploration/TransitionFactoryImplicitGraph.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 7d3af236a89624bd4a47ab82205e1101 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/IAlgorithm.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/IAlgorithm.cs new file mode 100755 index 0000000..1b1d894 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/IAlgorithm.cs @@ -0,0 +1,11 @@ +using System; +using QuickGraph.Algorithms.Services; + +namespace QuickGraph.Algorithms +{ + public interface IAlgorithm : + IComputation + { + TGraph VisitedGraph { get;} + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/IAlgorithm.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/IAlgorithm.cs.meta new file mode 100644 index 0000000..8eb78c9 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/IAlgorithm.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 34fcc00df114c400cbf489b982a8fd19 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/IComputation.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/IComputation.cs new file mode 100755 index 0000000..3760d38 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/IComputation.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace QuickGraph.Algorithms +{ + public interface IComputation + { + object SyncRoot { get; } + ComputationState State { get; } + + void Compute(); + void Abort(); + + event EventHandler StateChanged; + event EventHandler Started; + event EventHandler Finished; + event EventHandler Aborted; + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/IComputation.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/IComputation.cs.meta new file mode 100644 index 0000000..3ec3d2f --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/IComputation.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 6b96eaa25642248f6b768d338c733e6c +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/IConnectedComponentAlgorithm.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/IConnectedComponentAlgorithm.cs new file mode 100755 index 0000000..7548022 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/IConnectedComponentAlgorithm.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace QuickGraph.Algorithms +{ + public interface IConnectedComponentAlgorithm : IAlgorithm + where TGraph : IGraph + where TEdge : IEdge + { + int ComponentCount { get;} + IDictionary Components { get;} + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/IConnectedComponentAlgorithm.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/IConnectedComponentAlgorithm.cs.meta new file mode 100644 index 0000000..9fd381e --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/IConnectedComponentAlgorithm.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 877c61d80ee594c83bbf5b27b0451232 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/IDistanceRecorderAlgorithm.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/IDistanceRecorderAlgorithm.cs new file mode 100755 index 0000000..e290517 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/IDistanceRecorderAlgorithm.cs @@ -0,0 +1,12 @@ +using System; + +namespace QuickGraph.Algorithms +{ + public interface IDistanceRecorderAlgorithm + where TEdge : IEdge + { + event VertexEventHandler InitializeVertex; + event VertexEventHandler DiscoverVertex; + event EdgeEventHandler TreeEdge; + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/IDistanceRecorderAlgorithm.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/IDistanceRecorderAlgorithm.cs.meta new file mode 100644 index 0000000..1df0e5f --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/IDistanceRecorderAlgorithm.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: dc9d326915c874296834d9364a8865d0 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/IEdgeColorizerAlgorithm.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/IEdgeColorizerAlgorithm.cs new file mode 100755 index 0000000..2924527 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/IEdgeColorizerAlgorithm.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; + +namespace QuickGraph.Algorithms +{ + public interface IEdgeColorizerAlgorithm + where TEdge : IEdge + { + IDictionary EdgeColors { get;} + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/IEdgeColorizerAlgorithm.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/IEdgeColorizerAlgorithm.cs.meta new file mode 100644 index 0000000..16bc9b6 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/IEdgeColorizerAlgorithm.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: cf274d3b62019415aaac2c8bab740906 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/IEdgePredecessorRecorderAlgorithm.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/IEdgePredecessorRecorderAlgorithm.cs new file mode 100755 index 0000000..1309724 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/IEdgePredecessorRecorderAlgorithm.cs @@ -0,0 +1,11 @@ +using System; + +namespace QuickGraph.Algorithms +{ + public interface IEdgePredecessorRecorderAlgorithm + where TEdge : IEdge + { + event EdgeEdgeEventHandler DiscoverTreeEdge; + event EdgeEventHandler FinishEdge; + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/IEdgePredecessorRecorderAlgorithm.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/IEdgePredecessorRecorderAlgorithm.cs.meta new file mode 100644 index 0000000..e6426aa --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/IEdgePredecessorRecorderAlgorithm.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: c2e18ce75aa4f42b183331b04b6914c4 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/IEndPathEdgeRecorderAlgorithm.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/IEndPathEdgeRecorderAlgorithm.cs new file mode 100755 index 0000000..16b4ecb --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/IEndPathEdgeRecorderAlgorithm.cs @@ -0,0 +1,8 @@ +using System; +namespace QuickGraph.Algorithms +{ + public interface IEndPathEdgeRecorderAlgorithm + where TEdge : IEdge + { + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/IEndPathEdgeRecorderAlgorithm.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/IEndPathEdgeRecorderAlgorithm.cs.meta new file mode 100644 index 0000000..44cf459 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/IEndPathEdgeRecorderAlgorithm.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: a9f005fb3218f4681a3dec7366b02b63 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/ITreeBuilderAlgorithm.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/ITreeBuilderAlgorithm.cs new file mode 100755 index 0000000..3a826d6 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/ITreeBuilderAlgorithm.cs @@ -0,0 +1,10 @@ +using System; + +namespace QuickGraph.Algorithms +{ + public interface ITreeBuilderAlgorithm + where TEdge : IEdge + { + event EdgeEventHandler TreeEdge; + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/ITreeBuilderAlgorithm.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/ITreeBuilderAlgorithm.cs.meta new file mode 100644 index 0000000..1ee6099 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/ITreeBuilderAlgorithm.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 9183401b3c05f4eb994c9a91369b1776 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/IVertexColorizerAlgorithm.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/IVertexColorizerAlgorithm.cs new file mode 100755 index 0000000..9d8ec7d --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/IVertexColorizerAlgorithm.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; + +namespace QuickGraph.Algorithms +{ + public interface IVertexColorizerAlgorithm + where TEdge : IEdge + { + IDictionary VertexColors { get;} + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/IVertexColorizerAlgorithm.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/IVertexColorizerAlgorithm.cs.meta new file mode 100644 index 0000000..1b5fc20 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/IVertexColorizerAlgorithm.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 3cd3b6d5e25bf4d44900434bb396a264 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/IVertexPredecessorRecorderAlgorithm.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/IVertexPredecessorRecorderAlgorithm.cs new file mode 100755 index 0000000..a5d980f --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/IVertexPredecessorRecorderAlgorithm.cs @@ -0,0 +1,12 @@ +using System; + +namespace QuickGraph.Algorithms +{ + public interface IVertexPredecessorRecorderAlgorithm : + ITreeBuilderAlgorithm + where TEdge : IEdge + { + event VertexEventHandler StartVertex; + event VertexEventHandler FinishVertex; + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/IVertexPredecessorRecorderAlgorithm.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/IVertexPredecessorRecorderAlgorithm.cs.meta new file mode 100644 index 0000000..1067951 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/IVertexPredecessorRecorderAlgorithm.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d0d2dabc76db540e184b6f2dfeabbd01 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/IVertexTimeStamperAlgorithm.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/IVertexTimeStamperAlgorithm.cs new file mode 100755 index 0000000..6ee96d4 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/IVertexTimeStamperAlgorithm.cs @@ -0,0 +1,11 @@ +using System; + +namespace QuickGraph.Algorithms +{ + public interface IVertexTimeStamperAlgorithm + where TEdge : IEdge + { + event VertexEventHandler DiscoverVertex; + event VertexEventHandler FinishVertex; + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/IVertexTimeStamperAlgorithm.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/IVertexTimeStamperAlgorithm.cs.meta new file mode 100644 index 0000000..0d7ffd5 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/IVertexTimeStamperAlgorithm.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d8a69b4e653a949bb8083f59c73da0d7 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Matrix.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Matrix.meta new file mode 100644 index 0000000..4db64b5 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Matrix.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: b099c7cc50f984060aea32bf39e54dcb +folderAsset: yes +DefaultImporter: + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Matrix/DenseFloatMatrix.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Matrix/DenseFloatMatrix.cs new file mode 100755 index 0000000..d1780d7 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Matrix/DenseFloatMatrix.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace QuickGraph.Algorithms.Matrix +{ + public sealed class DenseFloatMatrix + { + private readonly int rowCount; + private readonly int columnCount; + private float[] data; + + public DenseFloatMatrix(int rowCount, int columnCount) + { + this.rowCount = rowCount; + this.columnCount = columnCount; + this.data = new float[this.rowCount * this.columnCount]; + } + + public int RowCount + { + get { return this.rowCount; } + } + + public int ColumnCount + { + get { return this.columnCount; } + } + + public float this[int i, int j] + { + get { return this.data[i * this.columnCount + j]; } + set { this.data[i * this.columnCount + j] = value; } + } + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Matrix/DenseFloatMatrix.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Matrix/DenseFloatMatrix.cs.meta new file mode 100644 index 0000000..a2d1dc0 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Matrix/DenseFloatMatrix.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 5a803d4b514d34bc091bac19c3517357 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Matrix/DoubleDenseMatrix.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Matrix/DoubleDenseMatrix.cs new file mode 100755 index 0000000..a76ba24 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Matrix/DoubleDenseMatrix.cs @@ -0,0 +1,382 @@ +using System; +using System.IO; +namespace QuickGraph.Algorithms.Matrix +{ + [Serializable] + public sealed class DoubleDenseMatrix : ICloneable + { + private readonly double[] data; + private readonly int rowCount; + private readonly int columnCount; + + public static DoubleDenseMatrix Create(DoubleDenseMatrix matrix) + { + return new DoubleDenseMatrix(matrix.RowCount, matrix.ColumnCount, matrix.GetData()); + } + + public static DoubleDenseMatrix Create(int rowCount, int columnCount, Double value) + { + // + if (columnCount * rowCount < 0) + throw new ArgumentException("columnCount * rowCount < 0"); + // + double[] data = new double[rowCount * columnCount]; + for (int i = 0; i < data.Length; ++i) + data[i] = value; + + return new DoubleDenseMatrix(rowCount, columnCount, data); + } + + public DoubleDenseMatrix (int rowCount, int columnCount) + { + // + if (rowCount < 0) + throw new ArgumentOutOfRangeException("rowCount"); + if (columnCount < 0) + throw new ArgumentOutOfRangeException("rowCount"); + if (columnCount * rowCount < 0) + throw new ArgumentException("columnCount * rowCount < 0"); + // + + this.rowCount = rowCount; + this.columnCount = columnCount; + this.data = new double[rowCount * columnCount]; + } + + private DoubleDenseMatrix(int rowCount, int columnCount, double[] data) + { + if (rowCount < 0) + throw new ArgumentOutOfRangeException("rowCount"); + if (columnCount < 0) + throw new ArgumentOutOfRangeException("rowCount"); + if (rowCount * columnCount != data.Length) + throw new ArgumentOutOfRangeException("data"); + + this.rowCount = rowCount; + this.columnCount = columnCount; + this.data = data; + } + + private void VerifySize(DoubleDenseMatrix matrix) + { + if (this.RowCount != matrix.RowCount) + throw new MatrixSizeMistmatchException(); + if (this.ColumnCount != matrix.ColumnCount) + throw new MatrixSizeMistmatchException(); + } + + #region Basic matrix + public int RowCount + { + get { return this.rowCount; } + } + + public int ColumnCount + { + get { return this.columnCount; } + } + + public int Count + { + get { return this.rowCount * this.columnCount; } + } + + public double[] GetData() + { + return this.data; + } + + public double this[int row, int column] + { + get { return this.data[row + column * this.RowCount]; } + set { this.data[row + column * this.RowCount] = value; } + } + #endregion + + #region Cloning + public DoubleDenseMatrix Clone() + { + return new DoubleDenseMatrix( + this.RowCount, + this.ColumnCount, + (double[])this.data.Clone() + ); + } + + object ICloneable.Clone() + { + return this.Clone(); + } + #endregion + + #region Basic operations + public DoubleDenseMatrix Add(DoubleDenseMatrix matrix) + { + VerifySize(matrix); + + for (int i = 0; i < data.Length; ++i) + this.data[i] += matrix.data[i]; + + return this; + } + + public static DoubleDenseMatrix Add(DoubleDenseMatrix left, DoubleDenseMatrix right) + { + // + if (left == (DoubleDenseMatrix)null) + throw new ArgumentNullException("left"); + // + DoubleDenseMatrix m = Create(left); + return m.Add(right); + } + + public static DoubleDenseMatrix operator +(DoubleDenseMatrix left, DoubleDenseMatrix right) + { + return Add(left, right); + } + + public DoubleDenseMatrix Sub(DoubleDenseMatrix matrix) + { + VerifySize(matrix); + + for (int i = 0; i < data.Length; ++i) + this.data[i] -= matrix.data[i]; + + return this; + } + + public static DoubleDenseMatrix Sub(DoubleDenseMatrix left, DoubleDenseMatrix right) + { + DoubleDenseMatrix m = Create(left); + return m.Sub(right); + } + + public static DoubleDenseMatrix operator - (DoubleDenseMatrix left, DoubleDenseMatrix right) + { + return Sub(left, right); + } + + public DoubleDenseMatrix Mul(double factor) + { + for (int i = 0; i < data.Length; ++i) + this.data[i] *= factor; + return this; + } + + public static DoubleDenseMatrix Mul(DoubleDenseMatrix left, double factor) + { + DoubleDenseMatrix m = Create(left); + return m.Mul(factor); + } + + public static DoubleDenseMatrix operator * (DoubleDenseMatrix left, double factor) + { + return Mul(left, factor); + } + + public static DoubleDenseMatrix Mul(double factor, DoubleDenseMatrix right) + { + DoubleDenseMatrix m = Create(right); + return m.Mul(factor); + } + + public static DoubleDenseMatrix operator *(double factor, DoubleDenseMatrix right) + { + return Mul(factor, right); + } + + public static DoubleDenseMatrix Mul(DoubleDenseMatrix left, DoubleDenseMatrix right) + { + // + if (left == (DoubleDenseMatrix)null) + throw new ArgumentNullException("left"); + if (right == (DoubleDenseMatrix)null) + throw new ArgumentNullException("right"); + // + if (left.ColumnCount != right.RowCount) + throw new MatrixSizeMistmatchException(); + + DoubleDenseMatrix m = new DoubleDenseMatrix(left.RowCount, right.ColumnCount); + for (int i = 0; i < left.RowCount; ++i) + { + for (int j = 0; j < left.ColumnCount; ++j) + { + for (int k = 0; k < right.ColumnCount; ++k) + { + m[i,k] += left[i,j] * right[j,k]; + } + } + } + + return m; + } + + public static DoubleDenseMatrix operator *(DoubleDenseMatrix left, DoubleDenseMatrix right) + { + return Mul(left, right); + } + + public DoubleDenseMatrix Div(double factor) + { + for (int i = 0; i < data.Length; ++i) + this.data[i] = checked(this.data[i]/factor); + + return this; + } + #endregion + + #region norms + public double GetNorm1() + { + double norm = 0; + for (int i = 0; i < this.RowCount; ++i) + { + double sum = 0; + for (int j = 0; j < this.ColumnCount; ++j) + { + sum += this[i, j]; + } + + norm = Math.Max(sum, norm); + } + + return norm; + } + + public double GetNormInfinity() + { + double norm = 0; + for (int j = 0; j < this.ColumnCount; ++j) + { + double sum = 0; + for (int i = 0; i < this.RowCount; ++i) + { + sum += this[i, j]; + } + norm = Math.Max(sum, norm); + } + + return norm; + } + + public double GetNorm2() + { + double norm = 0; + for (int i = 0; i < this.Count; ++i) + { + norm += this.data[i] * this.data[i]; + } + return Math.Sqrt(norm); + } + #endregion + + #region special methods + public DoubleDenseMatrix Trace() + { + if (this.RowCount != this.ColumnCount) + throw new MatrixSizeMistmatchException(); + DoubleDenseMatrix m = new DoubleDenseMatrix(this.RowCount,1); + for (int i = 0; i < this.RowCount; ++i) + m.data[i] = this[i, i]; + + return m; + } + + public DoubleDenseMatrix Transpose() + { + DoubleDenseMatrix m = new DoubleDenseMatrix(this.ColumnCount, this.RowCount); + for (int i = 0; i < this.RowCount; ++i) + for (int j = 0; j < this.ColumnCount; ++j) + m[j, i] = this[i, j]; + return m; + } + #endregion + + #region Factories + public static DoubleDenseMatrix Identity(int count) + { + DoubleDenseMatrix m = new DoubleDenseMatrix(count, count); + for (int i = 0; i < count; ++i) + m[i, i] = 1; + return m; + } + #endregion + + #region similarity + public static DoubleDenseMatrix Similarity( + DoubleDenseMatrix A, + DoubleDenseMatrix B, + double tolerance + ) + { + // + if (A == (DoubleDenseMatrix)null) + throw new ArgumentNullException("A"); + if (B == (DoubleDenseMatrix)null) + throw new ArgumentNullException("B"); + // + DoubleDenseMatrix AT = A.Transpose(); + DoubleDenseMatrix BT = B.Transpose(); + DoubleDenseMatrix Zk = DoubleDenseMatrix.Create(B.RowCount, A.RowCount, 1.0/(A.RowCount*B.RowCount)); + DoubleDenseMatrix Zk1 = null; + DoubleDenseMatrix ZkOld = null; + + int iteration = 0; + do + { + Zk1 = B * Zk * AT + BT * Zk * A; + Zk1.Div(Zk1.GetNorm2()); + + ZkOld = Zk; + Zk = B * Zk1 * AT + BT * Zk1 * A; + Zk.Div(Zk.GetNorm2()); + + Console.WriteLine(iteration); + Zk.WriteMatrix(Console.Out); + Console.WriteLine((Zk - ZkOld).GetNorm2()); + + if (iteration++ > 100) + throw new InvalidOperationException(); + + } while ((Zk - ZkOld).GetNorm2() > tolerance); + + return Zk; + } + #endregion + + #region ToString + public override string ToString() + { + return String.Format("({0}x{1})", this.RowCount, this.ColumnCount); + } + + public void WriteMatrix(TextWriter writer) + { + for (int i = 0; i < this.RowCount; ++i) + { + for (int j = 0; j < this.ColumnCount; ++j) + { + if (j != 0) + writer.Write(" "); + writer.Write(this[i, j]); + } + writer.WriteLine(); + } + } + + public void WriteMatrix(TextWriter writer, string formatString) + { + for (int i = 0; i < this.RowCount; ++i) + { + for (int j = 0; j < this.ColumnCount; ++j) + { + if (j != 0) + writer.Write(" "); + writer.Write(formatString, this[i, j]); + } + writer.WriteLine(); + } + } + #endregion + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Matrix/DoubleDenseMatrix.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Matrix/DoubleDenseMatrix.cs.meta new file mode 100644 index 0000000..3ef011a --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Matrix/DoubleDenseMatrix.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 9ec4b4364176040c884944d8f0dd7430 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/MaximumBipartiteMatchingAlgorithm.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/MaximumBipartiteMatchingAlgorithm.cs new file mode 100755 index 0000000..a62b55d --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/MaximumBipartiteMatchingAlgorithm.cs @@ -0,0 +1,124 @@ +using System; +using System.Collections.Generic; + +using QuickGraph.Algorithms.MaximumFlow; + +namespace QuickGraph.Algorithms +{ + public sealed class MaximumBipartiteMatchingAlgorithm : + AlgorithmBase> + where TEdge : IEdge + { + private IVertexFactory vertexFactory; + private IEdgeFactory edgeFactory; + private IList matchedEdges = new List(); + + public MaximumBipartiteMatchingAlgorithm( + IMutableVertexAndEdgeListGraph visitedGraph + ) + : this(visitedGraph, + FactoryCompiler.GetVertexFactory(), + FactoryCompiler.GetEdgeFactory() + ) + { } + + public MaximumBipartiteMatchingAlgorithm( + IMutableVertexAndEdgeListGraph visitedGraph, + IVertexFactory vertexFactory, + IEdgeFactory edgeFactory + ) + :base(visitedGraph) + { + if (vertexFactory == null) + throw new ArgumentNullException("vertexFactory"); + if (edgeFactory == null) + throw new ArgumentNullException("edgeFactory"); + + this.vertexFactory = vertexFactory; + this.edgeFactory = edgeFactory; + } + + public IVertexFactory VertexFactory + { + get { return this.vertexFactory; } + } + + public IEdgeFactory EdgeFactory + { + get { return this.edgeFactory; } + } + + public ICollection MatchedEdges + { + get { return this.matchedEdges; } + } + + protected override void InternalCompute() + { + var cancelManager = this.Services.CancelManager; + this.matchedEdges.Clear(); + AllVerticesGraphAugmentorAlgorithm augmentor=null; + ReversedEdgeAugmentorAlgorithm reverser=null; + try + { + if (cancelManager.IsCancelling) + return; + + //augmenting graph + augmentor = new AllVerticesGraphAugmentorAlgorithm( + this, + this.VisitedGraph, + this.VertexFactory, + this.EdgeFactory); + augmentor.Compute(); + if (cancelManager.IsCancelling) + return; + + + // adding reverse edges + reverser = new ReversedEdgeAugmentorAlgorithm( + this, + this.VisitedGraph, + this.EdgeFactory + ); + reverser.AddReversedEdges(); + if (cancelManager.IsCancelling) + return; + + + // compute maxflow + var flow = new EdmondsKarpMaximumFlowAlgorithm( + this, + this.VisitedGraph, + AlgoUtility.ConstantCapacities(this.VisitedGraph, 1), + reverser.ReversedEdges + ); + flow.Compute(augmentor.SuperSource, augmentor.SuperSink); + if (cancelManager.IsCancelling) + return; + + + foreach (var edge in this.VisitedGraph.Edges) + { + if (cancelManager.IsCancelling) return; + + if (flow.ResidualCapacities[edge] == 0) + this.matchedEdges.Add(edge); + } + } + finally + { + if (reverser!=null && reverser.Augmented) + { + reverser.RemoveReversedEdges(); + reverser=null; + } + if (augmentor != null && augmentor.Augmented) + { + augmentor.Rollback(); + augmentor = null; + } + } + } + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/MaximumBipartiteMatchingAlgorithm.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/MaximumBipartiteMatchingAlgorithm.cs.meta new file mode 100644 index 0000000..e52c19a --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/MaximumBipartiteMatchingAlgorithm.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 86c82d8c5c4fe46808fd0794244e7aa4 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/MaximumFlow.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/MaximumFlow.meta new file mode 100644 index 0000000..9844848 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/MaximumFlow.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: 49413ed86f227492f89c249fde7a64b1 +folderAsset: yes +DefaultImporter: + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/MaximumFlow/AllVerticesGraphAugmentorAlgorithm.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/MaximumFlow/AllVerticesGraphAugmentorAlgorithm.cs new file mode 100755 index 0000000..a2653c7 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/MaximumFlow/AllVerticesGraphAugmentorAlgorithm.cs @@ -0,0 +1,48 @@ +using System; +using QuickGraph.Algorithms.Services; + +namespace QuickGraph.Algorithms.MaximumFlow +{ + public sealed class AllVerticesGraphAugmentorAlgorithm : + GraphAugmentorAlgorithmBase> + where TEdge : IEdge + { + public AllVerticesGraphAugmentorAlgorithm( + IMutableVertexAndEdgeListGraph visitedGraph + ) + : this(visitedGraph, + FactoryCompiler.GetVertexFactory(), + FactoryCompiler.GetEdgeFactory() + ) + { } + + public AllVerticesGraphAugmentorAlgorithm( + IMutableVertexAndEdgeListGraph visitedGraph, + IVertexFactory vertexFactory, + IEdgeFactory edgeFactory + ) + : this(null, visitedGraph, vertexFactory, edgeFactory) + { } + + public AllVerticesGraphAugmentorAlgorithm( + IAlgorithmComponent host, + IMutableVertexAndEdgeListGraph visitedGraph, + IVertexFactory vertexFactory, + IEdgeFactory edgeFactory + ) + :base(host, visitedGraph,vertexFactory,edgeFactory) + {} + + protected override void AugmentGraph() + { + var cancelManager = this.Services.CancelManager; + foreach (var v in this.VisitedGraph.Vertices) + { + if (cancelManager.IsCancelling) break; + + this.AddAugmentedEdge(this.SuperSource, v); + this.AddAugmentedEdge(v, this.SuperSink); + } + } + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/MaximumFlow/AllVerticesGraphAugmentorAlgorithm.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/MaximumFlow/AllVerticesGraphAugmentorAlgorithm.cs.meta new file mode 100644 index 0000000..c7df061 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/MaximumFlow/AllVerticesGraphAugmentorAlgorithm.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 724e85497d33448aeac7dd85b183c9e6 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/MaximumFlow/EdmondsKarpMaximumFlowAlgorithm.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/MaximumFlow/EdmondsKarpMaximumFlowAlgorithm.cs new file mode 100755 index 0000000..87bf0f8 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/MaximumFlow/EdmondsKarpMaximumFlowAlgorithm.cs @@ -0,0 +1,133 @@ +using System; +using System.Collections.Generic; +using QuickGraph.Collections; +using QuickGraph.Algorithms.Observers; +using QuickGraph.Predicates; +using QuickGraph.Algorithms.Search; +using QuickGraph.Algorithms.Services; + +namespace QuickGraph.Algorithms.MaximumFlow +{ + /// + /// Edmond and Karp maximum flow algorithm + /// for directed graph with positive capacities and + /// flows. + /// + /// + /// + [Serializable] + public sealed class EdmondsKarpMaximumFlowAlgorithm + : MaximumFlowAlgorithm + where TEdge : IEdge + { + public EdmondsKarpMaximumFlowAlgorithm( + IVertexListGraph g, + IDictionary capacities, + IDictionary reversedEdges + ) + : this(null, g, capacities, reversedEdges) + { } + + public EdmondsKarpMaximumFlowAlgorithm( + IAlgorithmComponent host, + IVertexListGraph g, + IDictionary capacities, + IDictionary reversedEdges + ) + : base(host, g,capacities,reversedEdges) + {} + + private IVertexListGraph ResidualGraph + { + get + { + return new FilteredVertexListGraph< + TVertex, + TEdge, + IVertexListGraph + >( + VisitedGraph, + new AnyVertexPredicate().Test, + new ResidualEdgePredicate(ResidualCapacities).Test + ); + } + } + + private void Augment( + TVertex src, + TVertex sink + ) + { + TEdge e; + TVertex u; + + // find minimum residual capacity along the augmenting path + double delta = double.MaxValue; + u = sink; + do + { + e = Predecessors[u]; + delta = Math.Min(delta, ResidualCapacities[e]); + u = e.Source; + } while (!u.Equals(src)); + + // push delta units of flow along the augmenting path + u = sink; + do + { + e = Predecessors[u]; + ResidualCapacities[e] -= delta; + ResidualCapacities[ ReversedEdges[e] ] += delta; + u = e.Source; + } while (!u.Equals(src)); + } + + /// + /// Computes the maximum flow between and + /// + /// + /// + /// + /// + protected override void InternalCompute() + { + if (this.Source==null) + throw new InvalidOperationException("Source is not specified"); + if (this.Sink==null) + throw new InvalidOperationException("Sink is not specified"); + + foreach(TVertex u in VisitedGraph.Vertices) + { + foreach(TEdge e in VisitedGraph.OutEdges(u)) + { + ResidualCapacities[e] = Capacities[e]; + } + } + + VertexColors[Sink] = GraphColor.Gray; + while (VertexColors[Sink] != GraphColor.White) + { + VertexPredecessorRecorderObserver vis = new VertexPredecessorRecorderObserver( + Predecessors + ); + var Q = new QuickGraph.Collections.Queue(); + var bfs = new BreadthFirstSearchAlgorithm( + ResidualGraph, + Q, + VertexColors + ); + vis.Attach(bfs); + bfs.Compute(this.Source); + vis.Detach(bfs); + + if (VertexColors[this.Sink] != GraphColor.White) + Augment(this.Source, this.Sink); + } // while + + this.MaxFlow = 0; + foreach(TEdge e in VisitedGraph.OutEdges(Source)) + this.MaxFlow += (Capacities[e] - ResidualCapacities[e]); + } + } + +} \ No newline at end of file diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/MaximumFlow/EdmondsKarpMaximumFlowAlgorithm.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/MaximumFlow/EdmondsKarpMaximumFlowAlgorithm.cs.meta new file mode 100644 index 0000000..dfc962d --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/MaximumFlow/EdmondsKarpMaximumFlowAlgorithm.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 2acd97bb4bf4345928a250d45b09b28f +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/MaximumFlow/FeasibleFlowAlgorithm.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/MaximumFlow/FeasibleFlowAlgorithm.cs new file mode 100755 index 0000000..74fa704 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/MaximumFlow/FeasibleFlowAlgorithm.cs @@ -0,0 +1,18 @@ +#region Using directives + +using System; +using System.Collections.Generic; +using System.Text; + +#endregion + +namespace QuickGraph.Algorithms.MaximumFlow +{ + public class FeasibleFlowAlgorithm + { + public FeasibleFlowAlgorithm() + { + + } + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/MaximumFlow/FeasibleFlowAlgorithm.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/MaximumFlow/FeasibleFlowAlgorithm.cs.meta new file mode 100644 index 0000000..c419278 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/MaximumFlow/FeasibleFlowAlgorithm.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 2aeaf96b20a074adaa6b284d94fbbcd2 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/MaximumFlow/GraphAugmentorAlgorithmBase.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/MaximumFlow/GraphAugmentorAlgorithmBase.cs new file mode 100755 index 0000000..efdd740 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/MaximumFlow/GraphAugmentorAlgorithmBase.cs @@ -0,0 +1,129 @@ +using System; +using System.Collections.Generic; +using QuickGraph.Algorithms.Services; + +namespace QuickGraph.Algorithms.MaximumFlow +{ + public abstract class GraphAugmentorAlgorithmBase : + AlgorithmBase + where TEdge : IEdge + where TGraph : IMutableVertexAndEdgeListGraph + { + private bool augmented = false; + private List augmentedEdges = new List(); + private IVertexFactory vertexFactory; + private IEdgeFactory edgeFactory; + + private TVertex superSource = default(TVertex); + private TVertex superSink = default(TVertex); + + protected GraphAugmentorAlgorithmBase( + IAlgorithmComponent host, + TGraph visitedGraph, + IVertexFactory vertexFactory, + IEdgeFactory edgeFactory + ) + :base(host, visitedGraph) + { + if (vertexFactory == null) + throw new ArgumentNullException("vertexFactory"); + if (edgeFactory == null) + throw new ArgumentNullException("edgeFactory"); + + this.vertexFactory = vertexFactory; + this.edgeFactory = edgeFactory; + } + + public IVertexFactory VertexFactory + { + get { return this.vertexFactory; } + } + + public IEdgeFactory EdgeFactory + { + get { return this.edgeFactory; } + } + + public TVertex SuperSource + { + get { return this.superSource; } + } + + public TVertex SuperSink + { + get { return this.superSink; } + } + + public bool Augmented + { + get { return this.augmented; } + } + + public ICollection AugmentedEdges + { + get { return this.augmentedEdges; } + } + + public event VertexEventHandler SuperSourceAdded; + private void OnSuperSourceAdded(TVertex v) + { + if (this.SuperSourceAdded != null) + this.SuperSourceAdded(this, new VertexEventArgs(v)); + } + + public event VertexEventHandler SuperSinkAdded; + private void OnSuperSinkAdded(TVertex v) + { + if (this.SuperSinkAdded != null) + this.SuperSinkAdded(this, new VertexEventArgs(v)); + } + + public event EdgeEventHandler EdgeAdded; + private void OnEdgeAdded(TEdge e) + { + if (this.EdgeAdded != null) + this.EdgeAdded(this, new EdgeEventArgs(e)); + } + + + protected override void InternalCompute() + { + if (this.Augmented) + throw new InvalidOperationException("Graph already augmented"); + + this.superSource = this.VertexFactory.CreateVertex(); + this.VisitedGraph.AddVertex(this.superSource); + this.OnSuperSourceAdded(this.SuperSource); + + this.superSink = this.VertexFactory.CreateVertex(); + this.VisitedGraph.AddVertex(this.superSink); + this.OnSuperSinkAdded(this.SuperSink); + + this.AugmentGraph(); + this.augmented = true; + } + + public virtual void Rollback() + { + if (!this.Augmented) + return; + + this.VisitedGraph.RemoveVertex(this.SuperSource); + this.VisitedGraph.RemoveVertex(this.SuperSink); + this.superSource = default(TVertex); + this.superSink = default(TVertex); + this.augmentedEdges.Clear(); + this.augmented = false; + } + + protected abstract void AugmentGraph(); + + protected void AddAugmentedEdge(TVertex source, TVertex target) + { + TEdge edge = this.EdgeFactory.CreateEdge(source, target); + this.augmentedEdges.Add(edge); + this.VisitedGraph.AddEdge(edge); + this.OnEdgeAdded(edge); + } + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/MaximumFlow/GraphAugmentorAlgorithmBase.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/MaximumFlow/GraphAugmentorAlgorithmBase.cs.meta new file mode 100644 index 0000000..3d71dbf --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/MaximumFlow/GraphAugmentorAlgorithmBase.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: df0c499a327934f0c8238188fde1579c +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/MaximumFlow/GraphBalancingAlgorithm.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/MaximumFlow/GraphBalancingAlgorithm.cs new file mode 100755 index 0000000..ab93845 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/MaximumFlow/GraphBalancingAlgorithm.cs @@ -0,0 +1,380 @@ +using System; +using System.Collections.Generic; + +namespace QuickGraph.Algorithms.MaximumFlow +{ + [Serializable] + public class GraphBalancerAlgorithm + where TEdge : IEdge + { + private IMutableBidirectionalGraph visitedGraph; + private IVertexFactory vertexFactory; + private IEdgeFactory edgeFactory; + + private TVertex source; + private TVertex sink; + + private TVertex balancingSource; + private TEdge balancingSourceEdge; + + private TVertex balancingSink; + private TEdge balancingSinkEdge; + + private IDictionary capacities = new Dictionary(); + private Dictionary preFlow = new Dictionary(); + private List surplusVertices = new List(); + private List surplusEdges = new List(); + private List deficientVertices = new List(); + private List deficientEdges = new List(); + private bool balanced = false; + + public GraphBalancerAlgorithm( + IMutableBidirectionalGraph visitedGraph, + TVertex source, + TVertex sink + ) + : this(visitedGraph, + source, + sink, + FactoryCompiler.GetVertexFactory(), + FactoryCompiler.GetEdgeFactory() + ) + { } + + public GraphBalancerAlgorithm( + IMutableBidirectionalGraph visitedGraph, + TVertex source, + TVertex sink, + IVertexFactory vertexFactory, + IEdgeFactory edgeFactory + ) + { + if (visitedGraph == null) + throw new ArgumentNullException("visitedGraph"); + if (vertexFactory==null) + throw new ArgumentNullException("vertexFactory"); + if (edgeFactory==null) + throw new ArgumentNullException("edgeFactory"); + if (source == null) + throw new ArgumentNullException("source"); + if (!visitedGraph.ContainsVertex(source)) + throw new ArgumentException("source is not part of the graph"); + if (sink == null) + throw new ArgumentNullException("sink"); + if (!visitedGraph.ContainsVertex(sink)) + throw new ArgumentException("sink is not part of the graph"); + + this.visitedGraph = visitedGraph; + this.vertexFactory = vertexFactory; + this.edgeFactory = edgeFactory; + this.source = source; + this.sink = sink; + + // setting capacities = u(e) = +infty + foreach (var edge in this.VisitedGraph.Edges) + this.capacities.Add(edge, double.MaxValue); + + // setting preflow = l(e) = 1 + foreach (var edge in this.VisitedGraph.Edges) + this.preFlow.Add(edge, 1); + } + + public GraphBalancerAlgorithm( + IMutableBidirectionalGraph visitedGraph, + IVertexFactory vertexFactory, + IEdgeFactory edgeFactory, + TVertex source, + TVertex sink, + IDictionary capacities) + { + if (visitedGraph == null) + throw new ArgumentNullException("visitedGraph"); + if (vertexFactory==null) + throw new ArgumentNullException("vertexFactory"); + if (edgeFactory==null) + throw new ArgumentNullException("edgeFactory"); + if (source == null) + throw new ArgumentNullException("source"); + if (!visitedGraph.ContainsVertex(source)) + throw new ArgumentException("source is not part of the graph"); + if (sink == null) + throw new ArgumentNullException("sink"); + if (!visitedGraph.ContainsVertex(sink)) + throw new ArgumentException("sink is not part of the graph"); + if (capacities == null) + throw new ArgumentNullException("capacities"); + + this.visitedGraph = visitedGraph; + this.source = source; + this.sink = sink; + this.capacities = capacities; + + // setting preflow = l(e) = 1 + foreach (var edge in this.VisitedGraph.Edges) + this.preFlow.Add(edge, 1); + } + + public IMutableBidirectionalGraph VisitedGraph + { + get + { + return this.visitedGraph; + } + } + + public IVertexFactory VertexFactory + { + get { return this.vertexFactory;} + } + + public IEdgeFactory EdgeFactory + { + get { return this.edgeFactory;} + } + + public bool Balanced + { + get + { + return this.balanced; + } + } + + public TVertex Source + { + get + { + return this.source; + } + } + public TVertex Sink + { + get + { + return this.sink; + } + } + public TVertex BalancingSource + { + get + { + return this.balancingSource; + } + } + public TEdge BalancingSourceEdge + { + get + { + return this.balancingSourceEdge; + } + } + public TVertex BalancingSink + { + get + { + return this.balancingSink; + } + } + public TEdge BalancingSinkEdge + { + get + { + return this.balancingSinkEdge; + } + } + public ICollection SurplusVertices + { + get + { + return this.surplusVertices; + } + } + public ICollection SurplusEdges + { + get + { + return this.surplusEdges; + } + } + public ICollection DeficientVertices + { + get + { + return this.deficientVertices; + } + } + public ICollection DeficientEdges + { + get + { + return this.deficientEdges; + } + } + public IDictionary Capacities + { + get + { + return this.capacities; + } + } + + public event VertexEventHandler BalancingSourceAdded; + private void OnBalancingSourceAdded() + { + if (this.BalancingSourceAdded != null) + this.BalancingSourceAdded(this, new VertexEventArgs(source)); + } + public event VertexEventHandler BalancingSinkAdded; + private void OnBalancingSinkAdded() + { + if (this.BalancingSinkAdded != null) + this.BalancingSinkAdded(this, new VertexEventArgs(this.sink)); + } + public event EdgeEventHandler EdgeAdded; + private void OnEdgeAdded(TEdge edge) + { + if (this.EdgeAdded != null) + this.EdgeAdded(this, new EdgeEventArgs(edge)); + } + public event VertexEventHandler SurplusVertexAdded; + private void OnSurplusVertexAdded(TVertex vertex) + { + if (this.SurplusVertexAdded != null) + this.SurplusVertexAdded(this, new VertexEventArgs(vertex)); + } + public event VertexEventHandler DeficientVertexAdded; + private void OnDeficientVertexAdded(TVertex vertex) + { + if (this.DeficientVertexAdded != null) + this.DeficientVertexAdded(this, new VertexEventArgs(vertex)); + } + + public int GetBalancingIndex(TVertex v) + { + int bi = 0; + foreach (var edge in this.VisitedGraph.OutEdges(v)) + { + int pf = this.preFlow[edge]; + bi += pf; + } + foreach (var edge in this.VisitedGraph.InEdges(v)) + { + int pf = this.preFlow[edge]; + bi -= pf; + } + return bi; + } + + public void Balance() + { + if (this.Balanced) + throw new InvalidOperationException("Graph already balanced"); + + // step 0 + // create new source, new sink + this.balancingSource = this.VertexFactory.CreateVertex(); + this.visitedGraph.AddVertex(this.balancingSource); + this.OnBalancingSourceAdded(); + + this.balancingSink = this.VertexFactory.CreateVertex(); + this.visitedGraph.AddVertex(this.balancingSink); + this.OnBalancingSinkAdded(); + + // step 1 + this.balancingSourceEdge = this.EdgeFactory.CreateEdge(this.BalancingSource, this.Source); + this.VisitedGraph.AddEdge(this.BalancingSourceEdge); + this.capacities.Add(this.balancingSourceEdge, double.MaxValue); + this.preFlow.Add(this.balancingSourceEdge, 0); + OnEdgeAdded(balancingSourceEdge); + + this.balancingSinkEdge = this.EdgeFactory.CreateEdge(this.Sink, this.BalancingSink); + this.VisitedGraph.AddEdge(this.balancingSinkEdge); + this.capacities.Add(this.balancingSinkEdge, double.MaxValue); + this.preFlow.Add(this.balancingSinkEdge, 0); + OnEdgeAdded(balancingSinkEdge); + + // step 2 + // for each surplus vertex v, add (source -> v) + foreach (var v in this.VisitedGraph.Vertices) + { + if (v.Equals(this.balancingSource)) + continue; + if (v.Equals(this.balancingSink)) + continue; + if (v.Equals(this.source)) + continue; + if (v.Equals(this.sink)) + continue; + + int balacingIndex = this.GetBalancingIndex(v); + if (balacingIndex == 0) + continue; + + if (balacingIndex < 0) + { + // surplus vertex + TEdge edge = this.EdgeFactory.CreateEdge(this.BalancingSource, v); + this.VisitedGraph.AddEdge(edge); + this.surplusEdges.Add(edge); + this.surplusVertices.Add(v); + this.preFlow.Add(edge, 0); + this.capacities.Add(edge, -balacingIndex); + OnSurplusVertexAdded(v); + OnEdgeAdded(edge); + } + else + { + // deficient vertex + TEdge edge = this.EdgeFactory.CreateEdge(v, this.BalancingSink); + this.deficientEdges.Add(edge); + this.deficientVertices.Add(v); + this.preFlow.Add(edge, 0); + this.capacities.Add(edge, balacingIndex); + OnDeficientVertexAdded(v); + OnEdgeAdded(edge); + } + } + + this.balanced = true; + } + + public void UnBalance() + { + if (!this.Balanced) + throw new InvalidOperationException("Graph is not balanced"); + foreach (var edge in this.surplusEdges) + { + this.VisitedGraph.RemoveEdge(edge); + this.capacities.Remove(edge); + this.preFlow.Remove(edge); + } + foreach (var edge in this.deficientEdges) + { + this.VisitedGraph.RemoveEdge(edge); + this.capacities.Remove(edge); + this.preFlow.Remove(edge); + } + + this.capacities.Remove(this.BalancingSinkEdge); + this.capacities.Remove(this.BalancingSourceEdge); + this.preFlow.Remove(this.BalancingSinkEdge); + this.preFlow.Remove(this.BalancingSourceEdge); + this.VisitedGraph.RemoveEdge(this.BalancingSourceEdge); + this.VisitedGraph.RemoveEdge(this.BalancingSinkEdge); + this.VisitedGraph.RemoveVertex(this.BalancingSource); + this.VisitedGraph.RemoveVertex(this.BalancingSink); + + this.balancingSource = default(TVertex); + this.balancingSink = default(TVertex); + this.balancingSourceEdge = default(TEdge); + this.balancingSinkEdge = default(TEdge); + + this.surplusEdges.Clear(); + this.deficientEdges.Clear(); + this.surplusVertices.Clear(); + this.deficientVertices.Clear(); + + this.balanced = false; + } + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/MaximumFlow/GraphBalancingAlgorithm.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/MaximumFlow/GraphBalancingAlgorithm.cs.meta new file mode 100644 index 0000000..d29e6d5 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/MaximumFlow/GraphBalancingAlgorithm.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 29f1adf57a2884d72b71bea3737887a8 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/MaximumFlow/MaximumFlowAlgorithmBase.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/MaximumFlow/MaximumFlowAlgorithmBase.cs new file mode 100755 index 0000000..ae3123c --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/MaximumFlow/MaximumFlowAlgorithmBase.cs @@ -0,0 +1,123 @@ +using System; +using System.Collections.Generic; +using QuickGraph.Algorithms.Services; + +namespace QuickGraph.Algorithms.MaximumFlow +{ + /// + /// Abstract base class for maximum flow algorithms. + /// + [Serializable] + public abstract class MaximumFlowAlgorithm : + AlgorithmBase>, + IVertexColorizerAlgorithm + where TEdge : IEdge + { + private IDictionary predecessors; + private IDictionary capacities; + private IDictionary residualCapacities; + private IDictionary reversedEdges; + private IDictionary vertexColors; + private TVertex source; + private TVertex sink; + private double maxFlow = 0; + + protected MaximumFlowAlgorithm( + IAlgorithmComponent host, + IVertexListGraph visitedGraph, + IDictionary capacities, + IDictionary reversedEdges + ) + :base(host, visitedGraph) + { + if (capacities == null) + throw new ArgumentNullException("capacities"); + if (reversedEdges == null) + throw new ArgumentNullException("reversedEdges"); + + this.capacities = capacities; + this.reversedEdges = reversedEdges; + + this.predecessors = new Dictionary(); + this.residualCapacities = new Dictionary(); + this.vertexColors = new Dictionary(); + } + + public IDictionary Predecessors + { + get + { + return predecessors; + } + } + + public IDictionary Capacities + { + get + { + return capacities; + } + } + + public IDictionary ResidualCapacities + { + get + { + return residualCapacities; + } + } + + public IDictionary ReversedEdges + { + get + { + return reversedEdges; + } + } + + public IDictionary VertexColors + { + get + { + return vertexColors; + } + } + + public TVertex Source + { + get { return this.source; } + set + { + if (value == null) + throw new ArgumentNullException("source"); + this.source = value; + } + } + + public TVertex Sink + { + get { return this.sink; } + set + { + if (value == null) + throw new ArgumentNullException("sink"); + this.sink = value; + } + } + + public double MaxFlow + { + get { return this.maxFlow; } + set { this.maxFlow = value; } + } + + public double Compute(TVertex source, TVertex sink) + { + this.Source = source; + this.Sink = sink; + this.Compute(); + return this.MaxFlow; + } + } + +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/MaximumFlow/MaximumFlowAlgorithmBase.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/MaximumFlow/MaximumFlowAlgorithmBase.cs.meta new file mode 100644 index 0000000..df64c67 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/MaximumFlow/MaximumFlowAlgorithmBase.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 398973ac6692c4b6a9dec27a389dab1f +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/MaximumFlow/MinimumCostMaximumFlowAlgorithm.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/MaximumFlow/MinimumCostMaximumFlowAlgorithm.cs new file mode 100755 index 0000000..0e87594 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/MaximumFlow/MinimumCostMaximumFlowAlgorithm.cs @@ -0,0 +1,12 @@ +using System; + +namespace QuickGraph.Algorithms.MaximumFlow +{ + public class MinimumCostMaximumFlowAlgorithm + { + public MinimumCostMaximumFlowAlgorithm() + { + + } + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/MaximumFlow/MinimumCostMaximumFlowAlgorithm.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/MaximumFlow/MinimumCostMaximumFlowAlgorithm.cs.meta new file mode 100644 index 0000000..cbcad03 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/MaximumFlow/MinimumCostMaximumFlowAlgorithm.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 704f48c15c0c444c3951c2bf0e2ccbae +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/MaximumFlow/MultiSourceSinkGraphAugmentorAlgorithm.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/MaximumFlow/MultiSourceSinkGraphAugmentorAlgorithm.cs new file mode 100755 index 0000000..77f47bc --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/MaximumFlow/MultiSourceSinkGraphAugmentorAlgorithm.cs @@ -0,0 +1,49 @@ +using System; +using QuickGraph.Algorithms.Services; + +namespace QuickGraph.Algorithms.MaximumFlow +{ + public sealed class MultiSourceSinkGraphAugmentorAlgorithm : + GraphAugmentorAlgorithmBase> + where TEdge : IEdge + { + public MultiSourceSinkGraphAugmentorAlgorithm(IMutableBidirectionalGraph visitedGraph) + : this(visitedGraph, + FactoryCompiler.GetVertexFactory(), + FactoryCompiler.GetEdgeFactory() + ) + { } + + public MultiSourceSinkGraphAugmentorAlgorithm( + IMutableBidirectionalGraph visitedGraph, + IVertexFactory vertexFactory, + IEdgeFactory edgeFactory) + :this(null, visitedGraph, vertexFactory, edgeFactory) + {} + + public MultiSourceSinkGraphAugmentorAlgorithm( + IAlgorithmComponent host, + IMutableBidirectionalGraph visitedGraph, + IVertexFactory vertexFactory, + IEdgeFactory edgeFactory) + :base(host, visitedGraph,vertexFactory,edgeFactory) + {} + + protected override void AugmentGraph() + { + var cancelManager = this.Services.CancelManager; + foreach (var v in this.VisitedGraph.Vertices) + { + if (cancelManager.IsCancelling) break; + + // is source + if (this.VisitedGraph.IsInEdgesEmpty(v)) + this.AddAugmentedEdge(this.SuperSource, v); + + // is sink + if (this.VisitedGraph.IsOutEdgesEmpty(v)) + this.AddAugmentedEdge(v,this.SuperSink); + } + } + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/MaximumFlow/MultiSourceSinkGraphAugmentorAlgorithm.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/MaximumFlow/MultiSourceSinkGraphAugmentorAlgorithm.cs.meta new file mode 100644 index 0000000..05e33ad --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/MaximumFlow/MultiSourceSinkGraphAugmentorAlgorithm.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 148cdf4af1285496699a990ae9e7fb9e +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/MaximumFlow/ReverseEdgeAugmentorAlgorithm.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/MaximumFlow/ReverseEdgeAugmentorAlgorithm.cs new file mode 100755 index 0000000..fbe91cd --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/MaximumFlow/ReverseEdgeAugmentorAlgorithm.cs @@ -0,0 +1,156 @@ +using System; +using System.Collections.Generic; +using QuickGraph.Algorithms.Services; + +namespace QuickGraph.Algorithms.MaximumFlow +{ + [Serializable] + public sealed class ReversedEdgeAugmentorAlgorithm + where TEdge : IEdge + { + private IMutableVertexAndEdgeListGraph visitedGraph; + private IEdgeFactory edgeFactory; + private IList augmentedEgdes = new List(); + private IDictionary reversedEdges = new Dictionary(); + private bool augmented = false; + + public ReversedEdgeAugmentorAlgorithm( + IMutableVertexAndEdgeListGraph visitedGraph, + IEdgeFactory edgeFactory) + : this(null, visitedGraph, edgeFactory) + { } + + public ReversedEdgeAugmentorAlgorithm( + IAlgorithmComponent host, + IMutableVertexAndEdgeListGraph visitedGraph, + IEdgeFactory edgeFactory) + { + if (visitedGraph == null) + throw new ArgumentNullException("visitedGraph"); + if (edgeFactory == null) + throw new ArgumentNullException("edgeFactory"); + this.visitedGraph = visitedGraph; + this.edgeFactory = edgeFactory; + } + + public IMutableVertexAndEdgeListGraph VisitedGraph + { + get + { + return this.visitedGraph; + } + } + + public IEdgeFactory EdgeFactory + { + get { return this.edgeFactory; } + } + + public ICollection AugmentedEdges + { + get + { + return this.augmentedEgdes; + } + } + + public IDictionary ReversedEdges + { + get + { + return this.reversedEdges; + } + } + + public bool Augmented + { + get + { + return this.augmented; + } + } + + public event EdgeEventHandler ReversedEdgeAdded; + private void OnReservedEdgeAdded(EdgeEventArgs e) + { + if (this.ReversedEdgeAdded != null) + this.ReversedEdgeAdded(this, e); + } + + public void AddReversedEdges() + { + if (this.Augmented) + throw new InvalidOperationException("Graph already augmented"); + // step 1, find edges that need reversing + IList notReversedEdges = new List(); + foreach (var edge in this.VisitedGraph.Edges) + { + // if reversed already found, continue + if (this.reversedEdges.ContainsKey(edge)) + continue; + + TEdge reversedEdge = this.FindReversedEdge(edge); + if (reversedEdge != null) + { + // setup edge + this.reversedEdges[edge] = reversedEdge; + // setup reversed if needed + if (!this.reversedEdges.ContainsKey(reversedEdge)) + this.reversedEdges[reversedEdge] = edge; + continue; + } + + // this edge has no reverse + notReversedEdges.Add(edge); + } + + // step 2, go over each not reversed edge, add reverse + foreach (var edge in notReversedEdges) + { + if (this.reversedEdges.ContainsKey(edge)) + continue; + + // already been added + TEdge reversedEdge = this.FindReversedEdge(edge); + if (reversedEdge != null) + { + this.reversedEdges[edge] = reversedEdge; + continue; + } + + // need to create one + reversedEdge = this.edgeFactory.CreateEdge(edge.Target, edge.Source); + if (!this.VisitedGraph.AddEdge(reversedEdge)) + throw new InvalidOperationException("We should not be here"); + this.augmentedEgdes.Add(reversedEdge); + this.reversedEdges[edge] = reversedEdge; + this.reversedEdges[reversedEdge] = edge; + this.OnReservedEdgeAdded(new EdgeEventArgs(reversedEdge)); + } + + this.augmented = true; + } + + public void RemoveReversedEdges() + { + if (!this.Augmented) + throw new InvalidOperationException("Graph is not yet augmented"); + + foreach (var edge in this.augmentedEgdes) + this.VisitedGraph.RemoveEdge(edge); + + this.augmentedEgdes.Clear(); + this.reversedEdges.Clear(); + + this.augmented = false; + } + + private TEdge FindReversedEdge(TEdge edge) + { + foreach (var redge in this.VisitedGraph.OutEdges(edge.Target)) + if (redge.Target.Equals(edge.Source)) + return redge; + return default(TEdge); + } + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/MaximumFlow/ReverseEdgeAugmentorAlgorithm.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/MaximumFlow/ReverseEdgeAugmentorAlgorithm.cs.meta new file mode 100644 index 0000000..4074e06 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/MaximumFlow/ReverseEdgeAugmentorAlgorithm.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 338ce79453954445ba3d20705a17150e +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/MinimumSpanningTree.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/MinimumSpanningTree.meta new file mode 100644 index 0000000..7b57995 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/MinimumSpanningTree.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: d6cb40f85bb6944e3bee404516a0d890 +folderAsset: yes +DefaultImporter: + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/MinimumSpanningTree/PrimMinimumSpanningTreeAlgorithm.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/MinimumSpanningTree/PrimMinimumSpanningTreeAlgorithm.cs new file mode 100755 index 0000000..94dff1e --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/MinimumSpanningTree/PrimMinimumSpanningTreeAlgorithm.cs @@ -0,0 +1,141 @@ +using System; +using System.Collections.Generic; + +using QuickGraph.Collections; +using QuickGraph.Algorithms.Services; + +namespace QuickGraph.Algorithms.MinimumSpanningTree +{ + /// + /// Prim's classic minimum spanning tree algorithm for undirected graphs + /// + /// + /// + /// + [Serializable] + public sealed class PrimMinimumSpanningTreeAlgorithm : + RootedAlgorithmBase>, + ITreeBuilderAlgorithm, + IVertexPredecessorRecorderAlgorithm + where TEdge : IEdge + { + private IDictionary edgeWeights; + private Dictionary minimumWeights; + private PriorityQueue queue; + + public PrimMinimumSpanningTreeAlgorithm( + IUndirectedGraph visitedGraph, + IDictionary edgeWeights + ) + : this(null, visitedGraph, edgeWeights) + {} + + public PrimMinimumSpanningTreeAlgorithm( + IAlgorithmComponent host, + IUndirectedGraph visitedGraph, + IDictionary edgeWeights + ) + :base(host, visitedGraph) + { + if (edgeWeights == null) + throw new ArgumentNullException("edgeWeights"); + this.edgeWeights = edgeWeights; + } + + public IDictionary EdgeWeights + { + get { return this.edgeWeights; } + } + + + public event VertexEventHandler StartVertex; + private void OnStartVertex(TVertex v) + { + VertexEventHandler eh = this.StartVertex; + if (eh != null) + eh(this, new VertexEventArgs(v)); + } + + public event EdgeEventHandler TreeEdge; + private void OnTreeEdge(TEdge e) + { + EdgeEventHandler eh = this.TreeEdge; + if (eh != null) + eh(this, new EdgeEventArgs(e)); + } + + public event VertexEventHandler FinishVertex; + + private void OnFinishVertex(TVertex v) + { + VertexEventHandler eh = this.FinishVertex; + if (eh != null) + eh(this, new VertexEventArgs(v)); + } + + protected override void InternalCompute() + { + if (this.VisitedGraph.VertexCount == 0) + return; + var cancelManager = this.Services.CancelManager; + TVertex rootVertex; + if (!this.TryGetRootVertex(out rootVertex)) + rootVertex = TraversalHelper.GetFirstVertex(this.VisitedGraph); + + this.Initialize(); + + try + { + this.minimumWeights[rootVertex] = 0; + this.queue.Update(rootVertex); + this.OnStartVertex(rootVertex); + + while (queue.Count != 0) + { + if (cancelManager.IsCancelling) + return; + TVertex u = queue.Dequeue(); + foreach (var edge in this.VisitedGraph.AdjacentEdges(u)) + { + if (cancelManager.IsCancelling) + return; + double edgeWeight = this.EdgeWeights[edge]; + if ( + queue.Contains(edge.Target) && + edgeWeight < this.minimumWeights[edge.Target] + ) + { + this.minimumWeights[edge.Target] = edgeWeight; + this.queue.Update(edge.Target); + this.OnTreeEdge(edge); + } + } + this.OnFinishVertex(u); + } + } + finally + { + this.CleanUp(); + } + } + + private void Initialize() + { + this.minimumWeights = new Dictionary(this.VisitedGraph.VertexCount); + this.queue = new PriorityQueue(this.minimumWeights); + foreach (var u in this.VisitedGraph.Vertices) + { + this.minimumWeights.Add(u, double.MaxValue); + this.queue.Enqueue(u); + } + } + + private void CleanUp() + { + this.minimumWeights = null; + this.queue = null; + } + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/MinimumSpanningTree/PrimMinimumSpanningTreeAlgorithm.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/MinimumSpanningTree/PrimMinimumSpanningTreeAlgorithm.cs.meta new file mode 100644 index 0000000..007d803 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/MinimumSpanningTree/PrimMinimumSpanningTreeAlgorithm.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 80bf3b94a6bc649db8af099ef16ede8b +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Observers.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Observers.meta new file mode 100644 index 0000000..0285b28 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Observers.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: 75963fb3afec149998ddb844fcb688ec +folderAsset: yes +DefaultImporter: + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Observers/EdgePredecessorRecorderObserver.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Observers/EdgePredecessorRecorderObserver.cs new file mode 100755 index 0000000..461d840 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Observers/EdgePredecessorRecorderObserver.cs @@ -0,0 +1,158 @@ +using System; +using System.Collections.Generic; + +namespace QuickGraph.Algorithms.Observers +{ + /// + /// + /// + /// + /// + /// + [Serializable] + public sealed class EdgePredecessorRecorderObserver : + IObserver> + where TEdge : IEdge + { + private IDictionary edgePredecessors; + private IList endPathEdges; + + public EdgePredecessorRecorderObserver() + :this(new Dictionary(), new List()) + {} + + public EdgePredecessorRecorderObserver( + IDictionary edgePredecessors, + IList endPathEdges + ) + { + if (edgePredecessors == null) + throw new ArgumentNullException("edgePredecessors"); + if (endPathEdges == null) + throw new ArgumentNullException("endPathEdges"); + + this.edgePredecessors = edgePredecessors; + this.endPathEdges = endPathEdges; + } + + public IDictionary EdgePredecessors + { + get + { + return edgePredecessors; + } + } + + public IList EndPathEdges + { + get + { + return endPathEdges; + } + } + + public void Attach(IEdgePredecessorRecorderAlgorithm algorithm) + { + if (algorithm == null) + throw new ArgumentNullException("algorithm"); + + algorithm.DiscoverTreeEdge +=new EdgeEdgeEventHandler(this.DiscoverTreeEdge); + algorithm.FinishEdge +=new EdgeEventHandler(this.FinishEdge); + } + + public void Detach(IEdgePredecessorRecorderAlgorithm algorithm) + { + if (algorithm == null) + throw new ArgumentNullException("algorithm"); + + algorithm.DiscoverTreeEdge -= new EdgeEdgeEventHandler(this.DiscoverTreeEdge); + algorithm.FinishEdge -= new EdgeEventHandler(this.FinishEdge); + } + + public ICollection Path(TEdge se) + { + List path = new List(); + + TEdge ec = se; + path.Insert(0, ec); + while (EdgePredecessors.ContainsKey(ec)) + { + TEdge e = EdgePredecessors[ec]; + path.Insert(0, e); + ec = e; + } + return path; + } + + public ICollection> AllPaths() + { + IList> es = new List>(); + + foreach (var e in EndPathEdges) + es.Add(Path(e)); + + return es; + } + + public ICollection MergedPath(TEdge se, IDictionary colors) + { + List path = new List(); + + TEdge ec = se; + GraphColor c = colors[ec]; + if (c != GraphColor.White) + return path; + else + colors[ec] = GraphColor.Black; + + path.Insert(0, ec); + while (EdgePredecessors.ContainsKey(ec)) + { + TEdge e = EdgePredecessors[ec]; + c = colors[e]; + if (c != GraphColor.White) + return path; + else + colors[e] = GraphColor.Black; + + path.Insert(0, e); + ec = e; + } + return path; + } + + public ICollection> AllMergedPaths() + { + List> es = new List>(EndPathEdges.Count); + IDictionary colors = new Dictionary(); + + foreach (KeyValuePair de in EdgePredecessors) + { + colors[de.Key] = GraphColor.White; + colors[de.Value] = GraphColor.White; + } + + for (int i = 0; i < EndPathEdges.Count; ++i) + es.Add(MergedPath(EndPathEdges[i], colors)); + + return es; + } + + private void DiscoverTreeEdge(Object sender, EdgeEdgeEventArgs args) + { + if (!args.Edge.Equals(args.TargetEdge)) + EdgePredecessors[args.TargetEdge] = args.Edge; + } + + private void FinishEdge(Object sender, EdgeEventArgs args) + { + foreach (var edge in this.EdgePredecessors.Values) + if (edge.Equals(args.Edge)) + return; + + this.EndPathEdges.Add(args.Edge); + } + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Observers/EdgePredecessorRecorderObserver.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Observers/EdgePredecessorRecorderObserver.cs.meta new file mode 100644 index 0000000..96b1e88 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Observers/EdgePredecessorRecorderObserver.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: a881b56ac3b0d4ed08314d3fa6a7f4a9 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Observers/EdgeRecorderObserver.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Observers/EdgeRecorderObserver.cs new file mode 100755 index 0000000..889b326 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Observers/EdgeRecorderObserver.cs @@ -0,0 +1,63 @@ +using System; +using System.Collections.Generic; + +namespace QuickGraph.Algorithms.Observers +{ + /// + /// + /// + /// + /// + /// + [Serializable] + public sealed class EdgeRecorderObserver : + IObserver> + where TEdge : IEdge + { + private IList edges; + public EdgeRecorderObserver() + :this(new List()) + {} + + public EdgeRecorderObserver(IList edges) + { + if (edges == null) + throw new ArgumentNullException("edges"); + this.edges = edges; + } + + public IList Edges + { + get + { + return this.edges; + } + } + + public void Attach(ITreeBuilderAlgorithm algorithm) + { + algorithm.TreeEdge +=new EdgeEventHandler(RecordEdge); + } + + public void Detach(ITreeBuilderAlgorithm algorithm) + { + algorithm.TreeEdge -=new EdgeEventHandler(RecordEdge); + } + + public void RecordEdge(Object sender, EdgeEventArgs args) + { + this.Edges.Add(args.Edge); + } + public void RecordSource(Object sender, EdgeEdgeEventArgs args) + { + this.Edges.Add(args.Edge); + } + public void RecordTarget(Object sender, EdgeEdgeEventArgs args) + { + this.Edges.Add(args.TargetEdge); + } + + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Observers/EdgeRecorderObserver.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Observers/EdgeRecorderObserver.cs.meta new file mode 100644 index 0000000..f545304 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Observers/EdgeRecorderObserver.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: fbf16462c074f4a2a94b9280cad02291 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Observers/IObserver.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Observers/IObserver.cs new file mode 100755 index 0000000..25fadfb --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Observers/IObserver.cs @@ -0,0 +1,16 @@ +using System; +namespace QuickGraph.Algorithms.Observers +{ + /// + /// An algorithm observer + /// + /// + /// + public interface IObserver + { + void Attach(TAlgorithm algorithm); + void Detach(TAlgorithm algorithm); + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Observers/IObserver.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Observers/IObserver.cs.meta new file mode 100644 index 0000000..ff6384b --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Observers/IObserver.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ec97caa52e5884d758723e29ee27a034 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Observers/ObserverUtility.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Observers/ObserverUtility.cs new file mode 100755 index 0000000..6bcb447 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Observers/ObserverUtility.cs @@ -0,0 +1,44 @@ +using System; + +namespace QuickGraph.Algorithms.Observers +{ + [Serializable] + public static class ObserverScope + { + public static IDisposable + Create(TAlgorithm algorithm, IObserver observer) + { + return new ObserverGuardian(algorithm, observer); + } + + [Serializable] + internal sealed class ObserverGuardian : + IDisposable + { + private TAlgorithm algorithm; + private IObserver observer; + + public ObserverGuardian(TAlgorithm algorithm, IObserver observer) { + if (algorithm == null) + throw new ArgumentNullException("algorithm"); + if (observer == null) + throw new ArgumentNullException("observer"); + + this.algorithm = algorithm; + this.observer = observer; + + this.observer.Attach(this.algorithm); + } + + public void Dispose() { + if (this.observer != null && this.algorithm != null) + { + this.observer.Detach(this.algorithm); + this.algorithm = default(TAlgorithm); + this.observer = null; + } + } + } + + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Observers/ObserverUtility.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Observers/ObserverUtility.cs.meta new file mode 100644 index 0000000..63b6d4b --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Observers/ObserverUtility.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: c28144388749346ed8227f69045a3788 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Observers/VertexDistanceRecorderObserver.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Observers/VertexDistanceRecorderObserver.cs new file mode 100755 index 0000000..1df9373 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Observers/VertexDistanceRecorderObserver.cs @@ -0,0 +1,61 @@ +using System; +using System.Collections.Generic; + +namespace QuickGraph.Algorithms.Observers +{ + /// + /// + /// + /// + /// + /// + [Serializable] + public sealed class VertexDistanceRecorderObserver : + IObserver> + where TEdge : IEdge + { + private IDictionary distances; + + public VertexDistanceRecorderObserver() + :this(new Dictionary()) + {} + + public VertexDistanceRecorderObserver(IDictionary distances) + { + if (distances == null) + throw new ArgumentNullException("distances"); + this.distances = distances; + } + + public IDictionary Distances + { + get { return this.distances; } + } + + public void Attach(IDistanceRecorderAlgorithm algorithm) + { + if (algorithm == null) + throw new ArgumentNullException("algorithm"); + + algorithm.TreeEdge += new EdgeEventHandler(this.TreeEdge); + } + + public void Detach(IDistanceRecorderAlgorithm algorithm) + { + if (algorithm == null) + throw new ArgumentNullException("arg"); + + algorithm.TreeEdge -= new EdgeEventHandler(this.TreeEdge); + } + + private void TreeEdge(Object sender, EdgeEventArgs args) + { + int sourceDistance; + if(!this.distances.TryGetValue(args.Edge.Source, out sourceDistance)) + this.distances[args.Edge.Source] = sourceDistance = 0; + this.distances[args.Edge.Target] = sourceDistance + 1; + } + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Observers/VertexDistanceRecorderObserver.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Observers/VertexDistanceRecorderObserver.cs.meta new file mode 100644 index 0000000..0669401 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Observers/VertexDistanceRecorderObserver.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 5f5218d0d88684efd823e9e71aaaad86 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Observers/VertexPredecessorRecorderObserver.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Observers/VertexPredecessorRecorderObserver.cs new file mode 100755 index 0000000..439561d --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Observers/VertexPredecessorRecorderObserver.cs @@ -0,0 +1,112 @@ +using System; +using System.Collections.Generic; + +namespace QuickGraph.Algorithms.Observers +{ + /// + /// + /// + /// + /// + /// + [Serializable] + public sealed class VertexPredecessorRecorderObserver : + IObserver> + where TEdge : IEdge + { + private readonly IDictionary vertexPredecessors; + private readonly List endPathVertices = new List(); + private bool recordEndPath = true; + + public VertexPredecessorRecorderObserver() + :this(new Dictionary()) + {} + + public VertexPredecessorRecorderObserver( + IDictionary vertexPredecessors) + { + if (vertexPredecessors == null) + throw new ArgumentNullException("vertexPredecessors"); + this.vertexPredecessors = vertexPredecessors; + } + + public IDictionary VertexPredecessors + { + get { return this.vertexPredecessors; } + } + + public ICollection EndPathVertices + { + get { return this.endPathVertices; } + } + + public bool RecordEndPath + { + get { return this.recordEndPath; } + set { this.recordEndPath = value; } + } + + public void Attach(IVertexPredecessorRecorderAlgorithm algorithm) + { + algorithm.StartVertex += new VertexEventHandler(StartVertex); + algorithm.TreeEdge+=new EdgeEventHandler(TreeEdge); + algorithm.FinishVertex+=new VertexEventHandler(FinishVertex); + } + + public void Detach(IVertexPredecessorRecorderAlgorithm algorithm) + { + algorithm.StartVertex -= new VertexEventHandler(StartVertex); + algorithm.TreeEdge -= new EdgeEventHandler(TreeEdge); + algorithm.FinishVertex -= new VertexEventHandler(FinishVertex); + } + + void StartVertex(object sender, VertexEventArgs e) + { +// VertexPredecessors[e.Vertex] = default(Edge); + } + + void TreeEdge(Object sender, EdgeEventArgs e) + { + VertexPredecessors[e.Edge.Target] = e.Edge; + } + + void FinishVertex(Object sender, VertexEventArgs e) + { + if (this.RecordEndPath) + { + foreach (var edge in this.VertexPredecessors.Values) + { + if (edge.Source.Equals(e.Vertex)) + return; + } + this.endPathVertices.Add(e.Vertex); + } + } + + public List Path(TVertex v) + { + List path = new List(); + + TVertex vc = v; + TEdge e; + while (this.VertexPredecessors.TryGetValue(vc, out e)) + { + path.Insert(0, e); + vc = e.Source; + } + + return path; + } + + public IList> AllPaths() + { + List> es = new List>(); + foreach (var v in this.EndPathVertices) + es.Add(Path(v)); + + return es; + } + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Observers/VertexPredecessorRecorderObserver.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Observers/VertexPredecessorRecorderObserver.cs.meta new file mode 100644 index 0000000..ceb8f27 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Observers/VertexPredecessorRecorderObserver.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 7513d33d3ec9b4916858272c3c60caa7 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Observers/VertexRecorderObserver.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Observers/VertexRecorderObserver.cs new file mode 100755 index 0000000..df02389 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Observers/VertexRecorderObserver.cs @@ -0,0 +1,54 @@ +using System; +using System.Collections.Generic; + +namespace QuickGraph.Algorithms.Observers +{ + /// + /// + /// + /// + /// + /// + [Serializable] + public sealed class VertexRecorderObserver : + IObserver> + where TEdge : IEdge + { + private IList vertices; + public VertexRecorderObserver() + : this(new List()) + { } + + public VertexRecorderObserver(IList vertices) + { + if (vertices == null) + throw new ArgumentNullException("edges"); + this.vertices = vertices; + } + + public IList Vertices + { + get + { + return this.vertices; + } + } + + public void Attach(IVertexTimeStamperAlgorithm algorithm) + { + algorithm.DiscoverVertex += new VertexEventHandler(algorithm_DiscoverVertex); + } + + public void Detach(IVertexTimeStamperAlgorithm algorithm) + { + algorithm.DiscoverVertex -= new VertexEventHandler(algorithm_DiscoverVertex); + } + + void algorithm_DiscoverVertex(object sender, VertexEventArgs e) + { + this.Vertices.Add(e.Vertex); + } + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Observers/VertexRecorderObserver.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Observers/VertexRecorderObserver.cs.meta new file mode 100644 index 0000000..10f7096 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Observers/VertexRecorderObserver.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 81154368cbff9413c83eb23c15e49f06 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Observers/VertexTimeStamperObserver.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Observers/VertexTimeStamperObserver.cs new file mode 100755 index 0000000..46efb87 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Observers/VertexTimeStamperObserver.cs @@ -0,0 +1,71 @@ +using System; +using System.Collections.Generic; + +namespace QuickGraph.Algorithms.Observers +{ + /// + /// + /// + /// + /// + /// + [Serializable] + public sealed class VertexTimeStamperObserver : + IObserver> + where TEdge : IEdge + { + private IDictionary discoverTimes; + private IDictionary finishTimes; + private int currentTime = 0; + + public VertexTimeStamperObserver() + :this(new Dictionary(), new Dictionary()) + {} + + public VertexTimeStamperObserver( + IDictionary discoverTimes, + IDictionary finishTimes) + { + if (discoverTimes == null) + throw new ArgumentNullException("discoverTimes"); + if (finishTimes == null) + throw new ArgumentNullException("finishTimes"); + this.discoverTimes = discoverTimes; + this.finishTimes = finishTimes; + } + + public IDictionary DiscoverTimes + { + get { return this.discoverTimes; } + } + + public IDictionary FinishTimes + { + get { return this.finishTimes; } + } + + public void Attach(IVertexTimeStamperAlgorithm algorithm) + { + algorithm.DiscoverVertex+=new VertexEventHandler(DiscoverVertex); + algorithm.FinishVertex+=new VertexEventHandler(FinishVertex); + } + + public void Detach(IVertexTimeStamperAlgorithm algorithm) + { + algorithm.DiscoverVertex -= new VertexEventHandler(DiscoverVertex); + algorithm.FinishVertex -= new VertexEventHandler(FinishVertex); + } + + void DiscoverVertex(Object sender, VertexEventArgs e) + { + this.discoverTimes[e.Vertex] = this.currentTime++; + } + + void FinishVertex(Object sender, VertexEventArgs e) + { + this.finishTimes[e.Vertex] = this.currentTime++; + } + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Observers/VertexTimeStamperObserver.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Observers/VertexTimeStamperObserver.cs.meta new file mode 100644 index 0000000..4ca906f --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Observers/VertexTimeStamperObserver.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 1852c24fa2c9f4279ac708dc85bcb04d +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/PageRankAlgorithm.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/PageRankAlgorithm.cs new file mode 100755 index 0000000..55a42d9 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/PageRankAlgorithm.cs @@ -0,0 +1,176 @@ +using System; +using System.Collections.Generic; +using QuickGraph.Predicates; +using QuickGraph.Collections; + +namespace QuickGraph.Algorithms.Ranking +{ + [Serializable] + public sealed class PageRankAlgorithm : + AlgorithmBase> + where TEdge : IEdge + { + private IDictionary ranks = new Dictionary(); + + private int maxIterations = 60; + private double tolerance = 2 * double.Epsilon; + private double damping = 0.85; + + public PageRankAlgorithm(IBidirectionalGraph visitedGraph) + :base(visitedGraph) + {} + + public IDictionary Ranks + { + get + { + return this.ranks; + } + } + + public double Damping + { + get + { + return this.damping; + } + set + { + this.damping = value; + } + } + + public double Tolerance + { + get + { + return this.tolerance; + } + set + { + this.tolerance = value; + } + } + + public int MaxIteration + { + get + { + return this.maxIterations; + } + set + { + this.maxIterations = value; + } + } + + public void InitializeRanks() + { + this.ranks.Clear(); + foreach (var v in this.VisitedGraph.Vertices) + { + this.ranks.Add(v, 0); + } +// this.RemoveDanglingLinks(); + } +/* + public void RemoveDanglingLinks() + { + VertexCollection danglings = new VertexCollection(); + do + { + danglings.Clear(); + + // create filtered graph + IVertexListGraph fg = new FilteredVertexListGraph( + this.VisitedGraph, + new InDictionaryVertexPredicate(this.ranks) + ); + + // iterate over of the vertices in the rank map + foreach (IVertex v in this.ranks.Keys) + { + // if v does not have out-edge in the filtered graph, remove + if (fg.OutDegree(v) == 0) + danglings.Add(v); + } + + // remove from ranks + foreach (IVertex v in danglings) + this.ranks.Remove(v); + // iterate until no dangling was removed + } while (danglings.Count != 0); + } +*/ + protected override void InternalCompute() + { + var cancelManager = this.Services.CancelManager; + IDictionary tempRanks = new Dictionary(); + + // create filtered graph + FilteredBidirectionalGraph< + TVertex, + TEdge, + IBidirectionalGraph + > fg = new FilteredBidirectionalGraph>( + this.VisitedGraph, + new InDictionaryVertexPredicate(this.ranks).Test, + new AnyEdgePredicate().Test + ); + + int iter = 0; + double error = 0; + do + { + if (cancelManager.IsCancelling) + return; + + // compute page ranks + error = 0; + foreach (KeyValuePair de in this.Ranks) + { + if (cancelManager.IsCancelling) + return; + + TVertex v = de.Key; + double rank = de.Value; + // compute ARi + double r = 0; + foreach (var e in fg.InEdges(v)) + { + r += this.ranks[e.Source] / fg.OutDegree(e.Source); + } + + // add sourceRank and store + double newRank = (1 - this.damping) + this.damping * r; + tempRanks[v] = newRank; + // compute deviation + error += Math.Abs(rank - newRank); + } + + // swap ranks + var temp = ranks; + ranks = tempRanks; + tempRanks = temp; + + iter++; + } while (error > this.tolerance && iter < this.maxIterations); + Console.WriteLine("{0}, {1}", iter, error); + } + + public double GetRanksSum() + { + double sum = 0; + foreach (double rank in this.ranks.Values) + { + sum += rank; + } + return sum; + } + + public double GetRanksMean() + { + return GetRanksSum() / this.ranks.Count; + } + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/PageRankAlgorithm.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/PageRankAlgorithm.cs.meta new file mode 100644 index 0000000..0c1e139 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/PageRankAlgorithm.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 551c6fd618320496a9295852d0637557 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/RandomGraphFactory.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/RandomGraphFactory.cs new file mode 100755 index 0000000..9d6d28c --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/RandomGraphFactory.cs @@ -0,0 +1,150 @@ +using System; +using System.Collections.Generic; + +namespace QuickGraph.Algorithms +{ + [Serializable] + public static class RandomGraphFactory + { + public static TVertex GetVertex(IVertexListGraph g, Random rnd) + where TEdge : IEdge + { + if (g == null) + throw new ArgumentNullException("g"); + if (rnd == null) + throw new ArgumentNullException("random generator"); + if (g.VertexCount == 0) + throw new ArgumentException("g is empty"); + return GetVertex(g.Vertices, g.VertexCount, rnd); + } + + public static TVertex GetVertex(IEnumerable vertices, int count, Random rnd) + where TEdge : IEdge + { + if (vertices == null) + throw new ArgumentNullException("vertices"); + if (rnd == null) + throw new ArgumentNullException("random generator"); + if (count == 0) + throw new ArgumentException("vertices is empty"); + + int i = rnd.Next(count); + foreach (var v in vertices) + { + if (i == 0) + return v; + else + --i; + } + + // failed + throw new InvalidOperationException("Could not find vertex"); + } + + public static TEdge GetEdge(IEdgeSet g, Random rnd) + where TEdge : IEdge + { + if (g == null) + throw new ArgumentNullException("g"); + if (rnd == null) + throw new ArgumentNullException("random generator"); + if (g.EdgeCount == 0) + throw new ArgumentException("g is empty"); + + int i = rnd.Next(g.EdgeCount); + foreach (var e in g.Edges) + { + if (i == 0) + return e; + else + --i; + } + + // failed + throw new InvalidOperationException("Could not find edge"); + } + + public static TEdge GetEdge(IEnumerable edges, int count, Random rnd) + where TEdge : IEdge + { + if (edges == null) + throw new ArgumentNullException("edges"); + if (rnd == null) + throw new ArgumentNullException("random generator"); + if (count == 0) + throw new ArgumentException("edges is empty"); + + int i = rnd.Next(count); + foreach (var e in edges) + { + if (i == 0) + return e; + else + --i; + } + + // failed + throw new InvalidOperationException("Could not find edge"); + } + + public static void Create( + IMutableVertexAndEdgeListGraph g, + Random rnd, + int vertexCount, + int edgeCount, + bool selfEdges + ) where TEdge : IEdge + { + Create( + g, + FactoryCompiler.GetVertexFactory(), + FactoryCompiler.GetEdgeFactory(), + rnd, + vertexCount, + edgeCount, + selfEdges + ); + } + + public static void Create( + IMutableVertexAndEdgeListGraph g, + IVertexFactory vertexFactory, + IEdgeFactory edgeFactory, + Random rnd, + int vertexCount, + int edgeCount, + bool selfEdges + ) where TEdge : IEdge + { + if (g == null) + throw new ArgumentNullException("g"); + if (vertexFactory == null) + throw new ArgumentNullException("vertexFactory"); + if (edgeFactory == null) + throw new ArgumentNullException("edgeFactory"); + if (rnd == null) + throw new ArgumentNullException("random generator"); + + + for (int i = 0; i < vertexCount; ++i) + g.AddVertex( vertexFactory.CreateVertex() ); + + + TVertex a; + TVertex b; + int j = 0; + while (j < edgeCount) + { + a = GetVertex(g, rnd); + do + { + b = GetVertex(g, rnd); + } + while (selfEdges == false && a.Equals(b)); + + if (g.AddEdge( edgeFactory.CreateEdge(a,b))) + ++j; + } + } + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/RandomGraphFactory.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/RandomGraphFactory.cs.meta new file mode 100644 index 0000000..2c3f1d9 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/RandomGraphFactory.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 9203e7502d93f47f69ee9f9c5a1de628 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/RandomWalks.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/RandomWalks.meta new file mode 100644 index 0000000..32e38f1 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/RandomWalks.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: af2938d1854234403960a2bb626798b6 +folderAsset: yes +DefaultImporter: + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/RandomWalks/CyclePoppingRandomTreeAlgorithm.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/RandomWalks/CyclePoppingRandomTreeAlgorithm.cs new file mode 100755 index 0000000..21db4e5 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/RandomWalks/CyclePoppingRandomTreeAlgorithm.cs @@ -0,0 +1,261 @@ +using System; +using System.Collections.Generic; +using QuickGraph.Algorithms.Services; + +namespace QuickGraph.Algorithms.RandomWalks +{ + /// + /// Wilson-Propp Cycle-Popping Algorithm for Random Tree Generation. + /// + [Serializable] + public sealed class CyclePoppingRandomTreeAlgorithm : + RootedAlgorithmBase> + where TEdge : IEdge + { + private IDictionary vertexColors = new Dictionary(); + private IMarkovEdgeChain edgeChain = new NormalizedMarkovEdgeChain(); + private IDictionary successors = new Dictionary(); + private Random rnd = new Random((int)DateTime.Now.Ticks); + + public CyclePoppingRandomTreeAlgorithm( + IVertexListGraph visitedGraph) + : this(visitedGraph, new NormalizedMarkovEdgeChain()) + { } + + public CyclePoppingRandomTreeAlgorithm( + IVertexListGraph visitedGraph, + IMarkovEdgeChain edgeChain) + : this(null, visitedGraph, edgeChain) + { } + + public CyclePoppingRandomTreeAlgorithm( + IAlgorithmComponent host, + IVertexListGraph visitedGraph, + IMarkovEdgeChain edgeChain + ) + :base(host, visitedGraph) + { + if (edgeChain == null) + throw new ArgumentNullException("edgeChain"); + this.edgeChain = edgeChain; + } + + public IDictionary VertexColors + { + get + { + return this.vertexColors; + } + } + + public IMarkovEdgeChain EdgeChain + { + get + { + return this.edgeChain; + } + } + + /// + /// Gets or sets the random number generator used in RandomTree. + /// + /// + /// number generator + /// + public Random Rnd + { + get + { + return this.rnd; + } + set + { + this.rnd = value; + } + } + + public IDictionary Successors + { + get + { + return this.successors; + } + } + + public event VertexEventHandler InitializeVertex; + private void OnInitializeVertex(TVertex v) + { + if (this.InitializeVertex != null) + this.InitializeVertex(this, new VertexEventArgs(v)); + } + + public event VertexEventHandler FinishVertex; + private void OnFinishVertex(TVertex v) + { + if (this.FinishVertex != null) + this.FinishVertex(this, new VertexEventArgs(v)); + } + + public event EdgeEventHandler TreeEdge; + private void OnTreeEdge(TEdge e) + { + if (this.TreeEdge != null) + this.TreeEdge(this, new EdgeEventArgs(e)); + } + + public event VertexEventHandler ClearTreeVertex; + private void OnClearTreeVertex(TVertex v) + { + if (this.ClearTreeVertex != null) + this.ClearTreeVertex(this, new VertexEventArgs(v)); + } + + private void Initialize() + { + this.successors.Clear(); + this.vertexColors.Clear(); + foreach (var v in this.VisitedGraph.Vertices) + { + this.vertexColors.Add(v,GraphColor.White); + OnInitializeVertex(v); + } + } + + private bool NotInTree(TVertex u) + { + GraphColor color = this.vertexColors[u]; + return color == GraphColor.White; + } + + private void SetInTree(TVertex u) + { + this.vertexColors[u] = GraphColor.Black; + OnFinishVertex(u); + } + + private TEdge RandomSuccessor(TVertex u) + { + return this.EdgeChain.Successor(this.VisitedGraph, u); + } + + private void Tree(TVertex u, TEdge next) + { + this.successors[u] = next; + if (next == null) + return; + OnTreeEdge(next); + } + + private TVertex NextInTree(TVertex u) + { + TEdge next = this.successors[u]; + if (next == null) + return default(TVertex); + else + return next.Target; + } + + private bool Chance(double eps) + { + return this.rnd.NextDouble() <= eps; + } + + private void ClearTree(TVertex u) + { + this.successors[u] = default(TEdge); + OnClearTreeVertex(u); + } + + public void RandomTreeWithRoot(TVertex root) + { + if (root == null) + throw new ArgumentNullException("root"); + this.SetRootVertex(root); + this.Compute(); + } + + protected override void InternalCompute() + { + TVertex rootVertex; + if (!this.TryGetRootVertex(out rootVertex)) + throw new InvalidOperationException("RootVertex not specified"); + // initialize vertices to white + Initialize(); + + // process root + ClearTree(rootVertex); + SetInTree(rootVertex); + + TVertex u; + foreach (var i in this.VisitedGraph.Vertices) + { + u = i; + + // first pass exploring + while (u != null && NotInTree(u)) + { + Tree(u, RandomSuccessor(u)); + u = NextInTree(u); + } + + // second pass, coloring + u = i; + while (u != null && NotInTree(u)) + { + SetInTree(u); + u = NextInTree(u); + } + } + } + + public void RandomTree() + { + double eps = 1; + bool success; + do + { + eps /= 2; + success = Attempt(eps); + } while (!success); + } + + private bool Attempt(double eps) + { + Initialize(); + int numRoots = 0; + + TVertex u; + foreach (var i in this.VisitedGraph.Vertices) + { + u = i; + + // first pass exploring + while (u != null && NotInTree(u)) + { + if (Chance(eps)) + { + ClearTree(u); + SetInTree(u); + ++numRoots; + if (numRoots > 1) + return false; + } + else + { + Tree(u, RandomSuccessor(u)); + u = NextInTree(u); + } + } + + // second pass, coloring + u = i; + while (u != null && NotInTree(u)) + { + SetInTree(u); + u = NextInTree(u); + } + } + return true; + } + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/RandomWalks/CyclePoppingRandomTreeAlgorithm.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/RandomWalks/CyclePoppingRandomTreeAlgorithm.cs.meta new file mode 100644 index 0000000..b1c5cab --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/RandomWalks/CyclePoppingRandomTreeAlgorithm.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 73c6810cbc095455abf303548f1df969 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/RandomWalks/IEdgeChain.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/RandomWalks/IEdgeChain.cs new file mode 100755 index 0000000..bea4b75 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/RandomWalks/IEdgeChain.cs @@ -0,0 +1,8 @@ +namespace QuickGraph.Algorithms.RandomWalks +{ + public interface IEdgeChain + where TEdge : IEdge + { + TEdge Successor(IImplicitGraph g, TVertex u); + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/RandomWalks/IEdgeChain.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/RandomWalks/IEdgeChain.cs.meta new file mode 100644 index 0000000..1129e13 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/RandomWalks/IEdgeChain.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d9748959bf76e469e95f5ea5710c5c70 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/RandomWalks/IMarkovEdgeChain.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/RandomWalks/IMarkovEdgeChain.cs new file mode 100755 index 0000000..61c0c0e --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/RandomWalks/IMarkovEdgeChain.cs @@ -0,0 +1,9 @@ +using System; +namespace QuickGraph.Algorithms.RandomWalks +{ + public interface IMarkovEdgeChain : IEdgeChain + where TEdge : IEdge + { + Random Rand { get;set;} + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/RandomWalks/IMarkovEdgeChain.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/RandomWalks/IMarkovEdgeChain.cs.meta new file mode 100644 index 0000000..6720a08 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/RandomWalks/IMarkovEdgeChain.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 3803279c53e8a43099ee167b44d19bb5 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/RandomWalks/MarkovEdgeChainBase.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/RandomWalks/MarkovEdgeChainBase.cs new file mode 100755 index 0000000..29509b7 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/RandomWalks/MarkovEdgeChainBase.cs @@ -0,0 +1,26 @@ +using System; + +namespace QuickGraph.Algorithms.RandomWalks +{ + [Serializable] + public abstract class MarkovEdgeChainBase : + IMarkovEdgeChain + where TEdge : IEdge + { + private Random rand = new Random(); + + public Random Rand + { + get + { + return this.rand; + } + set + { + this.rand = value; + } + } + + public abstract TEdge Successor(IImplicitGraph g, TVertex u); + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/RandomWalks/MarkovEdgeChainBase.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/RandomWalks/MarkovEdgeChainBase.cs.meta new file mode 100644 index 0000000..3828622 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/RandomWalks/MarkovEdgeChainBase.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 7a59d22ac9b8e40acbe7852ee4b80b4e +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/RandomWalks/NormalizedMarkovEdgeChain.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/RandomWalks/NormalizedMarkovEdgeChain.cs new file mode 100755 index 0000000..8fb4850 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/RandomWalks/NormalizedMarkovEdgeChain.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; + +namespace QuickGraph.Algorithms.RandomWalks +{ + [Serializable] + public sealed class NormalizedMarkovEdgeChain : + MarkovEdgeChainBase + where TEdge : IEdge + { + public override TEdge Successor(IImplicitGraph g, TVertex u) + { + int outDegree = g.OutDegree(u); + if (outDegree == 0) + return default(TEdge); + + int index = this.Rand.Next(0, outDegree); + return g.OutEdge(u, index); + } + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/RandomWalks/NormalizedMarkovEdgeChain.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/RandomWalks/NormalizedMarkovEdgeChain.cs.meta new file mode 100644 index 0000000..979d5db --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/RandomWalks/NormalizedMarkovEdgeChain.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 70c4579455495474b814507a32309dd5 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/RandomWalks/RandomWalkAlgorithm.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/RandomWalks/RandomWalkAlgorithm.cs new file mode 100755 index 0000000..8c3471e --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/RandomWalks/RandomWalkAlgorithm.cs @@ -0,0 +1,129 @@ +using System; +using System.Collections.Generic; + +using QuickGraph.Algorithms.Observers; + +namespace QuickGraph.Algorithms.RandomWalks +{ + [Serializable] + public sealed class RandomWalkAlgorithm : + ITreeBuilderAlgorithm + where TEdge : IEdge + { + private IImplicitGraph visitedGraph; + private EdgePredicate endPredicate; + private IEdgeChain edgeChain; + + public RandomWalkAlgorithm(IImplicitGraph visitedGraph) + :this(visitedGraph,new NormalizedMarkovEdgeChain()) + {} + + public RandomWalkAlgorithm( + IImplicitGraph visitedGraph, + IEdgeChain edgeChain + ) + { + if (visitedGraph == null) + throw new ArgumentNullException("visitedGraph"); + if (edgeChain == null) + throw new ArgumentNullException("edgeChain"); + this.visitedGraph = visitedGraph; + this.edgeChain = edgeChain; + } + + public IImplicitGraph VisitedGraph + { + get + { + return this.visitedGraph; + } + } + + public IEdgeChain EdgeChain + { + get + { + return this.edgeChain; + } + set + { + if (value == null) + throw new ArgumentNullException("edgeChain"); + this.edgeChain = value; + } + } + + public EdgePredicate EndPredicate + { + get + { + return this.endPredicate; + } + set + { + this.endPredicate = value; + } + } + + public event VertexEventHandler StartVertex; + private void OnStartVertex(TVertex v) + { + if (StartVertex != null) + StartVertex(this, new VertexEventArgs(v)); + } + + public event VertexEventHandler EndVertex; + private void OnEndVertex(TVertex v) + { + if (EndVertex != null) + EndVertex(this, new VertexEventArgs(v)); + } + + public event EdgeEventHandler TreeEdge; + private void OnTreeEdge(TEdge e) + { + if (this.TreeEdge != null) + this.TreeEdge(this, new EdgeEventArgs(e)); + } + + private TEdge Successor(TVertex u) + { + return this.EdgeChain.Successor(this.VisitedGraph, u); + } + + public void Generate(TVertex root) + { + if (root == null) + throw new ArgumentNullException("root"); + Generate(root, 100); + } + + public void Generate(TVertex root, int walkCount) + { + if (root == null) + throw new ArgumentNullException("root"); + + int count = 0; + TEdge e = default(TEdge); + TVertex v = root; + + OnStartVertex(root); + while (count < walkCount) + { + e = Successor(v); + // if dead end stop + if (e==null) + break; + // if end predicate, test + if (this.endPredicate != null && this.endPredicate(e)) + break; + OnTreeEdge(e); + v = e.Target; + // upgrade count + ++count; + } + OnEndVertex(v); + } + + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/RandomWalks/RandomWalkAlgorithm.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/RandomWalks/RandomWalkAlgorithm.cs.meta new file mode 100644 index 0000000..c8cc8de --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/RandomWalks/RandomWalkAlgorithm.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 4505fbdb09fd945e38a70616f3b265c4 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/RandomWalks/RoundRobinEdgeChain.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/RandomWalks/RoundRobinEdgeChain.cs new file mode 100755 index 0000000..86dc811 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/RandomWalks/RoundRobinEdgeChain.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; + +namespace QuickGraph.Algorithms.RandomWalks +{ + [Serializable] + public sealed class RoundRobinEdgeChain : + IEdgeChain + where TEdge : IEdge + { + private Dictionary outEdgeIndices = new Dictionary(); + + public TEdge Successor(IImplicitGraph g, TVertex u) + { + int outDegree = g.OutDegree(u); + if (outDegree == 0) + return default(TEdge); + + int index; + if (!outEdgeIndices.TryGetValue(u, out index)) + { + index = 0; + outEdgeIndices.Add(u, index); + } + TEdge e = g.OutEdge(u, index); + this.outEdgeIndices[u] = (++index) % outDegree; + + return e; + } + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/RandomWalks/RoundRobinEdgeChain.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/RandomWalks/RoundRobinEdgeChain.cs.meta new file mode 100644 index 0000000..a8d4a77 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/RandomWalks/RoundRobinEdgeChain.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 46c01a87cffd84bf998e2563dc310077 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/RandomWalks/VanishingWeightedMarkovEdgeChain.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/RandomWalks/VanishingWeightedMarkovEdgeChain.cs new file mode 100755 index 0000000..26e165b --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/RandomWalks/VanishingWeightedMarkovEdgeChain.cs @@ -0,0 +1,58 @@ +using System; +using System.Collections.Generic; +namespace QuickGraph.Algorithms.RandomWalks +{ + [Serializable] + public sealed class VanishingWeightedMarkovEdgeChain : + WeightedMarkovEdgeChainBase + where TEdge : IEdge + { + private double factor; + + public VanishingWeightedMarkovEdgeChain(IDictionary weights) + :this(weights,0.2) + {} + + public VanishingWeightedMarkovEdgeChain(IDictionary weights, double factor) + :base(weights) + { + this.factor = factor; + } + + public double Factor + { + get + { + return this.factor; + } + set + { + this.factor = value; + } + } + + public override TEdge Successor(IImplicitGraph g, TVertex u) + { + if (g.IsOutEdgesEmpty(u)) + return default(TEdge); + // get outweight + double outWeight = GetOutWeight(g, u); + // get succesor + TEdge s = Successor(g,u,this.Rand.NextDouble() * outWeight); + + // update probabilities + this.Weights[s]*=this.Factor; + + // normalize + foreach(TEdge e in g.OutEdges(u)) + { + checked + { + this.Weights[e]/=outWeight; + } + } + + return s; + } + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/RandomWalks/VanishingWeightedMarkovEdgeChain.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/RandomWalks/VanishingWeightedMarkovEdgeChain.cs.meta new file mode 100644 index 0000000..5ac9ba5 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/RandomWalks/VanishingWeightedMarkovEdgeChain.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 4f24dadeaa3cf44378aa09c036d8d7b8 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/RandomWalks/WeightedMarkedEdgeChain.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/RandomWalks/WeightedMarkedEdgeChain.cs new file mode 100755 index 0000000..ce04e6b --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/RandomWalks/WeightedMarkedEdgeChain.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; + +namespace QuickGraph.Algorithms.RandomWalks +{ + [Serializable] + public sealed class WeightedMarkovEdgeChain : + WeightedMarkovEdgeChainBase + where TEdge : IEdge + { + public WeightedMarkovEdgeChain(IDictionary weights) + :base(weights) + {} + + public override TEdge Successor(IImplicitGraph g, TVertex u) + { + if (g == null) + throw new ArgumentNullException("g"); + if (u == null) + throw new ArgumentNullException("u"); + + // get number of out-edges + int n = g.OutDegree(u); + if (n == 0) + return default(TEdge); + // compute out-edge su + double outWeight = GetOutWeight(g, u); + // scale and get next edge + double r = this.Rand.NextDouble() * outWeight; + return Successor(g, u, r); + } + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/RandomWalks/WeightedMarkedEdgeChain.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/RandomWalks/WeightedMarkedEdgeChain.cs.meta new file mode 100644 index 0000000..ebc9449 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/RandomWalks/WeightedMarkedEdgeChain.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: dc43d8b0c329646dda76f083f52ff9de +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/RandomWalks/WeightedMarkovEdgeChainBase.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/RandomWalks/WeightedMarkovEdgeChainBase.cs new file mode 100755 index 0000000..be74983 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/RandomWalks/WeightedMarkovEdgeChainBase.cs @@ -0,0 +1,49 @@ +using System; +using System.Collections.Generic; + +namespace QuickGraph.Algorithms.RandomWalks +{ + [Serializable] + public abstract class WeightedMarkovEdgeChainBase : + MarkovEdgeChainBase + where TEdge : IEdge + { + private IDictionary weights; + public WeightedMarkovEdgeChainBase(IDictionary weights) + { + if (weights == null) + throw new ArgumentNullException("weights"); + this.weights = weights; + } + + public IDictionary Weights + { + get { return this.weights; } + set { this.weights = value; } + } + + protected double GetOutWeight(IImplicitGraph g, TVertex u) + { + double outWeight = 0; + foreach (var e in g.OutEdges(u)) + { + outWeight += this.weights[e]; + } + return outWeight; + } + + protected TEdge Successor(IImplicitGraph g, TVertex u, double position) + { + double pos = 0; + double nextPos = 0; + foreach (var e in g.OutEdges(u)) + { + nextPos = pos + this.weights[e]; + if (position >= pos && position <= nextPos) + return e; + pos = nextPos; + } + return default(TEdge); + } + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/RandomWalks/WeightedMarkovEdgeChainBase.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/RandomWalks/WeightedMarkovEdgeChainBase.cs.meta new file mode 100644 index 0000000..60d69c5 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/RandomWalks/WeightedMarkovEdgeChainBase.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 88e7932a833bb443d91fe9ba5f7cebe3 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/RootedAlgorithmBase.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/RootedAlgorithmBase.cs new file mode 100755 index 0000000..f997f8d --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/RootedAlgorithmBase.cs @@ -0,0 +1,67 @@ +using System; +using QuickGraph.Algorithms.Services; + +namespace QuickGraph.Algorithms +{ + [Serializable] + public abstract class RootedAlgorithmBase : + AlgorithmBase + { + private TVertex rootVertex; + private bool hasRootVertex; + + protected RootedAlgorithmBase( + IAlgorithmComponent host, + TGraph visitedGraph) + :base(host, visitedGraph) + {} + + public bool TryGetRootVertex(out TVertex rootVertex) + { + if (this.hasRootVertex) + { + rootVertex = this.rootVertex; + return true; + } + else + { + rootVertex = default(TVertex); + return false; + } + } + + public void SetRootVertex(TVertex rootVertex) + { + GraphContracts.AssumeNotNull(rootVertex, "rootVertex"); + // GraphContracts.AssumeInVertexSet(this.VisitedGraph, rootVertex, "rootVertex"); + + bool changed = !Comparison.Equals(this.rootVertex, rootVertex); + this.rootVertex = rootVertex; + if (changed) + this.OnRooVertexChanged(EventArgs.Empty); + this.hasRootVertex = true; + } + + public void ClearRootVertex() + { + this.rootVertex = default(TVertex); + this.hasRootVertex = false; + } + + public event EventHandler RootVertexChanged; + protected virtual void OnRooVertexChanged(EventArgs e) + { + if (this.RootVertexChanged != null) + this.RootVertexChanged(this, e); + } + + public void Compute(TVertex rootVertex) + { + GraphContracts.AssumeNotNull(rootVertex, "rootVertex"); + // GraphContracts.AssumeInVertexSet(this.VisitedGraph, rootVertex, "rootVertex"); + + this.SetRootVertex(rootVertex); + this.Compute(); + } + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/RootedAlgorithmBase.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/RootedAlgorithmBase.cs.meta new file mode 100644 index 0000000..7c4f796 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/RootedAlgorithmBase.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e72897705f83441a0bf279d93e9dee45 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Search.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Search.meta new file mode 100644 index 0000000..0dec8f0 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Search.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: cae3bd092ded64da48beb9ec449fdcc0 +folderAsset: yes +DefaultImporter: + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Search/BidirectionalDepthFirstSearchAlgorithm.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Search/BidirectionalDepthFirstSearchAlgorithm.cs new file mode 100755 index 0000000..4e77fa6 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Search/BidirectionalDepthFirstSearchAlgorithm.cs @@ -0,0 +1,214 @@ +using System; +using System.Collections.Generic; +using QuickGraph.Algorithms.Services; + +namespace QuickGraph.Algorithms.Search +{ + /// + /// A depth and height first search algorithm for directed graphs + /// + /// + /// This is a modified version of the classic DFS algorithm + /// where the search is performed both in depth and height. + /// + /// + [Serializable] + public sealed class BidirectionalDepthFirstSearchAlgorithm : + RootedAlgorithmBase>, + IVertexColorizerAlgorithm, + ITreeBuilderAlgorithm + where TEdge : IEdge + { + private IDictionary colors; + private int maxDepth = int.MaxValue; + + public BidirectionalDepthFirstSearchAlgorithm(IBidirectionalGraph g) + : this(g, new Dictionary()) + { } + + public BidirectionalDepthFirstSearchAlgorithm( + IBidirectionalGraph visitedGraph, + IDictionary colors + ) + : this(null, visitedGraph, colors) + { } + + public BidirectionalDepthFirstSearchAlgorithm( + IAlgorithmComponent host, + IBidirectionalGraph visitedGraph, + IDictionary colors + ) + : base(host, visitedGraph) + { + if (colors == null) + throw new ArgumentNullException("VertexColors"); + + this.colors = colors; + } + + public IDictionary VertexColors + { + get + { + return this.colors; + } + } + + public int MaxDepth + { + get + { + return this.maxDepth; + } + set + { + this.maxDepth = value; + } + } + + public event VertexEventHandler InitializeVertex; + private void OnInitializeVertex(TVertex v) + { + if (InitializeVertex != null) + InitializeVertex(this, new VertexEventArgs(v)); + } + + public event VertexEventHandler StartVertex; + private void OnStartVertex(TVertex v) + { + if (StartVertex != null) + StartVertex(this, new VertexEventArgs(v)); + } + + public event VertexEventHandler DiscoverVertex; + private void OnDiscoverVertex(TVertex v) + { + if (DiscoverVertex != null) + DiscoverVertex(this, new VertexEventArgs(v)); + } + + public event EdgeEventHandler ExamineEdge; + private void OnExamineEdge(TEdge e) + { + if (ExamineEdge != null) + ExamineEdge(this, new EdgeEventArgs(e)); + } + + public event EdgeEventHandler TreeEdge; + private void OnTreeEdge(TEdge e) + { + if (TreeEdge != null) + TreeEdge(this, new EdgeEventArgs(e)); + } + + public event EdgeEventHandler BackEdge; + private void OnBackEdge(TEdge e) + { + if (BackEdge != null) + BackEdge(this, new EdgeEventArgs(e)); + } + + public event EdgeEventHandler ForwardOrCrossEdge; + private void OnForwardOrCrossEdge(TEdge e) + { + if (ForwardOrCrossEdge != null) + ForwardOrCrossEdge(this, new EdgeEventArgs(e)); + } + + public event VertexEventHandler FinishVertex; + private void OnFinishVertex(TVertex v) + { + if (FinishVertex != null) + FinishVertex(this, new VertexEventArgs(v)); + } + + protected override void InternalCompute() + { + // put all vertex to white + Initialize(); + + // if there is a starting vertex, start whith him: + TVertex rootVertex; + if (this.TryGetRootVertex(out rootVertex)) + { + OnStartVertex(rootVertex); + Visit(rootVertex, 0); + } + + // process each vertex + var cancelManager = this.Services.CancelManager; + foreach (var u in VisitedGraph.Vertices) + { + if (cancelManager.IsCancelling) return; + if (VertexColors[u] == GraphColor.White) + { + OnStartVertex(u); + Visit(u, 0); + } + } + } + + public void Initialize() + { + foreach (var u in VisitedGraph.Vertices) + { + VertexColors[u] = GraphColor.White; + OnInitializeVertex(u); + } + } + + public void Visit(TVertex u, int depth) + { + GraphContracts.AssumeNotNull(u, "u"); + if (depth > this.maxDepth) + return; + + VertexColors[u] = GraphColor.Gray; + OnDiscoverVertex(u); + + var cancelManager = this.Services.CancelManager; + TVertex v = default(TVertex); + foreach (var e in VisitedGraph.OutEdges(u)) + { + if (cancelManager.IsCancelling) return; + + OnExamineEdge(e); + v = e.Target; + ProcessEdge(depth, v, e); + } + + foreach (var e in VisitedGraph.InEdges(u)) + { + if (cancelManager.IsCancelling) return; + + OnExamineEdge(e); + v = e.Source; + ProcessEdge(depth, v, e); + } + + VertexColors[u] = GraphColor.Black; + OnFinishVertex(u); + } + + private void ProcessEdge(int depth, TVertex v, TEdge e) + { + GraphColor c = VertexColors[v]; + if (c == GraphColor.White) + { + OnTreeEdge(e); + Visit(v, depth + 1); + } + else if (c == GraphColor.Gray) + { + OnBackEdge(e); + } + else + { + OnForwardOrCrossEdge(e); + } + } + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Search/BidirectionalDepthFirstSearchAlgorithm.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Search/BidirectionalDepthFirstSearchAlgorithm.cs.meta new file mode 100644 index 0000000..0f357d8 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Search/BidirectionalDepthFirstSearchAlgorithm.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: afc03efbba1744f2c84530578253e55e +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Search/BreadthFirstSearchAlgorithm.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Search/BreadthFirstSearchAlgorithm.cs new file mode 100755 index 0000000..3d61ca4 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Search/BreadthFirstSearchAlgorithm.cs @@ -0,0 +1,229 @@ +using System; +using System.Collections.Generic; + +using QuickGraph.Collections; +using QuickGraph.Algorithms.Observers; +using QuickGraph.Algorithms.Services; + +namespace QuickGraph.Algorithms.Search +{ + /// + /// A breath first search algorithm for directed graphs + /// + /// + [Serializable] + public sealed class BreadthFirstSearchAlgorithm : + RootedAlgorithmBase>, + IVertexPredecessorRecorderAlgorithm, + IDistanceRecorderAlgorithm, + IVertexColorizerAlgorithm, + ITreeBuilderAlgorithm + where TEdge : IEdge + { + private IDictionary vertexColors; + private IQueue vertexQueue; + + public BreadthFirstSearchAlgorithm(IVertexListGraph g) + : this(g, new QuickGraph.Collections.Queue(), new Dictionary()) + {} + + public BreadthFirstSearchAlgorithm( + IVertexListGraph visitedGraph, + IQueue vertexQueue, + IDictionary vertexColors + ) + : this(null, visitedGraph, vertexQueue, vertexColors) + { } + + public BreadthFirstSearchAlgorithm( + IAlgorithmComponent host, + IVertexListGraph visitedGraph, + IQueue vertexQueue, + IDictionary vertexColors + ) + :base(host, visitedGraph) + { + if (vertexQueue == null) + throw new ArgumentNullException("vertexQueue"); + if (vertexColors == null) + throw new ArgumentNullException("vertexColors"); + + this.vertexColors = vertexColors; + this.vertexQueue = vertexQueue; + } + + public IDictionary VertexColors + { + get + { + return vertexColors; + } + } + + public event VertexEventHandler InitializeVertex; + private void OnInitializeVertex(TVertex v) + { + if (InitializeVertex != null) + InitializeVertex(this, new VertexEventArgs(v)); + } + + public event VertexEventHandler StartVertex; + private void OnStartVertex(TVertex v) + { + VertexEventHandler eh = this.StartVertex; + if (eh!=null) + eh(this, new VertexEventArgs(v)); + } + + public event VertexEventHandler ExamineVertex; + private void OnExamineVertex(TVertex v) + { + if (ExamineVertex != null) + ExamineVertex(this, new VertexEventArgs(v)); + } + + public event VertexEventHandler DiscoverVertex; + private void OnDiscoverVertex(TVertex v) + { + if (DiscoverVertex != null) + DiscoverVertex(this, new VertexEventArgs(v)); + } + + public event EdgeEventHandler ExamineEdge; + private void OnExamineEdge(TEdge e) + { + if (ExamineEdge != null) + ExamineEdge(this, new EdgeEventArgs(e)); + } + + public event EdgeEventHandler TreeEdge; + private void OnTreeEdge(TEdge e) + { + if (TreeEdge != null) + TreeEdge(this, new EdgeEventArgs(e)); + } + + public event EdgeEventHandler NonTreeEdge; + private void OnNonTreeEdge(TEdge e) + { + if (NonTreeEdge != null) + NonTreeEdge(this, new EdgeEventArgs(e)); + } + + public event EdgeEventHandler GrayTarget; + private void OnGrayTarget(TEdge e) + { + if (GrayTarget != null) + GrayTarget(this, new EdgeEventArgs(e)); + } + + public event EdgeEventHandler BlackTarget; + private void OnBlackTarget(TEdge e) + { + if (BlackTarget != null) + BlackTarget(this, new EdgeEventArgs(e)); + } + + public event VertexEventHandler FinishVertex; + private void OnFinishVertex(TVertex v) + { + if (FinishVertex != null) + FinishVertex(this, new VertexEventArgs(v)); + } + + public void Initialize() + { + var cancelManager = this.Services.CancelManager; + // initialize vertex u + foreach (var v in VisitedGraph.Vertices) + { + if (cancelManager.IsCancelling) + return; + VertexColors[v] = GraphColor.White; + OnInitializeVertex(v); + } + } + + protected override void InternalCompute() + { + if (this.VisitedGraph.VertexCount == 0) + return; + + this.Initialize(); + + TVertex rootVertex; + if (!this.TryGetRootVertex(out rootVertex)) + { + // enqueue roots + foreach (var root in AlgoUtility.Roots(this.VisitedGraph)) + this.EnqueueRoot(root); + } + else // enqueue select root only + { + this.Visit(rootVertex); + } + this.FlushVisitQueue(); + } + + public void Visit(TVertex s) + { + this.EnqueueRoot(s); + this.FlushVisitQueue(); + } + + private void EnqueueRoot(TVertex s) + { + this.OnStartVertex(s); + + this.VertexColors[s] = GraphColor.Gray; + + OnDiscoverVertex(s); + this.vertexQueue.Enqueue(s); + } + + private void FlushVisitQueue() + { + var cancelManager = this.Services.CancelManager; + + while (this.vertexQueue.Count != 0) + { + if (cancelManager.IsCancelling) return; + + var u = this.vertexQueue.Dequeue(); + OnExamineVertex(u); + foreach (var e in VisitedGraph.OutEdges(u)) + { + TVertex v = e.Target; + OnExamineEdge(e); + + GraphColor vColor = VertexColors[v]; + if (vColor == GraphColor.White) + { + OnTreeEdge(e); + VertexColors[v] = GraphColor.Gray; + OnDiscoverVertex(v); + this.vertexQueue.Enqueue(v); + } + else + { + OnNonTreeEdge(e); + if (vColor == GraphColor.Gray) + { + OnGrayTarget(e); + } + else + { + OnBlackTarget(e); + } + } + } + VertexColors[u] = GraphColor.Black; + + OnFinishVertex(u); + } + } + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Search/BreadthFirstSearchAlgorithm.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Search/BreadthFirstSearchAlgorithm.cs.meta new file mode 100644 index 0000000..5044509 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Search/BreadthFirstSearchAlgorithm.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 35ae30e72c2da4baeacd1606f4fbe77c +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Search/DepthFirstSearchAlgorithm.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Search/DepthFirstSearchAlgorithm.cs new file mode 100755 index 0000000..db69052 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Search/DepthFirstSearchAlgorithm.cs @@ -0,0 +1,232 @@ +using System; +using System.Collections.Generic; +using QuickGraph.Algorithms.Services; + +namespace QuickGraph.Algorithms.Search +{ + /// + /// A depth first search algorithm for directed graph + /// + /// + /// + /// + [Serializable] + public sealed class DepthFirstSearchAlgorithm : + RootedAlgorithmBase>, + IDistanceRecorderAlgorithm, + IVertexColorizerAlgorithm, + IVertexPredecessorRecorderAlgorithm, + IVertexTimeStamperAlgorithm, + ITreeBuilderAlgorithm + where TEdge : IEdge + { + private readonly IDictionary colors; + private int maxDepth = int.MaxValue; + + public DepthFirstSearchAlgorithm(IVertexListGraph g) + :this(g, new Dictionary()) + {} + + public DepthFirstSearchAlgorithm( + IVertexListGraph visitedGraph, + IDictionary colors + ) + : this(null, visitedGraph, colors) + { } + + public DepthFirstSearchAlgorithm( + IAlgorithmComponent host, + IVertexListGraph visitedGraph, + IDictionary colors + ) + :base(host, visitedGraph) + { + if (colors == null) + throw new ArgumentNullException("VertexColors"); + this.colors = colors; + } + + public IDictionary VertexColors + { + get + { + return this.colors; + } + } + + public int MaxDepth + { + get + { + return this.maxDepth; + } + set + { + this.maxDepth = value; + } + } + + public event VertexEventHandler InitializeVertex; + private void OnInitializeVertex(TVertex v) + { + VertexEventHandler eh = this.InitializeVertex; + if (eh!=null) + eh(this, new VertexEventArgs(v)); + } + + public event VertexEventHandler StartVertex; + private void OnStartVertex(TVertex v) + { + VertexEventHandler eh = this.StartVertex; + if (eh!=null) + eh(this, new VertexEventArgs(v)); + } + + public event VertexEventHandler DiscoverVertex; + private void OnDiscoverVertex(TVertex v) + { + VertexEventHandler eh = this.DiscoverVertex; + if (eh!=null) + eh(this, new VertexEventArgs(v)); + } + + public event EdgeEventHandler ExamineEdge; + private void OnExamineEdge(TEdge e) + { + EdgeEventHandler eh = this.ExamineEdge; + if (eh!=null) + eh(this, new EdgeEventArgs(e)); + } + + public event EdgeEventHandler TreeEdge; + private void OnTreeEdge(TEdge e) + { + EdgeEventHandler eh = this.TreeEdge; + if (eh!=null) + eh(this, new EdgeEventArgs(e)); + } + + public event EdgeEventHandler BackEdge; + private void OnBackEdge(TEdge e) + { + EdgeEventHandler eh = this.BackEdge; + if (eh!=null) + eh(this, new EdgeEventArgs(e)); + } + + public event EdgeEventHandler ForwardOrCrossEdge; + private void OnForwardOrCrossEdge(TEdge e) + { + EdgeEventHandler eh = this.ForwardOrCrossEdge; + if (eh!=null) + eh(this, new EdgeEventArgs(e)); + } + + public event VertexEventHandler FinishVertex; + private void OnFinishVertex(TVertex v) + { + VertexEventHandler eh = this.FinishVertex; + if (eh!=null) + eh(this, new VertexEventArgs(v)); + } + + protected override void InternalCompute() + { + // put all vertex to white + Initialize(); + + // if there is a starting vertex, start whith him: + TVertex rootVertex; + if (this.TryGetRootVertex(out rootVertex)) + { + OnStartVertex(rootVertex); + Visit(rootVertex, 0); + } + + var cancelManager = this.Services.CancelManager; + // process each vertex + foreach(TVertex u in VisitedGraph.Vertices) + { + if (cancelManager.IsCancelling) + return; + if (VertexColors[u] == GraphColor.White) + { + OnStartVertex(u); + Visit(u,0); + } + } + } + + public void Initialize() + { + foreach(TVertex u in VisitedGraph.Vertices) + { + VertexColors[u] = GraphColor.White; + OnInitializeVertex(u); + } + } + + private struct SearchFrame + { + public readonly TVertex Vertex; + public readonly IEnumerator Edges; + public SearchFrame(TVertex vertex, IEnumerator edges) + { + this.Vertex = vertex; + this.Edges = edges; + } + } + + public void Visit(TVertex root, int depth) + { + if ((object)root==null) + throw new ArgumentNullException("root"); + + Stack todo = new Stack(); + this.VertexColors[root] = GraphColor.Gray; + OnDiscoverVertex(root); + + var cancelManager = this.Services.CancelManager; + todo.Push(new SearchFrame(root, this.VisitedGraph.OutEdges(root).GetEnumerator())); + while (todo.Count > 0) + { + if (cancelManager.IsCancelling) return; + + var frame = todo.Pop(); + var u = frame.Vertex; + + var edges = frame.Edges; + while(edges.MoveNext()) + { + TEdge e = edges.Current; + if (cancelManager.IsCancelling) return; + + this.OnExamineEdge(e); + TVertex v = e.Target; + GraphColor c = this.VertexColors[v]; + switch (c) + { + case GraphColor.White: + OnTreeEdge(e); + todo.Push(new SearchFrame(u, edges)); + u = v; + edges = this.VisitedGraph.OutEdges(u).GetEnumerator(); + this.VertexColors[u] = GraphColor.Gray; + this.OnDiscoverVertex(u); + break; + case GraphColor.Gray: + OnBackEdge(e); break; + case GraphColor.Black: + OnForwardOrCrossEdge(e); break; + } + } + + this.VertexColors[u] = GraphColor.Black; + this.OnFinishVertex(u); + } + } + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Search/DepthFirstSearchAlgorithm.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Search/DepthFirstSearchAlgorithm.cs.meta new file mode 100644 index 0000000..5c5c2af --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Search/DepthFirstSearchAlgorithm.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: a1b2c5b681dd0428197d8dc57ea4c1da +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Search/EdgeDepthFirstSearchAlgorithm.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Search/EdgeDepthFirstSearchAlgorithm.cs new file mode 100755 index 0000000..5e7fc7e --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Search/EdgeDepthFirstSearchAlgorithm.cs @@ -0,0 +1,227 @@ +using System; +using System.Collections.Generic; +using QuickGraph.Algorithms.Services; + +namespace QuickGraph.Algorithms.Search +{ + /// + /// A edge depth first search algorithm for directed graphs + /// + /// + /// This is a variant of the classic DFS algorithm where the + /// edges are color marked instead of the vertices. + /// + /// + [Serializable] + public sealed class EdgeDepthFirstSearchAlgorithm : + RootedAlgorithmBase>, + IEdgeColorizerAlgorithm, + IEdgePredecessorRecorderAlgorithm, + ITreeBuilderAlgorithm + where TEdge : IEdge + { + private IDictionary colors; + private int maxDepth = int.MaxValue; + + public EdgeDepthFirstSearchAlgorithm(IEdgeListAndIncidenceGraph g) + :this(g, new Dictionary()) + { + } + + public EdgeDepthFirstSearchAlgorithm( + IEdgeListAndIncidenceGraph visitedGraph, + IDictionary colors + ) + :this(null, visitedGraph, colors) + {} + + public EdgeDepthFirstSearchAlgorithm( + IAlgorithmComponent host, + IEdgeListAndIncidenceGraph visitedGraph, + IDictionary colors + ) + :base(host, visitedGraph) + { + if (colors == null) + throw new ArgumentNullException("VertexColors"); + + this.colors = colors; + } + + public IDictionary EdgeColors + { + get + { + return this.colors; + } + } + + public int MaxDepth + { + get + { + return this.maxDepth; + } + set + { + this.maxDepth = value; + } + } + + public event EdgeEventHandler InitializeEdge; + private void OnInitializeEdge(TEdge e) + { + if (InitializeEdge != null) + InitializeEdge(this, new EdgeEventArgs(e)); + } + + public event VertexEventHandler StartVertex; + private void OnStartVertex(TVertex v) + { + if (StartVertex != null) + StartVertex(this, new VertexEventArgs(v)); + } + + public event EdgeEventHandler StartEdge; + private void OnStartEdge(TEdge e) + { + if (StartEdge != null) + StartEdge(this, new EdgeEventArgs(e)); + } + + public event EdgeEdgeEventHandler DiscoverTreeEdge; + private void OnDiscoverTreeEdge(TEdge e, TEdge targetEge) + { + if (DiscoverTreeEdge != null) + DiscoverTreeEdge(this, new EdgeEdgeEventArgs(e, targetEge)); + } + + public event EdgeEventHandler ExamineEdge; + private void OnExamineEdge(TEdge e) + { + if (ExamineEdge != null) + ExamineEdge(this, new EdgeEventArgs(e)); + } + + public event EdgeEventHandler TreeEdge; + private void OnTreeEdge(TEdge e) + { + if (TreeEdge != null) + TreeEdge(this, new EdgeEventArgs(e)); + } + + public event EdgeEventHandler BackEdge; + private void OnBackEdge(TEdge e) + { + if (BackEdge != null) + BackEdge(this, new EdgeEventArgs(e)); + } + + public event EdgeEventHandler ForwardOrCrossEdge; + private void OnForwardOrCrossEdge(TEdge e) + { + if (ForwardOrCrossEdge != null) + ForwardOrCrossEdge(this, new EdgeEventArgs(e)); + } + + public event EdgeEventHandler FinishEdge; + private void OnFinishEdge(TEdge e) + { + if (FinishEdge != null) + FinishEdge(this, new EdgeEventArgs(e)); + } + + protected override void InternalCompute() + { + Initialize(); + var cancelManager = this.Services.CancelManager; + if (cancelManager.IsCancelling) + return; + + // start whith him: + TVertex rootVertex; + if (this.TryGetRootVertex(out rootVertex)) + { + OnStartVertex(rootVertex); + + // process each out edge of v + foreach (var e in VisitedGraph.OutEdges(rootVertex)) + { + if (cancelManager.IsCancelling) + return; + if (EdgeColors[e] == GraphColor.White) + { + OnStartEdge(e); + Visit(e, 0); + } + } + } + + // process the rest of the graph edges + foreach (var e in VisitedGraph.Edges) + { + if (cancelManager.IsCancelling) + return; + if (EdgeColors[e] == GraphColor.White) + { + OnStartEdge(e); + Visit(e, 0); + } + } + } + + public void Initialize() + { + // put all vertex to white + var cancelManager = this.Services.CancelManager; + foreach (var e in VisitedGraph.Edges) + { + if (cancelManager.IsCancelling) + return; + EdgeColors[e] = GraphColor.White; + OnInitializeEdge(e); + } + } + + public void Visit(TEdge se, int depth) + { + if (depth > this.maxDepth) + return; + var cancelManager = this.Services.CancelManager; + + // mark edge as gray + EdgeColors[se] = GraphColor.Gray; + // add edge to the search tree + OnTreeEdge(se); + + // iterate over out-edges + foreach (var e in VisitedGraph.OutEdges(se.Target)) + { + if (cancelManager.IsCancelling) return; + + // check edge is not explored yet, + // if not, explore it. + if (EdgeColors[e] == GraphColor.White) + { + OnDiscoverTreeEdge(se, e); + Visit(e, depth + 1); + } + else if (EdgeColors[e] == GraphColor.Gray) + { + // edge is being explored + OnBackEdge(e); + } + else + // edge is black + OnForwardOrCrossEdge(e); + } + + // all out-edges have been explored + EdgeColors[se] = GraphColor.Black; + OnFinishEdge(se); + } + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Search/EdgeDepthFirstSearchAlgorithm.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Search/EdgeDepthFirstSearchAlgorithm.cs.meta new file mode 100644 index 0000000..0ba7c46 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Search/EdgeDepthFirstSearchAlgorithm.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 22145ecb7e0b84b2e86bc97804ac1964 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Search/HeightFirstSearchAlgorithm.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Search/HeightFirstSearchAlgorithm.cs new file mode 100755 index 0000000..1775277 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Search/HeightFirstSearchAlgorithm.cs @@ -0,0 +1,403 @@ +using System; +using System.Collections.Generic; + +using QuickGraph; +using QuickGraph.Algorithms; + +namespace ModelDriven.Graph.Algorithms.Search +{ + + /// + /// + public sealed class HeightFirstSearchAlgorithm : + /* + IAlgorithm>, + IEdgeColorizerAlgorithm, + IEdgePredecessorRecorderAlgorithm, + ITreeBuilderAlgorithm + where Edge : IEdge + { + private IBidirectionalVertexListGraph visitedGraph; + private VertexColorDictionary colors; + private int maxDepth = int.MaxValue; + + /// + /// A height first search algorithm on a directed graph + /// + /// The graph to traverse + /// g is null + public HeightFirstSearchAlgorithm(IBidirectionalVertexListGraph g) + { + if (g == null) + throw new ArgumentNullException("g"); + this.visitedGraph = g; + this.colors = new VertexColorDictionary(); + } + + /// + /// A height first search algorithm on a directed graph + /// + /// The graph to traverse + /// vertex color map + /// g or colors are null + public HeightFirstSearchAlgorithm( + IBidirectionalVertexListGraph g, + VertexColorDictionary colors + ) + { + if (g == null) + throw new ArgumentNullException("g"); + if (colors == null) + throw new ArgumentNullException("Colors"); + + this.visitedGraph = g; + this.colors = colors; + } + + /// + /// Visited graph + /// + public IBidirectionalVertexListGraph VisitedGraph + { + get + { + return this.visitedGraph; + } + } + + Object IAlgorithm.VisitedGraph + { + get + { + return this.VisitedGraph; + } + } + + /// + /// Gets the vertex color map + /// + /// + /// Vertex color () dictionary + /// + public VertexColorDictionary Colors + { + get + { + return this.colors; + } + } + + /// + /// IVertexColorizerAlgorithm implementation + /// + IDictionary IVertexColorizerAlgorithm.Colors + { + get + { + return this.Colors; + } + } + + /// + /// Gets or sets the maximum exploration depth, from + /// the start vertex. + /// + /// + /// Defaulted at int.MaxValue. + /// + /// + /// Maximum exploration depth. + /// + public int MaxDepth + { + get + { + return this.maxDepth; + } + set + { + this.maxDepth = value; + } + } + + #region Events + /// + /// Invoked on every vertex of the graph before the start of the graph + /// search. + /// + public event VertexEventHandler InitializeVertex; + + /// + /// Raises the event. + /// + /// vertex that raised the event + protected void OnInitializeVertex(IVertex v) + { + if (InitializeVertex != null) + InitializeVertex(this, new VertexEventArgs(v)); + } + + /// + /// Invoked on the source vertex once before the start of the search. + /// + public event VertexEventHandler StartVertex; + + /// + /// Raises the event. + /// + /// vertex that raised the event + protected void OnStartVertex(IVertex v) + { + if (StartVertex != null) + StartVertex(this, new VertexEventArgs(v)); + } + + /// + /// Invoked when a vertex is encountered for the first time. + /// + public event VertexEventHandler DiscoverVertex; + + + /// + /// Raises the event. + /// + /// vertex that raised the event + protected void OnDiscoverVertex(IVertex v) + { + if (DiscoverVertex != null) + DiscoverVertex(this, new VertexEventArgs(v)); + } + + /// + /// Invoked on every out-edge of each vertex after it is discovered. + /// + public event EdgeEventHandler ExamineEdge; + + + /// + /// Raises the event. + /// + /// edge that raised the event + protected void OnExamineEdge(IEdge e) + { + if (ExamineEdge != null) + ExamineEdge(this, new EdgeEventArgs(e)); + } + + /// + /// Invoked on each edge as it becomes a member of the edges that form + /// the search tree. If you wish to record predecessors, do so at this + /// event point. + /// + public event EdgeEventHandler TreeEdge; + + + /// + /// Raises the event. + /// + /// edge that raised the event + protected void OnTreeEdge(IEdge e) + { + if (TreeEdge != null) + TreeEdge(this, new EdgeEventArgs(e)); + } + + /// + /// Invoked on the back edges in the graph. + /// + public event EdgeEventHandler BackEdge; + + + /// + /// Raises the event. + /// + /// edge that raised the event + protected void OnBackEdge(IEdge e) + { + if (BackEdge != null) + BackEdge(this, new EdgeEventArgs(e)); + } + + /// + /// Invoked on forward or cross edges in the graph. + /// (In an undirected graph this method is never called.) + /// + public event EdgeEventHandler ForwardOrCrossEdge; + + + /// + /// Raises the event. + /// + /// edge that raised the event + protected void OnForwardOrCrossEdge(IEdge e) + { + if (ForwardOrCrossEdge != null) + ForwardOrCrossEdge(this, new EdgeEventArgs(e)); + } + + /// + /// Invoked on a vertex after all of its out edges have been added to + /// the search tree and all of the adjacent vertices have been + /// discovered (but before their out-edges have been examined). + /// + public event VertexEventHandler FinishVertex; + + /// + /// Raises the event. + /// + /// vertex that raised the event + protected void OnFinishVertex(IVertex v) + { + if (FinishVertex != null) + FinishVertex(this, new VertexEventArgs(v)); + } + #endregion + + /// + /// Execute the DFS search. + /// + public void Compute() + { + Compute(null); + } + + /// + /// Execute the DFS starting with the vertex s + /// + /// Starting vertex + public void Compute(IVertex s) + { + // put all vertex to white + Initialize(); + + // if there is a starting vertex, start whith him: + if (s != null) + { + OnStartVertex(s); + Visit(s, 0); + } + + // process each vertex + foreach (IVertex u in VisitedGraph.Vertices) + { + if (Colors[u] == GraphColor.White) + { + OnStartVertex(u); + Visit(u, 0); + } + } + } + + /// + /// Initializes the vertex color map + /// + /// + /// + public void Initialize() + { + foreach (IVertex u in VisitedGraph.Vertices) + { + Colors[u] = GraphColor.White; + OnInitializeVertex(u); + } + } + + /// + /// Does a depth first search on the vertex u + /// + /// vertex to explore + /// current recursion depth + /// u cannot be null + public void Visit(IVertex u, int depth) + { + if (depth > this.maxDepth) + return; + if (u == null) + throw new ArgumentNullException("u"); + + Colors[u] = GraphColor.Gray; + OnDiscoverVertex(u); + + IVertex v = null; + foreach (IEdge e in VisitedGraph.InEdges(u)) + { + OnExamineEdge(e); + v = e.Source; + GraphColor c = Colors[v]; + if (c == GraphColor.White) + { + OnTreeEdge(e); + Visit(v, depth + 1); + } + else if (c == GraphColor.Gray) + { + OnBackEdge(e); + } + else + { + OnForwardOrCrossEdge(e); + } + } + + Colors[u] = GraphColor.Black; + OnFinishVertex(u); + } + + /// + /// Registers the predecessors handler + /// + /// + public void RegisterPredecessorRecorderHandlers(IPredecessorRecorderVisitor vis) + { + if (vis == null) + throw new ArgumentNullException("visitor"); + TreeEdge += new EdgeEventHandler(vis.TreeEdge); + FinishVertex += new VertexEventHandler(vis.FinishVertex); + } + + /// + /// + /// + /// + public void RegisterTimeStamperHandlers(ITimeStamperVisitor vis) + { + if (vis == null) + throw new ArgumentNullException("visitor"); + + DiscoverVertex += new VertexEventHandler(vis.DiscoverVertex); + FinishVertex += new VertexEventHandler(vis.FinishVertex); + } + + /// + /// + /// + /// + public void RegisterVertexColorizerHandlers(IVertexColorizerVisitor vis) + { + if (vis == null) + throw new ArgumentNullException("visitor"); + + InitializeVertex += new VertexEventHandler(vis.InitializeVertex); + DiscoverVertex += new VertexEventHandler(vis.DiscoverVertex); + FinishVertex += new VertexEventHandler(vis.FinishVertex); + } + + /// + /// + /// + /// + public void RegisterTreeEdgeBuilderHandlers(ITreeEdgeBuilderVisitor vis) + { + if (vis == null) + throw new ArgumentNullException("visitor"); + + TreeEdge += new EdgeEventHandler(vis.TreeEdge); + } + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Search/HeightFirstSearchAlgorithm.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Search/HeightFirstSearchAlgorithm.cs.meta new file mode 100644 index 0000000..bb56e86 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Search/HeightFirstSearchAlgorithm.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: f95833b6da636407585f31dba3543c6c +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Search/ImplicitDepthFirstSearchAlgorithm.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Search/ImplicitDepthFirstSearchAlgorithm.cs new file mode 100755 index 0000000..b7d3924 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Search/ImplicitDepthFirstSearchAlgorithm.cs @@ -0,0 +1,241 @@ +using System; +using System.Collections.Generic; +using QuickGraph.Algorithms.Services; + +namespace QuickGraph.Algorithms.Search +{ + /// + /// A depth first search algorithm for implicit directed graphs + /// + /// + [Serializable] + public sealed class ImplicitDepthFirstSearchAlgorithm : + RootedAlgorithmBase>, + IVertexPredecessorRecorderAlgorithm, + IVertexTimeStamperAlgorithm, + ITreeBuilderAlgorithm + where TEdge : IEdge + { + private int maxDepth = int.MaxValue; + private IDictionary vertexColors = new Dictionary(); + + public ImplicitDepthFirstSearchAlgorithm( + IIncidenceGraph visitedGraph) + : this(null, visitedGraph) + { } + + public ImplicitDepthFirstSearchAlgorithm( + IAlgorithmComponent host, + IIncidenceGraph visitedGraph) + :base(host, visitedGraph) + {} + + /// + /// Gets the vertex color map + /// + /// + /// Vertex color () dictionary + /// + public IDictionary VertexColors + { + get + { + return this.vertexColors; + } + } + + /// + /// Gets or sets the maximum exploration depth, from + /// the start vertex. + /// + /// + /// Defaulted at int.MaxValue. + /// + /// + /// Maximum exploration depth. + /// + public int MaxDepth + { + get + { + return this.maxDepth; + } + set + { + this.maxDepth = value; + } + } + + /// + /// Invoked on the source vertex once before the start of the search. + /// + public event VertexEventHandler StartVertex; + + /// + /// Raises the event. + /// + /// vertex that raised the event + private void OnStartVertex(TVertex v) + { + if (StartVertex != null) + StartVertex(this, new VertexEventArgs(v)); + } + + /// + /// Invoked when a vertex is encountered for the first time. + /// + public event VertexEventHandler DiscoverVertex; + + + /// + /// Raises the event. + /// + /// vertex that raised the event + private void OnDiscoverVertex(TVertex v) + { + if (DiscoverVertex != null) + DiscoverVertex(this, new VertexEventArgs(v)); + } + + /// + /// Invoked on every out-edge of each vertex after it is discovered. + /// + public event EdgeEventHandler ExamineEdge; + + + /// + /// Raises the event. + /// + /// edge that raised the event + private void OnExamineEdge(TEdge e) + { + if (ExamineEdge != null) + ExamineEdge(this, new EdgeEventArgs(e)); + } + + /// + /// Invoked on each edge as it becomes a member of the edges that form + /// the search tree. If you wish to record predecessors, do so at this + /// event point. + /// + public event EdgeEventHandler TreeEdge; + + + /// + /// Raises the event. + /// + /// edge that raised the event + private void OnTreeEdge(TEdge e) + { + if (TreeEdge != null) + TreeEdge(this, new EdgeEventArgs(e)); + } + + /// + /// Invoked on the back edges in the graph. + /// + public event EdgeEventHandler BackEdge; + + + /// + /// Raises the event. + /// + /// edge that raised the event + private void OnBackEdge(TEdge e) + { + if (BackEdge != null) + BackEdge(this, new EdgeEventArgs(e)); + } + + /// + /// Invoked on forward or cross edges in the graph. + /// (In an undirected graph this method is never called.) + /// + public event EdgeEventHandler ForwardOrCrossEdge; + + + /// + /// Raises the event. + /// + /// edge that raised the event + private void OnForwardOrCrossEdge(TEdge e) + { + if (ForwardOrCrossEdge != null) + ForwardOrCrossEdge(this, new EdgeEventArgs(e)); + } + + /// + /// Invoked on a vertex after all of its out edges have been added to + /// the search tree and all of the adjacent vertices have been + /// discovered (but before their out-edges have been examined). + /// + public event VertexEventHandler FinishVertex; + + /// + /// Raises the event. + /// + /// vertex that raised the event + private void OnFinishVertex(TVertex v) + { + if (FinishVertex != null) + FinishVertex(this, new VertexEventArgs(v)); + } + + protected override void InternalCompute() + { + TVertex rootVertex; + if (!this.TryGetRootVertex(out rootVertex)) + throw new RootVertexNotSpecifiedException(); + + this.Initialize(); + this.Visit(rootVertex, 0); + } + + private void Initialize() + { + this.VertexColors.Clear(); + } + + private void Visit(TVertex u, int depth) + { + if (depth > this.MaxDepth) + return; + + VertexColors[u] = GraphColor.Gray; + OnDiscoverVertex(u); + + var cancelManager = this.Services.CancelManager; + foreach (var e in VisitedGraph.OutEdges(u)) + { + if (cancelManager.IsCancelling) return; + + OnExamineEdge(e); + TVertex v = e.Target; + + if (!this.VertexColors.ContainsKey(v)) + { + OnTreeEdge(e); + Visit(v, depth + 1); + } + else + { + GraphColor c = VertexColors[v]; + if (c == GraphColor.Gray) + { + OnBackEdge(e); + } + else + { + OnForwardOrCrossEdge(e); + } + } + } + + VertexColors[u] = GraphColor.Black; + OnFinishVertex(u); + } + } +} \ No newline at end of file diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Search/ImplicitDepthFirstSearchAlgorithm.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Search/ImplicitDepthFirstSearchAlgorithm.cs.meta new file mode 100644 index 0000000..9fbc029 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Search/ImplicitDepthFirstSearchAlgorithm.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 1afed3eb9ff3f4e54bd23f96e1243da7 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Search/ImplicitEdgeDepthFirstSearchAlgorithm.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Search/ImplicitEdgeDepthFirstSearchAlgorithm.cs new file mode 100755 index 0000000..f48347c --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Search/ImplicitEdgeDepthFirstSearchAlgorithm.cs @@ -0,0 +1,268 @@ +using System; +using System.Collections.Generic; +using QuickGraph.Algorithms.Services; + +namespace QuickGraph.Algorithms.Search +{ + /// + /// A edge depth first search algorithm for implicit directed graphs + /// + /// + /// This is a variant of the classic DFS where the edges are color + /// marked. + /// + /// + [Serializable] + public sealed class ImplicitEdgeDepthFirstSearchAlgorithm : + RootedAlgorithmBase>, + ITreeBuilderAlgorithm + where TEdge : IEdge + { + private int maxDepth = int.MaxValue; + private IDictionary edgeColors = new Dictionary(); + + public ImplicitEdgeDepthFirstSearchAlgorithm(IIncidenceGraph visitedGraph) + : this(null, visitedGraph) + { } + + public ImplicitEdgeDepthFirstSearchAlgorithm( + IAlgorithmComponent host, + IIncidenceGraph visitedGraph + ) + :base(host, visitedGraph) + {} + + /// + /// + /// Gets the vertex color map + /// + /// + /// Vertex color () dictionary + /// + public IDictionary EdgeColors + { + get + { + return this.edgeColors; + } + } + + /// + /// Gets or sets the maximum exploration depth, from + /// the start vertex. + /// + /// + /// Defaulted at int.MaxValue. + /// + /// + /// Maximum exploration depth. + /// + public int MaxDepth + { + get + { + return this.maxDepth; + } + set + { + this.maxDepth = value; + } + } + + + /// + /// Invoked on the source vertex once before the start of the search. + /// + public event VertexEventHandler StartVertex; + + /// + /// Triggers the StartVertex event. + /// + /// + private void OnStartVertex(TVertex v) + { + if (this.StartVertex != null) + StartVertex(this, new VertexEventArgs(v)); + } + + /// + /// Invoked on the first edge of a test case + /// + public event EdgeEventHandler StartEdge; + + /// + /// Triggers the StartEdge event. + /// + /// + private void OnStartEdge(TEdge e) + { + if (this.StartEdge != null) + StartEdge(this, new EdgeEventArgs(e)); + } + + /// + /// + /// + public event EdgeEdgeEventHandler DiscoverTreeEdge; + + /// + /// Triggers DiscoverEdge event + /// + /// + /// + private void OnDiscoverTreeEdge(TEdge se, TEdge e) + { + if (DiscoverTreeEdge != null) + DiscoverTreeEdge(this, new EdgeEdgeEventArgs(se, e)); + } + + /// + /// Invoked on each edge as it becomes a member of the edges that form + /// the search tree. If you wish to record predecessors, do so at this + /// event point. + /// + public event EdgeEventHandler TreeEdge; + + /// + /// Triggers the TreeEdge event. + /// + /// + private void OnTreeEdge(TEdge e) + { + if (TreeEdge != null) + TreeEdge(this, new EdgeEventArgs(e)); + } + + /// + /// Invoked on the back edges in the graph. + /// + public event EdgeEventHandler BackEdge; + + /// + /// Triggers the BackEdge event. + /// + /// + private void OnBackEdge(TEdge e) + { + if (BackEdge != null) + BackEdge(this, new EdgeEventArgs(e)); + } + + /// + /// Invoked on forward or cross edges in the graph. + /// (In an undirected graph this method is never called.) + /// + public event EdgeEventHandler ForwardOrCrossEdge; + + /// + /// Triggers the ForwardOrCrossEdge event. + /// + /// + private void OnForwardOrCrossEdge(TEdge e) + { + if (this.ForwardOrCrossEdge != null) + ForwardOrCrossEdge(this, new EdgeEventArgs(e)); + } + + /// + /// Invoked on a edge after all of its out edges have been added to + /// the search tree and all of the adjacent vertices have been + /// discovered (but before their out-edges have been examined). + /// + public event EdgeEventHandler FinishEdge; + + /// + /// Triggers the ForwardOrCrossEdge event. + /// + /// + private void OnFinishEdge(TEdge e) + { + if (this.FinishEdge != null) + FinishEdge(this, new EdgeEventArgs(e)); + } + + + + protected override void InternalCompute() + { + TVertex rootVertex; + if (!this.TryGetRootVertex(out rootVertex)) + throw new RootVertexNotSpecifiedException(); + + // initialize algorithm + this.Initialize(); + + // start whith him: + OnStartVertex(rootVertex); + + var cancelManager = this.Services.CancelManager; + // process each out edge of v + foreach (var e in this.VisitedGraph.OutEdges(rootVertex)) + { + if (cancelManager.IsCancelling) return; + + if (!this.EdgeColors.ContainsKey(e)) + { + OnStartEdge(e); + Visit(e, 0); + } + } + } + + /// + /// Does a depth first search on the vertex u + /// + /// edge to explore + /// current exploration depth + /// se cannot be null + private void Visit(TEdge se, int depth) + { + GraphContracts.AssumeNotNull(se, "se"); + if (depth > this.maxDepth) + return; + + // mark edge as gray + this.EdgeColors[se] = GraphColor.Gray; + // add edge to the search tree + OnTreeEdge(se); + + var cancelManager = this.Services.CancelManager; + // iterate over out-edges + foreach (var e in this.VisitedGraph.OutEdges(se.Target)) + { + if (cancelManager.IsCancelling) return; + + // check edge is not explored yet, + // if not, explore it. + if (!this.EdgeColors.ContainsKey(e)) + { + OnDiscoverTreeEdge(se, e); + Visit(e, depth + 1); + } + else + { + GraphColor c = this.EdgeColors[e]; + if (EdgeColors[e] == GraphColor.Gray) + OnBackEdge(e); + else + OnForwardOrCrossEdge(e); + } + } + + // all out-edges have been explored + this.EdgeColors[se] = GraphColor.Black; + OnFinishEdge(se); + } + + /// + /// Initializes the algorithm before computation. + /// + private void Initialize() + { + this.EdgeColors.Clear(); + } + } +} \ No newline at end of file diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Search/ImplicitEdgeDepthFirstSearchAlgorithm.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Search/ImplicitEdgeDepthFirstSearchAlgorithm.cs.meta new file mode 100644 index 0000000..ebb6090 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Search/ImplicitEdgeDepthFirstSearchAlgorithm.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 1b49f0d85c7194b3fad4b93da756bc5b +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Search/UndirectedBreathFirstSearchAlgorithm.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Search/UndirectedBreathFirstSearchAlgorithm.cs new file mode 100755 index 0000000..3916bc6 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Search/UndirectedBreathFirstSearchAlgorithm.cs @@ -0,0 +1,225 @@ +using System; +using System.Collections.Generic; + +using QuickGraph.Collections; +using QuickGraph.Algorithms.Observers; +using QuickGraph.Algorithms.Services; + +namespace QuickGraph.Algorithms.Search +{ + /// + /// A breath first search algorithm for undirected graphs + /// + /// + [Serializable] + public sealed class UndirectedBreadthFirstSearchAlgorithm : + RootedAlgorithmBase>, + IVertexPredecessorRecorderAlgorithm, + IDistanceRecorderAlgorithm, + IVertexColorizerAlgorithm, + ITreeBuilderAlgorithm + where TEdge : IEdge + { + private IDictionary vertexColors; + private IQueue vertexQueue; + + public UndirectedBreadthFirstSearchAlgorithm(IUndirectedGraph g) + : this(g, new QuickGraph.Collections.Queue(), new Dictionary()) + { } + + public UndirectedBreadthFirstSearchAlgorithm( + IUndirectedGraph visitedGraph, + IQueue vertexQueue, + IDictionary vertexColors + ) + : this(null, visitedGraph, vertexQueue, vertexColors) + { } + + public UndirectedBreadthFirstSearchAlgorithm( + IAlgorithmComponent host, + IUndirectedGraph visitedGraph, + IQueue vertexQueue, + IDictionary vertexColors + ) + : base(host, visitedGraph) + { + if (vertexQueue == null) + throw new ArgumentNullException("vertexQueue"); + if (vertexColors == null) + throw new ArgumentNullException("vertexColors"); + + this.vertexColors = vertexColors; + this.vertexQueue = vertexQueue; + } + + public IDictionary VertexColors + { + get + { + return vertexColors; + } + } + + public event VertexEventHandler InitializeVertex; + private void OnInitializeVertex(TVertex v) + { + if (InitializeVertex != null) + InitializeVertex(this, new VertexEventArgs(v)); + } + + + public event VertexEventHandler StartVertex; + private void OnStartVertex(TVertex v) + { + VertexEventHandler eh = this.StartVertex; + if (eh != null) + eh(this, new VertexEventArgs(v)); + } + + public event VertexEventHandler ExamineVertex; + private void OnExamineVertex(TVertex v) + { + if (ExamineVertex != null) + ExamineVertex(this, new VertexEventArgs(v)); + } + + public event VertexEventHandler DiscoverVertex; + private void OnDiscoverVertex(TVertex v) + { + if (DiscoverVertex != null) + DiscoverVertex(this, new VertexEventArgs(v)); + } + + public event EdgeEventHandler ExamineEdge; + private void OnExamineEdge(TEdge e) + { + if (ExamineEdge != null) + ExamineEdge(this, new EdgeEventArgs(e)); + } + + public event EdgeEventHandler TreeEdge; + private void OnTreeEdge(TEdge e) + { + if (TreeEdge != null) + TreeEdge(this, new EdgeEventArgs(e)); + } + + public event EdgeEventHandler NonTreeEdge; + private void OnNonTreeEdge(TEdge e) + { + if (NonTreeEdge != null) + NonTreeEdge(this, new EdgeEventArgs(e)); + } + + public event EdgeEventHandler GrayTarget; + private void OnGrayTarget(TEdge e) + { + if (GrayTarget != null) + GrayTarget(this, new EdgeEventArgs(e)); + } + + public event EdgeEventHandler BlackTarget; + private void OnBlackTarget(TEdge e) + { + if (BlackTarget != null) + BlackTarget(this, new EdgeEventArgs(e)); + } + + public event VertexEventHandler FinishVertex; + private void OnFinishVertex(TVertex v) + { + if (FinishVertex != null) + FinishVertex(this, new VertexEventArgs(v)); + } + + public void Initialize() + { + // initialize vertex u + var cancelManager = this.Services.CancelManager; + foreach (var v in VisitedGraph.Vertices) + { + if (cancelManager.IsCancelling) + return; + VertexColors[v] = GraphColor.White; + OnInitializeVertex(v); + } + } + + protected override void InternalCompute() + { + this.Initialize(); + + TVertex rootVertex; + if (!this.TryGetRootVertex(out rootVertex)) + { + // enqueue all roots + foreach (var root in AlgoUtility.Roots(this.VisitedGraph)) + this.EnqueueRoot(root); + } + else + this.EnqueueRoot(rootVertex); + + this.FlushVisitQueue(); + } + + public void Visit(TVertex s) + { + this.EnqueueRoot(s); + this.FlushVisitQueue(); + } + + private void EnqueueRoot(TVertex s) + { + this.OnStartVertex(s); + this.VertexColors[s] = GraphColor.Gray; + OnDiscoverVertex(s); + this.vertexQueue.Enqueue(s); + } + + private void FlushVisitQueue() + { + var cancelManager = this.Services.CancelManager; + + while (this.vertexQueue.Count != 0) + { + if (cancelManager.IsCancelling) return; + + TVertex u = this.vertexQueue.Dequeue(); + + OnExamineVertex(u); + foreach (var e in VisitedGraph.AdjacentEdges(u)) + { + TVertex v = (e.Source.Equals(u)) ? e.Target : e.Source; + OnExamineEdge(e); + + GraphColor vColor = VertexColors[v]; + if (vColor == GraphColor.White) + { + OnTreeEdge(e); + VertexColors[v] = GraphColor.Gray; + OnDiscoverVertex(v); + this.vertexQueue.Enqueue(v); + } + else + { + OnNonTreeEdge(e); + if (vColor == GraphColor.Gray) + { + OnGrayTarget(e); + } + else + { + OnBlackTarget(e); + } + } + } + VertexColors[u] = GraphColor.Black; + + OnFinishVertex(u); + } + } + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Search/UndirectedBreathFirstSearchAlgorithm.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Search/UndirectedBreathFirstSearchAlgorithm.cs.meta new file mode 100644 index 0000000..b2df960 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Search/UndirectedBreathFirstSearchAlgorithm.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 00d2961c2e1d74aff968fbf374930941 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Search/UndirectedDepthFirstSearchAlgorithm.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Search/UndirectedDepthFirstSearchAlgorithm.cs new file mode 100755 index 0000000..cb0e38e --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Search/UndirectedDepthFirstSearchAlgorithm.cs @@ -0,0 +1,213 @@ +using System; +using System.Collections.Generic; +using QuickGraph.Algorithms.Services; + +namespace QuickGraph.Algorithms.Search +{ + /// + /// A depth first search algorithm for undirected graphs + /// + /// + [Serializable] + public sealed class UndirectedDepthFirstSearchAlgorithm : + RootedAlgorithmBase>, + IDistanceRecorderAlgorithm, + IVertexColorizerAlgorithm, + IVertexPredecessorRecorderAlgorithm, + IVertexTimeStamperAlgorithm, + ITreeBuilderAlgorithm + where TEdge : IEdge + { + private IDictionary colors; + private int maxDepth = int.MaxValue; + + public UndirectedDepthFirstSearchAlgorithm(IUndirectedGraph g) + :this(g, new Dictionary()) + { + } + + public UndirectedDepthFirstSearchAlgorithm( + IUndirectedGraph visitedGraph, + IDictionary colors + ) + :this(null, visitedGraph, colors) + {} + + public UndirectedDepthFirstSearchAlgorithm( + IAlgorithmComponent host, + IUndirectedGraph visitedGraph, + IDictionary colors + ) + :base(host, visitedGraph) + { + if (colors == null) + throw new ArgumentNullException("VertexColors"); + + this.colors = colors; + } + + public IDictionary VertexColors + { + get + { + return this.colors; + } + } + + public int MaxDepth + { + get + { + return this.maxDepth; + } + set + { + this.maxDepth = value; + } + } + + public event VertexEventHandler InitializeVertex; + private void OnInitializeVertex(TVertex v) + { + if (InitializeVertex != null) + InitializeVertex(this, new VertexEventArgs(v)); + } + + public event VertexEventHandler StartVertex; + private void OnStartVertex(TVertex v) + { + if (StartVertex != null) + StartVertex(this, new VertexEventArgs(v)); + } + + public event VertexEventHandler DiscoverVertex; + private void OnDiscoverVertex(TVertex v) + { + if (DiscoverVertex != null) + DiscoverVertex(this, new VertexEventArgs(v)); + } + + public event EdgeEventHandler ExamineEdge; + private void OnExamineEdge(TEdge e) + { + if (ExamineEdge != null) + ExamineEdge(this, new EdgeEventArgs(e)); + } + + public event EdgeEventHandler TreeEdge; + private void OnTreeEdge(TEdge e) + { + if (TreeEdge != null) + TreeEdge(this, new EdgeEventArgs(e)); + } + + public event EdgeEventHandler BackEdge; + private void OnBackEdge(TEdge e) + { + if (BackEdge != null) + BackEdge(this, new EdgeEventArgs(e)); + } + + public event EdgeEventHandler ForwardOrCrossEdge; + private void OnForwardOrCrossEdge(TEdge e) + { + if (ForwardOrCrossEdge != null) + ForwardOrCrossEdge(this, new EdgeEventArgs(e)); + } + + public event VertexEventHandler FinishVertex; + private void OnFinishVertex(TVertex v) + { + if (FinishVertex != null) + FinishVertex(this, new VertexEventArgs(v)); + } + + protected override void InternalCompute() + { + // put all vertex to white + Initialize(); + + // if there is a starting vertex, start whith him: + TVertex rootVertex; + if (this.TryGetRootVertex(out rootVertex)) + { + OnStartVertex(rootVertex); + Visit(rootVertex, 0); + } + + var cancelManager = this.Services.CancelManager; + // process each vertex + foreach (var u in VisitedGraph.Vertices) + { + if (cancelManager.IsCancelling) + return; + if (VertexColors[u] == GraphColor.White) + { + OnStartVertex(u); + Visit(u, 0); + } + } + } + + public void Initialize() + { + var cancelManager = this.Services.CancelManager; + foreach (var u in VisitedGraph.Vertices) + { + if (cancelManager.IsCancelling) + return; + VertexColors[u] = GraphColor.White; + OnInitializeVertex(u); + } + } + + public void Visit(TVertex u, int depth) + { + if (depth > this.maxDepth) + return; + if (u == null) + throw new ArgumentNullException("u"); + + var cancelManager = this.Services.CancelManager; + if (cancelManager.IsCancelling) + return; + + VertexColors[u] = GraphColor.Gray; + OnDiscoverVertex(u); + + TVertex v = default(TVertex); + foreach (var e in VisitedGraph.AdjacentEdges(u)) + { + if (cancelManager.IsCancelling) + return; + + OnExamineEdge(e); + if (u.Equals(e.Source)) + v = e.Target; + else + v = e.Source; + + GraphColor c = VertexColors[v]; + if (c == GraphColor.White) + { + OnTreeEdge(e); + Visit(v, depth + 1); + } + else if (c == GraphColor.Gray) + { + OnBackEdge(e); + } + else + { + OnForwardOrCrossEdge(e); + } + } + + VertexColors[u] = GraphColor.Black; + OnFinishVertex(u); + } + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Search/UndirectedDepthFirstSearchAlgorithm.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Search/UndirectedDepthFirstSearchAlgorithm.cs.meta new file mode 100644 index 0000000..bea6e41 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Search/UndirectedDepthFirstSearchAlgorithm.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 4bd3e69f4698547ba8e06d3b9ecbe257 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Search/UndirectedEdgeDepthFirstSearchAlgorithm.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Search/UndirectedEdgeDepthFirstSearchAlgorithm.cs new file mode 100755 index 0000000..dac88b5 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Search/UndirectedEdgeDepthFirstSearchAlgorithm.cs @@ -0,0 +1,205 @@ +using System; +using System.Collections.Generic; + +using QuickGraph; +using QuickGraph.Collections; +using QuickGraph.Algorithms; +using QuickGraph.Algorithms.Observers; +using QuickGraph.Algorithms.Services; + +namespace ModelDriven.Graph.Algorithms.Search +{ + [Serializable] + public sealed class UndirectedEdgeDepthFirstSearchAlgorithm : + RootedAlgorithmBase>, + IEdgeColorizerAlgorithm, + IEdgePredecessorRecorderAlgorithm, + ITreeBuilderAlgorithm + where Edge : IEdge + { + private IDictionary colors; + private int maxDepth = int.MaxValue; + + public UndirectedEdgeDepthFirstSearchAlgorithm(IUndirectedGraph g) + :this(g, new Dictionary()) + { + } + + public UndirectedEdgeDepthFirstSearchAlgorithm( + IUndirectedGraph visitedGraph, + IDictionary colors + ) + :base(visitedGraph) + { + if (colors == null) + throw new ArgumentNullException("VertexColors"); + + this.colors = colors; + } + + public IDictionary EdgeColors + { + get + { + return this.colors; + } + } + + public int MaxDepth + { + get + { + return this.maxDepth; + } + set + { + this.maxDepth = value; + } + } + + public event EdgeEventHandler InitializeEdge; + private void OnInitializeEdge(Edge e) + { + if (InitializeEdge != null) + InitializeEdge(this, new EdgeEventArgs(e)); + } + + public event VertexEventHandler StartVertex; + private void OnStartVertex(Vertex v) + { + if (StartVertex != null) + StartVertex(this, new VertexEventArgs(v)); + } + + public event EdgeEventHandler StartEdge; + private void OnStartEdge(Edge e) + { + if (StartEdge != null) + StartEdge(this, new EdgeEventArgs(e)); + } + + public event EdgeEdgeEventHandler DiscoverTreeEdge; + private void OnDiscoverTreeEdge(Edge e, Edge targetEge) + { + if (DiscoverTreeEdge != null) + DiscoverTreeEdge(this, new EdgeEdgeEventArgs(e, targetEge)); + } + + public event EdgeEventHandler ExamineEdge; + private void OnExamineEdge(Edge e) + { + if (ExamineEdge != null) + ExamineEdge(this, new EdgeEventArgs(e)); + } + + public event EdgeEventHandler TreeEdge; + private void OnTreeEdge(Edge e) + { + if (TreeEdge != null) + TreeEdge(this, new EdgeEventArgs(e)); + } + + public event EdgeEventHandler BackEdge; + private void OnBackEdge(Edge e) + { + if (BackEdge != null) + BackEdge(this, new EdgeEventArgs(e)); + } + + public event EdgeEventHandler ForwardOrCrossEdge; + private void OnForwardOrCrossEdge(Edge e) + { + if (ForwardOrCrossEdge != null) + ForwardOrCrossEdge(this, new EdgeEventArgs(e)); + } + + public event EdgeEventHandler FinishEdge; + private void OnFinishEdge(Edge e) + { + if (FinishEdge != null) + FinishEdge(this, new EdgeEventArgs(e)); + } + + protected override void InternalCompute() + { + Initialize(); + + // start whith him: + if (this.RootVertex != null) + { + OnStartVertex(this.RootVertex); + + // process each out edge of v + foreach (Edge e in VisitedGraph.OutEdges(this.RootVertex)) + { + if (EdgeColors[e] == GraphColor.White) + { + OnStartEdge(e); + Visit(e, 0); + } + } + } + + // process the rest of the graph edges + foreach (Edge e in VisitedGraph.Edges) + { + if (EdgeColors[e] == GraphColor.White) + { + OnStartEdge(e); + Visit(e, 0); + } + } + } + + public void Initialize() + { + // put all vertex to white + foreach (Edge e in VisitedGraph.Edges) + { + EdgeColors[e] = GraphColor.White; + OnInitializeEdge(e); + } + } + + public void Visit(Edge se, int depth) + { + if (depth > this.maxDepth) + return; + + // mark edge as gray + EdgeColors[se] = GraphColor.Gray; + // add edge to the search tree + OnTreeEdge(se); + + VisitEdges(this.VisitedGraph.AdjacentEdges(se.Target), depth); + VisitEdges(this.VisitedGraph.AdjacentEdges(se.Source), depth); + + // all edges have been explored + EdgeColors[se] = GraphColor.Black; + OnFinishEdge(se); + } + + private void VisitEdges(IEnumerable edges, int depth) + { + // iterate over out-edges + foreach (Edge e in edges) + { + // check edge is not explored yet, + // if not, explore it. + if (EdgeColors[e] == GraphColor.White) + { + OnDiscoverTreeEdge(se, e); + Visit(e, depth + 1); + } + else if (EdgeColors[e] == GraphColor.Gray) + { + // edge is being explored + OnBackEdge(e); + } + else + // edge is black + OnForwardOrCrossEdge(e); + } + } + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Search/UndirectedEdgeDepthFirstSearchAlgorithm.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Search/UndirectedEdgeDepthFirstSearchAlgorithm.cs.meta new file mode 100644 index 0000000..6247395 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Search/UndirectedEdgeDepthFirstSearchAlgorithm.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 1d7346abd9b3c40b28259b59f6c1a4a2 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Services.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Services.meta new file mode 100644 index 0000000..4a62221 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Services.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: 1d2b81998c7b7457d81c33068c77273d +folderAsset: yes +DefaultImporter: + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Services/IAlgorithmComponent.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Services/IAlgorithmComponent.cs new file mode 100755 index 0000000..d12b264 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Services/IAlgorithmComponent.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace QuickGraph.Algorithms.Services +{ + public interface IAlgorithmComponent + { + IAlgorithmServices Services { get; } + T GetService() where T : IService; + bool TryGetService(out T service) where T : IService; + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Services/IAlgorithmComponent.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Services/IAlgorithmComponent.cs.meta new file mode 100644 index 0000000..594bf01 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Services/IAlgorithmComponent.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 53f514da00e8242afbc962e8ea5619c4 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Services/IAlgorithmServices.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Services/IAlgorithmServices.cs new file mode 100755 index 0000000..ac1ba61 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Services/IAlgorithmServices.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace QuickGraph.Algorithms.Services +{ + /// + /// Common services available to algorithm instances + /// + public interface IAlgorithmServices + { + ICancelManager CancelManager { get; } + } + + class AlgorithmServices : + IAlgorithmServices + { + readonly IAlgorithmComponent host; + + public AlgorithmServices(IAlgorithmComponent host) + { + GraphContracts.AssumeNotNull(host, "host"); + this.host = host; + } + + ICancelManager _cancelManager; + public ICancelManager CancelManager + { + get + { + if (this._cancelManager == null) + this._cancelManager = this.host.GetService(); + return this._cancelManager; + } + } + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Services/IAlgorithmServices.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Services/IAlgorithmServices.cs.meta new file mode 100644 index 0000000..a9f6be0 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Services/IAlgorithmServices.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 8035ff247184445a2966d51187522fa4 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Services/ICancelManager.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Services/ICancelManager.cs new file mode 100755 index 0000000..8745af6 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Services/ICancelManager.cs @@ -0,0 +1,80 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading; + +namespace QuickGraph.Algorithms.Services +{ + public interface ICancelManager : + IService + { + /// + /// Raised when the cancel method is called + /// + event EventHandler CancelRequested; + + /// + /// Requests the component to cancel its computation + /// + void Cancel(); + + /// + /// Gets a value indicating if a cancellation request is pending. + /// + /// + bool IsCancelling { get; } + + /// + /// Raised when the cancel state has been reseted + /// + event EventHandler CancelReseted; + + /// + /// Resets the cancel state + /// + void ResetCancel(); + } + + class CancelManager : + ICancelManager + { + private int cancelling; + + public event EventHandler CancelRequested; + + public void Cancel() + { + var value = Interlocked.Increment(ref this.cancelling); + if (value == 0) + { + var eh = this.CancelRequested; + if (eh != null) + eh(this, EventArgs.Empty); + } + } + + public bool IsCancelling + { + get { return this.cancelling > 0; } + } + + /// + /// Raised when the cancel state has been reseted + /// + public event EventHandler CancelReseted; + + /// + /// Resets the cancel state + /// + public void ResetCancel() + { + var value = Interlocked.Exchange(ref this.cancelling, 0); + if (value != 0) + { + var eh = this.CancelReseted; + if (eh != null) + eh(this, EventArgs.Empty); + } + } + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Services/ICancelManager.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Services/ICancelManager.cs.meta new file mode 100644 index 0000000..72975b3 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Services/ICancelManager.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 93563a09f6cc540399bc2adc9258cf06 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Services/IService.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Services/IService.cs new file mode 100755 index 0000000..6d1a768 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Services/IService.cs @@ -0,0 +1,5 @@ +namespace QuickGraph.Algorithms.Services +{ + public interface IService + {} +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Services/IService.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Services/IService.cs.meta new file mode 100644 index 0000000..4170674 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/Services/IService.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 304e4d366974b41c2ac95d18632caa1e +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/ShortestPath.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/ShortestPath.meta new file mode 100644 index 0000000..d6e7ef3 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/ShortestPath.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: 8531232cc5c094baa9507f840b925cd0 +folderAsset: yes +DefaultImporter: + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/ShortestPath/BellmanFordShortestPathAlgorithm.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/ShortestPath/BellmanFordShortestPathAlgorithm.cs new file mode 100755 index 0000000..93a975c --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/ShortestPath/BellmanFordShortestPathAlgorithm.cs @@ -0,0 +1,261 @@ +using System; +using System.Collections.Generic; +using QuickGraph.Algorithms.Services; + +namespace QuickGraph.Algorithms.ShortestPath +{ + /// + /// Bellman Ford shortest path algorithm. + /// + /// + /// + /// The Bellman-Ford algorithm solves the single-source shortest paths + /// problem for a graph with both positive and negative edge weights. + /// + /// + /// If you only need to solve the shortest paths problem for positive + /// edge weights, Dijkstra's algorithm provides a more efficient + /// alternative. + /// + /// + /// If all the edge weights are all equal to one then breadth-first search + /// provides an even more efficient alternative. + /// + /// + /// + public sealed class BellmanFordShortestPathAlgorithm : + ShortestPathAlgorithmBase>, + ITreeBuilderAlgorithm + where TEdge : IEdge + { + private readonly Dictionary predecessors; + private bool foundNegativeCycle; + + public BellmanFordShortestPathAlgorithm( + IVertexAndEdgeListGraph visitedGraph, + IDictionary weights + ) + : this(visitedGraph, weights, new ShortestDistanceRelaxer()) + { } + + public BellmanFordShortestPathAlgorithm( + IVertexAndEdgeListGraph visitedGraph, + IDictionary weights, + IDistanceRelaxer distanceRelaxer + ) + : this(null, visitedGraph, weights, distanceRelaxer) + { } + + public BellmanFordShortestPathAlgorithm( + IAlgorithmComponent host, + IVertexAndEdgeListGraph visitedGraph, + IDictionary weights, + IDistanceRelaxer distanceRelaxer + ) + :base(host, visitedGraph, weights, distanceRelaxer) + { + this.predecessors = new Dictionary(); + } + + public bool FoundNegativeCycle + { + get { return this.foundNegativeCycle;} + } + + /// + /// Invoked on each vertex in the graph before the start of the + /// algorithm. + /// + public event VertexEventHandler InitializeVertex; + + /// + /// Raises the event. + /// + /// vertex that raised the event + private void OnInitializeVertex(TVertex v) + { + if (InitializeVertex != null) + InitializeVertex(this, new VertexEventArgs(v)); + } + + /// + /// Invoked on every edge in the graph |V| times. + /// + public event EdgeEventHandler ExamineEdge; + + /// + /// Raises the event. + /// + /// edge that raised the event + private void OnExamineEdge(TEdge e) + { + if (ExamineEdge != null) + ExamineEdge(this, new EdgeEventArgs(e)); + } + + /// + /// Invoked when the distance label for the target vertex is decreased. + /// The edge that participated in the last relaxation for vertex v is + /// an edge in the shortest paths tree. + /// + public event EdgeEventHandler TreeEdge; + + + /// + /// Raises the event. + /// + /// edge that raised the event + private void OnTreeEdge(TEdge e) + { + if (TreeEdge != null) + TreeEdge(this, new EdgeEventArgs(e)); + } + + /// + /// Invoked if the distance label for the target vertex is not + /// decreased. + /// + public event EdgeEventHandler EdgeNotRelaxed; + + /// + /// Raises the event. + /// + /// edge that raised the event + private void OnEdgeNotRelaxed(TEdge e) + { + if (EdgeNotRelaxed != null) + EdgeNotRelaxed(this, new EdgeEventArgs(e)); + } + + /// + /// Invoked during the second stage of the algorithm, + /// during the test of whether each edge was minimized. + /// + /// If the edge is minimized then this function is invoked. + /// + public event EdgeEventHandler EdgeMinimized; + + + /// + /// Raises the event. + /// + /// edge that raised the event + private void OnEdgeMinimized(TEdge e) + { + if (EdgeMinimized != null) + EdgeMinimized(this, new EdgeEventArgs(e)); + } + + /// + /// Invoked during the second stage of the algorithm, + /// during the test of whether each edge was minimized. + /// + /// If the edge was not minimized, this function is invoked. + /// This happens when there is a negative cycle in the graph. + /// + public event EdgeEventHandler EdgeNotMinimized; + + + /// + /// Raises the event. + /// + /// edge that raised the event + private void OnEdgeNotMinimized(TEdge e) + { + if (EdgeNotMinimized != null) + EdgeNotMinimized(this, new EdgeEventArgs(e)); + } + + /// + /// Constructed predecessor map + /// + public IDictionary Predecessors + { + get + { + return predecessors; + } + } + + private void Initialize() + { + this.foundNegativeCycle = false; + // init color, distance + foreach (var u in VisitedGraph.Vertices) + { + VertexColors[u] = GraphColor.White; + Distances[u] = double.PositiveInfinity; + OnInitializeVertex(u); + } + } + + /// + /// Applies the Bellman Ford algorithm + /// + /// + /// Does not initialize the predecessor and distance map. + /// + /// true if successful, false if there was a negative cycle. + protected override void InternalCompute() + { + this.Initialize(); + + // getting the number of + int N = this.VisitedGraph.VertexCount; + for (int k = 0; k < N; ++k) + { + bool atLeastOneTreeEdge = false; + foreach (var e in this.VisitedGraph.Edges) + { + OnExamineEdge(e); + + if (Relax(e)) + { + atLeastOneTreeEdge = true; + OnTreeEdge(e); + } + else + OnEdgeNotRelaxed(e); + } + if (!atLeastOneTreeEdge) + break; + } + + foreach (var e in VisitedGraph.Edges) + { + if ( + Compare( + Combine( + Distances[e.Source], Weights[e]), + Distances[e.Target] + ) + ) + { + OnEdgeMinimized(e); + this.foundNegativeCycle = true; + return; + } + else + OnEdgeNotMinimized(e); + } + this.foundNegativeCycle = false; + } + + private bool Relax(TEdge e) + { + double du = this.Distances[e.Source]; + double dv = this.Distances[e.Target]; + double we = this.Weights[e]; + + if (Compare(Combine(du, we), dv)) + { + this.Distances[e.Target] = Combine(du, we); + return true; + } + else + return false; + } + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/ShortestPath/BellmanFordShortestPathAlgorithm.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/ShortestPath/BellmanFordShortestPathAlgorithm.cs.meta new file mode 100644 index 0000000..5cf78e6 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/ShortestPath/BellmanFordShortestPathAlgorithm.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: a86f0011a084540a99326f8db8c469eb +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/ShortestPath/CriticalDistanceRelaxer.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/ShortestPath/CriticalDistanceRelaxer.cs new file mode 100755 index 0000000..03e675d --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/ShortestPath/CriticalDistanceRelaxer.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace QuickGraph.Algorithms.ShortestPath +{ + public sealed class CriticalDistanceRelaxer : + IDistanceRelaxer + { + public double InitialDistance + { + get { return double.MinValue; } + } + + public bool Compare(double a, double b) + { + return a > b; + } + + public double Combine(double distance, double weight) + { + return distance + weight; + } + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/ShortestPath/CriticalDistanceRelaxer.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/ShortestPath/CriticalDistanceRelaxer.cs.meta new file mode 100644 index 0000000..8fa4704 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/ShortestPath/CriticalDistanceRelaxer.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: be454f5cf6b6a448aa7c24fb8c5bd8e6 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/ShortestPath/DagShortestPathAlgorithm.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/ShortestPath/DagShortestPathAlgorithm.cs new file mode 100755 index 0000000..33bf131 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/ShortestPath/DagShortestPathAlgorithm.cs @@ -0,0 +1,172 @@ +using System; +using System.Collections.Generic; + +using QuickGraph.Algorithms.Search; +using QuickGraph.Algorithms.Observers; +using QuickGraph.Algorithms.Services; + +namespace QuickGraph.Algorithms.ShortestPath +{ + /// + /// A single-source shortest path algorithm for directed acyclic + /// graph. + /// + /// + /// + /// + [Serializable] + public sealed class DagShortestPathAlgorithm : + ShortestPathAlgorithmBase>, + IVertexColorizerAlgorithm, + ITreeBuilderAlgorithm, + IDistanceRecorderAlgorithm, + IVertexPredecessorRecorderAlgorithm + where TEdge : IEdge + { + public DagShortestPathAlgorithm( + IVertexListGraph g, + IDictionary weights + ) + : this(g, weights, new ShortestDistanceRelaxer()) + { } + + public DagShortestPathAlgorithm( + IVertexListGraph g, + IDictionary weights, + IDistanceRelaxer distanceRelaxer + ) + : this(null, g, weights, distanceRelaxer) + { } + + public DagShortestPathAlgorithm( + IAlgorithmComponent host, + IVertexListGraph g, + IDictionary weights, + IDistanceRelaxer distanceRelaxer + ) + :base(host, g,weights, distanceRelaxer) + {} + + public event VertexEventHandler InitializeVertex; + private void OnInitializeVertex(TVertex v) + { + if (InitializeVertex != null) + InitializeVertex(this, new VertexEventArgs(v)); + } + + public event VertexEventHandler StartVertex; + private void OnStartVertex(TVertex v) + { + VertexEventHandler eh = this.StartVertex; + if (eh!=null) + eh(this, new VertexEventArgs(v)); + } + + public event VertexEventHandler DiscoverVertex; + private void OnDiscoverVertex(TVertex v) + { + if (DiscoverVertex != null) + DiscoverVertex(this, new VertexEventArgs(v)); + } + + public event VertexEventHandler ExamineVertex; + private void OnExamineVertex(TVertex v) + { + if (ExamineVertex != null) + ExamineVertex(this, new VertexEventArgs(v)); + } + + public event EdgeEventHandler ExamineEdge; + private void OnExamineEdge(TEdge e) + { + if (ExamineEdge != null) + ExamineEdge(this, new EdgeEventArgs(e)); + } + + public event EdgeEventHandler TreeEdge; + private void OnTreeEdge(TEdge e) + { + if (TreeEdge != null) + TreeEdge(this, new EdgeEventArgs(e)); + } + + public event EdgeEventHandler EdgeNotRelaxed; + private void OnEdgeNotRelaxed(TEdge e) + { + if (EdgeNotRelaxed != null) + EdgeNotRelaxed(this, new EdgeEventArgs(e)); + } + + public event VertexEventHandler FinishVertex; + private void OnFinishVertex(TVertex v) + { + if (FinishVertex != null) + FinishVertex(this, new VertexEventArgs(v)); + } + + public void Initialize() + { + this.VertexColors.Clear(); + this.Distances.Clear(); + + // init color, distance + var initialDistance = this.DistanceRelaxer.InitialDistance; + foreach (var u in VisitedGraph.Vertices) + { + this.VertexColors.Add(u, GraphColor.White); + this.Distances.Add(u, initialDistance); + this.OnInitializeVertex(u); + } + } + + protected override void InternalCompute() + { + TVertex rootVertex; + if (!this.TryGetRootVertex(out rootVertex)) + throw new InvalidOperationException("RootVertex not initialized"); + + this.Initialize(); + VertexColors[rootVertex] = GraphColor.Gray; + Distances[rootVertex] = 0; + ComputeNoInit(rootVertex); + } + + public void ComputeNoInit(TVertex s) + { + ICollection orderedVertices = AlgoUtility.TopologicalSort(this.VisitedGraph); + + OnDiscoverVertex(s); + foreach (var v in orderedVertices) + { + OnExamineVertex(v); + foreach (var e in VisitedGraph.OutEdges(v)) + { + OnDiscoverVertex(e.Target); + bool decreased = Relax(e); + if (decreased) + OnTreeEdge(e); + else + OnEdgeNotRelaxed(e); + } + OnFinishVertex(v); + } + } + + private bool Relax(TEdge e) + { + double du = this.Distances[e.Source]; + double dv = this.Distances[e.Target]; + double we = this.Weights[e]; + + if (Compare(Combine(du, we), dv)) + { + Distances[e.Target] = Combine(du, we); + return true; + } + else + return false; + } + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/ShortestPath/DagShortestPathAlgorithm.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/ShortestPath/DagShortestPathAlgorithm.cs.meta new file mode 100644 index 0000000..f9a8d82 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/ShortestPath/DagShortestPathAlgorithm.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 6a5aa9be625fd4efaa1849410648105e +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/ShortestPath/DijkstraShortestPathAlgorithm.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/ShortestPath/DijkstraShortestPathAlgorithm.cs new file mode 100755 index 0000000..424ef32 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/ShortestPath/DijkstraShortestPathAlgorithm.cs @@ -0,0 +1,180 @@ +using System; +using System.Collections.Generic; +using QuickGraph.Algorithms.Search; +using QuickGraph.Algorithms.Observers; +using QuickGraph.Collections; +using QuickGraph.Algorithms.Services; + +namespace QuickGraph.Algorithms.ShortestPath +{ + /// + /// A single-source shortest path algorithm for directed graph + /// with positive distance. + /// + /// + /// + /// + [Serializable] + public sealed class DijkstraShortestPathAlgorithm : + ShortestPathAlgorithmBase>, + IVertexColorizerAlgorithm, + IVertexPredecessorRecorderAlgorithm, + IDistanceRecorderAlgorithm + where TEdge : IEdge + { + private PriorityQueue vertexQueue; + + public DijkstraShortestPathAlgorithm( + IVertexListGraph visitedGraph, + IDictionary weights) + : this(visitedGraph, weights, new ShortestDistanceRelaxer()) + { } + + public DijkstraShortestPathAlgorithm( + IVertexListGraph visitedGraph, + IDictionary weights, + IDistanceRelaxer distanceRelaxer + ) + : this(null, visitedGraph, weights, distanceRelaxer) + { } + + public DijkstraShortestPathAlgorithm( + IAlgorithmComponent host, + IVertexListGraph visitedGraph, + IDictionary weights, + IDistanceRelaxer distanceRelaxer + ) + :base(host, visitedGraph,weights, distanceRelaxer) + { } + + public event VertexEventHandler InitializeVertex; + public event VertexEventHandler DiscoverVertex; + public event VertexEventHandler StartVertex; + public event VertexEventHandler ExamineVertex; + public event EdgeEventHandler ExamineEdge; + public event VertexEventHandler FinishVertex; + + public event EdgeEventHandler TreeEdge; + private void OnTreeEdge(TEdge e) + { + if (TreeEdge != null) + TreeEdge(this, new EdgeEventArgs(e)); + } + public event EdgeEventHandler EdgeNotRelaxed; + private void OnEdgeNotRelaxed(TEdge e) + { + if (EdgeNotRelaxed != null) + EdgeNotRelaxed(this, new EdgeEventArgs(e)); + } + + private void InternalExamineEdge(Object sender, EdgeEventArgs args) + { + bool decreased = Relax(args.Edge); + if (decreased) + OnTreeEdge(args.Edge); + else + OnEdgeNotRelaxed(args.Edge); + } + + private void InternalGrayTarget(Object sender, EdgeEventArgs args) + { + bool decreased = Relax(args.Edge); + if (decreased) + { + this.vertexQueue.Update(args.Edge.Target); + OnTreeEdge(args.Edge); + } + else + { + OnEdgeNotRelaxed(args.Edge); + } + } + + public void Initialize() + { + this.VertexColors.Clear(); + this.Distances.Clear(); + // init color, distance + var initialDistance = this.DistanceRelaxer.InitialDistance; + foreach (var u in VisitedGraph.Vertices) + { + this.VertexColors.Add(u, GraphColor.White); + this.Distances.Add(u, initialDistance); + } + } + + protected override void InternalCompute() + { + TVertex rootVertex; + if (!this.TryGetRootVertex(out rootVertex)) + throw new InvalidOperationException("RootVertex not initialized"); + + this.Initialize(); + this.VertexColors[rootVertex] = GraphColor.Gray; + this.Distances[rootVertex] = 0; + ComputeNoInit(rootVertex); + } + + public void ComputeNoInit(TVertex s) + { + this.vertexQueue = new PriorityQueue(this.Distances); + + BreadthFirstSearchAlgorithm bfs = null; + + try + { + bfs = new BreadthFirstSearchAlgorithm( + this, + this.VisitedGraph, + this.vertexQueue, + VertexColors + ); + + bfs.InitializeVertex += this.InitializeVertex; + bfs.DiscoverVertex += this.DiscoverVertex; + bfs.StartVertex += this.StartVertex; + bfs.ExamineEdge += this.ExamineEdge; + bfs.ExamineVertex += this.ExamineVertex; + bfs.FinishVertex += this.FinishVertex; + + bfs.ExamineEdge += new EdgeEventHandler(this.InternalExamineEdge); + bfs.GrayTarget += new EdgeEventHandler(this.InternalGrayTarget); + + bfs.Visit(s); + } + finally + { + if (bfs != null) + { + bfs.InitializeVertex -= this.InitializeVertex; + bfs.DiscoverVertex -= this.DiscoverVertex; + bfs.StartVertex -= this.StartVertex; + bfs.ExamineEdge -= this.ExamineEdge; + bfs.ExamineVertex -= this.ExamineVertex; + bfs.FinishVertex -= this.FinishVertex; + + bfs.ExamineEdge -= new EdgeEventHandler(this.InternalExamineEdge); + bfs.GrayTarget -= new EdgeEventHandler(this.InternalGrayTarget); + } + } + } + + private bool Relax(TEdge e) + { + double du = this.Distances[e.Source]; + double dv = this.Distances[e.Target]; + double we = this.Weights[e]; + + var duwe = Combine(du, we); + if (Compare(duwe, dv)) + { + this.Distances[e.Target] = duwe; + return true; + } + else + return false; + } + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/ShortestPath/DijkstraShortestPathAlgorithm.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/ShortestPath/DijkstraShortestPathAlgorithm.cs.meta new file mode 100644 index 0000000..d1a5620 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/ShortestPath/DijkstraShortestPathAlgorithm.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 6b100c81667fc436f9b853a8a1448dea +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/ShortestPath/IDistanceRelaxer.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/ShortestPath/IDistanceRelaxer.cs new file mode 100755 index 0000000..2d85cbf --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/ShortestPath/IDistanceRelaxer.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace QuickGraph.Algorithms.ShortestPath +{ + public interface IDistanceRelaxer + { + double InitialDistance { get;} + bool Compare(double a, double b); + double Combine(double distance, double weight); + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/ShortestPath/IDistanceRelaxer.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/ShortestPath/IDistanceRelaxer.cs.meta new file mode 100644 index 0000000..646b6ac --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/ShortestPath/IDistanceRelaxer.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 6086e79a0dab64ba495d4a0de8f63133 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/ShortestPath/ShortestDistanceRelaxer.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/ShortestPath/ShortestDistanceRelaxer.cs new file mode 100755 index 0000000..dd3ae6a --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/ShortestPath/ShortestDistanceRelaxer.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace QuickGraph.Algorithms.ShortestPath +{ + public sealed class ShortestDistanceRelaxer : IDistanceRelaxer + { + public double InitialDistance + { + get { return double.MaxValue; } + } + + public bool Compare(double a, double b) + { + return a < b; + } + + public double Combine(double distance, double weight) + { + return distance + weight; + } + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/ShortestPath/ShortestDistanceRelaxer.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/ShortestPath/ShortestDistanceRelaxer.cs.meta new file mode 100644 index 0000000..070bccb --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/ShortestPath/ShortestDistanceRelaxer.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 92f9915f920b94c9a8f493553ea600b1 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/ShortestPath/ShortestPathAlgorithmBase.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/ShortestPath/ShortestPathAlgorithmBase.cs new file mode 100755 index 0000000..530da7b --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/ShortestPath/ShortestPathAlgorithmBase.cs @@ -0,0 +1,106 @@ +using System; +using System.Collections.Generic; +using QuickGraph.Algorithms.Search; +using QuickGraph.Algorithms.Observers; +using QuickGraph.Collections; +using QuickGraph.Algorithms.Services; + +namespace QuickGraph.Algorithms.ShortestPath +{ + [Serializable] + public abstract class ShortestPathAlgorithmBase : + RootedAlgorithmBase + where TEdge : IEdge + { + private readonly IDictionary vertexColors; + private readonly IDictionary distances; + private readonly IDictionary weights; + private readonly IDistanceRelaxer distanceRelaxer; + + protected ShortestPathAlgorithmBase( + IAlgorithmComponent host, + TGraph visitedGraph, + IDictionary weights + ) + :this(host, visitedGraph, weights, new ShortestDistanceRelaxer()) + {} + + protected ShortestPathAlgorithmBase( + IAlgorithmComponent host, + TGraph visitedGraph, + IDictionary weights, + IDistanceRelaxer distanceRelaxer + ) + :base(host, visitedGraph) + { + if (weights == null) + throw new ArgumentNullException("weights"); + if (distanceRelaxer == null) + throw new ArgumentNullException("distanceRelaxer"); + + this.vertexColors = new Dictionary(); + this.distances = new Dictionary(); + this.weights = weights; + this.distanceRelaxer = distanceRelaxer; + } + + public static Dictionary UnaryWeightsFromEdgeList( + IEdgeSet graph) + { + if (graph == null) + throw new ArgumentNullException("graph"); + Dictionary weights = new Dictionary(); + foreach (var e in graph.Edges) + weights.Add(e, 1); + return weights; + } + + public static Dictionary UnaryWeightsFromVertexList( + IVertexListGraph graph) + { + if (graph == null) + throw new ArgumentNullException("graph"); + var weights = new Dictionary(graph.VertexCount * 2); + foreach (var v in graph.Vertices) + foreach (var e in graph.OutEdges(v)) + weights.Add(e, 1); + return weights; + } + + public IDictionary VertexColors + { + get + { + return this.vertexColors; + } + } + + public IDictionary Distances + { + get + { + return this.distances; + } + } + + public IDictionary Weights + { + get { return this.weights; } + } + + public IDistanceRelaxer DistanceRelaxer + { + get { return this.distanceRelaxer; } + } + + protected bool Compare(double a, double b) + { + return this.distanceRelaxer.Compare(a, b); + } + + protected double Combine(double distance, double weight) + { + return this.distanceRelaxer.Combine(distance, weight); + } + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/ShortestPath/ShortestPathAlgorithmBase.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/ShortestPath/ShortestPathAlgorithmBase.cs.meta new file mode 100644 index 0000000..51718be --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/ShortestPath/ShortestPathAlgorithmBase.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b985078fdf0e54800bf4aa68e986b9ef +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/ShortestPath/UndirectedDijkstraShortestPathAlgorithm.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/ShortestPath/UndirectedDijkstraShortestPathAlgorithm.cs new file mode 100755 index 0000000..b909344 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/ShortestPath/UndirectedDijkstraShortestPathAlgorithm.cs @@ -0,0 +1,169 @@ +using System; +using System.Collections.Generic; +using QuickGraph.Algorithms.Search; +using QuickGraph.Algorithms.Observers; +using QuickGraph.Collections; +using QuickGraph.Algorithms.Services; + +namespace QuickGraph.Algorithms.ShortestPath +{ + /// + /// A single-source shortest path algorithm for undirected graph + /// with positive distance. + /// + /// + [Serializable] + public sealed class UndirectedDijkstraShortestPathAlgorithm : + ShortestPathAlgorithmBase>, + IVertexColorizerAlgorithm, + IVertexPredecessorRecorderAlgorithm, + IDistanceRecorderAlgorithm + where TEdge : IEdge + { + private PriorityQueue vertexQueue; + + public UndirectedDijkstraShortestPathAlgorithm( + IUndirectedGraph visitedGraph, + IDictionary weights, + IDistanceRelaxer distanceRelaxer + ) + : this(null, visitedGraph, weights, distanceRelaxer) + { } + + public UndirectedDijkstraShortestPathAlgorithm( + IAlgorithmComponent host, + IUndirectedGraph visitedGraph, + IDictionary weights, + IDistanceRelaxer distanceRelaxer + ) + : base(host, visitedGraph, weights, distanceRelaxer) + { } + + public event VertexEventHandler InitializeVertex; + public event VertexEventHandler StartVertex; + public event VertexEventHandler DiscoverVertex; + public event VertexEventHandler ExamineVertex; + public event EdgeEventHandler ExamineEdge; + public event VertexEventHandler FinishVertex; + + public event EdgeEventHandler TreeEdge; + private void OnTreeEdge(TEdge e) + { + if (TreeEdge != null) + TreeEdge(this, new EdgeEventArgs(e)); + } + public event EdgeEventHandler EdgeNotRelaxed; + private void OnEdgeNotRelaxed(TEdge e) + { + if (EdgeNotRelaxed != null) + EdgeNotRelaxed(this, new EdgeEventArgs(e)); + } + + private void InternalTreeEdge(Object sender, EdgeEventArgs args) + { + bool decreased = Relax(args.Edge); + if (decreased) + OnTreeEdge(args.Edge); + else + OnEdgeNotRelaxed(args.Edge); + } + + private void InternalGrayTarget(Object sender, EdgeEventArgs args) + { + bool decreased = Relax(args.Edge); + if (decreased) + { + this.vertexQueue.Update(args.Edge.Target); + OnTreeEdge(args.Edge); + } + else + { + OnEdgeNotRelaxed(args.Edge); + } + } + + public void Initialize() + { + this.VertexColors.Clear(); + this.Distances.Clear(); + // init color, distance + foreach (var u in VisitedGraph.Vertices) + { + this.VertexColors.Add(u, GraphColor.White); + this.Distances.Add(u, double.MaxValue); + } + } + + protected override void InternalCompute() + { + TVertex rootVertex; + if (!this.TryGetRootVertex(out rootVertex)) + throw new InvalidOperationException("RootVertex not initialized"); + + this.Initialize(); + this.VertexColors[rootVertex] = GraphColor.Gray; + this.Distances[rootVertex] = 0; + ComputeNoInit(rootVertex); + } + + public void ComputeNoInit(TVertex s) + { + this.vertexQueue = new PriorityQueue(this.Distances); + UndirectedBreadthFirstSearchAlgorithm bfs = null; + + try + { + bfs = new UndirectedBreadthFirstSearchAlgorithm( + this, + this.VisitedGraph, + this.vertexQueue, + VertexColors + ); + + bfs.InitializeVertex += this.InitializeVertex; + bfs.DiscoverVertex += this.DiscoverVertex; + bfs.StartVertex += this.StartVertex; + bfs.ExamineEdge += this.ExamineEdge; + bfs.ExamineVertex += this.ExamineVertex; + bfs.FinishVertex += this.FinishVertex; + + bfs.TreeEdge += new EdgeEventHandler(this.InternalTreeEdge); + bfs.GrayTarget += new EdgeEventHandler(this.InternalGrayTarget); + + bfs.Visit(s); + } + finally + { + if (bfs != null) + { + bfs.InitializeVertex -= this.InitializeVertex; + bfs.DiscoverVertex -= this.DiscoverVertex; + bfs.StartVertex -= this.StartVertex; + bfs.ExamineEdge -= this.ExamineEdge; + bfs.ExamineVertex -= this.ExamineVertex; + bfs.FinishVertex -= this.FinishVertex; + + bfs.TreeEdge -= new EdgeEventHandler(this.InternalTreeEdge); + bfs.GrayTarget -= new EdgeEventHandler(this.InternalGrayTarget); + } + } + } + + private bool Relax(TEdge e) + { + double du = this.Distances[e.Source]; + double dv = this.Distances[e.Target]; + double we = this.Weights[e]; + + if (Compare(Combine(du, we), dv)) + { + this.Distances[e.Target] = Combine(du, we); + return true; + } + else + return false; + } + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/ShortestPath/UndirectedDijkstraShortestPathAlgorithm.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/ShortestPath/UndirectedDijkstraShortestPathAlgorithm.cs.meta new file mode 100644 index 0000000..d324046 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/ShortestPath/UndirectedDijkstraShortestPathAlgorithm.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: fa738fc0006474037b648717509e29f0 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/SourceFirstTopologicalSortAlgorithm.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/SourceFirstTopologicalSortAlgorithm.cs new file mode 100755 index 0000000..40db589 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/SourceFirstTopologicalSortAlgorithm.cs @@ -0,0 +1,111 @@ +using System; +using System.Collections.Generic; + +using QuickGraph.Collections; + +namespace QuickGraph.Algorithms +{ + [Serializable] + public sealed class SourceFirstTopologicalSortAlgorithm : + AlgorithmBase> + where TEdge : IEdge + { + private IDictionary inDegrees = new Dictionary(); + private PriorityQueue heap; + private IList sortedVertices = new List(); + + public SourceFirstTopologicalSortAlgorithm( + IVertexAndEdgeListGraph visitedGraph + ) + :base(visitedGraph) + { + this.heap = new PriorityQueue(this.inDegrees); + } + + public ICollection SortedVertices + { + get + { + return this.sortedVertices; + } + } + + public PriorityQueue Heap + { + get + { + return this.heap; + } + } + + public IDictionary InDegrees + { + get + { + return this.inDegrees; + } + } + + public event VertexEventHandler AddVertex; + private void OnAddVertex(TVertex v) + { + if (this.AddVertex != null) + this.AddVertex(this, new VertexEventArgs(v)); + } + + public void Compute(IList vertices) + { + if (vertices == null) + throw new ArgumentNullException("vertices"); + this.sortedVertices = vertices; + Compute(); + } + + + protected override void InternalCompute() + { + var cancelManager = this.Services.CancelManager; + this.InitializeInDegrees(); + + while (this.heap.Count != 0) + { + if (cancelManager.IsCancelling) break; + + TVertex v = this.heap.Dequeue(); + if (this.inDegrees[v] != 0) + throw new NonAcyclicGraphException(); + + this.sortedVertices.Add(v); + this.OnAddVertex(v); + + // update the count of it's adjacent vertices + foreach (var e in this.VisitedGraph.OutEdges(v)) + { + if (e.Source.Equals(e.Target)) + continue; + + this.inDegrees[e.Target]--; + if (this.inDegrees[e.Target] < 0) + throw new InvalidOperationException("InDegree is negative, and cannot be"); + this.heap.Update(e.Target); + } + } + } + + private void InitializeInDegrees() + { + foreach (var v in this.VisitedGraph.Vertices) + { + this.inDegrees.Add(v, 0); + this.heap.Enqueue(v); + } + + foreach (var e in this.VisitedGraph.Edges) + { + if (e.Source.Equals(e.Target)) + continue; + this.inDegrees[e.Target]++; + } + } + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/SourceFirstTopologicalSortAlgorithm.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/SourceFirstTopologicalSortAlgorithm.cs.meta new file mode 100644 index 0000000..f095ecc --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/SourceFirstTopologicalSortAlgorithm.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 56eb53e40c8064e55999b2655087cc2a +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/StronglyConnectedComponentAlgorithm.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/StronglyConnectedComponentAlgorithm.cs new file mode 100755 index 0000000..3cdd264 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/StronglyConnectedComponentAlgorithm.cs @@ -0,0 +1,158 @@ +using System; +using System.Collections.Generic; + +using QuickGraph.Algorithms.Search; +using QuickGraph.Algorithms.Services; + +namespace QuickGraph.Algorithms +{ + [Serializable] + public sealed class StronglyConnectedComponentsAlgorithm : + AlgorithmBase>, + IConnectedComponentAlgorithm> + where TEdge : IEdge + { + private IDictionary components; + private IDictionary discoverTimes; + private IDictionary roots; + private Stack stack; + int componentCount; + int dfsTime; + + public StronglyConnectedComponentsAlgorithm( + IVertexListGraph g) + :this(g, new Dictionary()) + {} + + public StronglyConnectedComponentsAlgorithm( + IVertexListGraph g, + IDictionary components) + : this(null, g, components) + { } + + public StronglyConnectedComponentsAlgorithm( + IAlgorithmComponent host, + IVertexListGraph g, + IDictionary components) + :base(host, g) + { + if (components==null) + throw new ArgumentNullException("components"); + + this.components = components; + this.roots = new Dictionary(); + this.discoverTimes = new Dictionary(); + this.stack = new Stack(); + this.componentCount = 0; + this.dfsTime = 0; + } + + public IDictionary Components + { + get + { + return this.components; + } + } + + public IDictionary Roots + { + get + { + return this.roots; + } + } + + public IDictionary DiscoverTimes + { + get + { + return this.discoverTimes; + } + } + + public int ComponentCount + { + get + { + return this.componentCount; + } + } + + private void DiscoverVertex(Object sender, VertexEventArgs args) + { + TVertex v = args.Vertex; + this.Roots[v]=v; + this.Components[v]=int.MaxValue; + this.DiscoverTimes[v]=dfsTime++; + this.stack.Push(v); + } + + /// + /// Used internally + /// + /// + /// + private void FinishVertex(Object sender, VertexEventArgs args) + { + TVertex v = args.Vertex; + foreach(TEdge e in VisitedGraph.OutEdges(v)) + { + TVertex w = e.Target; + if (this.Components[w] == int.MaxValue) + this.Roots[v]=MinDiscoverTime(this.Roots[v], this.Roots[w]); + } + + if (Roots[v].Equals(v)) + { + TVertex w=default(TVertex); + do + { + w = this.stack.Pop(); + this.Components[w]=componentCount; + } + while (!w.Equals(v)); + ++componentCount; + } + } + + private TVertex MinDiscoverTime(TVertex u, TVertex v) + { + if (this.DiscoverTimes[u] dfs = null; + try + { + dfs = new DepthFirstSearchAlgorithm( + this, + VisitedGraph, + new Dictionary(this.VisitedGraph.VertexCount) + ); + dfs.DiscoverVertex += new VertexEventHandler(this.DiscoverVertex); + dfs.FinishVertex += new VertexEventHandler(this.FinishVertex); + + dfs.Compute(); + } + finally + { + if (dfs != null) + { + dfs.DiscoverVertex -= new VertexEventHandler(this.DiscoverVertex); + dfs.FinishVertex -= new VertexEventHandler(this.FinishVertex); + } + } + } + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/StronglyConnectedComponentAlgorithm.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/StronglyConnectedComponentAlgorithm.cs.meta new file mode 100644 index 0000000..645c37f --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/StronglyConnectedComponentAlgorithm.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e8a2ab939a215468eb517077a0987fb1 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/TopologicalSortAlgorithm.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/TopologicalSortAlgorithm.cs new file mode 100755 index 0000000..40da7a8 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/TopologicalSortAlgorithm.cs @@ -0,0 +1,87 @@ +using System; +using System.Collections.Generic; + +using QuickGraph.Algorithms.Search; + +namespace QuickGraph.Algorithms +{ + [Serializable] + public sealed class TopologicalSortAlgorithm : + AlgorithmBase> + where TEdge : IEdge + { + private IList vertices = new List(); + private bool allowCyclicGraph = false; + + public TopologicalSortAlgorithm(IVertexListGraph g) + :this(g, new List()) + {} + + public TopologicalSortAlgorithm( + IVertexListGraph g, + IList vertices) + :base(g) + { + if (vertices == null) + throw new ArgumentNullException("vertices"); + + this.vertices = vertices; + } + + public IList SortedVertices + { + get + { + return vertices; + } + } + + public bool AllowCyclicGraph + { + get { return this.allowCyclicGraph; } + } + + private void BackEdge(Object sender, EdgeEventArgs args) + { + if (!this.AllowCyclicGraph) + throw new NonAcyclicGraphException(); + } + + private void FinishVertex(Object sender, VertexEventArgs args) + { + vertices.Insert(0, args.Vertex); + } + + protected override void InternalCompute() + { + DepthFirstSearchAlgorithm dfs = null; + try + { + dfs = new DepthFirstSearchAlgorithm( + this, + this.VisitedGraph, + new Dictionary(this.VisitedGraph.VertexCount) + ); + dfs.BackEdge += new EdgeEventHandler(this.BackEdge); + dfs.FinishVertex += new VertexEventHandler(this.FinishVertex); + + dfs.Compute(); + } + finally + { + if (dfs != null) + { + dfs.BackEdge -= new EdgeEventHandler(this.BackEdge); + dfs.FinishVertex -= new VertexEventHandler(this.FinishVertex); + } + } + } + + public void Compute(IList vertices) + { + this.vertices = vertices; + this.vertices.Clear(); + this.Compute(); + } + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/TopologicalSortAlgorithm.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/TopologicalSortAlgorithm.cs.meta new file mode 100644 index 0000000..46c93ad --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/TopologicalSortAlgorithm.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 142b010b546f54ba79dd80fb7f79426e +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/UndirectedFirstTopologicalSortAlgorithm.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/UndirectedFirstTopologicalSortAlgorithm.cs new file mode 100755 index 0000000..689b79a --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/UndirectedFirstTopologicalSortAlgorithm.cs @@ -0,0 +1,113 @@ +using System; +using System.Collections.Generic; + +using QuickGraph.Collections; + +namespace QuickGraph.Algorithms +{ + [Serializable] + public sealed class UndirectedFirstTopologicalSortAlgorithm : + AlgorithmBase> + where TEdge : IEdge + { + private IDictionary degrees = new Dictionary(); + private PriorityQueue heap; + private IList sortedVertices = new List(); + private bool allowCyclicGraph = false; + + public UndirectedFirstTopologicalSortAlgorithm( + IUndirectedGraph visitedGraph + ) + : base(visitedGraph) + { + this.heap = new PriorityQueue(this.degrees); + } + + public ICollection SortedVertices + { + get + { + return this.sortedVertices; + } + } + + public PriorityQueue Heap + { + get + { + return this.heap; + } + } + + public IDictionary Degrees + { + get + { + return this.degrees; + } + } + + + public bool AllowCyclicGraph + { + get { return this.allowCyclicGraph; } + set { this.allowCyclicGraph = value; } + } + + public event VertexEventHandler AddVertex; + private void OnAddVertex(TVertex v) + { + if (this.AddVertex != null) + this.AddVertex(this, new VertexEventArgs(v)); + } + + public void Compute(IList vertices) + { + if (vertices == null) + throw new ArgumentNullException("vertices"); + this.sortedVertices = vertices; + Compute(); + } + + + protected override void InternalCompute() + { + this.InitializeInDegrees(); + var cancelManager = this.Services.CancelManager; + + while (this.heap.Count != 0) + { + if (cancelManager.IsCancelling) return; + + TVertex v = this.heap.Dequeue(); + if (this.degrees[v] != 0 && !this.AllowCyclicGraph) + throw new NonAcyclicGraphException(); + + this.sortedVertices.Add(v); + this.OnAddVertex(v); + + // update the count of it's adjacent vertices + foreach (var e in this.VisitedGraph.AdjacentEdges(v)) + { + if (e.Source.Equals(e.Target)) + continue; + + this.degrees[e.Target]--; + if (this.degrees[e.Target] < 0 && !this.AllowCyclicGraph) + throw new InvalidOperationException("Degree is negative, and cannot be"); + if (this.heap.Contains(e.Target)) + this.heap.Update(e.Target); + } + } + } + + private void InitializeInDegrees() + { + foreach (var v in this.VisitedGraph.Vertices) + { + this.degrees.Add(v, this.VisitedGraph.AdjacentDegree(v)); + this.heap.Enqueue(v); + } + } + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/UndirectedFirstTopologicalSortAlgorithm.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/UndirectedFirstTopologicalSortAlgorithm.cs.meta new file mode 100644 index 0000000..90c6ed6 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/UndirectedFirstTopologicalSortAlgorithm.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: a1988ee62705c48fab563bc866cd3efb +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/UndirectedTopologicalSortAlgorithm.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/UndirectedTopologicalSortAlgorithm.cs new file mode 100755 index 0000000..6e72e6b --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/UndirectedTopologicalSortAlgorithm.cs @@ -0,0 +1,88 @@ +using System; +using System.Collections.Generic; + +using QuickGraph.Algorithms.Search; + +namespace QuickGraph.Algorithms +{ + [Serializable] + public sealed class UndirectedTopologicalSortAlgorithm : + AlgorithmBase> + where TEdge : IEdge + { + private IList vertices; + private bool allowCyclicGraph = false; + + public UndirectedTopologicalSortAlgorithm(IUndirectedGraph g) + : this(g, new List()) + { } + + public UndirectedTopologicalSortAlgorithm( + IUndirectedGraph g, + IList vertices) + : base(g) + { + if (vertices == null) + throw new ArgumentNullException("vertices"); + + this.vertices = vertices; + } + + public IList SortedVertices + { + get + { + return vertices; + } + } + + public bool AllowCyclicGraph + { + get { return this.allowCyclicGraph; } + set { this.allowCyclicGraph = value; } + } + + private void BackEdge(Object sender, EdgeEventArgs args) + { + if (!this.AllowCyclicGraph) + throw new NonAcyclicGraphException(); + } + + private void FinishVertex(Object sender, VertexEventArgs args) + { + vertices.Insert(0, args.Vertex); + } + + protected override void InternalCompute() + { + UndirectedDepthFirstSearchAlgorithm dfs = null; + try + { + dfs = new UndirectedDepthFirstSearchAlgorithm( + this, + VisitedGraph, + new Dictionary(this.VisitedGraph.VertexCount) + ); + dfs.BackEdge += new EdgeEventHandler(this.BackEdge); + dfs.FinishVertex += new VertexEventHandler(this.FinishVertex); + + dfs.Compute(); + } + finally + { + if (dfs != null) + { + dfs.BackEdge -= new EdgeEventHandler(this.BackEdge); + dfs.FinishVertex -= new VertexEventHandler(this.FinishVertex); + } + } + } + + public void Compute(IList vertices) + { + this.vertices = vertices; + this.vertices.Clear(); + this.Compute(); + } + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/UndirectedTopologicalSortAlgorithm.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/UndirectedTopologicalSortAlgorithm.cs.meta new file mode 100644 index 0000000..edaadd1 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/UndirectedTopologicalSortAlgorithm.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 991d3d3c990234bd695e6b7042604f06 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/VertexAdjacencyMatrixBuilderAlgorithm.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/VertexAdjacencyMatrixBuilderAlgorithm.cs new file mode 100755 index 0000000..0ecd17c --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/VertexAdjacencyMatrixBuilderAlgorithm.cs @@ -0,0 +1,58 @@ +using System; +using System.Collections.Generic; +using System.Text; +using QuickGraph.Algorithms.Matrix; + +namespace QuickGraph.Algorithms +{ + public sealed class VertexAdjacencyMatrixBuilderAlgorithm : + AlgorithmBase> + where TEdge : IEdge + { + private DoubleDenseMatrix matrix; + private Dictionary vertexIndices; + + public VertexAdjacencyMatrixBuilderAlgorithm(IVertexListGraph visitedGraph) + :base(visitedGraph) + { + } + + public DoubleDenseMatrix Matrix + { + get { return this.matrix; } + } + + public Dictionary VertexIndices + { + get { return this.vertexIndices; } + } + + protected override void InternalCompute() + { + var cancelManager = this.Services.CancelManager; + this.matrix = new DoubleDenseMatrix(this.VisitedGraph.VertexCount, this.VisitedGraph.VertexCount); + this.vertexIndices = new Dictionary(this.VisitedGraph.VertexCount); + + int index = 0; + foreach (var v in this.VisitedGraph.Vertices) + { + if (cancelManager.IsCancelling) break; + + this.vertexIndices.Add(v, index++); + } + + foreach (var v in this.VisitedGraph.Vertices) + { + if (cancelManager.IsCancelling) break; + + int source = this.VertexIndices[v]; + foreach (var edge in this.VisitedGraph.OutEdges(v)) + { + int target = this.VertexIndices[edge.Target]; + + matrix[source, target] = 1; + } + } + } + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/VertexAdjacencyMatrixBuilderAlgorithm.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/VertexAdjacencyMatrixBuilderAlgorithm.cs.meta new file mode 100644 index 0000000..cda4415 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/VertexAdjacencyMatrixBuilderAlgorithm.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ae8d3406f51cc40d3a6900e69f9e6f0c +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/WeaklyConnectedComponentsAlgorithm.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/WeaklyConnectedComponentsAlgorithm.cs new file mode 100755 index 0000000..0054015 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/WeaklyConnectedComponentsAlgorithm.cs @@ -0,0 +1,102 @@ +using System; +using System.Collections.Generic; +using QuickGraph.Algorithms.Search; +using QuickGraph.Algorithms.Observers; +using QuickGraph.Algorithms.Services; + +namespace QuickGraph.Algorithms +{ + [Serializable] + public sealed class WeaklyConnectedComponentsAlgorithm : + AlgorithmBase>, + IConnectedComponentAlgorithm> + where TEdge : IEdge + { + private readonly IDictionary components; + private readonly Dictionary componentEquivalences = new Dictionary(); + private readonly DepthFirstSearchAlgorithm dfs; + private int componentCount = 0; + private int currentComponent = 0; + + public WeaklyConnectedComponentsAlgorithm(IVertexListGraph visitedGraph) + : this(visitedGraph, new Dictionary()) + { } + + public WeaklyConnectedComponentsAlgorithm( + IVertexListGraph visitedGraph, + IDictionary components) + : this(null, visitedGraph, components) + { } + + public WeaklyConnectedComponentsAlgorithm( + IAlgorithmComponent host, + IVertexListGraph visitedGraph, + IDictionary components) + : base(host, visitedGraph) + { + if (components == null) + throw new ArgumentNullException("components"); + this.components = components; + + this.dfs = new DepthFirstSearchAlgorithm(this.VisitedGraph); + this.dfs.StartVertex += new VertexEventHandler(dfs_StartVertex); + this.dfs.TreeEdge += new EdgeEventHandler(dfs_TreeEdge); + this.dfs.ForwardOrCrossEdge += new EdgeEventHandler(dfs_ForwardOrCrossEdge); + } + + public IDictionary Components + { + get { return this.components; } + } + + public int ComponentCount + { + get { return this.componentCount; } + } + + protected override void InternalCompute() + { + this.componentCount = 0; + this.currentComponent = 0; + this.componentEquivalences.Clear(); + this.components.Clear(); + this.dfs.Compute(); + + // updating component numbers + foreach (var v in this.VisitedGraph.Vertices) + { + int component = this.Components[v]; + int equivalent = this.componentEquivalences[component]; + if (component!=equivalent) + this.Components[v] =equivalent; + } + } + + void dfs_StartVertex(object sender, VertexEventArgs e) + { + // we are looking on a new tree + this.currentComponent = this.componentEquivalences.Count; + this.componentEquivalences.Add(this.currentComponent, this.currentComponent); + this.componentCount++; + this.components.Add(e.Vertex, this.currentComponent); + } + + void dfs_TreeEdge(object sender, EdgeEventArgs e) + { + // new edge, we store with the current component number + this.components.Add(e.Edge.Target, this.currentComponent); + } + + void dfs_ForwardOrCrossEdge(object sender, EdgeEventArgs e) + { + // we have touched another tree, updating count and current component + int otherComponent = this.componentEquivalences[this.components[e.Edge.Target]]; + if (otherComponent != this.currentComponent) + { + this.componentCount--; + this.componentEquivalences[this.currentComponent] = otherComponent; + this.currentComponent = otherComponent; + } + } + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/WeaklyConnectedComponentsAlgorithm.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/WeaklyConnectedComponentsAlgorithm.cs.meta new file mode 100644 index 0000000..b3fdc6c --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/WeaklyConnectedComponentsAlgorithm.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 59244c5d4d758437e98bfdca5dcc60b2 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/matrixsizemistmatchexception.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/matrixsizemistmatchexception.cs new file mode 100755 index 0000000..e8855d4 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/matrixsizemistmatchexception.cs @@ -0,0 +1,24 @@ +using System; +using QuickGraph.Algorithms.Matrix; + +namespace QuickGraph.Algorithms +{ + [Serializable] + public class MatrixSizeMistmatchException : ApplicationException + { + public MatrixSizeMistmatchException( + DoubleDenseMatrix left, + DoubleDenseMatrix right) + :this(String.Format("Matrix size ({0}x{1}) does not match ({2}x{3})", + left.RowCount,left.ColumnCount,right.RowCount, right.ColumnCount)) + { + } + public MatrixSizeMistmatchException() { } + public MatrixSizeMistmatchException(string message) : base(message) { } + public MatrixSizeMistmatchException(string message, Exception inner) : base(message, inner) { } + protected MatrixSizeMistmatchException( + System.Runtime.Serialization.SerializationInfo info, + System.Runtime.Serialization.StreamingContext context) + : base(info, context) { } + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/matrixsizemistmatchexception.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/matrixsizemistmatchexception.cs.meta new file mode 100644 index 0000000..5feff54 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Algorithms/matrixsizemistmatchexception.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 33a6ddd40300e47ad8dc70b99ecc407e +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/BidirectionalGraph.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/BidirectionalGraph.cs new file mode 100755 index 0000000..33856a0 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/BidirectionalGraph.cs @@ -0,0 +1,628 @@ +using System; +using System.Collections.Generic; +using System.Runtime.Serialization; + +namespace QuickGraph +{ + [Serializable] + public class BidirectionalGraph : + IVertexAndEdgeListGraph, + IEdgeListAndIncidenceGraph, + IMutableEdgeListGraph, + IMutableIncidenceGraph, + IMutableVertexListGraph, + IBidirectionalGraph, + IMutableBidirectionalGraph, + IMutableVertexAndEdgeListGraph, + ICloneable + where TEdge : IEdge + { + private readonly bool isDirected = true; + private readonly bool allowParallelEdges; + private readonly VertexEdgeDictionary vertexOutEdges + = new VertexEdgeDictionary(); + private readonly VertexEdgeDictionary vertexInEdges + = new VertexEdgeDictionary(); + private int edgeCount = 0; + private int edgeCapacity = -1; + + public BidirectionalGraph() + :this(true) + {} + + public BidirectionalGraph(bool allowParallelEdges) + :this(allowParallelEdges,-1) + {} + + public BidirectionalGraph(bool allowParallelEdges, int vertexCapacity) + { + this.allowParallelEdges = allowParallelEdges; + if (vertexCapacity > -1) + { + this.vertexInEdges = new VertexEdgeDictionary(vertexCapacity); + this.vertexOutEdges = new VertexEdgeDictionary(vertexCapacity); + } + else + { + this.vertexInEdges = new VertexEdgeDictionary(); + this.vertexOutEdges = new VertexEdgeDictionary(); + } + } + + public static Type VertexType + { + get { return typeof(TVertex); } + } + + public static Type EdgeType + { + get { return typeof(TEdge); } + } + + public int EdgeCapacity + { + get { return this.edgeCapacity; } + set { this.edgeCapacity = value; } + } + + public bool IsDirected + { + get { return this.isDirected; } + } + + public bool AllowParallelEdges + { + get { return this.allowParallelEdges; } + } + + public bool IsVerticesEmpty + { + get { return this.vertexOutEdges.Count == 0; } + } + + public int VertexCount + { + get { return this.vertexOutEdges.Count; } + } + + public IEnumerable Vertices + { + get { return this.vertexOutEdges.Keys; } + } + + public bool ContainsVertex(TVertex v) + { + GraphContracts.AssumeNotNull(v, "v"); + return this.vertexOutEdges.ContainsKey(v); + } + + public bool IsOutEdgesEmpty(TVertex v) + { + GraphContracts.AssumeInVertexSet(this, v, "v"); + return this.vertexOutEdges[v].Count == 0; + } + + public int OutDegree(TVertex v) + { + GraphContracts.AssumeInVertexSet(this, v, "v"); + return this.vertexOutEdges[v].Count; + } + + public IEnumerable OutEdges(TVertex v) + { + GraphContracts.AssumeInVertexSet(this, v, "v"); + return this.vertexOutEdges[v]; + } + + public TEdge OutEdge(TVertex v, int index) + { + GraphContracts.AssumeInVertexSet(this, v, "v"); + return this.vertexOutEdges[v][index]; + } + + public bool IsInEdgesEmpty(TVertex v) + { + GraphContracts.AssumeInVertexSet(this, v, "v"); + return this.vertexInEdges[v].Count == 0; + } + + public int InDegree(TVertex v) + { + GraphContracts.AssumeInVertexSet(this, v, "v"); + return this.vertexInEdges[v].Count; + } + + public IEnumerable InEdges(TVertex v) + { + GraphContracts.AssumeInVertexSet(this, v, "v"); + return this.vertexInEdges[v]; + } + + public TEdge InEdge(TVertex v, int index) + { + GraphContracts.AssumeInVertexSet(this, v, "v"); + return this.vertexInEdges[v][index]; + } + + public int Degree(TVertex v) + { + GraphContracts.AssumeInVertexSet(this, v, "v"); + return this.OutDegree(v) + this.InDegree(v); + } + + public bool IsEdgesEmpty + { + get { return this.edgeCount == 0; } + } + + public int EdgeCount + { + get + { + GraphContracts.Assert(this.edgeCount >= 0); + return this.edgeCount; + } + } + + public IEnumerable Edges + { + get + { + foreach (EdgeList edges in this.vertexOutEdges.Values) + foreach (var edge in edges) + yield return edge; + } + } + + public bool ContainsEdge(TVertex source, TVertex target) + { + GraphContracts.AssumeInVertexSet(this, source, "source"); + GraphContracts.AssumeInVertexSet(this, target, "target"); + foreach (var outEdge in this.OutEdges(source)) + if (outEdge.Target.Equals(target)) + return true; + return false; + } + + public bool TryGetEdge( + TVertex source, + TVertex target, + out TEdge edge) + { + GraphContracts.AssumeInVertexSet(this, source, "source"); + GraphContracts.AssumeInVertexSet(this, target, "target"); + + EdgeList edgeList; + if (this.vertexOutEdges.TryGetValue(source, out edgeList) && + edgeList.Count > 0) + { + foreach (var e in edgeList) + { + if (e.Target.Equals(target)) + { + edge = e; + return true; + } + } + } + edge = default(TEdge); + return false; + } + + public bool TryGetEdges( + TVertex source, + TVertex target, + out IEnumerable edges) + { + GraphContracts.AssumeInVertexSet(this, source, "source"); + GraphContracts.AssumeInVertexSet(this, target, "target"); + + EdgeList edgeList; + if (this.vertexOutEdges.TryGetValue(source, out edgeList)) + { + List list = new List(edgeList.Count); + foreach (var edge in edgeList) + if (edge.Target.Equals(target)) + list.Add(edge); + edges = list; + return true; + } + else + { + edges = null; + return false; + } + } + + public bool ContainsEdge(TEdge edge) + { + GraphContracts.AssumeInVertexSet(this, edge, "edge"); + return this.vertexOutEdges[edge.Source].Contains(edge); + } + + public virtual void AddVertex(TVertex v) + { + GraphContracts.AssumeNotInVertexSet(this, v, "v"); + + if (this.EdgeCapacity > 0) + { + this.vertexOutEdges.Add(v, new EdgeList(this.EdgeCapacity)); + this.vertexInEdges.Add(v, new EdgeList(this.EdgeCapacity)); + } + else + { + this.vertexOutEdges.Add(v, new EdgeList()); + this.vertexInEdges.Add(v, new EdgeList()); + } + this.OnVertexAdded(new VertexEventArgs(v)); + } + + public virtual void AddVertexRange(IEnumerable vertices) + { + GraphContracts.AssumeNotNull(vertices, "vertices"); + foreach (var v in vertices) + this.AddVertex(v); + } + + public event VertexEventHandler VertexAdded; + protected virtual void OnVertexAdded(VertexEventArgs args) + { + VertexEventHandler eh = this.VertexAdded; + if (eh != null) + eh(this, args); + } + + public virtual bool RemoveVertex(TVertex v) + { + GraphContracts.AssumeNotNull(v, "v"); + if (!this.ContainsVertex(v)) + return false; + + // collect edges to remove + EdgeList edgesToRemove = new EdgeList(); + foreach (var outEdge in this.OutEdges(v)) + { + this.vertexInEdges[outEdge.Target].Remove(outEdge); + edgesToRemove.Add(outEdge); + } + foreach (var inEdge in this.InEdges(v)) + { + // might already have been removed + if(this.vertexOutEdges[inEdge.Source].Remove(inEdge)) + edgesToRemove.Add(inEdge); + } + + // notify users + if (this.EdgeRemoved != null) + { + foreach(TEdge edge in edgesToRemove) + this.OnEdgeRemoved(new EdgeEventArgs(edge)); + } + + this.vertexOutEdges.Remove(v); + this.vertexInEdges.Remove(v); + this.edgeCount -= edgesToRemove.Count; + this.OnVertexRemoved(new VertexEventArgs(v)); + + GraphContracts.Assert(this.edgeCount >= 0); + return true; + } + + public event VertexEventHandler VertexRemoved; + protected virtual void OnVertexRemoved(VertexEventArgs args) + { + VertexEventHandler eh = this.VertexRemoved; + if (eh != null) + eh(this, args); + } + + public int RemoveVertexIf(VertexPredicate predicate) + { + GraphContracts.AssumeNotNull(predicate, "predicate"); + + VertexList vertices = new VertexList(); + foreach (var v in this.Vertices) + if (predicate(v)) + vertices.Add(v); + + foreach (var v in vertices) + this.RemoveVertex(v); + return vertices.Count; + } + + public virtual bool AddEdge(TEdge e) + { + GraphContracts.AssumeInVertexSet(this, e, "e"); + if (!this.AllowParallelEdges) + { + if (this.ContainsEdge(e.Source, e.Target)) + return false; + } + this.vertexOutEdges[e.Source].Add(e); + this.vertexInEdges[e.Target].Add(e); + this.edgeCount++; + + this.OnEdgeAdded(new EdgeEventArgs(e)); + + return true; + } + + public void AddEdgeRange(IEnumerable edges) + { + GraphContracts.AssumeNotNull(edges, "edges"); + foreach (var edge in edges) + this.AddEdge(edge); + } + + public virtual bool AddVerticesAndEdge(TEdge e) + { + GraphContracts.AssumeNotNull(e, "e"); + if (!this.ContainsVertex(e.Source)) + this.AddVertex(e.Source); + if (!this.ContainsVertex(e.Target)) + this.AddVertex(e.Target); + + return this.AddEdge(e); + } + + public event EdgeEventHandler EdgeAdded; + protected virtual void OnEdgeAdded(EdgeEventArgs args) + { + EdgeEventHandler eh = this.EdgeAdded; + if (eh != null) + eh(this, args); + } + + public virtual bool RemoveEdge(TEdge e) + { + GraphContracts.AssumeInVertexSet(this, e, "e"); + if (this.vertexOutEdges[e.Source].Remove(e)) + { + this.vertexInEdges[e.Target].Remove(e); + this.edgeCount--; + GraphContracts.Assert(this.edgeCount >= 0); + + this.OnEdgeRemoved(new EdgeEventArgs(e)); + return true; + } + else + { + return false; + } + } + + public event EdgeEventHandler EdgeRemoved; + protected virtual void OnEdgeRemoved(EdgeEventArgs args) + { + EdgeEventHandler eh = this.EdgeRemoved; + if (eh != null) + eh(this, args); + } + + public int RemoveEdgeIf(EdgePredicate predicate) + { + GraphContracts.AssumeNotNull(predicate, "predicate"); + EdgeList edges = new EdgeList(); + foreach (var edge in this.Edges) + if (predicate(edge)) + edges.Add(edge); + + foreach (var edge in edges) + this.RemoveEdge(edge); + return edges.Count; + } + + public int RemoveOutEdgeIf(TVertex v, EdgePredicate predicate) + { + GraphContracts.AssumeInVertexSet(this, v, "v"); + GraphContracts.AssumeNotNull(predicate, "predicate"); + EdgeList edges = new EdgeList(); + foreach (var edge in this.OutEdges(v)) + if (predicate(edge)) + edges.Add(edge); + foreach (var edge in edges) + this.RemoveEdge(edge); + return edges.Count; + } + + public int RemoveInEdgeIf(TVertex v, EdgePredicate predicate) + { + GraphContracts.AssumeInVertexSet(this, v, "v"); + GraphContracts.AssumeNotNull(predicate, "predicate"); + EdgeList edges = new EdgeList(); + foreach (var edge in this.InEdges(v)) + if (predicate(edge)) + edges.Add(edge); + foreach (var edge in edges) + this.RemoveEdge(edge); + return edges.Count; + } + + public void ClearOutEdges(TVertex v) + { + GraphContracts.AssumeInVertexSet(this, v, "v"); + + EdgeList outEdges = this.vertexOutEdges[v]; + foreach (var edge in outEdges) + { + this.vertexInEdges[edge.Target].Remove(edge); + this.OnEdgeRemoved(new EdgeEventArgs(edge)); + } + + this.edgeCount -= outEdges.Count; + outEdges.Clear(); + GraphContracts.Assert(this.edgeCount >= 0); + } + + public void ClearInEdges(TVertex v) + { + GraphContracts.AssumeInVertexSet(this, v, "v"); + + EdgeList inEdges = this.vertexInEdges[v]; + foreach (var edge in inEdges) + { + this.vertexOutEdges[edge.Source].Remove(edge); + this.OnEdgeRemoved(new EdgeEventArgs(edge)); + } + + this.edgeCount -= inEdges.Count; + inEdges.Clear(); + GraphContracts.Assert(this.edgeCount >= 0); + } + + public void ClearEdges(TVertex v) + { + GraphContracts.AssumeInVertexSet(this, v, "v"); + + ClearOutEdges(v); + ClearInEdges(v); + } + + public void TrimEdgeExcess() + { + foreach (var edges in this.vertexInEdges.Values) + edges.TrimExcess(); + foreach (var edges in this.vertexOutEdges.Values) + edges.TrimExcess(); + } + + public void Clear() + { + this.vertexOutEdges.Clear(); + this.vertexInEdges.Clear(); + this.edgeCount = 0; + } + + public void MergeVertex(TVertex v, IEdgeFactory edgeFactory) + { + GraphContracts.AssumeInVertexSet(this, v, "v"); + GraphContracts.AssumeNotNull(edgeFactory, "edgeFactory"); + + // storing edges in local array + EdgeList inedges = this.vertexInEdges[v]; + EdgeList outedges = this.vertexOutEdges[v]; + + // remove vertex + this.RemoveVertex(v); + + // add edges from each source to each target + foreach (var source in inedges) + { + //is it a self edge + if (source.Source.Equals(v)) + continue; + foreach (var target in outedges) + { + if (v.Equals(target.Target)) + continue; + // we add an new edge + this.AddEdge(edgeFactory.CreateEdge(source.Source, target.Target)); + } + } + } + + public void MergeVertexIf(VertexPredicate vertexPredicate, IEdgeFactory edgeFactory) + { + GraphContracts.AssumeNotNull(vertexPredicate, "vertexPredicate"); + GraphContracts.AssumeNotNull(edgeFactory, "edgeFactory"); + + // storing vertices to merge + VertexList mergeVertices = new VertexList(this.VertexCount / 4); + foreach (var v in this.Vertices) + if (vertexPredicate(v)) + mergeVertices.Add(v); + + // applying merge recursively + foreach (var v in mergeVertices) + MergeVertex(v, edgeFactory); + } + + [Serializable] + private sealed class VertexList : List + { + public VertexList() { } + public VertexList(int capacity) + : base(capacity) { } + } + + [Serializable] + private sealed class EdgeList : List, ICloneable + { + public EdgeList() { } + public EdgeList(int capacity) + : base(capacity) + { } + private EdgeList(EdgeList list) + : base(list) + { } + + public EdgeList Clone() + { + return new EdgeList(this); + } + + object ICloneable.Clone() + { + return this.Clone(); + } + } + + [Serializable] + private sealed class VertexEdgeDictionary + : Dictionary, ICloneable, ISerializable + { + public VertexEdgeDictionary() { } + public VertexEdgeDictionary(int capacity) + : base(capacity) + { } + + public VertexEdgeDictionary(SerializationInfo info, StreamingContext context):base(info,context) { } + + public VertexEdgeDictionary Clone() + { + VertexEdgeDictionary clone = new VertexEdgeDictionary(this.Count); + foreach (KeyValuePair kv in this) + clone.Add(kv.Key, kv.Value.Clone()); + return clone; + } + + object ICloneable.Clone() + { + return this.Clone(); + } + } + + #region ICloneable Members + private BidirectionalGraph( + VertexEdgeDictionary vertexInEdges, + VertexEdgeDictionary vertexOutEdges, + int edgeCount, + int edgeCapacity, + bool allowParallelEdges + ) + { + this.vertexInEdges = vertexInEdges; + this.vertexOutEdges = vertexOutEdges; + this.edgeCount = edgeCount; + this.edgeCapacity = edgeCapacity; + this.allowParallelEdges = allowParallelEdges; + } + + public BidirectionalGraph Clone() + { + return new BidirectionalGraph( + this.vertexInEdges.Clone(), + this.vertexOutEdges.Clone(), + this.edgeCount, + this.edgeCapacity, + this.allowParallelEdges + ); + } + + object ICloneable.Clone() + { + return this.Clone(); + } + #endregion + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/BidirectionalGraph.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/BidirectionalGraph.cs.meta new file mode 100644 index 0000000..ff228b6 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/BidirectionalGraph.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: f2797574f25e840379b8236311eafc32 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/BidirectionalMatrixGraph.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/BidirectionalMatrixGraph.cs new file mode 100755 index 0000000..b5b1092 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/BidirectionalMatrixGraph.cs @@ -0,0 +1,363 @@ +using System; +using System.Collections.Generic; + +namespace QuickGraph +{ + public class BidirectionalMatrixGraph : + IBidirectionalGraph, + IMutableEdgeListGraph + where TEdge : IEdge + { + private readonly int vertexCount; + private int edgeCount; + private readonly TEdge[,] edges; + + public BidirectionalMatrixGraph(int vertexCount) + { + if (vertexCount < 1) + throw new ArgumentOutOfRangeException("vertexCount"); + this.vertexCount = vertexCount; + this.edgeCount = 0; + this.edges = new TEdge[vertexCount, vertexCount]; + } + + #region IGraph + public bool AllowParallelEdges + { + get { return false; } + } + + public bool IsDirected + { + get { return true; } + } + #endregion + + #region IVertexListGraph + public int VertexCount + { + get { return this.vertexCount; } + } + + public bool IsVerticesEmpty + { + get { return this.VertexCount == 0; } + } + #endregion + + #region IEdgeListGraph + public int EdgeCount + { + get { return this.edgeCount; } + } + + public bool IsEdgesEmpty + { + get { return this.EdgeCount == 0; } + } + + public IEnumerable Edges + { + get + { + for (int i = 0; i < this.VertexCount; ++i) + { + for (int j = 0; j < this.VertexCount; ++j) + { + TEdge e = this.edges[i, j]; + if (e != null) + yield return e; + } + } + } + } + #endregion + + #region IBidirectionalGraph Members + + public bool IsInEdgesEmpty(int v) + { + for (int i = 0; i < this.VertexCount; ++i) + if (this.edges[i, v] != null) + return false; + return true; + } + + public int InDegree(int v) + { + int count = 0; + for (int i = 0; i < this.VertexCount; ++i) + if (this.edges[i, v] != null) + count++; + return count; + } + + public IEnumerable InEdges(int v) + { + for (int i = 0; i < this.VertexCount; ++i) + { + TEdge e = this.edges[i, v]; + if (e != null) + yield return e; + } + } + + public TEdge InEdge(int v, int index) + { + int count = 0; + for (int i = 0; i < this.VertexCount; ++i) + { + TEdge e = this.edges[i, v]; + if (e != null) + { + if (count == index) + return e; + count++; + } + } + throw new ArgumentOutOfRangeException("index"); + } + + public int Degree(int v) + { + return this.InDegree(v) + this.OutDegree(v); + } + + #endregion + + #region IIncidenceGraph Members + + public bool ContainsEdge(int source, int target) + { + return this.edges[source, target] != null; + } + + public bool TryGetEdge(int source, int target, out TEdge edge) + { + edge = this.edges[source, target]; + return edge != null; + } + + public bool TryGetEdges(int source, int target, out IEnumerable edges) + { + TEdge edge; + if (this.TryGetEdge(source, target, out edge)) + { + edges = new TEdge[] { edge }; + return true; + } + else + { + edges = null; + return false; + } + } + + #endregion + + #region IImplicitGraph Members + + public bool IsOutEdgesEmpty(int v) + { + for (int j = 0; j < this.vertexCount; ++j) + if (this.edges[v, j] != null) + return false; + return true; + } + + public int OutDegree(int v) + { + int count = 0; + for (int j = 0; j < this.vertexCount; ++j) + if (this.edges[v, j] != null) + count++; + return count; + } + + public IEnumerable OutEdges(int v) + { + for (int j = 0; j < this.vertexCount; ++j) + { + TEdge e = this.edges[v, j]; + if (e != null) + yield return e; + } + } + + public TEdge OutEdge(int v, int index) + { + int count = 0; + for (int j = 0; j < this.vertexCount; ++j) + { + TEdge e = this.edges[v, j]; + if (e != null) + { + if (count==index) + return e; + count++; + } + } + throw new ArgumentOutOfRangeException("index"); + } + + #endregion + + #region IVertexSet Members + + public IEnumerable Vertices + { + get + { + for (int i = 0; i < this.VertexCount; ++i) + yield return i; + } + } + + public bool ContainsVertex(int vertex) + { + return vertex >= 0 && vertex < this.VertexCount; + } + + #endregion + + #region IEdgeListGraph Members + + public bool ContainsEdge(TEdge edge) + { + TEdge e = this.edges[edge.Source, edge.Target]; + return e!=null && + e.Equals(edge); + } + + #endregion + + #region IMutableBidirectionalGraph Members + + public int RemoveInEdgeIf(int v, EdgePredicate edgePredicate) + { + int count = 0; + for (int i = 0; i < this.VertexCount; ++i) + { + TEdge e = this.edges[i, v]; + if (e != null && edgePredicate(e)) + { + this.RemoveEdge(e); + count++; + } + } + return count; + } + + public void ClearInEdges(int v) + { + for (int i = 0; i < this.VertexCount; ++i) + { + TEdge e = this.edges[i, v]; + if (e != null) + this.RemoveEdge(e); + } + } + + public void ClearEdges(int v) + { + this.ClearInEdges(v); + this.ClearOutEdges(v); + } + + #endregion + + #region IMutableIncidenceGraph Members + + public int RemoveOutEdgeIf(int v, EdgePredicate predicate) + { + int count = 0; + for (int j = 0; j < this.VertexCount; ++j) + { + TEdge e = this.edges[v, j]; + if (e != null && predicate(e)) + { + this.RemoveEdge(e); + count++; + } + } + return count; + } + + public void ClearOutEdges(int v) + { + for (int j = 0; j < this.VertexCount; ++j) + { + TEdge e = this.edges[v, j]; + if (e != null) + this.RemoveEdge(e); + } + } + + #endregion + + #region IMutableGraph Members + + public void Clear() + { + throw new Exception("The method or operation is not implemented."); + } + + #endregion + + #region IMutableEdgeListGraph Members + + public bool AddEdge(TEdge edge) + { + GraphContracts.AssumeNotNull(edge, "edge"); + if (this.edges[edge.Source, edge.Target]!=null) + throw new ParallelEdgeNotAllowedException(); + this.edges[edge.Source,edge.Target] = edge; + this.edgeCount++; + this.OnEdgeAdded(new EdgeEventArgs(edge)); + return true; + } + + public void AddEdgeRange(IEnumerable edges) + { + GraphContracts.AssumeNotNull(edges, "edges"); + foreach (var edge in edges) + this.AddEdge(edge); + } + + public event EdgeEventHandler EdgeAdded; + protected virtual void OnEdgeAdded(EdgeEventArgs args) + { + EdgeEventHandler eh = this.EdgeAdded; + if (eh != null) + eh(this, args); + } + + public bool RemoveEdge(TEdge edge) + { + TEdge e = this.edges[edge.Source, edge.Target]; + this.edges[edge.Source, edge.Target] = default(TEdge); + if (!e.Equals(default(TEdge))) + { + this.edgeCount--; + this.OnEdgeRemoved(new EdgeEventArgs(edge)); + return true; + } + else + return false; + } + + public event EdgeEventHandler EdgeRemoved; + protected virtual void OnEdgeRemoved(EdgeEventArgs args) + { + EdgeEventHandler eh = this.EdgeRemoved; + if (eh != null) + eh(this, args); + } + + public int RemoveEdgeIf(EdgePredicate predicate) + { + throw new NotImplementedException(); + } + #endregion +} +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/BidirectionalMatrixGraph.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/BidirectionalMatrixGraph.cs.meta new file mode 100644 index 0000000..8d98f56 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/BidirectionalMatrixGraph.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 792f61542c47543078206dca465c270e +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Collections.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Collections.meta new file mode 100644 index 0000000..04bdee8 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Collections.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: 8e344298df45d4ba8a927ac1a7f21c44 +folderAsset: yes +DefaultImporter: + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Collections/BinaryHeap.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Collections/BinaryHeap.cs new file mode 100755 index 0000000..73793bb --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Collections/BinaryHeap.cs @@ -0,0 +1,291 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Collections; + +namespace QuickGraph.Collections +{ + /// + /// Binary heap + /// + /// + /// + /// Indexing rules: + /// + /// parent index: index ¡ 1)/2 + /// left child: 2 * index + 1 + /// right child: 2 * index + 2 + /// + /// Reference: + /// http://dotnetslackers.com/Community/files/folders/data-structures-and-algorithms/entry28722.aspx + /// + [DebuggerDisplay("Count = {Count}")] + public class BinaryHeap : + IEnumerable> + { + readonly Comparison priorityComparsion; + KeyValuePair[] items; + int count; + int version; + + const int DefaultCapacity = 16; + + public BinaryHeap() + : this(DefaultCapacity, Comparer.Default.Compare) + { } + + public BinaryHeap(Comparison priorityComparison) + : this(DefaultCapacity, priorityComparison) + { } + + public BinaryHeap(int capacity, Comparison priorityComparison) + { + if (capacity < 0) + throw new ArgumentOutOfRangeException("capacity"); + if (priorityComparison == null) + throw new ArgumentNullException("priorityComparison"); + + this.items = new KeyValuePair[capacity]; + this.priorityComparsion = priorityComparison; + } + + public Comparison PriorityComparison + { + get { return this.priorityComparsion; } + } + + public int Capacity + { + get { return this.items.Length; } + } + + public int Count + { + get { return this.count; } + } + + public void Add(TPriority priority, TValue value) + { + GraphContracts.Assert(count <= this.items.Length); + + this.version++; + this.ResizeArray(); + this.items[this.count++] = new KeyValuePair(priority, value); + this.MinHeapifyDown(this.count - 1); + } + + private void MinHeapifyDown(int start) + { + int i = start; + int j = (i - 1) / 2; + while (i > 0 && + this.Less(i, j)) + { + this.Swap(i, j); + i = j; + j = (i - 1) / 2; + } + } + + private void ResizeArray() + { + if (this.count == this.items.Length) + { + var newItems = new KeyValuePair[this.count * 2 + 1]; + Array.Copy(this.items, newItems, this.count); + this.items = newItems; + } + } + + public KeyValuePair Minimum() + { + if (this.count == 0) + throw new InvalidOperationException(); + return this.items[0]; + } + + public KeyValuePair RemoveMinimum() + { + // shortcut for heap with 1 element. + if (this.count == 1) + { + this.version++; + return this.items[--this.count]; + } + return this.RemoveAt(0); + } + + public KeyValuePair RemoveAt(int index) + { + if (this.count == 0) + throw new InvalidOperationException("heap is empty"); + if (index < 0 | index >= this.count | index + this.count < this.count) + throw new ArgumentOutOfRangeException("index"); + + this.version++; + // shortcut for heap with 1 element. + if (this.count == 1) + return this.items[--this.count]; + + if (index < this.count - 1) + { + this.Swap(index, this.count - 1); + this.MinHeapifyUp(index); + } + + return this.items[--this.count]; + } + + private void MinHeapifyUp(int index) + { + var left = 2 * index + 1; + var right = 2 * index + 2; + while ( + (left < this.count - 1 && !this.Less(index, left)) || + (right < this.count - 1 && !this.Less(index, right)) + ) + { + if (right >= this.count - 1 || + this.Less(left, right)) + { + this.Swap(left, index); + index = left; + } + else + { + this.Swap(right, index); + index = right; + } + left = 2 * index + 1; + right = 2 * index + 2; + } + } + + public int IndexOf(TValue value) + { + for (int i = 0; i < this.count; i++) + { + if (object.Equals(value, this.items[i].Value)) + return i; + } + return -1; + } + + public void Update(TPriority priority, TValue value) + { + // find index + var index = this.IndexOf(value); + if (index < 0) + throw new InvalidOperationException("value was not found in the heap"); + + // remove and add + this.RemoveAt(index); + this.Add(priority, value); + } + + private bool Less(int i, int j) + { + GraphContracts.Assert(i >= 0 & i < this.count & + j >= 0 & j < this.count & + i != j, String.Format("i: {0}, j: {1}", i, j)); + + return this.priorityComparsion(this.items[i].Key, this.items[j].Key) <= 0; + } + + private void Swap(int i, int j) + { + GraphContracts.Assert(i >= 0 & i < this.count & + j >= 0 & j < this.count & + i != j); + + var kv = this.items[i]; + this.items[i] = this.items[j]; + this.items[j] = kv; + } + + [Conditional("DEBUG")] + public void ObjectInvariant() + { + GraphContracts.Assert(this.items != null); + GraphContracts.Assert( + this.count > -1 & + this.count <= this.items.Length); + for (int index = 0; index < this.count; ++index) + { + var left = 2 * index + 1; + GraphContracts.Assert(left >= count || this.Less(index, left)); + var right = 2 * index + 2; + GraphContracts.Assert(right >= count || this.Less(index, right)); + } + } + + #region IEnumerable> Members + public IEnumerator> GetEnumerator() + { + return new Enumerator(this); + } + + struct Enumerator : + IEnumerator> + { + BinaryHeap owner; + KeyValuePair[] items; + readonly int count; + readonly int version; + int index; + + public Enumerator(BinaryHeap owner) + { + this.owner = owner; + this.items = owner.items; + this.count = owner.count; + this.version = owner.version; + this.index = -1; + } + + public KeyValuePair Current + { + get + { + if (this.version != this.owner.version) + throw new InvalidOperationException(); + if (this.index < 0 | this.index == this.count) + throw new InvalidOperationException(); + GraphContracts.Assert(this.index <= this.count); + return this.items[this.index]; + } + } + + void IDisposable.Dispose() + { + this.owner = null; + this.items = null; + } + + object IEnumerator.Current + { + get { return this.Current; } + } + + public bool MoveNext() + { + if (this.version != this.owner.version) + throw new InvalidOperationException(); + return ++this.index < this.count; + } + + public void Reset() + { + if (this.version != this.owner.version) + throw new InvalidOperationException(); + this.index = -1; + } + } + + IEnumerator IEnumerable.GetEnumerator() + { + return this.GetEnumerator(); + } + #endregion + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Collections/BinaryHeap.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Collections/BinaryHeap.cs.meta new file mode 100644 index 0000000..4346cc8 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Collections/BinaryHeap.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 1927e045a2139404caeaed833a97569c +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Collections/IQueue.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Collections/IQueue.cs new file mode 100755 index 0000000..66618b0 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Collections/IQueue.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace QuickGraph.Collections +{ + public interface IQueue + { + int Count { get; } + + bool Contains(T value); + void Enqueue(T value); + T Dequeue(); + T Peek(); + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Collections/IQueue.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Collections/IQueue.cs.meta new file mode 100644 index 0000000..7ddc39d --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Collections/IQueue.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b6e0ff9e40b094355b40b6a258d1dea9 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Collections/PriorithizedQueue.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Collections/PriorithizedQueue.cs new file mode 100755 index 0000000..3a758ab --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Collections/PriorithizedQueue.cs @@ -0,0 +1,66 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; + +namespace QuickGraph.Collections +{ + [Serializable] + public sealed class PriorityQueue : + IQueue + { + private readonly IDictionary distances; + private readonly BinaryHeap heap; + + public PriorityQueue( + IDictionary distances + ) + : this(distances, Comparer.Default.Compare) + { } + + public PriorityQueue( + IDictionary distances, + Comparison distanceComparison + ) + { + if (distances == null) + throw new ArgumentNullException("distances"); + if (distanceComparison == null) + throw new ArgumentNullException("distanceComparison"); + + this.distances = distances; + this.heap = new BinaryHeap(distanceComparison); + } + + public void Update(TVertex v) + { + this.heap.Update(this.distances[v], v); + } + + public int Count + { + get { return this.heap.Count; } + } + + public bool Contains(TVertex value) + { + return this.heap.IndexOf(value) > -1; + } + + public void Enqueue(TVertex value) + { + GraphContracts.AssumeNotNull(value, "value"); + GraphContracts.Assume(this.distances.ContainsKey(value), "this.distances.ContainsKey(value)"); + this.heap.Add(this.distances[value], value); + } + + public TVertex Dequeue() + { + return this.heap.RemoveMinimum().Value; + } + + public TVertex Peek() + { + return this.heap.Minimum().Value; + } + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Collections/PriorithizedQueue.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Collections/PriorithizedQueue.cs.meta new file mode 100644 index 0000000..b9bf895 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Collections/PriorithizedQueue.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: de1f214c191c54ff4b98b8c206983fed +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Collections/PriorityQueue.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Collections/PriorityQueue.cs new file mode 100755 index 0000000..a3336a7 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Collections/PriorityQueue.cs @@ -0,0 +1,112 @@ +using System; +using System.Collections.Generic; + +namespace ModelDriven.Graph.Collections +{ + /// + /// + /// + /// + /// Algorithms in Java 3rd edition. Chapter 9.6 + /// + /// + public class PriorityQueue : IEnumerable + { + private T[] items; + private int[] pq; + private int[] qp; + private int count; + private IComparer comparer; + + public PriorityQueue(T[] items, IComparer comparer) + { + this.items = items; + this.count = 0; + this.comparer = comparer; + this.pq = new int[this.items.Length + 1]; + this.qp = new int[this.items.Length + 1]; + } + + #region Heap methods + private bool Less(int left, int right) + { + return this.comparer.Compare( + this.items[pq[left]], + this.items[pq[right]] + ) < 0; + } + + private void Exchange(int i, int j) + { + int t = pq[i]; + pq[i] = pq[j]; + pq[j] = t; + qp[pq[i]] = i; + qp[pq[j]] = j; + } + + private void Swim(int k) + { + while (k > 1 && Less(k / 2, k)) + { + Exchange(k, k / 2); + k = k / 2; + } + } + + private void Sink(int k, int N) + { + while (2 * k <= N) + { + int j = 2 * k; + if (j < N && Less(j, j + 1)) + j++; + if (!Less(k, j)) + break; + Exchange(k, j); + k = j; + } + } + #endregion + + public int Count + { + get { return this.count; } + } + + public int Capacity + { + get { return this.items.Length - 1; } + } + + public void Add(int v) + { + pq[++this.count] = v; + qp[v] = this.Count; + Swim(this.Count); + } + + public void Update(int k) + { + Swim(qp[k]); + Sink(qp[k], this.Count); + } + + public int Pop() + { + Exchange(1, this.Count); + Sink(1, this.Count - 1); + return pq[this.count--]; + } + + public IEnumerator GetEnumerator() + { + return (IEnumerator)this.items.GetEnumerator(); + } + + System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() + { + return this.GetEnumerator(); + } + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Collections/PriorityQueue.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Collections/PriorityQueue.cs.meta new file mode 100644 index 0000000..a2cefff --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Collections/PriorityQueue.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e6d90b51c3b7c46c19b3d9eceffa0f4f +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Collections/Queue.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Collections/Queue.cs new file mode 100755 index 0000000..bc6abd0 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Collections/Queue.cs @@ -0,0 +1,12 @@ +namespace QuickGraph.Collections +{ + using System; + using System.Collections.Generic; + + [Serializable] + public class Queue : + System.Collections.Generic.Queue, + IQueue + { + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Collections/Queue.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Collections/Queue.cs.meta new file mode 100644 index 0000000..4745387 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Collections/Queue.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e2085439d61254eec8b0a587641fe77c +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/CreateEdgeDelegate.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/CreateEdgeDelegate.cs new file mode 100755 index 0000000..a039f0b --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/CreateEdgeDelegate.cs @@ -0,0 +1,10 @@ +using System; +namespace QuickGraph +{ + [Serializable] + public delegate TEdge CreateEdgeDelegate( + IVertexListGraph g, + TVertex source, + TVertex target) + where TEdge : IEdge; +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/CreateEdgeDelegate.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/CreateEdgeDelegate.cs.meta new file mode 100644 index 0000000..c1581f5 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/CreateEdgeDelegate.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 40ab73837de614aa0a8f4b1ebeb9c083 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/CreateVertexDelegate.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/CreateVertexDelegate.cs new file mode 100755 index 0000000..a81d8b3 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/CreateVertexDelegate.cs @@ -0,0 +1,8 @@ +using System; +namespace QuickGraph +{ + [Serializable] + public delegate TVertex CreateVertexDelegate( + IVertexListGraph g) + where TEdge : IEdge; +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/CreateVertexDelegate.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/CreateVertexDelegate.cs.meta new file mode 100644 index 0000000..2f3d6d5 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/CreateVertexDelegate.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 7bb9ebce4b9ed4407b927c009a3f80e7 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Diagrams.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Diagrams.meta new file mode 100644 index 0000000..1c4f9c1 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Diagrams.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: 3f008bd24ddb54b8f86cb4054a58431b +folderAsset: yes +DefaultImporter: + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Diagrams/TraversalInterfaces.cd b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Diagrams/TraversalInterfaces.cd new file mode 100755 index 0000000..4482a5d --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Diagrams/TraversalInterfaces.cd @@ -0,0 +1,67 @@ + + + + + + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= + IEdgeListAndIncidenceGraph.cs + + + + + + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= + IEdgeListGraph.cs + + + + + + AAAAQAAgAAAAAAAAAAAAAAAAAAAAABAAAAAEAAAAAAA= + IImplicitGraph.cs + + + + + + AIAAAAAAAAAAAAAAECAAAAAAAAAAAAAAAAAAAAAAAAA= + IIncidenceGraph.cs + + + + + + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= + IVertexAndEdgeListGraph.cs + + + + + + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= + IVertexListGraph.cs + + + + + + AAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAEABAAACAAAA= + IVertexSet.cs + + + + + + AAAAgAAAAAAAAAAAACAAAAAQAAAAAAAAAAgAAAAAAAA= + IEdgeSet.cs + + + + + + gAAAAAQAAAAAAAAAAAAAAAASAAAAAAAAAAAAAAAAABA= + IBidirectionalGraph.cs + + + + \ No newline at end of file diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Diagrams/TraversalInterfaces.cd.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Diagrams/TraversalInterfaces.cd.meta new file mode 100644 index 0000000..77fcfa6 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Diagrams/TraversalInterfaces.cd.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: 2ec65a898edae4ea7bc6315534b080ed +DefaultImporter: + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Edge.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Edge.cs new file mode 100755 index 0000000..02509ab --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Edge.cs @@ -0,0 +1,40 @@ +using System; + +namespace QuickGraph +{ + [Serializable] + public class Edge : IEdge + { + private readonly TVertex source; + private readonly TVertex target; + + public Edge(TVertex source, TVertex target) + { + GraphContracts.AssumeNotNull(source, "source"); + GraphContracts.AssumeNotNull(target, "target"); + + this.source = source; + this.target = target; + } + + public static Type VertexType + { + get { return typeof(TVertex); } + } + + public TVertex Source + { + get { return this.source; } + } + + public TVertex Target + { + get { return this.target; } + } + + public override string ToString() + { + return String.Format("{0}->{1}", this.Source, this.Target); + } + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Edge.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Edge.cs.meta new file mode 100644 index 0000000..490bdab --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Edge.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d46206581d4b34d5a80c55f26ecdcd70 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/EdgeEdgeEventArgs.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/EdgeEdgeEventArgs.cs new file mode 100755 index 0000000..10ba863 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/EdgeEdgeEventArgs.cs @@ -0,0 +1,34 @@ +using System; + +namespace QuickGraph +{ + [Serializable] + public sealed class EdgeEdgeEventArgs : EventArgs + where TEdge : IEdge + { + private readonly TEdge edge; + private readonly TEdge targetEdge; + public EdgeEdgeEventArgs(TEdge edge, TEdge targetEdge) + { + GraphContracts.AssumeNotNull(edge, "edge"); + GraphContracts.AssumeNotNull(targetEdge, "targetEdge"); + this.edge = edge; + this.targetEdge = targetEdge; + } + + public TEdge Edge + { + get { return this.edge; } + } + + public TEdge TargetEdge + { + get { return this.targetEdge;} + } + } + + public delegate void EdgeEdgeEventHandler( + Object sender, + EdgeEdgeEventArgs e) + where TEdge : IEdge; +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/EdgeEdgeEventArgs.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/EdgeEdgeEventArgs.cs.meta new file mode 100644 index 0000000..c4dff13 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/EdgeEdgeEventArgs.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 3602a50dc872b4d509d185dafd4b6e0b +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/EdgeEventArgs.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/EdgeEventArgs.cs new file mode 100755 index 0000000..8f8a599 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/EdgeEventArgs.cs @@ -0,0 +1,27 @@ +using System; + +namespace QuickGraph +{ + [Serializable] + public class EdgeEventArgs : EventArgs + where TEdge : IEdge + { + private TEdge edge; + public EdgeEventArgs(TEdge edge) + { + if (edge == null) + throw new ArgumentNullException("edge"); + this.edge = edge; + } + + public TEdge Edge + { + get { return this.edge; } + } + } + + public delegate void EdgeEventHandler( + Object sender, + EdgeEventArgs e) + where TEdge : IEdge; +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/EdgeEventArgs.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/EdgeEventArgs.cs.meta new file mode 100644 index 0000000..927b381 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/EdgeEventArgs.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 41f246e17504b4ff9a47455bbaafc833 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/EdgeFactory.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/EdgeFactory.cs new file mode 100755 index 0000000..4f0993d --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/EdgeFactory.cs @@ -0,0 +1,13 @@ +using System; + +namespace QuickGraph +{ + [Serializable] + public sealed class EdgeFactory : IEdgeFactory> + { + public Edge CreateEdge(TVertex source, TVertex target) + { + return new Edge(source, target); + } + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/EdgeFactory.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/EdgeFactory.cs.meta new file mode 100644 index 0000000..97e5cac --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/EdgeFactory.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 276086653c01f40438c5f0a8a9e5fbb6 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/EdgeListGraph.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/EdgeListGraph.cs new file mode 100755 index 0000000..912d1a8 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/EdgeListGraph.cs @@ -0,0 +1,135 @@ +using System; +using System.Collections.Generic; + +namespace QuickGraph +{ + [Serializable] + public class EdgeListGraph : + IEdgeListGraph, + IMutableEdgeListGraph + where TEdge : IEdge + { + private readonly bool isDirected = true; + private readonly bool allowParralelEdges = true; + private readonly EdgeEdgeDictionary edges = new EdgeEdgeDictionary(); + + [Serializable] + public class EdgeEdgeDictionary : Dictionary + { } + + public EdgeListGraph() + {} + + public EdgeListGraph(bool isDirected, bool allowParralelEdges) + { + this.isDirected = isDirected; + this.allowParralelEdges = allowParralelEdges; + } + + public bool IsEdgesEmpty + { + get + { + return this.edges.Count==0; + } + } + + public int EdgeCount + { + get + { + return this.edges.Count; + } + } + + public IEnumerable Edges + { + get + { + return this.edges.Keys; + } + } + + public bool ContainsEdge(TEdge edge) + { + return this.edges.ContainsKey(edge); + } + + public bool IsDirected + { + get + { + return this.isDirected; + } + } + + public bool AllowParallelEdges + { + get + { + return this.allowParralelEdges; + } + } + + public bool AddEdge(TEdge edge) + { + GraphContracts.AssumeNotNull(edge, "edge"); + if(this.ContainsEdge(edge)) + return false; + this.edges.Add(edge, edge); + this.OnEdgeAdded(new EdgeEventArgs(edge)); + return true; + } + + public void AddEdgeRange(IEnumerable edges) + { + GraphContracts.AssumeNotNull(edges, "edges"); + foreach (var edge in edges) + this.AddEdge(edge); + } + + public event EdgeEventHandler EdgeAdded; + protected virtual void OnEdgeAdded(EdgeEventArgs args) + { + EdgeEventHandler eh = this.EdgeAdded; + if (eh != null) + eh(this, args); + } + + public bool RemoveEdge(TEdge edge) + { + if (this.edges.Remove(edge)) + { + this.OnEdgeRemoved(new EdgeEventArgs(edge)); + return true; + } + else + return false; + } + + public event EdgeEventHandler EdgeRemoved; + protected virtual void OnEdgeRemoved(EdgeEventArgs args) + { + EdgeEventHandler eh = this.EdgeRemoved; + if (eh != null) + eh(this, args); + } + + public int RemoveEdgeIf(EdgePredicate predicate) + { + List edgesToRemove = new List(); + foreach (var edge in this.Edges) + if (predicate(edge)) + edgesToRemove.Add(edge); + + foreach (var edge in edgesToRemove) + edges.Remove(edge); + return edgesToRemove.Count; + } + + public void Clear() + { + this.edges.Clear(); + } + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/EdgeListGraph.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/EdgeListGraph.cs.meta new file mode 100644 index 0000000..08f00dd --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/EdgeListGraph.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 039368e32b41649daa0fd08a398d7d38 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/EdgeNotFoundException.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/EdgeNotFoundException.cs new file mode 100755 index 0000000..41dfa69 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/EdgeNotFoundException.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace QuickGraph +{ + + [global::System.Serializable] + public class EdgeNotFoundException : Exception + { + // + // For guidelines regarding the creation of new exception types, see + // http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpgenref/html/cpconerrorraisinghandlingguidelines.asp + // and + // http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dncscol/html/csharp07192001.asp + // + + public EdgeNotFoundException() { } + public EdgeNotFoundException(string message) : base(message) { } + public EdgeNotFoundException(string message, Exception inner) : base(message, inner) { } + protected EdgeNotFoundException( + System.Runtime.Serialization.SerializationInfo info, + System.Runtime.Serialization.StreamingContext context) + : base(info, context) { } + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/EdgeNotFoundException.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/EdgeNotFoundException.cs.meta new file mode 100644 index 0000000..8b1a88d --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/EdgeNotFoundException.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 6b8ffe2bbd8ce4d658426c97a85e292b +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/FactoryCompiler.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/FactoryCompiler.cs new file mode 100755 index 0000000..3fef4dc --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/FactoryCompiler.cs @@ -0,0 +1,121 @@ +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Reflection.Emit; + +namespace QuickGraph +{ + public static class FactoryCompiler + { + private static readonly object syncRoot = new object(); + private static AssemblyBuilder assembly; + private static ModuleBuilder module; + + private static void CreateAssembly() + { + if (assembly == null) + { + assembly = AppDomain.CurrentDomain.DefineDynamicAssembly( + new AssemblyName("QuickGraph.FactoryCompilers"), + AssemblyBuilderAccess.Run + ); + module = assembly.DefineDynamicModule("QuickGraph.FactoryCompilers"); + } + } + + private static string GetVertexFactoryName(Type factoredType) + { + return string.Format( + "{0}VertexFactory", factoredType.MetadataToken + ); + } + + private static string GetEdgeFactoryName(Type vertexType, Type edgeType) + { + return string.Format( + "{0}{1}EdgeFactory", vertexType.MetadataToken, edgeType.MetadataToken); + } + + public static IVertexFactory GetVertexFactory() + { + return (IVertexFactory)Activator.CreateInstance(GetVertexFactoryType()); + } + + private static Type GetVertexFactoryType() + { + lock (syncRoot) + { + CreateAssembly(); + Type factoryType = assembly.GetType(GetVertexFactoryName(typeof(TVertex)), false); + if (factoryType != null) + return factoryType; + + ConstructorInfo constructor = + typeof(TVertex).GetConstructor(new Type[] { }); + if (constructor == null) + throw new ArgumentException(String.Format("Type {0} does not have public construtor", typeof(TVertex))); + + TypeBuilder type = module.DefineType(GetVertexFactoryName(typeof(TVertex)), + TypeAttributes.Sealed | TypeAttributes.Public); + type.AddInterfaceImplementation(typeof(IVertexFactory)); + + + // CreateVertex method + MethodBuilder createVertex = type.DefineMethod( + "CreateVertex", + MethodAttributes.FamANDAssem | MethodAttributes.Family | MethodAttributes.Final | MethodAttributes.Virtual | MethodAttributes.HideBySig | MethodAttributes.VtableLayoutMask, + typeof(TVertex), + Type.EmptyTypes + ); + ILGenerator gen = createVertex.GetILGenerator(); + gen.Emit(OpCodes.Newobj, constructor); + gen.Emit(OpCodes.Ret); + factoryType = type.CreateType(); + return factoryType; + } + } + + public static IEdgeFactory GetEdgeFactory() + where TEdge : IEdge + { + return (IEdgeFactory)Activator.CreateInstance(GetEdgeFactoryType()); + } + + private static Type GetEdgeFactoryType() + where TEdge : IEdge + { + lock (syncRoot) + { + CreateAssembly(); + string typeName = GetEdgeFactoryName(typeof(TVertex), typeof(TEdge)); + Type factoryType = assembly.GetType(typeName, false); + if (factoryType != null) + return factoryType; + + ConstructorInfo constructor = + typeof(TEdge).GetConstructor(new Type[] { typeof(TVertex), typeof(TVertex) }); + if (constructor == null) + throw new ArgumentException(String.Format("Type {0} does not have a construtor that takes 2 Vertex", typeof(TVertex))); + + TypeBuilder type = module.DefineType(typeName, + TypeAttributes.Sealed | TypeAttributes.Public); + type.AddInterfaceImplementation(typeof(IEdgeFactory)); + + // CreateVertex method + MethodBuilder createEdge = type.DefineMethod( + "CreateEdge", + MethodAttributes.FamANDAssem | MethodAttributes.Family | MethodAttributes.Final | MethodAttributes.Virtual | MethodAttributes.HideBySig | MethodAttributes.VtableLayoutMask, + typeof(TEdge), + new Type[] { typeof(TVertex), typeof(TVertex) } + ); + ILGenerator gen = createEdge.GetILGenerator(); + gen.Emit(OpCodes.Ldarg_1); + gen.Emit(OpCodes.Ldarg_2); + gen.Emit(OpCodes.Newobj, constructor); + gen.Emit(OpCodes.Ret); + factoryType = type.CreateType(); + return factoryType; + } + } + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/FactoryCompiler.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/FactoryCompiler.cs.meta new file mode 100644 index 0000000..aff1b29 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/FactoryCompiler.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 3e686553a9c3b46809dfd089f726091e +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/GraphColor.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/GraphColor.cs new file mode 100755 index 0000000..a548de3 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/GraphColor.cs @@ -0,0 +1,12 @@ +using System; + +namespace QuickGraph +{ + [Serializable] + public enum GraphColor + { + White, + Gray, + Black + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/GraphColor.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/GraphColor.cs.meta new file mode 100644 index 0000000..8d38d2b --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/GraphColor.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 907f03884462740f99619331131fa55e +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/GraphContracts.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/GraphContracts.cs new file mode 100755 index 0000000..745f878 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/GraphContracts.cs @@ -0,0 +1,88 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Diagnostics; + +namespace QuickGraph +{ + internal static class GraphContracts + { + [Conditional("DEBUG")] + public static void Assert(bool value) + { + if (!value) + throw new InvalidOperationException(); + } + + [Conditional("DEBUG")] + public static void Assert(bool value, string message) + { + if (!value) + throw new InvalidOperationException(message); + } + + [Conditional("DEBUG")] + public static void AssumeNotNull(T v, string parameterName) + { + if (object.Equals(v, null)) + throw new ArgumentNullException(parameterName); + } + + [Conditional("DEBUG")] + public static void Assume(bool value, string message) + { + if (!value) + throw new ArgumentException(message); + } + + [Conditional("DEBUG")] + public static void AssumeInVertexSet( + IVertexSet g, + TVertex v, + string parameterName) + { + AssumeNotNull(g, "g"); + AssumeNotNull(v, parameterName); + if (!g.ContainsVertex(v)) + throw new VertexNotFoundException(parameterName); + } + + [Conditional("DEBUG")] + public static void AssumeNotInVertexSet( + IVertexSet g, + TVertex v, + string parameterName) + { + AssumeNotNull(g, "g"); + AssumeNotNull(v, parameterName); + if (g.ContainsVertex(v)) + throw new ArgumentException("vertex already in set", parameterName); + } + + [Conditional("DEBUG")] + public static void AssumeInVertexSet( + IVertexAndEdgeSet g, + TEdge e, + string parameterName) + where TEdge : IEdge + { + AssumeNotNull(g, "g"); + AssumeNotNull(e, parameterName); + AssumeInVertexSet(g, e.Source, parameterName + ".Source"); + AssumeInVertexSet(g, e.Target, parameterName + ".Target"); + } + + [Conditional("DEBUG")] + public static void AssumeInEdgeSet( + IVertexAndEdgeSet g, + TEdge e, + string parameterName) + where TEdge : IEdge + { + AssumeInVertexSet(g, e, parameterName); + if (!g.ContainsEdge(e)) + throw new EdgeNotFoundException(parameterName); + } + + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/GraphContracts.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/GraphContracts.cs.meta new file mode 100644 index 0000000..afcfebb --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/GraphContracts.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: dc078e3eefd694b4c9f10ad991138e9f +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/HashCodeHelper.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/HashCodeHelper.cs new file mode 100755 index 0000000..67e76d5 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/HashCodeHelper.cs @@ -0,0 +1,56 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace QuickGraph +{ + static class HashCodeHelper + { + const Int32 FNV1_prime_32 = 16777619; + const Int32 FNV1_basis_32 = unchecked((int)2166136261); + const Int64 FNV1_prime_64 = 1099511628211; + const Int64 FNV1_basis_64 = unchecked((int)14695981039346656037); + + public static Int32 GetHashCode(Int64 x) + { + return Combine((Int32)x, (Int32)(((UInt64)x) >> 32)); + } + + private static Int32 Fold(Int32 hash, byte value) + { + return (hash * FNV1_prime_32) ^ (Int32)value; + } + + private static Int32 Fold(Int32 hash, Int32 value) + { + return Fold(Fold(Fold(Fold(hash, + (byte)value), + (byte)(((UInt32)value) >> 8)), + (byte)(((UInt32)value) >> 16)), + (byte)(((UInt32)value) >> 24)); + } + + /// + /// Combines two hashcodes in a strong way. + /// + /// + /// + /// + public static Int32 Combine(Int32 x, Int32 y) + { + return Fold(Fold(FNV1_basis_32, x), y); + } + + /// + /// Combines three hashcodes in a strong way. + /// + /// + /// + /// + /// + public static Int32 Combine(Int32 x, Int32 y, Int32 z) + { + return Fold(Fold(Fold(FNV1_basis_32, x), y), z); + } + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/HashCodeHelper.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/HashCodeHelper.cs.meta new file mode 100644 index 0000000..6fb755f --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/HashCodeHelper.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 4bd0a9fc8e82045f68652f21138ba149 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/IBidirectionalGraph.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IBidirectionalGraph.cs new file mode 100755 index 0000000..f205310 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IBidirectionalGraph.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; + +namespace QuickGraph +{ + public interface IBidirectionalGraph : + IVertexAndEdgeListGraph + where TEdge : IEdge + { + bool IsInEdgesEmpty(TVertex v); + int InDegree(TVertex v); + + IEnumerable InEdges(TVertex v); + TEdge InEdge(TVertex v, int index); + + int Degree(TVertex v); + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/IBidirectionalGraph.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IBidirectionalGraph.cs.meta new file mode 100644 index 0000000..8666abf --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IBidirectionalGraph.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 9e07e4b3f25924949bfc3178b19f2a21 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/ICloneableEdge.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/ICloneableEdge.cs new file mode 100755 index 0000000..2991d76 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/ICloneableEdge.cs @@ -0,0 +1,9 @@ +using System; + +namespace QuickGraph +{ + public interface ICloneableEdge : IEdge + { + ICloneableEdge Clone(TVertex source, TVertex target); + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/ICloneableEdge.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/ICloneableEdge.cs.meta new file mode 100644 index 0000000..d2da092 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/ICloneableEdge.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d6775900d389a439b9fb23b1d451a735 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/IEdge.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IEdge.cs new file mode 100755 index 0000000..0e1137d --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IEdge.cs @@ -0,0 +1,8 @@ +namespace QuickGraph +{ + public interface IEdge + { + TVertex Source { get;} + TVertex Target { get;} + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/IEdge.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IEdge.cs.meta new file mode 100644 index 0000000..0413714 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IEdge.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: aa9936237c4024b26811cfd4030da056 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/IEdgeFactory.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IEdgeFactory.cs new file mode 100755 index 0000000..589f55d --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IEdgeFactory.cs @@ -0,0 +1,9 @@ +using System; + +namespace QuickGraph +{ + public interface IEdgeFactory where TEdge : IEdge + { + TEdge CreateEdge(TVertex source, TVertex target); + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/IEdgeFactory.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IEdgeFactory.cs.meta new file mode 100644 index 0000000..bde8b0c --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IEdgeFactory.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 0a17c7006ca0c4626b971181d08e0ec3 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/IEdgeListAndIncidenceGraph.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IEdgeListAndIncidenceGraph.cs new file mode 100755 index 0000000..424131c --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IEdgeListAndIncidenceGraph.cs @@ -0,0 +1,8 @@ +namespace QuickGraph +{ + public interface IEdgeListAndIncidenceGraph : + IEdgeListGraph, IIncidenceGraph + where TEdge : IEdge + { + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/IEdgeListAndIncidenceGraph.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IEdgeListAndIncidenceGraph.cs.meta new file mode 100644 index 0000000..45ff55b --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IEdgeListAndIncidenceGraph.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d3defe4fcbf8740f3bb30bedc7571f44 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/IEdgeListGraph.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IEdgeListGraph.cs new file mode 100755 index 0000000..c38e248 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IEdgeListGraph.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; + +namespace QuickGraph +{ + public interface IEdgeListGraph : + IGraph, + IEdgeSet + where TEdge : IEdge + {} +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/IEdgeListGraph.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IEdgeListGraph.cs.meta new file mode 100644 index 0000000..cdf571b --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IEdgeListGraph.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: f7848c33465c54d17a14d7d8d12e9b6f +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/IEdgeSet.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IEdgeSet.cs new file mode 100755 index 0000000..8be8c5b --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IEdgeSet.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace QuickGraph +{ + public interface IEdgeSet + where TEdge : IEdge + { + bool IsEdgesEmpty { get; } + int EdgeCount { get; } + IEnumerable Edges { get; } + bool ContainsEdge(TEdge edge); + } + + +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/IEdgeSet.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IEdgeSet.cs.meta new file mode 100644 index 0000000..d741c6e --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IEdgeSet.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 195b5b93ba7bc4051b0e7173e7556f08 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/IGraph.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IGraph.cs new file mode 100755 index 0000000..a5fae2d --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IGraph.cs @@ -0,0 +1,11 @@ +using System; + +namespace QuickGraph +{ + public interface IGraph + where TEdge : IEdge + { + bool IsDirected { get;} + bool AllowParallelEdges { get;} + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/IGraph.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IGraph.cs.meta new file mode 100644 index 0000000..e87fab8 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IGraph.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: c097df43759c04098a6ac59d8fee2e70 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/IHierarchy.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IHierarchy.cs new file mode 100755 index 0000000..ef7ef95 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IHierarchy.cs @@ -0,0 +1,104 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace QuickGraph +{ + public interface IHierarchy : + IMutableVertexAndEdgeListGraph + where TEdge : IEdge + { + /// + /// Gets the roots of the hierarchy + /// + TVertex Root { get;} + + /// + /// Gets the parent of + /// + /// + /// + /// + /// is the root of the graph. + /// + TVertex GetParent(TVertex vertex); + + /// + /// Gets the parent of + /// + /// + /// + /// + /// is the root of the graph. + /// + TEdge GetParentEdge(TVertex vertex); + + /// + /// Gets a value indicating if is + /// a cross edge. + /// + /// + /// + bool IsCrossEdge(TEdge edge); + + /// + /// Gets a value indicating whether + /// exists really or is just an induced edge. + /// + /// + /// + bool IsRealEdge(TEdge edge); + + /// + /// Gets a value indicating if + /// is a predecessor of + /// + /// + /// + /// + /// true if is a predecessor of + /// + /// + bool IsPredecessorOf(TVertex source, TVertex target); + + /// + /// Gets the number of edges between + /// and . + /// + /// + /// + /// + /// + /// is a predecessor of + /// or the otherway round. + /// + int InducedEdgeCount(TVertex source, TVertex target); + + /// + /// Gets a value indicating if is + /// inner node or a leaf. + /// + /// + /// + /// true if not a leaf + /// + bool IsInnerNode(TVertex vertex); + + /// + /// Gets the collection of children + /// from + /// + /// + /// + IEnumerable ChildrenEdges(TVertex vertex); + + + /// + /// Gets the collection of children + /// from + /// + /// + /// + IEnumerable ChildrenVertices(TVertex vertex); + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/IHierarchy.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IHierarchy.cs.meta new file mode 100644 index 0000000..7516d5f --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IHierarchy.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: f827700fc6a664642a75115a6e66d586 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/IHyperEdge.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IHyperEdge.cs new file mode 100755 index 0000000..ff87852 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IHyperEdge.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; + +namespace QuickGraph +{ + public interface IHyperEdge + { + int EndPointCount { get;} + IEnumerable EndPoints { get;} + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/IHyperEdge.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IHyperEdge.cs.meta new file mode 100644 index 0000000..71594a5 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IHyperEdge.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b6bd2553961534246aa49b69fb0e7eb6 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/IIdentifiable.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IIdentifiable.cs new file mode 100755 index 0000000..b5604e6 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IIdentifiable.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace QuickGraph +{ + public interface IIdentifiable + { + string ID { get;} + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/IIdentifiable.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IIdentifiable.cs.meta new file mode 100644 index 0000000..576b740 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IIdentifiable.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 9bb0b28dbc8c84a8f8f25ac100c837d7 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/IIdentifiableEdgeFactory.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IIdentifiableEdgeFactory.cs new file mode 100755 index 0000000..7908dd4 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IIdentifiableEdgeFactory.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace QuickGraph +{ + public interface IIdentifiableEdgeFactory + where TEdge: IIdentifiable, IEdge + { + TEdge CreateEdge(string id, TVertex source, TVertex target); + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/IIdentifiableEdgeFactory.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IIdentifiableEdgeFactory.cs.meta new file mode 100644 index 0000000..34e9474 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IIdentifiableEdgeFactory.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 757d25b1ec45541e1acc72e9194f56de +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/IIdentifiableVertexFactory.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IIdentifiableVertexFactory.cs new file mode 100755 index 0000000..fdf01fb --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IIdentifiableVertexFactory.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace QuickGraph +{ + public interface IIdentifiableVertexFactory + where TVertex : IIdentifiable + { + TVertex CreateVertex(string id); + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/IIdentifiableVertexFactory.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IIdentifiableVertexFactory.cs.meta new file mode 100644 index 0000000..31afe8b --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IIdentifiableVertexFactory.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: c9bd09bb65e374d65b166f09e2c889d7 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/IImplicitGraph.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IImplicitGraph.cs new file mode 100755 index 0000000..ecab155 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IImplicitGraph.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; + +namespace QuickGraph +{ + public interface IImplicitGraph : IGraph + where TEdge : IEdge + { + bool IsOutEdgesEmpty(TVertex v); + int OutDegree(TVertex v); + IEnumerable OutEdges(TVertex v); + TEdge OutEdge(TVertex v, int index); + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/IImplicitGraph.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IImplicitGraph.cs.meta new file mode 100644 index 0000000..07bcebc --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IImplicitGraph.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 66c15c074a5a648a088c388db612cdf3 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/IIncidenceGraph.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IIncidenceGraph.cs new file mode 100755 index 0000000..80084f8 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IIncidenceGraph.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; + +namespace QuickGraph +{ + public interface IIncidenceGraph : IImplicitGraph + where TEdge : IEdge + { + bool ContainsEdge(TVertex source, TVertex target); + bool TryGetEdges( + TVertex source, + TVertex target, + out IEnumerable edges); + bool TryGetEdge( + TVertex source, + TVertex target, + out TEdge edge); + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/IIncidenceGraph.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IIncidenceGraph.cs.meta new file mode 100644 index 0000000..fc38156 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IIncidenceGraph.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 34c75defbe4234c21abadebb31230258 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/IIndexedEnumerable.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IIndexedEnumerable.cs new file mode 100755 index 0000000..0bfd7c3 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IIndexedEnumerable.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; + +namespace QuickGraph +{ + public interface ICountable : IEnumerable + { + int Count { get;} + } + + public interface IIndexable : ICountable + { + T this[int index] { get;} + int IndexOf(T v); + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/IIndexedEnumerable.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IIndexedEnumerable.cs.meta new file mode 100644 index 0000000..8209419 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IIndexedEnumerable.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 78f86e9bc7c4e468282fa4204625e4cf +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/IIndexedImplicitGraph.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IIndexedImplicitGraph.cs new file mode 100755 index 0000000..a4f730e --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IIndexedImplicitGraph.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; + +namespace QuickGraph +{ + public interface IIndexedImplicitGraph : IImplicitGraph + where TEdge : IEdge + { + IIndexable Vertices { get;} + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/IIndexedImplicitGraph.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IIndexedImplicitGraph.cs.meta new file mode 100644 index 0000000..14223b3 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IIndexedImplicitGraph.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b96547dc665794dd89f749e1930c71a4 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/IIndexedVertexListGraph.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IIndexedVertexListGraph.cs new file mode 100755 index 0000000..e0b90c4 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IIndexedVertexListGraph.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; + +namespace QuickGraph +{ + public interface IIndexedVertexListGraph : + IVertexListGraph, + IIndexedImplicitGraph + where TEdge : IEdge + { + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/IIndexedVertexListGraph.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IIndexedVertexListGraph.cs.meta new file mode 100644 index 0000000..5040b65 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IIndexedVertexListGraph.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 47d23c3d8005848dd853a60f4a5149e6 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/IMutableBidirectionalGraph.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IMutableBidirectionalGraph.cs new file mode 100755 index 0000000..1a7199f --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IMutableBidirectionalGraph.cs @@ -0,0 +1,12 @@ +namespace QuickGraph +{ + public interface IMutableBidirectionalGraph : + IMutableVertexAndEdgeListGraph, + IBidirectionalGraph + where TEdge : IEdge + { + int RemoveInEdgeIf(TVertex v, EdgePredicate edgePredicate); + void ClearInEdges(TVertex v); + void ClearEdges(TVertex v); + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/IMutableBidirectionalGraph.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IMutableBidirectionalGraph.cs.meta new file mode 100644 index 0000000..f1060c3 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IMutableBidirectionalGraph.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 94992bb5b50fc4b5fa30b8cf31d73fdc +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/IMutableEdgeListGraph.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IMutableEdgeListGraph.cs new file mode 100755 index 0000000..54b71c2 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IMutableEdgeListGraph.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; + +namespace QuickGraph +{ + public interface IMutableEdgeListGraph : + IMutableGraph, + IEdgeListGraph + where TEdge : IEdge + { + bool AddEdge(TEdge edge); + event EdgeEventHandler EdgeAdded; + + void AddEdgeRange(IEnumerable edges); + + bool RemoveEdge(TEdge edge); + event EdgeEventHandler EdgeRemoved; + + int RemoveEdgeIf(EdgePredicate predicate); + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/IMutableEdgeListGraph.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IMutableEdgeListGraph.cs.meta new file mode 100644 index 0000000..0e0b218 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IMutableEdgeListGraph.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d15c0347c1b82451eab9189740a74818 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/IMutableGraph.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IMutableGraph.cs new file mode 100755 index 0000000..88883fe --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IMutableGraph.cs @@ -0,0 +1,10 @@ +using System; + +namespace QuickGraph +{ + public interface IMutableGraph : IGraph + where TEdge : IEdge + { + void Clear(); + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/IMutableGraph.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IMutableGraph.cs.meta new file mode 100644 index 0000000..c4b8aff --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IMutableGraph.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 1fa89b06a7e3d4a98b3c0f9407fc31a7 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/IMutableIncidenceGraph.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IMutableIncidenceGraph.cs new file mode 100755 index 0000000..1b7305e --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IMutableIncidenceGraph.cs @@ -0,0 +1,17 @@ +using System; + +namespace QuickGraph +{ + public interface IMutableIncidenceGraph : + IMutableGraph, + IIncidenceGraph + where TEdge : IEdge + { + int RemoveOutEdgeIf( + TVertex v, + EdgePredicate predicate); + void ClearOutEdges(TVertex v); + + void TrimEdgeExcess(); + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/IMutableIncidenceGraph.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IMutableIncidenceGraph.cs.meta new file mode 100644 index 0000000..5a4ec5c --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IMutableIncidenceGraph.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 617ac68d3ef3240bf83a07a340c3e6b6 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/IMutableUndirectedGraph.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IMutableUndirectedGraph.cs new file mode 100755 index 0000000..1c04545 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IMutableUndirectedGraph.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; + +namespace QuickGraph +{ + public interface IMutableUndirectedGraph : + IMutableEdgeListGraph, + IUndirectedGraph + where TEdge : IEdge + { + int RemoveAdjacentEdgeIf(TVertex vertex, EdgePredicate predicate); + void ClearAdjacentEdges(TVertex vertex); + + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/IMutableUndirectedGraph.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IMutableUndirectedGraph.cs.meta new file mode 100644 index 0000000..83034ce --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IMutableUndirectedGraph.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 84cb84bd5ae704832addcb42fdfa956f +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/IMutableVertexAndEdgeListGraph.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IMutableVertexAndEdgeListGraph.cs new file mode 100755 index 0000000..ef609fa --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IMutableVertexAndEdgeListGraph.cs @@ -0,0 +1,13 @@ +using System; + +namespace QuickGraph +{ + public interface IMutableVertexAndEdgeListGraph : + IMutableVertexListGraph, + IMutableEdgeListGraph, + IVertexAndEdgeListGraph + where TEdge : IEdge + { + bool AddVerticesAndEdge(TEdge e); + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/IMutableVertexAndEdgeListGraph.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IMutableVertexAndEdgeListGraph.cs.meta new file mode 100644 index 0000000..1fa714d --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IMutableVertexAndEdgeListGraph.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: f9094cb7a18d04733a3498c4fb56d64d +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/IMutableVertexListGraph.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IMutableVertexListGraph.cs new file mode 100755 index 0000000..f207346 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IMutableVertexListGraph.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; + +namespace QuickGraph +{ + public delegate bool EdgePredicate(TEdge e) + where TEdge : IEdge; + + public delegate bool VertexPredicate(TVertex v); + + public interface IMutableVertexListGraph : + IMutableIncidenceGraph, + IVertexListGraph + where TEdge : IEdge + { + event VertexEventHandler VertexAdded; + void AddVertex(TVertex v); + void AddVertexRange(IEnumerable vertices); + + event VertexEventHandler VertexRemoved; + bool RemoveVertex(TVertex v); + int RemoveVertexIf(VertexPredicate pred); + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/IMutableVertexListGraph.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IMutableVertexListGraph.cs.meta new file mode 100644 index 0000000..38acdad --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IMutableVertexListGraph.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: bef1ab22e478f4b9f8fe56da8b6cfcb5 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/IPredicate.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IPredicate.cs new file mode 100755 index 0000000..322f9d7 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IPredicate.cs @@ -0,0 +1,9 @@ +using System; + +namespace QuickGraph +{ + public interface IPredicate + { + bool Test(T t); + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/IPredicate.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IPredicate.cs.meta new file mode 100644 index 0000000..da7abfe --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IPredicate.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: fb703a21c4bdf48b4b4cbd9c89a67a47 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/IUndirectedGraph.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IUndirectedGraph.cs new file mode 100755 index 0000000..1060c55 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IUndirectedGraph.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; + +namespace QuickGraph +{ + public interface IUndirectedGraph : + IVertexAndEdgeSet, + IGraph + where TEdge : IEdge + { + IEnumerable AdjacentEdges(TVertex v); + int AdjacentDegree(TVertex v); + bool IsAdjacentEdgesEmpty(TVertex v); + TEdge AdjacentEdge(TVertex v, int index); + + bool ContainsEdge(TVertex source, TVertex target); + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/IUndirectedGraph.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IUndirectedGraph.cs.meta new file mode 100644 index 0000000..343f1ac --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IUndirectedGraph.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 70e83054455104f97b5197ca9ea02ba1 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/IVertexAndEdgeListGraph.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IVertexAndEdgeListGraph.cs new file mode 100755 index 0000000..01aba20 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IVertexAndEdgeListGraph.cs @@ -0,0 +1,11 @@ +using System; + +namespace QuickGraph +{ + public interface IVertexAndEdgeListGraph : + IVertexListGraph, + IEdgeListGraph, + IVertexAndEdgeSet + where TEdge : IEdge + {} +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/IVertexAndEdgeListGraph.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IVertexAndEdgeListGraph.cs.meta new file mode 100644 index 0000000..2a12d57 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IVertexAndEdgeListGraph.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 4f4c444d4914b4e3e98085c99ea5ac4f +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/IVertexAndEdgeSet.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IVertexAndEdgeSet.cs new file mode 100755 index 0000000..fbc1a57 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IVertexAndEdgeSet.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace QuickGraph +{ + public interface IVertexAndEdgeSet : + IVertexSet, + IEdgeListGraph + where TEdge : IEdge + { + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/IVertexAndEdgeSet.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IVertexAndEdgeSet.cs.meta new file mode 100644 index 0000000..3bffc9e --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IVertexAndEdgeSet.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 025f7bf79d2af427ab048d4e50691e7f +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/IVertexFactory.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IVertexFactory.cs new file mode 100755 index 0000000..ab59492 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IVertexFactory.cs @@ -0,0 +1,9 @@ +using System; + +namespace QuickGraph +{ + public interface IVertexFactory + { + TVertex CreateVertex(); + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/IVertexFactory.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IVertexFactory.cs.meta new file mode 100644 index 0000000..2331f52 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IVertexFactory.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 8b92d61fb306f4a028b182501424f70d +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/IVertexListGraph.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IVertexListGraph.cs new file mode 100755 index 0000000..61e095f --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IVertexListGraph.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; + +namespace QuickGraph +{ + public interface IVertexListGraph : + IIncidenceGraph, + IVertexSet + where TEdge : IEdge + { + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/IVertexListGraph.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IVertexListGraph.cs.meta new file mode 100644 index 0000000..bce3cef --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IVertexListGraph.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 0a82a088642ce4e32b5869e261cb7459 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/IVertexSet.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IVertexSet.cs new file mode 100755 index 0000000..60bc4a2 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IVertexSet.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace QuickGraph +{ + public interface IVertexSet + { + bool IsVerticesEmpty { get;} + int VertexCount { get;} + IEnumerable Vertices { get;} + bool ContainsVertex(TVertex vertex); + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/IVertexSet.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IVertexSet.cs.meta new file mode 100644 index 0000000..da9d579 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IVertexSet.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 1f548e9bd90b34eabacbeb22e430424b +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/IView.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IView.cs new file mode 100755 index 0000000..b7a7ad6 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IView.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace QuickGraph +{ + public interface IView + where TEdge : IEdge + { + IHierarchy Hierarchy { get;} + void Expand(TVertex vertex); + void Collapse(TVertex vertex); + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/IView.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IView.cs.meta new file mode 100644 index 0000000..f08be1d --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IView.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b9f7546e5357d4b789586a7c1ffc036d +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/IdentifiableEdge.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IdentifiableEdge.cs new file mode 100755 index 0000000..6202398 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IdentifiableEdge.cs @@ -0,0 +1,33 @@ +using System; + +namespace QuickGraph +{ + public class IdentifiableEdge : Edge, IIdentifiable + { + private string id; + + public IdentifiableEdge(string id, TVertex source, TVertex target) + : base(source, target) + { + this.id = id; + } + + public string ID + { + get { return this.id; } + } + + public override string ToString() + { + return this.id; + } + } + + public sealed class IdentifiableEdgeFactory : IIdentifiableEdgeFactory> + { + public IdentifiableEdge CreateEdge(string id, TVertex source, TVertex target) + { + return new IdentifiableEdge(id, source, target); + } + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/IdentifiableEdge.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IdentifiableEdge.cs.meta new file mode 100644 index 0000000..f28f834 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IdentifiableEdge.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: a4340b56909914a8eac85bcc017f991b +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/IdentifiableVertex.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IdentifiableVertex.cs new file mode 100755 index 0000000..a3765e5 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IdentifiableVertex.cs @@ -0,0 +1,34 @@ +using System; +using System.Collections.Generic; +using System.Xml.Serialization; + +namespace QuickGraph +{ + public class IdentifiableVertex : IIdentifiable + { + private string id; + + public IdentifiableVertex(string id) + { + this.id = id; + } + + public string ID + { + get { return this.id; } + } + + public override string ToString() + { + return this.id; + } + } + + public sealed class IdentifiableVertexFactory : IIdentifiableVertexFactory + { + public IdentifiableVertex CreateVertex(string id) + { + return new IdentifiableVertex(id); + } + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/IdentifiableVertex.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IdentifiableVertex.cs.meta new file mode 100644 index 0000000..8fdaf5d --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IdentifiableVertex.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 04fd1f235bda64e64a61ba929efffa79 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/IntVertexFactory.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IntVertexFactory.cs new file mode 100755 index 0000000..d8cb0cf --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IntVertexFactory.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace QuickGraph +{ + [Serializable] + public sealed class IntVertexFactory :IVertexFactory + { + private int current; + + public int CreateVertex() + { + return current++; + } + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/IntVertexFactory.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IntVertexFactory.cs.meta new file mode 100644 index 0000000..7b5180f --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/IntVertexFactory.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 111fb918911de4b9386e73cb91007134 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/NamedEdge.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/NamedEdge.cs new file mode 100755 index 0000000..e82b465 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/NamedEdge.cs @@ -0,0 +1,26 @@ +using System; + +namespace QuickGraph +{ + [Serializable] + public class NamedEdge : Edge + { + private readonly string name; + public NamedEdge(TVertex source, TVertex target, string name) + :base(source,target) + { + GraphContracts.AssumeNotNull(name, "name"); + this.name = name; + } + + public string Name + { + get { return this.name; } + } + + public override string ToString() + { + return this.Name; + } + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/NamedEdge.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/NamedEdge.cs.meta new file mode 100644 index 0000000..f10c7d0 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/NamedEdge.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 4a815de1dd19b4fb5a995543aa2eb3fb +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/NonAcyclicGraphException.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/NonAcyclicGraphException.cs new file mode 100755 index 0000000..f680131 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/NonAcyclicGraphException.cs @@ -0,0 +1,17 @@ +using System; + +namespace QuickGraph +{ + [Serializable] + public class NonAcyclicGraphException : ApplicationException + { + public NonAcyclicGraphException() { } + public NonAcyclicGraphException(string message) : base( message ) { } + public NonAcyclicGraphException(string message, System.Exception inner) : base( message, inner ) { } + protected NonAcyclicGraphException( + System.Runtime.Serialization.SerializationInfo info, + System.Runtime.Serialization.StreamingContext context) : base( info, context ) { } + } +} + + diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/NonAcyclicGraphException.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/NonAcyclicGraphException.cs.meta new file mode 100644 index 0000000..15ecd88 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/NonAcyclicGraphException.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e73657fedd18e48668c9563a9dc75920 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/NotStronglyConnectedGraphException.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/NotStronglyConnectedGraphException.cs new file mode 100755 index 0000000..ff5c833 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/NotStronglyConnectedGraphException.cs @@ -0,0 +1,14 @@ +using System; +namespace QuickGraph +{ + [System.Serializable] + public class NotStronglyConnectedGraphException : System.ApplicationException + { + public NotStronglyConnectedGraphException() { } + public NotStronglyConnectedGraphException(string message) : base( message ) { } + public NotStronglyConnectedGraphException(string message, System.Exception inner) : base( message, inner ) { } + protected NotStronglyConnectedGraphException( + System.Runtime.Serialization.SerializationInfo info, + System.Runtime.Serialization.StreamingContext context) : base( info, context ) { } + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/NotStronglyConnectedGraphException.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/NotStronglyConnectedGraphException.cs.meta new file mode 100644 index 0000000..5398500 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/NotStronglyConnectedGraphException.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 7e6bc7bef35bd414c91d584975e3ee09 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/ParallelEdgeNotAllowedException.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/ParallelEdgeNotAllowedException.cs new file mode 100755 index 0000000..94b0259 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/ParallelEdgeNotAllowedException.cs @@ -0,0 +1,15 @@ +using System; + +namespace QuickGraph +{ + [System.Serializable] + public class ParallelEdgeNotAllowedException : System.ApplicationException + { + public ParallelEdgeNotAllowedException() { } + public ParallelEdgeNotAllowedException(string message) : base( message ) { } + public ParallelEdgeNotAllowedException(string message, System.Exception inner) : base( message, inner ) { } + protected ParallelEdgeNotAllowedException( + System.Runtime.Serialization.SerializationInfo info, + System.Runtime.Serialization.StreamingContext context) : base( info, context ) { } + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/ParallelEdgeNotAllowedException.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/ParallelEdgeNotAllowedException.cs.meta new file mode 100644 index 0000000..606aba3 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/ParallelEdgeNotAllowedException.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 2d0add793b3a34dc2ba918a767969384 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Petri.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Petri.meta new file mode 100644 index 0000000..877e6a4 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Petri.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: eb431530743fa4a01a7a618b2492f4dd +folderAsset: yes +DefaultImporter: + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Petri/AllwaysTrueConditionExpression.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Petri/AllwaysTrueConditionExpression.cs new file mode 100755 index 0000000..5eb42aa --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Petri/AllwaysTrueConditionExpression.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; + +namespace QuickGraph.Petri +{ + [Serializable] + public sealed class AllwaysTrueConditionExpression : IConditionExpression + { + public bool IsEnabled(IList tokens) + { + return true; + } + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Petri/AllwaysTrueConditionExpression.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Petri/AllwaysTrueConditionExpression.cs.meta new file mode 100644 index 0000000..a67bada --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Petri/AllwaysTrueConditionExpression.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 2bc883b74e52e4f6196ffb5f734b49c9 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Petri/Arc.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Petri/Arc.cs new file mode 100755 index 0000000..5e620d2 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Petri/Arc.cs @@ -0,0 +1,73 @@ +using System; + +namespace QuickGraph.Petri +{ + [Serializable] + internal sealed class Arc : Edge, + IArc + { + private bool isInputArc; + private IPlace place; + private ITransition transition; + private IExpression annotation = new IdentityExpression(); + + public Arc(IPlace place, ITransition transition) + :base(place,transition) + { + this.place=place; + this.transition=transition; + this.isInputArc=true; + } + public Arc(ITransition transition,IPlace place) + :base(place,transition) + { + this.place=place; + this.transition=transition; + this.isInputArc=false; + } + + public bool IsInputArc + { + get + { + return this.isInputArc; + } + } + + public IPlace Place + { + get + { + return this.place; + } + } + + public ITransition Transition + { + get + { + return this.transition; + } + } + + public IExpression Annotation + { + get + { + return this.annotation; + } + set + { + this.annotation=value; + } + } + + public override string ToString() + { + if (this.IsInputArc) + return String.Format("{0} -> {1}",this.place,this.transition); + else + return String.Format("{0} -> {1}",this.transition,this.place); + } + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Petri/Arc.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Petri/Arc.cs.meta new file mode 100644 index 0000000..6e30383 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Petri/Arc.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: a978eddba0b404902958613263bd49d7 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Petri/IArc.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Petri/IArc.cs new file mode 100755 index 0000000..df90fd3 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Petri/IArc.cs @@ -0,0 +1,72 @@ +using System; + +namespace QuickGraph.Petri +{ + /// + /// A directed edge of a net which may connect a + /// to a or a to + /// a . + /// + /// + /// + /// Usually represented by an arrow. + /// + /// + public interface IArc : IEdge + { + /// + /// Gets or sets a value indicating if the + /// instance is a input arc. + /// + /// + /// + /// An arc that leads from an input to a + /// is called an Input Arc of + /// the transition. + /// + /// + bool IsInputArc {get;} + + /// + /// Gets or sets the instance attached to the + /// . + /// + /// + /// The attached to the . + /// + /// + /// set property, value is a null reference (Nothing in Visual Basic). + /// + IPlace Place {get;} + + /// + /// Gets or sets the instance attached to the + /// . + /// + /// + /// The attached to the . + /// + /// + /// set property, value is a null reference (Nothing in Visual Basic). + /// + ITransition Transition{get;} + + /// + /// Gets or sets the arc annotation. + /// + /// + /// The annotation instance. + /// + /// + /// + /// An expression that may involve constans, variables and operators + /// used to annotate the arc. The expression evaluates over the type + /// of the arc's associated place. + /// + /// + /// + /// set property, value is a null reference (Nothing in Visual Basic). + /// + IExpression Annotation {get;set;} + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Petri/IArc.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Petri/IArc.cs.meta new file mode 100644 index 0000000..ec5716a --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Petri/IArc.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 7ee7b0f50dfcc41b7b93b9e3a801e1be +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Petri/IConditionExpression.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Petri/IConditionExpression.cs new file mode 100755 index 0000000..7556282 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Petri/IConditionExpression.cs @@ -0,0 +1,10 @@ +using System; +using System.Collections.Generic; + +namespace QuickGraph.Petri +{ + public interface IConditionExpression + { + bool IsEnabled(IList tokens); + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Petri/IConditionExpression.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Petri/IConditionExpression.cs.meta new file mode 100644 index 0000000..c78cb9a --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Petri/IConditionExpression.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 571a1cefd96384e479e7b4d0daf0fa8a +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Petri/IExpression.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Petri/IExpression.cs new file mode 100755 index 0000000..818aad6 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Petri/IExpression.cs @@ -0,0 +1,10 @@ +using System; +using System.Collections.Generic; + +namespace QuickGraph.Petri +{ + public interface IExpression + { + IList Eval(IList marking); + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Petri/IExpression.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Petri/IExpression.cs.meta new file mode 100644 index 0000000..321f2d6 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Petri/IExpression.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 2d7812067b92945b787d5d85b8c79dfa +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Petri/IMutablePetriNet.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Petri/IMutablePetriNet.cs new file mode 100755 index 0000000..556d9a0 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Petri/IMutablePetriNet.cs @@ -0,0 +1,12 @@ +using System; + +namespace QuickGraph.Petri +{ + public interface IMutablePetriNet : IPetriNet + { + IPlace AddPlace(string name); + ITransition AddTransition(string name); + IArc AddArc(IPlace place, ITransition transition); + IArc AddArc(ITransition transition, IPlace place); + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Petri/IMutablePetriNet.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Petri/IMutablePetriNet.cs.meta new file mode 100644 index 0000000..4ac00d1 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Petri/IMutablePetriNet.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 51716fab6203e482f8f047de24c29ab6 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Petri/IPetriGraph.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Petri/IPetriGraph.cs new file mode 100755 index 0000000..89e15e0 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Petri/IPetriGraph.cs @@ -0,0 +1,7 @@ +using System; + +namespace QuickGraph.Petri +{ + public interface IPetriGraph : IMutableBidirectionalGraph> + {} +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Petri/IPetriGraph.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Petri/IPetriGraph.cs.meta new file mode 100644 index 0000000..27c0cbf --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Petri/IPetriGraph.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 1e2acb5dddcc04dbf84980c516ff88b7 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Petri/IPetriNet.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Petri/IPetriNet.cs new file mode 100755 index 0000000..5939ff4 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Petri/IPetriNet.cs @@ -0,0 +1,43 @@ +using System; +using System.Collections.Generic; + +namespace QuickGraph.Petri +{ + /// + /// A High Level Petri Graph. + /// + /// + /// + /// This object is called a Petri Net in honour of Petri's work. In fact, + /// it should be named High Level Petri Graph. + /// + /// + public interface IPetriNet + { + /// + /// Gets a collection of instances. + /// + /// + /// A collection of instances. + /// + IList> Places {get;} + + /// + /// Gets a collection of instances. + /// + /// + /// A collection of instances. + /// + IList> Transitions { get;} + + /// + /// Gets a collection of instances. + /// + /// + /// A collection of instances. + /// + IList> Arcs { get;} + + IPetriGraph Graph { get;} + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Petri/IPetriNet.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Petri/IPetriNet.cs.meta new file mode 100644 index 0000000..a6d229d --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Petri/IPetriNet.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 187e5a8292f4d401b8430565e7ef45b7 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Petri/IPetriVertex.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Petri/IPetriVertex.cs new file mode 100755 index 0000000..64252cb --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Petri/IPetriVertex.cs @@ -0,0 +1,18 @@ +using System; + +namespace QuickGraph.Petri +{ + /// + /// A vertex (node) of a Petri Graph. + /// + public interface IPetriVertex + { + /// + /// Gets or sets the name of the node + /// + /// + /// A representing the name of the node. + /// + String Name {get;} + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Petri/IPetriVertex.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Petri/IPetriVertex.cs.meta new file mode 100644 index 0000000..e87043a --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Petri/IPetriVertex.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: c3e0160ec1afc41239acf01ff59efedb +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Petri/IPlace.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Petri/IPlace.cs new file mode 100755 index 0000000..1569b65 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Petri/IPlace.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; + +namespace QuickGraph.Petri +{ + /// + /// A Place in the HLPN framework + /// + /// + /// + /// A is characterized by a set of tokens, called the + /// of the place. The place is typed + /// by the instance. This means only object + /// of assignable to can reside + /// in the place. + /// + /// + /// Usually represented by an ellipses (often circles). + /// + /// + public interface IPlace : IPetriVertex + { + IList Marking {get;} + + string ToStringWithMarking(); + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Petri/IPlace.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Petri/IPlace.cs.meta new file mode 100644 index 0000000..252d430 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Petri/IPlace.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 48948ea1afc404c8784fa5f490671f56 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Petri/ITransition.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Petri/ITransition.cs new file mode 100755 index 0000000..4d4d5d5 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Petri/ITransition.cs @@ -0,0 +1,20 @@ +using System; + +namespace QuickGraph.Petri +{ + /// + /// A node of a net, taken from the transition kind. + /// + /// + /// + /// Usually represented by a rectangle. + /// + /// + public interface ITransition : IPetriVertex + { + /// + /// A boolean expression associated with the transition + /// + IConditionExpression Condition {get;set;} + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Petri/ITransition.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Petri/ITransition.cs.meta new file mode 100644 index 0000000..e9f8ac8 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Petri/ITransition.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 1e0e98a11a7f14ef59fe4c8e96882c52 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Petri/IdentityExpression.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Petri/IdentityExpression.cs new file mode 100755 index 0000000..d7d6b5e --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Petri/IdentityExpression.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; + +namespace QuickGraph.Petri +{ + public sealed class IdentityExpression :IExpression + { + public IList Eval(IList marking) + { + return marking; + } + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Petri/IdentityExpression.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Petri/IdentityExpression.cs.meta new file mode 100644 index 0000000..4a042a0 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Petri/IdentityExpression.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 22d42e25780ad4fbcae00177a3096526 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Petri/PetriGraph.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Petri/PetriGraph.cs new file mode 100755 index 0000000..32ae96a --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Petri/PetriGraph.cs @@ -0,0 +1,14 @@ +using System; + +namespace QuickGraph.Petri +{ + [Serializable] + internal sealed class PetriGraph : + BidirectionalGraph>, + IPetriGraph + { + public PetriGraph() + :base(true) + { } + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Petri/PetriGraph.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Petri/PetriGraph.cs.meta new file mode 100644 index 0000000..e0d30bb --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Petri/PetriGraph.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: fc31dee79315f4b49afc0750e31bc20f +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Petri/PetriNet.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Petri/PetriNet.cs new file mode 100755 index 0000000..9d93738 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Petri/PetriNet.cs @@ -0,0 +1,104 @@ +using System; +using System.Collections.Generic; +using System.IO; + +namespace QuickGraph.Petri +{ + [Serializable] + public sealed class PetriNet : IMutablePetriNet + { + private List> places = new List>(); + private List> transitions = new List>(); + private List> arcs = new List>(); + private PetriGraph graph = new PetriGraph(); + + public PetriNet() + {} + + public IPetriGraph Graph + { + get + { + return this.graph; + } + } + + public IPlace AddPlace(string name) + { + IPlace p = new Place(name); + this.places.Add(p); + this.graph.AddVertex(p); + return p; + } + public ITransition AddTransition(string name) + { + ITransition tr = new Transition(name); + this.transitions.Add(tr); + this.graph.AddVertex(tr); + return tr; + } + public IArc AddArc(IPlace place, ITransition transition) + { + IArc arc = new Arc(place, transition); + this.arcs.Add(arc); + this.graph.AddEdge(arc); + return arc; + } + public IArc AddArc(ITransition transition,IPlace place) + { + IArc arc=new Arc(transition,place); + this.arcs.Add(arc); + this.graph.AddEdge(arc); + return arc; + } + + public IList> Places + { + get + { + return this.places; + } + } + + public IList> Transitions + { + get + { + return this.transitions; + } + } + + public IList> Arcs + { + get + { + return this.arcs; + } + } + + public override string ToString() + { + StringWriter sw = new StringWriter(); + sw.WriteLine("-----------------------------------------------"); + sw.WriteLine("Places ({0})",this.places.Count); + foreach (IPlace place in this.places) + { + sw.WriteLine("\t{0}",place.ToStringWithMarking()); + } + + sw.WriteLine("Transitions ({0})",this.transitions.Count); + foreach (ITransition transition in this.transitions) + { + sw.WriteLine("\t{0}",transition); + } + + sw.WriteLine("Arcs"); + foreach (IArc arc in this.arcs) + { + sw.WriteLine("\t{0}",arc); + } + return sw.ToString(); + } + + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Petri/PetriNet.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Petri/PetriNet.cs.meta new file mode 100644 index 0000000..e605a17 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Petri/PetriNet.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 82e27f8dd90a94acbb514c7fc2e1b81a +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Petri/PetriNetSimulator.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Petri/PetriNetSimulator.cs new file mode 100755 index 0000000..cd716d5 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Petri/PetriNetSimulator.cs @@ -0,0 +1,109 @@ +using System; +using System.Collections.Generic; + +namespace QuickGraph.Petri +{ + [Serializable] + public sealed class PetriNetSimulator + { + private IPetriNet net; + private Dictionary, TransitionBuffer> transitionBuffers = new Dictionary, TransitionBuffer>(); + + public PetriNetSimulator(IPetriNet net) + { + if (net == null) + throw new ArgumentNullException("net"); + this.net = net; + } + + public IPetriNet Net + { + get + { + return this.net; + } + } + + public void Initialize() + { + this.transitionBuffers.Clear(); + foreach(ITransition tr in this.Net.Transitions) + { + this.transitionBuffers.Add(tr, new TransitionBuffer()); + } + } + + public void SimulateStep() + { + // first step, iterate over arc and gather tokens in transitions + foreach(IArc arc in this.Net.Arcs) + { + if(!arc.IsInputArc) + continue; + + IList tokens = this.transitionBuffers[arc.Transition].Tokens; + // get annotated tokens + IList annotatedTokens = arc.Annotation.Eval(arc.Place.Marking); + //add annontated tokens + foreach(Token annotatedToken in annotatedTokens) + tokens.Add(annotatedToken); + } + + // second step, see which transition was enabled + foreach(ITransition tr in this.Net.Transitions) + { + // get buffered tokens + IList tokens = this.transitionBuffers[tr].Tokens; + // check if enabled, store value + this.transitionBuffers[tr].Enabled = tr.Condition.IsEnabled(tokens); + } + + // third step, iterate over the arcs + foreach(IArc arc in this.Net.Arcs) + { + if (!this.transitionBuffers[arc.Transition].Enabled) + continue; + + if(arc.IsInputArc) + { + // get annotated tokens + IList annotatedTokens = arc.Annotation.Eval(arc.Place.Marking); + // remove annotated comments from source place + foreach(Token annotatedToken in annotatedTokens) + arc.Place.Marking.Remove(annotatedToken); + } + else + { + IList tokens = this.transitionBuffers[arc.Transition].Tokens; + // get annotated tokens + IList annotatedTokens = arc.Annotation.Eval(tokens); + // IList annotated comments to target place + foreach(Token annotatedToken in annotatedTokens) + arc.Place.Marking.Add(annotatedToken); + } + } + // step four, clear buffers + foreach(ITransition tr in this.Net.Transitions) + { + this.transitionBuffers[tr].Tokens.Clear(); + this.transitionBuffers[tr].Enabled = false; + } + } + + private sealed class TransitionBuffer + { + private IList tokens = new List(); + private bool enabled = true; + + public IList Tokens + { + get { return this.tokens;} + } + public bool Enabled + { + get { return this.enabled; } + set { this.enabled = value; } + } + } + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Petri/PetriNetSimulator.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Petri/PetriNetSimulator.cs.meta new file mode 100644 index 0000000..48a178b --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Petri/PetriNetSimulator.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 6cad41f0e341d41148d5bf3b10acca25 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Petri/Place.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Petri/Place.cs new file mode 100755 index 0000000..a77b29f --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Petri/Place.cs @@ -0,0 +1,49 @@ +using System; +using System.Collections.Generic; +using System.IO; + +namespace QuickGraph.Petri +{ + [Serializable] + internal sealed class Place : IPlace + { + private string name; + private IList marking = new List(); + + public Place(string name) + { + this.name=name; + } + + public IList Marking + { + get + { + return this.marking; + } + } + + public String Name + { + get + { + return this.name; + } + } + + public string ToStringWithMarking() + { + StringWriter sw = new StringWriter(); + sw.WriteLine(this.ToString()); + foreach(object token in this.marking) + sw.WriteLine("\t{0}",token.GetType().Name); + + return sw.ToString(); + + } + public override string ToString() + { + return String.Format("P({0}|{1})",this.name,this.marking.Count); + } + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Petri/Place.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Petri/Place.cs.meta new file mode 100644 index 0000000..1abbf92 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Petri/Place.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d4fbf1953e38c45138d9c49c3cd38f44 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Petri/Transition.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Petri/Transition.cs new file mode 100755 index 0000000..82f7d1e --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Petri/Transition.cs @@ -0,0 +1,36 @@ +using System; + +namespace QuickGraph.Petri +{ + [Serializable] + internal sealed class Transition : ITransition + { + private string name; + private IConditionExpression condition = new AllwaysTrueConditionExpression(); + + public Transition(string name) + {this.name=name;} + + public IConditionExpression Condition + { + get + { + return this.condition; + } + set + { + this.condition=value; + } + } + + public string Name + { + get{return name;} + } + + public override string ToString() + { + return String.Format("T({0})",this.name); + } + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Petri/Transition.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Petri/Transition.cs.meta new file mode 100644 index 0000000..620be62 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Petri/Transition.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 64b2b6e1c40054eec84b16390d06770b +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Predicates.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Predicates.meta new file mode 100644 index 0000000..81ebf2d --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Predicates.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: 5fbd20515f48941528ee10c8397f5617 +folderAsset: yes +DefaultImporter: + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Predicates/AnyEdgePredicate.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Predicates/AnyEdgePredicate.cs new file mode 100755 index 0000000..6408907 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Predicates/AnyEdgePredicate.cs @@ -0,0 +1,14 @@ +using System; + +namespace QuickGraph.Predicates +{ + [Serializable] + public sealed class AnyEdgePredicate + where TEdge : IEdge + { + public bool Test(TEdge edge) + { + return true; + } + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Predicates/AnyEdgePredicate.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Predicates/AnyEdgePredicate.cs.meta new file mode 100644 index 0000000..d6626db --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Predicates/AnyEdgePredicate.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: cecd169aa868746678e86135e54e9c4b +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Predicates/AnyVertexPredicate.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Predicates/AnyVertexPredicate.cs new file mode 100755 index 0000000..460c8dd --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Predicates/AnyVertexPredicate.cs @@ -0,0 +1,13 @@ +using System; + +namespace QuickGraph.Predicates +{ + [Serializable] + public sealed class AnyVertexPredicate + { + public bool Test(TVertex vertex) + { + return true; + } + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Predicates/AnyVertexPredicate.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Predicates/AnyVertexPredicate.cs.meta new file mode 100644 index 0000000..c0b1945 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Predicates/AnyVertexPredicate.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 7f463f9d95e344b168420e236dca53ab +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Predicates/FilteredBidirectionalGraph.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Predicates/FilteredBidirectionalGraph.cs new file mode 100755 index 0000000..aef8712 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Predicates/FilteredBidirectionalGraph.cs @@ -0,0 +1,92 @@ +using System; +using System.Collections.Generic; + +namespace QuickGraph.Predicates +{ + [Serializable] + public class FilteredBidirectionalGraph : + FilteredVertexListGraph, + IBidirectionalGraph + where TEdge : IEdge + where TGraph : IVertexAndEdgeListGraph + { + public FilteredBidirectionalGraph( + TGraph baseGraph, + VertexPredicate vertexPredicate, + EdgePredicate edgePredicate + ) + :base(baseGraph,vertexPredicate,edgePredicate) + { } + + public bool IsInEdgesEmpty(TVertex v) + { + return this.InDegree(v) == 0; + } + + public int InDegree(TVertex v) + { + int count = 0; + foreach (var edge in this.InEdges(v)) + if (TestEdge(edge)) + count++; + return count; + } + + public IEnumerable InEdges(TVertex v) + { + foreach (var edge in this.InEdges(v)) + if (TestEdge(edge)) + yield return edge; + } + + public int Degree(TVertex v) + { + return this.OutDegree(v) + this.InDegree(v); + } + + public bool IsEdgesEmpty + { + get + { + foreach (var edge in this.BaseGraph.Edges) + if (TestEdge(edge)) + return false; + return true; + } + } + + public int EdgeCount + { + get + { + int count = 0; + foreach (var edge in this.BaseGraph.Edges) + if (TestEdge(edge)) + count++; + return count; + } + } + + public IEnumerable Edges + { + get + { + foreach (var edge in this.BaseGraph.Edges) + if (TestEdge(edge)) + yield return edge; + } + } + + public bool ContainsEdge(TEdge edge) + { + if (!TestEdge(edge)) + return false; + return this.BaseGraph.ContainsEdge(edge); + } + + public TEdge InEdge(TVertex v, int index) + { + throw new NotSupportedException(); + } + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Predicates/FilteredBidirectionalGraph.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Predicates/FilteredBidirectionalGraph.cs.meta new file mode 100644 index 0000000..2ca994c --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Predicates/FilteredBidirectionalGraph.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ae3019de17a6e4105ac4426a1e43045c +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Predicates/FilteredEdgeListGraph.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Predicates/FilteredEdgeListGraph.cs new file mode 100755 index 0000000..36e825c --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Predicates/FilteredEdgeListGraph.cs @@ -0,0 +1,71 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace QuickGraph.Predicates +{ + [Serializable] + public sealed class FilteredEdgeListGraph : + FilteredGraph, + IEdgeListGraph + where TGraph : IEdgeListGraph + where TEdge : IEdge + { + public FilteredEdgeListGraph( + TGraph baseGraph, + VertexPredicate vertexPredicate, + EdgePredicate edgePredicate + ) + :base(baseGraph, vertexPredicate, edgePredicate) + { + } + public bool IsEdgesEmpty + { + get + { + foreach(TEdge edge in this.Edges) + return false; + return true; + } + } + + public int EdgeCount + { + get + { + int count = 0; + foreach(TEdge edge in this.Edges) + count++; + return count; + } + } + + public IEnumerable Edges + { + get + { + foreach(TEdge edge in this.BaseGraph.Edges) + { + if ( + this.VertexPredicate(edge.Source) + && this.VertexPredicate(edge.Target) + && this.EdgePredicate(edge) + ) + yield return edge; + } + } + } + + public bool ContainsEdge(TEdge edge) + { + if ( + this.VertexPredicate(edge.Source) + && this.VertexPredicate(edge.Target) + && this.EdgePredicate(edge) + ) + return this.BaseGraph.ContainsEdge(edge); + else + return false; + } + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Predicates/FilteredEdgeListGraph.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Predicates/FilteredEdgeListGraph.cs.meta new file mode 100644 index 0000000..d8a923f --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Predicates/FilteredEdgeListGraph.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 64294ec0ba8fa413795327ec5852ba44 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Predicates/FilteredGraph.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Predicates/FilteredGraph.cs new file mode 100755 index 0000000..92cdbc9 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Predicates/FilteredGraph.cs @@ -0,0 +1,81 @@ +using System; + +namespace QuickGraph.Predicates +{ + [Serializable] + public class FilteredGraph : IGraph + where TEdge : IEdge + where TGraph : IGraph + { + private TGraph baseGraph; + private EdgePredicate edgePredicate; + private VertexPredicate vertexPredicate; + + public FilteredGraph( + TGraph baseGraph, + VertexPredicate vertexPredicate, + EdgePredicate edgePredicate + ) + { + if (baseGraph == null) + throw new ArgumentNullException("baseGraph"); + if (vertexPredicate == null) + throw new ArgumentNullException("vertexPredicate"); + if (edgePredicate == null) + throw new ArgumentNullException("edgePredicate"); + this.baseGraph = baseGraph; + this.vertexPredicate = vertexPredicate; + this.edgePredicate = edgePredicate; + } + + /// + /// Underlying filtered graph + /// + public TGraph BaseGraph + { + get + { + return baseGraph; + } + } + + /// + /// Edge predicate used to filter the edges + /// + public EdgePredicate EdgePredicate + { + get + { + return edgePredicate; + } + } + + public VertexPredicate VertexPredicate + { + get + { + return vertexPredicate; + } + } + + protected bool TestEdge(TEdge edge) + { + return this.VertexPredicate(edge.Source) + && this.VertexPredicate(edge.Target) + && this.EdgePredicate(edge); + } + + public bool IsDirected + { + get { return this.BaseGraph.IsDirected; } + } + + public bool AllowParallelEdges + { + get + { + return baseGraph.AllowParallelEdges; + } + } + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Predicates/FilteredGraph.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Predicates/FilteredGraph.cs.meta new file mode 100644 index 0000000..8ba1e4d --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Predicates/FilteredGraph.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 5cbe97477fbb84f58850c3c8f0750e72 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Predicates/FilteredImplicitGraph.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Predicates/FilteredImplicitGraph.cs new file mode 100755 index 0000000..6557826 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Predicates/FilteredImplicitGraph.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.Generic; + +namespace QuickGraph.Predicates +{ + [Serializable] + public class FilteredImplicitGraph : + FilteredGraph, + IImplicitGraph + where TEdge : IEdge + where TGraph : IImplicitGraph + { + public FilteredImplicitGraph( + TGraph baseGraph, + VertexPredicate vertexPredicate, + EdgePredicate edgePredicate + ) + :base(baseGraph,vertexPredicate,edgePredicate) + { } + + public bool IsOutEdgesEmpty(TVertex v) + { + return this.OutDegree(v) == 0; + } + + public int OutDegree(TVertex v) + { + int count =0; + foreach (var edge in this.BaseGraph.OutEdges(v)) + if (this.TestEdge(edge)) + count++; + return count; + } + + public IEnumerable OutEdges(TVertex v) + { + foreach (var edge in this.BaseGraph.OutEdges(v)) + if (this.TestEdge(edge)) + yield return edge; + } + + public TEdge OutEdge(TVertex v, int index) + { + throw new NotSupportedException(); + } + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Predicates/FilteredImplicitGraph.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Predicates/FilteredImplicitGraph.cs.meta new file mode 100644 index 0000000..c6b43c4 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Predicates/FilteredImplicitGraph.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: cf8673f01bcd1488a85b8e848a920008 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Predicates/FilteredIncidenceGraph.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Predicates/FilteredIncidenceGraph.cs new file mode 100755 index 0000000..3aca99c --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Predicates/FilteredIncidenceGraph.cs @@ -0,0 +1,80 @@ +using System; +using System.Collections.Generic; + +namespace QuickGraph.Predicates +{ + [Serializable] + public class FilteredIncidenceGraph : + FilteredImplicitGraph, + IIncidenceGraph + where TEdge : IEdge + where TGraph : IIncidenceGraph + { + public FilteredIncidenceGraph( + TGraph baseGraph, + VertexPredicate vertexPredicate, + EdgePredicate edgePredicate + ) + :base(baseGraph,vertexPredicate,edgePredicate) + {} + + public bool ContainsEdge(TVertex source, TVertex target) + { + if (!this.VertexPredicate(source)) + return false; + if (!this.VertexPredicate(target)) + return false; + + foreach (var edge in this.BaseGraph.OutEdges(source)) + if (edge.Target.Equals(target) && this.EdgePredicate(edge)) + return true; + return false; + } + + public bool TryGetEdge( + TVertex source, + TVertex target, + out TEdge edge) + { + IEnumerable unfilteredEdges; + if (this.VertexPredicate(source) && + this.VertexPredicate(target) && + this.BaseGraph.TryGetEdges(source, target, out unfilteredEdges)) + { + foreach (var ufe in unfilteredEdges) + if (this.EdgePredicate(ufe)) + { + edge = ufe; + return true; + } + } + edge = default(TEdge); + return false; + } + + public bool TryGetEdges( + TVertex source, + TVertex target, + out IEnumerable edges) + { + edges = null; + if (!this.VertexPredicate(source)) + return false; + if (!this.VertexPredicate(target)) + return false; + + IEnumerable unfilteredEdges; + if (this.BaseGraph.TryGetEdges(source, target, out unfilteredEdges)) + { + List filtered = new List(); + foreach (var edge in unfilteredEdges) + if (this.EdgePredicate(edge)) + filtered.Add(edge); + edges = filtered; + return true; + } + + return false; + } + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Predicates/FilteredIncidenceGraph.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Predicates/FilteredIncidenceGraph.cs.meta new file mode 100644 index 0000000..696a83e --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Predicates/FilteredIncidenceGraph.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 4f9b27f111ee74551b8e1b3a902eb811 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Predicates/FilteredUndirectedGraph.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Predicates/FilteredUndirectedGraph.cs new file mode 100755 index 0000000..b612d65 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Predicates/FilteredUndirectedGraph.cs @@ -0,0 +1,161 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace QuickGraph.Predicates +{ + [Serializable] + public sealed class FilteredUndirectedGraph : + FilteredGraph, + IUndirectedGraph + where TEdge : IEdge + where TGraph : IUndirectedGraph + { + public FilteredUndirectedGraph( + TGraph baseGraph, + VertexPredicate vertexPredicate, + EdgePredicate edgePredicate + ) + : base(baseGraph, vertexPredicate, edgePredicate) + { } + + public IEnumerable AdjacentEdges(TVertex v) + { + if (this.VertexPredicate(v)) + { + foreach (var edge in this.BaseGraph.AdjacentEdges(v)) + { + if (TestEdge(edge)) + yield return edge; + } + } + } + + public int AdjacentDegree(TVertex v) + { + int count = 0; + foreach (var edge in this.AdjacentEdges(v)) + count++; + return count; + } + + public bool IsAdjacentEdgesEmpty(TVertex v) + { + foreach (var edge in this.AdjacentEdges(v)) + return false; + return true; + } + + public TEdge AdjacentEdge(TVertex v, int index) + { + if (this.VertexPredicate(v)) + { + int count = 0; + foreach (var edge in this.AdjacentEdges(v)) + { + if (count == index) + return edge; + count++; + } + } + + throw new IndexOutOfRangeException(); + } + + public bool ContainsEdge(TVertex source, TVertex target) + { + if (!this.VertexPredicate(source)) + return false; + if (!this.VertexPredicate(target)) + return false; + if (!this.BaseGraph.ContainsEdge(source, target)) + return false; + // we need to find the edge + foreach (var edge in this.Edges) + { + if (edge.Source.Equals(source) && edge.Target.Equals(target) + && this.EdgePredicate(edge)) + return true; + } + + return false; + } + + public bool IsEdgesEmpty + { + get + { + foreach (var edge in this.Edges) + return false; + return true; + } + } + + public int EdgeCount + { + get + { + int count = 0; + foreach (var edge in this.Edges) + count++; + return count; + } + } + + public IEnumerable Edges + { + get + { + foreach (var edge in this.BaseGraph.Edges) + if (this.TestEdge(edge)) + yield return edge; + } + } + + public bool ContainsEdge(TEdge edge) + { + if (!this.TestEdge(edge)) + return false; + return this.BaseGraph.ContainsEdge(edge); + } + + public bool IsVerticesEmpty + { + get + { + foreach (var vertex in this.Vertices) + return false; + return true; + } + } + + public int VertexCount + { + get + { + int count = 0; + foreach (var vertex in this.Vertices) + count++; + return count; + } + } + + public IEnumerable Vertices + { + get + { + foreach (var vertex in this.BaseGraph.Vertices) + if (this.VertexPredicate(vertex)) + yield return vertex; + } + } + + public bool ContainsVertex(TVertex vertex) + { + if (!this.VertexPredicate(vertex)) + return false; + else + return this.BaseGraph.ContainsVertex(vertex); + } + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Predicates/FilteredUndirectedGraph.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Predicates/FilteredUndirectedGraph.cs.meta new file mode 100644 index 0000000..a7dba5f --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Predicates/FilteredUndirectedGraph.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ad496f4316c9e42e7b91caf61ee530dc +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Predicates/FilteredVertexAndEdgeListGraph.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Predicates/FilteredVertexAndEdgeListGraph.cs new file mode 100755 index 0000000..b809138 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Predicates/FilteredVertexAndEdgeListGraph.cs @@ -0,0 +1,69 @@ +using System; +using System.Collections.Generic; + +namespace QuickGraph.Predicates +{ + [Serializable] + public class FilteredVertexAndEdgeListGraph : + FilteredVertexListGraph, + IVertexAndEdgeListGraph + where TEdge : IEdge + where TGraph : IVertexAndEdgeListGraph + { + public FilteredVertexAndEdgeListGraph( + TGraph baseGraph, + VertexPredicate vertexPredicate, + EdgePredicate edgePredicate + ) + :base(baseGraph,vertexPredicate,edgePredicate) + { } + + public bool IsEdgesEmpty + { + get + { + return this.EdgeCount == 0; + } + } + + public int EdgeCount + { + get + { + int count = 0; + foreach (var edge in this.BaseGraph.Edges) + { + if ( + this.VertexPredicate(edge.Source) + && this.VertexPredicate(edge.Target) + && this.EdgePredicate(edge)) + count++; + } + return count; + } + } + + public IEnumerable Edges + { + get + { + foreach(TEdge edge in this.BaseGraph.Edges) + { + if ( + this.VertexPredicate(edge.Source) + && this.VertexPredicate(edge.Target) + && this.EdgePredicate(edge)) + yield return edge; + } + } + } + + public bool ContainsEdge(TEdge edge) + { + foreach (var e in this.Edges) + if (Comparison.Equals(edge, e)) + return true; + return false; + } + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Predicates/FilteredVertexAndEdgeListGraph.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Predicates/FilteredVertexAndEdgeListGraph.cs.meta new file mode 100644 index 0000000..9cec13d --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Predicates/FilteredVertexAndEdgeListGraph.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 9b8d60db21c374a7a9ce1ef6d4ba356d +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Predicates/FilteredVertexListGraph.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Predicates/FilteredVertexListGraph.cs new file mode 100755 index 0000000..6b1ce22 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Predicates/FilteredVertexListGraph.cs @@ -0,0 +1,58 @@ +using System; +using System.Collections.Generic; +namespace QuickGraph.Predicates +{ + [Serializable] + public class FilteredVertexListGraph : + FilteredIncidenceGraph, + IVertexListGraph + where TEdge : IEdge + where Graph : IVertexListGraph + { + public FilteredVertexListGraph( + Graph baseGraph, + VertexPredicate vertexPredicate, + EdgePredicate edgePredicate + ) + :base(baseGraph,vertexPredicate,edgePredicate) + { } + + public bool IsVerticesEmpty + { + get + { + foreach (var v in this.Vertices) + return false; + return true; + } + } + + public int VertexCount + { + get + { + int count = 0; + foreach (var v in this.Vertices) + count++; + return count; + } + } + + public IEnumerable Vertices + { + get + { + foreach (var v in this.BaseGraph.Vertices) + if (this.VertexPredicate(v)) + yield return v; + } + } + + public bool ContainsVertex(TVertex vertex) + { + if (!this.VertexPredicate(vertex)) + return false; + return this.ContainsVertex(vertex); + } + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Predicates/FilteredVertexListGraph.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Predicates/FilteredVertexListGraph.cs.meta new file mode 100644 index 0000000..5da0fd2 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Predicates/FilteredVertexListGraph.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 0a13407d7965d40f489f97a8575361de +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Predicates/InDictionaryVertexPredicate.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Predicates/InDictionaryVertexPredicate.cs new file mode 100755 index 0000000..98eaff3 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Predicates/InDictionaryVertexPredicate.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; + +namespace QuickGraph.Predicates +{ + [Serializable] + public sealed class InDictionaryVertexPredicate + { + private IDictionary dictionary; + + public InDictionaryVertexPredicate( + IDictionary dictionary) + { + this.dictionary = dictionary; + } + + public bool Test(TVertex v) + { + if (v == null) + throw new ArgumentNullException("v"); + return this.dictionary.ContainsKey(v); + } + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Predicates/InDictionaryVertexPredicate.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Predicates/InDictionaryVertexPredicate.cs.meta new file mode 100644 index 0000000..3f96420 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Predicates/InDictionaryVertexPredicate.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e1890ebbd76bd4de2a94b5a6f61e9e90 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Predicates/IsolatedVertexPredicate.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Predicates/IsolatedVertexPredicate.cs new file mode 100755 index 0000000..593a476 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Predicates/IsolatedVertexPredicate.cs @@ -0,0 +1,21 @@ +using System; + +namespace QuickGraph.Predicates +{ + public sealed class IsolatedVertexPredicate + where TEdge : IEdge + { + private IBidirectionalGraph visitedGraph; + + public IsolatedVertexPredicate(IBidirectionalGraph visitedGraph) + { + this.visitedGraph = visitedGraph; + } + + public bool Test(TVertex v) + { + return this.visitedGraph.IsInEdgesEmpty(v) + && this.visitedGraph.IsOutEdgesEmpty(v); + } + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Predicates/IsolatedVertexPredicate.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Predicates/IsolatedVertexPredicate.cs.meta new file mode 100644 index 0000000..d6c05ec --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Predicates/IsolatedVertexPredicate.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: abdeeb51692a9411ba012bd6b5125ff2 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Predicates/ResidualEdgePrediate.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Predicates/ResidualEdgePrediate.cs new file mode 100755 index 0000000..77c2dbf --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Predicates/ResidualEdgePrediate.cs @@ -0,0 +1,35 @@ +using System; +using System.Collections.Generic; + +namespace QuickGraph.Predicates +{ + public sealed class ResidualEdgePredicate + where TEdge : IEdge + { + private IDictionary residualCapacities; + + public ResidualEdgePredicate( + IDictionary residualCapacities) + { + if (residualCapacities == null) + throw new ArgumentNullException("residualCapacities"); + this.residualCapacities = residualCapacities; + } + + public IDictionary ResidualCapacities + { + get + { + return this.residualCapacities; + } + } + + public bool Test(TEdge e) + { + if (e == null) + throw new ArgumentNullException("e"); + + return 0 < this.residualCapacities[e]; + } + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Predicates/ResidualEdgePrediate.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Predicates/ResidualEdgePrediate.cs.meta new file mode 100644 index 0000000..25629e3 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Predicates/ResidualEdgePrediate.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 0f90b18959e824cbf9f43323dde682b3 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Predicates/ReversedResidualEdgePredicate.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Predicates/ReversedResidualEdgePredicate.cs new file mode 100755 index 0000000..b710a4f --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Predicates/ReversedResidualEdgePredicate.cs @@ -0,0 +1,54 @@ +using System; +using System.Collections.Generic; +namespace QuickGraph.Predicates +{ + [Serializable] + public sealed class ReversedResidualEdgePredicate + where TEdge : IEdge + { + private IDictionary residualCapacities; + private IDictionary reversedEdges; + + public ReversedResidualEdgePredicate( + IDictionary residualCapacities, + IDictionary reversedEdges) + { + if (residualCapacities == null) + throw new ArgumentNullException("residualCapacities"); + if (reversedEdges == null) + throw new ArgumentNullException("reversedEdges"); + this.residualCapacities = residualCapacities; + this.reversedEdges = reversedEdges; + } + + /// + /// Residual capacities map + /// + public IDictionary ResidualCapacities + { + get + { + return this.residualCapacities; + } + } + + /// + /// Reversed edges map + /// + public IDictionary ReversedEdges + { + get + { + return this.reversedEdges; + } + } + + public bool Test(TEdge e) + { + if (e == null) + throw new ArgumentNullException("e"); + + return 0 < this.residualCapacities[reversedEdges[e]]; + } + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Predicates/ReversedResidualEdgePredicate.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Predicates/ReversedResidualEdgePredicate.cs.meta new file mode 100644 index 0000000..89f1cf6 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Predicates/ReversedResidualEdgePredicate.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 210290ab67b6148f29a617e0e2ace6c6 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Predicates/SinkVertexPredicate.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Predicates/SinkVertexPredicate.cs new file mode 100755 index 0000000..3247cf4 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Predicates/SinkVertexPredicate.cs @@ -0,0 +1,23 @@ +using System; + +namespace QuickGraph.Predicates +{ + [Serializable] + public sealed class SinkVertexPredicate + where TEdge : IEdge + { + private IIncidenceGraph visitedGraph; + + public SinkVertexPredicate(IIncidenceGraph visitedGraph) + { + if (visitedGraph == null) + throw new ArgumentNullException("visitedGraph"); + this.visitedGraph = visitedGraph; + } + + public bool Test(TVertex v) + { + return this.visitedGraph.IsOutEdgesEmpty(v); + } + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Predicates/SinkVertexPredicate.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Predicates/SinkVertexPredicate.cs.meta new file mode 100644 index 0000000..e170f0d --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Predicates/SinkVertexPredicate.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 22cd39f5c3ec64dc2b1321d43118a1d4 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/QuickGraph.csproj b/src/Assets/quickgraph4unity/Runtime/QuickGraph/QuickGraph.csproj new file mode 100755 index 0000000..8e8fbab --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/QuickGraph.csproj @@ -0,0 +1,273 @@ + + + Debug + AnyCPU + 9.0.30729 + 2.0 + {A9A5C115-0680-44B3-A87E-5ECF4C93814E} + Library + QuickGraph + QuickGraph + 4 + quickgraph.snk + File + true + SAK + SAK + SAK + SAK + + + 2.0 + + + + + true + full + false + .\bin\Debug\ + DEBUG;TRACE + true + 4 + + + Off + 1591 + + + false + true + .\bin\Release\ + TRACE + + + Off + + + + + + + + + + Properties\version.cs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Code + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Code + + + + + + + + + Code + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/QuickGraph.csproj.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/QuickGraph.csproj.meta new file mode 100644 index 0000000..6514e97 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/QuickGraph.csproj.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: 3f5b494f5091c4385a69c3c4654840fd +DefaultImporter: + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/QuickGraph.csproj.vspscc b/src/Assets/quickgraph4unity/Runtime/QuickGraph/QuickGraph.csproj.vspscc new file mode 100755 index 0000000..feffdec --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/QuickGraph.csproj.vspscc @@ -0,0 +1,10 @@ +"" +{ +"FILE_VERSION" = "9237" +"ENLISTMENT_CHOICE" = "NEVER" +"PROJECT_FILE_RELATIVE_PATH" = "" +"NUMBER_OF_EXCLUDED_FILES" = "0" +"ORIGINAL_PROJECT_FILE_PATH" = "" +"NUMBER_OF_NESTED_PROJECTS" = "0" +"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROVIDER" +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/QuickGraph.csproj.vspscc.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/QuickGraph.csproj.vspscc.meta new file mode 100644 index 0000000..9a4f388 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/QuickGraph.csproj.vspscc.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: b7e71bab2d13e4f4f9b8f08150a23329 +DefaultImporter: + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/QuickGraphResourceManager.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/QuickGraphResourceManager.cs new file mode 100755 index 0000000..3b03996 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/QuickGraphResourceManager.cs @@ -0,0 +1,35 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Drawing; +using System.IO; + +namespace QuickGraph +{ + public static class QuickGraphResourceManager + { + public static Image GetLogo() + { + return GetImage("quickgraph"); + } + + public static Image GetBanner() + { + return GetImage("quickgraph.banner"); + } + + private static Image GetImage(string name) + { + using (Stream stream = typeof(QuickGraphResourceManager).Assembly.GetManifestResourceStream(String.Format("QuickGraph.{0}.png", name))) + return Image.FromStream(stream); + } + + public static void DumpResources(string path) + { + if (String.IsNullOrEmpty(path)) + throw new ArgumentNullException("path"); + GetLogo().Save(Path.Combine(path, "quickgraph.png"), System.Drawing.Imaging.ImageFormat.Png); + GetBanner().Save(Path.Combine(path, "quickgraph.banner.png"), System.Drawing.Imaging.ImageFormat.Png); + } + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/QuickGraphResourceManager.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/QuickGraphResourceManager.cs.meta new file mode 100644 index 0000000..f010871 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/QuickGraphResourceManager.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: f466ffd1f349a4baaa902bda1b5e0eb6 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/ReversedBidirectionalListGraph.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/ReversedBidirectionalListGraph.cs new file mode 100755 index 0000000..7dde126 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/ReversedBidirectionalListGraph.cs @@ -0,0 +1,175 @@ +using System; +using System.Collections.Generic; + +namespace QuickGraph +{ + public sealed class ReversedBidirectionalGraph : + IBidirectionalGraph> + where TEdge : IEdge + { + private readonly IBidirectionalGraph originalGraph; + public ReversedBidirectionalGraph(IBidirectionalGraph originalGraph) + { + if (originalGraph==null) + throw new ArgumentNullException("originalGraph"); + this.originalGraph = originalGraph; + } + + public IBidirectionalGraph OriginalGraph + { + get { return this.originalGraph;} + } + + public bool IsVerticesEmpty + { + get { return this.OriginalGraph.IsVerticesEmpty; } + } + + public bool IsDirected + { + get { return this.OriginalGraph.IsDirected; } + } + + public bool AllowParallelEdges + { + get { return this.OriginalGraph.AllowParallelEdges; } + } + + public int VertexCount + { + get { return this.OriginalGraph.VertexCount; } + } + + public IEnumerable Vertices + { + get { return this.OriginalGraph.Vertices; } + } + + + public bool ContainsVertex(TVertex vertex) + { + return this.OriginalGraph.ContainsVertex(vertex); + } + + public bool ContainsEdge(TVertex source, TVertex target) + { + return this.OriginalGraph.ContainsEdge(target,source); + } + + public bool TryGetEdge( + TVertex source, + TVertex target, + out ReversedEdge edge) + { + TEdge oedge; + if (this.OriginalGraph.TryGetEdge(target, source, out oedge)) + { + edge = new ReversedEdge(oedge); + return true; + } + else + { + edge = default(ReversedEdge); + return false; + } + } + + public bool TryGetEdges( + TVertex source, + TVertex target, + out IEnumerable> edges) + { + IEnumerable oedges; + if (this.OriginalGraph.TryGetEdges(target, source, out oedges)) + { + List> list = new List>(); + foreach (var oedge in oedges) + list.Add(new ReversedEdge(oedge)); + edges = list; + return true; + } + else + { + edges = null; + return false; + } + } + + public bool IsOutEdgesEmpty(TVertex v) + { + return this.OriginalGraph.IsInEdgesEmpty(v); + } + + public int OutDegree(TVertex v) + { + return this.OriginalGraph.InDegree(v); + } + + public IEnumerable> InEdges(TVertex v) + { + foreach(TEdge edge in this.OriginalGraph.OutEdges(v)) + yield return new ReversedEdge(edge); + } + + public ReversedEdge InEdge(TVertex v, int index) + { + TEdge edge = this.OriginalGraph.OutEdge(v, index); + if (edge == null) + return default(ReversedEdge); + return new ReversedEdge(edge); + } + + public bool IsInEdgesEmpty(TVertex v) + { + return this.OriginalGraph.IsOutEdgesEmpty(v); + } + + public int InDegree(TVertex v) + { + return this.OriginalGraph.OutDegree(v); + } + + public IEnumerable> OutEdges(TVertex v) + { + foreach(TEdge edge in this.OriginalGraph.InEdges(v)) + yield return new ReversedEdge(edge); + } + + public ReversedEdge OutEdge(TVertex v, int index) + { + TEdge edge = this.OriginalGraph.InEdge(v, index); + if (edge == null) + return default(ReversedEdge); + return new ReversedEdge(edge); + } + + public IEnumerable> Edges + { + get + { + foreach(TEdge edge in this.OriginalGraph.Edges) + yield return new ReversedEdge(edge); + } + } + + public bool ContainsEdge(ReversedEdge edge) + { + return this.OriginalGraph.ContainsEdge(edge.OriginalEdge); + } + + public int Degree(TVertex v) + { + return this.OriginalGraph.Degree(v); + } + + public bool IsEdgesEmpty + { + get { return this.OriginalGraph.IsEdgesEmpty; } + } + + public int EdgeCount + { + get { return this.OriginalGraph.EdgeCount; } + } + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/ReversedBidirectionalListGraph.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/ReversedBidirectionalListGraph.cs.meta new file mode 100644 index 0000000..699f815 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/ReversedBidirectionalListGraph.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e269240fbe4c24ee6b02b4df55b1b619 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/ReversedEdge.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/ReversedEdge.cs new file mode 100755 index 0000000..5f6486b --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/ReversedEdge.cs @@ -0,0 +1,55 @@ +using System; + +namespace QuickGraph +{ + public struct ReversedEdge : + IEdge, + IEquatable> + where TEdge : IEdge + { + private readonly TEdge originalEdge; + public ReversedEdge(TEdge originalEdge) + { + GraphContracts.AssumeNotNull(originalEdge, "originalEdge"); + this.originalEdge = originalEdge; + } + + public TEdge OriginalEdge + { + get { return this.originalEdge; } + } + + public TVertex Source + { + get { return this.OriginalEdge.Target; } + } + + public TVertex Target + { + get { return this.OriginalEdge.Source; } + } + + public override bool Equals(object obj) + { + if (!(obj is ReversedEdge)) + return false; + + return Equals((ReversedEdge)obj); + } + + public override int GetHashCode() + { + return this.OriginalEdge.GetHashCode(); + } + + public override string ToString() + { + return String.Format("R({0})", this.OriginalEdge); + } + + public bool Equals(ReversedEdge other) + { + return this.OriginalEdge.Equals(other.OriginalEdge); + } + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/ReversedEdge.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/ReversedEdge.cs.meta new file mode 100644 index 0000000..68349b7 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/ReversedEdge.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 4a759536443b04adbbdecac8a6bc4de3 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/RootVertexNotSpecifiedException.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/RootVertexNotSpecifiedException.cs new file mode 100755 index 0000000..1ee7d5f --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/RootVertexNotSpecifiedException.cs @@ -0,0 +1,15 @@ +using System; + +namespace QuickGraph +{ + [System.Serializable] + public class RootVertexNotSpecifiedException : System.ApplicationException + { + public RootVertexNotSpecifiedException() { } + public RootVertexNotSpecifiedException(string message) : base( message ) { } + public RootVertexNotSpecifiedException(string message, System.Exception inner) : base( message, inner ) { } + protected RootVertexNotSpecifiedException( + System.Runtime.Serialization.SerializationInfo info, + System.Runtime.Serialization.StreamingContext context) : base( info, context ) { } + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/RootVertexNotSpecifiedException.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/RootVertexNotSpecifiedException.cs.meta new file mode 100644 index 0000000..1415df3 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/RootVertexNotSpecifiedException.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 97a5fce77186e4ec083824f55763505c +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Serialization.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Serialization.meta new file mode 100644 index 0000000..963c274 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Serialization.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: 79e8f7f7f1edf4ef5bb684fa623651e3 +folderAsset: yes +DefaultImporter: + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Serialization/GraphMLSerializer.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Serialization/GraphMLSerializer.cs new file mode 100755 index 0000000..8f523f5 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Serialization/GraphMLSerializer.cs @@ -0,0 +1,702 @@ +using System; +using System.Collections.Generic; +using System.Xml; +using System.IO; +using System.Text; +using System.Reflection; +using System.Xml.Serialization; +using System.Reflection.Emit; + +namespace QuickGraph.Serialization +{ + /// + /// A GraphML ( http://graphml.graphdrawing.org/ ) format serializer. + /// + /// + /// + /// + /// + /// Custom vertex and edge attributes can be specified by + /// using the + /// attribute on properties (field not suppored). + /// + /// + /// The serializer uses LCG (lightweight code generation) to generate the + /// methods that writes the attributes to avoid paying the price of + /// Reflection on each vertex/edge. Since nothing is for free, the first + /// time you will use the serializer *on a particular pair of types*, it + /// will have to bake that method. + /// + /// + /// Hyperedge, nodes, nested graphs not supported. + /// + /// + public sealed class GraphMLSerializer + : SerializerBase + where TVertex : IIdentifiable + where TEdge : IIdentifiable, IEdge + { + #region Attributes + private delegate void WriteVertexAttributesDelegate( + XmlWriter writer, + TVertex v); + private delegate void WriteEdgeAttributesDelegate( + XmlWriter writer, + TEdge e); + private delegate void ReadVertexAttributesDelegate( + XmlReader reader, + TVertex v); + private delegate void ReadEdgeAttributesDelegate( + XmlReader reader, + TEdge e); + + private static class DelegateCompiler + { + private static readonly object syncRoot = new object(); + private static WriteVertexAttributesDelegate writeVertexAttributesDelegate; + private static WriteEdgeAttributesDelegate writeEdgeAttributesDelegate; + private static ReadVertexAttributesDelegate readVertexAttributesDelegate; + private static ReadEdgeAttributesDelegate readEdgeAttributesDelegate; + + public static WriteVertexAttributesDelegate VertexAttributesWriter + { + get + { + lock (syncRoot) + { + if (writeVertexAttributesDelegate == null) + DelegateCompiler.CreateWriteDelegates(); + return writeVertexAttributesDelegate; + } + } + } + + public static WriteEdgeAttributesDelegate EdgeAttributesWriter + { + get + { + lock (syncRoot) + { + if (writeEdgeAttributesDelegate == null) + DelegateCompiler.CreateWriteDelegates(); + return writeEdgeAttributesDelegate; + } + } + } + + public static ReadVertexAttributesDelegate VertexAttributesReader + { + get + { + lock (syncRoot) + { + if (readVertexAttributesDelegate == null) + DelegateCompiler.CreateReadDelegates(); + return readVertexAttributesDelegate; + } + } + } + + public static ReadEdgeAttributesDelegate EdgeAttributesReader + { + get + { + lock (syncRoot) + { + if (readEdgeAttributesDelegate == null) + DelegateCompiler.CreateReadDelegates(); + return readEdgeAttributesDelegate; + } + } + } + + public static void CreateReadDelegates() + { + readVertexAttributesDelegate = + (ReadVertexAttributesDelegate)CreateReadDelegate( + typeof(ReadVertexAttributesDelegate), + typeof(TVertex), + "id" + ); + readEdgeAttributesDelegate = + (ReadEdgeAttributesDelegate)CreateReadDelegate( + typeof(ReadEdgeAttributesDelegate), + typeof(TEdge), + "id", "source", "target" + ); + } + + public static void CreateWriteDelegates() + { + writeVertexAttributesDelegate = + (WriteVertexAttributesDelegate)CreateWriteDelegate( + typeof(TVertex), + typeof(WriteVertexAttributesDelegate)); + writeEdgeAttributesDelegate = + (WriteEdgeAttributesDelegate)CreateWriteDelegate( + typeof(TEdge), + typeof(WriteEdgeAttributesDelegate) + ); + } + + public static Delegate CreateWriteDelegate(Type nodeType, Type delegateType) + { + DynamicMethod method = new DynamicMethod( + "Write"+delegateType.Name + nodeType.Name, + typeof(void), + new Type[] { typeof(XmlWriter), nodeType }, + nodeType.Module + ); + ILGenerator gen = method.GetILGenerator(); + + MethodInfo writeStartElement = + typeof(XmlWriter).GetMethod( + "WriteStartElement", + BindingFlags.Instance | BindingFlags.Public, + null, + new Type[] { typeof(string) }, + null); + MethodInfo writeEndElement = + typeof(XmlWriter).GetMethod( + "WriteEndElement", + BindingFlags.Instance | BindingFlags.Public, + null, + new Type[] { }, + null); + MethodInfo writeString = + typeof(XmlWriter).GetMethod( + "WriteString", + BindingFlags.Instance | BindingFlags.Public, + null, + new Type[] { typeof(string) }, + null); + MethodInfo writeAttributeString = + typeof(XmlWriter).GetMethod( + "WriteAttributeString", + BindingFlags.Instance | BindingFlags.Public, + null, + new Type[] { typeof(string), typeof(string) }, + null); + MethodInfo toString = typeof(object).GetMethod( + "ToString", + BindingFlags.Public | BindingFlags.Instance, + null, + new Type[] { }, + null); + + foreach (KeyValuePair kv in SerializationHelper.GetAttributeProperties(nodeType)) + { + // for each property of the type, + // write it to the xmlwriter (we need to take care of value types, etc...) + // writer.WriteStartElement("data") + gen.Emit(OpCodes.Ldarg_0); + gen.Emit(OpCodes.Ldstr, "data"); + gen.EmitCall(OpCodes.Callvirt, writeStartElement, null); + + // writer.WriteAttributeString("key", name); + gen.Emit(OpCodes.Ldarg_0); + gen.Emit(OpCodes.Ldstr, "key"); + gen.Emit(OpCodes.Ldstr, kv.Value); + gen.EmitCall(OpCodes.Callvirt, writeAttributeString, null); + + + // writer.WriteString(v.xxx); + gen.Emit(OpCodes.Ldarg_0); + + // we now need to load the vertex and invoke the property + // load vertex + gen.Emit(OpCodes.Ldarg_1); + // invoke property + MethodInfo getMethod = kv.Key.GetGetMethod(); + gen.EmitCall( + (getMethod.IsVirtual) ? OpCodes.Callvirt : OpCodes.Call, + getMethod, + null); + + // since XmlWrite takes to string, we need to convert that + // object to a string... + // of course, if it's a string, we don't need to do anything + Type propertyType = kv.Key.PropertyType; + if (propertyType != typeof(string)) + { + // if it's a value type, it has to be boxed before + // invoking ToString + if (propertyType.IsValueType) + gen.Emit(OpCodes.Box, propertyType); + gen.Emit( + (toString.IsVirtual) ? OpCodes.Callvirt : OpCodes.Call, + toString); + } + + // we now have two string on the stack... + gen.EmitCall(OpCodes.Callvirt, writeString, null); + + // writer.WriteEndElement() + gen.Emit(OpCodes.Ldarg_0); + gen.EmitCall(OpCodes.Callvirt, writeEndElement, null); + } + + gen.Emit(OpCodes.Ret); + + //let's bake the method + return method.CreateDelegate(delegateType); + } + + public static Delegate CreateReadDelegate( + Type delegateType, + Type elementType, + params string[] ignoredAttributes + ) + { + DynamicMethod method = new DynamicMethod( + "Read"+elementType.Name, + typeof(void), + new Type[] { typeof(XmlReader), elementType }, + elementType.Module + ); + ILGenerator gen = method.GetILGenerator(); + + MethodInfo readToFollowing = + typeof(XmlReader).GetMethod( + "ReadToFollowing", + BindingFlags.Instance | BindingFlags.Public, + null, + new Type[] { typeof(string) }, + null); + MethodInfo getAttribute = + typeof(XmlReader).GetMethod( + "GetAttribute", + BindingFlags.Instance | BindingFlags.Public, + null, + new Type[] { typeof(string) }, + null); + MethodInfo stringEquals = + typeof(string).GetMethod( + "op_Equality", + BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public, + null, + new Type[] { typeof(string), typeof(string) }, + null); + ConstructorInfo argumentException = + typeof(ArgumentException).GetConstructor(new Type[] { }); + + + // read content as methods + Dictionary readContentMethods = new Dictionary(); + readContentMethods.Add(typeof(int), typeof(XmlReader).GetMethod("ReadElementContentAsInt", new Type[] { })); + readContentMethods.Add(typeof(double), typeof(XmlReader).GetMethod("ReadElementContentAsDouble", new Type[] { })); + readContentMethods.Add(typeof(bool), typeof(XmlReader).GetMethod("ReadElementContentAsBoolean", new Type[] { })); + readContentMethods.Add(typeof(DateTime), typeof(XmlReader).GetMethod("ReadElementContentAsDateTime", new Type[] { })); + readContentMethods.Add(typeof(long), typeof(XmlReader).GetMethod("ReadElementContentAsLong", new Type[] { })); + readContentMethods.Add(typeof(string), typeof(XmlReader).GetMethod("ReadElementContentAsString", new Type[] { })); + + + LocalBuilder key= gen.DeclareLocal(typeof(string)); + + Label start = gen.DefineLabel(); + Label doWhile = gen.DefineLabel(); + + gen.Emit(OpCodes.Br_S, doWhile); + gen.MarkLabel(start); + gen.Emit(OpCodes.Ldarg_0); + gen.Emit(OpCodes.Ldstr, "key"); + gen.EmitCall(OpCodes.Callvirt, getAttribute, null); + gen.Emit(OpCodes.Stloc_0); + + + // if (key.Equals("id")) continue; + foreach (string ignoredAttribute in ignoredAttributes) + { + gen.Emit(OpCodes.Ldloc_0); + gen.Emit(OpCodes.Ldstr, ignoredAttribute); + gen.EmitCall(OpCodes.Call, stringEquals, null); + gen.Emit(OpCodes.Brtrue_S, doWhile); + } + + // we need to create the swicth for each property + Label next = gen.DefineLabel(); + bool first = true; + foreach (KeyValuePair kv in SerializationHelper.GetAttributeProperties(elementType)) + { + if (!first) + { + gen.MarkLabel(next); + next = gen.DefineLabel(); + } + first = false; + + // if (!key.Equals("foo")) + gen.Emit(OpCodes.Ldloc_0); + gen.Emit(OpCodes.Ldstr, kv.Value); + gen.EmitCall(OpCodes.Callvirt, stringEquals,null); + // if false jump to next + gen.Emit(OpCodes.Brfalse_S, next); + + // do our stuff + MethodInfo readMethod = null; + if (!readContentMethods.TryGetValue(kv.Key.PropertyType, out readMethod)) + throw new ArgumentException(String.Format("Property {0} has a non-supported type",kv.Key.Name)); + + // do we have a set method ? + MethodInfo setMethod = kv.Key.GetSetMethod(); + if (setMethod==null) + throw new ArgumentException( + String.Format("Property {0} is readonly", kv.Key.Name) + ); + // reader.ReadXXX + gen.Emit(OpCodes.Ldarg_1); + gen.Emit(OpCodes.Ldarg_0); + gen.EmitCall(OpCodes.Callvirt, readMethod, null); + gen.EmitCall(OpCodes.Callvirt, setMethod, null); + + // jump to do while + gen.Emit(OpCodes.Br_S, doWhile); + } + + // we don't know this parameter.. we throw + gen.MarkLabel(next); + gen.Emit(OpCodes.Newobj, argumentException); + gen.Emit(OpCodes.Throw); + + gen.MarkLabel(doWhile); + gen.Emit(OpCodes.Ldarg_0); + gen.Emit(OpCodes.Ldstr, "data"); + gen.EmitCall(OpCodes.Callvirt, readToFollowing,null); + gen.Emit(OpCodes.Brtrue_S, start); + + gen.Emit(OpCodes.Ret); + + //let's bake the method + return method.CreateDelegate(delegateType); + } + } + #endregion + + public void Serialize(TextWriter writer, IVertexAndEdgeSet visitedGraph) + { + GraphContracts.AssumeNotNull(writer, "writer"); + GraphContracts.AssumeNotNull(visitedGraph, "visitedGraph"); + + using (var xwriter = new XmlTextWriter(writer)) + { + xwriter.Formatting = Formatting.Indented; + Serialize(xwriter, visitedGraph); + } + } + + public void Serialize(Stream stream, Encoding encoding, IVertexAndEdgeSet visitedGraph) + { + if (stream == null) + throw new ArgumentNullException("stream"); + if (encoding == null) + throw new ArgumentNullException("encoding"); + if (visitedGraph == null) + throw new ArgumentNullException("visitedGraph"); + + using (var xwriter = new XmlTextWriter(stream, encoding)) + { + xwriter.Formatting = Formatting.Indented; + Serialize(xwriter, visitedGraph); + } + } + + public void Serialize(XmlWriter writer, IVertexAndEdgeSet visitedGraph) + { + if (writer == null) + throw new ArgumentNullException("writer"); + if (visitedGraph == null) + throw new ArgumentNullException("visitedGraph"); + + var worker = new WriterWorker(this, writer, visitedGraph); + worker.Serialize(); + } + + public void Deserialize( + XmlReader reader, + IMutableVertexAndEdgeListGraph visitedGraph, + IIdentifiableVertexFactory vertexFactory, + IIdentifiableEdgeFactory edgeFactory) + { + if (reader == null) + throw new ArgumentNullException("reader"); + if (visitedGraph == null) + throw new ArgumentNullException("visitedGraph"); + if (vertexFactory == null) + throw new ArgumentNullException("vertexFactory"); + if (edgeFactory == null) + throw new ArgumentNullException("edgeFactory"); + + ReaderWorker worker = new ReaderWorker( + this, + reader, + visitedGraph, + vertexFactory, + edgeFactory); + worker.Deserialize(); + } + + class ReaderWorker + { + private GraphMLSerializer serializer; + private XmlReader reader; + private IMutableVertexAndEdgeListGraph visitedGraph; + private IIdentifiableVertexFactory vertexFactory; + private IIdentifiableEdgeFactory edgeFactory; + + public ReaderWorker( + GraphMLSerializer serializer, + XmlReader reader, + IMutableVertexAndEdgeListGraph visitedGraph, + IIdentifiableVertexFactory vertexFactory, + IIdentifiableEdgeFactory edgeFactory + ) + { + this.serializer = serializer; + this.reader = reader; + this.visitedGraph = visitedGraph; + this.vertexFactory = vertexFactory; + this.edgeFactory = edgeFactory; + } + + public GraphMLSerializer Serializer + { + get { return this.serializer; } + } + + public XmlReader Reader + { + get { return this.reader; } + } + + public IMutableVertexAndEdgeListGraph VisitedGraph + { + get { return this.visitedGraph; } + } + + public void Deserialize() + { + this.ReadHeader(); + this.ReadGraphHeader(); + this.ReadElements(); + } + + private void ReadHeader() + { + // read flow until we hit the graphml node + if (!this.Reader.ReadToFollowing("graphml")) + throw new ArgumentException("graphml node not found"); + } + + private void ReadGraphHeader() + { + if (!this.Reader.ReadToDescendant("graph")) + throw new ArgumentException("graph node not found"); + } + + private void ReadElements() + { + this.Reader.ReadStartElement("graph"); + + Dictionary vertices = new Dictionary(); + + // read vertices or edges + while (this.Reader.Read()) + { + if (this.Reader.NodeType == XmlNodeType.Element) + { + if (this.Reader.Name == "node") + { + // get subtree + XmlReader subReader = this.Reader.ReadSubtree(); + // read id + string id = this.ReadAttributeValue("id"); + // create new vertex + TVertex vertex = vertexFactory.CreateVertex(id); + // read data + GraphMLSerializer.DelegateCompiler.VertexAttributesReader(subReader, vertex); + // add to graph + this.VisitedGraph.AddVertex(vertex); + vertices.Add(vertex.ID, vertex); + } + else if (this.Reader.Name == "edge") + { + // get subtree + XmlReader subReader = reader.ReadSubtree(); + // read id + string id = this.ReadAttributeValue("id"); + string sourceid = this.ReadAttributeValue("source"); + TVertex source; + if (!vertices.TryGetValue(sourceid, out source)) + throw new ArgumentException("Could not find vertex " + sourceid); + string targetid = this.ReadAttributeValue("target"); + TVertex target; + if (!vertices.TryGetValue(targetid, out target)) + throw new ArgumentException("Could not find vertex " + targetid); + + TEdge edge = this.edgeFactory.CreateEdge(id, source, target); + + // read data + GraphMLSerializer.DelegateCompiler.EdgeAttributesReader(subReader, edge); + + this.VisitedGraph.AddEdge(edge); + } + } + } + } + + private string ReadAttributeValue(string attributeName) + { + this.Reader.MoveToAttribute(attributeName); + if (!this.Reader.ReadAttributeValue()) + throw new ArgumentException("missing "+ attributeName +" attribute"); + return this.Reader.Value; + } + } + + private sealed class WriterWorker + { + private GraphMLSerializer serializer; + private XmlWriter writer; + private IVertexAndEdgeSet visitedGraph; + + public WriterWorker( + GraphMLSerializer serializer, + XmlWriter writer, + IVertexAndEdgeSet visitedGraph) + { + this.serializer = serializer; + this.writer = writer; + this.visitedGraph = visitedGraph; + } + + public GraphMLSerializer Serializer + { + get { return this.serializer; } + } + + public XmlWriter Writer + { + get { return this.writer; } + } + + public IVertexAndEdgeSet VisitedGraph + { + get { return this.visitedGraph; } + } + + public void Serialize() + { + this.WriteHeader(); + this.WriteVertexAttributeDefinitions(); + this.WriteEdgeAttributeDefinitions(); + this.WriteGraphHeader(); + this.WriteVertices(); + this.WriteEdges(); + this.WriteGraphFooter(); + this.WriteFooter(); + } + + private void WriteHeader() + { + if (this.Serializer.EmitDocumentDeclaration) + this.Writer.WriteStartDocument(); + this.Writer.WriteStartElement("graphml"); + this.Writer.WriteAttributeString("xmlns","http://graphml.graphdrawing.org/xmlns"); + this.Writer.WriteAttributeString("xmlns:xsi","http://www.w3.org/2001/XMLSchema-instance"); + this.Writer.WriteAttributeString("xsi:schemaLocation", "http://graphml.graphdrawing.org/xmlns http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd"); + } + + private void WriteFooter() + { + this.Writer.WriteEndElement(); + this.Writer.WriteEndDocument(); + } + + private void WriteGraphHeader() + { + this.Writer.WriteStartElement("graph"); + this.Writer.WriteAttributeString("id", "G"); + this.Writer.WriteAttributeString("edgedefault", + (this.VisitedGraph.IsDirected) ? "directed" : "undirected" + ); + this.Writer.WriteAttributeString("parse.nodes", this.VisitedGraph.VertexCount.ToString()); + this.Writer.WriteAttributeString("parse.edges", this.VisitedGraph.EdgeCount.ToString()); + this.Writer.WriteAttributeString("parse.order", "nodefirst"); + this.Writer.WriteAttributeString("parse.nodeids", "free"); + this.Writer.WriteAttributeString("parse.edgeids", "free"); + } + + private void WriteGraphFooter() + { + this.Writer.WriteEndElement(); + } + + private void WriteVertexAttributeDefinitions() + { + string forNode = "node"; + Type nodeType = typeof(TVertex); + + WriteAttributeDefinitions(forNode, nodeType); + } + + private void WriteEdgeAttributeDefinitions() + { + string forNode = "edge"; + Type nodeType = typeof(TEdge); + + WriteAttributeDefinitions(forNode, nodeType); + } + + private void WriteAttributeDefinitions(string forNode, Type nodeType) + { + foreach (KeyValuePair kv in SerializationHelper.GetAttributeProperties(nodeType)) + { + // + this.Writer.WriteStartElement("key"); + this.Writer.WriteAttributeString("id", kv.Value); + this.Writer.WriteAttributeString("for", forNode); + this.Writer.WriteAttributeString("attr.name", kv.Value); + + Type propertyType = kv.Key.PropertyType; + if (propertyType == typeof(bool)) + this.Writer.WriteAttributeString("attr.type", "boolean"); + else if (propertyType == typeof(int)) + this.Writer.WriteAttributeString("attr.type", "int"); + else if (propertyType == typeof(long)) + this.Writer.WriteAttributeString("attr.type", "long"); + else if (propertyType == typeof(float)) + this.Writer.WriteAttributeString("attr.type", "float"); + else if (propertyType == typeof(double)) + this.Writer.WriteAttributeString("attr.type", "double"); + else + this.Writer.WriteAttributeString("attr.type", "string"); + this.Writer.WriteEndElement(); + } + } + + private void WriteVertices() + { + foreach (var v in this.VisitedGraph.Vertices) + { + this.Writer.WriteStartElement("node"); + this.Writer.WriteAttributeString("id", v.ID); + GraphMLSerializer.DelegateCompiler.VertexAttributesWriter(this.Writer, v); + this.Writer.WriteEndElement(); + } + } + + private void WriteEdges() + { + foreach (var e in this.VisitedGraph.Edges) + { + this.Writer.WriteStartElement("edge"); + this.Writer.WriteAttributeString("id", e.ID); + this.Writer.WriteAttributeString("source", e.Source.ID); + this.Writer.WriteAttributeString("target", e.Target.ID); + GraphMLSerializer.DelegateCompiler.EdgeAttributesWriter(this.Writer, e); + this.Writer.WriteEndElement(); + } + } + } + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Serialization/GraphMLSerializer.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Serialization/GraphMLSerializer.cs.meta new file mode 100644 index 0000000..95f2e08 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Serialization/GraphMLSerializer.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 7cdec9573f05040cfaa52653d6ccafc3 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Serialization/SerializationHelper.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Serialization/SerializationHelper.cs new file mode 100755 index 0000000..48d3396 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Serialization/SerializationHelper.cs @@ -0,0 +1,39 @@ +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Xml.Serialization; + +namespace QuickGraph.Serialization +{ + internal static class SerializationHelper + { + public static IEnumerable> GetAttributeProperties(Type type) + { + foreach (PropertyInfo property in type.GetProperties()) + { + // must have a get, and not be an index + if (!property.CanRead || property.GetIndexParameters().Length > 0) + continue; + // is it tagged with XmlAttributeAttribute? + string name = GetAttributeName(property); + if (name != null) + yield return new KeyValuePair(property, name); + } + } + + public static string GetAttributeName(PropertyInfo property) + { + object[] attributes = property.GetCustomAttributes(typeof(XmlAttributeAttribute), true); + if (attributes.Length == 0) + return null; + else + { + XmlAttributeAttribute attribute = attributes[0] as XmlAttributeAttribute; + if (String.IsNullOrEmpty(attribute.AttributeName)) + return property.Name; + else + return attribute.AttributeName; + } + } + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Serialization/SerializationHelper.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Serialization/SerializationHelper.cs.meta new file mode 100644 index 0000000..d69bcad --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Serialization/SerializationHelper.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ed289c003d82f409ea760ea433847613 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Serialization/SerializerBase.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Serialization/SerializerBase.cs new file mode 100755 index 0000000..da5b389 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Serialization/SerializerBase.cs @@ -0,0 +1,17 @@ +using System; +using System.Xml; + +namespace QuickGraph.Serialization +{ + public abstract class SerializerBase + where TEdge :IEdge + { + private bool emitDocumentDeclaration = true; + + public bool EmitDocumentDeclaration + { + get { return this.emitDocumentDeclaration; } + set { this.emitDocumentDeclaration = value; } + } + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/Serialization/SerializerBase.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Serialization/SerializerBase.cs.meta new file mode 100644 index 0000000..2d26193 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/Serialization/SerializerBase.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e6c80f1b4bd7846019f8345f30ee01f2 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/TaggedEdge.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/TaggedEdge.cs new file mode 100755 index 0000000..b71155e --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/TaggedEdge.cs @@ -0,0 +1,37 @@ +using System; + +namespace QuickGraph +{ + [Serializable] + public class TaggedEdge : Edge + { + private TTag tag; + + public TaggedEdge(TVertex source, TVertex target, TTag tag) + :base(source,target) + { + this.tag = tag; + } + + public event EventHandler TagChanged; + + protected virtual void OnTagChanged(EventArgs e) + { + if (this.TagChanged != null) + this.TagChanged(this, e); + } + + public TTag Tag + { + get { return this.tag; } + set + { + if (!object.Equals(this.tag, value)) + { + this.tag = value; + this.OnTagChanged(EventArgs.Empty); + } + } + } + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/TaggedEdge.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/TaggedEdge.cs.meta new file mode 100644 index 0000000..b3d1ee3 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/TaggedEdge.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ebb112f45b0714bdaa9eb2834395a39e +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/TraversalHelper.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/TraversalHelper.cs new file mode 100755 index 0000000..d193215 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/TraversalHelper.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace QuickGraph +{ + public static class TraversalHelper + { + public static TVertex GetFirstVertex(IVertexListGraph g) + where TEdge : IEdge + { + foreach (var v in g.Vertices) + return v; + return default(TVertex); + } + + public static TVertex GetFirstVertex(IUndirectedGraph g) + where TEdge : IEdge + { + foreach (var v in g.Vertices) + return v; + return default(TVertex); + } + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/TraversalHelper.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/TraversalHelper.cs.meta new file mode 100644 index 0000000..506f06d --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/TraversalHelper.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: bc83fe0d8102d42118d23ddf81ad0949 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/UndirectedBidirectionalGraph.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/UndirectedBidirectionalGraph.cs new file mode 100755 index 0000000..31b638b --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/UndirectedBidirectionalGraph.cs @@ -0,0 +1,126 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace QuickGraph +{ + [Serializable] + public sealed class UndirectedBidirectionalGraph : + IUndirectedGraph + where TEdge : IEdge + { + private readonly IBidirectionalGraph visitedGraph; + + public UndirectedBidirectionalGraph(IBidirectionalGraph visitedGraph) + { + if (visitedGraph == null) + throw new ArgumentNullException("visitedGraph"); + this.visitedGraph = visitedGraph; + } + + public IBidirectionalGraph VisitedGraph + { + get { return this.visitedGraph; } + } + + #region IUndirectedGraph Members + + public IEnumerable AdjacentEdges(TVertex v) + { + foreach (var e in this.VisitedGraph.OutEdges(v)) + yield return e; + foreach (var e in this.VisitedGraph.InEdges(v)) + { + // we skip selfedges here since + // we already did those in the outedge run + if (e.Source.Equals(e.Target)) + continue; + yield return e; + } + } + + public int AdjacentDegree(TVertex v) + { + return this.VisitedGraph.Degree(v); + } + + public bool IsAdjacentEdgesEmpty(TVertex v) + { + return this.VisitedGraph.IsOutEdgesEmpty(v) && this.VisitedGraph.IsInEdgesEmpty(v); + } + + public TEdge AdjacentEdge(TVertex v, int index) + { + throw new NotSupportedException(); + } + + public bool ContainsEdge(TVertex source, TVertex target) + { + throw new NotSupportedException(); + } + + #endregion + + #region IVertexSet Members + + public bool IsVerticesEmpty + { + get { return this.VisitedGraph.IsVerticesEmpty; } + } + + public int VertexCount + { + get { return this.VisitedGraph.VertexCount; } + } + + public IEnumerable Vertices + { + get { return this.VisitedGraph.Vertices; } + } + + public bool ContainsVertex(TVertex vertex) + { + return this.VisitedGraph.ContainsVertex(vertex); + } + + #endregion + + #region IEdgeListGraph Members + + public bool IsEdgesEmpty + { + get { return this.VisitedGraph.IsEdgesEmpty; } + } + + public int EdgeCount + { + get { return this.VisitedGraph.EdgeCount; } + } + + public IEnumerable Edges + { + get { return this.VisitedGraph.Edges; } + } + + public bool ContainsEdge(TEdge edge) + { + return this.VisitedGraph.ContainsEdge(edge); + } + + #endregion + + #region IGraph Members + + public bool IsDirected + { + get { return false; } + } + + public bool AllowParallelEdges + { + get { return this.VisitedGraph.AllowParallelEdges; } + } + + #endregion + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/UndirectedBidirectionalGraph.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/UndirectedBidirectionalGraph.cs.meta new file mode 100644 index 0000000..5407a06 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/UndirectedBidirectionalGraph.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 3ce634f6854dd4086b0d37a9df28bb3a +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/UndirectedGraph.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/UndirectedGraph.cs new file mode 100755 index 0000000..a1caece --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/UndirectedGraph.cs @@ -0,0 +1,302 @@ +using System; +using System.Collections.Generic; + +namespace QuickGraph +{ + public class UndirectedGraph : + IMutableUndirectedGraph + where TEdge : IEdge + { + private readonly bool allowParallelEdges = true; + private readonly Dictionary> adjacentEdges = + new Dictionary>(); + private int edgeCount = 0; + + public UndirectedGraph() + :this(true) + {} + + public UndirectedGraph(bool allowParallelEdges) + { + this.allowParallelEdges = allowParallelEdges; + } + + #region IGraph Members + public bool IsDirected + { + get { return false; } + } + + public bool AllowParallelEdges + { + get { return this.allowParallelEdges; } + } + #endregion + + #region IMutableUndirected Members + + public void AddVertex(TVertex v) + { + GraphContracts.AssumeNotInVertexSet(this, v, "v"); + this.adjacentEdges.Add(v, new List()); + } + + public bool RemoveVertex(TVertex v) + { + GraphContracts.AssumeNotNull(v, "v"); + this.ClearAdjacentEdges(v); + return this.adjacentEdges.Remove(v); + } + + public int RemoveVertexIf(VertexPredicate pred) + { + GraphContracts.AssumeNotNull(pred, "pred"); + List vertices = new List(); + foreach (var v in this.Vertices) + if (pred(v)) + vertices.Add(v); + + foreach (var v in vertices) + RemoveVertex(v); + return vertices.Count; + } + #endregion + + #region IMutableIncidenceGraph Members + public int RemoveAdjacentEdgeIf(TVertex v, EdgePredicate predicate) + { + GraphContracts.AssumeInVertexSet(this, v, "v"); + GraphContracts.AssumeNotNull(predicate, "predicate"); + + IList outEdges = this.adjacentEdges[v]; + List edges = new List(outEdges.Count); + foreach (var edge in outEdges) + if (predicate(edge)) + edges.Add(edge); + + this.RemoveEdges(edges); + return edges.Count; + } + + public void ClearAdjacentEdges(TVertex v) + { + GraphContracts.AssumeInVertexSet(this, v, "v"); + IList edges = this.adjacentEdges[v]; + this.edgeCount -= edges.Count; + foreach (var edge in edges) + { + if (edge.Source.Equals(v)) + this.adjacentEdges[edge.Target].Remove(edge); + else + this.adjacentEdges[edge.Source].Remove(edge); + } + System.Diagnostics.Debug.Assert(this.edgeCount >= 0); + } + #endregion + + #region IMutableGraph Members + public void TrimEdgeExcess() + { + foreach (var edges in this.adjacentEdges.Values) + edges.TrimExcess(); + } + + public void Clear() + { + this.adjacentEdges.Clear(); + this.edgeCount = 0; + } + #endregion + + #region IUndirectedGraph Members + + public bool ContainsEdge(TVertex source, TVertex target) + { + foreach(TEdge edge in this.AdjacentEdges(source)) + { + if (edge.Source.Equals(source) && edge.Target.Equals(target)) + return true; + + if (edge.Target.Equals(source) && edge.Source.Equals(target)) + return true; + } + return false; + } + + public TEdge AdjacentEdge(TVertex v, int index) + { + return this.adjacentEdges[v][index]; + } + + public bool IsVerticesEmpty + { + get { return this.adjacentEdges.Count == 0; } + } + + public int VertexCount + { + get { return this.adjacentEdges.Count; } + } + + public IEnumerable Vertices + { + get { return this.adjacentEdges.Keys; } + } + + + public bool ContainsVertex(TVertex vertex) + { + GraphContracts.AssumeNotNull(vertex, "vertex"); + return this.adjacentEdges.ContainsKey(vertex); + } + #endregion + + #region IMutableEdgeListGraph Members + + public bool AddEdge(TEdge edge) + { + GraphContracts.AssumeInVertexSet(this, edge, "edge"); + + if (!this.AllowParallelEdges) + { + if (this.adjacentEdges[edge.Source].Contains(edge)) + return false; + } + this.adjacentEdges[edge.Source].Add(edge); + this.adjacentEdges[edge.Target].Add(edge); + this.edgeCount++; + + this.OnEdgeAdded(new EdgeEventArgs(edge)); + + return true; + } + + public void AddEdgeRange(IEnumerable edges) + { + GraphContracts.AssumeNotNull(edges, "edges"); + foreach (var edge in edges) + this.AddEdge(edge); + } + + public event EdgeEventHandler EdgeAdded; + protected virtual void OnEdgeAdded(EdgeEventArgs args) + { + EdgeEventHandler eh = this.EdgeAdded; + if (eh != null) + eh(this, args); + } + + public bool RemoveEdge(TEdge edge) + { + GraphContracts.AssumeInVertexSet(this, edge, "edge"); + + this.adjacentEdges[edge.Source].Remove(edge); + if (this.adjacentEdges[edge.Target].Remove(edge)) + { + this.edgeCount--; + System.Diagnostics.Debug.Assert(this.edgeCount >= 0); + this.OnEdgeRemoved(new EdgeEventArgs(edge)); + return true; + } + else + return false; + } + + public event EdgeEventHandler EdgeRemoved; + protected virtual void OnEdgeRemoved(EdgeEventArgs args) + { + EdgeEventHandler eh = this.EdgeRemoved; + if (eh != null) + eh(this, args); + } + + public int RemoveEdgeIf(EdgePredicate predicate) + { + GraphContracts.AssumeNotNull(predicate, "predicate"); + + List edges = new List(); + foreach (var edge in this.Edges) + { + if (predicate(edge)) + edges.Add(edge); + } + return this.RemoveEdges(edges); + } + + public int RemoveEdges(IEnumerable edges) + { + GraphContracts.AssumeNotNull(edges, "edges"); + + int count = 0; + foreach (var edge in edges) + { + if (RemoveEdge(edge)) + count++; + } + return count; + } + #endregion + + #region IEdgeListGraph Members + public bool IsEdgesEmpty + { + get { return this.EdgeCount==0; } + } + + public int EdgeCount + { + get { return this.edgeCount; } + } + + public IEnumerable Edges + { + get + { + Dictionary edgeColors = new Dictionary(this.EdgeCount); + foreach (IList edges in this.adjacentEdges.Values) + { + foreach(TEdge edge in edges) + { + GraphColor c; + if (edgeColors.TryGetValue(edge, out c)) + continue; + edgeColors.Add(edge, GraphColor.Black); + yield return edge; + } + } + } + } + + public bool ContainsEdge(TEdge edge) + { + GraphContracts.AssumeInVertexSet(this, edge, "edge"); + foreach (var e in this.Edges) + if (e.Equals(edge)) + return true; + return false; + } + #endregion + + #region IUndirectedGraph Members + + public IEnumerable AdjacentEdges(TVertex v) + { + GraphContracts.AssumeInVertexSet(this, v, "v"); + return this.adjacentEdges[v]; + } + + public int AdjacentDegree(TVertex v) + { + GraphContracts.AssumeInVertexSet(this, v, "v"); + return this.adjacentEdges[v].Count; + } + + public bool IsAdjacentEdgesEmpty(TVertex v) + { + GraphContracts.AssumeInVertexSet(this, v, "v"); + return this.adjacentEdges[v].Count == 0; + } + + #endregion + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/UndirectedGraph.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/UndirectedGraph.cs.meta new file mode 100644 index 0000000..0e25309 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/UndirectedGraph.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ba27481ebda464d629207af8377e1af1 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/VertexEventArgs.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/VertexEventArgs.cs new file mode 100755 index 0000000..ae61226 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/VertexEventArgs.cs @@ -0,0 +1,24 @@ +using System; + +namespace QuickGraph +{ + [Serializable] + public class VertexEventArgs : EventArgs + { + private readonly TVertex vertex; + public VertexEventArgs(TVertex vertex) + { + GraphContracts.AssumeNotNull(vertex, "vertex"); + this.vertex = vertex; + } + + public TVertex Vertex + { + get { return this.vertex; } + } + } + + public delegate void VertexEventHandler( + object sender, + VertexEventArgs e); +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/VertexEventArgs.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/VertexEventArgs.cs.meta new file mode 100644 index 0000000..55cb27e --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/VertexEventArgs.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 1e91533ad7f884e3c94994f1c2de8c17 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/VertexNotConnectedException.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/VertexNotConnectedException.cs new file mode 100755 index 0000000..b8a4534 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/VertexNotConnectedException.cs @@ -0,0 +1,18 @@ +using System; + +namespace QuickGraph +{ + /// + /// Specialized exception to report unconnected vertices + /// + [Serializable] + public sealed class VertexNotConnectedException : ApplicationException + { + public VertexNotConnectedException() { } + public VertexNotConnectedException(string message) : base( message ) { } + public VertexNotConnectedException(string message, System.Exception inner) : base( message, inner ) { } + public VertexNotConnectedException( + System.Runtime.Serialization.SerializationInfo info, + System.Runtime.Serialization.StreamingContext context) : base( info, context ) { } + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/VertexNotConnectedException.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/VertexNotConnectedException.cs.meta new file mode 100644 index 0000000..6f5483e --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/VertexNotConnectedException.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 8c7bbec090b554842959c6a9a4083e4f +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/VertexNotFoundException.cs b/src/Assets/quickgraph4unity/Runtime/QuickGraph/VertexNotFoundException.cs new file mode 100755 index 0000000..1a57525 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/VertexNotFoundException.cs @@ -0,0 +1,15 @@ +using System; + +namespace QuickGraph +{ + [Serializable] + public class VertexNotFoundException : ApplicationException + { + public VertexNotFoundException() { } + public VertexNotFoundException(string message) : base( message ) { } + public VertexNotFoundException(string message, System.Exception inner) : base( message, inner ) { } + public VertexNotFoundException( + System.Runtime.Serialization.SerializationInfo info, + System.Runtime.Serialization.StreamingContext context) : base( info, context ) { } + } +} diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/VertexNotFoundException.cs.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/VertexNotFoundException.cs.meta new file mode 100644 index 0000000..f27fff9 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/VertexNotFoundException.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d5b737e14a6964326ac7b3f936d02f3f +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/quickgraph.banner.png b/src/Assets/quickgraph4unity/Runtime/QuickGraph/quickgraph.banner.png new file mode 100755 index 0000000..8077435 Binary files /dev/null and b/src/Assets/quickgraph4unity/Runtime/QuickGraph/quickgraph.banner.png differ diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/quickgraph.banner.png.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/quickgraph.banner.png.meta new file mode 100644 index 0000000..b71703d --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/quickgraph.banner.png.meta @@ -0,0 +1,46 @@ +fileFormatVersion: 2 +guid: c3b75faf76b1d4ab0a648bc19a4c85a1 +TextureImporter: + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + linearTexture: 0 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: -1 + mipBias: -1 + wrapMode: -1 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 0 + textureType: -1 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/quickgraph.png b/src/Assets/quickgraph4unity/Runtime/QuickGraph/quickgraph.png new file mode 100755 index 0000000..5d7bb71 Binary files /dev/null and b/src/Assets/quickgraph4unity/Runtime/QuickGraph/quickgraph.png differ diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/quickgraph.png.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/quickgraph.png.meta new file mode 100644 index 0000000..014fb96 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/quickgraph.png.meta @@ -0,0 +1,46 @@ +fileFormatVersion: 2 +guid: 48cbaeedad2bd45e991563abd0655cd8 +TextureImporter: + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + linearTexture: 0 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: -1 + mipBias: -1 + wrapMode: -1 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 0 + textureType: -1 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/quickgraph.snk b/src/Assets/quickgraph4unity/Runtime/QuickGraph/quickgraph.snk new file mode 100755 index 0000000..a630ef5 Binary files /dev/null and b/src/Assets/quickgraph4unity/Runtime/QuickGraph/quickgraph.snk differ diff --git a/src/Assets/quickgraph4unity/Runtime/QuickGraph/quickgraph.snk.meta b/src/Assets/quickgraph4unity/Runtime/QuickGraph/quickgraph.snk.meta new file mode 100644 index 0000000..f00c7a3 --- /dev/null +++ b/src/Assets/quickgraph4unity/Runtime/QuickGraph/quickgraph.snk.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: 89e74692ab5fb44a7ab2c83772dafb4c +DefaultImporter: + userData: diff --git a/src/ProjectSettings/AudioManager.asset b/src/ProjectSettings/AudioManager.asset new file mode 100644 index 0000000..ec6be29 --- /dev/null +++ b/src/ProjectSettings/AudioManager.asset @@ -0,0 +1,12 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!11 &1 +AudioManager: + m_ObjectHideFlags: 0 + m_Volume: 1 + Rolloff Scale: 1 + m_SpeedOfSound: 347 + Doppler Factor: 1 + Default Speaker Mode: 2 + m_DSPBufferSize: 0 + m_DisableAudio: 0 diff --git a/src/ProjectSettings/DynamicsManager.asset b/src/ProjectSettings/DynamicsManager.asset new file mode 100644 index 0000000..717b5c2 --- /dev/null +++ b/src/ProjectSettings/DynamicsManager.asset @@ -0,0 +1,15 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!55 &1 +PhysicsManager: + m_ObjectHideFlags: 0 + m_Gravity: {x: 0, y: -9.81000042, z: 0} + m_DefaultMaterial: {fileID: 0} + m_BounceThreshold: 2 + m_SleepVelocity: .150000006 + m_SleepAngularVelocity: .140000001 + m_MaxAngularVelocity: 7 + m_MinPenetrationForPenalty: .00999999978 + m_SolverIterationCount: 6 + m_RaycastsHitTriggers: 1 + m_LayerCollisionMatrix: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff diff --git a/src/ProjectSettings/EditorBuildSettings.asset b/src/ProjectSettings/EditorBuildSettings.asset new file mode 100644 index 0000000..6dc24f7 --- /dev/null +++ b/src/ProjectSettings/EditorBuildSettings.asset @@ -0,0 +1,7 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1045 &1 +EditorBuildSettings: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Scenes: [] diff --git a/src/ProjectSettings/EditorSettings.asset b/src/ProjectSettings/EditorSettings.asset new file mode 100644 index 0000000..f6bcc6a --- /dev/null +++ b/src/ProjectSettings/EditorSettings.asset @@ -0,0 +1,12 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!159 &1 +EditorSettings: + m_ObjectHideFlags: 0 + serializedVersion: 3 + m_ExternalVersionControlSupport: Visible Meta Files + m_SerializationMode: 2 + m_WebSecurityEmulationEnabled: 0 + m_WebSecurityEmulationHostUrl: http://www.mydomain.com/mygame.unity3d + m_DefaultBehaviorMode: 0 + m_SpritePackerMode: 0 diff --git a/src/ProjectSettings/GraphicsSettings.asset b/src/ProjectSettings/GraphicsSettings.asset new file mode 100644 index 0000000..553f97d --- /dev/null +++ b/src/ProjectSettings/GraphicsSettings.asset @@ -0,0 +1,7 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!30 &1 +GraphicsSettings: + m_ObjectHideFlags: 0 + m_AlwaysIncludedShaders: + - {fileID: 7, guid: 0000000000000000f000000000000000, type: 0} diff --git a/src/ProjectSettings/InputManager.asset b/src/ProjectSettings/InputManager.asset new file mode 100644 index 0000000..c95d27b --- /dev/null +++ b/src/ProjectSettings/InputManager.asset @@ -0,0 +1,246 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!13 &1 +InputManager: + m_ObjectHideFlags: 0 + m_Axes: + - serializedVersion: 3 + m_Name: Horizontal + descriptiveName: + descriptiveNegativeName: + negativeButton: left + positiveButton: right + altNegativeButton: a + altPositiveButton: d + gravity: 3 + dead: .00100000005 + sensitivity: 3 + snap: 1 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Vertical + descriptiveName: + descriptiveNegativeName: + negativeButton: down + positiveButton: up + altNegativeButton: s + altPositiveButton: w + gravity: 3 + dead: .00100000005 + sensitivity: 3 + snap: 1 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Fire1 + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: left ctrl + altNegativeButton: + altPositiveButton: mouse 0 + gravity: 1000 + dead: .00100000005 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Fire2 + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: left alt + altNegativeButton: + altPositiveButton: mouse 1 + gravity: 1000 + dead: .00100000005 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Fire3 + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: left cmd + altNegativeButton: + altPositiveButton: mouse 2 + gravity: 1000 + dead: .00100000005 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Jump + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: space + altNegativeButton: + altPositiveButton: + gravity: 1000 + dead: .00100000005 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Mouse X + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: + altNegativeButton: + altPositiveButton: + gravity: 0 + dead: 0 + sensitivity: .100000001 + snap: 0 + invert: 0 + type: 1 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Mouse Y + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: + altNegativeButton: + altPositiveButton: + gravity: 0 + dead: 0 + sensitivity: .100000001 + snap: 0 + invert: 0 + type: 1 + axis: 1 + joyNum: 0 + - serializedVersion: 3 + m_Name: Mouse ScrollWheel + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: + altNegativeButton: + altPositiveButton: + gravity: 0 + dead: 0 + sensitivity: .100000001 + snap: 0 + invert: 0 + type: 1 + axis: 2 + joyNum: 0 + - serializedVersion: 3 + m_Name: Horizontal + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: + altNegativeButton: + altPositiveButton: + gravity: 0 + dead: .189999998 + sensitivity: 1 + snap: 0 + invert: 0 + type: 2 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Vertical + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: + altNegativeButton: + altPositiveButton: + gravity: 0 + dead: .189999998 + sensitivity: 1 + snap: 0 + invert: 1 + type: 2 + axis: 1 + joyNum: 0 + - serializedVersion: 3 + m_Name: Fire1 + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: joystick button 0 + altNegativeButton: + altPositiveButton: + gravity: 1000 + dead: .00100000005 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Fire2 + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: joystick button 1 + altNegativeButton: + altPositiveButton: + gravity: 1000 + dead: .00100000005 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Fire3 + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: joystick button 2 + altNegativeButton: + altPositiveButton: + gravity: 1000 + dead: .00100000005 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Jump + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: joystick button 3 + altNegativeButton: + altPositiveButton: + gravity: 1000 + dead: .00100000005 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 diff --git a/src/ProjectSettings/NavMeshLayers.asset b/src/ProjectSettings/NavMeshLayers.asset new file mode 100644 index 0000000..79cb3ae --- /dev/null +++ b/src/ProjectSettings/NavMeshLayers.asset @@ -0,0 +1,133 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!126 &1 +NavMeshLayers: + m_ObjectHideFlags: 0 + Built-in Layer 0: + name: Default + cost: 1 + editType: 2 + Built-in Layer 1: + name: Not Walkable + cost: 1 + editType: 0 + Built-in Layer 2: + name: Jump + cost: 2 + editType: 2 + User Layer 0: + name: + cost: 1 + editType: 3 + User Layer 1: + name: + cost: 1 + editType: 3 + User Layer 2: + name: + cost: 1 + editType: 3 + User Layer 3: + name: + cost: 1 + editType: 3 + User Layer 4: + name: + cost: 1 + editType: 3 + User Layer 5: + name: + cost: 1 + editType: 3 + User Layer 6: + name: + cost: 1 + editType: 3 + User Layer 7: + name: + cost: 1 + editType: 3 + User Layer 8: + name: + cost: 1 + editType: 3 + User Layer 9: + name: + cost: 1 + editType: 3 + User Layer 10: + name: + cost: 1 + editType: 3 + User Layer 11: + name: + cost: 1 + editType: 3 + User Layer 12: + name: + cost: 1 + editType: 3 + User Layer 13: + name: + cost: 1 + editType: 3 + User Layer 14: + name: + cost: 1 + editType: 3 + User Layer 15: + name: + cost: 1 + editType: 3 + User Layer 16: + name: + cost: 1 + editType: 3 + User Layer 17: + name: + cost: 1 + editType: 3 + User Layer 18: + name: + cost: 1 + editType: 3 + User Layer 19: + name: + cost: 1 + editType: 3 + User Layer 20: + name: + cost: 1 + editType: 3 + User Layer 21: + name: + cost: 1 + editType: 3 + User Layer 22: + name: + cost: 1 + editType: 3 + User Layer 23: + name: + cost: 1 + editType: 3 + User Layer 24: + name: + cost: 1 + editType: 3 + User Layer 25: + name: + cost: 1 + editType: 3 + User Layer 26: + name: + cost: 1 + editType: 3 + User Layer 27: + name: + cost: 1 + editType: 3 + User Layer 28: + name: + cost: 1 + editType: 3 diff --git a/src/ProjectSettings/NetworkManager.asset b/src/ProjectSettings/NetworkManager.asset new file mode 100644 index 0000000..5dc6a83 --- /dev/null +++ b/src/ProjectSettings/NetworkManager.asset @@ -0,0 +1,8 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!149 &1 +NetworkManager: + m_ObjectHideFlags: 0 + m_DebugLevel: 0 + m_Sendrate: 15 + m_AssetToPrefab: {} diff --git a/src/ProjectSettings/Physics2DSettings.asset b/src/ProjectSettings/Physics2DSettings.asset new file mode 100644 index 0000000..28cf91b --- /dev/null +++ b/src/ProjectSettings/Physics2DSettings.asset @@ -0,0 +1,21 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!19 &1 +Physics2DSettings: + m_ObjectHideFlags: 0 + m_Gravity: {x: 0, y: -9.81000042} + m_DefaultMaterial: {fileID: 0} + m_VelocityIterations: 8 + m_PositionIterations: 3 + m_VelocityThreshold: 1 + m_MaxLinearCorrection: .200000003 + m_MaxAngularCorrection: 8 + m_MaxTranslationSpeed: 100 + m_MaxRotationSpeed: 360 + m_BaumgarteScale: .200000003 + m_BaumgarteTimeOfImpactScale: .75 + m_TimeToSleep: .5 + m_LinearSleepTolerance: .00999999978 + m_AngularSleepTolerance: 2 + m_RaycastsHitTriggers: 1 + m_LayerCollisionMatrix: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff diff --git a/src/ProjectSettings/ProjectSettings.asset b/src/ProjectSettings/ProjectSettings.asset new file mode 100644 index 0000000..39e3068 --- /dev/null +++ b/src/ProjectSettings/ProjectSettings.asset @@ -0,0 +1,226 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!129 &1 +PlayerSettings: + m_ObjectHideFlags: 0 + serializedVersion: 3 + AndroidProfiler: 0 + defaultScreenOrientation: 4 + targetDevice: 2 + targetGlesGraphics: 1 + targetResolution: 0 + accelerometerFrequency: 60 + companyName: DefaultCompany + productName: graph4unity + defaultCursor: {fileID: 0} + cursorHotspot: {x: 0, y: 0} + defaultScreenWidth: 1024 + defaultScreenHeight: 768 + defaultScreenWidthWeb: 960 + defaultScreenHeightWeb: 600 + m_RenderingPath: 1 + m_MobileRenderingPath: 1 + m_ActiveColorSpace: 0 + m_MTRendering: 1 + m_MobileMTRendering: 0 + m_UseDX11: 1 + m_Stereoscopic3D: 0 + iosShowActivityIndicatorOnLoading: -1 + androidShowActivityIndicatorOnLoading: -1 + displayResolutionDialog: 1 + allowedAutorotateToPortrait: 1 + allowedAutorotateToPortraitUpsideDown: 1 + allowedAutorotateToLandscapeRight: 1 + allowedAutorotateToLandscapeLeft: 1 + useOSAutorotation: 1 + use32BitDisplayBuffer: 1 + use24BitDepthBuffer: 1 + defaultIsFullScreen: 1 + defaultIsNativeResolution: 1 + runInBackground: 0 + captureSingleScreen: 0 + Override IPod Music: 0 + Prepare IOS For Recording: 0 + enableHWStatistics: 1 + usePlayerLog: 1 + stripPhysics: 0 + forceSingleInstance: 0 + resizableWindow: 0 + useMacAppStoreValidation: 0 + gpuSkinning: 0 + xboxPIXTextureCapture: 0 + xboxEnableAvatar: 0 + xboxEnableKinect: 0 + xboxEnableKinectAutoTracking: 0 + xboxEnableFitness: 0 + macFullscreenMode: 2 + xboxSpeechDB: 0 + xboxEnableHeadOrientation: 0 + xboxEnableGuest: 0 + videoMemoryForVertexBuffers: 0 + m_SupportedAspectRatios: + 4:3: 1 + 5:4: 1 + 16:10: 1 + 16:9: 1 + Others: 1 + iPhoneBundleIdentifier: com.Company.ProductName + metroEnableIndependentInputSource: 0 + metroEnableLowLatencyPresentationAPI: 0 + productGUID: 71088effccc53408a8e844fdddf3ca84 + iPhoneBundleVersion: 1.0 + AndroidBundleVersionCode: 1 + AndroidMinSdkVersion: 9 + AndroidPreferredInstallLocation: 1 + aotOptions: + apiCompatibilityLevel: 2 + iPhoneStrippingLevel: 0 + iPhoneScriptCallOptimization: 0 + ForceInternetPermission: 0 + ForceSDCardPermission: 0 + CreateWallpaper: 0 + APKExpansionFiles: 0 + StripUnusedMeshComponents: 0 + iPhoneSdkVersion: 988 + iPhoneTargetOSVersion: 16 + uIPrerenderedIcon: 0 + uIRequiresPersistentWiFi: 0 + uIStatusBarHidden: 1 + uIExitOnSuspend: 0 + uIStatusBarStyle: 0 + iPhoneSplashScreen: {fileID: 0} + iPhoneHighResSplashScreen: {fileID: 0} + iPhoneTallHighResSplashScreen: {fileID: 0} + iPadPortraitSplashScreen: {fileID: 0} + iPadHighResPortraitSplashScreen: {fileID: 0} + iPadLandscapeSplashScreen: {fileID: 0} + iPadHighResLandscapeSplashScreen: {fileID: 0} + AndroidTargetDevice: 0 + AndroidSplashScreenScale: 0 + AndroidKeystoreName: + AndroidKeyaliasName: + resolutionDialogBanner: {fileID: 0} + m_BuildTargetIcons: [] + m_BuildTargetBatching: [] + webPlayerTemplate: APPLICATION:Default + m_TemplateCustomTags: {} + XboxTitleId: + XboxImageXexPath: + XboxSpaPath: + XboxGenerateSpa: 0 + XboxDeployKinectResources: 0 + XboxSplashScreen: {fileID: 0} + xboxEnableSpeech: 0 + xboxAdditionalTitleMemorySize: 0 + xboxDeployKinectHeadOrientation: 0 + xboxDeployKinectHeadPosition: 0 + ps3TitleConfigPath: + ps3DLCConfigPath: + ps3ThumbnailPath: + ps3BackgroundPath: + ps3SoundPath: + ps3TrophyCommId: + ps3NpCommunicationPassphrase: + ps3TrophyPackagePath: + ps3BootCheckMaxSaveGameSizeKB: 128 + ps3TrophyCommSig: + ps3SaveGameSlots: 1 + ps3TrialMode: 0 + psp2Splashimage: {fileID: 0} + psp2LiveAreaGate: {fileID: 0} + psp2LiveAreaBackround: {fileID: 0} + psp2NPTrophyPackPath: + psp2NPCommsID: + psp2NPCommsPassphrase: + psp2NPCommsSig: + psp2ParamSfxPath: + psp2PackagePassword: + psp2DLCConfigPath: + psp2ThumbnailPath: + psp2BackgroundPath: + psp2SoundPath: + psp2TrophyCommId: + psp2TrophyPackagePath: + psp2PackagedResourcesPath: + flashStrippingLevel: 2 + spritePackerPolicy: + scriptingDefineSymbols: {} + metroPackageName: graph4unity + metroPackageLogo: + metroPackageLogo140: + metroPackageLogo180: + metroPackageVersion: + metroCertificatePath: + metroCertificatePassword: + metroCertificateSubject: + metroCertificateIssuer: + metroCertificateNotAfter: 0000000000000000 + metroApplicationDescription: graph4unity + metroTileLogo80: + metroTileLogo: + metroTileLogo140: + metroTileLogo180: + metroTileWideLogo80: + metroTileWideLogo: + metroTileWideLogo140: + metroTileWideLogo180: + metroTileSmallLogo80: + metroTileSmallLogo: + metroTileSmallLogo140: + metroTileSmallLogo180: + metroSmallTile80: + metroSmallTile: + metroSmallTile140: + metroSmallTile180: + metroLargeTile80: + metroLargeTile: + metroLargeTile140: + metroLargeTile180: + metroTileShortName: + metroCommandLineArgsFile: + metroTileShowName: 0 + metroMediumTileShowName: 0 + metroLargeTileShowName: 0 + metroWideTileShowName: 0 + metroDefaultTileSize: 1 + metroTileForegroundText: 1 + metroTileBackgroundColor: {r: 0, g: 0, b: 0, a: 1} + metroSplashScreenImage: + metroSplashScreenImage140: + metroSplashScreenImage180: + metroSplashScreenBackgroundColor: {r: 0, g: 0, b: 0, a: 1} + metroSplashScreenUseBackgroundColor: 0 + metroCapabilities: {} + metroUnprocessedPlugins: [] + metroCompilationOverrides: 1 + blackberryDeviceAddress: + blackberryDevicePassword: + blackberryTokenPath: + blackberryTokenExires: + blackberryTokenAuthor: + blackberryTokenAuthorId: + blackberryAuthorId: + blackberryCskPassword: + blackberrySaveLogPath: + blackberryAuthorIdOveride: 0 + blackberrySharedPermissions: 0 + blackberryCameraPermissions: 0 + blackberryGPSPermissions: 0 + blackberryDeviceIDPermissions: 0 + blackberryMicrophonePermissions: 0 + blackberryGamepadSupport: 0 + blackberryBuildId: 0 + blackberryLandscapeSplashScreen: {fileID: 0} + blackberryPortraitSplashScreen: {fileID: 0} + blackberrySquareSplashScreen: {fileID: 0} + tizenProductDescription: + tizenProductURL: + tizenCertificatePath: + tizenCertificatePassword: + tizenGPSPermissions: 0 + tizenMicrophonePermissions: 0 + stvDeviceAddress: + firstStreamedLevelWithResources: 0 + unityRebuildLibraryVersion: 9 + unityForwardCompatibleVersion: 39 + unityStandardAssetsVersion: 0 diff --git a/src/ProjectSettings/QualitySettings.asset b/src/ProjectSettings/QualitySettings.asset new file mode 100644 index 0000000..080f046 --- /dev/null +++ b/src/ProjectSettings/QualitySettings.asset @@ -0,0 +1,140 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!47 &1 +QualitySettings: + m_ObjectHideFlags: 0 + serializedVersion: 5 + m_CurrentQuality: 3 + m_QualitySettings: + - serializedVersion: 2 + name: Fastest + pixelLightCount: 0 + shadows: 0 + shadowResolution: 0 + shadowProjection: 1 + shadowCascades: 1 + shadowDistance: 15 + blendWeights: 1 + textureQuality: 1 + anisotropicTextures: 0 + antiAliasing: 0 + softParticles: 0 + softVegetation: 0 + vSyncCount: 0 + lodBias: .300000012 + maximumLODLevel: 0 + particleRaycastBudget: 4 + excludedTargetPlatforms: [] + - serializedVersion: 2 + name: Fast + pixelLightCount: 0 + shadows: 0 + shadowResolution: 0 + shadowProjection: 1 + shadowCascades: 1 + shadowDistance: 20 + blendWeights: 2 + textureQuality: 0 + anisotropicTextures: 0 + antiAliasing: 0 + softParticles: 0 + softVegetation: 0 + vSyncCount: 0 + lodBias: .400000006 + maximumLODLevel: 0 + particleRaycastBudget: 16 + excludedTargetPlatforms: [] + - serializedVersion: 2 + name: Simple + pixelLightCount: 1 + shadows: 1 + shadowResolution: 0 + shadowProjection: 1 + shadowCascades: 1 + shadowDistance: 20 + blendWeights: 2 + textureQuality: 0 + anisotropicTextures: 1 + antiAliasing: 0 + softParticles: 0 + softVegetation: 0 + vSyncCount: 0 + lodBias: .699999988 + maximumLODLevel: 0 + particleRaycastBudget: 64 + excludedTargetPlatforms: [] + - serializedVersion: 2 + name: Good + pixelLightCount: 2 + shadows: 2 + shadowResolution: 1 + shadowProjection: 1 + shadowCascades: 2 + shadowDistance: 40 + blendWeights: 2 + textureQuality: 0 + anisotropicTextures: 1 + antiAliasing: 0 + softParticles: 0 + softVegetation: 1 + vSyncCount: 1 + lodBias: 1 + maximumLODLevel: 0 + particleRaycastBudget: 256 + excludedTargetPlatforms: [] + - serializedVersion: 2 + name: Beautiful + pixelLightCount: 3 + shadows: 2 + shadowResolution: 2 + shadowProjection: 1 + shadowCascades: 2 + shadowDistance: 70 + blendWeights: 4 + textureQuality: 0 + anisotropicTextures: 2 + antiAliasing: 2 + softParticles: 1 + softVegetation: 1 + vSyncCount: 1 + lodBias: 1.5 + maximumLODLevel: 0 + particleRaycastBudget: 1024 + excludedTargetPlatforms: [] + - serializedVersion: 2 + name: Fantastic + pixelLightCount: 4 + shadows: 2 + shadowResolution: 2 + shadowProjection: 1 + shadowCascades: 4 + shadowDistance: 150 + blendWeights: 4 + textureQuality: 0 + anisotropicTextures: 2 + antiAliasing: 2 + softParticles: 1 + softVegetation: 1 + vSyncCount: 1 + lodBias: 2 + maximumLODLevel: 0 + particleRaycastBudget: 4096 + excludedTargetPlatforms: [] + m_PerPlatformDefaultQuality: + Android: 2 + BlackBerry: 2 + FlashPlayer: 3 + GLES Emulation: 3 + PS3: 3 + PS4: 3 + PSM: 3 + PSP2: 3 + Samsung TV: 2 + Standalone: 3 + Tizen: 2 + WP8: 3 + Web: 3 + Windows Store Apps: 3 + XBOX360: 3 + XboxOne: 3 + iPhone: 2 diff --git a/src/ProjectSettings/TagManager.asset b/src/ProjectSettings/TagManager.asset new file mode 100644 index 0000000..e903991 --- /dev/null +++ b/src/ProjectSettings/TagManager.asset @@ -0,0 +1,43 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!78 &1 +TagManager: + tags: + - + Builtin Layer 0: Default + Builtin Layer 1: TransparentFX + Builtin Layer 2: Ignore Raycast + Builtin Layer 3: + Builtin Layer 4: Water + Builtin Layer 5: UI + Builtin Layer 6: + Builtin Layer 7: + User Layer 8: + User Layer 9: + User Layer 10: + User Layer 11: + User Layer 12: + User Layer 13: + User Layer 14: + User Layer 15: + User Layer 16: + User Layer 17: + User Layer 18: + User Layer 19: + User Layer 20: + User Layer 21: + User Layer 22: + User Layer 23: + User Layer 24: + User Layer 25: + User Layer 26: + User Layer 27: + User Layer 28: + User Layer 29: + User Layer 30: + User Layer 31: + m_SortingLayers: + - name: Default + userID: 0 + uniqueID: 0 + locked: 0 diff --git a/src/ProjectSettings/TimeManager.asset b/src/ProjectSettings/TimeManager.asset new file mode 100644 index 0000000..f0e494b --- /dev/null +++ b/src/ProjectSettings/TimeManager.asset @@ -0,0 +1,8 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!5 &1 +TimeManager: + m_ObjectHideFlags: 0 + Fixed Timestep: .0199999996 + Maximum Allowed Timestep: .333333343 + m_TimeScale: 1