/
MustVerb.scala
231 lines (220 loc) · 9.23 KB
/
MustVerb.scala
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
/*
* Copyright 2001-2013 Artima, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.scalatest.verbs
import org.scalactic._
/**
* Provides an implicit conversion that adds <code>must</code> methods to <code>String</code>
* to support the syntax of <code>FlatSpec</code>, <code>WordSpec</code>, <code>fixture.FlatSpec</code>,
* and <code>fixture.WordSpec</code>.
*
* <p>
* For example, this trait enables syntax such as the following test registration in <code>FlatSpec</code>
* and <code>fixture.FlatSpec</code>:
* </p>
*
* <pre class="stHighlighted">
* <span class="stQuotedString">"A Stack (when empty)"</span> must <span class="stQuotedString">"be empty"</span> in { ... }
* ^
* </pre>
*
* <p>
* It also enables syntax such as the following shared test registration in <code>FlatSpec</code>
* and <code>fixture.FlatSpec</code>:
* </p>
*
* <pre class="stHighlighted">
* <span class="stQuotedString">"A Stack (with one item)"</span> must behave like nonEmptyStack(stackWithOneItem, lastValuePushed)
* ^
* </pre>
*
* <p>
* In addition, it supports the registration of subject descriptions in <code>WordSpec</code>
* and <code>fixture.WordSpec</code>, such as:
* </p>
*
* <pre class="stHighlighted">
* <span class="stQuotedString">"A Stack (when empty)"</span> must { ...
* ^
* </pre>
*
* <p>
* And finally, it also supportds the registration of subject descriptions with after words
* in <code>WordSpec</code> and <code>fixture.WordSpec</code>. For example:
* </p>
*
* <pre class="stHighlighted">
* <span class="stReserved">def</span> provide = afterWord(<span class="stQuotedString">"provide"</span>)
* <br/><span class="stQuotedString">"The ScalaTest Matchers DSL"</span> must provide {
* ^
* </pre>
*
* <p>
* The reason this implicit conversion is provided in a separate trait, instead of being provided
* directly in <code>FlatSpec</code>, <code>WordSpec</code>, <code>fixture.FlatSpec</code>, and
* <code>fixture.WordSpec</code>, is because an implicit conversion provided directly would conflict
* with the implicit conversion that provides <code>must</code> methods on <code>String</code>
* in the <code>MustMatchers</code> trait. By contrast, there is no conflict with
* the separate <code>MustVerb</code> trait approach, because:
* </p>
*
* <ol>
* <li><code>FlatSpec</code>, <code>WordSpec</code>, <code>fixture.FlatSpec</code>, and <code>fixture.WordSpec</code>
* mix in <code>MustVerb</code> directly, and</li>
* <li><code>MustMatchers</code> extends <code>MustVerb</code>, overriding the
* <code>convertToStringMustWrapper</code> implicit conversion function.</li>
* </ol>
*
* <p>
* So whether or not
* a <code>FlatSpec</code>, <code>WordSpec</code>, <code>fixture.FlatSpec</code>, or <code>fixture.WordSpec</code>
* mixes in <code>MustMatchers</code>, there will only be one
* implicit conversion in scope that adds <code>must</code> methods to <code>String</code>s.
* </p>
*
* </p>
* Also, because the class of the result of the overriding <code>convertToStringMustWrapper</code>
* implicit conversion method provided in <code>MustMatchers</code> extends this trait's
* <code>StringMustWrapperForVerb</code> class, the four uses of <code>must</code> provided here
* are still available. These four <code>must</code> are in fact available to any class
* that mixes in <code>MustMatchers</code>, but each takes an implicit parameter that is provided
* only in <code>FlatSpec</code> and <code>fixture.FlatSpec</code>, or <code>WordSpec</code> and
* <code>fixture.WordSpec</code>.
* </p>
*
* @author Bill Venners
*/
trait MustVerb {
/**
* This class supports the syntax of <code>FlatSpec</code>, <code>WordSpec</code>, <code>fixture.FlatSpec</code>,
* and <code>fixture.WordSpec</code>.
*
* <p>
* This class is used in conjunction with an implicit conversion to enable <code>must</code> methods to
* be invoked on <code>String</code>s.
* </p>
*
* @author Bill Venners
*/
trait StringMustWrapperForVerb {
val leftSideString: String
val pos: source.Position
/**
* Supports test registration in <code>FlatSpec</code> and <code>fixture.FlatSpec</code>.
*
* <p>
* For example, this method enables syntax such as the following in <code>FlatSpec</code>
* and <code>fixture.FlatSpec</code>:
* </p>
*
* <pre class="stHighlighted">
* <span class="stQuotedString">"A Stack (when empty)"</span> must <span class="stQuotedString">"be empty"</span> in { ... }
* ^
* </pre>
*
* <p>
* <code>FlatSpec</code> passes in a function via the implicit parameter that takes
* three strings and results in a <code>ResultOfStringPassedToVerb</code>. This method
* simply invokes this function, passing in leftSideString, the verb string
* <code>"must"</code>, and right, and returns the result.
* </p>
*/
def must(right: String)(implicit svsi: StringVerbStringInvocation): ResultOfStringPassedToVerb = {
svsi(leftSideString, "must", right, pos)
}
/**
* Supports shared test registration in <code>FlatSpec</code> and <code>fixture.FlatSpec</code>.
*
* <p>
* For example, this method enables syntax such as the following in <code>FlatSpec</code>
* and <code>fixture.FlatSpec</code>:
* </p>
*
* <pre class="stHighlighted">
* <span class="stQuotedString">"A Stack (with one item)"</span> must behave like nonEmptyStack(stackWithOneItem, lastValuePushed)
* ^
* </pre>
*
* <p>
* <code>FlatSpec</code> and <code>fixture.FlatSpec</code> passes in a function via the implicit parameter that takes
* a string and results in a <code>BehaveWord</code>. This method
* simply invokes this function, passing in leftSideString, and returns the result.
* </p>
*/
def must(right: BehaveWord)(implicit svbli: StringVerbBehaveLikeInvocation): BehaveWord = {
svbli(leftSideString, pos)
}
/**
* Supports the registration of subject descriptions in <code>WordSpec</code>
* and <code>fixture.WordSpec</code>.
*
* <p>
* For example, this method enables syntax such as the following in <code>WordSpec</code>
* and <code>fixture.WordSpec</code>:
* </p>
*
* <pre class="stHighlighted">
* <span class="stQuotedString">"A Stack (when empty)"</span> must { ...
* ^
* </pre>
*
* <p>
* <code>WordSpec</code> passes in a function via the implicit parameter of type <code>StringVerbBlockRegistration</code>,
* a function that takes two strings and a no-arg function and results in <code>Unit</code>. This method
* simply invokes this function, passing in leftSideString, the verb string
* <code>"must"</code>, and the right by-name parameter transformed into a
* no-arg function.
* </p>
*/
def must(right: => Unit)(implicit fun: StringVerbBlockRegistration): Unit = {
fun(leftSideString, "must", pos, () => right)
}
/**
* Supports the registration of subject descriptions with after words
* in <code>WordSpec</code> and <code>fixture.WordSpec</code>.
*
* <p>
* For example, this method enables syntax such as the following in <code>WordSpec</code>
* and <code>fixture.WordSpec</code>:
* </p>
*
* <pre class="stHighlighted">
* <span class="stReserved">def</span> provide = afterWord(<span class="stQuotedString">"provide"</span>)
* <br/><span class="stQuotedString">"The ScalaTest Matchers DSL"</span> must provide {
* ^
* </pre>
*
* <p>
* <code>WordSpec</code> passes in a function via the implicit parameter that takes
* two strings and a <code>ResultOfAfterWordApplication</code> and results in <code>Unit</code>. This method
* simply invokes this function, passing in leftSideString, the verb string
* <code>"must"</code>, and the <code>ResultOfAfterWordApplication</code> passed to <code>must</code>.
* </p>
*/
def must(resultOfAfterWordApplication: ResultOfAfterWordApplication)(implicit swawr: SubjectWithAfterWordRegistration): Unit = {
swawr(leftSideString, "must", resultOfAfterWordApplication, pos)
}
}
import scala.language.implicitConversions
/**
* Implicitly converts an object of type <code>String</code> to a <code>StringMustWrapper</code>,
* to enable <code>must</code> methods to be invokable on that object.
*/
implicit def convertToStringMustWrapperForVerb(o: String)(implicit position: source.Position): StringMustWrapperForVerb =
new StringMustWrapperForVerb {
val leftSideString = o.trim
val pos = position
}
}