Browse Source

Merge pull request #463 from qadan/7.x-datastream-validation

7.x datastream validation
pull/495/head
Adam 11 years ago
parent
commit
9ec50b6ebc
  1. 1
      islandora.info
  2. 41
      tests/README.md
  3. 277
      tests/datastream_validator_tests.test
  4. 988
      tests/datastream_validators.inc
  5. 66
      tests/islandora_web_test_case.inc

1
islandora.info

@ -22,4 +22,5 @@ files[] = tests/islandora_manage_permissions.test
files[] = tests/datastream_versions.test files[] = tests/datastream_versions.test
files[] = tests/datastream_cache.test files[] = tests/datastream_cache.test
files[] = tests/derivatives.test files[] = tests/derivatives.test
files[] = tests/datastream_validator_tests.test
php = 5.3 php = 5.3

41
tests/README.md

@ -1,4 +1,43 @@
You can define your own configurations specific to your enviroment by copying OVERVIEW
********
You can define your own configurations specific to your environment by copying
default.test_config.ini to test_config.ini, making your changes in the copied default.test_config.ini to test_config.ini, making your changes in the copied
file. These test need write access to the system's $FEDORA_HOME/server/config file. These test need write access to the system's $FEDORA_HOME/server/config
directory as well as the filter-drupal.xml file. directory as well as the filter-drupal.xml file.
DATASTREAM VALIDATION TESTS
***************************
The datastream validator included in the Islandora testing suite is able to
generate tests procedurally based on the files in the folder
'fixtures/datastream_validator_files'. By default, this folder is empty.
The unit tests for the validator pull the name of the file (before the
extension) and use that to instantiate the correct ______DatastreamValidator
class to test that file against (e.g. Image.jpg spins up an instance of the
ImageDatastreamValidator class and checks the results).
You can test against multiple different encodings of the same filetype by giving
each file a different set of extensions, e.g. MP3.vbr.mp3 and MP3.sbr.mp3 both
test against the MP3 datastream validator, even though both are encoded
differently.
For classes that require the third parameter (e.g. the TextDatastreamValidator),
place an additional name.extension.ini file in the datastream_validator_files
folder (e.g. the Text.txt would be paired with Text.txt.ini). This .ini file
should be structured like a PHP .ini file (e.g. according to the format used by
http://php.net/parse_ini_file).The generated test will parse the .ini
file as an array and pass it on to the third parameter.
The following prefixes are currently available for use:
- Image (jpg, png, gif, and other filetypes recognized by PHPGD)
- TIFF
- JP2
- PDF
- Text (requires a configured .ini)
- WAV
- MP3
- MP4
- OGG (asserts OGG video; use an .ini with an 'audio' key to test audio only)
- MKV

277
tests/datastream_validator_tests.test

@ -0,0 +1,277 @@
<?php
/**
* @file
* Tests for things that test tests. Madness.
*/
include 'datastream_validators.inc';
/**
* A test DatastreamValidator for the DatastreamValidatorResultTestCase.
*/
class TestDatastreamValidator extends DatastreamValidator {
/**
* Assertion that adds a TRUE result.
*/
protected function assertSomethingSuccessfully() {
$this->addResult(TRUE, 'yay you did it', $this->getAssertionCall());
}
/**
* Assertion that adds a FALSE result.
*/
protected function assertSomethingFailed() {
$this->addResult(FALSE, 'boo you failed', $this->getAssertionCall());
}
}
/**
* Tests the ability of DatastreamValidators to produce correct results.
*/
class DatastreamValidatorResultTestCase extends IslandoraWebTestCase {
/**
* Returns the info for this test case.
*
* @see DrupalWebTestCase::getInfo()
*/
public static function getInfo() {
return array(
'name' => 'Datastream Validator Result Tests',
'description' => 'Unit tests for datastream validation result functionality.',
'group' => 'Islandora',
);
}
/**
* Sets up the test.
*
* @see DrupalWebTestCase::setUp()
*/
public function setUp() {
parent::setUp();
$user = $this->drupalCreateUser(array_keys(module_invoke_all('permission')));
$this->drupalLogin($user);
$object = $this->ingestConstructedObject();
$validator = new TestDatastreamValidator($object, 'DC');
$this->validator_results = $validator->getResults();
}
/**
* Generates a generic DatastreamValidatorResult and grabs its properties.
*/
public function testDatastreamValidatorResult() {
$result = new DatastreamValidatorResult(TRUE, 'true', array());
$this->assertEqual($result->getMessage(), 'true', "Result message generated correctly.", 'Islandora');
$this->assertEqual($result->getType(), TRUE, "Result type generated correctly.", 'Islandora');
$this->assertEqual($result->getCaller(), array(), "Result caller generated correctly.", 'Islandora');
}
/**
* Gets the results of TestDatastreamValidator and confirms only 2 exist.
*/
public function testTestDatastreamValidatorResultCount() {
$this->assertTrue(isset($this->validator_results[0]), "First of two expected results found.", 'Islandora');
$this->assertTrue(isset($this->validator_results[1]), "Second of two expected results found.", 'Islandora');
$this->assertFalse(isset($this->validator_results[2]), "No other unexpected results found.", 'Islandora');
}
/**
* Confirms the messages from TestDatastreamValidator.
*/
public function testTestDatastreamValidatorMessages() {
if (isset($this->validator_results[0]) && isset($this->validator_results[1])) {
$this->assertEqual($this->validator_results[0]->getMessage(), 'yay you did it', "Appropriate pass message returned.", 'Islandora');
$this->assertEqual($this->validator_results[1]->getMessage(), 'boo you failed', "Appropriate fail message returned.", 'Islandora');
}
}
/**
* Confirms the types from TestDatastreamValidator.
*/
public function testTestDatastreamValidatorTypes() {
if (isset($this->validator_results[0]) && isset($this->validator_results[1])) {
$this->assertEqual($this->validator_results[0]->getType(), TRUE, "Appropriate pass type of TRUE returned.", 'Islandora');
$this->assertEqual($this->validator_results[1]->getType(), FALSE, "Appropriate fail type of FALSE returned.", 'Islandora');
}
}
/**
* Confirms the useful information from TestDatastreamValidator.
*/
public function testTestDatastreamValidatorCallers() {
if (isset($this->validator_results[0]) && isset($this->validator_results[1])) {
// Grab the callers.
$first_caller = $this->validator_results[0]->getCaller();
$second_caller = $this->validator_results[1]->getCaller();
// Assert the 'file' key.
$this->assertTrue(substr($first_caller['file'], -48) === '/islandora/tests/datastream_validator_tests.test', "Appropriate pass caller file returned.", 'Islandora');
$this->assertTrue(substr($first_caller['file'], -48) === substr($second_caller['file'], -48), "Fail caller file matches the pass caller file.", 'Islandora');
$this->assertTrue($first_caller['function'] === 'TestDatastreamValidator->assertSomethingSuccessfully()', "Correct pass caller function returned (actual: {$first_caller['function']}; expected: TestDatastreamValidator->assertSomethingSuccessfully()).", 'Islandora');
$this->assertTrue($second_caller['function'] === 'TestDatastreamValidator->assertSomethingFailed()', "Correct fail caller function returned (actual: {$second_caller['function']}; expected: TestDatastreamValidator->assertSomethingFailed()).", 'Islandora');
$this->assertTrue($first_caller['line'] === 18, "Correct pass line number returned (actual: {$first_caller['line']}; expected: 9).", 'Islandora');
$this->assertTrue($second_caller['line'] === 25, "Correct fail line number returned (actual: {$second_caller['line']}; expected: 13).", 'Islandora');
}
}
}
/**
* Procedurally generated tests for DatastreamValidators.
*/
class PrefixDatastreamValidatorTestCase extends IslandoraWebTestCase {
/**
* The path to the datastream validator files.
*
* @var string
*/
protected $path;
/**
* Returns the info for this test case.
*
* @see DrupalWebTestCase::getInfo()
*/
public static function getInfo() {
return array(
'name' => 'Datastream File Validation Tests',
'description' => 'Tests each file in the islandora/tests/fixtures/datastream_validator_files folder against the appropriate DatastreamValidator class (see the README.md in the tests folder for details).',
'group' => 'Islandora',
);
}
/**
* Sets up the test.
*
* @see DrupalWebTestCase::setUp()
*/
public function setUp() {
parent::setUp();
$this->path = DRUPAL_ROOT . drupal_get_path('module', 'islandora') . "/tests/fixtures/datastream_validator_files/";
}
/**
* Confirms that a DatastreamValidator class exists for given filename.
*
* @param string $filename
* The file to grab the DatastreamValidator prefix from.
*
* @return bool
* TRUE if such a class exists; FALSE otherwise.
*/
protected function confirmValidatorClass($filename) {
$prefix = $this->getPrefix($filename);
if (!class_exists("{$prefix}DatastreamValidator")) {
$this->fail("No such DatastreamValidator exists for the prefix $prefix (filename: $filename).");
return FALSE;
}
return TRUE;
}
/**
* Confirms that a file exists at the given path.
*
* Bundled with lovely return values and fail messages.
*
* @param string $path
* The path to the file.
*
* @return bool
* TRUE if the file exists, FALSE otherwise.
*/
protected function confirmValidatorFile($path) {
if (!file_exists($path)) {
$this->fail("No such file exists at path $path.");
return FALSE;
}
return TRUE;
}
/**
* Gets the intended prefix from a filename.
*
* Uses the portion of the filename before the first period.
*
* @param string $filename
* The filename to get the prefix for.
*
* @return string
* The intended prefix.
*/
protected function getPrefix($filename) {
return array_shift(explode('.', $filename));
}
/**
* Create an object with a datastream generated from the given filename.
*
* @param string $filename
* The filename to use when adding a datastream.
*
* @return IslandoraFedoraObject
* The created object.
*/
protected function createObjectWithDatastream($filename) {
$prefix = $this->getPrefix($filename);
if (!$this->confirmValidatorClass($filename) && !$this->confirmValidatorFile($this->path . $filename)) {
return FALSE;
}
$datastreams = array(array(
'dsid' => $prefix,
'path' => $this->path . $filename,
'control_group' => 'M',
),
);
$object = $this->ingestConstructedObject(array(), $datastreams);
return $object;
}
/**
* Procedurally test each file in $this->path against a datastream validator.
*
* Check the README.md in this folder for details.
*/
public function testDatastreamValidators() {
// Grab everything in the validator files folder except for .ini files.
$files = array_intersect(glob("{$this->path}/*"), glob("{$this->path}/*.ini"));
foreach ($files as $file) {
$prefix = $this->getPrefix($file);
// If createObjectWithDatastream fails, we don't want to continue. We'll
// task it with returning fail messages rather than do so here.
$object = $this->createObjectWithDatastream($file);
if ($object !== FALSE) {
// Generate an appropriate validator.
$validator_name = "{$prefix}DatastreamValidator";
// If the file is paired with an .ini, use it as the third param.
if (file_exists("{$this->path}$file.ini")) {
$validator = new $validator_name($object, $prefix, parse_ini_file("{$this->path}$file.ini"));
}
else {
$validator = new $validator_name($object, $prefix);
}
// Get the results, check for fails.
$results = $validator->getResults();
$fails = FALSE;
foreach ($results as $result) {
if (!$result->getType()) {
$fails = TRUE;
$caller = $result->getCaller();
$this->fail("Failed to validate the test file $file against the assertion {$caller['function']}.");
}
}
// If there were no fails, say that the file passed validation.
if (!$fails) {
$this->pass("Test file $file validated successfully.");
}
}
}
}
}

988
tests/datastream_validators.inc

File diff suppressed because it is too large Load Diff

66
tests/islandora_web_test_case.inc

@ -216,37 +216,67 @@ class IslandoraWebTestCase extends DrupalWebTestCase {
/** /**
* Attempts to validate an array of datastreams, generally via binary checks. * Attempts to validate an array of datastreams, generally via binary checks.
* *
* These functions exist in, and can be added to, datastream_validators.inc, * Datastream validation classes exist in, and can be added to, the file
* which is found in this folder. * 'datastream_validators.inc', which is found in this folder. Datastream
* validator classes use the naming convention 'PrefixDatastreamValidator',
* and that 'Prefix' is what this function uses to determine what class to
* instantiate.
* *
* $param AbstractObject $object * $param IslandoraFedoraObject $object
* The object to load datastreams from. * The object to load datastreams from.
* $param array $datastreams * $param array $datastreams
* An array of paired DSIDs, validate function names, and optional params. * An array of arrays that pair DSIDs, DatastreamValidator class prefixes,
* and optional params. You can check some of the existing implementations
* for examples.
*/ */
public function validateDatastreams($object, array $datastreams) { public function validateDatastreams($object, array $datastreams) {
if (!is_object($object)) { if (!is_object($object)) {
$this->fail("Failed. Object passed in is invalid.", 'Islandora'); $this->fail("Datastream validation failed; Object passed in is invalid.", 'Islandora');
return;
} }
module_load_include('inc', 'islandora', 'tests/datastream_validators'); module_load_include('inc', 'islandora', 'tests/datastream_validators');
foreach ($datastreams as $datastream) { foreach ($datastreams as $datastream) {
if (isset($object[$datastream[0]])) { // Let's give them conventional names.
$function = 'islandora_validate_' . $datastream[1] . '_datastream'; $dsid = $datastream[0];
if (function_exists($function)) { $prefix = $datastream[1];
if (isset($datastream[2])) { $params = array();
$results = $function($object, $datastream[0], $datastream[2]); if (isset($datastream[2])) {
} $params = $datastream[2];
else { }
$results = $function($object, $datastream[0]);
} // Legacy tests were created before the CamelCase conventions of the class
foreach ($results as $result) { // system now in place. So, we need to automagically seek out prefixes
$this->assertTrue($result[0], $result[1], 'Islandora'); // that start with a lower-case letter and convert them to the proper
} // format (rather than fixing every single legacy test).
if (ctype_lower(substr($prefix, 0, 1))) {
// Handle the case where the prefix is "image".
if ($prefix === 'image') {
$prefix = 'Image';
} }
// Handle the case where the prefix is "text".
elseif ($prefix === 'text') {
$prefix = 'Text';
}
// All other cases involve just converting everything to caps.
else { else {
$this->fail("No {$datastream[0]} validation function exists for the {$datastream[1]} datastream.", 'Islandora'); $prefix = strtoupper($prefix);
}
}
// Instantiate the appropriate class, and grab the results.
$class_name = "{$prefix}DatastreamValidator";
if (class_exists($class_name)) {
$validator = new $class_name($object, $dsid, $params);
foreach ($validator->getResults() as $result) {
$this->assert($result->getType(), $result->getMessage(), 'Islandora', $result->getCaller());
} }
} }
else {
$this->fail("No DatastreamValidator class was found with the name '$class_name'; are you sure the prefix given to IslandoraWebTestCase->validateDatastreams() was entered correctly, or that such a validator exists?", 'Islandora');
}
} }
} }

Loading…
Cancel
Save