#!/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()



syntax highlighted by Code2HTML, v. 0.9.1