summaryrefslogtreecommitdiff
path: root/Xamarin.Forms.Loader
diff options
context:
space:
mode:
Diffstat (limited to 'Xamarin.Forms.Loader')
-rw-r--r--Xamarin.Forms.Loader/ExemptMembers.cs157
-rw-r--r--Xamarin.Forms.Loader/FormsLoader.cs51
-rw-r--r--Xamarin.Forms.Loader/FormsMember.cs17
-rw-r--r--Xamarin.Forms.Loader/FormsType.cs46
-rw-r--r--Xamarin.Forms.Loader/ILoaderElement.cs7
-rw-r--r--Xamarin.Forms.Loader/InvalidTestCloudUploadParameters.cs17
-rw-r--r--Xamarin.Forms.Loader/LoaderException.cs8
-rw-r--r--Xamarin.Forms.Loader/LoaderExtensions.cs126
-rw-r--r--Xamarin.Forms.Loader/Logger.cs30
-rw-r--r--Xamarin.Forms.Loader/LoggerWriter.cs8
-rw-r--r--Xamarin.Forms.Loader/MissingCategoryOnTestFixtureException.cs17
-rw-r--r--Xamarin.Forms.Loader/Properties/AssemblyInfo.cs42
-rw-r--r--Xamarin.Forms.Loader/TestMember.cs43
-rw-r--r--Xamarin.Forms.Loader/TestType.cs41
-rw-r--r--Xamarin.Forms.Loader/Xamarin.Forms.Loader.csproj108
-rw-r--r--Xamarin.Forms.Loader/packages.config4
16 files changed, 722 insertions, 0 deletions
diff --git a/Xamarin.Forms.Loader/ExemptMembers.cs b/Xamarin.Forms.Loader/ExemptMembers.cs
new file mode 100644
index 00000000..da997f79
--- /dev/null
+++ b/Xamarin.Forms.Loader/ExemptMembers.cs
@@ -0,0 +1,157 @@
+using System;
+using System.Collections.Generic;
+
+namespace Xamarin.Forms.Loader
+{
+ internal static class ExemptMembers
+ {
+ public static Dictionary<Type, IEnumerable<string>> UnitTestedTypes = new Dictionary<Type, IEnumerable<string>>
+ {
+ // Unit tested
+ { typeof (BindingTypeConverter), new[] { "CanConvertFrom", "ConvertFrom" } },
+ { typeof (DateChangedEventArgs), new[] { "OldDate", "NewDate" } },
+ { typeof (ElementEventArgs), new[] { "Element" } },
+ { typeof (ItemTappedEventArgs), new[] { "Group", "Item" } },
+ { typeof (ItemVisibilityEventArgs), new[] { "Item" } },
+ { typeof (NavigationEventArgs), new[] { "Page" } },
+ {
+ typeof (BindableObject),
+ new[]
+ {
+ "SetValue", "SetValue", "GetValue", "ClearValue", "ClearValue", "SetBinding", "RemoveBinding", "BindingContext",
+ "PropertyChanging", "PropertyChanged", "BindingContextChanged"
+ }
+ },
+ { typeof (BindableObjectExtensions), new[] { "SetBinding", "SetBinding" } },
+ {
+ typeof (BindableProperty),
+ new[]
+ {
+ "Create", "CreateReadOnly", "Create", "CreateReadOnly", "CreateAttached", "CreateAttachedReadOnly",
+ "CreateAttachedReadOnly", "CreateAttached", "PropertyName", "ReturnType", "DeclaringType", "DefaultValue",
+ "DefaultBindingMode", "IsReadOnly"
+ }
+ },
+ {
+ typeof (BindingBase),
+ new[] { "EnableCollectionSynchronization", "DisableCollectionSynchronization", "Mode", "StringFormat" }
+ },
+ { typeof (PropertyChangingEventArgs), new[] { "PropertyName" } },
+ { typeof (SelectedItemChangedEventArgs), new[] { "SelectedItem" } },
+ { typeof (TextChangedEventArgs), new[] { "OldTextValue", "NewTextValue" } },
+ { typeof (ToggledEventArgs), new[] { "Value" } },
+ { typeof (TypeConverter), new[] { "CanConvertFrom", "ConvertFrom", "ConvertFrom" } },
+ { typeof (View), new[] { "VerticalOptions", "HorizontalOptions" } },
+ { typeof (Easing), new[] { "Ease" } },
+ { typeof (NavigationPage), new[] { "CurrentPage", "Pushed", "PoppedToRoot" } },
+ { typeof (Page), new[] { "ForceLayout", "Padding", "LayoutChanged" } },
+ { typeof (RectangleTypeConverter), new[] { "CanConvertFrom", "ConvertFrom" } },
+ { typeof (ColorTypeConverter), new[] { "CanConvertFrom", "ConvertFrom" } },
+ {
+ typeof (ResourceDictionary),
+ new[] { "Add", "Clear", "ContainsKey", "GetEnumerator", "Remove", "TryGetValue", "Item", "Count", "Keys", "Values" }
+ },
+ { typeof (PointTypeConverter), new[] { "CanConvertFrom", "ConvertFrom" } },
+ { typeof (ThicknessTypeConverter), new[] { "CanConvertFrom", "ConvertFrom" } },
+ { typeof (ToolbarItem), new[] { "CommandParameter" } },
+ { typeof (MessagingCenter), new[] { "Subscribe", "Subscribe", "Unsubscribe", "Unsubscribe", "Send", "Send" } },
+ { typeof (TextCell), new[] { "CommandParameter" } },
+ { typeof (ItemsView<>), new[] { "ItemsSource", "ItemTemplate" } },
+ {
+ typeof (TableSectionBase),
+ new[]
+ {
+ "GetEnumerator", "Add", "Add", "Clear", "Contains", "CopyTo", "Remove", "IndexOf", "Insert", "RemoveAt", "Count",
+ "Item", "CollectionChanged"
+ }
+ },
+ { typeof (DataTemplate), new[] { "CreateContent", "SetBinding", "SetValue", "Bindings", "Values" } },
+ { typeof (AbsoluteLayout), new[] { "GetLayoutFlags", "GetLayoutBounds", "AutoSize" } },
+ { typeof (BoundsTypeConverter), new[] { "CanConvertFrom", "ConvertFrom" } },
+ { typeof (Button), new[] { "CommandParameter" } },
+ { typeof (Command), new[] { "Execute", "CanExecute", "ChangeCanExecute", "CanExecuteChanged" } },
+ { typeof (DependencyService), new[] { "Get" } },
+ { typeof (KeyboardTypeConverter), new[] { "CanConvertFrom", "ConvertFrom" } },
+ { typeof (MasterDetailPage), new[] { "IsPresentedChanged" } },
+ { typeof (ProgressBar), new[] { "ProgressTo" } },
+ { typeof (Constraint), new[] { "Constant", "RelativeToParent", "RelativeToView", "FromExpression" } },
+ { typeof (ConstraintExpression), new[] { "ProvideValue", "Type", "Constant", "Factor", "Property", "ElementName" } },
+ { typeof (ConstraintTypeConverter), new[] { "CanConvertFrom", "ConvertFrom" } },
+ { typeof (BoundsConstraint), new[] { "FromExpression" } },
+ {
+ typeof (RelativeLayout),
+ new[] { "GetXConstraint", "GetYConstraint", "GetWidthConstraint", "GetHeightConstraint", "GetBoundsConstraint" }
+ },
+ { typeof (ScrollView), new[] { "ContentSize" } },
+ { typeof (SearchBar), new[] { "SearchCommandParameter" } },
+ { typeof (Slider), new[] { "ValueChanged" } },
+ { typeof (Stepper), new[] { "ValueChanged" } },
+ { typeof (Switch), new[] { "Toggled" } },
+ { typeof (TemplateExtensions), new[] { "SetBinding" } },
+ {
+ typeof (ViewExtensions),
+ new[]
+ {
+ "TranslateTo", "LayoutTo", "RelRotateTo", "RelScaleTo", "RotateTo", "RotateYTo", "RotateXTo", "ScaleTo", "FadeTo",
+ "CancelAnimations"
+ }
+ },
+ { typeof (WebView), new[] { "Eval", "GoBack", "GoForward", "CanGoBack", "CanGoForward", "Navigating", "Navigated" } },
+ { typeof (WebViewSourceTypeConverter), new[] { "CanConvertFrom", "ConvertFrom" } },
+ {
+ typeof (Animation),
+ new[] { "GetEnumerator", "Insert", "Commit", "Add", "WithConcurrent", "WithConcurrent", "GetCallback" }
+ },
+ {
+ typeof (AnimationExtensions),
+ new[]
+ {
+ "AnimateKinetic", "Animate", "Interpolate", "Animate", "Animate", "Animate", "AbortAnimation",
+ "AnimationIsRunning"
+ }
+ },
+ { typeof (UriTypeConverter), new[] { "CanConvertFrom", "ConvertFrom" } },
+ { typeof (GridLengthTypeConverter), new[] { "CanConvertFrom", "ConvertFrom" } },
+ { typeof (Grid), new[] { "GetRow", "GetRowSpan", "GetColumn", "GetColumnSpan" } },
+ { typeof (RowDefinition), new[] { "Height", "SizeChanged" } },
+ { typeof (ColumnDefinition), new[] { "Width", "SizeChanged" } },
+ {
+ typeof (DefinitionCollection<>),
+ new[]
+ {
+ "IndexOf", "Insert", "RemoveAt", "Add", "Clear", "Contains", "CopyTo", "Remove", "GetEnumerator", "Item", "Count",
+ "IsReadOnly", "ItemSizeChanged"
+ }
+ },
+ {
+ typeof (Element),
+ new[]
+ {
+ "Parent", "ParentView", "ClassId", "StyleId", "Id", "ChildAdded", "ChildRemoved", "DescendantAdded",
+ "DescendantRemoved"
+ }
+ },
+ { typeof (Layout), new[] { "GetSizeRequest", "ForceLayout", "LayoutChildIntoBoundingRegion", "LayoutChanged" } },
+ { typeof (FocusEventArgs), new[] { "IsFocused", "VisualElement" } },
+ {
+ typeof (VisualElement),
+ new[]
+ {
+ "BatchBegin", "BatchCommit", "GetSizeRequest", "WidthRequest", "HeightRequest", "MinimumWidthRequest",
+ "MinimumHeightRequest", "Resources", "ChildrenReordered", "SizeChanged", "MeasureInvalidated", "Focused",
+ "Unfocused"
+ }
+ },
+ { typeof (NameScopeExtensions), new[] { "FindByName" } },
+ { typeof (FontTypeConverter), new[] { "CanConvertFrom", "ConvertFrom" } },
+ { typeof (Picker), new[] { "SelectedIndexChanged" } },
+ { typeof (BindablePropertyKey), new[] { "BindableProperty" } },
+ { typeof (TappedEventArgs), new[] { "Parameter" } }
+ };
+
+ public static Dictionary<Type, IEnumerable<string>> CannotTestTypes = new Dictionary<Type, IEnumerable<string>>
+ {
+ { typeof (Button), new[] { "BorderColor", "BorderRadius", "BorderWidth", "Image" } }
+ };
+ }
+} \ No newline at end of file
diff --git a/Xamarin.Forms.Loader/FormsLoader.cs b/Xamarin.Forms.Loader/FormsLoader.cs
new file mode 100644
index 00000000..d6826830
--- /dev/null
+++ b/Xamarin.Forms.Loader/FormsLoader.cs
@@ -0,0 +1,51 @@
+using System.Collections.Generic;
+using System.Linq;
+using Xamarin.Forms.Core.UITests;
+
+namespace Xamarin.Forms.Loader
+{
+ internal sealed class FormsLoader
+ {
+ static IEnumerable<FormsType> formsTypes;
+ static IEnumerable<TestType> iOSTestTypes;
+ static IEnumerable<TestType> androidTestTypes;
+
+ public FormsLoader()
+ {
+ var formsCoreAssembly = typeof (View).Assembly;
+ var iOSUITestAssembly = typeof (iOSLoaderIdentifier).Assembly;
+ var androidUITestAssembly = typeof (AndroidLoaderIdentifier).Assembly;
+
+ // skip interfaces, delegates, classes that inherit from attribute
+ formsTypes =
+ from o in formsCoreAssembly.GetTypes()
+ where o.IsVisible && o.IsClass && !o.IsDelegate() && !o.InheritsFromAttribute() && !o.InheritsFromException()
+ select new FormsType(this, o);
+
+ iOSTestTypes =
+ from o in iOSUITestAssembly.GetTypes()
+ where o.IsTestFixture() && o.HasCategoryAttribute()
+ select new TestType(this, o);
+
+ androidTestTypes =
+ from o in androidUITestAssembly.GetTypes()
+ where o.IsTestFixture() && o.HasCategoryAttribute()
+ select new TestType(this, o);
+ }
+
+ public IEnumerable<FormsType> FormsTypes()
+ {
+ return formsTypes;
+ }
+
+ public IEnumerable<TestType> IOSTestTypes()
+ {
+ return iOSTestTypes;
+ }
+
+ public IEnumerable<TestType> AndroidTestTypes()
+ {
+ return androidTestTypes;
+ }
+ }
+} \ No newline at end of file
diff --git a/Xamarin.Forms.Loader/FormsMember.cs b/Xamarin.Forms.Loader/FormsMember.cs
new file mode 100644
index 00000000..1d12ddf9
--- /dev/null
+++ b/Xamarin.Forms.Loader/FormsMember.cs
@@ -0,0 +1,17 @@
+using System.Reflection;
+
+namespace Xamarin.Forms.Loader
+{
+ internal sealed class FormsMember : ILoaderElement
+ {
+ internal FormsMember(FormsType formsType, MemberInfo memberInfo)
+ {
+ FormsType = formsType;
+ MemberInfo = memberInfo;
+ }
+
+ public FormsType FormsType { get; }
+
+ public MemberInfo MemberInfo { get; }
+ }
+} \ No newline at end of file
diff --git a/Xamarin.Forms.Loader/FormsType.cs b/Xamarin.Forms.Loader/FormsType.cs
new file mode 100644
index 00000000..44b4af7a
--- /dev/null
+++ b/Xamarin.Forms.Loader/FormsType.cs
@@ -0,0 +1,46 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+
+namespace Xamarin.Forms.Loader
+{
+ internal sealed class FormsType : ILoaderElement
+ {
+ readonly IEnumerable<FormsMember> formsMembers;
+
+ internal FormsType(FormsLoader formsLoader, Type type)
+ {
+ FormsLoader = formsLoader;
+ Type = type;
+
+ const BindingFlags bindingFlags = BindingFlags.DeclaredOnly |
+ BindingFlags.Public |
+ BindingFlags.Instance |
+ BindingFlags.Static;
+
+ const MemberTypes memberTypes = MemberTypes.Event |
+ MemberTypes.Method |
+ MemberTypes.Property;
+
+ formsMembers =
+ from o in Type.GetMember("*", memberTypes, bindingFlags)
+ where
+ o.IsPublic() &&
+ !o.IsCompilerGenerated() &&
+ !o.IsEqualityOverride() &&
+ !o.IsToStringOverride() &&
+ !LoaderExtensions.IsUnitTested(type, o)
+ select new FormsMember(this, o);
+ }
+
+ public FormsLoader FormsLoader { get; }
+
+ public Type Type { get; }
+
+ public IEnumerable<FormsMember> Members()
+ {
+ return formsMembers;
+ }
+ }
+} \ No newline at end of file
diff --git a/Xamarin.Forms.Loader/ILoaderElement.cs b/Xamarin.Forms.Loader/ILoaderElement.cs
new file mode 100644
index 00000000..7d703fdb
--- /dev/null
+++ b/Xamarin.Forms.Loader/ILoaderElement.cs
@@ -0,0 +1,7 @@
+namespace Xamarin.Forms.Loader
+{
+ internal interface ILoaderElement
+ {
+ string ToString();
+ }
+} \ No newline at end of file
diff --git a/Xamarin.Forms.Loader/InvalidTestCloudUploadParameters.cs b/Xamarin.Forms.Loader/InvalidTestCloudUploadParameters.cs
new file mode 100644
index 00000000..a48cd587
--- /dev/null
+++ b/Xamarin.Forms.Loader/InvalidTestCloudUploadParameters.cs
@@ -0,0 +1,17 @@
+namespace Xamarin.Forms.Loader
+{
+ public sealed class InvalidTestCloudUploadParameters : LoaderException
+ {
+ readonly string parameters;
+
+ public InvalidTestCloudUploadParameters(string parameters)
+ {
+ this.parameters = parameters;
+ }
+
+ public override string Message
+ {
+ get { return "Missing Category attribute: " + parameters; }
+ }
+ }
+} \ No newline at end of file
diff --git a/Xamarin.Forms.Loader/LoaderException.cs b/Xamarin.Forms.Loader/LoaderException.cs
new file mode 100644
index 00000000..895a5198
--- /dev/null
+++ b/Xamarin.Forms.Loader/LoaderException.cs
@@ -0,0 +1,8 @@
+using System;
+
+namespace Xamarin.Forms.Loader
+{
+ public class LoaderException : Exception
+ {
+ }
+} \ No newline at end of file
diff --git a/Xamarin.Forms.Loader/LoaderExtensions.cs b/Xamarin.Forms.Loader/LoaderExtensions.cs
new file mode 100644
index 00000000..9c0b91fa
--- /dev/null
+++ b/Xamarin.Forms.Loader/LoaderExtensions.cs
@@ -0,0 +1,126 @@
+using System;
+using System.Linq;
+using System.Reflection;
+using NUnit.Framework;
+using Xamarin.Forms.CustomAttributes;
+
+namespace Xamarin.Forms.Loader
+{
+ internal static class LoaderExtensions
+ {
+ public static bool InheritsFromException(this Type type)
+ {
+ if (type.IsSubclassOf(typeof (Exception)))
+ return true;
+ return false;
+ }
+
+ public static bool InheritsFromAttribute(this Type type)
+ {
+ if (type.IsSubclassOf(typeof (Attribute)))
+ return true;
+ return false;
+ }
+
+ public static bool IsDelegate(this Type type)
+ {
+ // ignore delegates
+ if (type.BaseType == typeof (MulticastDelegate))
+ return true;
+ return false;
+ }
+
+ public static bool IsTestFixture(this Type type)
+ {
+ var attributes = type.GetCustomAttributes();
+ if (attributes.OfType<TestFixtureAttribute>().Any())
+ return true;
+ return false;
+ }
+
+ public static bool HasTestAttribute(this MemberInfo memberInfo)
+ {
+ var attributes = memberInfo.GetCustomAttributes();
+ return attributes.Any(attr => attr is UiTestAttribute);
+ }
+
+ public static bool IsUnitTested(Type type, MemberInfo memberInfo)
+ {
+ if (ExemptMembers.UnitTestedTypes.ContainsKey(type))
+ {
+ if (ExemptMembers.UnitTestedTypes[type].Contains(memberInfo.Name))
+ return true;
+ }
+ return false;
+ }
+
+ public static bool HasTestExemptAttribute(this MemberInfo memberInfo)
+ {
+ var attributes = memberInfo.GetCustomAttributes();
+ return attributes.Any(attr => attr is UiTestExemptAttribute);
+ }
+
+ public static bool IsSetupOrTearDown(this MemberInfo memberInfo)
+ {
+ var attributes = memberInfo.GetCustomAttributes();
+ return
+ attributes.Any(
+ attr =>
+ attr is SetUpAttribute || attr is TearDownAttribute || attr is TestFixtureSetUpAttribute ||
+ attr is TestFixtureTearDownAttribute);
+ }
+
+ public static bool IsEqualityOverride(this MemberInfo memberInfo)
+ {
+ return
+ memberInfo.Name == "Equals" ||
+ memberInfo.Name == "GetHashCode" ||
+ memberInfo.Name == "GetType";
+ }
+
+ public static bool IsToStringOverride(this MemberInfo memberInfo)
+ {
+ return memberInfo.Name == "ToString";
+ }
+
+ public static bool HasCategoryAttribute(this Type type)
+ {
+ var attributes = type.GetCustomAttributes();
+ if (attributes.OfType<CategoryAttribute>().Any())
+ return true;
+ //throw new MissingCategoryOnTestFixtureException (type.Name);
+ return false;
+ }
+
+ public static bool IsPublic(this MemberInfo memberInfo)
+ {
+ var type = memberInfo as Type;
+ if (type != null)
+ return type.IsPublic;
+
+ var method = memberInfo as MethodInfo;
+ if (method != null)
+ return method.IsPublic;
+
+ var property = memberInfo as PropertyInfo;
+ if (property != null)
+ return true; // binding flags determine public
+
+ var evt = memberInfo as EventInfo;
+ if (evt != null)
+ return true; // binding flags determine public
+
+ throw new LoaderException();
+ }
+
+ public static bool IsCompilerGenerated(this MemberInfo memberInfo)
+ {
+ // ignore autogenerated get_ and set_ methods
+ var method = memberInfo as MethodInfo;
+ if (method != null && method.IsSpecialName)
+ return true;
+
+ return false;
+ }
+ }
+} \ No newline at end of file
diff --git a/Xamarin.Forms.Loader/Logger.cs b/Xamarin.Forms.Loader/Logger.cs
new file mode 100644
index 00000000..ad0877e8
--- /dev/null
+++ b/Xamarin.Forms.Loader/Logger.cs
@@ -0,0 +1,30 @@
+using System.IO;
+
+namespace Xamarin.Forms.Loader
+{
+ internal static class Logger
+ {
+ static StreamWriter writer;
+
+ public static void Init()
+ {
+ writer = new StreamWriter("../../Logs/Xamarin.Forms.UITest.Validator.log", false);
+ }
+
+ public static void Log(string text)
+ {
+ writer.WriteLine(text);
+ }
+
+ public static void LogLine(string line = "")
+ {
+ writer.WriteLine(line);
+ }
+
+ public static void Close()
+ {
+ writer.Flush();
+ writer.Close();
+ }
+ }
+} \ No newline at end of file
diff --git a/Xamarin.Forms.Loader/LoggerWriter.cs b/Xamarin.Forms.Loader/LoggerWriter.cs
new file mode 100644
index 00000000..98939795
--- /dev/null
+++ b/Xamarin.Forms.Loader/LoggerWriter.cs
@@ -0,0 +1,8 @@
+namespace Xamarin.Forms.Loader
+{
+ internal enum LoggerWriter
+ {
+ Core,
+ Test
+ }
+} \ No newline at end of file
diff --git a/Xamarin.Forms.Loader/MissingCategoryOnTestFixtureException.cs b/Xamarin.Forms.Loader/MissingCategoryOnTestFixtureException.cs
new file mode 100644
index 00000000..a4cd4348
--- /dev/null
+++ b/Xamarin.Forms.Loader/MissingCategoryOnTestFixtureException.cs
@@ -0,0 +1,17 @@
+namespace Xamarin.Forms.Loader
+{
+ public sealed class MissingCategoryOnTestFixtureException : LoaderException
+ {
+ readonly string fixtureName;
+
+ public MissingCategoryOnTestFixtureException(string fixtureName)
+ {
+ this.fixtureName = fixtureName;
+ }
+
+ public override string Message
+ {
+ get { return "Missing Category attribute: " + fixtureName; }
+ }
+ }
+} \ No newline at end of file
diff --git a/Xamarin.Forms.Loader/Properties/AssemblyInfo.cs b/Xamarin.Forms.Loader/Properties/AssemblyInfo.cs
new file mode 100644
index 00000000..b9ca2d1a
--- /dev/null
+++ b/Xamarin.Forms.Loader/Properties/AssemblyInfo.cs
@@ -0,0 +1,42 @@
+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("Xamarin.Form.FormsLoader")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("Xamarin.Form.FormsLoader")]
+[assembly: AssemblyCopyright("Copyright © 2014")]
+[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("c1b9ec92-9f75-41a1-a3fa-e88d59af6794")]
+
+// 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 Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
+[assembly: InternalsVisibleTo("Xamarin.Forms.UITest.Validator")]
+[assembly: InternalsVisibleTo("Xamarin.Forms.UITest.TestCloud")] \ No newline at end of file
diff --git a/Xamarin.Forms.Loader/TestMember.cs b/Xamarin.Forms.Loader/TestMember.cs
new file mode 100644
index 00000000..95eb0ec9
--- /dev/null
+++ b/Xamarin.Forms.Loader/TestMember.cs
@@ -0,0 +1,43 @@
+using System.Collections.Generic;
+using System.Reflection;
+using NUnit.Framework;
+using Xamarin.Forms.CustomAttributes;
+
+namespace Xamarin.Forms.Loader
+{
+ internal sealed class TestMember : ILoaderElement
+ {
+ readonly IEnumerable<CategoryAttribute> categoryAttributes;
+
+ readonly IEnumerable<UiTestAttribute> uiTestAttributes;
+
+ public TestMember(TestType uiTestType, MemberInfo memberInfo)
+ {
+ DeclaringType = uiTestType;
+ MemberInfo = memberInfo;
+
+ // handle public overrides that inherit attributes
+ uiTestAttributes = memberInfo.GetCustomAttributes<UiTestAttribute>();
+ categoryAttributes = memberInfo.GetCustomAttributes<CategoryAttribute>();
+ }
+
+ internal FormsLoader FormsLoader
+ {
+ get { return DeclaringType.FormsLoader; }
+ }
+
+ public TestType DeclaringType { get; }
+
+ public MemberInfo MemberInfo { get; }
+
+ public IEnumerable<UiTestAttribute> UiTestAttributes()
+ {
+ return uiTestAttributes;
+ }
+
+ public IEnumerable<CategoryAttribute> CategoryAttributes()
+ {
+ return categoryAttributes;
+ }
+ }
+} \ No newline at end of file
diff --git a/Xamarin.Forms.Loader/TestType.cs b/Xamarin.Forms.Loader/TestType.cs
new file mode 100644
index 00000000..50e0e639
--- /dev/null
+++ b/Xamarin.Forms.Loader/TestType.cs
@@ -0,0 +1,41 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using NUnit.Framework;
+
+namespace Xamarin.Forms.Loader
+{
+ internal sealed class TestType : ILoaderElement
+ {
+ readonly IEnumerable<CategoryAttribute> _categories;
+ readonly IEnumerable<TestMember> _members;
+
+ internal TestType(FormsLoader formsLoader, Type type)
+ {
+ FormsLoader = formsLoader;
+ Type = type;
+
+ _members =
+ from o in Type.GetMethods()
+ where !o.IsSetupOrTearDown() && !o.IsEqualityOverride() && !o.IsToStringOverride()
+ select new TestMember(this, o);
+
+ _categories = type.GetCustomAttributes<CategoryAttribute>();
+ }
+
+ public FormsLoader FormsLoader { get; }
+
+ public Type Type { get; }
+
+ public IEnumerable<TestMember> Members()
+ {
+ return _members;
+ }
+
+ public IEnumerable<CategoryAttribute> Categories()
+ {
+ return _categories;
+ }
+ }
+} \ No newline at end of file
diff --git a/Xamarin.Forms.Loader/Xamarin.Forms.Loader.csproj b/Xamarin.Forms.Loader/Xamarin.Forms.Loader.csproj
new file mode 100644
index 00000000..8bb0151d
--- /dev/null
+++ b/Xamarin.Forms.Loader/Xamarin.Forms.Loader.csproj
@@ -0,0 +1,108 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProjectGuid>{00211725-2F89-4E2C-AC5A-38E5FF61BE67}</ProjectGuid>
+ <OutputType>Library</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>Xamarin.Forms.Loader</RootNamespace>
+ <AssemblyName>Xamarin.Forms.Loader</AssemblyName>
+ <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
+ <FileAlignment>512</FileAlignment>
+ <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\</SolutionDir>
+ <RestorePackages>true</RestorePackages>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>bin\Debug\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\Release\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Turkey|AnyCPU'">
+ <DebugSymbols>true</DebugSymbols>
+ <OutputPath>bin\Turkey\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <DebugType>full</DebugType>
+ <PlatformTarget>AnyCPU</PlatformTarget>
+ <ErrorReport>prompt</ErrorReport>
+ <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="nunit.framework, Version=2.6.4.14350, Culture=neutral, PublicKeyToken=96d09a1eb7f44a77, processorArchitecture=MSIL">
+ <SpecificVersion>False</SpecificVersion>
+ <HintPath>..\packages\NUnit.2.6.4\lib\nunit.framework.dll</HintPath>
+ </Reference>
+ <Reference Include="System" />
+ <Reference Include="System.Core" />
+ <Reference Include="System.Xml.Linq" />
+ <Reference Include="System.Data.DataSetExtensions" />
+ <Reference Include="Microsoft.CSharp" />
+ <Reference Include="System.Data" />
+ <Reference Include="System.Xml" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="ExemptMembers.cs" />
+ <Compile Include="FormsMember.cs" />
+ <Compile Include="FormsType.cs" />
+ <Compile Include="ILoaderElement.cs" />
+ <Compile Include="FormsLoader.cs" />
+ <Compile Include="InvalidTestCloudUploadParameters.cs" />
+ <Compile Include="LoaderException.cs" />
+ <Compile Include="LoaderExtensions.cs" />
+ <Compile Include="Logger.cs" />
+ <Compile Include="LoggerWriter.cs" />
+ <Compile Include="MissingCategoryOnTestFixtureException.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ <Compile Include="TestMember.cs" />
+ <Compile Include="TestType.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\Xamarin.Forms.Core.Android.UITests\Xamarin.Forms.Core.Android.UITests.csproj">
+ <Project>{a34ebe01-25bf-4e69-a2dc-2288dc625541}</Project>
+ <Name>Xamarin.Forms.Core.Android.UITests</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\Xamarin.Forms.Core.iOS.UITests\Xamarin.Forms.Core.iOS.UITests.csproj">
+ <Project>{eadd8100-b3ae-4a31-92c4-267a64a1c6eb}</Project>
+ <Name>Xamarin.Forms.Core.iOS.UITests</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\Xamarin.Forms.Core\Xamarin.Forms.Core.csproj">
+ <Project>{57b8b73d-c3b5-4c42-869e-7b2f17d354ac}</Project>
+ <Name>Xamarin.Forms.Core</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\Xamarin.Forms.CustomAttributes\Xamarin.Forms.CustomAttributes.csproj">
+ <Project>{4dcd0420-1168-4b77-86db-6196ee4bd491}</Project>
+ <Name>Xamarin.Forms.CustomAttributes</Name>
+ </ProjectReference>
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="packages.config" />
+ </ItemGroup>
+ <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+ <Import Project="$(SolutionDir)\.nuget\NuGet.targets" Condition="Exists('$(SolutionDir)\.nuget\NuGet.targets')" />
+ <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
+ <PropertyGroup>
+ <ErrorText>This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
+ </PropertyGroup>
+ <Error Condition="!Exists('$(SolutionDir)\.nuget\NuGet.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\.nuget\NuGet.targets'))" />
+ </Target>
+ <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+ Other similar extension points exist, see Microsoft.Common.targets.
+ <Target Name="BeforeBuild">
+ </Target>
+ <Target Name="AfterBuild">
+ </Target>
+ -->
+</Project> \ No newline at end of file
diff --git a/Xamarin.Forms.Loader/packages.config b/Xamarin.Forms.Loader/packages.config
new file mode 100644
index 00000000..c714ef3a
--- /dev/null
+++ b/Xamarin.Forms.Loader/packages.config
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<packages>
+ <package id="NUnit" version="2.6.4" targetFramework="net45" />
+</packages> \ No newline at end of file