diff options
21 files changed, 138 insertions, 26 deletions
diff --git a/src/DotNetOpenAuth/Configuration/AssociationTypeCollection.cs b/src/DotNetOpenAuth/Configuration/AssociationTypeCollection.cs index c75ceb6..b65f92d 100644 --- a/src/DotNetOpenAuth/Configuration/AssociationTypeCollection.cs +++ b/src/DotNetOpenAuth/Configuration/AssociationTypeCollection.cs @@ -7,10 +7,12 @@ namespace DotNetOpenAuth.Configuration { using System.Collections.Generic; using System.Configuration; + using System.Diagnostics.Contracts; /// <summary> /// Describes a collection of association type sub-elements in a .config file. /// </summary> + [ContractVerification(true)] internal class AssociationTypeCollection : ConfigurationElementCollection, IEnumerable<AssociationTypeElement> { /// <summary> /// Initializes a new instance of the <see cref="AssociationTypeCollection"/> class. @@ -52,6 +54,7 @@ namespace DotNetOpenAuth.Configuration { /// An <see cref="T:System.Object"/> that acts as the key for the specified <see cref="T:System.Configuration.ConfigurationElement"/>. /// </returns> protected override object GetElementKey(ConfigurationElement element) { + Contract.Assert(element != null); // this should be Contract.Requires in base class. return ((AssociationTypeElement)element).AssociationType; } } diff --git a/src/DotNetOpenAuth/Configuration/AssociationTypeElement.cs b/src/DotNetOpenAuth/Configuration/AssociationTypeElement.cs index dce8d74..0eaea0e 100644 --- a/src/DotNetOpenAuth/Configuration/AssociationTypeElement.cs +++ b/src/DotNetOpenAuth/Configuration/AssociationTypeElement.cs @@ -8,6 +8,7 @@ namespace DotNetOpenAuth.Configuration { using System; using System.Collections.Generic; using System.Configuration; + using System.Diagnostics.Contracts; using System.Linq; using System.Text; @@ -15,6 +16,7 @@ namespace DotNetOpenAuth.Configuration { /// Describes an association type and its maximum lifetime as an element /// in a .config file. /// </summary> + [ContractVerification(true)] internal class AssociationTypeElement : ConfigurationElement { /// <summary> /// The name of the attribute that stores the association type. diff --git a/src/DotNetOpenAuth/Configuration/DotNetOpenAuthSection.cs b/src/DotNetOpenAuth/Configuration/DotNetOpenAuthSection.cs index a419334..b38c882 100644 --- a/src/DotNetOpenAuth/Configuration/DotNetOpenAuthSection.cs +++ b/src/DotNetOpenAuth/Configuration/DotNetOpenAuthSection.cs @@ -6,11 +6,13 @@ namespace DotNetOpenAuth.Configuration { using System.Configuration; + using System.Diagnostics.Contracts; /// <summary> /// Represents the section in the host's .config file that configures /// this library's settings. /// </summary> + [ContractVerification(true)] public class DotNetOpenAuthSection : ConfigurationSection { /// <summary> /// The name of the section under which this library's settings must be found. @@ -31,7 +33,8 @@ namespace DotNetOpenAuth.Configuration { /// Initializes a new instance of the <see cref="DotNetOpenAuthSection"/> class. /// </summary> internal DotNetOpenAuthSection() { - SectionInformation.AllowLocation = false; + Contract.Assert(this.SectionInformation != null); + this.SectionInformation.AllowLocation = false; } /// <summary> diff --git a/src/DotNetOpenAuth/Configuration/HostNameElement.cs b/src/DotNetOpenAuth/Configuration/HostNameElement.cs index 304fe92..f252d6f 100644 --- a/src/DotNetOpenAuth/Configuration/HostNameElement.cs +++ b/src/DotNetOpenAuth/Configuration/HostNameElement.cs @@ -6,10 +6,12 @@ namespace DotNetOpenAuth.Configuration { using System.Configuration; + using System.Diagnostics.Contracts; /// <summary> /// Represents the name of a single host or a regex pattern for host names. /// </summary> + [ContractVerification(true)] internal class HostNameElement : ConfigurationElement { /// <summary> /// Gets the name of the @name attribute. diff --git a/src/DotNetOpenAuth/Configuration/HostNameOrRegexCollection.cs b/src/DotNetOpenAuth/Configuration/HostNameOrRegexCollection.cs index 0fa2fb1..1c3062f 100644 --- a/src/DotNetOpenAuth/Configuration/HostNameOrRegexCollection.cs +++ b/src/DotNetOpenAuth/Configuration/HostNameOrRegexCollection.cs @@ -7,11 +7,13 @@ namespace DotNetOpenAuth.Configuration { using System.Collections.Generic; using System.Configuration; + using System.Diagnostics.Contracts; using System.Text.RegularExpressions; /// <summary> /// Represents a collection of child elements that describe host names either as literal host names or regex patterns. /// </summary> + [ContractVerification(true)] internal class HostNameOrRegexCollection : ConfigurationElementCollection { /// <summary> /// Initializes a new instance of the <see cref="HostNameOrRegexCollection"/> class. @@ -59,6 +61,7 @@ namespace DotNetOpenAuth.Configuration { /// An <see cref="T:System.Object"/> that acts as the key for the specified <see cref="T:System.Configuration.ConfigurationElement"/>. /// </returns> protected override object GetElementKey(ConfigurationElement element) { + Contract.Assert(element != null); // this should be Contract.Requires in base class. return ((HostNameElement)element).Name; } } diff --git a/src/DotNetOpenAuth/Configuration/MessagingElement.cs b/src/DotNetOpenAuth/Configuration/MessagingElement.cs index 6c4fb24..86ff615 100644 --- a/src/DotNetOpenAuth/Configuration/MessagingElement.cs +++ b/src/DotNetOpenAuth/Configuration/MessagingElement.cs @@ -7,12 +7,14 @@ namespace DotNetOpenAuth.Configuration { using System; using System.Configuration; + using System.Diagnostics.Contracts; using DotNetOpenAuth.Messaging; using DotNetOpenAuth.Messaging.Bindings; /// <summary> /// Represents the <messaging> element in the host's .config file. /// </summary> + [ContractVerification(true)] public class MessagingElement : ConfigurationElement { /// <summary> /// The name of the <untrustedWebRequest> sub-element. diff --git a/src/DotNetOpenAuth/Configuration/OpenIdElement.cs b/src/DotNetOpenAuth/Configuration/OpenIdElement.cs index ec466ca..d5986c6 100644 --- a/src/DotNetOpenAuth/Configuration/OpenIdElement.cs +++ b/src/DotNetOpenAuth/Configuration/OpenIdElement.cs @@ -7,10 +7,12 @@ namespace DotNetOpenAuth.Configuration { using System; using System.Configuration; + using System.Diagnostics.Contracts; /// <summary> /// Represents the <openid> element in the host's .config file. /// </summary> + [ContractVerification(true)] internal class OpenIdElement : ConfigurationElement { /// <summary> /// Gets the name of the <relyingParty> sub-element. diff --git a/src/DotNetOpenAuth/Configuration/OpenIdProviderElement.cs b/src/DotNetOpenAuth/Configuration/OpenIdProviderElement.cs index 5b51907..a68c0c4 100644 --- a/src/DotNetOpenAuth/Configuration/OpenIdProviderElement.cs +++ b/src/DotNetOpenAuth/Configuration/OpenIdProviderElement.cs @@ -6,11 +6,13 @@ namespace DotNetOpenAuth.Configuration { using System.Configuration; + using System.Diagnostics.Contracts; using DotNetOpenAuth.OpenId.Provider; /// <summary> /// The section in the .config file that allows customization of OpenID Provider behaviors. /// </summary> + [ContractVerification(true)] internal class OpenIdProviderElement : ConfigurationElement { /// <summary> /// The name of the security sub-element. diff --git a/src/DotNetOpenAuth/Configuration/OpenIdRelyingPartyElement.cs b/src/DotNetOpenAuth/Configuration/OpenIdRelyingPartyElement.cs index cb20c19..fd16125 100644 --- a/src/DotNetOpenAuth/Configuration/OpenIdRelyingPartyElement.cs +++ b/src/DotNetOpenAuth/Configuration/OpenIdRelyingPartyElement.cs @@ -6,11 +6,13 @@ namespace DotNetOpenAuth.Configuration { using System.Configuration; + using System.Diagnostics.Contracts; using DotNetOpenAuth.OpenId.RelyingParty; /// <summary> /// The section in the .config file that allows customization of OpenID Relying Party behaviors. /// </summary> + [ContractVerification(true)] internal class OpenIdRelyingPartyElement : ConfigurationElement { /// <summary> /// The name of the custom store sub-element. diff --git a/src/DotNetOpenAuth/Configuration/ProviderSecuritySettingsElement.cs b/src/DotNetOpenAuth/Configuration/ProviderSecuritySettingsElement.cs index 11b4859..3cd17f3 100644 --- a/src/DotNetOpenAuth/Configuration/ProviderSecuritySettingsElement.cs +++ b/src/DotNetOpenAuth/Configuration/ProviderSecuritySettingsElement.cs @@ -6,12 +6,14 @@ namespace DotNetOpenAuth.Configuration { using System.Configuration; + using System.Diagnostics.Contracts; using DotNetOpenAuth.OpenId; using DotNetOpenAuth.OpenId.Provider; /// <summary> /// Represents the .config file element that allows for setting the security policies of the Provider. /// </summary> + [ContractVerification(true)] internal class ProviderSecuritySettingsElement : ConfigurationElement { /// <summary> /// Gets the name of the @protectDownlevelReplayAttacks attribute. @@ -73,8 +75,14 @@ namespace DotNetOpenAuth.Configuration { [ConfigurationProperty(AssociationsConfigName, IsDefaultCollection = false)] [ConfigurationCollection(typeof(AssociationTypeCollection))] public AssociationTypeCollection AssociationLifetimes { - get { return (AssociationTypeCollection)this[AssociationsConfigName] ?? new AssociationTypeCollection(); } - set { this[AssociationsConfigName] = value; } + get { + Contract.Ensures(Contract.Result<AssociationTypeCollection>() != null); + return (AssociationTypeCollection)this[AssociationsConfigName] ?? new AssociationTypeCollection(); + } + + set { + this[AssociationsConfigName] = value; + } } /// <summary> @@ -87,6 +95,7 @@ namespace DotNetOpenAuth.Configuration { settings.MaximumHashBitLength = this.MaximumHashBitLength; settings.ProtectDownlevelReplayAttacks = this.ProtectDownlevelReplayAttacks; foreach (AssociationTypeElement element in this.AssociationLifetimes) { + Contract.Assert(element != null); settings.AssociationLifetimes.Add(element.AssociationType, element.MaximumLifetime); } return settings; diff --git a/src/DotNetOpenAuth/Messaging/ErrorUtilities.cs b/src/DotNetOpenAuth/Messaging/ErrorUtilities.cs index c07a70e..8c001c4 100644 --- a/src/DotNetOpenAuth/Messaging/ErrorUtilities.cs +++ b/src/DotNetOpenAuth/Messaging/ErrorUtilities.cs @@ -214,6 +214,7 @@ namespace DotNetOpenAuth.Messaging { /// <param name="args">The string formatting arguments, if any.</param> /// <exception cref="ArgumentException">Thrown if <paramref name="condition"/> evaluates to <c>false</c>.</exception> internal static void VerifyArgument(bool condition, string message, params object[] args) { + Contract.Requires(condition); Contract.Requires(args != null); Contract.Assume(message != null); if (!condition) { @@ -228,6 +229,7 @@ namespace DotNetOpenAuth.Messaging { /// <param name="parameterName">Name of the parameter.</param> /// <exception cref="ArgumentOutOfRangeException">Thrown if <paramref name="condition"/> evaluates to <c>false</c>.</exception> internal static void VerifyArgumentInRange(bool condition, string parameterName) { + Contract.Requires(condition); if (!condition) { throw new ArgumentOutOfRangeException(parameterName); } @@ -242,6 +244,7 @@ namespace DotNetOpenAuth.Messaging { /// <param name="args">The string formatting arguments.</param> /// <exception cref="ArgumentOutOfRangeException">Thrown if <paramref name="condition"/> evaluates to <c>false</c>.</exception> internal static void VerifyArgumentInRange(bool condition, string parameterName, string message, params object[] args) { + Contract.Requires(condition); Contract.Requires(args != null); Contract.Assume(message != null); if (!condition) { @@ -258,6 +261,7 @@ namespace DotNetOpenAuth.Messaging { /// <param name="args">The string formatting arguments, if any.</param> /// <exception cref="ArgumentException">Thrown if <paramref name="condition"/> evaluates to <c>false</c>.</exception> internal static void VerifyArgumentNamed(bool condition, string parameterName, string message, params object[] args) { + Contract.Requires(condition); Contract.Requires(args != null); Contract.Assume(message != null); if (!condition) { @@ -272,7 +276,7 @@ namespace DotNetOpenAuth.Messaging { /// <param name="paramName">Name of the parameter, which will be used in the <see cref="ArgumentException"/>, if thrown.</param> /// <exception cref="ArgumentNullException">Thrown if <paramref name="value"/> is null.</exception> internal static void VerifyArgumentNotNull(object value, string paramName) { - Contract.EndContractBlock(); + Contract.Requires(value != null); if (value == null) { throw new ArgumentNullException(paramName); } @@ -288,7 +292,7 @@ namespace DotNetOpenAuth.Messaging { /// <exception cref="ArgumentNullException">Thrown if <paramref name="value"/> is null.</exception> /// <exception cref="ArgumentException">Thrown if <paramref name="value"/> has zero length.</exception> internal static void VerifyNonZeroLength(string value, string paramName) { - Contract.EndContractBlock(); + Contract.Requires(!string.IsNullOrEmpty(value) || (value != null && value.Length > 0)); VerifyArgumentNotNull(value, paramName); if (value.Length == 0) { throw new ArgumentException(MessagingStrings.UnexpectedEmptyString, paramName); diff --git a/src/DotNetOpenAuth/Messaging/IMessage.cs b/src/DotNetOpenAuth/Messaging/IMessage.cs index acc1224..7eba540 100644 --- a/src/DotNetOpenAuth/Messaging/IMessage.cs +++ b/src/DotNetOpenAuth/Messaging/IMessage.cs @@ -7,16 +7,21 @@ namespace DotNetOpenAuth.Messaging { using System; using System.Collections.Generic; + using System.Diagnostics.Contracts; using System.Text; /// <summary> /// The interface that classes must implement to be serialized/deserialized /// as protocol or extension messages. /// </summary> + [ContractClass(typeof(IMessageContract))] public interface IMessage { /// <summary> /// Gets the version of the protocol or extension this message is prepared to implement. /// </summary> + /// <remarks> + /// Implementations of this interface should ensure that this property never returns null. + /// </remarks> Version Version { get; } /// <summary> @@ -41,4 +46,46 @@ namespace DotNetOpenAuth.Messaging { /// <exception cref="ProtocolException">Thrown if the message is invalid.</exception> void EnsureValidMessage(); } + + [ContractClassFor(typeof(IMessage))] + internal sealed class IMessageContract : IMessage { + /// <summary> + /// Gets the version of the protocol or extension this message is prepared to implement. + /// </summary> + Version IMessage.Version { + get { + Contract.Ensures(Contract.Result<Version>() != null); + return default(Version); // dummy return + } + } + + /// <summary> + /// Gets the extra, non-standard Protocol parameters included in the message. + /// </summary> + /// <value></value> + /// <remarks> + /// Implementations of this interface should ensure that this property never returns null. + /// </remarks> + IDictionary<string, string> IMessage.ExtraData { + get { + Contract.Ensures(Contract.Result<IDictionary<string, string>>() != null); + return default(IDictionary<string, string>); + } + } + + /// <summary> + /// Checks the message state for conformity to the protocol specification + /// and throws an exception if the message is invalid. + /// </summary> + /// <remarks> + /// <para>Some messages have required fields, or combinations of fields that must relate to each other + /// in specialized ways. After deserializing a message, this method checks the state of the + /// message to see if it conforms to the protocol.</para> + /// <para>Note that this property should <i>not</i> check signatures or perform any state checks + /// outside this scope of this particular message.</para> + /// </remarks> + /// <exception cref="ProtocolException">Thrown if the message is invalid.</exception> + void IMessage.EnsureValidMessage() { + } + } } diff --git a/src/DotNetOpenAuth/Messaging/MessageSerializer.cs b/src/DotNetOpenAuth/Messaging/MessageSerializer.cs index 55f82df..873c7bf 100644 --- a/src/DotNetOpenAuth/Messaging/MessageSerializer.cs +++ b/src/DotNetOpenAuth/Messaging/MessageSerializer.cs @@ -33,6 +33,7 @@ namespace DotNetOpenAuth.Messaging { /// that will be serialized and deserialized using this class.</param> private MessageSerializer(Type messageType) { Contract.Requires(messageType != null); + Contract.Requires(typeof(IMessage).IsAssignableFrom(messageType)); ErrorUtilities.VerifyArgumentNamed( typeof(IMessage).IsAssignableFrom(messageType), @@ -50,9 +51,9 @@ namespace DotNetOpenAuth.Messaging { /// <param name="messageType">The type of message that will be serialized/deserialized.</param> /// <returns>A message serializer for the given message type.</returns> internal static MessageSerializer Get(Type messageType) { - if (messageType == null) { - throw new ArgumentNullException("messageType"); - } + Contract.Requires(messageType != null); + Contract.Requires(typeof(IMessage).IsAssignableFrom(messageType)); + ErrorUtilities.VerifyArgumentNotNull(messageType, "messageType"); return new MessageSerializer(messageType); } @@ -64,6 +65,7 @@ namespace DotNetOpenAuth.Messaging { /// <returns>The dictionary of values to send for the message.</returns> [SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic", Justification = "Parallel design with Deserialize method.")] internal IDictionary<string, string> Serialize(IMessage message) { + Contract.Requires(message != null); ErrorUtilities.VerifyArgumentNotNull(message, "message"); var messageDescription = MessageDescription.Get(this.messageType, message.Version); @@ -77,6 +79,7 @@ namespace DotNetOpenAuth.Messaging { foreach (var pair in messageDictionary) { MessagePart partDescription; if (messageDescription.Mapping.TryGetValue(pair.Key, out partDescription)) { + Contract.Assert(partDescription != null); if (partDescription.IsRequired || partDescription.IsNondefaultValueSet(message)) { result.Add(pair.Key, pair.Value); } @@ -96,6 +99,8 @@ namespace DotNetOpenAuth.Messaging { /// <param name="message">The message to deserialize into.</param> /// <exception cref="ProtocolException">Thrown when protocol rules are broken by the incoming message.</exception> internal void Deserialize(IDictionary<string, string> fields, IMessage message) { + Contract.Requires(fields != null); + Contract.Requires(message != null); ErrorUtilities.VerifyArgumentNotNull(fields, "fields"); ErrorUtilities.VerifyArgumentNotNull(message, "message"); diff --git a/src/DotNetOpenAuth/Messaging/Reflection/MessageDescription.cs b/src/DotNetOpenAuth/Messaging/Reflection/MessageDescription.cs index dcd5b9c..a47126a 100644 --- a/src/DotNetOpenAuth/Messaging/Reflection/MessageDescription.cs +++ b/src/DotNetOpenAuth/Messaging/Reflection/MessageDescription.cs @@ -8,6 +8,7 @@ namespace DotNetOpenAuth.Messaging.Reflection { using System; using System.Collections.Generic; using System.Diagnostics; + using System.Diagnostics.Contracts; using System.Globalization; using System.Linq; using System.Reflection; @@ -68,6 +69,9 @@ namespace DotNetOpenAuth.Messaging.Reflection { /// <param name="messageVersion">The protocol version of the message.</param> /// <returns>A <see cref="MessageDescription"/> instance.</returns> internal static MessageDescription Get(Type messageType, Version messageVersion) { + Contract.Requires(messageType != null); + Contract.Requires(messageVersion != null); + Contract.Ensures(Contract.Result<MessageDescription>() != null); ErrorUtilities.VerifyArgumentNotNull(messageType, "messageType"); ErrorUtilities.VerifyArgumentNotNull(messageVersion, "messageVersion"); diff --git a/src/DotNetOpenAuth/OpenId/Identifier.cs b/src/DotNetOpenAuth/OpenId/Identifier.cs index 0179ee1..d1f09ce 100644 --- a/src/DotNetOpenAuth/OpenId/Identifier.cs +++ b/src/DotNetOpenAuth/OpenId/Identifier.cs @@ -90,6 +90,7 @@ namespace DotNetOpenAuth.OpenId { /// <returns>An <see cref="Identifier"/> instance for the given value.</returns> [SuppressMessage("Microsoft.Usage", "CA2234:PassSystemUriObjectsInsteadOfStrings", Justification = "Some of these identifiers are not properly formatted to be Uris at this stage.")] public static Identifier Parse(string identifier) { + Contract.Requires(!string.IsNullOrEmpty(identifier)); ErrorUtilities.VerifyArgumentNotNull(identifier, "identifier"); if (XriIdentifier.IsValidXri(identifier)) { return new XriIdentifier(identifier); @@ -125,6 +126,7 @@ namespace DotNetOpenAuth.OpenId { /// </returns> [SuppressMessage("Microsoft.Usage", "CA2234:PassSystemUriObjectsInsteadOfStrings", Justification = "Some of these identifiers are not properly formatted to be Uris at this stage.")] public static bool IsValid(string identifier) { + Contract.Requires(!string.IsNullOrEmpty(identifier)); return XriIdentifier.IsValidXri(identifier) || UriIdentifier.IsValidUri(identifier); } diff --git a/src/DotNetOpenAuth/OpenId/NoDiscoveryIdentifier.cs b/src/DotNetOpenAuth/OpenId/NoDiscoveryIdentifier.cs index 531356f..2c8e865 100644 --- a/src/DotNetOpenAuth/OpenId/NoDiscoveryIdentifier.cs +++ b/src/DotNetOpenAuth/OpenId/NoDiscoveryIdentifier.cs @@ -6,6 +6,7 @@ namespace DotNetOpenAuth.OpenId { using System.Collections.Generic; + using System.Diagnostics.Contracts; using System.Linq; using DotNetOpenAuth.Messaging; using DotNetOpenAuth.OpenId.RelyingParty; @@ -13,11 +14,13 @@ namespace DotNetOpenAuth.OpenId { /// <summary> /// Wraps an existing Identifier and prevents it from performing discovery. /// </summary> + [ContractVerification(true)] + [Pure] internal class NoDiscoveryIdentifier : Identifier { /// <summary> /// The wrapped identifier. /// </summary> - private Identifier wrappedIdentifier; + private readonly Identifier wrappedIdentifier; /// <summary> /// Initializes a new instance of the <see cref="NoDiscoveryIdentifier"/> class. @@ -26,6 +29,7 @@ namespace DotNetOpenAuth.OpenId { /// <param name="claimSsl">Whether this Identifier should claim to be SSL-secure, although no discovery will never generate service endpoints anyway.</param> internal NoDiscoveryIdentifier(Identifier wrappedIdentifier, bool claimSsl) : base(claimSsl) { + Contract.Requires(wrappedIdentifier != null); ErrorUtilities.VerifyArgumentNotNull(wrappedIdentifier, "wrappedIdentifier"); this.wrappedIdentifier = wrappedIdentifier; diff --git a/src/DotNetOpenAuth/OpenId/Realm.cs b/src/DotNetOpenAuth/OpenId/Realm.cs index 90680aa..83a2189 100644 --- a/src/DotNetOpenAuth/OpenId/Realm.cs +++ b/src/DotNetOpenAuth/OpenId/Realm.cs @@ -26,7 +26,6 @@ namespace DotNetOpenAuth.OpenId { /// See http://openid.net/specs/openid-authentication-2_0.html#realms /// </remarks> [Serializable] -// [ContractVerification(true)] [Pure] public sealed class Realm { /// <summary> diff --git a/src/DotNetOpenAuth/OpenId/UriIdentifier.cs b/src/DotNetOpenAuth/OpenId/UriIdentifier.cs index e5de997..6f5ff7c 100644 --- a/src/DotNetOpenAuth/OpenId/UriIdentifier.cs +++ b/src/DotNetOpenAuth/OpenId/UriIdentifier.cs @@ -21,7 +21,6 @@ namespace DotNetOpenAuth.OpenId { /// A URI style of OpenID Identifier. /// </summary> [Serializable] - //[ContractVerification(true)] [Pure] public sealed class UriIdentifier : Identifier { /// <summary> @@ -417,6 +416,7 @@ namespace DotNetOpenAuth.OpenId { /// require network access are also done, such as lower-casing the hostname in the URI. /// </remarks> private static bool TryCanonicalize(string uri, out Uri canonicalUri, bool forceHttpsDefaultScheme, out bool schemePrepended) { + Contract.Requires(!string.IsNullOrEmpty(uri)); ErrorUtilities.VerifyNonZeroLength(uri, "uri"); uri = uri.Trim(); diff --git a/src/DotNetOpenAuth/OpenId/XriIdentifier.cs b/src/DotNetOpenAuth/OpenId/XriIdentifier.cs index b0610b5..20fa1d5 100644 --- a/src/DotNetOpenAuth/OpenId/XriIdentifier.cs +++ b/src/DotNetOpenAuth/OpenId/XriIdentifier.cs @@ -72,6 +72,7 @@ namespace DotNetOpenAuth.OpenId { /// </param> internal XriIdentifier(string xri, bool requireSsl) : base(requireSsl) { + Contract.Requires(!string.IsNullOrEmpty(xri)); ErrorUtilities.VerifyFormat(IsValidXri(xri), OpenIdStrings.InvalidXri, xri); Contract.Assume(xri != null); // Proven by IsValidXri this.xriResolverProxy = XriResolverProxyTemplate; @@ -93,7 +94,10 @@ namespace DotNetOpenAuth.OpenId { /// Gets the canonical form of the XRI string. /// </summary> internal string CanonicalXri { - get { return this.canonicalXri; } + get { + Contract.Ensures(Contract.Result<string>() != null); + return this.canonicalXri; + } } /// <summary> @@ -142,15 +146,6 @@ namespace DotNetOpenAuth.OpenId { } /// <summary> - /// Verifies conditions that should be true for any valid state of this object. - /// </summary> - [ContractInvariantMethod] - protected void ObjectInvariant() { - Contract.Invariant(this.xriResolverProxy != null); - Contract.Invariant(this.canonicalXri != null); - } - - /// <summary> /// Tests whether a given string represents a valid XRI format. /// </summary> /// <param name="xri">The value to test for XRI validity.</param> @@ -158,6 +153,7 @@ namespace DotNetOpenAuth.OpenId { /// <c>true</c> if the given string constitutes a valid XRI; otherwise, <c>false</c>. /// </returns> internal static bool IsValidXri(string xri) { + Contract.Requires(!string.IsNullOrEmpty(xri)); ErrorUtilities.VerifyNonZeroLength(xri, "xri"); xri = xri.Trim(); @@ -224,6 +220,15 @@ namespace DotNetOpenAuth.OpenId { } /// <summary> + /// Verifies conditions that should be true for any valid state of this object. + /// </summary> + [ContractInvariantMethod] + protected void ObjectInvariant() { + Contract.Invariant(this.xriResolverProxy != null); + Contract.Invariant(this.canonicalXri != null); + } + + /// <summary> /// Takes any valid form of XRI string and returns the canonical form of the same XRI. /// </summary> /// <param name="xri">The xri to canonicalize.</param> diff --git a/src/DotNetOpenAuth/UriUtil.cs b/src/DotNetOpenAuth/UriUtil.cs index f8f480c..4790ec6 100644 --- a/src/DotNetOpenAuth/UriUtil.cs +++ b/src/DotNetOpenAuth/UriUtil.cs @@ -8,12 +8,12 @@ namespace DotNetOpenAuth { using System; using System.Collections.Specialized; using System.Diagnostics.CodeAnalysis; + using System.Diagnostics.Contracts; using System.Linq; using System.Text.RegularExpressions; using System.Web; using System.Web.UI; using DotNetOpenAuth.Messaging; - using System.Diagnostics.Contracts; /// <summary> /// Utility methods for working with URIs. @@ -29,12 +29,14 @@ namespace DotNetOpenAuth { /// True if the URI contains an OAuth message. /// </returns> internal static bool QueryStringContainPrefixedParameters(this Uri uri, string prefix) { + Contract.Requires(!string.IsNullOrEmpty(prefix)); ErrorUtilities.VerifyNonZeroLength(prefix, "prefix"); if (uri == null) { return false; } NameValueCollection nvc = HttpUtility.ParseQueryString(uri.Query); + Contract.Assert(nvc != null); // BCL return nvc.Keys.OfType<string>().Any(key => key.StartsWith(prefix, StringComparison.Ordinal)); } @@ -97,6 +99,8 @@ namespace DotNetOpenAuth { } if (page != null && !designMode) { + Contract.Assert(page.Request != null); + // Validate new value by trying to construct a Realm object based on it. new Uri(page.Request.Url, page.ResolveUrl(value)); // throws an exception on failure. } else { diff --git a/src/DotNetOpenAuth/Util.cs b/src/DotNetOpenAuth/Util.cs index cb5581f..1a67966 100644 --- a/src/DotNetOpenAuth/Util.cs +++ b/src/DotNetOpenAuth/Util.cs @@ -6,6 +6,7 @@ namespace DotNetOpenAuth { using System; using System.Collections.Generic; + using System.Diagnostics.Contracts; using System.Globalization; using System.Net; using System.Reflection; @@ -14,6 +15,7 @@ namespace DotNetOpenAuth { /// <summary> /// A grab-bag utility class. /// </summary> + [ContractVerification(true)] internal static class Util { /// <summary> /// The base namespace for this library from which all other namespaces derive. @@ -72,6 +74,7 @@ namespace DotNetOpenAuth { return new DelayedToString<IEnumerable<KeyValuePair<K, V>>>( pairs, p => { + Contract.Requires(pairs != null); var dictionary = pairs as IDictionary<K, V>; StringBuilder sb = new StringBuilder(dictionary != null ? dictionary.Count * 40 : 200); foreach (var pair in pairs) { @@ -103,6 +106,9 @@ namespace DotNetOpenAuth { return new DelayedToString<IEnumerable<T>>( list, l => { + Contract.Requires(l != null); + string newLine = Environment.NewLine; + Contract.Assume(newLine != null && newLine.Length > 0); StringBuilder sb = new StringBuilder(); if (multiLineElements) { sb.AppendLine("[{"); @@ -111,7 +117,7 @@ namespace DotNetOpenAuth { string objString = obj != null ? obj.ToString() : "<NULL>"; // Indent every line printed - objString = objString.Replace(Environment.NewLine, Environment.NewLine + "\t"); + objString = objString.Replace(newLine, Environment.NewLine + "\t"); sb.Append("\t"); sb.Append(objString); @@ -150,12 +156,12 @@ namespace DotNetOpenAuth { /// <summary> /// The object that will be serialized if called upon. /// </summary> - private T obj; + private readonly T obj; /// <summary> /// The method used to serialize <see cref="obj"/> to string form. /// </summary> - private Func<T, string> toString; + private readonly Func<T, string> toString; /// <summary> /// Initializes a new instance of the DelayedToString class. @@ -163,6 +169,8 @@ namespace DotNetOpenAuth { /// <param name="obj">The object that may be serialized to string form.</param> /// <param name="toString">The method that will serialize the object if called upon.</param> public DelayedToString(T obj, Func<T, string> toString) { + Contract.Requires(toString != null); + this.obj = obj; this.toString = toString; } @@ -174,7 +182,7 @@ namespace DotNetOpenAuth { /// A <see cref="T:System.String"/> that represents the current <see cref="T:System.Object"/>. /// </returns> public override string ToString() { - return this.toString(this.obj); + return this.toString(this.obj) ?? string.Empty; } } } |