Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Extracted request dispatcher from service.

Introduced request/response features.
Introduced request/response pipeline.
Always returns a resource (instead of just a response when an error occurs etc).
Refactoring of unit tests and removal of redundant tests.
  • Loading branch information...
commit 3049c09be179f25c7d34051a7f098f8dbf8bde03 1 parent 208ebd8
@MrBretticus MrBretticus authored
Showing with 5,928 additions and 545 deletions.
  1. +2 −0  .gitignore
  2. +11 −1 RestfulieClient/RestfulieClient.csproj
  3. +11 −0 RestfulieClient/features/IRequestFeature.cs
  4. +10 −0 RestfulieClient/features/IResponseFeature.cs
  5. +56 −0 RestfulieClient/http/DefaultRequestDispatcher.cs
  6. +18 −0 RestfulieClient/request/IRequestDispatcher.cs
  7. +33 −0 RestfulieClient/request/Request.cs
  8. +20 −0 RestfulieClient/request/RequestChain.cs
  9. +37 −0 RestfulieClient/request/RequestStack.cs
  10. +33 −0 RestfulieClient/request/ResponseChain.cs
  11. +31 −24 RestfulieClient/resources/DynamicXmlResource.cs
  12. +24 −0 RestfulieClient/resources/EmptyResource.cs
  13. +89 −101 RestfulieClient/resources/EntryPointService.cs
  14. +30 −0 RestfulieClient/resources/IResource.cs
  15. +2 −1  RestfulieClient/resources/{Restifulie.cs → Restfulie.cs}
  16. +11 −7 RestfulieClient/service/HttpRemoteResponse.cs
  17. +58 −6 RestfulieClient/service/IRemoteResourceService.cs
  18. +3 −2 RestfulieClient/service/RestfulieHttpVerbDiscovery.cs
  19. +81 −0 RestfulieClientTest/BaseTest.cs
  20. +11 −94 RestfulieClientTest/DynamicXmlResourceTest.cs
  21. +139 −0 RestfulieClientTest/EntryPointServiceTests.cs
  22. +8 −66 RestfulieClientTest/EntryPointTests.cs
  23. +0 −92 RestfulieClientTest/ResourceServiceTest.cs
  24. +5 −16 RestfulieClientTest/RestfulieClientTests.csproj
  25. +12 −56 RestfulieClientTest/RestfulieHttpVerbDiscoveryTest.cs
  26. +2 −54 RestfulieClientTest/StringValueConverterTest.cs
  27. +57 −0 RestfulieClientTest/helpers/EmbeddedFileResourceDispatcher.cs
  28. +14 −20 RestfulieClientTest/helpers/LoadDocument.cs
  29. +0 −5 RestfulieClientTest/helpers/RemoteResourceFactory.cs
  30. BIN  libs/Moq-4.0/Moq.dll
  31. +5,120 −0 libs/Moq-4.0/Moq.xml
