ae 1.0.0 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/MANIFEST +3 -1
- data/{README → README.rdoc} +40 -17
- data/demo/01_overview.rdoc +25 -30
- data/demo/03_assert.rdoc +55 -22
- data/demo/04_subjunctive.rdoc +32 -59
- data/demo/05_expect.qed +83 -0
- data/doc/qedoc/index.html +119 -113
- data/lib/ae.rb +1 -0
- data/lib/ae/assertor.rb +14 -0
- data/lib/ae/core_ext.rb +2 -2
- data/lib/ae/expect.rb +124 -0
- data/meta/homepage +1 -1
- data/meta/version +1 -1
- metadata +8 -8
data/MANIFEST
CHANGED
@@ -4,6 +4,7 @@ demo/01_overview.rdoc
|
|
4
4
|
demo/02_assertion.rdoc
|
5
5
|
demo/03_assert.rdoc
|
6
6
|
demo/04_subjunctive.rdoc
|
7
|
+
demo/05_expect.qed
|
7
8
|
doc/qedoc
|
8
9
|
doc/qedoc/index.html
|
9
10
|
doc/qedoc/jquery.js
|
@@ -13,6 +14,7 @@ lib/ae/assert.rb
|
|
13
14
|
lib/ae/assertion.rb
|
14
15
|
lib/ae/assertor.rb
|
15
16
|
lib/ae/core_ext.rb
|
17
|
+
lib/ae/expect.rb
|
16
18
|
lib/ae/subjunctive
|
17
19
|
lib/ae/subjunctive/must.rb
|
18
20
|
lib/ae/subjunctive/should.rb
|
@@ -35,5 +37,5 @@ meta/title
|
|
35
37
|
meta/version
|
36
38
|
test
|
37
39
|
LICENSE
|
38
|
-
README
|
40
|
+
README.rdoc
|
39
41
|
HISTORY
|
data/{README → README.rdoc}
RENAMED
@@ -1,11 +1,11 @@
|
|
1
1
|
= A.E. -- Assertive Expressive
|
2
2
|
|
3
|
-
* http://
|
3
|
+
* http://proutils.rubyforge.org/ae/
|
4
4
|
|
5
5
|
|
6
6
|
== DESCRIPTION
|
7
7
|
|
8
|
-
|
8
|
+
Assertive Expressive (A.E.) is an assertions framework
|
9
9
|
intended for reuse by any TDD, BDD or similar system.
|
10
10
|
|
11
11
|
|
@@ -14,7 +14,7 @@ intended for reuse by any TDD, BDD or similar system.
|
|
14
14
|
* Clear, simple and concise syntax.
|
15
15
|
* Uses higher-order functions and fluid notation.
|
16
16
|
* Reusable core extensions ease assertion construction.
|
17
|
-
* Core extensions are
|
17
|
+
* Core extensions are standardized around Ruby Facets.
|
18
18
|
* Facets is an optional dependency; extensions are built-in.
|
19
19
|
* Easily extensible allowing for alternate notations.
|
20
20
|
* Eats it's own dog food.
|
@@ -38,12 +38,11 @@ the result of which is likewise verified.
|
|
38
38
|
|
39
39
|
assert{true}
|
40
40
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
like:
|
41
|
+
However, the true power the AE's +assert+ method, lies in it's use
|
42
|
+
without argument or block. In this case, it returns an instance of
|
43
|
+
+Assertor+. An +Assertor+ is an <i>Assertions Functor</i> --also
|
44
|
+
called a Higher-Order Function, it is a function that operates on
|
45
|
+
another function. With it, we can make assertions like:
|
47
46
|
|
48
47
|
x.assert == y
|
49
48
|
|
@@ -53,22 +52,46 @@ like:
|
|
53
52
|
...
|
54
53
|
end
|
55
54
|
|
56
|
-
And so forth.
|
57
|
-
|
55
|
+
And so forth. Any method can be used in conjunction with +assert+
|
56
|
+
to make an assertion. Eg.
|
57
|
+
|
58
|
+
class String
|
59
|
+
def daffy?
|
60
|
+
/daffy/i =~ self
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
"Daffy Duck".assert.daffy?
|
65
|
+
|
66
|
+
Please have a look at the QEDocs and RDocs to learn more.
|
58
67
|
|
59
68
|
|
60
69
|
== HOW TO INSTALL
|
61
70
|
|
62
|
-
|
71
|
+
=== Gem Installs
|
72
|
+
|
73
|
+
AE releases it's gems via Gemcutter. If you don't have Gemcutter
|
74
|
+
installed do:
|
75
|
+
|
76
|
+
$ gem install gemcutter
|
77
|
+
$ gem tumble
|
78
|
+
|
79
|
+
Then you can install AE with:
|
63
80
|
|
64
81
|
gem install ae
|
65
82
|
|
66
|
-
|
67
|
-
|
83
|
+
=== Site Installs
|
84
|
+
|
85
|
+
Local installation requires Setup.rb.
|
86
|
+
|
87
|
+
gem install setup
|
88
|
+
|
89
|
+
Then download the tarball package from GitHub (under pack/ directory)
|
90
|
+
and do:
|
68
91
|
|
69
|
-
tar -xvzf ae-1.0.0.tgz
|
70
|
-
cd ae-1.0.0.tgz
|
71
|
-
sudo setup.rb all
|
92
|
+
$ tar -xvzf ae-1.0.0.tgz
|
93
|
+
$ cd ae-1.0.0.tgz
|
94
|
+
$ sudo setup.rb all
|
72
95
|
|
73
96
|
Windows users use 'ruby setup.rb all'.
|
74
97
|
|
data/demo/01_overview.rdoc
CHANGED
@@ -14,19 +14,16 @@ Requiring the AE library.
|
|
14
14
|
require 'ae'
|
15
15
|
|
16
16
|
Loads two classes, +Assertion+ and +Assertor+, the Kernel
|
17
|
-
method +assert+ and it's ancillaries
|
17
|
+
method +assert+ and it's ancillaries <tt>assert!</tt> and +refute+
|
18
18
|
and a set of core extensions that make writing certain types
|
19
19
|
of assertions easier.
|
20
20
|
|
21
21
|
|
22
22
|
== Assertion and Assertor Classes
|
23
23
|
|
24
|
-
The +Assertion+ class is a subclass of +Exception+. It is the
|
25
|
-
error raised when an assertion fails.
|
26
|
-
|
27
24
|
The +Assertion+ class is at the heart of AE. All other AE
|
28
|
-
|
29
|
-
of Exception. When an assertion is made
|
25
|
+
methods depend on it. The +Assertion+ class is a subclass
|
26
|
+
of Exception. When an assertion is made and fails, it is
|
30
27
|
an instance of Assertion that is raised.
|
31
28
|
|
32
29
|
Assertion.assert.raised? do
|
@@ -35,33 +32,31 @@ an instance of Assertion that is raised.
|
|
35
32
|
end
|
36
33
|
|
37
34
|
Like any raised exception, the last Assertion message is available
|
38
|
-
via
|
35
|
+
via <tt>$!</tt>.
|
39
36
|
|
40
|
-
(FYI, in Test::Unit the equivalent class was called
|
41
|
-
AE has adopted the shortened term for my fingers sake ;) Also, recently
|
42
|
-
it was discoverd to be the choosen term in minitest --proving good ideas
|
43
|
-
find their way to the top.)
|
37
|
+
(FYI, in Test::Unit the equivalent class was called +AssertionFailedError+.)
|
44
38
|
|
45
|
-
Assertions
|
46
|
-
behavior specifications. Rather they are used to create
|
39
|
+
Assertions themselves are not generally used in creating tests or
|
40
|
+
behavior specifications. Rather they are used to create additional
|
47
41
|
types of assertion methods.
|
48
42
|
|
49
|
-
As mentioned above the +Assertor+ class is a type of
|
50
|
-
or
|
43
|
+
As mentioned above the +Assertor+ class is a type of Higher-Order
|
44
|
+
function, or Functor, which intercedes with a normal message
|
51
45
|
invocation to monitor for failed conditions, upon which is raises
|
52
46
|
Assertion exceptions.
|
53
47
|
|
54
48
|
|
55
49
|
== Assertion Methods
|
56
50
|
|
57
|
-
The three methods, +assert+,
|
58
|
-
an Assertor instance when used fluidly, i.e. magic-dot
|
59
|
-
higher-order notation, functor notation, whatever you
|
60
|
-
to call it.
|
51
|
+
The three methods, +assert+, <tt>assert!</tt> and +refute+ all
|
52
|
+
return an Assertor instance when used fluidly, i.e. magic-dot
|
53
|
+
notation, higher-order notation, functor notation, whatever you
|
54
|
+
prefer to call it.
|
61
55
|
|
62
56
|
assert(Assertor === assert)
|
63
57
|
|
64
|
-
|
58
|
+
Through the use of +method_missing+, the Assertor allows us to write
|
59
|
+
statements like:
|
65
60
|
|
66
61
|
1.assert == 1
|
67
62
|
|
@@ -72,20 +67,20 @@ is raised.
|
|
72
67
|
1.assert == 2
|
73
68
|
end
|
74
69
|
|
75
|
-
The methods
|
76
|
-
they purport the negative condition. Patterned after Ruby's
|
77
|
-
use of
|
78
|
-
While +refute+ exists for the sake of those
|
79
|
-
a
|
70
|
+
The methods <tt>assert!</tt> and +refute+ are just like +assert+
|
71
|
+
expect they purport the negative condition. Patterned after Ruby's
|
72
|
+
own use of "<tt>!</tt>" as meaning +not+, <tt>assert!</tt> should be
|
73
|
+
read "assert not". While +refute+ exists for the sake of those who
|
74
|
+
find the use of a bang method for this purpose unsuited to them.
|
80
75
|
|
81
76
|
|
82
|
-
== How It
|
77
|
+
== How It Works
|
83
78
|
|
84
79
|
An Assertor essentially sits in wait for a method call (via
|
85
|
-
method_missing). When that happens it applies the method to
|
86
|
-
|
87
|
-
|
88
|
-
|
80
|
+
method_missing). When that happens it applies the method to the
|
81
|
+
original receiver, but wrapped in a clause that raises an
|
82
|
+
Assertion should the statement fail. If we wanted to be
|
83
|
+
pedantic, we could write our assertions like:
|
89
84
|
|
90
85
|
raise Assertion.new("1 != 1") unless 1 == 1
|
91
86
|
|
data/demo/03_assert.rdoc
CHANGED
@@ -2,10 +2,10 @@
|
|
2
2
|
|
3
3
|
== Compatible with Test::Unit
|
4
4
|
|
5
|
-
The
|
6
|
-
with the same method in
|
5
|
+
The +assert+ method is designed to be backward compatible
|
6
|
+
with the same method in <tt>Test::Unit</tt>.
|
7
7
|
|
8
|
-
Using an argument,
|
8
|
+
Using an argument, +assert+ will check that an argument evaluates
|
9
9
|
to true. Optionally one can send along a meaningful message should
|
10
10
|
the assertion fail.
|
11
11
|
|
@@ -18,7 +18,7 @@ the assertion fail.
|
|
18
18
|
|
19
19
|
== Assert with a Block
|
20
20
|
|
21
|
-
In addition
|
21
|
+
In addition +assert+ has been extended to accept a block. Like the case of the
|
22
22
|
argument, the block is expected to return something that evaluates as true.
|
23
23
|
|
24
24
|
assert do
|
@@ -42,18 +42,18 @@ into the block as a block argument.
|
|
42
42
|
|
43
43
|
== Antonyms for Assert
|
44
44
|
|
45
|
-
We can state the opposite assertion using
|
45
|
+
We can state the opposite assertion using <tt>assert!</tt>.
|
46
46
|
|
47
47
|
10.assert! == 9
|
48
48
|
|
49
|
-
Or, because some people do not like the use of a bang method,
|
49
|
+
Or, because some people do not like the use of a bang method, +refute+.
|
50
50
|
|
51
51
|
10.refute == 9
|
52
52
|
|
53
|
-
These terms can be used just as
|
53
|
+
These terms can be used just as +assert+ is used in all examples,
|
54
54
|
but with the opposite inference.
|
55
55
|
|
56
|
-
Another way to get the opposite inference, is to use
|
56
|
+
Another way to get the opposite inference, is to use +not+.
|
57
57
|
|
58
58
|
10.assert.not == 9
|
59
59
|
|
@@ -65,11 +65,11 @@ Rather then the general form:
|
|
65
65
|
x = 10
|
66
66
|
x.assert.object_id == x.object_id
|
67
67
|
|
68
|
-
We can use Ruby's own
|
68
|
+
We can use Ruby's own <tt>equal?</tt> method.
|
69
69
|
|
70
70
|
x.assert.equal?(x)
|
71
71
|
|
72
|
-
AE provides
|
72
|
+
AE provides <tt>identical?</tt> method as an alternative
|
73
73
|
to make it a bit more clear.
|
74
74
|
|
75
75
|
x.assert.identical?(x)
|
@@ -77,10 +77,10 @@ to make it a bit more clear.
|
|
77
77
|
|
78
78
|
== Equality Assertions
|
79
79
|
|
80
|
-
The most common assertion is that of value equality (
|
80
|
+
The most common assertion is that of value equality (<tt>==</tt>),
|
81
81
|
as we have seen throughout this document. But other forms of
|
82
82
|
equality can be verified as easily. We have already mentioned
|
83
|
-
identity. In addition there is
|
83
|
+
identity. In addition there is <i>type equality</i>.
|
84
84
|
|
85
85
|
17.assert.eql? 17
|
86
86
|
|
@@ -88,7 +88,7 @@ identity. In addition there is *Type Equality*.
|
|
88
88
|
17.assert.eql? 17.0
|
89
89
|
end
|
90
90
|
|
91
|
-
And there is
|
91
|
+
And there is <i>case equality</i>.
|
92
92
|
|
93
93
|
Numeric.assert === 3
|
94
94
|
|
@@ -98,10 +98,10 @@ And there is *Case Equality*.
|
|
98
98
|
Because operators can not take blocks, and at times blocks can
|
99
99
|
be convenient means of supplying a value to an assertion,
|
100
100
|
AE has defined alternate renditions of the equality methods.
|
101
|
-
For equal? and eql?, the method
|
102
|
-
can take a block
|
101
|
+
For equal? and eql?, the method names are the same, they simply
|
102
|
+
can take a block in place of an argument if need be.
|
103
103
|
|
104
|
-
For
|
104
|
+
For <i>value equality</i> (<tt>==</tt>), the method is called <tt>eq?</tt>.
|
105
105
|
|
106
106
|
10.assert.eq? do
|
107
107
|
10.0
|
@@ -115,7 +115,7 @@ And should it fail...
|
|
115
115
|
end
|
116
116
|
end
|
117
117
|
|
118
|
-
For
|
118
|
+
For <i>case equality</i> (<tt>===</tt>), it is <tt>case?</tt>.
|
119
119
|
|
120
120
|
Numeric.assert.case? do
|
121
121
|
"3".to_i
|
@@ -142,7 +142,7 @@ in the document to verify assertion failures.
|
|
142
142
|
|
143
143
|
While testing or specifying the internal state of an object is
|
144
144
|
generally considered poor form, there are times when it is
|
145
|
-
|
145
|
+
necessary. Assert combined with +instance_eval+ makes it easy too.
|
146
146
|
|
147
147
|
class X
|
148
148
|
attr :a
|
@@ -158,14 +158,14 @@ necessay. Assert combined with +instance_eval+ makes it easy too.
|
|
158
158
|
|
159
159
|
== Catch/Try Assertions
|
160
160
|
|
161
|
-
Catch/Try throws can be tested via
|
161
|
+
Catch/Try throws can be tested via <tt>Symbol#thrown?</tt>.
|
162
162
|
|
163
163
|
:hookme.assert.thrown? do
|
164
164
|
throw :hookme
|
165
165
|
end
|
166
166
|
|
167
167
|
Alternatively, a lambda containing the potential throw
|
168
|
-
can be the receiver using
|
168
|
+
can be the receiver using <tt>throws?</tt>.
|
169
169
|
|
170
170
|
hook = lambda{ throw :hookme }
|
171
171
|
|
@@ -191,7 +191,7 @@ Ruby already provides the #nil? method.
|
|
191
191
|
|
192
192
|
nil.assert.nil?
|
193
193
|
|
194
|
-
AE
|
194
|
+
AE adds <tt>true?</tt> and <tt>false?</tt> which acts accordingly.
|
195
195
|
|
196
196
|
true.assert.true?
|
197
197
|
false.assert.false?
|
@@ -226,5 +226,38 @@ create reusable assertions.
|
|
226
226
|
|
227
227
|
"abracarba".assert palindrome
|
228
228
|
|
229
|
-
|
229
|
+
|
230
|
+
== Verifying Object State
|
231
|
+
|
232
|
+
NOTE: <i>This functionality is not currently supported, but is being
|
233
|
+
considered for a future version.</i>
|
234
|
+
|
235
|
+
If no block parameter is designated and the receiver differs from +self+
|
236
|
+
in scope of the given block, then the block is evaluated in the scope of
|
237
|
+
the receiver via +instance_eval+. This can be also be used to verify the
|
238
|
+
state of an object.
|
239
|
+
|
240
|
+
class X
|
241
|
+
attr :a
|
242
|
+
def initialize(a); @a = a; end
|
243
|
+
end
|
244
|
+
|
245
|
+
x = X.new(4)
|
246
|
+
|
247
|
+
x.must do
|
248
|
+
4 == @a
|
249
|
+
end
|
250
|
+
|
251
|
+
And should it fail...
|
252
|
+
|
253
|
+
Assertion.assert.raised? do
|
254
|
+
x.must do
|
255
|
+
5 == @a
|
256
|
+
end
|
257
|
+
end
|
258
|
+
|
259
|
+
For some this might be considered poor form, i.e. to test underlying
|
260
|
+
implementation. You will get no argument here. It should be used
|
261
|
+
thoughtfully, but I would not bet against there being occasions
|
262
|
+
when such validations might be handy.
|
230
263
|
|
data/demo/04_subjunctive.rdoc
CHANGED
@@ -1,51 +1,50 @@
|
|
1
1
|
= Subjunctives
|
2
2
|
|
3
|
-
Okay. I can hear the BDDers rumbling, "where's the
|
4
|
-
|
3
|
+
Okay. I can hear the BDDers rumbling, "where's the *should?*"
|
4
|
+
AE has nothing against "should", but there are different
|
5
5
|
approaches for utilizing should nomenclature in specifications,
|
6
6
|
and AE wants to be open to these techniques. One of which
|
7
|
-
|
7
|
+
is how Shoulda (http://shoulda.rubyforge.org) utilizes
|
8
8
|
+should+ in a way analogous to RSpec's use of +it+.
|
9
9
|
|
10
|
-
Even so, AE provides a an optional mixin called Subjunctive which
|
11
|
-
can be used to create assertor methods
|
12
|
-
terms such as +should
|
10
|
+
Even so, AE provides a an optional mixin called +Subjunctive+ which
|
11
|
+
can be used to create assertor methods with English subjunctive
|
12
|
+
terms, such as +should+, or +must+, +shall+ and +will+.
|
13
13
|
To load this library use:
|
14
14
|
|
15
15
|
require 'ae/subjunctive'
|
16
16
|
|
17
|
-
Then all that is required it to define
|
17
|
+
Then all that is required it to define a subjunctive method for all
|
18
18
|
objects. For example:
|
19
19
|
|
20
20
|
def will(*args, &block)
|
21
21
|
Assertor.new(self, :backtrace=>caller).be(*args,&block)
|
22
22
|
end
|
23
23
|
|
24
|
-
It's that easy. Because of their
|
25
|
-
+should+ and +must+ as optional add-ons.
|
24
|
+
It's that easy. Because of their commonality AE provides two such terms,
|
25
|
+
+should+ and +must+ as optional add-ons out-of-the-box.
|
26
26
|
|
27
27
|
require 'ae/subjunctive/should'
|
28
28
|
require 'ae/subjunctive/must'
|
29
29
|
|
30
30
|
We will use these two methods interchangeable for the rest of this
|
31
31
|
demonstration, but to be clear they both work exactly the same way,
|
32
|
-
and almost exactly like
|
32
|
+
and almost exactly like +assert+.
|
33
33
|
|
34
|
-
Keep in mind, AE "conical" functionality does not entail subjunctive
|
35
|
-
forms
|
36
|
-
|
37
|
-
or need to support these nomenclatures.
|
34
|
+
Keep in mind, AE "conical" functionality does not entail the subjunctive
|
35
|
+
forms. These are simply options you can load via your <tt>test_helper.rb</tt>,
|
36
|
+
or similar script, if you prefer these nomenclatures.
|
38
37
|
|
39
38
|
|
40
39
|
== Fluent Notation and Antonyms
|
41
40
|
|
42
|
-
Like +assert+, +should+ and +must+ can be used as
|
41
|
+
Like +assert+, +should+ and +must+ can be used as higher order functions.
|
43
42
|
|
44
43
|
4.should == 4
|
45
44
|
4.must == 4
|
46
45
|
|
47
|
-
|
48
|
-
+must
|
46
|
+
Antonyms provided for +should+ as <tt>should!</tt> (read "should not") and +shouldnt+.
|
47
|
+
For +must+ +must+, they are <tt>must!</tt> and +wont+.
|
49
48
|
|
50
49
|
4.should! == 5
|
51
50
|
4.shouldnt == 5
|
@@ -56,8 +55,8 @@ With the antonym of +should!+ (read as "should not") or +shouldnt+, and for
|
|
56
55
|
|
57
56
|
== To Be
|
58
57
|
|
59
|
-
On occasions where the English readability of a specification is
|
60
|
-
|
58
|
+
On occasions where the English readability of a specification is hindered,
|
59
|
+
+be+ can be used.
|
61
60
|
|
62
61
|
StandardError.must.be.raised? do
|
63
62
|
unknown_method
|
@@ -65,63 +64,37 @@ hindered, +be+ can be used.
|
|
65
64
|
|
66
65
|
The +be+ method is the same as +assert+ with the single exception
|
67
66
|
that it will compare a lone argument to the receiver using +equate?+,
|
68
|
-
unlike +assert+ which simply
|
67
|
+
unlike +assert+ which simply checks to see that the argument evaluates
|
69
68
|
as true.
|
70
69
|
|
71
70
|
10.should.be 10
|
72
71
|
10.should.be 10.0
|
73
72
|
10.should.be Numeric
|
74
73
|
|
74
|
+
Assertion.assert.raised? do
|
75
|
+
10.should.be "40"
|
76
|
+
end
|
77
|
+
|
75
78
|
|
76
79
|
== Indefinite Articles
|
77
80
|
|
78
|
-
|
79
|
-
that they use
|
81
|
+
Additional English forms are +a+ and +an+, equivalent to +be+ except
|
82
|
+
that they use <tt>case?</tt> (same as <tt>#===</tt>) instead of
|
83
|
+
<tt>equate?</tt> when acting on a single argument.
|
80
84
|
|
81
85
|
"hi".must.be.a String
|
82
86
|
|
83
|
-
|
87
|
+
Assertion.assert.raised? do
|
88
|
+
/x/.must.be.a /x/
|
89
|
+
end
|
84
90
|
|
85
|
-
|
91
|
+
Otherwise they are interchangeable.
|
86
92
|
|
87
|
-
|
93
|
+
"hi".must.be.an.instance_of?(String)
|
88
94
|
|
95
|
+
The indefinite articles work well when a noun follows as an arguments.
|
89
96
|
|
90
97
|
palindrome = lambda{ |x| x == x.reverse }
|
91
98
|
|
92
99
|
"abracarba".must.be.a palindrome
|
93
100
|
|
94
|
-
|
95
|
-
== Verifying Object State
|
96
|
-
|
97
|
-
The block notation of the subjunctive form is similar to +assert+, with
|
98
|
-
the important exception that the block is is evaluated in the scope of the
|
99
|
-
receiver via #instance_eval, if no block parameter is designated.
|
100
|
-
This can be also be used to test the state of an object.
|
101
|
-
|
102
|
-
class X
|
103
|
-
attr :a
|
104
|
-
def initialize(a); @a = a; end
|
105
|
-
end
|
106
|
-
|
107
|
-
x = X.new(4)
|
108
|
-
|
109
|
-
x.must do
|
110
|
-
4 == @a
|
111
|
-
end
|
112
|
-
|
113
|
-
And should it fail...
|
114
|
-
|
115
|
-
Assertion.assert.raised? do
|
116
|
-
x.must do
|
117
|
-
5 == @a
|
118
|
-
end
|
119
|
-
end
|
120
|
-
|
121
|
-
For some this might seem controversial --to test underlying
|
122
|
-
implementation. And you will get no argument here, it should be used
|
123
|
-
thoughtfully, but there are occasions when such validations are
|
124
|
-
necessary.
|
125
|
-
|
126
|
-
QED.
|
127
|
-
|