Skip to content

Commit

Permalink
Merge branch 'master' into Tests
Browse files Browse the repository at this point in the history
  • Loading branch information
nieve committed May 2, 2010
2 parents 045af9d + 7cb3eea commit 4dbd9de
Show file tree
Hide file tree
Showing 25 changed files with 503 additions and 18 deletions.
3 changes: 2 additions & 1 deletion .gitignore
@@ -1,3 +1,4 @@
push.bat
TestResult.xml
build
obj
Expand All @@ -8,7 +9,7 @@ src/CommonAssemblyInfo.cs
_ReSharper.*
*.csproj.user
*.resharper.user
*.resharper
*.ReSharper.user
*.suo
*.cache
~$*
6 changes: 6 additions & 0 deletions src/FubuCore/Binding/BindingContext.cs
Expand Up @@ -3,6 +3,7 @@
using System.Linq;
using System.Reflection;
using FubuCore.Binding;
using FubuMVC.Core;
using Microsoft.Practices.ServiceLocation;

namespace FubuCore.Binding
Expand Down Expand Up @@ -127,6 +128,11 @@ public void LogProblem(string exceptionText)
public void BindChild(PropertyInfo property, Type childType, string prefix)
{
var target = Object;
if (_propertyStack.Any(p => p.PropertyType == childType))
{
_propertyStack.Push(property);
throw new FubuException(2202, "Infinite recursion detected while binding child properties: {0} would try to resolve {1} again.", string.Join("=>", _propertyStack.Reverse().Select(p => "{1}.{0}".ToFormat(p.Name, p.ReflectedType.Name)).ToArray()), childType.Name);
}
_propertyStack.Push(property);

var resolver = Service<IObjectResolver>();
Expand Down
12 changes: 12 additions & 0 deletions src/FubuCore/Reflection/ReflectionExtensions.cs
Expand Up @@ -43,6 +43,18 @@ public static class ReflectionExtensions
}
}

public static void ForAttribute<T>(this ICustomAttributeProvider provider, Action<T> action, Action elseDo) where T : Attribute
{
bool found = false;
foreach (T attribute in provider.GetCustomAttributes(typeof(T), true))
{
action(attribute);
found = true;
}

if (!found) elseDo();
}

public static void ForAttribute<T>(this Accessor accessor, Action<T> action) where T : Attribute
{
foreach (T attribute in accessor.InnerProperty.GetCustomAttributes(typeof (T), true))
Expand Down
16 changes: 16 additions & 0 deletions src/FubuMVC.5.0.ReSharper
@@ -0,0 +1,16 @@
<Configuration>
<SharedSolutionTemplateManager>
<LiveTemplates>
<Template uid="c7021f12-6126-43b0-9e05-5f94d617d1e1" shortcut="pvt" description="New test case" text="[Test]&#xD;&#xA;public void $TESTNAME$()&#xD;&#xA;{&#xD;&#xA; $END$&#xD;&#xA;}" reformat="True" shortenQualifiedReferences="True">
<Context>
<CSharpContext context="TypeMember" minimumLanguageVersion="2.0" />
</Context>
<Categories />
<Variables>
<Variable name="TESTNAME" expression="" initialRange="0" />
</Variables>
<CustomProperties />
</Template>
</LiveTemplates>
</SharedSolutionTemplateManager>
</Configuration>
19 changes: 19 additions & 0 deletions src/FubuMVC.Core/Attributes.cs
Expand Up @@ -80,4 +80,23 @@ public WebFormsEndpointAttribute(Type viewType)
public class FubuPartialAttribute : Attribute
{
}

/// <summary>
/// Just declares
/// </summary>
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, AllowMultiple = false)]
public class UrlRegistryCategoryAttribute : Attribute
{
private readonly string _category;

public UrlRegistryCategoryAttribute(string category)
{
_category = category;
}

public string Category
{
get { return _category; }
}
}
}
1 change: 1 addition & 0 deletions src/FubuMVC.Core/FubuMVC.Core.csproj
Expand Up @@ -122,6 +122,7 @@
<Compile Include="Registration\Conventions\JsonMessageInputConvention.cs" />
<Compile Include="Registration\Conventions\NulloRouteDefinition.cs" />
<Compile Include="Registration\Conventions\RouteConstraintPolicy.cs" />
<Compile Include="Registration\Conventions\UrlRegistryCategoryConvention.cs" />
<Compile Include="Registration\DSL\ModelsExpression.cs" />
<Compile Include="Registration\DSL\PoliciesExpression.cs" />
<Compile Include="Registration\Conventions\ActionCallModification.cs" />
Expand Down
6 changes: 3 additions & 3 deletions src/FubuMVC.Core/FubuRegistry.Expressions.cs
Expand Up @@ -155,9 +155,9 @@ private void setupServices(BehaviorGraph graph)
graph.Services.SetServiceIfNone<IPropertyBinderCache, PropertyBinderCache>();
graph.Services.SetServiceIfNone<IModelBinderCache, ModelBinderCache>();
graph.Services.SetServiceIfNone<IDisplayFormatter, DisplayFormatter>();

