//-----------------------------------------------------------------------
//
// Copyright (c) Outercurve Foundation. All rights reserved.
//
//-----------------------------------------------------------------------
namespace DotNetOpenAuth.Test.Messaging.Reflection {
using System;
using System.Linq;
using System.Reflection;
using System.Text;
using DotNetOpenAuth.Messaging;
using DotNetOpenAuth.Messaging.Reflection;
using DotNetOpenAuth.Test.Mocks;
using NUnit.Framework;
[TestFixture]
public class MessagePartTests : MessagingTestBase {
[TestCase, ExpectedException(typeof(ArgumentException))]
public void OptionalNonNullableStruct() {
this.ParameterizedMessageTypeTest(typeof(MessageWithNonNullableOptionalStruct));
}
[TestCase]
public void RequiredNonNullableStruct() {
this.ParameterizedMessageTypeTest(typeof(MessageWithNonNullableRequiredStruct));
}
[TestCase]
public void OptionalNullableStruct() {
var message = new MessageWithNullableOptionalStruct();
var part = this.ParameterizedMessageTypeTest(message.GetType());
Assert.IsNull(part.GetValue(message));
part.SetValue(message, "3");
Assert.AreEqual("3", part.GetValue(message));
}
[TestCase]
public void RequiredNullableStruct() {
this.ParameterizedMessageTypeTest(typeof(MessageWithNullableRequiredStruct));
}
[TestCase, ExpectedException(typeof(ArgumentNullException))]
public void CtorNullMember() {
new MessagePart(null, new MessagePartAttribute());
}
[TestCase, ExpectedException(typeof(ArgumentNullException))]
public void CtorNullAttribute() {
PropertyInfo field = typeof(MessageWithNullableOptionalStruct).GetProperty("OptionalInt", BindingFlags.NonPublic | BindingFlags.Instance);
new MessagePart(field, null);
}
[TestCase]
public void SetValue() {
var message = new MessageWithNonNullableRequiredStruct();
MessagePart part = this.ParameterizedMessageTypeTest(message.GetType());
part.SetValue(message, "5");
Assert.AreEqual(5, message.OptionalInt);
}
[TestCase]
public void GetValue() {
var message = new MessageWithNonNullableRequiredStruct();
message.OptionalInt = 8;
MessagePart part = this.ParameterizedMessageTypeTest(message.GetType());
Assert.AreEqual("8", part.GetValue(message));
}
[TestCase]
public void Base64Member() {
var message = new MessageWithBase64EncodedString();
message.LastName = "andrew";
MessagePart part = GetMessagePart(message.GetType(), "nameBytes");
Assert.AreEqual("YW5kcmV3", part.GetValue(message));
part.SetValue(message, "YXJub3R0");
Assert.AreEqual("arnott", message.LastName);
}
[TestCase]
public void ConstantFieldMemberValidValues() {
var message = new MessageWithConstantField();
MessagePart part = GetMessagePart(message.GetType(), "ConstantField");
Assert.AreEqual("abc", part.GetValue(message));
part.SetValue(message, "abc");
Assert.AreEqual("abc", part.GetValue(message));
}
[TestCase, ExpectedException(typeof(ProtocolException))]
public void ConstantFieldMemberInvalidValues() {
var message = new MessageWithConstantField();
MessagePart part = GetMessagePart(message.GetType(), "ConstantField");
part.SetValue(message, "def");
}
[TestCase, ExpectedException(typeof(ArgumentException))]
public void NonFieldOrPropertyMember() {
MemberInfo method = typeof(MessageWithNullableOptionalStruct).GetMethod("Equals", BindingFlags.Public | BindingFlags.Instance);
new MessagePart(method, new MessagePartAttribute());
}
[TestCase]
public void RequiredMinAndMaxVersions() {
Type messageType = typeof(MessageWithMinAndMaxVersionParts);
FieldInfo newIn2Field = messageType.GetField("NewIn2", BindingFlags.Public | BindingFlags.Instance);
MessagePartAttribute newIn2Attribute = newIn2Field.GetCustomAttributes(typeof(MessagePartAttribute), true).OfType().Single();
FieldInfo removedIn3Field = messageType.GetField("RemovedIn3", BindingFlags.Public | BindingFlags.Instance);
MessagePartAttribute removedIn3Attribute = removedIn3Field.GetCustomAttributes(typeof(MessagePartAttribute), true).OfType().Single();
Assert.AreEqual(new Version(2, 0), newIn2Attribute.MinVersionValue);
Assert.AreEqual(new Version(2, 5), removedIn3Attribute.MaxVersionValue);
}
private static MessagePart GetMessagePart(Type messageType, string memberName) {
FieldInfo field = messageType.GetField(memberName, BindingFlags.NonPublic | BindingFlags.Instance);
MessagePartAttribute attribute = field.GetCustomAttributes(typeof(MessagePartAttribute), true).OfType().Single();
return new MessagePart(field, attribute);
}
private MessagePart ParameterizedMessageTypeTest(Type messageType) {
PropertyInfo field = messageType.GetProperty("OptionalInt", BindingFlags.NonPublic | BindingFlags.Instance);
MessagePartAttribute attribute = field.GetCustomAttributes(typeof(MessagePartAttribute), true).OfType().Single();
return new MessagePart(field, attribute);
}
private class MessageWithNonNullableOptionalStruct : TestMessage {
// Optional structs like int must be nullable for Optional to make sense.
[MessagePart(IsRequired = false)]
internal int OptionalInt { get; set; }
}
private class MessageWithNonNullableRequiredStruct : TestMessage {
// This should work because a required field will always have a value so it
// need not be nullable.
[MessagePart(IsRequired = true)]
internal int OptionalInt { get; set; }
}
private class MessageWithNullableOptionalStruct : TestMessage {
// Optional structs like int must be nullable for Optional to make sense.
[MessagePart(IsRequired = false)]
internal int? OptionalInt { get; set; }
}
private class MessageWithNullableRequiredStruct : TestMessage {
[MessagePart(IsRequired = true)]
private int? OptionalInt { get; set; }
}
private class MessageWithBase64EncodedString : TestMessage {
[MessagePart]
private byte[] nameBytes;
public string LastName {
get { return this.nameBytes != null ? Encoding.UTF8.GetString(this.nameBytes) : null; }
set { this.nameBytes = value != null ? Encoding.UTF8.GetBytes(value) : null; }
}
}
private class MessageWithConstantField : TestMessage {
[MessagePart(IsRequired = true)]
#pragma warning disable 0414 // read by reflection
private readonly string ConstantField = "abc";
#pragma warning restore 0414
}
private class MessageWithMinAndMaxVersionParts : TestMessage {
#pragma warning disable 0649 // written to by reflection
[MessagePart(MinVersion = "2.0")]
public string NewIn2;
[MessagePart(MaxVersion = "2.5")]
public string RemovedIn3;
#pragma warning restore 0649
}
}
}