[squeak-dev] assert:equals: in Object

Eliot Miranda eliot.miranda at gmail.com
Mon Oct 12 18:41:44 UTC 2020


Hi Levente,

On Mon, Oct 12, 2020 at 10:59 AM Eliot Miranda <eliot.miranda at gmail.com>
wrote:

> Hi Levente,
>
> On Fri, Oct 9, 2020 at 4:04 PM Levente Uzonyi <leves at caesar.elte.hu>
> wrote:
>
>> Hi Eliot,
>>
>> On Fri, 9 Oct 2020, Eliot Miranda wrote:
>>
>> > Hi All,
>> >
>> >     moving code from a test into a workspace and back is painful
>> because Object does not implement assert:equals: or
>> assert:equals:description: even though it implements assert:description:.
>> So one has to edit out the
>> > equals: moving to the workspace and edit it back in again on the way
>> back.  I'd like to suggest implementing Object>>assert:equals:
>> and Object>>assert:equals:description: but I won't, because someone is
>> bound to criticise it
>> > as being too green or ill considered or some other depressing BS.
>>
>> In my opinion, it would be better to get rid of #assert:equals: and
>> #assert:equals:description:. Many find the order of its arguments
>> confusing, and they are only good to help tracking down what failed.
>> If #assert: could give information about it's argument: the source code
>> and probably the values of the variables in it, then #assert:equals:
>> would
>> simply become unnecessary.
>>
>
> I couldn't agree more.  I *hate* assert:equals: being, for me, the wrong
> way round.  We would need to provide an abstraction around extracting the
> parse tree for an argument, which shouldn't be too hard.  Let me take a
> look at this and see if I can provide something simple and robust.
>
>>
>> For example
>>
>> | x y |
>> x := 'foo'.
>> y := 1.
>> self assert: x = y.
>>
>> would signal an exception with the message 'Assertion failed: x = y (x =
>> ''foo'', y = 1)' instead of just 'Assertion failed'.
>>
>
Having thought about it a bit the problem is more difficult than it
appears.  If the form of an assert is
    self assert: exprA = exprB
then in general only the result of exprA = exprB is available. exprA and
exprB may have only been evaluated on the stack and not bound to
variables.  So no matter tha introspection makes it trivial to derive the
parse node and present the text for the expression: 'exprA = exprB' there
is no way to retrieve the values of either exprA or exprB because they have
been consumed and replaced by the result of their comparison.  This is what
assert:equals: does; it binds both the actual and expected values to the
arguments of assert:equals: and then performs the comparison.  So, absent
time reversal debugging machinery (which has costs and is unlikely to be
attractive for general use in running test suites which are > 99% correct
most of the time) we're stuck with assert:equals:.

So things to think about are perhaps
- a sibling of assert:equals: which takes its arguments in the opposite
order
- appealing to the SUnit community to reverse the order of arguments to
assert:equals:, plus a rewrite rule that reversed the obvious cases where
the first argument is a literal constant.
- seeing if assert:equals: could infer the order of its arguments; this
would require some analysis.  For how many assert:equals: cases can it
easily be determined if one or other of the arguments is the expected?  How
many cases are ambiguous?  Are any undecidable? etc...
- implementing "backwards in time" debugging for the Test Runner when one
selects a failing or erroring case.  This might be no more than
instrumenting the method to place breakpoints before comparisons whose
results are consumed by assert: variants and running up until the break.
This could be somewhat analogous to toggle break on entry in that
adding/removing the pre comparison breakpoints would be automatic.  And one
might be able to do it by mapping comparisons to comparisons for asserts.
 e.g.  consider:

        self assert: a = b   (along with >, <, >= et al)
transformed into
        self assert: (a compareEqualForAssert: b)
where compareEqualForAssert: answers a structured object (AssertResult?)
holding onto a, b, and the result of the comparison.  AssertResult would
answer its result in response to value.  So assert methods (that already
send value to coerce blocks and booleans to booleans) could send value to
the argument, and then if that was false, query to see if the argument was
an AssertResult and xtract a more informative error message if so.

All this is fun, and could function in the context of SUnit.  It does
nothing to answer my problem of running asserts in Workspaces.  However,
that was thoughtless on my part.  All I have to remember to do is inspect
an instance of a TestCase class and evaluate my doit in that inspector.  So
for the SocketTesxts if I had had my wits about me I would have simply
inspected SocketTest new and then could use ll of SUnit's assert machinery
in a doit in the inspector.


Levente
>>
>
> _,,,^..^,,,_
> best, Eliot
>

_,,,^..^,,,_
best, Eliot
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.squeakfoundation.org/pipermail/squeak-dev/attachments/20201012/01d76e19/attachment.html>


More information about the Squeak-dev mailing list