PageRenderTime 88ms CodeModel.GetById 21ms RepoModel.GetById 1ms app.codeStats 0ms

/src/NUnit/framework/Constraints/Constraint.cs

#
C# | 379 lines | 194 code | 39 blank | 146 comment | 17 complexity | 9f28fe896aeac4fe9bf543ac00953ec4 MD5 | raw file
Possible License(s): GPL-2.0
  1. // ****************************************************************
  2. // Copyright 2007, Charlie Poole
  3. // This is free software licensed under the NUnit license. You may
  4. // obtain a copy of the license at http://nunit.org
  5. // ****************************************************************
  6. using System.Collections;
  7. namespace NUnit.Framework.Constraints
  8. {
  9. /// <summary>
  10. /// Delegate used to delay evaluation of the actual value
  11. /// to be used in evaluating a constraint
  12. /// </summary>
  13. public delegate object ActualValueDelegate();
  14. /// <summary>
  15. /// The Constraint class is the base of all built-in constraints
  16. /// within NUnit. It provides the operator overloads used to combine
  17. /// constraints.
  18. /// </summary>
  19. public abstract class Constraint : IResolveConstraint
  20. {
  21. #region UnsetObject Class
  22. /// <summary>
  23. /// Class used to detect any derived constraints
  24. /// that fail to set the actual value in their
  25. /// Matches override.
  26. /// </summary>
  27. private class UnsetObject
  28. {
  29. public override string ToString()
  30. {
  31. return "UNSET";
  32. }
  33. }
  34. #endregion
  35. #region Static and Instance Fields
  36. /// <summary>
  37. /// Static UnsetObject used to detect derived constraints
  38. /// failing to set the actual value.
  39. /// </summary>
  40. protected static object UNSET = new UnsetObject();
  41. /// <summary>
  42. /// The actual value being tested against a constraint
  43. /// </summary>
  44. protected object actual = UNSET;
  45. /// <summary>
  46. /// The display name of this Constraint for use by ToString()
  47. /// </summary>
  48. private string displayName;
  49. /// <summary>
  50. /// Argument fields used by ToString();
  51. /// </summary>
  52. private readonly int argcnt;
  53. private readonly object arg1;
  54. private readonly object arg2;
  55. /// <summary>
  56. /// The builder holding this constraint
  57. /// </summary>
  58. private ConstraintBuilder builder;
  59. #endregion
  60. #region Constructors
  61. /// <summary>
  62. /// Construct a constraint with no arguments
  63. /// </summary>
  64. public Constraint()
  65. {
  66. argcnt = 0;
  67. }
  68. /// <summary>
  69. /// Construct a constraint with one argument
  70. /// </summary>
  71. public Constraint(object arg)
  72. {
  73. argcnt = 1;
  74. this.arg1 = arg;
  75. }
  76. /// <summary>
  77. /// Construct a constraint with two arguments
  78. /// </summary>
  79. public Constraint(object arg1, object arg2)
  80. {
  81. argcnt = 2;
  82. this.arg1 = arg1;
  83. this.arg2 = arg2;
  84. }
  85. #endregion
  86. #region Set Containing ConstraintBuilder
  87. /// <summary>
  88. /// Sets the ConstraintBuilder holding this constraint
  89. /// </summary>
  90. internal void SetBuilder(ConstraintBuilder builder)
  91. {
  92. this.builder = builder;
  93. }
  94. #endregion
  95. #region Properties
  96. /// <summary>
  97. /// The display name of this Constraint for use by ToString().
  98. /// The default value is the name of the constraint with
  99. /// trailing "Constraint" removed. Derived classes may set
  100. /// this to another name in their constructors.
  101. /// </summary>
  102. public string DisplayName
  103. {
  104. get
  105. {
  106. if (displayName == null)
  107. {
  108. displayName = this.GetType().Name.ToLower();
  109. if (displayName.EndsWith("`1") || displayName.EndsWith("`2"))
  110. displayName = displayName.Substring(0, displayName.Length - 2);
  111. if (displayName.EndsWith("constraint"))
  112. displayName = displayName.Substring(0, displayName.Length - 10);
  113. }
  114. return displayName;
  115. }
  116. set { displayName = value; }
  117. }
  118. #endregion
  119. #region Abstract and Virtual Methods
  120. /// <summary>
  121. /// Write the failure message to the MessageWriter provided
  122. /// as an argument. The default implementation simply passes
  123. /// the constraint and the actual value to the writer, which
  124. /// then displays the constraint description and the value.
  125. ///
  126. /// Constraints that need to provide additional details,
  127. /// such as where the error occured can override this.
  128. /// </summary>
  129. /// <param name="writer">The MessageWriter on which to display the message</param>
  130. public virtual void WriteMessageTo(MessageWriter writer)
  131. {
  132. writer.DisplayDifferences(this);
  133. }
  134. /// <summary>
  135. /// Test whether the constraint is satisfied by a given value
  136. /// </summary>
  137. /// <param name="actual">The value to be tested</param>
  138. /// <returns>True for success, false for failure</returns>
  139. public abstract bool Matches(object actual);
  140. /// <summary>
  141. /// Test whether the constraint is satisfied by an
  142. /// ActualValueDelegate that returns the value to be tested.
  143. /// The default implementation simply evaluates the delegate
  144. /// but derived classes may override it to provide for delayed
  145. /// processing.
  146. /// </summary>
  147. /// <param name="del">An ActualValueDelegate</param>
  148. /// <returns>True for success, false for failure</returns>
  149. public virtual bool Matches(ActualValueDelegate del)
  150. {
  151. return Matches(del());
  152. }
  153. #if NET_2_0
  154. /// <summary>
  155. /// Test whether the constraint is satisfied by a given reference.
  156. /// The default implementation simply dereferences the value but
  157. /// derived classes may override it to provide for delayed processing.
  158. /// </summary>
  159. /// <param name="actual">A reference to the value to be tested</param>
  160. /// <returns>True for success, false for failure</returns>
  161. public virtual bool Matches<T>(ref T actual)
  162. {
  163. return Matches(actual);
  164. }
  165. #else
  166. /// <summary>
  167. /// Test whether the constraint is satisfied by a given bool reference.
  168. /// The default implementation simply dereferences the value but
  169. /// derived classes may override it to provide for delayed processing.
  170. /// </summary>
  171. /// <param name="actual">A reference to the value to be tested</param>
  172. /// <returns>True for success, false for failure</returns>
  173. public virtual bool Matches(ref bool actual)
  174. {
  175. return Matches(actual);
  176. }
  177. #endif
  178. /// <summary>
  179. /// Write the constraint description to a MessageWriter
  180. /// </summary>
  181. /// <param name="writer">The writer on which the description is displayed</param>
  182. public abstract void WriteDescriptionTo(MessageWriter writer);
  183. /// <summary>
  184. /// Write the actual value for a failing constraint test to a
  185. /// MessageWriter. The default implementation simply writes
  186. /// the raw value of actual, leaving it to the writer to
  187. /// perform any formatting.
  188. /// </summary>
  189. /// <param name="writer">The writer on which the actual value is displayed</param>
  190. public virtual void WriteActualValueTo(MessageWriter writer)
  191. {
  192. writer.WriteActualValue( actual );
  193. }
  194. #endregion
  195. #region ToString Override
  196. /// <summary>
  197. /// Default override of ToString returns the constraint DisplayName
  198. /// followed by any arguments within angle brackets.
  199. /// </summary>
  200. /// <returns></returns>
  201. public override string ToString()
  202. {
  203. string rep = GetStringRepresentation();
  204. return this.builder == null ? rep : string.Format("<unresolved {0}>", rep);
  205. }
  206. /// <summary>
  207. /// Returns the string representation of this constraint
  208. /// </summary>
  209. protected virtual string GetStringRepresentation()
  210. {
  211. switch (argcnt)
  212. {
  213. default:
  214. case 0:
  215. return string.Format("<{0}>", DisplayName);
  216. case 1:
  217. return string.Format("<{0} {1}>", DisplayName, _displayable(arg1));
  218. case 2:
  219. return string.Format("<{0} {1} {2}>", DisplayName, _displayable(arg1), _displayable(arg2));
  220. }
  221. }
  222. private string _displayable(object o)
  223. {
  224. if (o == null) return "null";
  225. string fmt = o is string ? "\"{0}\"" : "{0}";
  226. return string.Format(System.Globalization.CultureInfo.InvariantCulture, fmt, o);
  227. }
  228. #endregion
  229. #region Operator Overloads
  230. /// <summary>
  231. /// This operator creates a constraint that is satisfied only if both
  232. /// argument constraints are satisfied.
  233. /// </summary>
  234. public static Constraint operator &(Constraint left, Constraint right)
  235. {
  236. IResolveConstraint l = (IResolveConstraint)left;
  237. IResolveConstraint r = (IResolveConstraint)right;
  238. return new AndConstraint(l.Resolve(), r.Resolve());
  239. }
  240. /// <summary>
  241. /// This operator creates a constraint that is satisfied if either
  242. /// of the argument constraints is satisfied.
  243. /// </summary>
  244. public static Constraint operator |(Constraint left, Constraint right)
  245. {
  246. IResolveConstraint l = (IResolveConstraint)left;
  247. IResolveConstraint r = (IResolveConstraint)right;
  248. return new OrConstraint(l.Resolve(), r.Resolve());
  249. }
  250. /// <summary>
  251. /// This operator creates a constraint that is satisfied if the
  252. /// argument constraint is not satisfied.
  253. /// </summary>
  254. public static Constraint operator !(Constraint constraint)
  255. {
  256. IResolveConstraint r = constraint as IResolveConstraint;
  257. return new NotConstraint(r == null ? new NullConstraint() : r.Resolve());
  258. }
  259. #endregion
  260. #region Binary Operators
  261. /// <summary>
  262. /// Returns a ConstraintExpression by appending And
  263. /// to the current constraint.
  264. /// </summary>
  265. public ConstraintExpression And
  266. {
  267. get
  268. {
  269. ConstraintBuilder builder = this.builder;
  270. if (builder == null)
  271. {
  272. builder = new ConstraintBuilder();
  273. builder.Append(this);
  274. }
  275. builder.Append(new AndOperator());
  276. return new ConstraintExpression(builder);
  277. }
  278. }
  279. /// <summary>
  280. /// Returns a ConstraintExpression by appending And
  281. /// to the current constraint.
  282. /// </summary>
  283. public ConstraintExpression With
  284. {
  285. get { return this.And; }
  286. }
  287. /// <summary>
  288. /// Returns a ConstraintExpression by appending Or
  289. /// to the current constraint.
  290. /// </summary>
  291. public ConstraintExpression Or
  292. {
  293. get
  294. {
  295. ConstraintBuilder builder = this.builder;
  296. if (builder == null)
  297. {
  298. builder = new ConstraintBuilder();
  299. builder.Append(this);
  300. }
  301. builder.Append(new OrOperator());
  302. return new ConstraintExpression(builder);
  303. }
  304. }
  305. #endregion
  306. #region After Modifier
  307. /// <summary>
  308. /// Returns a DelayedConstraint with the specified delay time.
  309. /// </summary>
  310. /// <param name="delayInMilliseconds">The delay in milliseconds.</param>
  311. /// <returns></returns>
  312. public DelayedConstraint After(int delayInMilliseconds)
  313. {
  314. return new DelayedConstraint(
  315. builder == null ? this : builder.Resolve(),
  316. delayInMilliseconds);
  317. }
  318. /// <summary>
  319. /// Returns a DelayedConstraint with the specified delay time
  320. /// and polling interval.
  321. /// </summary>
  322. /// <param name="delayInMilliseconds">The delay in milliseconds.</param>
  323. /// <param name="pollingInterval">The interval at which to test the constraint.</param>
  324. /// <returns></returns>
  325. public DelayedConstraint After(int delayInMilliseconds, int pollingInterval)
  326. {
  327. return new DelayedConstraint(
  328. builder == null ? this : builder.Resolve(),
  329. delayInMilliseconds,
  330. pollingInterval);
  331. }
  332. #endregion
  333. #region IResolveConstraint Members
  334. Constraint IResolveConstraint.Resolve()
  335. {
  336. return builder == null ? this : builder.Resolve();
  337. }
  338. #endregion
  339. }
  340. }