graph.Services.SetServiceIfNone<ITypeDescriptorCache, TypeDescriptorCache>();
graph.Services.SetServiceIfNone(_partialViewTypes);

graph.Services.SetServiceIfNone<ITypeDescriptorCache, TypeDescriptorCache>();
graph.Services.SetServiceIfNone(_partialViewTypes);

graph.Services.SetServiceIfNone<IStreamingData, StreamingData>();
graph.Services.SetServiceIfNone<IJsonReader, JavaScriptJsonReader>();
Expand Down
1 change: 1 addition & 0 deletions src/FubuMVC.Core/FubuRegistry.cs
Expand Up @@ -62,6 +62,7 @@ public FubuRegistry()

_conventions.Add(_viewAttacher);
Policies.Add<JsonMessageInputConvention>();
Policies.Add<UrlRegistryCategoryConvention>();
}

public FubuRegistry(Action<FubuRegistry> configure)
Expand Down
@@ -0,0 +1,18 @@
using System;
using System.Collections.Generic;
using FubuCore.Reflection;

namespace FubuMVC.Core.Registration.Conventions
{
public class UrlRegistryCategoryConvention : IConfigurationAction
{
public void Configure(BehaviorGraph graph)
{
graph.Actions().Each(a =>
{
a.HandlerType.ForAttribute<UrlRegistryCategoryAttribute>(att => a.ParentChain().Route.Category = att.Category);
a.Method.ForAttribute<UrlRegistryCategoryAttribute>(att => a.ParentChain().Route.Category = att.Category);
});
}
}
}
11 changes: 11 additions & 0 deletions src/FubuMVC.Core/Registration/Nodes/BehaviorNode.cs
Expand Up @@ -53,6 +53,17 @@ public virtual IEnumerator<BehaviorNode> GetEnumerator()
}
}

public BehaviorChain ParentChain()
{
if (this is BehaviorChain) return (BehaviorChain) this;

if (Previous == null) return null;

if (Previous is BehaviorChain) return (BehaviorChain) Previous;

return Previous.ParentChain();
}

public virtual ObjectDef ToObjectDef()
{
ObjectDef objectDef = toObjectDef();
Expand Down
56 changes: 56 additions & 0 deletions src/FubuMVC.Core/Urls/IUrlRegistry.cs
@@ -1,6 +1,8 @@
using System;
using System.Linq.Expressions;
using System.Reflection;
using FubuCore.Reflection;
using FubuCore;

namespace FubuMVC.Core.Urls
{
Expand All @@ -26,4 +28,58 @@ public interface IUrlRegistry

string UrlFor(Type handlerType, MethodInfo method);
}

// This is just to have a predictable stub for unit testing
public class StubUrlRegistry : IUrlRegistry
{
public string UrlFor(object model)
{
return "url for " + model.ToString();
}

public string UrlFor(object model, string category)
{
return UrlFor(model) + ", category=" + category;
}

public string UrlFor<TController>(Expression<Action<TController>> expression)
{
return "url for " + typeof (TController).FullName + "." + ReflectionHelper.GetMethod(expression).Name + "()";
}

public string UrlForNew<T>()
{
return "url for new " + typeof (T).FullName;
}

public string UrlForNew(Type entityType)
{
return "url for new " + entityType.FullName;
}

public bool HasNewUrl<T>()
{
throw new NotImplementedException();
}

public bool HasNewUrl(Type type)
{
throw new NotImplementedException();
}

public string UrlForPropertyUpdate(object model)
{
return "url for property update: " + model.ToString();
}

public string UrlForPropertyUpdate(Type type)
{
return "url for property update: " + type.FullName;
}

public string UrlFor(Type handlerType, MethodInfo method)
{
return "url for {0}.{1}()".ToFormat(handlerType.FullName, method.Name);
}
}
}
16 changes: 15 additions & 1 deletion src/FubuMVC.Core/Urls/UrlRegistry.cs
Expand Up @@ -5,6 +5,7 @@
using System.Reflection;
using FubuCore.Reflection;
using FubuCore.Util;
using FubuCore;

