Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

@uuf6429
Copy link
Contributor

@uuf6429 uuf6429 commented May 12, 2025

Closes #318.

  1. Makes all immutable private properties readonly, when possible.
  2. Additionally, declares the correct property type (since it's a requirement of using readonly)
  3. Adds more normalizer methods and fixes the relevant test

Copy link
Member

@stof stof left a comment

Choose a reason for hiding this comment

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

Instead of adding those wither methods in the public API just for usage in tests (including some normalization logic which is needed only because we don't "yet" handle the description the same way than upstream and we hide that difference in compatibility tests), I'd rather fix the test:

  1. try to fix the difference in parsing descriptions so that we don't need custom normalization anymore
  2. figure out the reason for changing the keywordType and arguments during normalization (arguments looks especially weird to me, as this drops some part that should be compared IMO). then, this should be solved if possible. And otherwise, maybe register a custom comparator to hook into the comparison of assertEquals instead of normalizing objects.

@uuf6429
Copy link
Contributor Author

uuf6429 commented May 13, 2025

@stof @acoulton those are some very good points - I'll see if I can make it work.

@uuf6429 uuf6429 marked this pull request as draft May 13, 2025 13:51
@acoulton
Copy link
Contributor

@stof on the normalisation:

  1. Feature description is tracked at Feature description whitespace does not match Cucumber #209 - I think there is a valid argument for not parsing this the same as cucumber/gherkin: I think it's the only place where the indentation from the original file is preserved, and IMO there's no good reason for that to be the case...
  2. keywordType looks like a custom property that we attempt to populate with e.g. Given / When etc for steps like And, based on the steps that have come before. There's no equivalent concept/property in the cucumber/gherkin ndjson hence there is nothing to compare against - CucumberNDJsonAstLoader just populates it the same as the keyword value. I suppose we could implement similar logic to give it a value in CucumberNDJsonLoader, but I'm not sure how useful that is - ignoring it from the comparison is probably just as effective?
  3. arguments looks like it's just because CucumberNDJsonAstLoader doesn't attempt to load/parse step arguments. It looks like those are present in the NDJson (as either docString or dataTable keys) so I'm not sure whether there was a problem parsing them originally, or whether it was just felt that it was not required. This would probably be worth fixing, as I agree it'd be useful to compare our parsing of the table and pystring arguments are well.

I think each of these are probably separate things to discuss / address in their own issues / PRs.

In the meantime, I agree that we should either register a custom comparator to the assertEquals or do the normalisation inline in this test. IMO for this PR it would be sufficient to just inline the method bodies of @uuf6429's ->withXX methods into the places he's calling them in the test.

@uuf6429 uuf6429 marked this pull request as ready for review May 13, 2025 19:05
@uuf6429 uuf6429 requested review from acoulton and stof May 13, 2025 19:06
@uuf6429
Copy link
Contributor Author

uuf6429 commented May 13, 2025

Done, I simply expanded the normalizer method since it sounded more natural than having with/copy methods.

I considered a custom comparator, but:

  • comparing with assertObjectEquals() I would need to implement an equality method for all relevant classes - while it could be generally useful, it's too specific to testing.
  • adding a custom comparator sounded like a lot of work - new class with a lot of logic, registered in the test bootstrap
  • using assertThat() with a custom constraint class also looked too complicated

Copy link
Contributor

@acoulton acoulton left a comment

Choose a reason for hiding this comment

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

Thanks @uuf6429 this generally looks great - a couple of personal-preference nits on style, and I've suggested adding more information on why the StepNode needs to be normalised for future reference.

@codecov
Copy link

codecov bot commented May 13, 2025

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 96.86%. Comparing base (b08b4d4) to head (7cc96d8).
Report is 1 commits behind head on master.

Additional details and impacted files
@@             Coverage Diff              @@
##             master     #319      +/-   ##
============================================
+ Coverage     96.70%   96.86%   +0.16%     
+ Complexity      602      600       -2     
============================================
  Files            36       36              
  Lines          1760     1724      -36     
============================================
- Hits           1702     1670      -32     
+ Misses           58       54       -4     
Flag Coverage Δ
php8.1 96.86% <100.00%> (+0.16%) ⬆️
php8.1--with=symfony/yaml:^5.4 96.86% <100.00%> (+0.16%) ⬆️
php8.1--with=symfony/yaml:^6.4 96.86% <100.00%> (+0.16%) ⬆️
php8.2 96.86% <100.00%> (+0.16%) ⬆️
php8.3 96.86% <100.00%> (+0.16%) ⬆️
php8.4 96.86% <100.00%> (+0.16%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

Copy link
Contributor

@acoulton acoulton left a comment

Choose a reason for hiding this comment

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

Thanks

@stof
Copy link
Member

stof commented May 14, 2025

I'm fine with using readonly properties. However, I suggest having a policy banning the usage of readonly classes (even though our support of PHP 8.1 currently forbids it until we bump our min PHP versions).
non-final readonly classes are a maintenance nightmare, because both adding and removing the readonly keyword is a BC break (due to the fact that the whole inheritance tree must be either readonly or non-readonly). Readonly classes are also incompatible with property hooks (while property hooks are a formidable tool to write BC layers when refactoring a class based on public properties rather than getters).
To me readonly classes have much bigger drawbacks than advantages (saving a few keystrokes by avoiding to repeat the readonly keyword on each property is really their only advantage, and IDEs autocomplete the keyword so we don't even save 9 keystrokes per additional properties but less than that).

@acoulton
Copy link
Contributor

I'm fine with using readonly properties. However, I suggest having a policy banning the usage of readonly classes

@stof agreed. Are you otherwise happy with this PR?

* Update ArrayKeywords.php

* Change null assign syntax
@uuf6429 uuf6429 requested a review from stof May 14, 2025 11:13
Copy link
Contributor

@acoulton acoulton left a comment

Choose a reason for hiding this comment

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

Thanks @uuf6429

Copy link
Contributor

@carlos-granados carlos-granados left a comment

Choose a reason for hiding this comment

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

@uuf6429 I would have really preferred to see this as two separate PRs, one covering the use of readonly properties, and another with the normaliser changes. Thanks for your work anyway

@uuf6429
Copy link
Contributor Author

uuf6429 commented May 17, 2025

@carlos-granados that wouldn't have worked - as soon as the properties are made private, tests would fail. The only way is if I did the normalizers first and then made the properties private in a child branch, but it would have ended up messier and somewhat counterintuitive.

On a related note, GitHub makes a mess out of contributed PRs (e.g. showing huge diffs without factoring in other PRs), which slows down reviewing a lot - which is why I'm avoiding dependent PRs, despite being my day-to-day flow.

I'd like to point out that my plan was to fully integrate PHPStan by the end of January - at this point I don't even remember anymore what I was doing that required or warranted setting up PHPStan... and now I just don't want to leave it half-finished.

(to be clear, I appreciate everyone's efforts)

@acoulton acoulton merged commit cb6b904 into Behat:master May 20, 2025
10 checks passed
@uuf6429 uuf6429 deleted the chore/make-private-properties-readonly branch May 20, 2025 08:59
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.

setPrivateProperty and readonly properties in tests

4 participants