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