namespace FubuMVC.Core.Urls
{
Expand Down Expand Up @@ -74,7 +75,7 @@ public string UrlFor(object model)
if (model == null) return null;

Type modelType = model.GetType();
List<IModelUrl> models = _byType[modelType];
var models = _byType[modelType];

switch (models.Count)
{
Expand All @@ -86,10 +87,23 @@ public string UrlFor(object model)

default:
IModelUrl defaultModel = models.FirstOrDefault(x => x.Category == Categories.DEFAULT);
if (defaultModel == null)
{
if (models.Count(x => x.Category.IsEmpty()) == 1)
{
defaultModel = models.First(x => x.Category.IsEmpty());
}
}


if (defaultModel != null)
{
return defaultModel.CreateUrl(model);
}




throw new FubuException(2103,
"More than one url is registered for {0} and none is marked as the default.\n{1}",
modelType.FullName, listAllModels(models));
Expand Down
1 change: 1 addition & 0 deletions src/FubuMVC.Tests/FubuMVC.Tests.csproj
Expand Up @@ -85,6 +85,7 @@
</Compile>
<Compile Include="AjaxExtensionsTester.cs" />
<Compile Include="Registration\attaching_behaviors_to_action_calls.cs" />
<Compile Include="Registration\Conventions\UrlRegistryCategoryConventionTester.cs" />
<Compile Include="UrlExtensionsTester.cs" />
<Compile Include="Behaviors\ActionInvokersTester.cs" />
<Compile Include="Behaviors\DeserializeJsonBehaviorTester.cs" />
Expand Down
@@ -0,0 +1,94 @@
using FubuMVC.Core;
using FubuMVC.Core.Registration;
using FubuMVC.Core.Registration.Conventions;
using FubuMVC.Core.Urls;
using NUnit.Framework;

namespace FubuMVC.Tests.Registration.Conventions
{
[TestFixture]
public class UrlRegistryCategoryConventionTester
{
#region Setup/Teardown

[SetUp]
public void SetUp()
{
graph = new FubuRegistry(x =>
{
x.Applies.ToThisAssembly();
x.Actions.IncludeTypesNamed(n => n.StartsWith("UrlCategory"));
}).BuildGraph();


}

[Test]
public void action_that_has_no_attribute_on_either_class_or_method_should_have_no_category()
{
graph.BehaviorFor<UrlCategoryController3>(x => x.Go()).Route.Category.ShouldBeNull();
graph.BehaviorFor<UrlCategoryController3>(x => x.Comeback()).Route.Category.ShouldBeNull();

}

[Test]
public void class_attribute_sets_the_category_if_there_is_no_method_level_attribute()
{
graph.BehaviorFor<UrlCategoryController1>(x => x.Go()).Route.Category.ShouldEqual("admin");
}

[Test]
public void method_attribute_has_precedence_over_class_attribute()
{
graph.BehaviorFor<UrlCategoryController1>(x => x.Comeback()).Route.Category.ShouldEqual("public");
}

[Test]
public void method_attribute_without_class_attribute()
{
graph.BehaviorFor<UrlCategoryController2>(x => x.DecoratedMethod()).Route.Category.ShouldEqual("public");
}

#endregion

private BehaviorGraph graph;
}



[UrlRegistryCategory("admin")]
public class UrlCategoryController1
{
public void Go()
{
}

[UrlRegistryCategory("public")]
public void Comeback()
{
}
}

public class UrlCategoryController2
{
public void Go()
{
}

[UrlRegistryCategory("public")]
public void DecoratedMethod()
{
}
}

public class UrlCategoryController3
{
public void Go()
{
}

public void Comeback()
{
}
}
}

0 comments on commit 4dbd9de

Please sign in to comment.