From c6beca5ae8b1fea0453f23b5885f21befb526479 Mon Sep 17 00:00:00 2001 From: Nelson Hart Date: Wed, 4 Sep 2013 09:17:07 -0300 Subject: [PATCH 01/59] allow mulitple mime types for viewers --- includes/solution_packs.inc | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/includes/solution_packs.inc b/includes/solution_packs.inc index 7cf0351a..337f76c4 100644 --- a/includes/solution_packs.inc +++ b/includes/solution_packs.inc @@ -679,11 +679,17 @@ function islandora_viewers_form($variable_id = NULL, $mimetype = NULL, $model = function islandora_get_viewers($mimetype = NULL, $content_model = NULL) { $viewers = array(); $defined_viewers = module_invoke_all('islandora_viewer_info'); + + if(!is_array($mimetype)) { + $mimetype = array($mimetype); + } + // Filter viewers by MIME type. foreach ($defined_viewers as $key => $value) { $value['mimetype'] = isset($value['mimetype']) ? $value['mimetype'] : array(); $value['model'] = isset($value['model']) ? $value['model'] : array(); - if (in_array($mimetype, $value['mimetype']) OR in_array($content_model, $value['model'])) { + if (array_intersect($mimetype, $value['mimetype']) OR in_array($content_model, $value['model'])) { + //if (in_array($mimetype, $value['mimetype']) OR in_array($content_model, $value['model'])) { $viewers[$key] = $value; } } From f486133fbbe72869ee50fe86eb965a85091cab25 Mon Sep 17 00:00:00 2001 From: Nelson Hart Date: Wed, 12 Feb 2014 10:44:56 -0400 Subject: [PATCH 02/59] remove comment --- includes/solution_packs.inc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/includes/solution_packs.inc b/includes/solution_packs.inc index 30cc8576..6f4b4ae3 100644 --- a/includes/solution_packs.inc +++ b/includes/solution_packs.inc @@ -256,7 +256,7 @@ function islandora_solution_pack_form_submit(array $form, array &$form_state) { * the batch. * @param array $not_checked * The object that will bot be install. - * + * * @return array * An array defining a batch which can be passed on to batch_set(). */ @@ -735,7 +735,6 @@ function islandora_get_viewers($mimetype = NULL, $content_model = NULL) { $value['mimetype'] = isset($value['mimetype']) ? $value['mimetype'] : array(); $value['model'] = isset($value['model']) ? $value['model'] : array(); if (array_intersect($mimetype, $value['mimetype']) OR in_array($content_model, $value['model'])) { - //if (in_array($mimetype, $value['mimetype']) OR in_array($content_model, $value['model'])) { $viewers[$key] = $value; } } From 3bdd909e15d5f3b340d3d97aff8fac0426782d21 Mon Sep 17 00:00:00 2001 From: Nelson Hart Date: Wed, 12 Feb 2014 10:49:42 -0400 Subject: [PATCH 03/59] docs update for array of mime types --- includes/solution_packs.inc | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/includes/solution_packs.inc b/includes/solution_packs.inc index 6f4b4ae3..0ff7d253 100644 --- a/includes/solution_packs.inc +++ b/includes/solution_packs.inc @@ -712,9 +712,8 @@ function islandora_viewers_form($variable_id = NULL, $mimetype = NULL, $model = * given, than any viewer that supports either the give $mimetype or $model will * be listed. * - * @param string $mimetype - * Specify a mimetype to return only viewers that support this certain - * mimetype. + * @param array $mimetype + * List of mimetypes that the view supports. * @param string $content_model * Specify a content model to return only viewers that support the content * model. @@ -722,7 +721,7 @@ function islandora_viewers_form($variable_id = NULL, $mimetype = NULL, $model = * @return array * Viewer definitions, or FALSE if none are found. */ -function islandora_get_viewers($mimetype = NULL, $content_model = NULL) { +function islandora_get_viewers($mimetype = array(), $content_model = NULL) { $viewers = array(); $defined_viewers = module_invoke_all('islandora_viewer_info'); From ecb4f09766176fcc0564916f9f046afdf09adea2 Mon Sep 17 00:00:00 2001 From: Nelson Hart Date: Wed, 12 Feb 2014 10:50:43 -0400 Subject: [PATCH 04/59] spelling --- includes/solution_packs.inc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/includes/solution_packs.inc b/includes/solution_packs.inc index 0ff7d253..d875bc69 100644 --- a/includes/solution_packs.inc +++ b/includes/solution_packs.inc @@ -713,7 +713,7 @@ function islandora_viewers_form($variable_id = NULL, $mimetype = NULL, $model = * be listed. * * @param array $mimetype - * List of mimetypes that the view supports. + * List of mimetypes that the viewer supports. * @param string $content_model * Specify a content model to return only viewers that support the content * model. From 656d2b13058ada19e0a9a7dd670a0826dcf4370e Mon Sep 17 00:00:00 2001 From: Nelson Hart Date: Thu, 13 Feb 2014 14:58:37 -0400 Subject: [PATCH 05/59] cs fixes --- includes/solution_packs.inc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/includes/solution_packs.inc b/includes/solution_packs.inc index d875bc69..0209ecbd 100644 --- a/includes/solution_packs.inc +++ b/includes/solution_packs.inc @@ -725,7 +725,7 @@ function islandora_get_viewers($mimetype = array(), $content_model = NULL) { $viewers = array(); $defined_viewers = module_invoke_all('islandora_viewer_info'); - if(!is_array($mimetype)) { + if (!is_array($mimetype)) { $mimetype = array($mimetype); } From 9a7acddf2a65c1701b2bc5e60f7c2bc42c4f0866 Mon Sep 17 00:00:00 2001 From: qadan Date: Sat, 22 Feb 2014 18:24:05 +0000 Subject: [PATCH 06/59] datastream validation objectively rather than procedurally --- tests/datastream_validators.inc | 964 +++++++++++++++++++----------- tests/islandora_web_test_case.inc | 71 ++- tests/scripts/travis_setup.sh | 10 +- 3 files changed, 678 insertions(+), 367 deletions(-) diff --git a/tests/datastream_validators.inc b/tests/datastream_validators.inc index 4c69788b..1428321b 100644 --- a/tests/datastream_validators.inc +++ b/tests/datastream_validators.inc @@ -1,59 +1,9 @@ TRUE); + + /** + * The IslandoraFedoraObject containing the datastream to test. + * + * @var IslandoraFedoraObject + */ + public $object; + + /** + * The DSID of the string to test. + * + * @var string + */ + public $datastream; + + /** + * The content of the datastream. + * + * @var string[] + */ + public $datastreamContent; + + /** + * An associative array of messages returned from passed tests, and callers. + * + * This should only be added to using $this->addPass(), so that the caller can + * be appropriately determined. + * + * @var array + */ + public $passes = array(); + + /** + * An associative array of messages returned from failed tests, and callers. + * + * This should only be added to using $this->addFail(), so that the caller can + * be appropriately determined. + * + * @var array + */ + public $fails = array(); + + /** + * An array of additional required parameters. + * + * @var array + */ + public $params = array(); + + /** + * Constructs a DatastreamValidator. + * + * @param IslandoraFedoraObject $object + * The object to grab the datastream from. + * @param string $datastream + * The DSID of the datastream itself. + * @param array $params + * An extra array of parameters the validator might need. + */ + public function __construct($object, $datastream, array $params = array()) { + $this->object = $object; + $this->datastream = $datastream; + $this->params = $params; + $this->datastreamContent = $object[$datastream]->content; + $this->runValidators(); + } + + /** + * Helper function to run all the validators in a class. + * + * On DatastreamValidator::__construct(), this looks for any functions + * within the class beginning in "assert" and runs them. In all current cases + * (and realistically in all future cases), this adds one or more passes or + * fails to $this->passes and/or $this->fails. + */ + public function runValidators() { + $methods = get_class_methods($this); + foreach ($methods as $method) { + if (substr($method, 0, 6) === 'assert') { + $this->$method(); + } + } + } + + /** + * Returns an array of pass messages. + * + * @return string[] + * The pass messages. + */ + public function getPasses() { + return $this->passes; + } + + /** + * Returns an array of fail messages. + * + * @return string[] + * The fail messages. + */ + public function getFails() { + return $this->fails; + } + + /** + * Adds a pass to $this->pass. + * + * Passes are an associative array of messages and callers. Callers should be + * obtained using $this->getAssertionCall(). + * + * @param string $message + * The message to use. + */ + public function addPass($message) { + $this->passes[$message] = $this->getAssertionCall(); + } + + /** + * Adds a fail to $this->fail. + * + * Fails are an associative array of messages and callers. Callers should be + * obtained using $this->getAssertionCall(). + * + * @param string $message + * The message to use. + */ + public function addFail($message) { + $this->fails[$message] = $this->getAssertionCall(); + } + + /** + * Cycles through backtrace until the first non-assertion method is found. + * + * This is a manipulated version of DrupalWebTestCase::getAssertionCall(). + * We use it here so that we can pass back assertion calls from + * DatastreamValidator assertions instead of less useful TestCase functions. + * + * @return array + * Array representing the true caller. + */ + protected function getAssertionCall() { + $backtrace = debug_backtrace(); + + // While the current caller's function starts with 'assert', and another one + // exists after this function, keep poppin' em off. + while (substr($backtrace[1]['function'], 0, 6) !== 'assert' && isset($backtrace[2])) { + array_shift($backtrace); + } + + return _drupal_get_last_caller($backtrace); + } + +} + /** * Asserts that an object's given datastreams are common-type image files. * * Uses PHPGD to run the assertion check. This means that only certain kinds * of image files can be checked. Please check the documentation for the PHPGD * imagecreatefromstring() function to determine what filetypes are valid. - * - * @param AbstractObject $object - * The PID of the object. - * @param string $datastream - * A DSID to check that corresponds to a PHPGD-valid image datastream. - * - * @return array - * A series of TRUE(pass)/FALSE(fail) results paired with result messages. */ -function islandora_validate_image_datastream($object, $datastream) { - $datastream_string = $object[$datastream]->content; - $results = array(); - $pass = "Image datastream {$datastream} is valid."; - $fail = "Image datastream {$datastream} is either invalid or corrupt."; - $results = islandora_assert_valid(imagecreatefromstring($datastream_string), $results, $pass, $fail); - return $results; +class ImageDatastreamValidator extends DatastreamValidator { + + /** + * Asserts the validity of an image using PHPGD. + */ + protected function assertImageGeneration() { + if (imagecreatefromstring($this->datastreamContent) !== FALSE) { + $this->addPass("Image datastream {$this->datastream} is valid."); + } + else { + $this->addFail("Image datastream {$this->datastream} is either invalid or corrupt."); + } + } + } /** * Asserts the validity of any .tif/.tiff datastream. - * - * Does not use the islandora_assert_valid() function, as this is not a simple - * true/false. - * - * @param AbstractObject $object - * The PID of the object. - * @param string $datastream - * A DSID to check that corresponds to a .tif/.tiff datastream. - * - * @return array - * A series of TRUE(pass)/FALSE(fail) results paired with result messages. */ -function islandora_validate_tiff_datastream($object, $datastream) { - $datastream_string = $object[$datastream]->content; - $datastream_header_hex = substr(bin2hex($datastream_string), 0, 8); - $results = array(); - if ($datastream_header_hex == "49492a00") { - // In this case, the ingested TIFF is designated as using the "Intel - // byte-order" (e.g. little-endian) by starting with the characters "II" - // (repeated so that byte order does not yet need to be significant). - // The number that follows is '42' in little-endian hex, a number of - // 'deep philosophical significance' to the TIFF format creators. - array_push($results, array(TRUE, "{$datastream} datastream asserts that it is a valid Intel-byte-orderded TIF/TIFF file.")); - } - elseif ($datastream_header_hex == "4d4d002a") { - // In this case, the ingested TIFF is designated as using the "Motorola - // byte-order" (e.g. big-endian) by starting with the characters "MM" - // instead. 42 follows once again, this time in big-endian hex. - array_push($results, array(TRUE, "{$datastream} datastream asserts that it is a valid Motorola-byte-ordered TIF/TIFF file.")); - } - else { - array_push($results, array(FALSE, "{$datastream} datastream does not assert that it is a valid TIF/TIFF file.")); - } - return $results; +class TIFFDatastreamValidator extends DatastreamValidator { + + /** + * Asserts that the TIFF contains an appropriate header. + */ + public function assertTIFFHeaderHex() { + $datastream_header_hex = self::getTIFFHeaderHex(); + if ($datastream_header_hex == "49492a00") { + // In this case, the ingested TIFF is designated as using the "Intel + // byte-order" (i.e. little-endian) by starting with the characters "II" + // (repeated so that byte order does not yet need to be significant). + // The number that follows is '42' in little-endian hex, a number of + // 'deep philosophical significance' to the TIFF format creators. + $this->addPass("{$this->datastream} datastream asserts that it is a valid Intel-byte-orderded TIF/TIFF file."); + } + elseif ($datastream_header_hex == "4d4d002a") { + // In this case, the ingested TIFF is designated as using the "Motorola + // byte-order" (i.e. big-endian) by starting with the characters "MM" + // instead. 42 follows once again, this time in big-endian hex. + $this->addPass("{$this->datastream} datastream asserts that it is a valid Motorola-byte-ordered TIF/TIFF file."); + } + else { + $this->addFail("{$this->datastream} datastream does not assert that it is a valid TIF/TIFF file."); + } + } + + /** + * Grabs the first 8 characters from the TIFF datastream's hex. + * + * @return string + * The ... thing I just wrote up there. + */ + protected function getTIFFHeaderHex() { + return substr(bin2hex($this->datastreamContent), 0, 8); + } + } /** - * Asserts the validity of any .jp2 datastream. - * - * @param AbstractObject $object - * The PID of the object. - * @param string $datastream - * A DSID to check that corresponds to a .jp2 datastream. - * - * @return array - * A series of TRUE(pass)/FALSE(fail) results paired with result messages. + * Asserts the validity of a JP2 datastream. */ -function islandora_validate_jp2_datastream($object, $datastream) { - $datastream_hex = bin2hex($object[$datastream]->content); - $results = array(); - // JP2 files begin with an offset header at the second 32-bit integer, - // 0x6A502020. This header is in all .jp2s, and we check for it here. - $pass = "{$datastream} datastream begins correctly with the appropriate .jp2 header."; - $fail = "{$datastream} datastream does not begin with the appropriate .jp2 header."; - $results = islandora_assert_valid(substr($datastream_hex, 8, 8) == '6a502020', $results, $pass, $fail); - // JP2 files have their codestream capped with a marker, 0xFFD9. We're - // just checking for it here to see if the .jp2 encoder finished okay. - $pass = "{$datastream} datastream ends correctly with the appropriate .jp2 marker."; - $fail = "{$datastream} datastream does not end with a .jp2 marker; derivative generation was likely interrupted."; - $results = islandora_assert_valid(substr($datastream_hex, strlen($datastream_hex) - 4, 4) == 'ffd9', $results, $pass, $fail); - return $results; +class JP2DatastreamValidator extends DatastreamValidator { + + /** + * Asserts the hex values at the head of the JP2 file. + * + * JP2 files begin with an offset header at the second 32-bit integer, + * 0x6A502020. This header is in all .jp2s, and we check for it here. + */ + protected function assertJP2Header() { + if (substr(bin2hex($this->datastreamContent), 8, 8) == '6a502020') { + $this->addPass("Datastream {$this->datastream} contains the appropriate JP2 header."); + } + else { + $this->addFail("Datastream {$this->datastream} does not contain the appropriate JP2 header."); + } + } + + /** + * Asserts the marker at the end of the JP2 file. + * + * JP2 files have their codestream capped with a marker, 0xFFD9. We're just + * checking for it here to see if the .jp2 encoder finished okay. + */ + protected function assertJP2Marker() { + if (substr(bin2hex($this->datastreamContent), strlen(bin2hex($this->datastreamContent)) - 4, 4) == 'ffd9') { + $this->addPass("Datastream {$this->datastream} contains the appropriate JP2 ending marker."); + } + else { + $this->addFail("Datastream {$this->datastream} does not contain the appropriate JP2 ending marker. If this is the only JP2 validator that failed, it is likely that derivative generation was interrupted."); + } + } } /** - * Asserts the validity of any .pdf datastream. - * - * @param AbstractObject $object - * The PID of the object. - * @param string $datastream - * A DSID to check that corresponds to a .pdf datastream. - * - * @return array - * A series of TRUE(pass)/FALSE(fail) results paired with result messages. + * Asserts the validity of a PDF datastream. */ -function islandora_validate_pdf_datastream($object, $datastream) { - $pdf = $object[$datastream]->content; - $pdf_version = substr($pdf, 5, 3); - $results = array(); - $pass = "{$datastream} datastream asserts that it is a valid PDF file using PDF version {$pdf_version}"; - $fail = "{$datastream} datastream binary header appears to be corrupt and missing a valid PDF signature."; - $results = islandora_assert_valid(substr($pdf, 0, 5) == '%PDF-', $results, $pass, $fail); - - $pdf_streams = substr_count(bin2hex($pdf), '0a73747265616d0a'); - $pass = "{$datastream} datastream reports the existence of {$pdf_streams} PDF streams. Note that an extremely low number could still indicate corruption."; - $fail = "{$datastream} datastream contains zero PDF streams, and is likely not a PDF file."; - $results = islandora_assert_valid($pdf_streams, $results, $pass, $fail); - - $pass = "{$datastream} datastream reports the existence of the closing 'EOF' tag required at the end of PDFs"; - $fail = "{$datastream} datastream does not contain the closing 'EOF' tag. If this is the only PDF validation that failed, it is likely that derivative generation was interrupted."; - $results = islandora_assert_valid(strpos(bin2hex($pdf), '0a2525454f460a'), $results, $pass, $fail); - return $results; +class PDFDatastreamValidator extends DatastreamValidator { + + /** + * Validates the PDF signature. + */ + protected function assertPDFSignature() { + if (substr($this->datastreamContent, 0, 5) == '%PDF-') { + $pdf_version = substr($this->datastreamContent, 5, 3); + $this->addPass("{$this->datastream} datastream asserts that it is a valid PDF file using PDF version {$pdf_version}"); + } + else { + $this->addFail("{$this->datastream} datastream binary header appears to be corrupt and missing a valid PDF signature."); + } + } + + /** + * Counts the number of signatures in this PDF file and asserts there are any. + */ + protected function assertPDFStreamCount() { + $pdf_stream_count = substr_count(bin2hex($this->datastreamContent), '0a73747265616d0a'); + if ($pdf_stream_count !== 0) { + $this->addPass("{$this->datastream} datastream reports the existence of {$pdf_stream_count} PDF streams. Note that an extremely low number could still indicate corruption."); + } + else { + $this->addFail("{$this->datastream} datastream contains zero PDF streams, and is likely not a PDF file."); + } + } + + /** + * Validates the PDF closing tag. + * + * @return bool + * TRUE if it was present; FALSE otherwise. + */ + protected function assertPDFClosingTag() { + if (strpos(bin2hex($this->datastreamContent), '0a2525454f460a')) { + $this->addPass("{$this->datastream} datastream reports the existence of the closing 'EOF' tag required at the end of PDFs"); + } + else { + $this->addFail("{$this->datastream} datastream does not contain the closing 'EOF' tag. If this is the only PDF validation that failed, it is likely that derivative generation was interrupted."); + } + } } /** - * Asserts that a string of text shows up inside a datastream. - * - * @param AbstractObject $object - * The PID of the object. - * @param string $datastream - * A DSID to check that corresponds to a datastream containing text. - * @param array $text - * An array of strings/the number of times it should appear in the datastream. + * Validates the number of times a string occurs in a datastream. * - * @return array - * A series of TRUE(pass)/FALSE(fail) results paired with result messages. + * Requires $this->params to be set to an array containing two keys - the first + * is the string we're looking to find in the datastream, and the second is an + * integer representing the number of times it should appear in the datastream. */ -function islandora_validate_text_datastream($object, $datastream, array $text) { - $results = array(); - $content = $object[$datastream]->content; - $string_count = substr_count($content, $text[0]); - $pass = "{$datastream} datastream contains the word(s) '{$text[0]}' repeated {$string_count} time(s) (expected: {$text[1]})."; - $fail = "{$datastream} datastream contains the word(s) '{$text[0]}' repeated {$string_count} time(s) (expected: {$text[1]})."; - $results = islandora_assert_valid($string_count == $text[1], $results, $pass, $fail); - return $results; +class TextDatastreamValidator extends DatastreamValidator { + + /** + * Asserts that the string given appears the correct number of times. + */ + protected function assertTextStringCount() { + if (!isset($this->params[1])) { + $this->addFail("TextDatastreamValidator cannot be instantiated without two keys in the 'params' variable."); + return; + } + $string_count = self::getTextStringCount(); + $expected = $this->params[1]; + $function = $string_count === $expected ? 'addPass' : 'addFail'; + $this->$function("{$this->datastream} datastream contains the word(s) '{$this->params[0]}' repeated {$string_count} time(s) (expected: {$expected})."); + } + + /** + * The number of times key [0] in $this->params appears in the datastream. + * + * @return int + * That count I just mentioned up there. + */ + protected function getTextStringCount() { + return substr_count($this->datastreamContent, $this->params[0]); + } } /** - * Asserts the validity of any .wav datastraeam. + * Asserts the validity a WAV datastream. * * WAV files contain a rigidly detailed header that contains all sorts of fun * information we can use to validate things against other things. So, we check @@ -242,54 +416,140 @@ function islandora_validate_text_datastream($object, $datastream, array $text) { * see if certain values are at their expected byte offset. We also compare * declared chunk sizes against actual sizes. If any of these are off, WAV * players will fail to function. - * - * @param AbstractObject $object - * The PID of the object. - * @param string $datastream - * A DSID to check that corresponds to a datastream generated via OCR or HOCR. - * - * @return array - * A series of TRUE(pass)/FALSE(fail) results paired with result messages. */ -function islandora_validate_wav_datastream($object, $datastream) { - $results = array(); - $wav = bin2hex($object['OBJ']->content); - $wav_subchunk2size = islandora_hex2int(substr($wav, 80, 8)); - $wav_samplerate = islandora_hex2int(substr($wav, 48, 8)); - $wav_numchannels = islandora_hex2int(substr($wav, 44, 4)); - $wav_bytespersample = islandora_hex2int(substr($wav, 68, 4)) / 8; - $wav_numsamples = strlen(substr($wav, 88)) / $wav_numchannels / $wav_bytespersample / 2; - $magic_number = str_split(substr($wav, 0, 24), 8); - - $pass = "Header of the {$datastream} datastream contains correct file signature"; - $fail = "Header of the {$datastream} datastream contains corrupt file signature"; - $results = islandora_assert_valid($magic_number[0] = '52494646' && $magic_number[2] = '57415645', $results, $pass, $fail); - - $pass = "{$datastream} datastream chunksize in WAV header is correct"; - $fail = "{$datastream} datastream chunksize in WAV header does not match actual chunksize."; - $results = islandora_assert_valid(islandora_hex2int(substr($wav, 8, 8)) === 36 + $wav_subchunk2size, $results, $pass, $fail); - - $pass = "{$datastream} datastream contains a 'fmt' subchunk."; - $fail = "{$datastream} datastream is missing the required 'fmt' subchunk."; - $results = islandora_assert_valid(substr($wav, 24, 8) === '666d7420', $results, $pass, $fail); - - $pass = "{$datastream} datastream byterate in the WAV header is correct."; - $fail = "{$datastream} datastream byterate in the WAV header does not match actual calculated byterate."; - $results = islandora_assert_valid(islandora_hex2int(substr($wav, 56, 8)) === $wav_samplerate * $wav_numchannels * $wav_bytespersample, $results, $pass, $fail); - - $pass = "{$datastream} datastream block alignment is set correctly."; - $fail = "{$datastream} datastream block alignment is off."; - $results = islandora_assert_valid(islandora_hex2int(substr($wav, 64, 4)) === $wav_numchannels * $wav_bytespersample, $results, $pass, $fail); - - $pass = "{$datastream} datastream contains 'data' subchunk."; - $fail = "{$datastream} datastream is missing the 'data' subchunk."; - $results = islandora_assert_valid(substr($wav, 72, 8) === '64617461', $results, $pass, $fail); - - $pass = "{$datastream} datastream 'data' chunk is the correct size."; - $fail = "{$datastream} datastream 'data' chunk is sized incorrectly."; - $results = islandora_assert_valid($wav_subchunk2size === $wav_numsamples * $wav_numchannels * $wav_bytespersample, $results, $pass, $fail); - - return $results; +class WAVDatastreamValidator extends DatastreamValidator { + + /** + * We need a special constructor here to get the hex datastream content. + * + * @param IslandoraFedoraObject $object + * The object to grab the datastream from. + * @param string $datastream + * The DSID of the datastream itself. + * @param array $params + * An extra array of parameters the validator might need. + */ + public function __construct($object, $datastream, array $params = array()) { + $this->object = $object; + $this->datastream = $datastream; + $this->params = $params; + $this->datastreamContent = bin2hex($object[$datastream]->content); + $this->runValidators(); + } + + /** + * Asserts that the datastream contains a valid WAV signature. + */ + protected function assertWAVSignature() { + $signatures = str_split(substr($this->datastreamContent, 0, 24), 8); + if ($signatures[0] = '52494646' && $signatures[2] = '57415645') { + $this->addPass("Header of the {$this->datastream} datastream contains a valid file signature."); + } + else { + $this->addFail("Header of the {$this->datastream} datastream contains corrupt file signature."); + } + } + + /** + * Asserts that the chunksize in the header is correct. + */ + protected function assertWAVChunkSize() { + if (islandora_hex2int(substr($this->datastreamContent, 8, 8)) === 36 + self::getDataSubChunkSize()) { + $this->addPass("{$this->datastream} datastream chunksize in WAV header is correct"); + } + else { + $this->addFail("{$this->datastream} datastream chunksize in WAV header does not match actual chunksize."); + } + } + + /** + * Asserts that the datastream contains a 'fmt' subchunk. + */ + protected function assertWAVFmtSubChunk() { + if (substr($this->datastreamContent, 24, 8) === '666d7420') { + $this->addPass("{$this->datastream} datastream contains a 'fmt' subchunk."); + } + else { + $this->addFail("{$this->datastream} datastream is missing the required 'fmt' subchunk."); + } + } + + /** + * Asserts that the byterate reported by the WAV header is valid. + */ + protected function assertWAVByteRate() { + $wav_samplerate = islandora_hex2int(substr($this->datastreamContent, 48, 8)); + if (islandora_hex2int(substr($this->datastreamContent, 56, 8)) === $wav_samplerate * self::getNumChannels() * self::getBytesPerSample()) { + $this->addPass("{$this->datastream} datastream byterate in the WAV header is correct."); + } + else { + $this->addFail("{$this->datastream} datastream byterate in the WAV header does not match actual calculated byterate."); + } + } + + /** + * Asserts that the block alignment is correct. + */ + protected function assertWAVBlockAlignment() { + if (islandora_hex2int(substr($this->datastreamContent, 64, 4)) === self::getNumChannels() * self::getBytesPerSample()) { + $this->addPass("{$this->datastream} datastream block alignment is set correctly."); + } + else { + $this->addFail("{$this->datastream} datastream block alignment is off."); + } + } + + /** + * Asserts the existence of a 'data' subchunk. + * + * Also asserts that the subchunk size is correct. + */ + protected function assertWAVDataSubChunk() { + if (substr($this->datastreamContent, 72, 8) !== '64617461') { + $this->addFail("{$this->datastream} datastream is missing the 'data' subchunk."); + return; + } + else { + $this->addPass("{$this->datastream} datastream contains 'data' subchunk."); + $wav_numsamples = strlen(substr($this->datastreamContent, 88)) / self::getNumChannels() / self::getBytesPerSample() / 2; + if (self::getDataSubChunkSize() === $wav_numsamples * self::getNumChannels() * self::getBytesPerSample()) { + $this->addPass("{$this->datastream} datastream 'data' chunk is the correct size."); + } + else { + $this->addFail("{$this->datastream} datastream 'data' chunk is sized incorrectly."); + } + } + } + + /** + * Gets the number of channels reported by the WAV header. + * + * @return int + * The number of channels reported by the datastream header. + */ + protected function getNumChannels() { + return islandora_hex2int(substr($this->datastreamContent, 44, 4)); + } + + /** + * Gets the reported number of byte rates per sample. + * + * @return int + * The number of bytes per sample reported by the datastream header. + */ + protected function getBytesPerSample() { + return islandora_hex2int(substr($this->datastreamContent, 68, 4)) / 8; + } + + /** + * Gets the size of the 'data' subchunk. + * + * @return int + * The size of the 'data' subchunk. + */ + protected function getDataSubChunkSize() { + return islandora_hex2int(substr($this->datastreamContent, 80, 8)); + } } /** @@ -300,76 +560,89 @@ function islandora_validate_wav_datastream($object, $datastream) { * 'Xing', it is flagged as VBR, and we can do an in-depth check on each of the * VBR settings. Otherwise, we look for the basic MP3 signature 'fffa' or 'fffb' * at the start of the binary. - * - * @param AbstractObject $object - * The PID of the object. - * @param string $datastream - * A DSID of a datastream corresponding to an mp3 file. - * - * @return array - * A series of TRUE(pass)/FALSE(fail) results paired with result messages. */ -function islandora_validate_mp3_datastream($object, $datastream) { - $results = array(); - $mp3 = bin2hex($object[$datastream]->content); - $mp3_size = strlen($mp3) / 2; - - // Looks to see if VBR was set properly by LAME. If so, MATH TIME! - if (strpos($mp3, '58696e67')) { - $mp3_vbrheader = substr($mp3, strpos($mp3, '58696e67'), 240); - - // Check the field flags. VBR-formatted MP3 files contain a 32-bit - // integer (stored as $mp3_flag_value) that is a combination of four - // bits, each one indicating the on-off status of a VBR setting, via - // logical OR. Rather than disassembling this value into individual - // bits, we use the algorithm "if (binary_total+bit_value*2)/bit_value*2 - // is greater than or equal to bit_value, that bit is turned on" to find - // the status of each bit, so we know whether to offset the rest. - $mp3_field_offset = array(0, 0, 0); - $mp3_flag_value = hexdec(substr($mp3_vbrheader, 8, 8)); - - // We can't use the first flag, but we still need to offset the rest. - if (($mp3_flag_value + 1) % 2 == 0) { - $mp3_field_offset[0] += 8; - $mp3_field_offset[1] += 8; - $mp3_field_offset[2] += 8; +class MP3DatastreamValidator extends DatastreamValidator { + + /** + * Asserts the validity of the MP3. + * + * The MP3 file format is a bit of a mess; the entire makeup of the file + * depends on whether it uses variable bit rate or static bit rate. So, I'm + * breaking my own rules here and using a single assert function so that I + * can handle the weird logic. + */ + protected function assertValidMP3() { + $this->datastreamContent = bin2hex($this->datastreamContent); + + // If it's not a VBR MP3, we don't have to check much, so let's get that + // out of the way first before we go doing a bunch of potentially pointless + // math. Check to see if the VBR flag (58696e67) isn't there. + if (strpos($this->datastreamContent, '58696e67') == FALSE && substr($this->datastreamContent, 0, 4) == 'fffa') { + $this->addPass("{$this->datastream} datastream is encoded as a valid MPEG-1 Layer 3 file with CRC protection"); + return; } - - // The second flag leads us to filesize data, which we can verify. - if (($mp3_flag_value + 4) % 4 > 1) { - $mp3_field_bytes = hexdec(substr($mp3_vbrheader, $mp3_field_offset[0] + 16, 8)); - $pass = "{$datastream} datastream reported filesize of {$mp3_size} bytes matches size field value of {$mp3_field_bytes}"; - $fail = "{$datastream} datastream reported filesize of {$mp3_size} bytes does not match size field value of {$mp3_field_bytes}"; - $results = islandora_assert_valid($mp3_size == $mp3_field_bytes, $results, $pass, $fail); - $mp3_field_offset[1] += 8; - $mp3_field_offset[2] += 8; + if (strpos($this->datastreamContent, '58696e67') == FALSE && substr($this->datastreamContent, 0, 4) == 'fffb') { + $this->addPass("{$this->datastream} datastream is encoded as a valid unprotected MPEG-1 Layer 3 file"); + return; } - // We can't use the third flag for anything either. - if (($mp3_flag_value + 8) % 8 > 3) { - $mp3_field_offset[2] += 200; + // And what if the flag IS set? + if (strpos($this->datastreamContent, '58696e67')) { + // Check the field flags. VBR-formatted MP3 files contain a 32-bit + // integer (stored as $mp3_flag_value) that is a combination of four + // bits, each one indicating the on-off status of a VBR setting, via + // logical OR. Rather than disassembling this value into individual + // bits, we use the algorithm "if (binary_total+bit_value*2)/bit_value*2 + // is greater than or equal to bit_value, that bit is turned on" to find + // the status of each bit, so we know whether to offset the rest. + $mp3_field_offset = array(0, 0, 0); + $mp3_vbrheader = substr($this->datastreamContent, strpos($this->datastreamContent, '58696e67'), 240); + $mp3_flag_value = hexdec(substr($mp3_vbrheader, 8, 8)); + + // We can't use the first flag, but we still need to offset the rest. + if (($mp3_flag_value + 1) % 2 == 0) { + $mp3_field_offset[0] += 8; + $mp3_field_offset[1] += 8; + $mp3_field_offset[2] += 8; + } + + // The second flag leads us to filesize data, which we can verify. + if (($mp3_flag_value + 4) % 4 > 1) { + $mp3_field_bytes = hexdec(substr($mp3_vbrheader, $mp3_field_offset[0] + 16, 8)); + $mp3_size = strlen($this->datastreamContent) / 2; + if ($mp3_size == $mp3_field_bytes) { + $this->addPass("{$this->datastream} datastream reported filesize of {$mp3_size} bytes matches size field value of {$mp3_field_bytes}"); + } + else { + $this->addFail("{$this->datastream} datastream reported filesize of {$mp3_size} bytes does not match size field value of {$mp3_field_bytes}"); + } + $mp3_field_offset[1] += 8; + $mp3_field_offset[2] += 8; + } + + // We can't use the third flag for anything, but we still have to offset. + if (($mp3_flag_value + 8) % 8 > 3) { + $mp3_field_offset[2] += 200; + } + + // The fourth flag leads us to VBR quality data, which we can validate. + if ($mp3_flag_value > 7) { + $mp3_field_quality = hexdec(substr($mp3_vbrheader, $mp3_field_offset[2] + 16, 8)); + if ($mp3_field_quality <= 100 && $mp3_field_quality >= 0) { + $this->addPass("{$this->datastream} datastream reports valid VBR quality of {$mp3_field_quality} (expected: between 0-100)"); + } + else { + $this->addFail("{$this->datastream} datastream reports invalid VBR quality of {$mp3_field_quality} (expected: between 0-100)"); + } + } } - // The fourth flag leads us to VBR quality data, which we can validate. - if ($mp3_flag_value > 7) { - $mp3_field_quality = hexdec(substr($mp3_vbrheader, $mp3_field_offset[2] + 16, 8)); - $pass = "{$datastream} datastream reports valid VBR quality of {$mp3_field_quality} (expected: between 0-100)"; - $fail = "{$datastream} datastream reports invalid VBR quality of {$mp3_field_quality} (expected: between 0-100)"; - $results = islandora_assert_valid($mp3_field_quality <= 100 && $mp3_field_quality >= 0, $results, $pass, $fail); + // If none of that works out, fail. + else { + $this->addFail("{$this->datastream} datastream is corrupt and does not identify as a valid MP3."); } } - // Otherwise, just forget everything and check the file signature. - elseif (strpos($mp3, '58696e67') == FALSE && substr($mp3, 0, 4) == 'fffa') { - $results = array(array(TRUE, "{$datastream} datastream is encoded as a valid MPEG-1 Layer 3 file with CRC protection")); - } - elseif (strpos($mp3, '58696e67') == FALSE && substr($mp3, 0, 4) == 'fffb') { - $results = array(array(TRUE, "{$datastream} datastream is encoded as a valid unprotected MPEG-1 Layer 3 file")); - } - else { - $results = array(array(FALSE, "{$datastream} datastream is corrupt and does not identify as a valid MP3.")); - } - return $results; } /** @@ -378,27 +651,23 @@ function islandora_validate_mp3_datastream($object, $datastream) { * MP4 files are a subset of the ISO file format specification, and as such need * to contain a 64-bit declaration of type within the first eight eight bytes of * the file. This declaration is comprised of the characters 'ftyp', followed by - * a four-character filetype code. Below, we look for 'ftyp', and then pass the + * a four-character filetype code. Here, we look for 'ftyp', and then pass the * filetype code to the test message. - * - * @param AbstractObject $object - * The PID of the object. - * @param string $datastream - * A DSID of a datastream corresponding to an mp4 file. - * - * @return array - * A series of TRUE(pass)/FALSE(fail) results paired with result messages. */ -function islandora_validate_mp4_datastream($object, $datastream) { - $results = array(); - $mp4 = $object[$datastream]->content; - if (strpos($mp4, 'ftyp')) { - $mp4_ftyp = substr(strpos($mp4, 'ftyp'), 4, 4); - } - $pass = "{$datastream} datastream asserts that it is a valid ISO-formatted video file using ftyp {$mp4_ftyp}"; - $fail = "{$datastream} datastream is not a valid ISO-formatted video"; - $results = islandora_assert_valid(strpos($mp4, 'ftyp'), $results, $pass, $fail); - return $results; +class MP4DatastreamValidator extends DatastreamValidator { + + /** + * Asserts that the datastream is ISO-formatted video. + */ + protected function assertISOVideo() { + if (strpos($this->datastreamContent, 'ftyp')) { + $mp4_ftyp = substr(strpos($this->datastreamContent, 'ftyp'), 4, 4); + $this->addPass("{$this->datastream} datastream asserts that it is a valid ISO-formatted video file using ftyp {$mp4_ftyp}"); + } + else { + $this->addFail("{$this->datastream} datastream is not a valid ISO-formatted video"); + } + } } /** @@ -409,33 +678,45 @@ function islandora_validate_mp4_datastream($object, $datastream) { * what encoders were used to create the file. Here, we're looking for at least * one OGG page, and confirming that the file asserts the Theora and Vorbis * codecs were used to create the file. - * - * @param AbstractObject $object - * The PID of the object. - * @param string $datastream - * A DSID of a datastream corresponding to an ogg file. - * - * @return array - * A series of TRUE(pass)/FALSE(fail) results paired with result messages. */ -function islandora_validate_ogg_datastream($object, $datastream) { - $results = array(); - $ogg = $object[$datastream]->content; - $ogg_pages = substr_count($ogg, 'OggS'); - - $pass = "{$datastream} datastream asserts that it contains {$ogg_pages} Ogg pages (even a very small file should contain several)."; - $fail = "{$datastream} datastream contains no Ogg pages."; - $results = islandora_assert_valid(substr_count($ogg, 'OggS'), $results, $pass, $fail); - - $pass = "{$datastream} datastream asserts that it contains Theora-encoded video data."; - $fail = "{$datastream} datastream contains no marker indicating the presence of Theora-encoded video data."; - $results = islandora_assert_valid(substr_count($ogg, 'theora'), $results, $pass, $fail); +class OGGDatastreamValidator extends DatastreamValidator { + + /** + * Asserts that the datastream contains ogg pages. + */ + protected function assertOGGPages() { + $ogg_pages = substr_count($this->datastreamContent, 'OggS'); + if ($ogg_pages !== 0) { + $this->addPass("{$this->datastream} datastream asserts that it contains {$ogg_pages} Ogg pages (even a very small file should contain several)."); + } + else { + $this->addFail("{$this->datastream} datastream contains no Ogg pages."); + } + } - $pass = "{$datastream} datastream asserts that it contains Vorbis-encoded audio data"; - $fail = "{$datastream} datastream contains no marker indicating the presence of Vorbis-encoded audio data."; - $results = islandora_assert_valid(substr_count($ogg, 'vorbis'), $results, $pass, $fail); + /** + * Asserts that the datastream contains Theora-encoded video. + */ + protected function assertTheoraVideo() { + if (substr_count($this->datastreamContent, 'theora') !== 0) { + $this->addPass("{$this->datastream} datastream asserts that it contains Theora-encoded video data."); + } + else { + $this->addFail("{$this->datastream} datastream contains no marker indicating the presence of Theora-encoded video data."); + } + } - return $results; + /** + * Asserts that the datastream contains Vorbis-encoded audio. + */ + protected function assertVorbisAudio() { + if (substr_count($this->datastreamContent, 'vorbis')) { + $this->addPass("{$this->datastream} datastream asserts that it contains Vorbis-encoded audio data"); + } + else { + $this->addFail("{$this->datastream} datastream contains no marker indicating the presence of Vorbis-encoded audio data."); + } + } } /** @@ -446,28 +727,31 @@ function islandora_validate_ogg_datastream($object, $datastream) { * EBML format, the first four characters will always be the same. Since they're * non-standard characters, we're looking at their hex values instead. And * second, we know that the file will contain the declaration 'matroska' soon - * after. We could look for this in the binary, but we already have the hex- - * translated version, so we just look for 'matroska' in hex. - * - * @param AbstractObject $object - * The PID of the object. - * @param string $datastream - * A DSID of a datastream corresponding to an MKV file. - * - * @return array - * A series of TRUE(pass)/FALSE(fail) results paired with result messages. + * after. */ -function islandora_validate_mkv_datastream($object, $datastream) { - $results = array(); - $mkv = bin2hex($object[$datastream]->content); - - $pass = "{$datastream} datastream asserts that it is an EBML-formatted file"; - $fail = "{$datastream} datastream is not an EBML-formatted file."; - $results = islandora_assert_valid(substr($mkv, 0, 8) == '1a45dfa3', $results, $pass, $fail); - - $pass = "{$datastream} datastream asserts that its EBML DocType is Matroska"; - $fail = "{$datastream} datastream does not contain a Matroska EBML DocType marker."; - $results = islandora_assert_valid(substr_count($mkv, '6d6174726f736b61') == 1, $results, $pass, $fail); +class MKVDatastreamValidator extends DatastreamValidator { + + /** + * Asserts that the datastream is an EBML-format file. + */ + protected function assertEBMLFormat() { + if (substr(bin2hex($this->datastreamContent), 0, 8) == '1a45dfa3') { + $this->addPass("{$this->datastream} datastream asserts that it is an EBML-formatted file"); + } + else { + $this->addFail("{$this->datastream} datastream is not an EBML-formatted file."); + } + } - return $results; + /** + * Asserts that the datastream contains a matroska marker. + */ + protected function assertMatroskaMarker() { + if (substr_count($this->datastreamContent, 'matroska') == 1) { + $this->addPass("{$this->datastream} datastream asserts that its EBML DocType is Matroska"); + } + else { + $this->addFail("{$this->datastream} datastream does not contain a Matroska EBML DocType marker."); + } + } } diff --git a/tests/islandora_web_test_case.inc b/tests/islandora_web_test_case.inc index 89ca9cbb..284f634f 100644 --- a/tests/islandora_web_test_case.inc +++ b/tests/islandora_web_test_case.inc @@ -216,37 +216,72 @@ class IslandoraWebTestCase extends DrupalWebTestCase { /** * Attempts to validate an array of datastreams, generally via binary checks. * - * These functions exist in, and can be added to, datastream_validators.inc, - * which is found in this folder. + * Datastream validation classes exist in, and can be added to, the file + * '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. * $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 - e.g. array( + * array('DSID', 'TIFF'), + * array('DSID2, 'Text', array('param 1', 'param 2')), + * ) and so on. */ public function validateDatastreams($object, array $datastreams) { + 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'); + foreach ($datastreams as $datastream) { - if (isset($object[$datastream[0]])) { - $function = 'islandora_validate_' . $datastream[1] . '_datastream'; - if (function_exists($function)) { - if (isset($datastream[2])) { - $results = $function($object, $datastream[0], $datastream[2]); - } - else { - $results = $function($object, $datastream[0]); - } - foreach ($results as $result) { - $this->assertTrue($result[0], $result[1], 'Islandora'); - } + // Let's give them conventional names. + $dsid = $datastream[0]; + $prefix = $datastream[1]; + $params = array(); + if (isset($datastream[2])) { + $params = $datastream[2]; + } + + // Legacy tests were created before the CamelCase conventions of the class + // system now in place. So, we need to automagically seek out prefixes + // 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 { - $this->fail("No {$datastream[0]} validation function exists for the {$datastream[1]} datastream.", 'Islandora'); + $prefix = strtoupper($prefix); } } + + // Instantiate the appropriate class, grab the passes and fails. + $class_name = "{$prefix}DatastreamValidator"; + if (class_exists($class_name)) { + $validator = new $class_name($object, $dsid, $params); + foreach ($validator->getPasses() as $message => $caller) { + $this->assert(TRUE, $message, 'Islandora', $caller); + } + foreach ($validator->getFails() as $message => $caller) { + $this->assert(FALSE, $message, 'Islandora', $caller); + } + } + 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'); + } } } diff --git a/tests/scripts/travis_setup.sh b/tests/scripts/travis_setup.sh index c1bd7751..3a52bb75 100755 --- a/tests/scripts/travis_setup.sh +++ b/tests/scripts/travis_setup.sh @@ -21,15 +21,7 @@ pear channel-discover pear.phpqatools.org pear channel-discover pear.netpirates.net pear install pear/PHP_CodeSniffer-1.4.8 pear install pear.phpunit.de/phpcpd - -# Install Drush -git clone https://github.com/drush-ops/drush.git -pushd drush -git checkout 5.9.0 -chmod +x drush -popd -sudo ln -s $HOME/drush/drush /usr/local/sbin - +pear install drush/drush-5.9.0 phpenv rehash drush dl --yes drupal cd drupal-* From b9bf3a6c1283a3ead8402ed59ef81f2bc3eeb6a3 Mon Sep 17 00:00:00 2001 From: qadan Date: Sat, 22 Feb 2014 18:32:05 +0000 Subject: [PATCH 07/59] accidental reversion --- tests/scripts/travis_setup.sh | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/tests/scripts/travis_setup.sh b/tests/scripts/travis_setup.sh index 3a52bb75..c1bd7751 100755 --- a/tests/scripts/travis_setup.sh +++ b/tests/scripts/travis_setup.sh @@ -21,7 +21,15 @@ pear channel-discover pear.phpqatools.org pear channel-discover pear.netpirates.net pear install pear/PHP_CodeSniffer-1.4.8 pear install pear.phpunit.de/phpcpd -pear install drush/drush-5.9.0 + +# Install Drush +git clone https://github.com/drush-ops/drush.git +pushd drush +git checkout 5.9.0 +chmod +x drush +popd +sudo ln -s $HOME/drush/drush /usr/local/sbin + phpenv rehash drush dl --yes drupal cd drupal-* From 058f1fc8039f61a5a71d438f5a1308b7715fbf2c Mon Sep 17 00:00:00 2001 From: qadan Date: Sat, 22 Feb 2014 18:55:11 +0000 Subject: [PATCH 08/59] coding standards failure --- tests/islandora_web_test_case.inc | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/tests/islandora_web_test_case.inc b/tests/islandora_web_test_case.inc index 284f634f..e2e3ab7d 100644 --- a/tests/islandora_web_test_case.inc +++ b/tests/islandora_web_test_case.inc @@ -226,10 +226,8 @@ class IslandoraWebTestCase extends DrupalWebTestCase { * The object to load datastreams from. * $param array $datastreams * An array of arrays that pair DSIDs, DatastreamValidator class prefixes, - * and optional params - e.g. array( - * array('DSID', 'TIFF'), - * array('DSID2, 'Text', array('param 1', 'param 2')), - * ) and so on. + * and optional params. You can check some of the existing implementations + * for examples. */ public function validateDatastreams($object, array $datastreams) { From ad503afbf0962688183734d317d760c4e12277c9 Mon Sep 17 00:00:00 2001 From: qadan Date: Sat, 22 Feb 2014 21:07:57 +0000 Subject: [PATCH 09/59] needs less if/then --- tests/datastream_validators.inc | 394 +++++++++++++++--------------- tests/islandora_web_test_case.inc | 9 +- 2 files changed, 206 insertions(+), 197 deletions(-) diff --git a/tests/datastream_validators.inc b/tests/datastream_validators.inc index 1428321b..b9063992 100644 --- a/tests/datastream_validators.inc +++ b/tests/datastream_validators.inc @@ -44,6 +44,79 @@ function islandora_hex2int($hex) { } } +/** + * A result from a datastream validator; $type defines TRUE/FALSE as pass/fail. + */ +class DatastreamValidatorResult { + + /** + * The message for this result. + * + * @var string + */ + protected $message; + + /** + * The caller for this result. + * + * @var array + */ + protected $caller; + + /** + * The type of result this is - TRUE for pass, FALSE for fail. + * + * @var bool + */ + protected $type; + + /** + * Constructs a DatastreamValidatorResult. + * + * @param bool $type + * Whether this result should indicate a pass (TRUE) or fail (FALSE). + * @param string $message + * The message that will be used by this result. + * @param array $caller + * The caller for this result. + */ + public function __construct($type, $message, array $caller) { + $this->message = $message; + $this->caller = $caller; + $this->type = $type; + } + + /** + * Get the message for this result. + * + * @return string + * The message for this result. + */ + public function getMessage() { + return $this->message; + } + + /** + * Get the caller for this result. + * + * @return string + * The caller for this result. + */ + public function getCaller() { + return $this->caller; + } + + /** + * Get the type of result. + * + * @return bool + * The type of pass (TRUE for pass, FALSE for fail). + */ + public function getType() { + return $this->type; + } +} + /** * Abstraction for datastream validators. * @@ -66,13 +139,6 @@ function islandora_hex2int($hex) { */ abstract class DatastreamValidator { - /** - * This class is skipped when looking for the source of an assertion. - * - * @see DrupalWebTestCase::skipClasses - */ - protected $skipClasses = array(__CLASS__ => TRUE); - /** * The IslandoraFedoraObject containing the datastream to test. * @@ -95,24 +161,13 @@ abstract class DatastreamValidator { public $datastreamContent; /** - * An associative array of messages returned from passed tests, and callers. - * - * This should only be added to using $this->addPass(), so that the caller can - * be appropriately determined. - * - * @var array - */ - public $passes = array(); - - /** - * An associative array of messages returned from failed tests, and callers. + * An array of DatastreamValidatorResults. * - * This should only be added to using $this->addFail(), so that the caller can - * be appropriately determined. + * These should be generated using $this->addResult. * - * @var array + * @var DatastreamValidatorResult[] */ - public $fails = array(); + public $results = array(); /** * An array of additional required parameters. @@ -157,49 +212,26 @@ abstract class DatastreamValidator { } /** - * Returns an array of pass messages. + * Returns an array of DatastreamValidatorResults. * - * @return string[] - * The pass messages. + * @return DatastreamValidatorResult[] + * The results. */ - public function getPasses() { - return $this->passes; + public function getResults() { + return $this->results; } /** - * Returns an array of fail messages. - * - * @return string[] - * The fail messages. - */ - public function getFails() { - return $this->fails; - } - - /** - * Adds a pass to $this->pass. - * - * Passes are an associative array of messages and callers. Callers should be - * obtained using $this->getAssertionCall(). + * Adds a result to $this->results. * + * @param bool $type + * The type of result (TRUE for pass, FALSE for fail). * @param string $message - * The message to use. + * The message to put in the result. */ - public function addPass($message) { - $this->passes[$message] = $this->getAssertionCall(); - } - - /** - * Adds a fail to $this->fail. - * - * Fails are an associative array of messages and callers. Callers should be - * obtained using $this->getAssertionCall(). - * - * @param string $message - * The message to use. - */ - public function addFail($message) { - $this->fails[$message] = $this->getAssertionCall(); + public function addResult($type, $message) { + $result = new DatastreamValidatorResult($type, $message, $this->getAssertionCall()); + $this->results[] = $result; } /** @@ -239,12 +271,11 @@ class ImageDatastreamValidator extends DatastreamValidator { * Asserts the validity of an image using PHPGD. */ protected function assertImageGeneration() { - if (imagecreatefromstring($this->datastreamContent) !== FALSE) { - $this->addPass("Image datastream {$this->datastream} is valid."); - } - else { - $this->addFail("Image datastream {$this->datastream} is either invalid or corrupt."); - } + $assertion = imagecreatefromstring($this->datastreamContent) !== FALSE; + $pass = "Image datastream {$this->datastream} is valid."; + $fail = "Image datastream {$this->datastream} is either invalid or corrupt."; + $message = $assertion ? $pass : $fail; + $this->addResult($assertion, $message); } } @@ -264,17 +295,17 @@ class TIFFDatastreamValidator extends DatastreamValidator { // byte-order" (i.e. little-endian) by starting with the characters "II" // (repeated so that byte order does not yet need to be significant). // The number that follows is '42' in little-endian hex, a number of - // 'deep philosophical significance' to the TIFF format creators. - $this->addPass("{$this->datastream} datastream asserts that it is a valid Intel-byte-orderded TIF/TIFF file."); + // 'deep philosophical significance' to the TIFF format creators.' + $this->addResult(TRUE, "{$this->datastream} datastream asserts that it is a valid Intel-byte-orderded TIF/TIFF file."); } elseif ($datastream_header_hex == "4d4d002a") { // In this case, the ingested TIFF is designated as using the "Motorola // byte-order" (i.e. big-endian) by starting with the characters "MM" // instead. 42 follows once again, this time in big-endian hex. - $this->addPass("{$this->datastream} datastream asserts that it is a valid Motorola-byte-ordered TIF/TIFF file."); + $this->addResult(TRUE, "{$this->datastream} datastream asserts that it is a valid Motorola-byte-ordered TIF/TIFF file."); } else { - $this->addFail("{$this->datastream} datastream does not assert that it is a valid TIF/TIFF file."); + $this->addResult(FALSE, "{$this->datastream} datastream does not assert that it is a valid TIF/TIFF file."); } } @@ -302,12 +333,11 @@ class JP2DatastreamValidator extends DatastreamValidator { * 0x6A502020. This header is in all .jp2s, and we check for it here. */ protected function assertJP2Header() { - if (substr(bin2hex($this->datastreamContent), 8, 8) == '6a502020') { - $this->addPass("Datastream {$this->datastream} contains the appropriate JP2 header."); - } - else { - $this->addFail("Datastream {$this->datastream} does not contain the appropriate JP2 header."); - } + $assertion = substr(bin2hex($this->datastreamContent), 8, 8) == '6a502020'; + $pass = "Datastream {$this->datastream} contains the appropriate JP2 header."; + $fail = "Datastream {$this->datastream} does not contain the appropriate JP2 header."; + $message = $assertion ? $pass : $fail; + $this->addResult($assertion, $message); } /** @@ -317,12 +347,11 @@ class JP2DatastreamValidator extends DatastreamValidator { * checking for it here to see if the .jp2 encoder finished okay. */ protected function assertJP2Marker() { - if (substr(bin2hex($this->datastreamContent), strlen(bin2hex($this->datastreamContent)) - 4, 4) == 'ffd9') { - $this->addPass("Datastream {$this->datastream} contains the appropriate JP2 ending marker."); - } - else { - $this->addFail("Datastream {$this->datastream} does not contain the appropriate JP2 ending marker. If this is the only JP2 validator that failed, it is likely that derivative generation was interrupted."); - } + $assertion = substr(bin2hex($this->datastreamContent), strlen(bin2hex($this->datastreamContent)) - 4, 4) == 'ffd9'; + $pass = "Datastream {$this->datastream} contains the appropriate JP2 ending marker."; + $fail = "Datastream {$this->datastream} does not contain the appropriate JP2 ending marker. If this is the only JP2 validator that failed, it is likely that derivative generation was interrupted."; + $message = $assertion ? $pass : $fail; + $this->addResult($assertion, $message); } } @@ -335,13 +364,12 @@ class PDFDatastreamValidator extends DatastreamValidator { * Validates the PDF signature. */ protected function assertPDFSignature() { - if (substr($this->datastreamContent, 0, 5) == '%PDF-') { - $pdf_version = substr($this->datastreamContent, 5, 3); - $this->addPass("{$this->datastream} datastream asserts that it is a valid PDF file using PDF version {$pdf_version}"); - } - else { - $this->addFail("{$this->datastream} datastream binary header appears to be corrupt and missing a valid PDF signature."); - } + $assertion = substr($this->datastreamContent, 0, 5) == '%PDF-'; + $pdf_version = substr($this->datastreamContent, 5, 3); + $pass = "{$this->datastream} datastream asserts that it is a valid PDF file using PDF version {$pdf_version}"; + $fail = "{$this->datastream} datastream binary header appears to be corrupt and missing a valid PDF signature."; + $message = $assertion ? $pass : $fail; + $this->addResult($assertion, $message); } /** @@ -349,12 +377,11 @@ class PDFDatastreamValidator extends DatastreamValidator { */ protected function assertPDFStreamCount() { $pdf_stream_count = substr_count(bin2hex($this->datastreamContent), '0a73747265616d0a'); - if ($pdf_stream_count !== 0) { - $this->addPass("{$this->datastream} datastream reports the existence of {$pdf_stream_count} PDF streams. Note that an extremely low number could still indicate corruption."); - } - else { - $this->addFail("{$this->datastream} datastream contains zero PDF streams, and is likely not a PDF file."); - } + $assertion = $pdf_stream_count !== 0; + $pass = "{$this->datastream} datastream reports the existence of {$pdf_stream_count} PDF streams. Note that an extremely low number could still indicate corruption."; + $fail = "{$this->datastream} datastream contains zero PDF streams, and is likely not a PDF file."; + $message = $assertion ? $pass : $fail; + $this->addResult($assertion, $message); } /** @@ -364,12 +391,11 @@ class PDFDatastreamValidator extends DatastreamValidator { * TRUE if it was present; FALSE otherwise. */ protected function assertPDFClosingTag() { - if (strpos(bin2hex($this->datastreamContent), '0a2525454f460a')) { - $this->addPass("{$this->datastream} datastream reports the existence of the closing 'EOF' tag required at the end of PDFs"); - } - else { - $this->addFail("{$this->datastream} datastream does not contain the closing 'EOF' tag. If this is the only PDF validation that failed, it is likely that derivative generation was interrupted."); - } + $assertion = strpos(bin2hex($this->datastreamContent), '0a2525454f460a') == TRUE; + $pass = "{$this->datastream} datastream reports the existence of the closing 'EOF' tag required at the end of PDFs"; + $fail = "{$this->datastream} datastream does not contain the closing 'EOF' tag. If this is the only PDF validation that failed, it is likely that derivative generation was interrupted."; + $message = $assertion ? $pass : $fail; + $this->addResult($assertion, $message); } } @@ -387,13 +413,13 @@ class TextDatastreamValidator extends DatastreamValidator { */ protected function assertTextStringCount() { if (!isset($this->params[1])) { - $this->addFail("TextDatastreamValidator cannot be instantiated without two keys in the 'params' variable."); + $this->addResult(FALSE, "TextDatastreamValidator cannot be instantiated without two keys in the 'params' variable."); return; } $string_count = self::getTextStringCount(); $expected = $this->params[1]; - $function = $string_count === $expected ? 'addPass' : 'addFail'; - $this->$function("{$this->datastream} datastream contains the word(s) '{$this->params[0]}' repeated {$string_count} time(s) (expected: {$expected})."); + $assertion = $string_count === $expected; + $this->addResult($assertion, "{$this->datastream} datastream contains the word(s) '{$this->params[0]}' repeated {$string_count} time(s) (expected: {$expected})."); } /** @@ -442,36 +468,33 @@ class WAVDatastreamValidator extends DatastreamValidator { */ protected function assertWAVSignature() { $signatures = str_split(substr($this->datastreamContent, 0, 24), 8); - if ($signatures[0] = '52494646' && $signatures[2] = '57415645') { - $this->addPass("Header of the {$this->datastream} datastream contains a valid file signature."); - } - else { - $this->addFail("Header of the {$this->datastream} datastream contains corrupt file signature."); - } + $assertion = $signatures[0] == '52494646' && $signatures[2] == '57415645'; + $pass = "Header of the {$this->datastream} datastream contains a valid file signature."; + $fail = "Header of the {$this->datastream} datastream contains corrupt file signature."; + $message = $assertion ? $pass : $fail; + $this->addResult($assertion, $message); } /** * Asserts that the chunksize in the header is correct. */ protected function assertWAVChunkSize() { - if (islandora_hex2int(substr($this->datastreamContent, 8, 8)) === 36 + self::getDataSubChunkSize()) { - $this->addPass("{$this->datastream} datastream chunksize in WAV header is correct"); - } - else { - $this->addFail("{$this->datastream} datastream chunksize in WAV header does not match actual chunksize."); - } + $assertion = islandora_hex2int(substr($this->datastreamContent, 8, 8)) === 36 + self::getDataSubChunkSize(); + $pass = "{$this->datastream} datastream chunksize in WAV header is correct"; + $fail = "{$this->datastream} datastream chunksize in WAV header does not match actual chunksize."; + $message = $assertion ? $pass : $fail; + $this->addResult($assertion, $message); } /** * Asserts that the datastream contains a 'fmt' subchunk. */ protected function assertWAVFmtSubChunk() { - if (substr($this->datastreamContent, 24, 8) === '666d7420') { - $this->addPass("{$this->datastream} datastream contains a 'fmt' subchunk."); - } - else { - $this->addFail("{$this->datastream} datastream is missing the required 'fmt' subchunk."); - } + $assertion = substr($this->datastreamContent, 24, 8) === '666d7420'; + $pass = "{$this->datastream} datastream contains a 'fmt' subchunk."; + $fail = "{$this->datastream} datastream is missing the required 'fmt' subchunk."; + $message = $assertion ? $pass : $fail; + $this->addResult($assertion, $message); } /** @@ -479,24 +502,22 @@ class WAVDatastreamValidator extends DatastreamValidator { */ protected function assertWAVByteRate() { $wav_samplerate = islandora_hex2int(substr($this->datastreamContent, 48, 8)); - if (islandora_hex2int(substr($this->datastreamContent, 56, 8)) === $wav_samplerate * self::getNumChannels() * self::getBytesPerSample()) { - $this->addPass("{$this->datastream} datastream byterate in the WAV header is correct."); - } - else { - $this->addFail("{$this->datastream} datastream byterate in the WAV header does not match actual calculated byterate."); - } + $assertion = islandora_hex2int(substr($this->datastreamContent, 56, 8)) === $wav_samplerate * self::getNumChannels() * self::getBytesPerSample(); + $pass = "{$this->datastream} datastream byterate in the WAV header is correct."; + $fail = "{$this->datastream} datastream byterate in the WAV header does not match actual calculated byterate."; + $message = $assertion ? $pass : $fail; + $this->addResult($assertion, $message); } /** * Asserts that the block alignment is correct. */ protected function assertWAVBlockAlignment() { - if (islandora_hex2int(substr($this->datastreamContent, 64, 4)) === self::getNumChannels() * self::getBytesPerSample()) { - $this->addPass("{$this->datastream} datastream block alignment is set correctly."); - } - else { - $this->addFail("{$this->datastream} datastream block alignment is off."); - } + $assertion = islandora_hex2int(substr($this->datastreamContent, 64, 4)) === self::getNumChannels() * self::getBytesPerSample(); + $pass = "{$this->datastream} datastream block alignment is set correctly."; + $fail = "{$this->datastream} datastream block alignment is off."; + $message = $assertion ? $pass : $fail; + $this->addResult($assertion, $message); } /** @@ -506,18 +527,17 @@ class WAVDatastreamValidator extends DatastreamValidator { */ protected function assertWAVDataSubChunk() { if (substr($this->datastreamContent, 72, 8) !== '64617461') { - $this->addFail("{$this->datastream} datastream is missing the 'data' subchunk."); + $this->addResult(FALSE, "{$this->datastream} datastream is missing the 'data' subchunk."); return; } else { - $this->addPass("{$this->datastream} datastream contains 'data' subchunk."); + $this->addResult(TRUE, "{$this->datastream} datastream contains 'data' subchunk."); $wav_numsamples = strlen(substr($this->datastreamContent, 88)) / self::getNumChannels() / self::getBytesPerSample() / 2; - if (self::getDataSubChunkSize() === $wav_numsamples * self::getNumChannels() * self::getBytesPerSample()) { - $this->addPass("{$this->datastream} datastream 'data' chunk is the correct size."); - } - else { - $this->addFail("{$this->datastream} datastream 'data' chunk is sized incorrectly."); - } + $assertion = self::getDataSubChunkSize() === $wav_numsamples * self::getNumChannels() * self::getBytesPerSample(); + $pass = "{$this->datastream} datastream 'data' chunk is the correct size."; + $fail = "{$this->datastream} datastream 'data' chunk is sized incorrectly."; + $message = $assertion ? $pass : $fail; + $this->addResult($assertion, $message); } } @@ -578,11 +598,11 @@ class MP3DatastreamValidator extends DatastreamValidator { // out of the way first before we go doing a bunch of potentially pointless // math. Check to see if the VBR flag (58696e67) isn't there. if (strpos($this->datastreamContent, '58696e67') == FALSE && substr($this->datastreamContent, 0, 4) == 'fffa') { - $this->addPass("{$this->datastream} datastream is encoded as a valid MPEG-1 Layer 3 file with CRC protection"); + $this->addResult(TRUE, "{$this->datastream} datastream is encoded as a valid MPEG-1 Layer 3 file with CRC protection"); return; } if (strpos($this->datastreamContent, '58696e67') == FALSE && substr($this->datastreamContent, 0, 4) == 'fffb') { - $this->addPass("{$this->datastream} datastream is encoded as a valid unprotected MPEG-1 Layer 3 file"); + $this->addResult(TRUE, "{$this->datastream} datastream is encoded as a valid unprotected MPEG-1 Layer 3 file"); return; } @@ -610,12 +630,11 @@ class MP3DatastreamValidator extends DatastreamValidator { if (($mp3_flag_value + 4) % 4 > 1) { $mp3_field_bytes = hexdec(substr($mp3_vbrheader, $mp3_field_offset[0] + 16, 8)); $mp3_size = strlen($this->datastreamContent) / 2; - if ($mp3_size == $mp3_field_bytes) { - $this->addPass("{$this->datastream} datastream reported filesize of {$mp3_size} bytes matches size field value of {$mp3_field_bytes}"); - } - else { - $this->addFail("{$this->datastream} datastream reported filesize of {$mp3_size} bytes does not match size field value of {$mp3_field_bytes}"); - } + $assertion = $mp3_size == $mp3_field_bytes; + $pass = "{$this->datastream} datastream reported filesize of {$mp3_size} bytes matches size field value of {$mp3_field_bytes}"; + $fail = "{$this->datastream} datastream reported filesize of {$mp3_size} bytes does not match size field value of {$mp3_field_bytes}"; + $message = $assertion ? $pass : $fail; + $this->addResult($assertion, $message); $mp3_field_offset[1] += 8; $mp3_field_offset[2] += 8; } @@ -628,18 +647,17 @@ class MP3DatastreamValidator extends DatastreamValidator { // The fourth flag leads us to VBR quality data, which we can validate. if ($mp3_flag_value > 7) { $mp3_field_quality = hexdec(substr($mp3_vbrheader, $mp3_field_offset[2] + 16, 8)); - if ($mp3_field_quality <= 100 && $mp3_field_quality >= 0) { - $this->addPass("{$this->datastream} datastream reports valid VBR quality of {$mp3_field_quality} (expected: between 0-100)"); - } - else { - $this->addFail("{$this->datastream} datastream reports invalid VBR quality of {$mp3_field_quality} (expected: between 0-100)"); - } + $assertion = $mp3_field_quality <= 100 && $mp3_field_quality >= 0; + $pass = "{$this->datastream} datastream reports valid VBR quality of {$mp3_field_quality} (expected: between 0-100)"; + $fail = "{$this->datastream} datastream reports invalid VBR quality of {$mp3_field_quality} (expected: between 0-100)"; + $message = $assertion ? $pass : $fail; + $this->addResult($assertion, $message); } } // If none of that works out, fail. else { - $this->addFail("{$this->datastream} datastream is corrupt and does not identify as a valid MP3."); + $this->addResult(FALSE, "{$this->datastream} datastream is corrupt and does not identify as a valid MP3."); } } @@ -660,13 +678,12 @@ class MP4DatastreamValidator extends DatastreamValidator { * Asserts that the datastream is ISO-formatted video. */ protected function assertISOVideo() { - if (strpos($this->datastreamContent, 'ftyp')) { - $mp4_ftyp = substr(strpos($this->datastreamContent, 'ftyp'), 4, 4); - $this->addPass("{$this->datastream} datastream asserts that it is a valid ISO-formatted video file using ftyp {$mp4_ftyp}"); - } - else { - $this->addFail("{$this->datastream} datastream is not a valid ISO-formatted video"); - } + $mp4_ftyp = substr(strpos($this->datastreamContent, 'ftyp'), 4, 4); + $assertion = strpos($this->datastreamContent, 'ftyp') !== 0; + $pass = "{$this->datastream} datastream asserts that it is a valid ISO-formatted video file using ftyp {$mp4_ftyp}"; + $fail = "{$this->datastream} datastream is not a valid ISO-formatted video"; + $message = $assertion ? $pass : $fail; + $this->addResult($assertion, $message); } } @@ -686,36 +703,33 @@ class OGGDatastreamValidator extends DatastreamValidator { */ protected function assertOGGPages() { $ogg_pages = substr_count($this->datastreamContent, 'OggS'); - if ($ogg_pages !== 0) { - $this->addPass("{$this->datastream} datastream asserts that it contains {$ogg_pages} Ogg pages (even a very small file should contain several)."); - } - else { - $this->addFail("{$this->datastream} datastream contains no Ogg pages."); - } + $assertion = $ogg_pages !== 0; + $pass = "{$this->datastream} datastream asserts that it contains {$ogg_pages} Ogg pages (even a very small file should contain several)."; + $fail = "{$this->datastream} datastream contains no Ogg pages."; + $message = $assertion ? $pass : $fail; + $this->addResult($assertion, $message); } /** * Asserts that the datastream contains Theora-encoded video. */ protected function assertTheoraVideo() { - if (substr_count($this->datastreamContent, 'theora') !== 0) { - $this->addPass("{$this->datastream} datastream asserts that it contains Theora-encoded video data."); - } - else { - $this->addFail("{$this->datastream} datastream contains no marker indicating the presence of Theora-encoded video data."); - } + $assertion = substr_count($this->datastreamContent, 'theora') !== 0; + $pass = "{$this->datastream} datastream asserts that it contains Theora-encoded video data."; + $fail = "{$this->datastream} datastream contains no marker indicating the presence of Theora-encoded video data."; + $message = $assertion ? $pass : $fail; + $this->addResult($assertion, $message); } /** * Asserts that the datastream contains Vorbis-encoded audio. */ protected function assertVorbisAudio() { - if (substr_count($this->datastreamContent, 'vorbis')) { - $this->addPass("{$this->datastream} datastream asserts that it contains Vorbis-encoded audio data"); - } - else { - $this->addFail("{$this->datastream} datastream contains no marker indicating the presence of Vorbis-encoded audio data."); - } + $assertion = substr_count($this->datastreamContent, 'vorbis') !== 0; + $pass = "{$this->datastream} datastream asserts that it contains Vorbis-encoded audio data"; + $fail = "{$this->datastream} datastream contains no marker indicating the presence of Vorbis-encoded audio data."; + $message = $assertion ? $pass : $fail; + $this->addResult($assertion, $message); } } @@ -735,23 +749,21 @@ class MKVDatastreamValidator extends DatastreamValidator { * Asserts that the datastream is an EBML-format file. */ protected function assertEBMLFormat() { - if (substr(bin2hex($this->datastreamContent), 0, 8) == '1a45dfa3') { - $this->addPass("{$this->datastream} datastream asserts that it is an EBML-formatted file"); - } - else { - $this->addFail("{$this->datastream} datastream is not an EBML-formatted file."); - } + $assertion = substr(bin2hex($this->datastreamContent), 0, 8) == '1a45dfa3'; + $pass = "{$this->datastream} datastream asserts that it is an EBML-formatted file"; + $fail = "{$this->datastream} datastream is not an EBML-formatted file."; + $message = $assertion ? $pass : $fail; + $this->addResult($assertion, $message); } /** * Asserts that the datastream contains a matroska marker. */ protected function assertMatroskaMarker() { - if (substr_count($this->datastreamContent, 'matroska') == 1) { - $this->addPass("{$this->datastream} datastream asserts that its EBML DocType is Matroska"); - } - else { - $this->addFail("{$this->datastream} datastream does not contain a Matroska EBML DocType marker."); - } + $assertion = substr_count($this->datastreamContent, 'matroska') == 1; + $pass = "{$this->datastream} datastream asserts that its EBML DocType is Matroska"; + $fail = "{$this->datastream} datastream does not contain a Matroska EBML DocType marker."; + $message = $assertion ? $pass : $fail; + $this->addResult($assertion, $message); } } diff --git a/tests/islandora_web_test_case.inc b/tests/islandora_web_test_case.inc index e2e3ab7d..e866a929 100644 --- a/tests/islandora_web_test_case.inc +++ b/tests/islandora_web_test_case.inc @@ -266,15 +266,12 @@ class IslandoraWebTestCase extends DrupalWebTestCase { } } - // Instantiate the appropriate class, grab the passes and fails. + // 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->getPasses() as $message => $caller) { - $this->assert(TRUE, $message, 'Islandora', $caller); - } - foreach ($validator->getFails() as $message => $caller) { - $this->assert(FALSE, $message, 'Islandora', $caller); + foreach ($validator->getResults() as $result) { + $this->assert($result->getType(), $result->getMessage(), 'Islandora', $result->getCaller()); } } else { From 50481d8b3d34c238ebb051ca5576d011779ce7cf Mon Sep 17 00:00:00 2001 From: vagrant Date: Mon, 24 Feb 2014 18:01:13 +0000 Subject: [PATCH 10/59] aaaand tests --- islandora.info | 1 + tests/README.md | 28 +++++++++++++++++++++++++++- tests/datastream_validators.inc | 14 +++++++++++--- 3 files changed, 39 insertions(+), 4 deletions(-) diff --git a/islandora.info b/islandora.info index 732143b5..0142f1ce 100644 --- a/islandora.info +++ b/islandora.info @@ -22,4 +22,5 @@ files[] = tests/islandora_manage_permissions.test files[] = tests/datastream_versions.test files[] = tests/datastream_cache.test files[] = tests/derivatives.test +files[] = tests/datastream_validator_tests.test php = 5.3 diff --git a/tests/README.md b/tests/README.md index c4a0ae1a..d68c4b82 100644 --- a/tests/README.md +++ b/tests/README.md @@ -1,4 +1,30 @@ -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 file. These test need write access to the system's $FEDORA_HOME/server/config 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 existing Text.txt in that folder is 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://http://ca1.php.net/parse_ini_file).The generated test will +parse the .ini file as an array and pass it on to the third parameter. \ No newline at end of file diff --git a/tests/datastream_validators.inc b/tests/datastream_validators.inc index b9063992..854f6db5 100644 --- a/tests/datastream_validators.inc +++ b/tests/datastream_validators.inc @@ -186,12 +186,20 @@ abstract class DatastreamValidator { * @param array $params * An extra array of parameters the validator might need. */ - public function __construct($object, $datastream, array $params = array()) { + public function __construct(IslandoraFedoraObject $object, $datastream, array $params = array()) { $this->object = $object; $this->datastream = $datastream; $this->params = $params; - $this->datastreamContent = $object[$datastream]->content; - $this->runValidators(); + if ($object[$datastream]) { + $this->datastreamContent = $object[$datastream]->content; + $this->runValidators(); + } + else { + drupal_set_message(t("Error grabbing content from datastream %datastream in object %id", 'error'), array( + '%datastream' => $datastream, + '%id' => $object->id, + )); + } } /** From 5965802a467258a90f520a2cf115eb536d5637d9 Mon Sep 17 00:00:00 2001 From: qadan Date: Mon, 24 Feb 2014 18:02:02 +0000 Subject: [PATCH 11/59] and the actual test --- tests/datastream_validator_tests.test | 277 ++++++++++++++++++++++++++ 1 file changed, 277 insertions(+) create mode 100644 tests/datastream_validator_tests.test diff --git a/tests/datastream_validator_tests.test b/tests/datastream_validator_tests.test new file mode 100644 index 00000000..79e1df7f --- /dev/null +++ b/tests/datastream_validator_tests.test @@ -0,0 +1,277 @@ +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."); + } + } + } + } +} From 7b7d67f23cc4240211711796ae9521799a1b36ba Mon Sep 17 00:00:00 2001 From: qadan Date: Mon, 24 Feb 2014 18:11:45 +0000 Subject: [PATCH 12/59] the readme lies --- tests/README.md | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/tests/README.md b/tests/README.md index d68c4b82..3918b117 100644 --- a/tests/README.md +++ b/tests/README.md @@ -24,7 +24,20 @@ 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 existing Text.txt in that folder is 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://http://ca1.php.net/parse_ini_file).The generated test will -parse the .ini file as an array and pass it on to the third parameter. \ No newline at end of file +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 From 3dcc9e9c5bd2a789d5501c36b1c20c0c17c85db8 Mon Sep 17 00:00:00 2001 From: qadan Date: Mon, 24 Feb 2014 18:33:21 +0000 Subject: [PATCH 13/59] random coder violations. weird. --- includes/datastream.version.inc | 2 +- includes/manage_deleted_objects.inc | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/includes/datastream.version.inc b/includes/datastream.version.inc index 8c02aaad..ecef019d 100644 --- a/includes/datastream.version.inc +++ b/includes/datastream.version.inc @@ -234,7 +234,7 @@ function islandora_revert_datastream_version_form_submit(array $form, array &$fo /** * Gets Audit datastream values from foxml. * - * @param String $pid + * @param string $pid * PID of parent object * * @return array diff --git a/includes/manage_deleted_objects.inc b/includes/manage_deleted_objects.inc index 2708efe3..48796304 100644 --- a/includes/manage_deleted_objects.inc +++ b/includes/manage_deleted_objects.inc @@ -287,7 +287,7 @@ function islandora_get_contentmodels_with_deleted_members() { /** * Restores deleted object. * - * @param String $pid + * @param string $pid * PID of object to be restored */ function islandora_restore_object_by_pid($pid) { @@ -298,7 +298,7 @@ function islandora_restore_object_by_pid($pid) { /** * Purges deleted object. * - * @param String $pid + * @param string $pid * PID of object to be restored */ function islandora_purge_object_by_pid($pid) { @@ -314,7 +314,7 @@ function islandora_purge_object_by_pid($pid) { * @param int $offset * offset to be added to search * - * @return String + * @return string * Sparql query */ function islandora_get_deleted_query($content_models, $offset = 0) { From e560c90520bbacab56e04ecb1dedb55a8521005e Mon Sep 17 00:00:00 2001 From: willtp87 Date: Fri, 28 Mar 2014 11:16:20 -0300 Subject: [PATCH 14/59] doc clarification and mentioning new clean up practice --- islandora.api.php | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/islandora.api.php b/islandora.api.php index e8b45ba7..062e96e6 100644 --- a/islandora.api.php +++ b/islandora.api.php @@ -627,11 +627,14 @@ function hook_CMODEL_PID_islandora_overview_object_alter(AbstractObject &$object * - force: Bool denoting whether we are forcing the generation of * derivatives. * - source_dsid: (Optional) String of the datastream id we are generating - * from or NULL if it's the object itself. + * from or NULL if it's the object itself. Does not impact function + * ordering. * - destination_dsid: (Optional) String of the datastream id that is being - * created. To be used in the UI. + * created. To be used in the UI. Does not impact function ordering. * - weight: A string denoting the weight of the function. This value is - * sorted upon to run functions in order. + * sorted upon to run functions in order. Some derivation steps operate as + * clean up steps. For consistency with ingest steps they use weight:50 it + * is advisable to stay beneath this weight. * - function: An array of function(s) to be ran when constructing * derivatives. Functions that are defined to be called for derivation * creation must have the following structure: From 27e2f5f978a18cc2387924208d747ff0b43110e5 Mon Sep 17 00:00:00 2001 From: willtp87 Date: Mon, 31 Mar 2014 11:20:24 -0300 Subject: [PATCH 15/59] letting batch derivitives run during batches --- includes/derivatives.inc | 22 ++++++++++++++++++++++ islandora.module | 10 ++-------- 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/includes/derivatives.inc b/includes/derivatives.inc index d25789cc..5c0c3dd7 100644 --- a/includes/derivatives.inc +++ b/includes/derivatives.inc @@ -4,6 +4,28 @@ * Defines functions used when constructing derivatives. */ +/** + * Decides which derivative function to call and runs it. + * + * @param AbstractObject $object + * The object to run the derivative function for. + * @param string $dsid + * The DSID to run the derivative function for. + */ +function islandora_run_derivatives (AbstractObject $object, $dsid) { + if (empty(batch_get())) { + $logging_results = islandora_do_derivatives($object, array( + 'source_dsid' => $dsid, + )); + islandora_derivative_logging($logging_results); + } + else { + islandora_do_batch_derivatives($object, array( + 'source_dsid' => $dsid, + )); + } +} + /** * Kicks off derivative functions based upon hooks and conditions. * diff --git a/islandora.module b/islandora.module index 9e7809eb..94b34e93 100644 --- a/islandora.module +++ b/islandora.module @@ -1695,10 +1695,7 @@ function islandora_islandora_basic_collection_get_query_filters() { */ function islandora_islandora_object_ingested(AbstractObject $object) { module_load_include('inc', 'islandora', 'includes/derivatives'); - $logging_results = islandora_do_derivatives($object, array( - 'source_dsid' => NULL, - )); - islandora_derivative_logging($logging_results); + islandora_run_derivatives($object, NULL); } /** @@ -1709,10 +1706,7 @@ function islandora_islandora_object_ingested(AbstractObject $object) { */ function islandora_islandora_datastream_ingested(AbstractObject $object, AbstractDatastream $datastream) { module_load_include('inc', 'islandora', 'includes/derivatives'); - $logging_results = islandora_do_derivatives($object, array( - 'source_dsid' => $datastream->id, - )); - islandora_derivative_logging($logging_results); + islandora_run_derivatives($object, $datastream->id); } /** From 90c60eda0ede3616922e5d4dfd9854efc81884fd Mon Sep 17 00:00:00 2001 From: willtp87 Date: Wed, 2 Apr 2014 15:30:06 -0300 Subject: [PATCH 16/59] rules integration during ingest --- includes/tuque_wrapper.inc | 4 ++++ islandora.rules.inc | 23 ++++++++++++++++++++--- islandora.rules_defaults.inc | 26 ++++++++++++++++++++++++++ 3 files changed, 50 insertions(+), 3 deletions(-) create mode 100644 islandora.rules_defaults.inc diff --git a/includes/tuque_wrapper.inc b/includes/tuque_wrapper.inc index d30af147..573d7c62 100644 --- a/includes/tuque_wrapper.inc +++ b/includes/tuque_wrapper.inc @@ -115,6 +115,10 @@ class IslandoraFedoraRepository extends FedoraRepository { foreach ($object as $dsid => $datastream) { islandora_invoke_datastream_hooks(ISLANDORA_DATASTREAM_INGESTED_HOOK, $object->models, $dsid, $object, $datastream); } + // Fire of event if rules is enabled. + if (module_exists('rules')) { + rules_invoke_event('islandora_object_ingested', $object); + } return $ret; } catch (Exception $e) { diff --git a/islandora.rules.inc b/islandora.rules.inc index 4045b1b9..02f5c822 100644 --- a/islandora.rules.inc +++ b/islandora.rules.inc @@ -5,11 +5,30 @@ * Does rule type stuff, */ +/** + * Implements hook_rules_event_info(). + */ +function islandora_rules_event_info() { + return array( + 'islandora_object_ingested' => array( + 'group' => t('Islandora'), + 'label' => t('Object ingested'), + 'variables' => array( + 'object' => array( + 'type' => 'islandora_object', + 'label' => t('The ingested object'), + 'description' => t('A Tuque object for the ingested Fedora object, as an entity.'), + ), + ), + ), + ); +} + /** * Helper function to get reused "parameter" array. */ function islandora_rules_relationship_parameter_array() { - $to_return = array( + return array( 'subject' => array( 'type' => 'islandora_object', 'label' => t('Subject'), @@ -39,8 +58,6 @@ function islandora_rules_relationship_parameter_array() { 'default value' => 0, ), ); - - return $to_return; } /** diff --git a/islandora.rules_defaults.inc b/islandora.rules_defaults.inc new file mode 100644 index 00000000..17f83b63 --- /dev/null +++ b/islandora.rules_defaults.inc @@ -0,0 +1,26 @@ +label = 'E-mail admin'; + $rule->active = FALSE; + $rule + ->event('islandora_object_ingested') + ->action( + 'mail', + array( + 'to' => '[site:mail]', + 'subject' => '[[site:name]] "[object:label]" has been ingested', + 'message' => '[object:label] has been ingested as [object:id].', + ) + ); + return array('islandora_object_ingested_notify_admin' => $rule); +} From 4507d5b39c63b9fec103505c8cde52551c2251bf Mon Sep 17 00:00:00 2001 From: Jordan Dukart Date: Wed, 2 Apr 2014 19:50:39 +0000 Subject: [PATCH 17/59] Use redirect set in form state before defaulting to the object. --- includes/ingest.form.inc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/includes/ingest.form.inc b/includes/ingest.form.inc index 89376f7d..8fd1c6ea 100644 --- a/includes/ingest.form.inc +++ b/includes/ingest.form.inc @@ -769,7 +769,7 @@ function islandora_ingest_form_submit(array $form, array &$form_state) { islandora_ingest_form_execute_consecutive_callback_steps($form, $form_state, $step); } // Ingest the objects. - $set_redirect = TRUE; + $set_redirect = isset($form_state['redirect']) ? FALSE : TRUE; foreach ($form_state['islandora']['objects'] as &$object) { try { islandora_add_object($object); From bbc6cec2298ae9ecd4f812ca414d5693a95c69b7 Mon Sep 17 00:00:00 2001 From: willtp87 Date: Thu, 3 Apr 2014 11:09:25 -0300 Subject: [PATCH 18/59] date time available --- islandora.module | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/islandora.module b/islandora.module index 9e7809eb..fd71bb3c 100644 --- a/islandora.module +++ b/islandora.module @@ -1531,6 +1531,11 @@ function islandora_entity_property_info() { 'label' => t('Content Models'), 'description' => t('The list of content models which the object has.'), ); + $p['createdDate'] = array( + 'type' => 'text', + 'label' => t('Created Date'), + 'description' => t('When the object was created.'), + ); return $info; } From 785eedcc8397ff4d432570fc0d4e95429dcac64a Mon Sep 17 00:00:00 2001 From: Adam Vessey Date: Fri, 4 Apr 2014 13:42:22 +0000 Subject: [PATCH 19/59] Make the "undo_function" bit optional. The "undo_function" part of callbacks was required, even though it might not be required for functionality... Make it optional, so we don't end up making/using no-op functions to avoid doing anything. --- includes/ingest.form.inc | 12 +++++++----- islandora.api.php | 6 +++--- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/includes/ingest.form.inc b/includes/ingest.form.inc index 8fd1c6ea..f7979063 100644 --- a/includes/ingest.form.inc +++ b/includes/ingest.form.inc @@ -467,12 +467,14 @@ function islandora_ingest_form_undo_consecutive_callback_steps(array $form, arra * The step which the undo callback is being called on. */ function islandora_ingest_form_undo_callback_step(array $form, array &$form_state, array $step) { - $args = array(&$form_state); - $args = isset($step['undo_function']['args']) ? array_merge($args, $step['undo_function']['args']) : $args; - if (isset($step['undo_function']['file'])) { - require_once drupal_get_path('module', $step['module']) . "/" . $step['undo_function']['file']; + if (isset($step['undo_function'])) { + $args = array(&$form_state); + $args = isset($step['undo_function']['args']) ? array_merge($args, $step['undo_function']['args']) : $args; + if (isset($step['undo_function']['file'])) { + require_once drupal_get_path('module', $step['module']) . "/" . $step['undo_function']['file']; + } + call_user_func_array($step['undo_function']['function'], $args); } - call_user_func_array($step['undo_function']['function'], $args); } /** diff --git a/islandora.api.php b/islandora.api.php index e8b45ba7..d32b7fdf 100644 --- a/islandora.api.php +++ b/islandora.api.php @@ -423,13 +423,13 @@ function hook_islandora_undeletable_datastreams(array $models) { * - form_id: The form building function to call to get the form structure * for this step. * - args: An array of arguments to pass to the form building function. - * Required "callback" type specific parameters: - * - do_function: An associate array including: + * "Callback" type specific parameters: + * - do_function: A required associative array including: * - 'function': The callback function to be called. * - 'args': An array of arguments to pass to the callback function. * - 'file': A file to include (relative to the module's path, including * the file's extension). - * - undo_function: An associate array including: + * - undo_function: An optional associative array including: * - 'function': The callback function to be called to reverse the * executed action in the ingest steps. * - 'args': An array of arguments to pass to the callback function. From e9faa1810d4f2b9631c112c91ac3a818e5fa5c30 Mon Sep 17 00:00:00 2001 From: Adam Vessey Date: Fri, 4 Apr 2014 16:02:19 +0000 Subject: [PATCH 20/59] Try getting rid of the "upgrade-all" shenanigans. --- tests/scripts/travis_setup.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/scripts/travis_setup.sh b/tests/scripts/travis_setup.sh index c1bd7751..4079d3b6 100755 --- a/tests/scripts/travis_setup.sh +++ b/tests/scripts/travis_setup.sh @@ -14,7 +14,6 @@ export JAVA_OPTS="-Xms1024m -Xmx1024m -XX:MaxPermSize=512m -XX:+CMSClassUnloadin cd $HOME pear upgrade --force Console_Getopt pear upgrade --force pear -pear upgrade-all pear channel-discover pear.drush.org pear channel-discover pear.drush.org pear channel-discover pear.phpqatools.org From 254ee5d60be9b3e169d4483778b350f9c23ed3c8 Mon Sep 17 00:00:00 2001 From: willtp87 Date: Tue, 8 Apr 2014 13:32:59 -0300 Subject: [PATCH 21/59] passing derivative deffinition to callback (usefull for single callback handling many derivatives) --- includes/derivatives.inc | 16 ++++++++++------ islandora.api.php | 2 +- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/includes/derivatives.inc b/includes/derivatives.inc index d25789cc..2f4adc51 100644 --- a/includes/derivatives.inc +++ b/includes/derivatives.inc @@ -49,7 +49,7 @@ function islandora_do_derivatives(AbstractObject $object, array $options) { } foreach ($hook['function'] as $function) { if (function_exists($function)) { - $logging = call_user_func($function, $object, $options['force']); + $logging = call_user_func($function, $object, $options['force'], $hook); if (!empty($logging)) { $results[] = $logging; } @@ -142,11 +142,15 @@ function islandora_do_batch_derivatives(AbstractObject $object, array $options) $file = $hook['file']; } foreach ($hook['function'] as $function) { - $operations[] = array('islandora_derivative_perform_batch_operation', array( - $function, - $file, - $object->id, - $options['force']), + $operations[] = array( + 'islandora_derivative_perform_batch_operation', + array( + $function, + $file, + $object->id, + $options['force'], + $hook + ), ); } } diff --git a/islandora.api.php b/islandora.api.php index d32b7fdf..eeeeae1c 100644 --- a/islandora.api.php +++ b/islandora.api.php @@ -635,7 +635,7 @@ function hook_CMODEL_PID_islandora_overview_object_alter(AbstractObject &$object * - function: An array of function(s) to be ran when constructing * derivatives. Functions that are defined to be called for derivation * creation must have the following structure: - * module_name_derivative_creation_function($object, $force = FALSE) + * module_name_derivative_creation_function($object, $force = FALSE, $hook) * These functions must return an array in the structure of: * - success: Bool denoting whether the operation was successful. * - messages: An array structure containing zero or more array's with the From 7be2653ba646af812fdfaa7c3ef7996265c4d208 Mon Sep 17 00:00:00 2001 From: willtp87 Date: Tue, 8 Apr 2014 13:47:51 -0300 Subject: [PATCH 22/59] forgot comma --- includes/derivatives.inc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/includes/derivatives.inc b/includes/derivatives.inc index 2f4adc51..635c1c54 100644 --- a/includes/derivatives.inc +++ b/includes/derivatives.inc @@ -149,7 +149,7 @@ function islandora_do_batch_derivatives(AbstractObject $object, array $options) $file, $object->id, $options['force'], - $hook + $hook, ), ); } From 91c7103f50922fc4d20e70ff1250d3eae5b4b232 Mon Sep 17 00:00:00 2001 From: Jordan Dukart Date: Wed, 9 Apr 2014 16:13:19 +0000 Subject: [PATCH 23/59] Don't render unneeded markup when there is no thumbnail. --- theme/islandora-object.tpl.php | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/theme/islandora-object.tpl.php b/theme/islandora-object.tpl.php index fdd09607..f91c3272 100644 --- a/theme/islandora-object.tpl.php +++ b/theme/islandora-object.tpl.php @@ -61,13 +61,13 @@

-
-
- -
- -
-
+ +
+
+ +
+
+