Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

replace property and returnValueOf with feature or similar #40

Closed
robstoll opened this issue Jul 19, 2018 · 2 comments
Closed

replace property and returnValueOf with feature or similar #40

robstoll opened this issue Jul 19, 2018 · 2 comments
Assignees
Milestone

Comments

@robstoll
Copy link
Owner

robstoll commented Jul 19, 2018

Platform (JVM and/or JS): JVM/JS

Code related feature

setup

data class Person(val firstName: String, val lastName: String) {
    fun fullName() = "$firstName $lastName"
    fun nickname(includeLastName: Boolean) = when(includeLastName){
        false -> "Mr. $firstName"
        true -> "$firstName aka. $lastName"
    }
}
val person = Person("Robert", "Stoll")

feature as such

assert(person) {
    feature(Person::fullName).contains("treboR", "llotS")
    feature(Person::nickname, false).toBe("Robert aka. Stoll")
}

We could furthermore consider to add featureRef as alternative where one can use a bounded reference:

assert(person).featureRef { subject::firstName }.toBe("robert")
assert(person).featureRef({ subjectPerson::nickname }, false).toBe("Robert aka. Stoll")

Yet, considering the problems we still encounter due to Kotlins problems with overloads involving KFunction types, I am not sure if it is really a good idea to allow bounded reference.

Alternatively we could also go with a Pair<String, T>:

assert(person)
  .feature{ "name" to name }

But that involves quite a bit of boilerplate. On the other hand it would allow mapping over multiple levels:

assert(person)
  .feature{ "name.first()" to name.first() }

We could reduce the boilerplate for JS by using eval but eval is evil and we would loose type safety so probably not a good idea.

The good thing about map` would be that we hide the implementation detail whether firstName is actually a property or a getter. I stumble over this problematic from time to time when I deal with Java Code where Kotlin provides property syntax even for getters. But that's not the case for function references. So the following is the result which is... not so nice:

val person = Person("hello")
person.name //calling the getter via property syntax
assert(person).property(Person::name).toBe(...) //fails because it is not really a property but the method `getName`
assert(person).property(Person::getName).toBe(...) // fails as well, because it is a method not a property
assert(person).returnValueOf(Person::getName).toBe(...) // that's ok

We cannot get rid of the confusion that Person does not have a name property, but we can at least lower the confusion by providing one single method.

assert(person).feature(Person::getName)

Care has to be taken due to current bugs concerning overloading in Kotlin.

@robstoll robstoll changed the title replace property and returnValueOf with map replace property and returnValueOf with map or similar Sep 22, 2018
@robstoll
Copy link
Owner Author

robstoll commented Sep 22, 2018

I am no longer sure if map is a good choice. We do not map to the thing we return but use it to create a feature assertions.. Maybe feature, as I intended to name it at the beginning, is better.

@robstoll robstoll changed the title replace property and returnValueOf with map or similar replace property and returnValueOf with feature or similar Oct 17, 2018
@robstoll
Copy link
Owner Author

robstoll commented Jan 26, 2019

To workaround the kotlin bug concerning multiple overloads with function type we could introduce featureNullable for nullable features. Then feature could be define as

fun <T : Any, TFeature : Any> Assert<T>.feature(provider: FeatureProvider<T>.() -> Assert<TFeature>, assertionCreator: Assert<T>.() -> Unit): Assert<T>

where FeatureProvider in turn provides helper functions to construct features out of properties and functions. The only problem here, Kotlin has also bugs concerning function reference of overloaded functions and expecting KProperty/KFunction :(
We could start off with p for property and f for function (similar to property and returnValueOf which we have currently). The usage would then look something like:

data class Person(val firstName: String, val lastName: String, val nickName: String?)
assert(Person("robert", "stoll", null))
    .feature({ p(it::firstName) }) { toBe("hello") }
    .featureNullable({ p(it::nickName) }) { notToBeNullBut("robstoll") }
    .feature({ f(it::name) }) { startsWith("robert") }

or we could start of with r (for reference) people would only need to use p and f in case of a problem

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant