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

fix: Kotlin name mangling #1549

Closed

Conversation

TimothyEarley
Copy link

@TimothyEarley TimothyEarley commented Feb 27, 2024

Problem

Kotlin mangles some names when value classes are used. See https://kotlinlang.org/docs/inline-classes.html#mangling
This mangled name is then used in the reports.

Solution

This commit removes the dash and following chars from the default method name.
Thus leading to better readable reports.

This should not affect Java projects as far as I can tell since "-" is not valid in method names (see https://docs.oracle.com/javase/specs/jls/se7/html/jls-3.html#jls-3.8).

Alternatives

  • Instead of having this case covered by JGiven, we could also override the method name in all affected methods using @As (repeated test name), @As with a custom provider, or Kotlins @JvmName (repeated test name).

  • Another alternative would be to allow setting the default AsProvider (same as with the formatter currently). I presume this would mean adding the config in all our test classes, but not on each method individually.

Thanks for your time!

@l-1squared l-1squared self-requested a review February 29, 2024 05:54
@l-1squared
Copy link
Collaborator

Hi, thanks for the submission. I will take a look as soon as possible

@l-1squared
Copy link
Collaborator

Looks good so far,
I need to check, whether it might affect the spock package, since that uses groovy.

Kotlin mangles some names when value classes are used. See https://kotlinlang.org/docs/inline-classes.html#mangling

This commit removes the dash and following chars from the default method name.
@TimothyEarley TimothyEarley force-pushed the fix/kotlin-value-class-mangling branch from 4799ac3 to 71ee784 Compare March 20, 2024 15:57
Copy link
Collaborator

@l-1squared l-1squared left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi,
I finally had some time to have an in depth look into your PR. Unfortunately, the concern I voiced earlier has proven itsself true: Spock (i.e. groovy) method naming does allow for "-" signs in methods natively. I took a quick look and I see no way to distinguish a groovy invocation from a Java one. Also, I just learned that kotlin itsself support function names of the form name-with-minus-inbetween. Now, I didn't test, but I fear that for a kotlin function we would run into the same issues as with groovy. (Fortunately it does not affect names given with @Description)

Overall, I think that we may require a more sophisticated approach here. In my opinon this should leverage the existing flexibility the @As annotation affords. You can have a look here https://jgiven.org/userguide/#_overriding_the_default_reporting what can be done with that annotation.

I could imagine that for a more comfortable solution for kotlin users it would make sense to resurrect that jgiven-kotlin branch we still have and potentially create a KotlinAs Provider or something similar that deals with name mangled classes automatically.

Edit: I'll see if I can make the AsProvider a part of the configuration, so that a different default is more easily provided

@l-1squared
Copy link
Collaborator

@TimothyEarley I started writing #1574, hoping that it might alleviate your issues

@TimothyEarley
Copy link
Author

Thanks for continuing to look into it!

Configuring a default As Provider should help alleviate the problem (and then the method described below could be in a separate Kotlin Provider).

Another approach I just tested is using Kotlin Reflection. With the kotlin-reflect library we can use the following code snippet to get the source method name (as opposed to the JVM name) in the DefaultAsProvider:

var kMethod = ReflectJvmMapping.getKotlinFunction(method);
if (kMethod != null) {
    return methodNameToReadableText( kMethod.getName() );
} else {
    return methodNameToReadableText( method.getName() );
}

Docs for kMethod.getName(): https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.reflect/-k-callable/name.html

This would remove manipulating the method name by hand and should be safe in other languages (kMethod would be null) at the cost of adding a dependency on the kotlin-reflect library.
Let me know if you would like a commit trying these out (with kotlin tests?)

@l-1squared
Copy link
Collaborator

Hi, sorry for keeping you waiting, I was busy celebrating easter.

I think that using the kotlin reflect library might be a good tool to solve the issue for a hypothetical jgiven-kotlin package; using it in core just doesn't have the right ring in my ears. It would be an rather unexpected feature with an unexpected dependency at an unexpected place ( wo do advertise as "plain java" after all ). Therefore, if we are willing to tackle kotlin-specific problems when using jgiven. they should go in #407

@l-1squared
Copy link
Collaborator

Closing this PR, I think a more custom solution based on a tailored AsProvider is more appropriate

@l-1squared l-1squared closed this Sep 27, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants