<?php
/**
* SeekQuarry/Yioop --
* Open Source Pure PHP Search Engine, Crawler, and Indexer
*
* Copyright (C) 2009 - 2026 Chris Pollett chris@pollett.org
*
* LICENSE:
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* END LICENSE
*
* @author Chris Pollett chris@pollett.org
* @license https://www.gnu.org/licenses/ GPL3
* @link https://www.seekquarry.com/
* @copyright 2009 - 2026
* @filesource
*/
namespace seekquarry\yioop\tests;
use seekquarry\yioop\configs as C;
use seekquarry\yioop\library\UnitTest;
/**
* Tests the command line tool for audio and video: that it writes a
* thumbnail where it is told to, at the width asked for, that it can
* describe a file without decoding it, and that it says what is wrong
* rather than stopping without a word.
*
* The tool is run as a person runs it, in its own process, since that is
* the only way its reading of a command line and what it prints are both
* checked.
*
* @author Chris Pollett
*/
class AVToolTest extends UnitTest
{
/**
* The video file the cases run the tool over.
* @var string
*/
public $video = "";
/**
* Where the tool is asked to write its picture.
* @var string
*/
public $written = "";
/**
* Writes the video out of the base64 it is kept in.
*/
public function setUp()
{
$held = file_get_contents(C\PARENT_DIR .
"/tests/test_files/video_white_mp4.txt");
$this->video = C\WORK_DIRECTORY . "/temp/av_tool" . getmypid() .
".mp4";
file_put_contents($this->video, base64_decode($held));
$this->written = C\WORK_DIRECTORY . "/temp/av_tool" . getmypid() .
".webp";
}
/**
* Removes what the cases wrote.
*/
public function tearDown()
{
foreach ([$this->video, $this->written] as $path) {
if ($path !== "" && file_exists($path)) {
unlink($path);
}
}
}
/**
* Runs the tool and gives back what it printed.
*
* @param string $arguments what to put after the tool's own name
* @return string everything the tool printed, output and errors both
*/
public function runTool($arguments)
{
$tool = C\BASE_DIR . "/executables/AVTool.php";
return shell_exec("php " . escapeshellarg($tool) . " " .
$arguments . " 2>&1");
}
/**
* Asked for help, the tool says what it does and what its options
* are, so somebody who runs it with nothing is not left guessing.
*/
public function askedForHelpItSaysWhatItDoesTestCase()
{
$said = $this->runTool("--help");
$this->assertTrue(strpos($said, "picture from a video") !== false,
"the help says the tool makes a picture from a video");
$this->assertTrue(strpos($said, "convert a recording") !== false,
"and that it converts a recording");
$this->assertTrue(strpos($said, "--probe") !== false,
"and lists the option that describes a file");
$this->assertTrue(strpos($said, "--width") !== false,
"and the option that sets the width");
}
/**
* The tool writes a picture where it is told to, at the width asked
* for, and says what it wrote.
*/
public function itWritesAThumbnailWhereToldTestCase()
{
$said = $this->runTool(escapeshellarg($this->video) . " -o " .
escapeshellarg($this->written) . " -w 200");
$this->assertTrue(file_exists($this->written),
"a picture is written where the tool was told to write it");
$size = getimagesize($this->written);
$this->assertEqual(200, $size[0] ?? 0,
"it is as wide as was asked for");
$this->assertEqual(150, $size[1] ?? 0,
"and its height keeps the shape of the frame");
$this->assertTrue(strpos($said, "200x150") !== false,
"and the tool says what it wrote");
}
/**
* Asked to describe a file, the tool says what it holds without
* decoding a frame, which is what a site wants when it only needs to
* know how long a video runs.
*/
public function itDescribesAFileWithoutDecodingTestCase()
{
$said = $this->runTool(escapeshellarg($this->video) . " --probe");
$held = json_decode($said, true);
$this->assertTrue(is_array($held),
"what it prints reads back as a description");
$this->assertEqual("MP4", $held['container'] ?? "",
"it names the kind of file");
$this->assertEqual(320, $held['width'] ?? 0,
"how wide the video is");
$this->assertEqual(10, round($held['duration'] ?? 0),
"and how long it runs");
}
/**
* A still picture is what the tool writes unless a moving one is
* asked for. It used to look at how long the video ran and write a
* moving picture for anything over a minute, which surprised
* somebody who asked for one frame at one moment.
*/
public function itWritesAStillPictureUnlessAskedOtherwiseTestCase()
{
$this->runTool(escapeshellarg($this->video) . " -t 2.5 -o " .
escapeshellarg($this->written) . " -w 200");
$written = file_get_contents($this->written);
$this->assertTrue(strpos($written, "ANIM") === false,
"what it wrote carries no moving picture mark");
$size = getimagesize($this->written);
$this->assertEqual(200, $size[0] ?? 0,
"and it is as wide as was asked for");
$said = $this->runTool(escapeshellarg($this->video) .
" --animated -n 3 -o " . escapeshellarg($this->written) .
" -w 200");
$written = file_get_contents($this->written);
$this->assertTrue(strpos($written, "ANIM") !== false,
"asked for a moving picture, it writes one");
$this->assertTrue(strpos($said, "animated") !== false,
"and says so");
}
/**
* Handed a file that is not a video, the tool says so and stops,
* rather than writing a broken picture or saying nothing.
*/
public function handedSomethingElseItSaysSoTestCase()
{
$not_a_video = C\WORK_DIRECTORY . "/temp/av_tool_words" .
getmypid() . ".txt";
file_put_contents($not_a_video, "these are only words");
$said = $this->runTool(escapeshellarg($not_a_video));
$this->assertTrue(strpos($said, "unrecognized container") !== false,
"it says the file is not a kind it knows");
$this->assertTrue(!file_exists($this->written),
"and writes no picture");
if (file_exists($not_a_video)) {
unlink($not_a_video);
}
}
}