#!/usr/bin/env python2.4 # -*- coding: utf-8 -*- """ Test hachoir-metadata using the testcase. """ DOWNLOAD_SCRIPT = "download_testcase.py" # Configure Hachoir from hachoir_core import config config.use_i18n = False # Don't use i18n config.quiet = True # Don't display warnings from hachoir_core.i18n import getTerminalCharset from hachoir_core.error import HachoirError from hachoir_core.stream import InputStreamError from hachoir_parser import createParser from hachoir_core.compatibility import all from hachoir_core.language import Language from hachoir_metadata import extractMetadata from datetime import date, timedelta, datetime from locale import setlocale, LC_ALL import os import sys def checkAttr(metadata, name, value): sys.stdout.write(" - Check metadata %s=%s: " % (name, repr(value))) if not isinstance(value, (list, tuple)): value = [value] # Has subgroup? (eg. "audio/sample_rate") if "/" in name: group, name = name.split("/", 1) if group not in metadata: sys.stdout.write("no group \"%s\"!\n" % group) return False metadata = metadata[group] # Has asked attribute? if not metadata.has(name): sys.stdout.write("no attribute \"%s\"!\n" % name) return False # Read value reads = metadata.getValues(name) # Check value if len(reads) != len(value): sys.stdout.write("wrong len (%s instead of %s)!\n" % (len(reads), len(value))) return False values = value for index, value in enumerate(values): read = reads[index] # Check type if type(read) != type(value) \ and not(isinstance(value, (int, long)) and isinstance(value, (int, long))): sys.stdout.write("wrong type (%s instead of %s)!\n" % (type(read).__name__, type(value).__name__)) return False # Check value if value != read: sys.stdout.write("wrong value %s (%r instead of %r)!\n" % (index, read, value)) return False sys.stdout.write("ok\n") return True def checkLogoUbuntuMeta(metadata): return ( checkAttr(metadata, "bits_per_pixel", 32), checkAttr(metadata, "creation_date", datetime(2006, 5, 26, 9, 41, 46)), checkAttr(metadata, "mime_type", u"image/png")) def checkClickMeta(metadata): return ( checkAttr(metadata, "producer", u"Sound Forge 4.5"), checkAttr(metadata, "creation_date", date(2001, 2, 21)), checkAttr(metadata, "duration", timedelta(microseconds=19546)), checkAttr(metadata, "bit_rate", 705600), checkAttr(metadata, "sample_rate", 22050)) def checkGzipMeta(metadata): return ( checkAttr(metadata, "file_size", 99), checkAttr(metadata, "compr_size", 90), checkAttr(metadata, "last_modification", datetime(2006, 7, 29, 12, 20, 44)), checkAttr(metadata, "os", u"Unix"), checkAttr(metadata, "compression", u"deflate")) def checkSheepMeta(metadata): return ( checkAttr(metadata, "format_version", u"MPEG version 1 layer III"), checkAttr(metadata, "author", u"Sheep On Drugs"), checkAttr(metadata, "comment", u"Stainless Steel Provider is compilated to the car of Twinstar.")) def checkPng331_90_8Meta(metadata): return ( checkAttr(metadata, "width", 331), checkAttr(metadata, "creation_date", datetime(2006, 5, 26, 9, 41, 46)), checkAttr(metadata, "mime_type", u"image/png"), checkAttr(metadata, "endian", u"Big endian")) def checkFlashMobInfo(metadata): return ( checkAttr(metadata, "copyright", u"© dadaprod, licence Creative Commons by-nc-sa 2.0 fr"), checkAttr(metadata, "video[1]/width", 384), checkAttr(metadata, "video[1]/language", Language('fre')), checkAttr(metadata, "duration", timedelta(seconds=17, milliseconds=844)), ) def check10min(meta): return ( checkAttr(meta, "duration", timedelta(minutes=10)), checkAttr(meta, "producer", [u"x264", u"Haali Matroska Writer b0"]), checkAttr(meta, "video[1]/width", 384), checkAttr(meta, "video[1]/height", 288), checkAttr(meta, "video[1]/compression", u"V_MPEG4/ISO/AVC"), ) def checkWormuxIco(meta): return ( checkAttr(meta, "image[0]/width", 16), checkAttr(meta, "image[0]/height", 16), checkAttr(meta, "image[0]/bits_per_pixel", 32), checkAttr(meta, "image[0]/compression", u"Uncompressed (RGB)"), ) def checkAudio8kHz(meta): return ( checkAttr(meta, "mime_type", u"audio/basic"), checkAttr(meta, "nb_channel", 1), checkAttr(meta, "bits_per_sample", 8), checkAttr(meta, "bit_rate", 64096), checkAttr(meta, "sample_rate", 8012), checkAttr(meta, "compression", u"8-bit ISDN u-law"), checkAttr(meta, "comment", u"../tmp/temp.snd"), checkAttr(meta, "duration", timedelta(seconds=4, microseconds=391538)), ) def checkCrossXCF(meta): return ( checkAttr(meta, "comment", u"Created with The GIMP"), checkAttr(meta, "width", 61), checkAttr(meta, "height", 72), checkAttr(meta, "compression", u"RLE"), checkAttr(meta, "mime_type", u"image/x-xcf")) def checkTARMeta(meta): return ( checkAttr(meta, "file[0]/filename", u"dummy.txt"), checkAttr(meta, "file[0]/file_size", 62), checkAttr(meta, "file[1]/file_attr", u"-rwxr-xr-x (755)"), checkAttr(meta, "file[1]/last_modification", datetime(2006, 10, 1, 13, 9, 3)), checkAttr(meta, "file[2]/file_type", u"Normal disk file"), ) def checkCornerBMPMeta(meta): return ( checkAttr(meta, "width", 189), checkAttr(meta, "nb_colors", 70), checkAttr(meta, "compression", u"Uncompressed"), checkAttr(meta, "mime_type", u"image/x-ms-bmp"), ) def checkSmallville(metadata): return ( checkAttr(metadata, "duration", timedelta(minutes=44, seconds=1, microseconds=141141)), checkAttr(metadata, "producer", u"VirtualDubMod 1.5.10.1 (build 2366/release)"), checkAttr(metadata, "video/width", 640), checkAttr(metadata, "video/height", 352), checkAttr(metadata, "video/compression", u'XviD MPEG-4 (fourcc:"xvid")'), checkAttr(metadata, "video/frame_rate", 23.976), checkAttr(metadata, "audio[1]/nb_channel", 2), checkAttr(metadata, "audio[1]/sample_rate", 48000), checkAttr(metadata, "audio[1]/compression", u"MPEG Layer 3")) def checkLechat(meta): return ( checkAttr(meta, "album", [u"Arte Radio", u"Chat Broodthaers"]), checkAttr(meta, "url", u"Liens direct ARTE Radio: www.arteradio.com/son.html?473"), checkAttr(meta, "creation_date", date(2003, 1, 1)), checkAttr(meta, "producer", u"www.arteradio.com"), checkAttr(meta, "sample_rate", 44100), checkAttr(meta, "bit_rate", 128000)) def checkJpegExifPSD(meta): return ( checkAttr(meta, "producer", [u"Adobe Photoshop 7.0"]), checkAttr(meta, "width", 124), checkAttr(meta, "compression", u"JPEG (Progressive)"), checkAttr(meta, "creation_date", datetime(2006, 6, 28, 14, 51, 9))) def checkInterludeDavid(meta): return ( checkAttr(meta, "title", u"interlude symbiosys1"), checkAttr(meta, "artist", u"david aubrun"), checkAttr(meta, "duration", timedelta(minutes=1, seconds=12, microseconds=19592)), checkAttr(meta, "audio[1]/nb_channel", 2), checkAttr(meta, "audio[1]/format_version", u"Vorbis version 0"), checkAttr(meta, "audio[1]/sample_rate", 44100), checkAttr(meta, "mime_type", u"audio/vorbis"), ) def checkBreakdance(meta): return ( checkAttr(meta, "audio/sample_rate", 22050), checkAttr(meta, "duration", timedelta(seconds=46, milliseconds=942)), checkAttr(meta, "producer", [u"YouTube, Inc.", u"YouTube Metadata Injector."]), ) def checkMatrixPingPong(meta): return ( checkAttr(meta, "title", u"欽ちゃん&香取慎吾の全日本仮装大賞"), checkAttr(meta, "duration", timedelta(minutes=1, seconds=47, milliseconds=258)), checkAttr(meta, "creation_date", datetime(2003, 6, 16, 7, 57, 23, 235000)), checkAttr(meta, "audio[1]/sample_rate", 8000), checkAttr(meta, "audio[1]/bits_per_sample", 16), checkAttr(meta, "audio[1]/compression", u"Windows Media Audio V7 / V8 / V9"), checkAttr(meta, "video[1]/width", 200), checkAttr(meta, "video[1]/height", 150), checkAttr(meta, "video[1]/bits_per_pixel", 24), ) def checkUSARailroad(meta): return ( # Check IPTC parser checkAttr(meta, "author", u"Ian Britton"), checkAttr(meta, "copyright", u"FreeFoto.com"), ) def checkHero(meta): return ( checkAttr(meta, "width", 320), checkAttr(meta, "bits_per_pixel", 8), checkAttr(meta, "nb_colors", 256), checkAttr(meta, "compression", u"8-bit uncompressed"), ) def check25min(meta): return ( checkAttr(meta, "duration", timedelta(minutes=25, seconds=33)), checkAttr(meta, "nb_channel", 2), checkAttr(meta, "sample_rate", 44100), checkAttr(meta, "bit_rate", 1411200), checkAttr(meta, "bits_per_sample", 16), checkAttr(meta, "compression", u"Little-endian, no compression"), ) def checkLadouce(meta): return ( checkAttr(meta, "duration", timedelta(hours=1, minutes=16, seconds=32, microseconds=516032)), checkAttr(meta, "nb_channel", 6), checkAttr(meta, "sample_rate", 44100), checkAttr(meta, "bits_per_sample", 32), checkAttr(meta, "compression", u"IEEE Float"), checkAttr(meta, "bit_rate", 8467200), ) def checkLaraCroft(meta): return ( checkAttr(meta, "width", 320), checkAttr(meta, "nb_colors", 256), checkAttr(meta, "compression", u"Run-length encoding (RLE)"), ) def checkHachoirOrgSXW(meta): return ( checkAttr(meta, "mime_type", u"application/vnd.sun.xml.writer"), checkAttr(meta, "file[0]/file_size", 30), checkAttr(meta, "file[1]/creation_date", datetime(2007, 1, 22, 19, 8, 14)), checkAttr(meta, "file[2]/filename", u"Configurations2/accelerator/current.xml"), checkAttr(meta, "file[2]/compression", u"Deflate"), ) def checkFirstRun(meta): return ( checkAttr(meta, "duration", timedelta(seconds=17, milliseconds=66)), checkAttr(meta, "creation_date", datetime(2000, 6, 14, 10, 3, 18)), checkAttr(meta, "copyright", u"©2000 RealNetworks"), checkAttr(meta, "producer", u"RealProducer Plus 6.1.0.153 Windows"), checkAttr(meta, "stream[0]/mime_type", u"audio/x-pn-realaudio"), checkAttr(meta, "stream[0]/bit_rate", 32148), checkAttr(meta, "stream[0]/title", u"Audio Stream"), checkAttr(meta, "mime_type", u"audio/x-pn-realaudio"), checkAttr(meta, "bit_rate", 32348), checkAttr(meta, "stream[1]/bit_rate", 200), ) def checkDejaVu(meta): return ( checkAttr(meta, "title", u"DejaVu Serif"), checkAttr(meta, "author", u"DejaVu fonts team"), checkAttr(meta, "version", u"2.7"), checkAttr(meta, "creation_date", datetime(2006, 7, 6, 17, 29, 52)), checkAttr(meta, "last_modification", datetime(2006, 7, 6, 17, 29, 52)), checkAttr(meta, "copyright", [ u"Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved.\nDejaVu changes are in public domain", u"http://dejavu.sourceforge.net/wiki/index.php/License"]), checkAttr(meta, "url", u"http://dejavu.sourceforge.net"), checkAttr(meta, "comment", [ u"Smallest readable size in pixels: 8 pixels", u"Font direction: Mixed directional"]), ) def checkTwunk16(meta): return ( checkAttr(meta, "title", [ u"Twain_32.dll Client's 16-Bit Thunking Server", u"Twain Thunker"]), checkAttr(meta, "author", u"Twain Working Group"), checkAttr(meta, "version", u"1,7,0,0"), checkAttr(meta, "format_version", u"New-style executable: Dynamic-link library (DLL)"), ) def checkDebianTorrent(meta): return ( checkAttr(meta, "filename", u"debian-31r4-i386-binary-1.iso"), checkAttr(meta, "url", u"http://bttracker.acc.umu.se:6969/announce"), checkAttr(meta, "file_size", 669775872), checkAttr(meta, "creation_date", datetime(2006, 11, 16, 21, 44, 37)), ) def checkFile(filename, check_metadata, quality=1.0): sys.stdout.write(" - Create parser: ") sys.stdout.flush() try: parser = createParser(filename) except InputStreamError, err: sys.stdout.write("stream error! %s\n" % unicode(err)) sys.exit(1) if not parser: sys.stdout.write("unable to create parser\n") return False sys.stdout.write("ok\n") sys.stdout.write(" - Create metadata: ") sys.stdout.flush() try: metadata = extractMetadata(parser, quality) except HachoirError, err: sys.stdout.write("stream error! %s\n" % unicode(err)) sys.exit(1) if not metadata: sys.stdout.write("unable to create parser\n") return False sys.stdout.write("ok\n") return all(check_metadata(metadata)) def testFiles(directory): if not os.path.exists(directory): try: os.mkdir(directory) except OSError: print "Unable to create directory: %s" % directory return False for filename, check_metadata in testcase_files: fullname = os.path.join(directory, filename) try: os.stat(fullname) except OSError: print >>sys.stderr, \ "[!] Error: file %s is missing, " \ "use script %s to fix your testcase" \ % (filename, DOWNLOAD_SCRIPT) return False print "[+] Test %s:" % filename if not checkFile(fullname, check_metadata): return False return True def main(): setlocale(LC_ALL, "C") if len(sys.argv) != 2: print >>sys.stderr, "usage: %s testcase_directory" % sys.argv[0] sys.exit(1) charset = getTerminalCharset() directory = unicode(sys.argv[1], charset) print "Test hachoir-metadata using testcase." print print "Testcase is in directory: %s" % directory ok = testFiles(directory) if ok: print print "Result: ok for the %s files" % len(testcase_files) sys.exit(0) else: print for index in xrange(3): print "!!! ERROR !!!" print sys.exit(1) testcase_files = ( (u"logo-kubuntu.png", checkLogoUbuntuMeta), (u"kde_click.wav", checkClickMeta), (u"test.txt.gz", checkGzipMeta), (u"flashmob.mkv", checkFlashMobInfo), (u"10min.mkv", check10min), (u"wormux_32x32_16c.ico", checkWormuxIco), (u"audio_8khz_8bit_ulaw_4s39.au", checkAudio8kHz), (u"sheep_on_drugs.mp3", checkSheepMeta), (u"cross.xcf", checkCrossXCF), (u"small_text.tar", checkTARMeta), (u"kde_haypo_corner.bmp", checkCornerBMPMeta), (u"png_331x90x8_truncated.png", checkPng331_90_8Meta), (u"smallville.s03e02.avi", checkSmallville), (u"08lechat_hq_fr.mp3", checkLechat), (u"jpeg.exif.photoshop.jpg", checkJpegExifPSD), (u"interlude_david_aubrun.ogg", checkInterludeDavid), (u"breakdance.flv", checkBreakdance), (u"matrix_ping_pong.wmv", checkMatrixPingPong), (u"usa_railroad.jpg", checkUSARailroad), (u"hero.tga", checkHero), (u"25min.aifc", check25min), (u"ladouce_1h15.wav", checkLadouce), (u"lara_croft.pcx", checkLaraCroft), (u"hachoir.org.sxw", checkHachoirOrgSXW), (u"firstrun.rm", checkFirstRun), (u"deja_vu_serif-2.7.ttf", checkDejaVu), (u"twunk_16.exe", checkTwunk16), (u"debian-31r4-i386-binary-1.iso.torrent", checkDebianTorrent), ) if __name__ == "__main__": main()