Problem/Motivation
Out there in #2950132: Support PHPUnit 7 optionally in Drupal 8, while keeping support for ^6.5, some FileFieldTestBase tests fail.
That is due to the following code:
/**
* Asserts that a file exists physically on disk.
*
* Overrides PHPUnit\Framework\Assert::assertFileExists() to also work with
* file entities.
*
* @param \Drupal\File\FileInterface|string $file
* Either the file entity or the file URI.
* @param string $message
* (optional) A message to display with the assertion.
*/
public static function assertFileExists($file, $message = NULL) {
$message = isset($message) ? $message : format_string('File %file exists on the disk.', ['%file' => $file->getFileUri()]);
$filename = $file instanceof FileInterface ? $file->getFileUri() : $file;
parent::assertFileExists($filename, $message);
}
....
/**
* Asserts that a file does not exist on disk.
*
* Overrides PHPUnit\Framework\Assert::assertFileExists() to also work with
* file entities.
*
* @param \Drupal\File\FileInterface|string $file
* Either the file entity or the file URI.
* @param string $message
* (optional) A message to display with the assertion.
*/
public static function assertFileNotExists($file, $message = NULL) {
$message = isset($message) ? $message : format_string('File %file exists on the disk.', ['%file' => $file->getFileUri()]);
$filename = $file instanceof FileInterface ? $file->getFileUri() : $file;
parent::assertFileNotExists($filename, $message);
}
these methods that override PHPUnit's ones raise fatal errors because in PHPUnit7 they are signed with scalar type hints, so you can no longer overload $file being either a string or a FileInterface variable.
Proposed resolution
Explicitly pass the File entity URI via File::getFileUri() to assertFileExists and assertFileNotExists, and conditionally deprecate the two current methods that override PHPUnit ones, when FileInterface arguments are passed in.
Remaining tasks
User interface changes
none
API changes
none
Data model changes
none
Release notes snippet
Comments
Comment #2
mondrakeHere's a patch. We'll have to deprecate in 8.7.x and remove in 8.8.x if we want to have a chance to have PHPUnit 7 test runs with 8.8.x - otherwise test will fail because
assertFileExistsandassertFileNotExists, being direct overrides of PHPUnit methods, will fail because of changed method signature.Comment #3
mondrakeComment #4
mondrakeComment #6
amateescu commentedThis patch looks great to me! Just two things to fix clarify:
Since Drupal 8.7 has been released, I think we need to move the deprecation message to 8.8.x. Also, it should be removed in Drupal 9, not in 8.9.x.
Also, this deprecated tag marks the method as deprecated (in IDEs) even when it's used with a string argument, which is not what we want. Tricky situation...
We need a change record for this :)
Comment #7
mondrake#6.1 actually I think we should not add the @deprecated annotation at all - these are valid PHPUnit methods :) Just keep the conditional @trigger_error.
Comment #8
amateescu commentedYup, I think that's the best way forward. The CR should explicitly say that only passing a file entity as the first argument to
assertFileExistsandassertFileNotExistsis deprecated.Comment #9
mondrakeFiled draft CR https://www.drupal.org/node/3057326
Comment #10
mondrakeAddressing #6 and #7.
Comment #12
mondrake#10 good, deprecation tests work :)
Comment #14
mondrakeTypo :(
Comment #15
amateescu commentedThanks for the quick updates, the patch looks great to me!
Comment #17
mondrakeComment #18
larowlanany reason these are static?
we could return early and avoid the else here
Playing devils advocate, if we implemented __toString on the file entity, would this issue go away?
Comment #19
mondrakeOn it.
Comment #20
berdir> any reason these are static?
Probably consistency with phpunit assert methods, which are usually static?
> Playing devils advocate, if we implemented __toString on the file entity, would this issue go away?
I don't think we should do that. These methods have nothing to to with their parents, I assume they were added long before we converted the test to phpunit, I prefer renaming them. Adding __toString() (that would do what, return the ID?) to file entities seems pretty arbitrary.
Comment #21
larowlanreturn the uri, which is the change we make in assertManagedFile
happy for the consensus to be that's a dumb idea
Comment #22
mondrake1. Yes, was following PHPUnit pattern where most
assert*methods are static. In fact there's even an issue #3029358: Change tests calling static methods as '$this->' to 'static::' to convert assert calls to static::2.
I'm 99% sure it wont work anyway, because in PHPUnit 7 the assertFileExists method is
function assertFileExists(string $filename, string $message = ''): void, and I think type checking is strict, so passing the entity (to be casted to string) will fail. But the @larowlan's hint is good: we already have aFile::getFileUrimethod, so how about just droppingassertManagedFileExistsandassertManagedFileNotExists(less API), and just call that method in tests likeassertFileExists($file->getFileUri)(more readable tests)?Comment #23
mondrakePatch, doing #22.2
Comment #25
mondrakeOuch.
Comment #26
amateescu commentedI like the new direction a lot, "less API"++ :)
Comment #27
mondrakeComment #28
mondrakeUpdated IS and draft CR.
Comment #29
alexpottSo in Drupal 9 we can remove these method overrides. Nice work - great solution. It does mean we might be stuck on PHPUnit6 for Drupal 8 but this makes crossing that bridge if we have to a little easier.
Committed 3954b06 and pushed to 8.8.x. Thanks!
Comment #31
mondrakePublished CR.
Comment #32
berdir> It does mean we might be stuck on PHPUnit6 for Drupal 8 but this makes crossing that bridge if we have to a little easier.
Yeah, I think if this ends up being the only reason we don't update in D8 then we should just drop this method. I didn't find any usages of this on http://grep.xnddx.ru, there are a few subclasses, but afaik none that uses this helper method.
Comment #33
mondrakeActually, if we were to introduce PHPUnit-version-dependent traits like I am suggesting in #2950132: Support PHPUnit 7 optionally in Drupal 8, while keeping support for ^6.5, we can test on PHPUnit 6 with the overriden method and keep the deprecation, or test on PUHPunit 7 with the 'native' method and fail if an object is passed to
assertFileExists. What we cannot have is a deprecation on PHPUnit 7, because of the strict typing of the method itself. See #2950132-89: Support PHPUnit 7 optionally in Drupal 8, while keeping support for ^6.5.Comment #35
mondrake