I little point I got caught with a few times... us...
# strikt
d
I little point I got caught with a few times... using
and { get(SomeClass::someProp).isEqualTo(...) }
on a nullable type without
isNotNull()
allows the
and
, but has
get()
undefined... I wonder if it makes sense to have an
and
in this case in the first place...? What can one do with a nullable type? Also, is there anything like a
isNotNullAnd { ... }
or
withNotNull { }
? I find myself doing
expectThat(result).isNotNull().and { ... }
quite often...
c
hmm but
isNotNull().and { ... }
is pretty short and nice to read
maybe we should allow and only on not null receivers?
d
The thing is that the trailing
and
is really not an
and
but rather testing the not null result... it's not a side-effect like
and
seems to point out.
maybe we should allow and only on not null receivers?
That's what I was wondering... but maybe there's some use-case for that I'm not thinking of?
It could maybe be deprecated saying
and should only be used in not null contexts
or something?
For the previous suggestion, there's already a bunch of mappers like
with
... couldn't
withNotNull { }
be such a mapper, when the main assertion is the expected non-null result's contents?
But in cases when it only matters that the result
isNotNull()
then it being an assertion in itself might make more sense...
r
It would certainly be easy to add a
withNotNull
. I’ve never been super happy with the naming of
and
. It reads well in some contexts but not in others.
👍 1
c
But in isnotnull().and() it fits pretty well
r
true
d
with can also be replaced by get and and.... I guess it's a bit hard to draw the line... i just find myself doing isnotnull and and pretty often. But I also don't want to pollute the library with things others might not be using.
It's easy to add a few extension functions to my project.
r
The maintenance cost for those kind of things in the lib is pretty much zero. So long as it’s not some kind of new API direction I’m not sure about I’m happy to add it. I think
withNotNull
as an alias for
.isNotNull().and { }
is useful enough to be worth adding
d
Also, do you ever assert anything on a nullable value without isNotNull()? Is it on purpose that matchers/mappers (apart from the ones checking or mapping nulls) are available for nullables?
r
you can use
isEqualTo
on a null value
d
Is that good practice, or might that encourage subtle cases that aren't covered by the tests?
r
and since Kotlin makes it possible to write extension functions for nullable types it makes sense to allow for the possibility someone may want to write assertions for it
I don’t think
.isNotNull() isEqualTo "foo"
is more correct than just
isEqualTo "foo"
d
It raises awareness to have to check the null cases, but I guess it might be overkill in some cases... so
and
on nullables also make sense? Inside it, there's not even a get() to use to test on multiple mapped properties..., or am I missing a use case?
r
I can’t see myself using
and
on a nullable, but I wouldn’t like to prevent it only to find there’s a good reason for someone to want it
d
Yeah, I guess there might always be that case we would never think of... I just tripped up on it a few times, importing a get() inside such an and() from some other library - and not finding matchers on it... just to realize it was a nullable. If only matchers that can be used are available in code-complete, it would be quicker to choose the right things...
r
yeah, I sometimes wonder if the opaqueness of Strikt’s API is more trouble than it’s worth. It’s deliberate, but when I find myself mirroring every useful operation on subject classes it feels a bit clunky
c
I always type “is” and invoke autocompete to see whats possible. in this case it works pretty well:
d
I don't usually do
isXXX
in an
and
block, since those can be chained. The main use of an
and
block for me is to check properties of a class using
get()
.
c
we could add a get method for the nullable receiver that is deprecated and tells you that you need to do isNotNull.
hmm or there could be a get receiver on nullable types that does the isNotNull for you
d
The first option was my original idea, the latter seems a bit too inexplicit (which
withNotNull { }
would avoid together with the first option you stated).
But is it possible to make only the nullable reciever's get() deprecated without affecting the other one?
c
hmm i can check…
hmm for me get actually is available in a nullable and block:
it just complains that it cannot call the name method because of nullability
d
I don't use that syntax, I use get(SomeClass::someProperty).
You're right the other syntax is available, but I think it's a mistake too.
c
what is a mistake?
d
To allow
get { }
in a nullable
and { }
block...
c
it allows it and the warning then tells you that you have a nullability problem
fun String?.someProperty() would be available in your syntax too
🤔 1
also its the same get method, just called with a different syntax
d
I don't think
get(SomeClass?::someProperty)
syntax exists in Kotlin... and
get { }
gives you an error in the IDE...
c
get(A?::hashCode)
works
😮 1
d
hashCode
does, but other properties don't ... that's funny!
r
I think Kotlin’s stdlib implements hashcode for nullable types
👍 1
c
yes