Skip to content

Commit b20bbca

Browse files
Tests: Cover the HEIC client-side sideload and companion-delete flow.
Adds REST API controller tests: - The sideload route exposes 'original-heic' in the image_size enum. - The sideload route exposes a 'generate_sub_sizes' boolean arg defaulting to false. - Sideloading an 'original-heic' image writes the filename to $metadata['original'] and leaves 'original_image' untouched. Adds wp_delete_attachment_heic_companion_file() unit tests: - The companion HEIC is removed when the attachment is deleted. - The hook is a no-op when $metadata['original'] is missing. - The hook bails when $metadata['original'] is not a string (regression coverage for the guard added in GB #78128).
1 parent c711280 commit b20bbca

2 files changed

Lines changed: 151 additions & 0 deletions

File tree

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
<?php
2+
3+
/**
4+
* Tests for the `wp_delete_attachment_heic_companion_file()` function.
5+
*
6+
* @group media
7+
* @covers ::wp_delete_attachment_heic_companion_file
8+
*/
9+
class Tests_Media_wpDeleteAttachmentHeicCompanionFile extends WP_UnitTestCase {
10+
11+
public function tear_down() {
12+
$this->remove_added_uploads();
13+
14+
parent::tear_down();
15+
}
16+
17+
/**
18+
* @ticket 64915
19+
*/
20+
public function test_deletes_heic_file_recorded_in_metadata_original() {
21+
$attachment_id = $this->factory->attachment->create_upload_object( DIR_TESTDATA . '/images/canola.jpg' );
22+
23+
$attached_file = get_attached_file( $attachment_id, true );
24+
$dir = dirname( $attached_file );
25+
$heic_name = 'companion-' . wp_generate_password( 6, false ) . '.heic';
26+
$heic_path = $dir . '/' . $heic_name;
27+
28+
// Create a dummy companion file on disk.
29+
file_put_contents( $heic_path, 'test' );
30+
$this->assertFileExists( $heic_path, 'Test fixture should be on disk.' );
31+
32+
// Record the companion under metadata['original'] as the sideload route does.
33+
$metadata = wp_get_attachment_metadata( $attachment_id, true );
34+
$metadata['original'] = $heic_name;
35+
wp_update_attachment_metadata( $attachment_id, $metadata );
36+
37+
wp_delete_attachment( $attachment_id, true );
38+
39+
$this->assertFileDoesNotExist( $heic_path, 'Companion HEIC file should be deleted alongside the attachment.' );
40+
}
41+
42+
/**
43+
* @ticket 64915
44+
*/
45+
public function test_noop_when_metadata_original_is_missing() {
46+
$attachment_id = $this->factory->attachment->create_upload_object( DIR_TESTDATA . '/images/canola.jpg' );
47+
48+
// Sanity: no 'original' key on freshly-created metadata.
49+
$metadata = wp_get_attachment_metadata( $attachment_id, true );
50+
$this->assertArrayNotHasKey( 'original', $metadata );
51+
52+
// Should not raise even though the hook fires.
53+
wp_delete_attachment( $attachment_id, true );
54+
55+
$this->assertNull( get_post( $attachment_id ) );
56+
}
57+
58+
/**
59+
* Guards against $metadata['original'] holding a non-string value (e.g.
60+
* the array form some flows write). Regression coverage for GB #78128.
61+
*
62+
* @ticket 64915
63+
*/
64+
public function test_noop_when_metadata_original_is_not_a_string() {
65+
$attachment_id = $this->factory->attachment->create_upload_object( DIR_TESTDATA . '/images/canola.jpg' );
66+
$attached_file = get_attached_file( $attachment_id, true );
67+
68+
$metadata = wp_get_attachment_metadata( $attachment_id, true );
69+
$metadata['original'] = array( 'file' => 'should-not-delete.heic' );
70+
wp_update_attachment_metadata( $attachment_id, $metadata );
71+
72+
// Should not raise (no path_join() / file_exists() on an array).
73+
wp_delete_attachment_heic_companion_file( $attachment_id );
74+
75+
$this->assertFileExists( $attached_file, 'Attached file should still be on disk; the hook must bail on non-string original.' );
76+
}
77+
}

tests/phpunit/tests/rest-api/rest-attachments-controller.php

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3351,6 +3351,80 @@ public function test_sideload_route_includes_scaled_enum() {
33513351
$this->assertContains( 'scaled', $args[ $param_name ]['enum'], 'image_size enum should include scaled.' );
33523352
}
33533353

3354+
/**
3355+
* Tests that the sideload endpoint includes 'original-heic' in the image_size enum.
3356+
*
3357+
* @ticket 64915
3358+
*/
3359+
public function test_sideload_route_includes_original_heic_enum() {
3360+
$this->enable_client_side_media_processing();
3361+
3362+
$routes = rest_get_server()->get_routes();
3363+
$endpoint = $routes['/wp/v2/media/(?P<id>[\d]+)/sideload'][0];
3364+
$args = $endpoint['args'];
3365+
3366+
$this->assertArrayHasKey( 'image_size', $args, 'Route should have image_size arg.' );
3367+
$this->assertContains( 'original-heic', $args['image_size']['enum'], 'image_size enum should include original-heic.' );
3368+
}
3369+
3370+
/**
3371+
* Tests that the sideload endpoint exposes the generate_sub_sizes arg.
3372+
*
3373+
* @ticket 64915
3374+
*/
3375+
public function test_sideload_route_includes_generate_sub_sizes_arg() {
3376+
$this->enable_client_side_media_processing();
3377+
3378+
$routes = rest_get_server()->get_routes();
3379+
$endpoint = $routes['/wp/v2/media/(?P<id>[\d]+)/sideload'][0];
3380+
$args = $endpoint['args'];
3381+
3382+
$this->assertArrayHasKey( 'generate_sub_sizes', $args, 'Route should have generate_sub_sizes arg.' );
3383+
$this->assertSame( 'boolean', $args['generate_sub_sizes']['type'], 'generate_sub_sizes should be a boolean.' );
3384+
$this->assertFalse( $args['generate_sub_sizes']['default'], 'generate_sub_sizes should default to false on sideload.' );
3385+
}
3386+
3387+
/**
3388+
* Tests sideloading an 'original-heic' companion file alongside its JPEG
3389+
* derivative. The HEIC filename is recorded under $metadata['original']
3390+
* so it does not collide with 'original_image', which the scaled-sideload
3391+
* flow owns.
3392+
*
3393+
* @ticket 64915
3394+
* @requires function imagejpeg
3395+
*/
3396+
public function test_sideload_original_heic_writes_metadata_original() {
3397+
$this->enable_client_side_media_processing();
3398+
3399+
wp_set_current_user( self::$author_id );
3400+
3401+
// Create the JPEG attachment that the HEIC will be a companion to.
3402+
$request = new WP_REST_Request( 'POST', '/wp/v2/media' );
3403+
$request->set_header( 'Content-Type', 'image/jpeg' );
3404+
$request->set_header( 'Content-Disposition', 'attachment; filename=canola.jpg' );
3405+
$request->set_body( file_get_contents( self::$test_file ) );
3406+
$response = rest_get_server()->dispatch( $request );
3407+
$attachment_id = $response->get_data()['id'];
3408+
3409+
$this->assertSame( 201, $response->get_status() );
3410+
3411+
// Sideload the HEIC companion. Uses a JPEG body since the size enum,
3412+
// not the file format, is what we're exercising here.
3413+
$request = new WP_REST_Request( 'POST', "/wp/v2/media/{$attachment_id}/sideload" );
3414+
$request->set_header( 'Content-Type', 'image/jpeg' );
3415+
$request->set_header( 'Content-Disposition', 'attachment; filename=canola.heic' );
3416+
$request->set_param( 'image_size', 'original-heic' );
3417+
$request->set_body( file_get_contents( self::$test_file ) );
3418+
$response = rest_get_server()->dispatch( $request );
3419+
3420+
$this->assertSame( 200, $response->get_status(), 'Sideloading original-heic should succeed.' );
3421+
3422+
$metadata = wp_get_attachment_metadata( $attachment_id );
3423+
$this->assertArrayHasKey( 'original', $metadata, "Metadata should contain 'original' for the HEIC companion." );
3424+
$this->assertMatchesRegularExpression( '/canola.*\.heic$/', $metadata['original'], "Metadata 'original' should reference the HEIC filename." );
3425+
$this->assertArrayNotHasKey( 'original_image', $metadata, "Metadata 'original_image' should be untouched by the HEIC sideload." );
3426+
}
3427+
33543428
/**
33553429
* Tests the filter_wp_unique_filename method handles the -scaled suffix.
33563430
*

0 commit comments

Comments
 (0)