/mcs/nunit24/NUnitFramework/framework/Constraints/ConstraintBuilder.cs

https://github.com/letssellsomebananas/mono · C# · 436 lines · 229 code · 43 blank · 164 comment · 2 complexity · 28b99b5bb07454baac07efdfea8156fc MD5 · raw file

  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/?p=license&r=2.4
  5. // ****************************************************************
  6. using System;
  7. using System.Collections;
  8. namespace NUnit.Framework.Constraints
  9. {
  10. /// <summary>
  11. /// ConstraintBuilder is used to resolve the Not and All properties,
  12. /// which serve as prefix operators for constraints. With the addition
  13. /// of an operand stack, And and Or could be supported, but we have
  14. /// left them out in favor of a simpler, more type-safe implementation.
  15. /// Use the &amp; and | operator overloads to combine constraints.
  16. /// </summary>
  17. public class ConstraintBuilder
  18. {
  19. private enum Op
  20. {
  21. Not,
  22. All,
  23. Some,
  24. None,
  25. Prop,
  26. }
  27. Stack ops = new Stack();
  28. Stack opnds = new Stack();
  29. /// <summary>
  30. /// Implicitly convert ConstraintBuilder to an actual Constraint
  31. /// at the point where the syntax demands it.
  32. /// </summary>
  33. /// <param name="builder"></param>
  34. /// <returns></returns>
  35. public static implicit operator Constraint( ConstraintBuilder builder )
  36. {
  37. return builder.Resolve();
  38. }
  39. #region Constraints Without Arguments
  40. /// <summary>
  41. /// Resolves the chain of constraints using
  42. /// EqualConstraint(null) as base.
  43. /// </summary>
  44. public Constraint Null
  45. {
  46. get { return Resolve(new EqualConstraint(null)); }
  47. }
  48. /// <summary>
  49. /// Resolves the chain of constraints using
  50. /// EqualConstraint(true) as base.
  51. /// </summary>
  52. public Constraint True
  53. {
  54. get { return Resolve(new EqualConstraint(true)); }
  55. }
  56. /// <summary>
  57. /// Resolves the chain of constraints using
  58. /// EqualConstraint(false) as base.
  59. /// </summary>
  60. public Constraint False
  61. {
  62. get { return Resolve(new EqualConstraint(false)); }
  63. }
  64. /// <summary>
  65. /// Resolves the chain of constraints using
  66. /// Is.NaN as base.
  67. /// </summary>
  68. public Constraint NaN
  69. {
  70. get { return Resolve(new EqualConstraint(double.NaN)); }
  71. }
  72. /// <summary>
  73. /// Resolves the chain of constraints using
  74. /// Is.Empty as base.
  75. /// </summary>
  76. public Constraint Empty
  77. {
  78. get { return Resolve(new EmptyConstraint()); }
  79. }
  80. /// <summary>
  81. /// Resolves the chain of constraints using
  82. /// Is.Unique as base.
  83. /// </summary>
  84. public Constraint Unique
  85. {
  86. get { return Resolve(new UniqueItemsConstraint()); }
  87. }
  88. #endregion
  89. #region Constraints with an expected value
  90. #region Equality and Identity
  91. /// <summary>
  92. /// Resolves the chain of constraints using an
  93. /// EqualConstraint as base.
  94. /// </summary>
  95. public Constraint EqualTo(object expected)
  96. {
  97. return Resolve(new EqualConstraint(expected));
  98. }
  99. /// <summary>
  100. /// Resolves the chain of constraints using a
  101. /// SameAsConstraint as base.
  102. /// </summary>
  103. public Constraint SameAs(object expected)
  104. {
  105. return Resolve(new SameAsConstraint(expected));
  106. }
  107. #endregion
  108. #region Comparison Constraints
  109. /// <summary>
  110. /// Resolves the chain of constraints using a
  111. /// LessThanConstraint as base.
  112. /// </summary>
  113. public Constraint LessThan(IComparable expected)
  114. {
  115. return Resolve(new LessThanConstraint(expected));
  116. }
  117. /// <summary>
  118. /// Resolves the chain of constraints using a
  119. /// GreaterThanConstraint as base.
  120. /// </summary>
  121. public Constraint GreaterThan(IComparable expected)
  122. {
  123. return Resolve(new GreaterThanConstraint(expected));
  124. }
  125. /// <summary>
  126. /// Resolves the chain of constraints using a
  127. /// LessThanOrEqualConstraint as base.
  128. /// </summary>
  129. public Constraint LessThanOrEqualTo(IComparable expected)
  130. {
  131. return Resolve(new LessThanOrEqualConstraint(expected));
  132. }
  133. /// <summary>
  134. /// Resolves the chain of constraints using a
  135. /// LessThanOrEqualConstraint as base.
  136. /// </summary>
  137. public Constraint AtMost(IComparable expected)
  138. {
  139. return Resolve(new LessThanOrEqualConstraint(expected));
  140. }
  141. /// <summary>
  142. /// Resolves the chain of constraints using a
  143. /// GreaterThanOrEqualConstraint as base.
  144. /// </summary>
  145. public Constraint GreaterThanOrEqualTo(IComparable expected)
  146. {
  147. return Resolve(new GreaterThanOrEqualConstraint(expected));
  148. }
  149. /// <summary>
  150. /// Resolves the chain of constraints using a
  151. /// GreaterThanOrEqualConstraint as base.
  152. /// </summary>
  153. public Constraint AtLeast(IComparable expected)
  154. {
  155. return Resolve(new GreaterThanOrEqualConstraint(expected));
  156. }
  157. #endregion
  158. #region Type Constraints
  159. /// <summary>
  160. /// Resolves the chain of constraints using an
  161. /// ExactTypeConstraint as base.
  162. /// </summary>
  163. public Constraint TypeOf(Type expectedType)
  164. {
  165. return Resolve(new ExactTypeConstraint(expectedType));
  166. }
  167. /// <summary>
  168. /// Resolves the chain of constraints using an
  169. /// InstanceOfTypeConstraint as base.
  170. /// </summary>
  171. public Constraint InstanceOfType(Type expectedType)
  172. {
  173. return Resolve(new InstanceOfTypeConstraint(expectedType));
  174. }
  175. /// <summary>
  176. /// Resolves the chain of constraints using an
  177. /// AssignableFromConstraint as base.
  178. /// </summary>
  179. public Constraint AssignableFrom(Type expectedType)
  180. {
  181. return Resolve(new AssignableFromConstraint(expectedType));
  182. }
  183. #endregion
  184. #region Containing Constraint
  185. /// <summary>
  186. /// Resolves the chain of constraints using a
  187. /// ContainsConstraint as base. This constraint
  188. /// will, in turn, make use of the appropriate
  189. /// second-level constraint, depending on the
  190. /// type of the actual argument.
  191. /// </summary>
  192. public Constraint Contains(object expected)
  193. {
  194. return Resolve( new ContainsConstraint(expected) );
  195. }
  196. /// <summary>
  197. /// Resolves the chain of constraints using a
  198. /// CollectionContainsConstraint as base.
  199. /// </summary>
  200. /// <param name="expected">The expected object</param>
  201. public Constraint Member( object expected )
  202. {
  203. return Resolve( new CollectionContainsConstraint( expected ) );
  204. }
  205. #endregion
  206. #region String Constraints
  207. /// <summary>
  208. /// Resolves the chain of constraints using a
  209. /// StartsWithConstraint as base.
  210. /// </summary>
  211. public Constraint StartsWith(string substring)
  212. {
  213. return Resolve( new StartsWithConstraint(substring) );
  214. }
  215. /// <summary>
  216. /// Resolves the chain of constraints using a
  217. /// StringEndingConstraint as base.
  218. /// </summary>
  219. public Constraint EndsWith(string substring)
  220. {
  221. return Resolve( new EndsWithConstraint(substring) );
  222. }
  223. /// <summary>
  224. /// Resolves the chain of constraints using a
  225. /// StringMatchingConstraint as base.
  226. /// </summary>
  227. public Constraint Matches(string pattern)
  228. {
  229. return Resolve(new RegexConstraint(pattern));
  230. }
  231. #endregion
  232. #region Collection Constraints
  233. /// <summary>
  234. /// Resolves the chain of constraints using a
  235. /// CollectionEquivalentConstraint as base.
  236. /// </summary>
  237. public Constraint EquivalentTo(ICollection expected)
  238. {
  239. return Resolve( new CollectionEquivalentConstraint(expected) );
  240. }
  241. /// <summary>
  242. /// Resolves the chain of constraints using a
  243. /// CollectionContainingConstraint as base.
  244. /// </summary>
  245. public Constraint CollectionContaining(object expected)
  246. {
  247. return Resolve( new CollectionContainsConstraint(expected) );
  248. }
  249. /// <summary>
  250. /// Resolves the chain of constraints using a
  251. /// CollectionSubsetConstraint as base.
  252. /// </summary>
  253. public Constraint SubsetOf(ICollection expected)
  254. {
  255. return Resolve(new CollectionSubsetConstraint(expected));
  256. }
  257. #endregion
  258. #region Property Constraints
  259. /// <summary>
  260. /// Resolves the chain of constraints using a
  261. /// PropertyConstraint as base
  262. /// </summary>
  263. public Constraint Property( string name, object expected )
  264. {
  265. return Resolve( new PropertyConstraint( name, new EqualConstraint( expected ) ) );
  266. }
  267. /// <summary>
  268. /// Resolves the chain of constraints using a
  269. /// PropertyCOnstraint on Length as base
  270. /// </summary>
  271. /// <param name="length"></param>
  272. /// <returns></returns>
  273. public Constraint Length(int length)
  274. {
  275. return Property("Length", length);
  276. }
  277. /// <summary>
  278. /// Resolves the chain of constraints using a
  279. /// PropertyCOnstraint on Length as base
  280. /// </summary>
  281. /// <param name="count"></param>
  282. /// <returns></returns>
  283. public Constraint Count(int count)
  284. {
  285. return Property("Count", count);
  286. }
  287. #endregion
  288. #endregion
  289. #region Prefix Operators
  290. /// <summary>
  291. /// Modifies the ConstraintBuilder by pushing a Not operator on the stack.
  292. /// </summary>
  293. public ConstraintBuilder Not
  294. {
  295. get
  296. {
  297. ops.Push(Op.Not);
  298. return this;
  299. }
  300. }
  301. /// <summary>
  302. /// Modifies the ConstraintBuilder by pushing a Not operator on the stack.
  303. /// </summary>
  304. public ConstraintBuilder No
  305. {
  306. get
  307. {
  308. ops.Push(Op.Not);
  309. return this;
  310. }
  311. }
  312. /// <summary>
  313. /// Modifies the ConstraintBuilder by pushing an All operator on the stack.
  314. /// </summary>
  315. public ConstraintBuilder All
  316. {
  317. get
  318. {
  319. ops.Push(Op.All);
  320. return this;
  321. }
  322. }
  323. /// <summary>
  324. /// Modifies the ConstraintBuilder by pushing a Some operator on the stack.
  325. /// </summary>
  326. public ConstraintBuilder Some
  327. {
  328. get
  329. {
  330. ops.Push(Op.Some);
  331. return this;
  332. }
  333. }
  334. /// <summary>
  335. /// Modifies the constraint builder by pushing All and Not operators on the stack
  336. /// </summary>
  337. public ConstraintBuilder None
  338. {
  339. get
  340. {
  341. ops.Push(Op.None);
  342. return this;
  343. }
  344. }
  345. /// <summary>
  346. /// Modifies the ConstraintBuilder by pushing a Prop operator on the
  347. /// ops stack and the name of the property on the opnds stack.
  348. /// </summary>
  349. /// <param name="name"></param>
  350. /// <returns></returns>
  351. public ConstraintBuilder Property(string name)
  352. {
  353. ops.Push( Op.Prop );
  354. opnds.Push( name );
  355. return this;
  356. }
  357. #endregion
  358. #region Helper Methods
  359. /// <summary>
  360. /// Resolve a constraint that has been recognized by applying
  361. /// any pending operators and returning the resulting Constraint.
  362. /// </summary>
  363. /// <returns>A constraint that incorporates all pending operators</returns>
  364. private Constraint Resolve(Constraint constraint)
  365. {
  366. while (ops.Count > 0)
  367. switch ((Op)ops.Pop())
  368. {
  369. case Op.Not:
  370. constraint = new NotConstraint(constraint);
  371. break;
  372. case Op.All:
  373. constraint = new AllItemsConstraint(constraint);
  374. break;
  375. case Op.Some:
  376. constraint = new SomeItemsConstraint(constraint);
  377. break;
  378. case Op.None:
  379. constraint = new NoItemConstraint(constraint);
  380. break;
  381. case Op.Prop:
  382. constraint = new PropertyConstraint( (string)opnds.Pop(), constraint );
  383. break;
  384. }
  385. return constraint;
  386. }
  387. private Constraint Resolve()
  388. {
  389. return Resolve(null);
  390. }
  391. #endregion
  392. }
  393. }