View
2  .gitignore
@@ -25,3 +25,5 @@
_ReSharper.*/
Thumbs.db
*.exe
+
+/TestResults
View
12 RestfulieClient/RestfulieClient.csproj
@@ -40,9 +40,19 @@
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
+ <Compile Include="features\IRequestFeature.cs" />
+ <Compile Include="features\IResponseFeature.cs" />
+ <Compile Include="http\DefaultRequestDispatcher.cs" />
+ <Compile Include="request\IRequestDispatcher.cs" />
+ <Compile Include="request\Request.cs" />
+ <Compile Include="request\RequestChain.cs" />
+ <Compile Include="request\RequestStack.cs" />
+ <Compile Include="request\ResponseChain.cs" />
<Compile Include="resources\DynamicXmlResource.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
- <Compile Include="resources\Restifulie.cs" />
+ <Compile Include="resources\EmptyResource.cs" />
+ <Compile Include="resources\IResource.cs" />
+ <Compile Include="resources\Restfulie.cs" />
<Compile Include="resources\EntryPointService.cs" />
<Compile Include="service\HttpRemoteResponseFactory.cs" />
<Compile Include="service\HttpRemoteResponse.cs" />
View
11 RestfulieClient/features/IRequestFeature.cs
@@ -0,0 +1,11 @@
+using System;
+using RestfulieClient.request;
+using RestfulieClient.service;
+
+namespace RestfulieClient.features
+{
+ public interface IRequestFeature
+ {
+ HttpRemoteResponse Process(RequestChain chain, Request request, string verb, Uri uri, string content);
+ }
+}
View
10 RestfulieClient/features/IResponseFeature.cs
@@ -0,0 +1,10 @@
+using RestfulieClient.request;
+using RestfulieClient.service;
+
+namespace RestfulieClient.features
+{
+ public interface IResponseFeature
+ {
+ HttpRemoteResponse Process(ResponseChain chain, HttpRemoteResponse response);
+ }
+}
View
56 RestfulieClient/http/DefaultRequestDispatcher.cs
@@ -0,0 +1,56 @@
+using System;
+using System.IO;
+using System.Linq;
+using System.Net;
+using System.Text;
+using RestfulieClient.request;
+using RestfulieClient.service;
+
+namespace RestfulieClient.http
+{
+ public class DefaultRequestDispatcher : IRequestDispatcher
+ {
+ private string GetContent(HttpWebResponse response) {
+ Stream stream = response.GetResponseStream();
+
+ if (stream == null || stream.Length == 0)
+ return null;
+
+ using (var reader = new StreamReader(stream))
+ return reader.ReadToEnd();
+ }
+
+ private void WriteContent(HttpWebRequest request, string content) {
+ byte[] byteArray = Encoding.UTF8.GetBytes(content);
+ request.ContentLength = byteArray.Length;
+ Stream bodyStream = request.GetRequestStream();
+ bodyStream.Write(byteArray, 0, byteArray.Length);
+ bodyStream.Close();
+ }
+
+ private HttpRemoteResponse GetRemoteResponse(HttpWebResponse response) {
+ return new HttpRemoteResponse(
+ response.StatusCode,
+ response.Headers.AllKeys.ToDictionary(k => k, k => response.Headers[k], StringComparer.OrdinalIgnoreCase),
+ GetContent(response));
+ }
+
+ public HttpRemoteResponse Process(IRemoteResourceService service, string verb, Uri uri, string content) {
+ HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);
+ try
+ {
+ foreach (var header in service.Headers)
+ request.Headers.Add(header.Key, header.Value);
+
+ request.Method = verb;
+ if (!String.IsNullOrWhiteSpace(content))
+ WriteContent(request, content);
+ return GetRemoteResponse((HttpWebResponse)request.GetResponse());
+ }
+ catch (Exception ex)
+ {
+ throw new ArgumentException(string.Format("An error occurred while connecting to the resource in url {0} with message {1}.", uri, ex.Message), ex);
+ }
+ }
+ }
+}
View
18 RestfulieClient/request/IRequestDispatcher.cs
@@ -0,0 +1,18 @@
+using System;
+using RestfulieClient.service;
+
+namespace RestfulieClient.request
+{
+ public interface IRequestDispatcher
+ {
+ /// <summary>
+ /// Instructs the dispatcher to process the given request based on it's current configuration
+ /// </summary>
+ /// <param name="service">The service that called the dispatcher</param>
+ /// <param name="verb">The HTTP verb to use for making the request</param>
+ /// <param name="uri">The URI to use for making the request</param>
+ /// <param name="content">The text to include in the request body</param>
+ /// <returns>The result of the request (including status code and content), will be null if using an asynch callback</returns>
+ HttpRemoteResponse Process(IRemoteResourceService service, string verb, Uri uri, string content);
+ }
+}
View
33 RestfulieClient/request/Request.cs
@@ -0,0 +1,33 @@
+using System;
+using RestfulieClient.features;
+using RestfulieClient.service;
+
+namespace RestfulieClient.request
+{
+ public class Request
+ {
+ private readonly IRequestDispatcher _dispatcher;
+ private readonly RequestStack _stack;
+
+ public IRequestDispatcher Dispatcher {
+ get { return _dispatcher; }
+ }
+
+ public Request(IRemoteResourceService service, IRequestDispatcher dispatcher) {
+ _dispatcher = dispatcher;
+ _stack = new RequestStack(service);
+ }
+
+ public void AddFeature(IRequestFeature requestFeature) {
+ _stack.AddFeature(requestFeature);
+ }
+
+ public void AddFeature(IResponseFeature responseFeature) {
+ _stack.AddFeature(responseFeature);
+ }
+
+ public virtual HttpRemoteResponse Process(Uri uri, string verb, string content) {
+ return _stack.Process(this, verb, uri, content);
+ }
+ }
+}
View
20 RestfulieClient/request/RequestChain.cs
@@ -0,0 +1,20 @@
+using System;
+using System.Collections.Generic;
+using RestfulieClient.features;
+using RestfulieClient.service;
+
+namespace RestfulieClient.request
+{
+ public class RequestChain
+ {
+ private readonly IEnumerator<IRequestFeature> _current;
+
+ public RequestChain(IEnumerable<IRequestFeature> features) {
+ _current = features.GetEnumerator();
+ }
+
+ public HttpRemoteResponse Next(Request request, string verb, Uri uri, string content) {
+ return _current.MoveNext() ? _current.Current.Process(this, request, verb, uri, content) : null;
+ }
+ }
+}
View
37 RestfulieClient/request/RequestStack.cs
@@ -0,0 +1,37 @@
+using System;
+using System.Collections.Generic;
+using RestfulieClient.features;
+using RestfulieClient.service;
+
+namespace RestfulieClient.request
+{
+ public class RequestStack : IRequestFeature
+ {
+ private readonly IRemoteResourceService _service;
+ private readonly IList<IRequestFeature> _requestFeatures = new List<IRequestFeature>();
+ private readonly IList<IResponseFeature> _responseFeatures = new List<IResponseFeature>();
+
+ public RequestStack(IRemoteResourceService service) {
+ _service = service;
+ }
+
+ public void AddFeature(IRequestFeature requestFeature) {
+ _requestFeatures.Add(requestFeature);
+ }
+
+ public void AddFeature(IResponseFeature responseFeature) {
+ _responseFeatures.Add(responseFeature);
+ }
+
+ public HttpRemoteResponse Process(Request request, string verb, Uri uri, string content) {
+ _requestFeatures.Add(this);
+
+ return new RequestChain(_requestFeatures).Next(request, verb, uri, content);
+ }
+
+ public virtual HttpRemoteResponse Process(RequestChain chain, Request request, string verb, Uri uri, string content) {
+ return new ResponseChain(_service, _responseFeatures)
+ .Next(_service.Dispatcher.Process(_service, verb, uri, content));
+ }
+ }
+}
View
33 RestfulieClient/request/ResponseChain.cs
@@ -0,0 +1,33 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using RestfulieClient.features;
+using RestfulieClient.resources;
+using RestfulieClient.service;
+
+namespace RestfulieClient.request
+{
+ public class ResponseChain
+ {
+ private readonly IRemoteResourceService _service;
+ private readonly IEnumerator<IResponseFeature> _current;
+
+ public IRemoteResourceService Service {
+ get { return _service; }
+ }
+
+ public ResponseChain(IRemoteResourceService service, IEnumerable<IResponseFeature> features) {
+ _service = service;
+ _current = features.GetEnumerator();
+ }
+
+ public void Reset() {
+ _current.Reset();
+ }
+
+ public HttpRemoteResponse Next(HttpRemoteResponse response) {
+ return _current.MoveNext() ? _current.Current.Process(this, response) : response;
+ }
+ }
+}
View
55 RestfulieClient/resources/DynamicXmlResource.cs
@@ -2,62 +2,66 @@
using System.Linq;
using System.Xml.Linq;
using System.Dynamic;
-using System.Reflection;
using RestfulieClient.service;
using System.Globalization;
namespace RestfulieClient.resources
{
- public class DynamicXmlResource : DynamicObject
+ public class DynamicXmlResource : DynamicObject, IResource
{
- private StringValueConverter converter = new StringValueConverter();
+ private readonly StringValueConverter _converter = new StringValueConverter();
public HttpRemoteResponse WebResponse { get; private set; }
+
+ public bool IsEmpty {
+ get { return WebResponse.HasNoContent(); } // should check if any nodes exist
+ }
+
public IRemoteResourceService RemoteResourceService { get; private set; }
public NumberFormatInfo NumberFormatInfo { get; set; }
public XElement XmlRepresentation
{
get
{
- if (this.WebResponse.HasNoContent())
+ if (WebResponse.HasNoContent())
return null;
- else
- return XElement.Parse(this.WebResponse.Content);
+
+ return XElement.Parse(WebResponse.Content);
}
}
public DynamicXmlResource(HttpRemoteResponse response)
{
- this.WebResponse = response;
- this.NumberFormatInfo = System.Globalization.NumberFormatInfo.CurrentInfo;
+ WebResponse = response;
+ NumberFormatInfo = NumberFormatInfo.CurrentInfo;
}
public DynamicXmlResource(HttpRemoteResponse response, IRemoteResourceService remoteService)
: this(response)
{
- this.RemoteResourceService = remoteService;
+ RemoteResourceService = remoteService;
}
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
string fieldName = binder.Name.Replace("_", "-").ToLower();
- XElement firstElement = this.GetFirstElementWithName(fieldName);
- result = this.GetValueFromXmlElement(firstElement);
+ XElement firstElement = GetFirstElementWithName(fieldName);
+ result = GetValueFromXmlElement(firstElement);
return result != null ? true : false;
}
public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
{
- object value = this.GetValueFromAttributeName(binder.Name, "href");
+ object value = GetValueFromAttributeName(binder.Name, "href");
if (value == null)
throw new ArgumentException(string.Format("There is not method defined with name:", binder.Name));
- DynamicXmlResource resource = (DynamicXmlResource)this.InvokeRemoteResource(value.ToString(), binder.Name);
+ DynamicXmlResource resource = (DynamicXmlResource)InvokeRemoteResource(value.ToString(), binder.Name);
if (resource.WebResponse.HasNoContent())
{
- result = this.XmlRepresentation;
- this.UpdateWebResponse(resource.WebResponse);
+ result = XmlRepresentation;
+ UpdateWebResponse(resource.WebResponse);
}
else
{
@@ -70,12 +74,7 @@ private object InvokeRemoteResource(string url, string transitionName)
{
try
{
- Type remoteResourceServiceType = this.RemoteResourceService.GetType();
- return remoteResourceServiceType.InvokeMember("Execute",
- BindingFlags.InvokeMethod |
- BindingFlags.Public |
- BindingFlags.Instance,
- null, this.RemoteResourceService, new Object[] { url, transitionName });
+ return RemoteResourceService.Execute(url, transitionName);
}
catch (Exception ex)
{
@@ -89,11 +88,11 @@ private object GetValueFromXmlElement(XElement element)
{
if (element.HasElements)
{
- return new DynamicXmlResource(this.WebResponse);
+ return new DynamicXmlResource(WebResponse);
}
else
{
- object result = this.converter.TransformText(element.Value).WithNumberFormatInfo(this.NumberFormatInfo).ToValue();
+ object result = _converter.TransformText(element.Value).WithNumberFormatInfo(NumberFormatInfo).ToValue();
return result;
}
}
@@ -123,7 +122,15 @@ private object GetValueFromAttributeName(string name, string attributeName)
private void UpdateWebResponse(HttpRemoteResponse response)
{
- this.WebResponse = response;
+ WebResponse = response;
+ }
+
+ public bool HasLink(string rel) {
+ throw new NotImplementedException();
+ }
+
+ public IResource Follow(string rel, string content) {
+ throw new NotImplementedException();
}
}
}
View
24 RestfulieClient/resources/EmptyResource.cs
@@ -0,0 +1,24 @@
+using System;
+using RestfulieClient.service;
+
+namespace RestfulieClient.resources
+{
+ public class EmptyResource : IResource
+ {
+ public HttpRemoteResponse WebResponse { get; private set; }
+
+ public bool IsEmpty { get { return true; } }
+
+ public EmptyResource(HttpRemoteResponse webResponse) {
+ WebResponse = webResponse;
+ }
+
+ public bool HasLink(string rel) {
+ return false;
+ }
+
+ public IResource Follow(string rel, string content) {
+ throw new NotImplementedException();
+ }
+ }
+}
View
190 RestfulieClient/resources/EntryPointService.cs
@@ -1,127 +1,115 @@
using System;
+using System.Collections.Generic;
using System.Net;
+using RestfulieClient.features;
+using RestfulieClient.request;
using RestfulieClient.service;
-using System.Text;
-using System.IO;
-using System.Net.Mime;
namespace RestfulieClient.resources
{
public class EntryPointService : IRemoteResourceService
{
- private string entryPointURI = "";
- private string contentType = "";
- private string accepts = "";
+ private readonly string _entryPointUri = "";
+ private readonly IRequestDispatcher _dispatcher;
+ private readonly IList<IRequestFeature> _requestFeatures = new List<IRequestFeature>();
+ private readonly IList<IResponseFeature> _responseFeatures = new List<IResponseFeature>();
+ private readonly IDictionary<string, string> _headers = new Dictionary<string, string>();
+ private readonly RestfulieHttpVerbDiscovery _httpVerbDiscovery = new RestfulieHttpVerbDiscovery();
- private RestfulieHttpVerbDiscovery httpVerbDiscovery = new RestfulieHttpVerbDiscovery();
+ public IRequestDispatcher Dispatcher {
+ get { return _dispatcher; }
+ }
+
+ public IDictionary<string, string> Headers {
+ get { return _headers; }
+ }
+
+ public EntryPointService(string uri, IRequestDispatcher dispatcher) {
+ _entryPointUri = uri;
+ _dispatcher = dispatcher;
+ }
+
+ public IRemoteResourceService As(string mediaType) {
+ return With("Content-Type", mediaType);
+ }
+
+ public IRemoteResourceService Accepts(string mediaType) {
+ return With("Accept", mediaType);;
+ }
- public EntryPointService(string uri)
- {
- this.entryPointURI = uri;
+ public IRemoteResourceService Handling(string mediaType) {
+ return As(mediaType).Accepts(mediaType);
}
- public dynamic As(string contentType)
- {
- this.contentType = contentType;
- this.accepts = contentType;
+ public IRemoteResourceService With(string name, string value) {
+ _headers.Add(name, value);
return this;
}
- public dynamic Accepts(string acceptType)
- {
- this.accepts = acceptType;
+ private string GetVerb(string transitionName) {
+ return _httpVerbDiscovery.GetHttpVerbByTransitionName(transitionName);
+ }
+
+ private IResource ParseResponse(HttpRemoteResponse response) {
+ if (response.StatusCode >= HttpStatusCode.BadRequest ||
+ response.HasNoContent() || !response.Headers.ContainsKey("Content-Type"))
+ return new EmptyResource(response);
+
+ if (response.Headers["Content-Type"].IndexOf("application/xml", StringComparison.OrdinalIgnoreCase) > -1)
+ return new DynamicXmlResource(response, this);
+
+ throw new InvalidOperationException("unsupported media type: " + response.Headers["Content-Type"]);
+ }
+
+ public IRemoteResourceService With(IRequestFeature requestFeature) {
+ _requestFeatures.Add(requestFeature);
return this;
}
- public dynamic Get()
- {
- if (string.IsNullOrEmpty(this.entryPointURI))
- throw new ArgumentNullException("There is no uri defined. Use the At() method for to define the uri.");
- HttpWebResponse response = (HttpWebResponse)this.FromWeb(this.entryPointURI);
- return ParseGetResponse(response);
+ public IRemoteResourceService With(IResponseFeature responseFeature) {
+ _responseFeatures.Add(responseFeature);
+ return this;
}
- private dynamic ParseGetResponse(HttpWebResponse res)
- {
- dynamic response = HttpRemoteResponseFactory.GetRemoteResponse(res);
- if (res.StatusCode == HttpStatusCode.OK)
- {
- return ParseGetOkResponse(res, response);
- }
- else
- return response;
+ private IResource Process(Uri uri, string verb, string content) {
+ var request = new Request(this, _dispatcher);
+
+ foreach (var feature in _requestFeatures)
+ request.AddFeature(feature);
+ foreach (var feature in _responseFeatures)
+ request.AddFeature(feature);
+
+ return ParseResponse(request.Process(uri, verb, content));
}
- private dynamic ParseGetOkResponse(HttpWebResponse res, dynamic response)
- {
- if (res.ContentType.Contains("application/xml"))
- {
- return new DynamicXmlResource(response, this);
- }
- else
- {
- throw new InvalidOperationException("unsupported media type: " + res.ContentType);
- }
- }
-
- public dynamic Create(string content)
- {
- HttpWebResponse postResponse = InvokeRemoteUri(this.entryPointURI, "post", content);
- return ParsePostResponse(postResponse);
- }
-
- public dynamic ParsePostResponse(HttpWebResponse postResponse)
- {
- dynamic response = HttpRemoteResponseFactory.GetRemoteResponse(postResponse);
- if (postResponse.StatusCode == HttpStatusCode.Created)
- {
- this.accepts = "application/xml";
- return FromWeb(response.Location);
- }
- else
- return response;
- }
-
- private dynamic FromWeb(string uri)
- {
- WebResponse response = this.InvokeRemoteUri(uri, "get");
- return response;
- }
-
- public object Execute(string uri, string transitionName)
- {
- string httpVerb = httpVerbDiscovery.GetHttpVerbByTransitionName(transitionName);
- return InvokeRemoteUri(uri, httpVerb);
- }
-
-
- private HttpWebResponse InvokeRemoteUri(string uri, string httpVerb, string content = "")
- {
- Uri requestUri = new Uri(this.entryPointURI);
- HttpWebRequest request = (HttpWebRequest)WebRequest.Create(requestUri);
- try
- {
- request.Method = httpVerb;
- if (!accepts.Equals(""))
- {
- request.Accept = accepts;
- request.ContentType = contentType;
- }
- if (!content.Equals(""))
- {
- byte[] byteArray = Encoding.UTF8.GetBytes(content);
- request.ContentLength = byteArray.Length;
- Stream bodyStream = request.GetRequestStream();
- bodyStream.Write(byteArray, 0, byteArray.Length);
- bodyStream.Close();
- }
- return (HttpWebResponse)request.GetResponse();
- }
- catch (Exception ex)
- {
- throw new ArgumentException(string.Format("An error occurred while connecting to the resource in url {0} with message {1}.", uri, ex.Message), ex);
- }
+ private IResource Process(string uri, string verb, string content) {
+ return Process(new Uri(uri), verb, content);
+ }
+
+ public object Execute(string uri) {
+ return Process(uri, "GET", null);
+ }
+
+ public object Execute(string uri, string transitionName) {
+ return Process(uri, GetVerb(transitionName), null);
}
+ public object Execute(string uri, string transitionName, string content) {
+ return Process(uri, GetVerb(transitionName), content);
+ }
+
+ public dynamic Get() {
+ if (_entryPointUri == null)
+ throw new InvalidOperationException("There is no uri defined. Use the At() method for to define the uri.");
+
+ return Process(_entryPointUri, "GET", null);
+ }
+
+ public dynamic Create(string content) {
+ if (_entryPointUri == null)
+ throw new InvalidOperationException("There is no uri defined. Use the At() method for to define the uri.");
+
+ return Process(_entryPointUri, "POST", content);
+ }
}
}
View
30 RestfulieClient/resources/IResource.cs
@@ -0,0 +1,30 @@
+using System;
+using RestfulieClient.service;
+
+namespace RestfulieClient.resources
+{
+ public interface IResource
+ {
+ HttpRemoteResponse WebResponse { get; }
+
+ /// <summary>
+ /// Indicates whether this resource is considered empty (even if content length > 0)
+ /// </summary>
+ bool IsEmpty { get; }
+
+ /// <summary>
+ /// Checks whether the specified link exists in the response
+ /// </summary>
+ /// <param name="rel">The expected rel of the link to lookup</param>
+ bool HasLink(string rel);
+
+ /// <summary>
+ /// Causes the resource to follow the specified link and issue a new request.
+ /// It is expected that an <see cref="ArgumentException"/> will be thrown if the link does not exist.
+ /// </summary>
+ /// <param name="rel">The rel of the link to follow</param>
+ /// <param name="content">The content to include in the request body</param>
+ /// <returns>The resource result of the new request</returns>
+ IResource Follow(string rel, string content);
+ }
+}
View
3  RestfulieClient/resources/Restifulie.cs → RestfulieClient/resources/Restfulie.cs
@@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Linq;
using System.Text;
+using RestfulieClient.http;
using RestfulieClient.service;
using System.Dynamic;
@@ -18,7 +19,7 @@ private Restfulie(IRemoteResourceService service)
private Restfulie(string uri)
{
- this.EntryPointService = new EntryPointService(uri);
+ this.EntryPointService = new EntryPointService(uri, new DefaultRequestDispatcher());
}
public static IRemoteResourceService At(string uri)
View
18 RestfulieClient/service/HttpRemoteResponse.cs
@@ -1,7 +1,8 @@
-using System.Net;
+using System;
+using System.Linq;
+using System.Net;
using System.Dynamic;
using System.Collections.Generic;
-using System.Xml.Linq;
namespace RestfulieClient.service
{
@@ -13,15 +14,18 @@ public class HttpRemoteResponse : DynamicObject
public HttpRemoteResponse(HttpStatusCode statusCode, Dictionary<string, string> headers, string content)
{
- this.StatusCode = statusCode;
- this.Headers = headers;
- this.Content = content;
+ if (headers == null)
+ throw new ArgumentNullException("headers");
+
+ StatusCode = statusCode;
+ Headers = headers.ToDictionary(p => p.Key, p => p.Value, StringComparer.OrdinalIgnoreCase); // make a copy for better comparisons
+ Content = content;
}
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
string headerValue = "";
- if (Headers.TryGetValue(binder.Name.ToUpper(), out headerValue))
+ if (Headers.TryGetValue(binder.Name.Replace("_", "-"), out headerValue))
{
result = headerValue;
return true;
@@ -35,7 +39,7 @@ public override bool TryGetMember(GetMemberBinder binder, out object result)
public bool HasNoContent()
{
- return Content.Equals("");
+ return String.IsNullOrEmpty(Content);
}
}
}
View
64 RestfulieClient/service/IRemoteResourceService.cs
@@ -1,13 +1,65 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
+using System.Collections.Generic;
+using RestfulieClient.features;
+using RestfulieClient.request;
-namespace RestfulieClient.resources
+namespace RestfulieClient.service
{
public interface IRemoteResourceService
{
- object Execute(string uri, string transitionName);
+ /// <summary>
+ /// Returns the registered dispatcher for this service
+ /// </summary>
+ IRequestDispatcher Dispatcher { get; }
+
+ /// <summary>
+ /// Returns the registered request headers
+ /// </summary>
+ IDictionary<string, string> Headers { get; }
+
+ /// <summary>
+ /// Specifies the media type that the server should attempt to return
+ /// </summary>
+ IRemoteResourceService Accepts(string mediaType);
+
+ /// <summary>
+ /// Specifies the media type that will be sent to the server
+ /// </summary>
+ IRemoteResourceService As(string mediaType);
+
+ /// <summary>
+ /// Shortcut to specify Accept and As together
+ /// </summary>
+ IRemoteResourceService Handling(string mediaType);
+
+ /// <summary>
+ /// Allows a custom header to be set for requests
+ /// </summary>
+ IRemoteResourceService With(string name, string value);
+
+ /// <summary>
+ /// Allows a feature to be added to the request stack
+ /// </summary>
+ IRemoteResourceService With(IRequestFeature requestFeature);
+
+ /// <summary>
+ /// Allows a feature to be added to the response stack
+ /// </summary>
+ IRemoteResourceService With(IResponseFeature responseFeature);
+
+ /// <summary>
+ /// Executes a GET request against the given uri
+ /// </summary>
+ object Execute(string uri);
+
+ /// <summary>
+ /// Executes a request against the given uri based on the transition name provided
+ /// </summary>
+ object Execute(string uri, string transitionName);
+
+ /// <summary>
+ /// Executes a request with content against the given uri based on the transition name provided
+ /// </summary>
+ object Execute(string uri, string transitionName, string content);
dynamic Get();
dynamic Create(string content);
View
5 RestfulieClient/service/RestfulieHttpVerbDiscovery.cs
@@ -9,8 +9,8 @@ public class RestfulieHttpVerbDiscovery
{
private const string GET = "GET";
+ private const string PUT = "PUT";
private const string POST = "POST";
- private const string UPDATE = "UPDATE";
private const string DELETE = "DELETE";
private Dictionary<string, string> verbNames;
@@ -40,7 +40,8 @@ private void InitializeHttpVerbsWithTransitionNameRelationship()
verbNames.Add("Cancel",DELETE);
verbNames.Add("Destroy", DELETE);
verbNames.Add("Delete", DELETE);
- verbNames.Add("Update", POST);
+ verbNames.Add("Create", POST);
+ verbNames.Add("Update", PUT);
verbNames.Add("Refresh", GET);
verbNames.Add("Reload", GET);
verbNames.Add("Show", GET);
View
81 RestfulieClientTest/BaseTest.cs
@@ -0,0 +1,81 @@
+using System;
+using System.Collections.Generic;
+using Moq;
+using RestfulieClient.features;
+using RestfulieClient.request;
+using RestfulieClient.resources;
+using RestfulieClient.service;
+using RestfulieClientTests.helpers;
+
+namespace RestfulieClientTests
+{
+ public abstract class BaseTest
+ {
+ protected Mock<IRemoteResourceService> GetServiceFake(string rawUri, string contentType = "application/xml") {
+ var service = new Mock<IRemoteResourceService>();
+
+ var headers = new Dictionary<string, string> {
+ {"Accept", contentType},
+ {"Content-Type", contentType}
+ };
+
+ service.SetupGet(s => s.Headers).Returns(headers);
+ service.Setup(s => s.Execute(It.IsAny<string>()))
+ .Returns<string>(u => GetDynamicResourceWithServiceFake(u, contentType));
+ service.Setup(s => s.Execute(It.IsAny<string>(), It.IsAny<string>()))
+ .Returns<string, string>((u, t) => GetDynamicResourceWithServiceFake(u, contentType));
+ service.Setup(s => s.Execute(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>()))
+ .Returns<string, string, object>((u, t, p) => GetDynamicResourceWithServiceFake(u, contentType));
+
+ return service;
+ }
+
+ protected DynamicXmlResource GetDynamicResourceWithServiceFake(string rawUri, string contentType = "application/xml")
+ {
+ var uri = rawUri.StartsWith("http://") ? new Uri(rawUri) : new Uri(String.Format("file://{0}", rawUri));
+ var dispatcher = new EmbeddedFileRequestDispatcher(contentType);
+ var service = GetServiceFake(rawUri, contentType);
+ var response = dispatcher.Process(service.Object, "GET", uri, null);
+
+ response.Headers.Add("X-Runtime", "29");
+ response.Headers.Add("Connection", "keep-alive");
+ response.Headers.Add("Cache-Control", "private, max-age=0, must-revalidate");
+ response.Headers.Add("Date", "Mon, 11 Jan 2010 22:39:24 GMT");
+ response.Headers.Add("ETag", "40edb82345bbb4d257708270c4cd8f76");
+ response.Headers.Add("Last-Modified", "Tue, 05 Jan 2010 02:44:25 GMT");
+ response.Headers.Add("Server", "nginx/0.6.39");
+ response.Headers.Add("Via", "1.1 varnish");
+
+ return new DynamicXmlResource(response, service.Object);
+ }
+
+ protected Mock<IRequestDispatcher> GetDispatcherFake(HttpRemoteResponse response) {
+ var dispatcher = new Mock<IRequestDispatcher>();
+
+ dispatcher.Setup(d => d.Process(It.IsAny<IRemoteResourceService>(), It.IsAny<string>(), It.IsAny<Uri>(), It.IsAny<string>()))
+ .Returns(response);
+
+ return dispatcher;
+ }
+
+ protected Mock<IRequestFeature> CreateRequestFeature(HttpRemoteResponse response) {
+ var requestFeature = new Mock<IRequestFeature>();
+
+ requestFeature.Setup(f => f.Process(It.IsAny<RequestChain>(), It.IsAny<Request>(), It.IsAny<string>(), It.IsAny<Uri>(), It.IsAny<string>()))
+ .Callback<RequestChain, Request, string, Uri, string>((c, r, v, u, p) => c.Next(r, v, u, p))
+ .Returns(response);
+
+ return requestFeature;
+ }
+
+ protected Mock<IResponseFeature> CreateResponseFeature(HttpRemoteResponse response) {
+ var responseFeature = new Mock<IResponseFeature>();
+
+ responseFeature.Setup(f => f.Process(It.IsAny<ResponseChain>(), response))
+ .Callback<ResponseChain, HttpRemoteResponse>((c, r) => c.Next(r))
+ .Returns(response);
+
+ return responseFeature;
+ }
+ }
+}
View
105 RestfulieClientTest/DynamicXmlResourceTest.cs
@@ -1,71 +1,16 @@
using System;
-using System.Collections.Generic;
using Microsoft.VisualStudio.TestTools.UnitTesting;
-using RestfulieClientTests.helpers;
-using System.Xml.Linq;
-using RestfulieClient.resources;
-using RestfulieClient.service;
-using System.Net;
using System.Globalization;
namespace RestfulieClientTests
{
- /// <summary>
- /// Summary description for DynamicXmlResourceTest
- /// </summary>
[TestClass]
- public class DynamicXmlResourceTest
+ public class DynamicXmlResourceTest : BaseTest
{
- public DynamicXmlResourceTest()
- {
- //
- // TODO: Add constructor logic here
- //
- }
-
- private TestContext testContextInstance;
-
- /// <summary>
- ///Gets or sets the test context which provides
- ///information about and functionality for the current test run.
- ///</summary>
- public TestContext TestContext
- {
- get
- {
- return testContextInstance;
- }
- set
- {
- testContextInstance = value;
- }
- }
-
- #region Additional test attributes
- //
- // You can use the following additional attributes as you write your tests:
- //
- // Use ClassInitialize to run code before running the first test in the class
- // [ClassInitialize()]
- // public static void MyClassInitialize(TestContext testContext) { }
- //
- // Use ClassCleanup to run code after all tests in a class have run
- // [ClassCleanup()]
- // public static void MyClassCleanup() { }
- //
- // Use TestInitialize to run code before running each test
- // [TestInitialize()]
- // public void MyTestInitialize() { }
- //
- // Use TestCleanup to run code after each test has run
- // [TestCleanup()]
- // public void MyTestCleanup() { }
- //
- #endregion
[TestMethod]
public void ShouldBePossibleToLoadAXmlByTheyDynamicObject()
{
- dynamic order = this.GetDynamicResourceWithServiceFake("order.xml");
+ dynamic order = GetDynamicResourceWithServiceFake("order.xml");
Assert.IsNotNull(order.date, "the attribute date is no expected");
Assert.IsNotNull(order.total, "the attribute total is no expected");
}
@@ -73,7 +18,7 @@ public void ShouldBePossibleToLoadAXmlByTheyDynamicObject()
[TestMethod]
public void ShouldBePossibleToExecuteDynamicMethodsInResource()
{
- dynamic order = this.GetDynamicResourceWithServiceFake("order.xml");
+ dynamic order = GetDynamicResourceWithServiceFake("order.xml");
Assert.IsNotNull(order.Pay());
}
@@ -81,7 +26,7 @@ public void ShouldBePossibleToExecuteDynamicMethodsInResource()
[Ignore]
public void ShouldBeAbleToAnswerToMethodRelName()
{
- dynamic order = this.GetDynamicResourceWithServiceFake("order.xml");
+ dynamic order = GetDynamicResourceWithServiceFake("order.xml");
Assert.IsNotNull(order.Update());
}
@@ -89,22 +34,22 @@ public void ShouldBeAbleToAnswerToMethodRelName()
[TestMethod]
public void LearningToReadAAtomLinkInXml()
{
- dynamic order = this.GetDynamicResourceWithServiceFake("order.xml");
+ dynamic order = GetDynamicResourceWithServiceFake("order.xml");
Assert.IsNotNull(order.Pay());
}
[TestMethod]
public void ShouldBePossibleToAccessResponseHeadersEasily()
{
- dynamic order = this.GetDynamicResourceWithServiceFake("order.xml");
- Assert.AreEqual("application/xml", order.WebResponse.ContentType);
+ dynamic order = GetDynamicResourceWithServiceFake("order.xml");
+ Assert.AreEqual("application/xml", order.WebResponse.Content_Type);
Assert.AreEqual("keep-alive", order.WebResponse.Connection);
}
[TestMethod]
public void ShouldBePossibleToAccessFieldsLikeUpdateAt()
{
- dynamic order = this.GetDynamicResourceWithServiceFake("order.xml");
+ dynamic order = GetDynamicResourceWithServiceFake("order.xml");
DateTime date = new DateTime(2010, 01, 01);
Assert.AreEqual(date, order.Update_At);
}
@@ -112,7 +57,7 @@ public void ShouldBePossibleToAccessFieldsLikeUpdateAt()
[TestMethod]
public void ShouldBePossibleToAccessInnerFieldsInAResource()
{
- dynamic city = this.GetDynamicResourceWithServiceFake("city.xml");
+ dynamic city = GetDynamicResourceWithServiceFake("city.xml");
Assert.AreEqual(18000000, city.Population.Size);
Assert.AreEqual(10, city.Growth);
}
@@ -120,7 +65,7 @@ public void ShouldBePossibleToAccessInnerFieldsInAResource()
[TestMethod]
public void ShouldBePossibleToAccessInnerFieldsWithYourRealTypes()
{
- dynamic order = this.GetDynamicResourceWithServiceFake("order.xml");
+ dynamic order = GetDynamicResourceWithServiceFake("order.xml");
order.NumberFormatInfo = new CultureInfo("en-US", false).NumberFormat;
Assert.AreEqual(15.00, order.Total);
Assert.AreEqual(1, order.Id);
@@ -131,39 +76,11 @@ public void ShouldBePossibleToAccessInnerFieldsWithYourRealTypes()
[TestMethod]
public void ShouldBePossibleToAccessAOtherResourceByLink()
{
- dynamic city = this.GetDynamicResourceWithServiceFake("city.xml");
+ dynamic city = GetDynamicResourceWithServiceFake("city.xml");
dynamic otherCity = city.Next_Largest();
Assert.IsNotNull(otherCity);
Assert.AreEqual("Rio de Janeiro", otherCity.Name);
Assert.AreEqual("Sao Paulo", city.Name);
}
-
- private DynamicXmlResource GetDynamicResourceWithServiceFake(string fileName)
- {
- XElement element;
- IRemoteResourceService remoteService;
- string xml = new LoadDocument().GetDocumentContent(fileName);
- element = XElement.Parse(xml);
- Dictionary<string, string> headers = new Dictionary<string, string>();
- headers.Add("XRUNTIME", "29");
- headers.Add("CONNECTION", "keep-alive");
- headers.Add("CONTENTTYPE", "application/xml");
- headers.Add("CACHECONTROL", "private, max-age=0, must-revalidate");
- headers.Add("DATE", "Mon, 11 Jan 2010 22:39:24 GMT");
- headers.Add("ETAG", "40edb82345bbb4d257708270c4cd8f76");
- headers.Add("LASTMODIFIED", "Tue, 05 Jan 2010 02:44:25 GMT");
- headers.Add("SERVER", "nginx/0.6.39");
- headers.Add("VIA", "1.1 varnish");
- HttpRemoteResponse response = new HttpRemoteResponse(HttpStatusCode.OK, headers, xml);
-
- remoteService = this.GetRemoteServiceFake(fileName);
- return new DynamicXmlResource(response, remoteService);
- }
-
-
- private IRemoteResourceService GetRemoteServiceFake(string fileName)
- {
- return RemoteResourceFactory.GetRemoteResource(fileName);
- }
}
}
View
139 RestfulieClientTest/EntryPointServiceTests.cs
@@ -0,0 +1,139 @@
+using System;
+using System.Collections.Generic;
+using System.Net;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Moq;
+using RestfulieClient.request;
+using RestfulieClient.resources;
+using RestfulieClient.service;
+
+namespace RestfulieClientTests
+{
+ [TestClass]
+ public class EntryPointServiceTests : BaseTest
+ {
+ private HttpRemoteResponse CreateResponse(HttpStatusCode code = HttpStatusCode.OK, Dictionary<string, string> headers = null, string content = "") {
+ return new HttpRemoteResponse(code, headers ?? new Dictionary<string, string>(), content);
+ }
+
+ private IRemoteResourceService CreateService(HttpRemoteResponse response = null, IRequestDispatcher dispatcher = null) {
+ if (response == null)
+ response = CreateResponse();
+ if (dispatcher == null)
+ dispatcher = GetDispatcherFake(response).Object;
+
+ return new EntryPointService("file://NotImportant", dispatcher);
+ }
+
+ [TestMethod]
+ public void it_should_return_a_resource() {
+ Assert.IsNotNull(CreateService().Get());
+ }
+
+ [TestMethod]
+ public void it_should_allow_custom_request_headers() {
+ var service = CreateService().With("Test", "Value");
+ var headers = service.Headers;
+
+ Assert.AreEqual(1, headers.Count);
+ Assert.IsTrue(headers.ContainsKey("Test"));
+ Assert.AreEqual("Value", headers["Test"], true);
+ }
+
+ [TestMethod]
+ public void it_should_apply_accept_header() {
+ var service = CreateService().Accepts("application/json");
+ var headers = service.Headers;
+
+ Assert.AreEqual(1, headers.Count);
+ Assert.IsTrue(headers.ContainsKey("Accept"));
+ Assert.AreEqual("application/json", headers["Accept"], true);
+ }
+
+ [TestMethod]
+ public void it_should_apply_content_type_header() {
+ var service = CreateService().As("application/json");
+ var headers = service.Headers;
+
+ Assert.AreEqual(1, headers.Count);
+ Assert.IsTrue(headers.ContainsKey("Content-Type"));
+ Assert.AreEqual("application/json", headers["Content-Type"], true);
+ }
+
+ [TestMethod]
+ public void it_should_provide_dispatcher() {
+ var dispatcher = GetDispatcherFake(It.IsAny<HttpRemoteResponse>());
+
+ Assert.AreEqual(dispatcher.Object, CreateService(dispatcher: dispatcher.Object).Dispatcher);
+ }
+
+ [TestMethod]
+ public void it_should_be_possible_to_handle_error_status() {
+ var response = CreateResponse(HttpStatusCode.NotFound);
+
+ Assert.AreEqual(HttpStatusCode.NotFound, CreateService(response).Get().WebResponse.StatusCode);
+ }
+
+ [TestMethod]
+ public void it_should_return_empty_for_no_content_regardless_of_content_type() {
+ var response = CreateResponse(headers: new Dictionary<string, string> { { "Content-Type", "application/xml" } });
+ var resource = CreateService().Get();
+
+ Assert.IsTrue(resource.IsEmpty);
+ Assert.IsInstanceOfType(resource, typeof(EmptyResource));
+ }
+
+ [TestMethod]
+ public void it_should_return_empty_for_no_content_type() {
+ var response = CreateResponse(content: "{ }");
+ var resource = CreateService(response).Get();
+
+ Assert.IsTrue(resource.IsEmpty);
+ Assert.IsInstanceOfType(resource, typeof(EmptyResource));
+ }
+
+ [TestMethod]
+ public void it_should_use_request_feature() {
+ var response = CreateResponse();
+ var feature = CreateRequestFeature(response);
+ var service = CreateService(response).With(feature.Object);
+
+ service.Get();
+
+ feature.Verify(f => f.Process(It.IsAny<RequestChain>(), It.IsAny<Request>(), It.IsAny<string>(), It.IsAny<Uri>(), It.IsAny<string>()), Times.Once());
+ }
+
+ [TestMethod]
+ public void it_should_use_response_feature() {
+ var response = CreateResponse();
+ var feature = CreateResponseFeature(response);
+ var service = CreateService(response).With(feature.Object);
+
+ service.Get();
+
+ feature.Verify(f => f.Process(It.IsAny<ResponseChain>(), It.IsAny<HttpRemoteResponse>()), Times.Once());
+ }
+
+ [TestMethod]
+ public void it_should_chain_request_features() {
+ var response = CreateResponse();
+ var feature = CreateRequestFeature(response);
+ var service = CreateService().With(feature.Object).With(feature.Object);
+
+ service.Get();
+
+ feature.Verify(f => f.Process(It.IsAny<RequestChain>(), It.IsAny<Request>(), It.IsAny<string>(), It.IsAny<Uri>(), It.IsAny<string>()), Times.Exactly(2));
+ }
+
+ [TestMethod]
+ public void it_should_chain_response_features() {
+ var response = CreateResponse();
+ var feature = CreateResponseFeature(response);
+ var service = CreateService(response).With(feature.Object).With(feature.Object);
+
+ service.Get();
+
+ feature.Verify(f => f.Process(It.IsAny<ResponseChain>(), It.IsAny<HttpRemoteResponse>()), Times.Exactly(2));
+ }
+ }
+}
View
74 RestfulieClientTest/EntryPointTests.cs
@@ -1,70 +1,16 @@
using System;
-using System.Text;
-using System.Collections.Generic;
-using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using RestfulieClient.resources;
-using RestfulieClientTests.helpers;
namespace RestfulieClientTests
{
- /// <summary>
- /// Summary description for EntryPointTests
- /// </summary>
[TestClass]
- public class EntryPointTests
+ public class EntryPointTests : BaseTest
{
- public EntryPointTests()
- {
- //
- // TODO: Add constructor logic here
- //
- }
-
- private TestContext testContextInstance;
-
- /// <summary>
- ///Gets or sets the test context which provides
- ///information about and functionality for the current test run.
- ///</summary>
- public TestContext TestContext
- {
- get
- {
- return testContextInstance;
- }
- set
- {
- testContextInstance = value;
- }
- }
-
- #region Additional test attributes
- //
- // You can use the following additional attributes as you write your tests:
- //
- // Use ClassInitialize to run code before running the first test in the class
- // [ClassInitialize()]
- // public static void MyClassInitialize(TestContext testContext) { }
- //
- // Use ClassCleanup to run code after all tests in a class have run
- // [ClassCleanup()]
- // public static void MyClassCleanup() { }
- //
- // Use TestInitialize to run code before running each test
- // [TestInitialize()]
- // public void MyTestInitialize() { }
- //
- // Use TestCleanup to run code after each test has run
- // [TestCleanup()]
- // public void MyTestCleanup() { }
- //
- #endregion
-
[TestMethod]
public void ShouldBePossibleToGetAResourceRepresentationByTheEntryFluentInteface()
{
- dynamic order = Restfulie.At(GetEntryPointServiceForTests("order.xml")).Get();
+ dynamic order = Restfulie.At(GetServiceFake("order.xml")).Get();
Assert.IsNotNull(order);
Assert.IsNotNull(order.date, "the attribute date is no expected");
Assert.IsNotNull(order.total, "the attribute total is no expected");
@@ -73,7 +19,7 @@ public void ShouldBePossibleToGetAResourceRepresentationByTheEntryFluentInteface
[TestMethod]
public void ShouldBePossibleDefineConfigurationOfEntryPointService()
{
- dynamic entryPointService = Restfulie.At(GetEntryPointServiceForTests("http:\\localhost:3000\\order\\1.xml"));
+ dynamic entryPointService = Restfulie.At(GetServiceFake("http:\\localhost:3000\\order\\1.xml"));
Assert.IsNotNull(entryPointService);
}
@@ -88,21 +34,22 @@ public void ShouldHasAnInstanceOfDefaultEntryPointServiceDefinedWithoutSetAConfi
[ExpectedException(typeof(ArgumentNullException))]
public void ShouldBeThrowAnErrorIfTheInvokeGetMethodWithoutUriDefined()
{
- dynamic entryPointService = Restfulie.At(GetEntryPointServiceForTests(""));
+ dynamic entryPointService = Restfulie.At(GetServiceFake(""));
dynamic order = entryPointService.Get();
}
[TestMethod]
public void ShoudBePossibleToGetAWebReponse()
{
- dynamic order = Restfulie.At(GetEntryPointServiceForTests("http:\\localhost:3000\\order\\1.xml")).Get();
+ dynamic order = Restfulie.At(GetServiceFake("http:\\localhost:3000\\order\\1.xml")).Get();
+ Assert.IsNotNull(order);
Assert.IsNotNull(order.WebResponse);
}
[TestMethod]
public void ShouldBePossibleToGetTheResponseStatusCode()
{
- dynamic order = Restfulie.At(GetEntryPointServiceForTests("http:\\localhost:3000\\order\\1.xml")).Get();
+ dynamic order = Restfulie.At(GetServiceFake("http:\\localhost:3000\\order\\1.xml")).Get();
Assert.IsNotNull(order.WebResponse.StatusCode);
}
@@ -118,13 +65,8 @@ public void ShouldBePossibleToCreateResourcesFromEntryPoint()
" <updated-at>10/01/2010</updated-at> " +
" <link rel=\"next_largest\" href=\"city.xml\" /> " +
"</city> ";
- dynamic newCity = Restfulie.At(GetEntryPointServiceForTests("http://localhost:3000/cities")).Create(resourceXml);
+ dynamic newCity = Restfulie.At(GetServiceFake("http://localhost:3000/cities")).Create(resourceXml);
Assert.AreEqual(System.Net.HttpStatusCode.OK, newCity.WebResponse.StatusCode);
}
-
- private dynamic GetEntryPointServiceForTests(string uri)
- {
- return RemoteResourceFactory.GetRemoteResource(uri);
- }
}
}
View
92 RestfulieClientTest/ResourceServiceTest.cs
@@ -1,92 +0,0 @@
-using System;
-using System.Text;
-using System.Collections.Generic;
-using System.Linq;
-using Microsoft.VisualStudio.TestTools.UnitTesting;
-using RestfulieClientTests.helpers;
-using RestfulieClient.resources;
-
-namespace RestfulieClientTests
-{
- /// <summary>
- /// Summary description for ResourceServiceTest
- /// </summary>
- [TestClass]
- public class ResourceServiceTest
- {
- public ResourceServiceTest()
- {
- //
- // TODO: Add constructor logic here
- //
- }
-
- private TestContext testContextInstance;
-
- /// <summary>
- ///Gets or sets the test context which provides
- ///information about and functionality for the current test run.
- ///</summary>
- public TestContext TestContext
- {
- get
- {
- return testContextInstance;
- }
- set
- {
- testContextInstance = value;
- }
- }
-
- #region Additional test attributes
- //
- // You can use the following additional attributes as you write your tests:
- //
- // Use ClassInitialize to run code before running the first test in the class
- // [ClassInitialize()]
- // public static void MyClassInitialize(TestContext testContext) { }
- //
- // Use ClassCleanup to run code after all tests in a class have run
- // [ClassCleanup()]
- // public static void MyClassCleanup() { }
- //
- // Use TestInitialize to run code before running each test
- // [TestInitialize()]
- // public void MyTestInitialize() { }
- //
- // Use TestCleanup to run code after each test has run
- // [TestCleanup()]
- // public void MyTestCleanup() { }
- //
- #endregion
-
- [TestMethod]
- public void ShoudBePossibleToLoadAResourceFromXml()
- {
-
- IRemoteResourceService resource = GetEntryPointServiceForTests("order.xml");
- dynamic order = resource.Get();
-
- // verificando os atributos do recurso
- Assert.IsNotNull(order.date);
- Assert.IsNotNull(order.total);
- }
-
- [Ignore]
- public void ShouldBePossibleToExecuteATransitionOfStateOfAResource()
- {
- EntryPointService resource = GetEntryPointServiceForTests("order.xml");
- dynamic order = resource.Get();
- Assert.IsNotNull(order.Pay());
-
- }
-
- private dynamic GetEntryPointServiceForTests(string uri)
- {
- return RemoteResourceFactory.GetRemoteResource(uri);
- }
-
-
- }
-}
View
21 RestfulieClientTest/RestfulieClientTests.csproj
@@ -35,8 +35,8 @@
<ItemGroup>
<Reference Include="Microsoft.CSharp" />
<Reference Include="Microsoft.VisualStudio.QualityTools.UnitTestFramework, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL" />
- <Reference Include="Rhino.Mocks">
- <HintPath>..\..\libs\Rhino.Mocks-3.6\Rhino.Mocks.dll</HintPath>
+ <Reference Include="Moq">
+ <HintPath>..\libs\Moq-4.0\Moq.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core">
@@ -48,17 +48,12 @@
<Reference Include="System.Xml.Linq" />
</ItemGroup>
<ItemGroup>
+ <Compile Include="BaseTest.cs" />
<Compile Include="DynamicXmlResourceTest.cs" />
- <Compile Include="EntryPointTests.cs" />
+ <Compile Include="EntryPointServiceTests.cs" />
+ <Compile Include="helpers\EmbeddedFileResourceDispatcher.cs" />
<Compile Include="helpers\LoadDocument.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
- <Compile Include="helpers\RemoteResourceFactory.cs" />
- <Compile Include="Properties\Resources.Designer.cs">
- <AutoGen>True</AutoGen>
- <DesignTime>True</DesignTime>
- <DependentUpon>Resources.resx</DependentUpon>
- </Compile>
- <Compile Include="ResourceServiceTest.cs" />
<Compile Include="RestfulieHttpVerbDiscoveryTest.cs" />
<Compile Include="StringValueConverterTest.cs" />
</ItemGroup>
@@ -69,12 +64,6 @@
</ProjectReference>
</ItemGroup>
<ItemGroup>
- <EmbeddedResource Include="Properties\Resources.resx">
- <Generator>ResXFileCodeGenerator</Generator>
- <LastGenOutput>Resources.Designer.cs</LastGenOutput>
- </EmbeddedResource>
- </ItemGroup>
- <ItemGroup>
<EmbeddedResource Include="xmls\order.xml" />
<EmbeddedResource Include="xmls\orderWithoutAtomLinks.xml" />
</ItemGroup>
View
68 RestfulieClientTest/RestfulieHttpVerbDiscoveryTest.cs
@@ -1,65 +1,12 @@
-using System;
-using System.Text;
-using System.Collections.Generic;
-using System.Linq;
+using System.Collections.Generic;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using RestfulieClient.service;
namespace RestfulieClientTests
{
- /// <summary>
- /// Summary description for RestfulieHttpVerbDiscoveryTest
- /// </summary>
[TestClass]
public class RestfulieHttpVerbDiscoveryTest
{
- public RestfulieHttpVerbDiscoveryTest()
- {
- //
- // TODO: Add constructor logic here
- //
- }
-
- private TestContext testContextInstance;
-
- /// <summary>
- ///Gets or sets the test context which provides
- ///information about and functionality for the current test run.
- ///</summary>
- public TestContext TestContext
- {
- get
- {
- return testContextInstance;
- }
- set
- {
- testContextInstance = value;
- }
- }
-
- #region Additional test attributes
- //
- // You can use the following additional attributes as you write your tests:
- //
- // Use ClassInitialize to run code before running the first test in the class
- // [ClassInitialize()]
- // public static void MyClassInitialize(TestContext testContext) { }
- //
- // Use ClassCleanup to run code after all tests in a class have run
- // [ClassCleanup()]
- // public static void MyClassCleanup() { }
- //
- // Use TestInitialize to run code before running each test
- // [TestInitialize()]
- // public void MyTestInitialize() { }
- //
- // Use TestCleanup to run code after each test has run
- // [TestCleanup()]
- // public void MyTestCleanup() { }
- //
- #endregion
-
[TestMethod]
public void ShouldSendADELETEIfTheStateTransitionNameIsCancelDestroyOrDelete()
{
@@ -71,15 +18,24 @@ public void ShouldSendADELETEIfTheStateTransitionNameIsCancelDestroyOrDelete()
);
}
+
[TestMethod]
- public void ShouldSendAPOSTIfTheStateTransitionNameIsUpdate()
+ public void ShouldSendAPOSTIfTheStateTransitionNameIsCreate()
{
RestfulieHttpVerbDiscovery verbDiscovery = new RestfulieHttpVerbDiscovery();
- string verbName = verbDiscovery.GetHttpVerbByTransitionName("Update");
+ string verbName = verbDiscovery.GetHttpVerbByTransitionName("Create");
Assert.AreEqual("POST", verbName);
}
[TestMethod]
+ public void ShouldSendAPUTIfTheStateTransitionNameIsUpdate()
+ {
+ RestfulieHttpVerbDiscovery verbDiscovery = new RestfulieHttpVerbDiscovery();
+ string verbName = verbDiscovery.GetHttpVerbByTransitionName("Update");
+ Assert.AreEqual("PUT", verbName);
+ }
+
+ [TestMethod]
public void ShouldBeSendAGetIfTheStateTransitionNameIsRefreshReloadShowOrLatest()
{
RestfulieHttpVerbDiscovery verbDiscovery = new RestfulieHttpVerbDiscovery();
View
56 RestfulieClientTest/StringValueConverterTest.cs
@@ -5,61 +5,9 @@
namespace RestfulieClientTests
{
- /// <summary>
- ///This is a test class for StringValueConverterTest and is intended
- ///to contain all StringValueConverterTest Unit Tests
- ///</summary>
- [TestClass()]
+ [TestClass]
public class StringValueConverterTest
{
- private TestContext testContextInstance;
-
- /// <summary>
- ///Gets or sets the test context which provides
- ///information about and functionality for the current test run.
- ///</summary>
- public TestContext TestContext
- {
- get
- {
- return testContextInstance;
- }
- set
- {
- testContextInstance = value;
- }
- }
-
- #region Additional test attributes
- //
- //You can use the following additional attributes as you write your tests:
- //
- //Use ClassInitialize to run code before running the first test in the class
- //[ClassInitialize()]
- //public static void MyClassInitialize(TestContext testContext)
- //{
- //}
- //
- //Use ClassCleanup to run code after all tests in a class have run
- //[ClassCleanup()]
- //public static void MyClassCleanup()
- //{
- //}
- //
- //Use TestInitialize to run code before running each test
- //[TestInitialize()]
- //public void MyTestInitialize()
- //{
- //}
- //
- //Use TestCleanup to run code after each test has run
- //[TestCleanup()]
- //public void MyTestCleanup()
- //{
- //}
- //
- #endregion
-
[TestMethod]
public void ShouldBePossibleToVerifyStringHasBooleanValue()
{
@@ -72,7 +20,7 @@ public void ShouldBePossibleToVerifyStringHasBooleanValue()
public void ShouldBePossibleToVerifyStringHasDoubleValue()
{
StringValueConverter converter = new StringValueConverter();
- string text = "10" + System.Globalization.NumberFormatInfo.CurrentInfo.NumberDecimalSeparator + "00";
+ string text = "10" + NumberFormatInfo.CurrentInfo.NumberDecimalSeparator + "00";
Assert.IsTrue(converter.IsDouble(text));
}
View
57 RestfulieClientTest/helpers/EmbeddedFileResourceDispatcher.cs
@@ -0,0 +1,57 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Net;
+using RestfulieClient.request;
+using RestfulieClient.service;
+
+namespace RestfulieClientTests.helpers
+{
+ public class EmbeddedFileRequestDispatcher : IRequestDispatcher
+ {
+ private readonly string _contentType;
+
+ public EmbeddedFileRequestDispatcher(string contentType) {
+ _contentType = contentType;
+ }
+
+ private string GetContentFromFile(Uri uri) {
+ var content = "";
+
+ if (uri != null && uri.IsFile)
+ content = new LoadDocument(_contentType).GetDocumentContent(Path.GetFileName(uri.OriginalString));
+
+ return content;
+ }
+
+ private HttpRemoteResponse CreateRemoteResponse(string content, string verb) {
+ var statusCode = HttpStatusCode.OK;
+ var hasContent = !String.IsNullOrWhiteSpace(content);
+
+ switch (verb.ToUpper()) {
+ case "POST":
+ statusCode = hasContent ? HttpStatusCode.Created : HttpStatusCode.BadRequest;
+ break;
+ case "PUT":
+ statusCode = hasContent ? HttpStatusCode.OK : HttpStatusCode.Conflict;
+ break;
+ case "DELETE":
+ statusCode = HttpStatusCode.NoContent;
+ break;
+ }
+
+ var response = new HttpRemoteResponse(statusCode, new Dictionary<string, string>(), content);
+
+ if (hasContent) {
+ response.Headers.Add("Content-Type", _contentType);
+ response.Headers.Add("Content-Length", content.Length.ToString());
+ }
+
+ return response;
+ }
+
+ public HttpRemoteResponse Process(IRemoteResourceService service, string verb, Uri uri, string content) {
+ return CreateRemoteResponse(GetContentFromFile(uri), verb);
+ }
+ }
+}
View
34 RestfulieClientTest/helpers/LoadDocument.cs
@@ -1,33 +1,27 @@
using System;
using System.Collections.Generic;
-using System.Linq;
-using System.Text;
using System.IO;
using System.Reflection;
-using System.Xml;
-
-
namespace RestfulieClientTests.helpers
{
public class LoadDocument
{
+ private static readonly IDictionary<string, string> ContentTypeNamespaces = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase) {
+ { "application/xml", "xmls" }
+ };
+
+ private readonly string _contentType;
+
+ public LoadDocument(string contentType) {
+ _contentType = contentType;
+ }
+
+ public string GetDocumentContent(string fileName) {
+ var filePath = String.Format("RestfulieClientTests.{0}.{1}", ContentTypeNamespaces[_contentType], fileName);
- public string GetDocumentContent(string fileName)
- {
- string filePath = "RestfulieClientTests.xmls." + fileName;
- Stream fileStream = Assembly.GetExecutingAssembly().GetManifestResourceStream(filePath);
- XmlDocument data = null;
- if (fileStream != null)
- {
- data = new XmlDocument();
- data.Load(fileStream);
- if (data.InnerXml != null)
- return data.InnerXml;
- else
- return "";
- }
- else return "";
+ using (var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(filePath))
+ return stream == null ? "" : new StreamReader(stream).ReadToEnd();
}
}
}
View
5 RestfulieClientTest/helpers/RemoteResourceFactory.cs
@@ -1,13 +1,8 @@
using System;
using System.Collections.Generic;
-using System.Linq;
-using System.Text;
using RestfulieClient.resources;
-using Rhino.Mocks;
-using RestfulieClientTests.helpers;
using RestfulieClient.service;
using System.Net;
-using System.Dynamic;
namespace RestfulieClientTests.helpers
{
View
BIN  libs/Moq-4.0/Moq.dll
Binary file not shown
View
5,120 libs/Moq-4.0/Moq.xml
5,120 additions, 0 deletions not shown

0 comments on commit 3049c09

Please sign in to comment.
Something went wrong with that request. Please try again.