'''
Created on Aug 30, 2010

@author: sau
'''
import unittest
import os
import string
from array import array
from erange import commoncode
from erange import Region
from cistematic.genomes import Genome


class TestCommoncode(unittest.TestCase):
    logFile = "testLogFile"
    celegansChroms = ["I", "II", "III", "IV", "V", "X", "MtDNA"]
    genome = Genome("celegans")

    def setUp(self):
        pass


    def tearDown(self):
        try:
            os.remove(self.logFile)
        except OSError:
            pass


    def testGetReverseComplement(self):
        self.assertEquals("T", commoncode.getReverseComplement("A"))
        self.assertEquals("A", commoncode.getReverseComplement("T"))
        self.assertEquals("C", commoncode.getReverseComplement("G"))
        self.assertEquals("G", commoncode.getReverseComplement("C"))
        self.assertEquals("N", commoncode.getReverseComplement("N"))
        self.assertRaises(KeyError, commoncode.getReverseComplement, "")
        self.assertRaises(KeyError, commoncode.getReverseComplement, "B")


    def testCountDuplicatesInList(self):
        testList = []
        self.assertEquals([], commoncode.countDuplicatesInList(testList))

        testList = [0, 1]
        result = [(0, 1), (1, 1)]
        self.assertEquals(result, commoncode.countDuplicatesInList(testList))

        testList = [0, 1, 1]
        result = [(0, 1), (1, 2)]
        self.assertEquals(result, commoncode.countDuplicatesInList(testList))

        testList = [0, 1, 2, 1]
        result = [(0, 1), (1, 2), (2, 1)]
        self.assertEquals(result, commoncode.countDuplicatesInList(testList))


    def testWriteLog(self):
        messenger = "testMessenger"
        message = "testMessage"

        commoncode.writeLog(self.logFile, messenger, message)
        file = open(self.logFile)
        line = file.readline()
        fields = line.split()
        self.assertEquals(fields[2], "[%s]" % messenger)
        self.assertEquals(fields[3], message)
        line = file.readline()
        self.assertEquals("", line)

        messenger2 = "testMessenger2"
        message2 = "testMessage2"

        commoncode.writeLog(self.logFile, messenger2, message2)
        file = open(self.logFile)
        line = file.readline()
        fields = line.split()
        self.assertEquals(fields[2], "[%s]" % messenger)
        self.assertEquals(fields[3], message)
        line = file.readline()
        fields = line.split()
        self.assertEquals(fields[2], "[%s]" % messenger2)
        self.assertEquals(fields[3], message2)
        line = file.readline()
        self.assertEquals("", line)

        os.remove(self.logFile)

        commoncode.writeLog(self.logFile, messenger, message)
        file = open(self.logFile)
        line = file.readline()
        fields = line.split()
        self.assertEquals(fields[2], "[%s]" % messenger)
        self.assertEquals(fields[3], message)
        line = file.readline()
        self.assertEquals("", line)

        os.remove(self.logFile)

        commoncode.writeLog(self.logFile, "", message)
        file = open(self.logFile)
        line = file.readline()
        fields = line.split()
        self.assertEquals(fields[2], "[]")
        self.assertEquals(fields[3], message)
        line = file.readline()
        self.assertEquals("", line)

        os.remove(self.logFile)

        commoncode.writeLog(self.logFile, "", "")
        file = open(self.logFile)
        line = file.readline()
        fields = line.split()
        self.assertEquals(fields[2], "[]")
        self.assertEquals(3, len(fields))
        line = file.readline()
        self.assertEquals("", line)


    def testGetMergedRegions(self):
        testfile = open("regionTestFile", "w")
        regionEntry = string.join(["1", "chr1", "10", "20", "5"], "\t")
        testfile.write(regionEntry)
        testfile.close()
        result = commoncode.getMergedRegions("regionTestFile")
        self.assertEquals(10, result["1"][0].start)
        self.assertEquals(20, result["1"][0].stop)
        self.assertEquals(10, result["1"][0].length)
        os.remove("regionTestFile")


    def testGetMergedRegionsFromList(self):
        self.assertEquals({}, commoncode.getMergedRegionsFromList([]))

        regionEntry = string.join(["1", "chr1", "10", "20", "5"], "\t")
        regionList = [regionEntry]
        result = commoncode.getMergedRegionsFromList(regionList)
        self.assertEquals(10, result["1"][0].start)
        self.assertEquals(20, result["1"][0].stop)
        self.assertEquals(10, result["1"][0].length)

        result = commoncode.getMergedRegionsFromList(regionList, pad=5)
        self.assertEquals(5, result["1"][0].start)
        self.assertEquals(25, result["1"][0].stop)
        self.assertEquals(20, result["1"][0].length)

        result = commoncode.getMergedRegionsFromList(regionList, pad=-2)
        self.assertEquals(12, result["1"][0].start)
        self.assertEquals(18, result["1"][0].stop)
        self.assertEquals(6, result["1"][0].length)

        result = commoncode.getMergedRegionsFromList(regionList, fullChrom=True)
        self.assertEquals(10, result["chr1"][0].start)
        self.assertEquals(20, result["chr1"][0].stop)
        self.assertEquals(10, result["chr1"][0].length)

        regionEntry = string.join(["1", "chr1:10-20", "5"], "\t")
        regionList = [regionEntry]
        result = commoncode.getMergedRegionsFromList(regionList, compact=True, scoreField=2)
        self.assertEquals(10, result["1"][0].start)
        self.assertEquals(20, result["1"][0].stop)
        self.assertEquals(10, result["1"][0].length)

        regionEntry = string.join(["1", "chr1", "10", "20", "5"], "\t")
        regionList = [regionEntry]
        regionEntry = string.join(["2", "chr1", "15", "40", "10"], "\t")
        regionList.append(regionEntry)
        result = commoncode.getMergedRegionsFromList(regionList)
        self.assertEquals(10, result["1"][0].start)
        self.assertEquals(40, result["1"][0].stop)
        self.assertEquals(30, result["1"][0].length)

        result = commoncode.getMergedRegionsFromList(regionList, doMerge=False)
        self.assertEquals(10, result["1"][0].start)
        self.assertEquals(20, result["1"][0].stop)
        self.assertEquals(10, result["1"][0].length)
        self.assertEquals(15, result["1"][1].start)
        self.assertEquals(40, result["1"][1].stop)
        self.assertEquals(25, result["1"][1].length)

        result = commoncode.getMergedRegionsFromList(regionList, doMerge=False, keepLabel=True)
        self.assertEquals(10, result["1"][0].start)
        self.assertEquals(20, result["1"][0].stop)
        self.assertEquals(10, result["1"][0].length)
        self.assertEquals("1", result["1"][0].label)
        self.assertEquals(15, result["1"][1].start)
        self.assertEquals(40, result["1"][1].stop)
        self.assertEquals(25, result["1"][1].length)
        self.assertEquals("2", result["1"][1].label)

        regionEntry = string.join(["1", "spacer", "chr1", "10", "20", "5"], "\t")
        regionList = [regionEntry]
        regionEntry = string.join(["2", "spacer2", "chr1", "15", "40", "10"], "\t")
        regionList.append(regionEntry)
        result = commoncode.getMergedRegionsFromList(regionList, doMerge=False, keepLabel=True, chromField=2)
        self.assertEquals(10, result["1"][0].start)
        self.assertEquals(20, result["1"][0].stop)
        self.assertEquals(10, result["1"][0].length)
        self.assertEquals("1\tspacer", result["1"][0].label)
        self.assertEquals(15, result["1"][1].start)
        self.assertEquals(40, result["1"][1].stop)
        self.assertEquals(25, result["1"][1].length)
        self.assertEquals("2\tspacer2", result["1"][1].label)

        regionEntry = string.join(["1", "chr1", "10", "20", "5"], "\t")
        regionList = [regionEntry]
        regionEntry = string.join(["2", "chr1", "2030", "2040", "15"], "\t")
        regionList.append(regionEntry)
        result = commoncode.getMergedRegionsFromList(regionList)
        self.assertEquals(10, result["1"][0].start)
        self.assertEquals(20, result["1"][0].stop)
        self.assertEquals(10, result["1"][0].length)
        self.assertEquals(2030, result["1"][1].start)
        self.assertEquals(2040, result["1"][1].stop)
        self.assertEquals(10, result["1"][1].length)

        result = commoncode.getMergedRegionsFromList(regionList, maxDist=3000)
        self.assertEquals(10, result["1"][0].start)
        self.assertEquals(2040, result["1"][0].stop)
        self.assertEquals(2030, result["1"][0].length)

        result = commoncode.getMergedRegionsFromList(regionList, minHits=5)
        self.assertEquals(10, result["1"][0].start)
        self.assertEquals(20, result["1"][0].stop)
        self.assertEquals(10, result["1"][0].length)
        self.assertEquals(2030, result["1"][1].start)
        self.assertEquals(2040, result["1"][1].stop)
        self.assertEquals(10, result["1"][1].length)

        result = commoncode.getMergedRegionsFromList(regionList, minHits=12)
        self.assertEquals(2030, result["1"][0].start)
        self.assertEquals(2040, result["1"][0].stop)
        self.assertEquals(10, result["1"][0].length)
        result = commoncode.getMergedRegionsFromList(regionList, minHits=12)
        self.assertEquals(2030, result["1"][0].start)
        self.assertEquals(2040, result["1"][0].stop)
        self.assertEquals(10, result["1"][0].length)

        regionEntry = string.join(["1", "chr1", "10", "20", "+", "5"], "\t")
        regionList = [regionEntry]
        regionEntry = string.join(["2", "chr2", "15", "40", "+", "15"], "\t")
        regionList.append(regionEntry)
        result = commoncode.getMergedRegionsFromList(regionList, scoreField=5, minHits=12)
        self.assertEquals(15, result["2"][0].start)
        self.assertEquals(40, result["2"][0].stop)
        self.assertEquals(25, result["2"][0].length)
        self.assertRaises(IndexError, commoncode.getMergedRegionsFromList, regionList, scoreField=6, returnTop=1)
        self.assertEquals({}, commoncode.getMergedRegionsFromList(regionList, scoreField=6))
        self.assertEquals({}, commoncode.getMergedRegionsFromList(regionList, scoreField=1))

        regionEntry = string.join(["1", "chr1", "10", "20", "5", "3", "40"], "\t")
        regionList = [regionEntry]
        result = commoncode.getMergedRegionsFromList(regionList)
        self.assertEquals(10, result["1"][0].start)
        self.assertEquals(20, result["1"][0].stop)
        self.assertEquals(10, result["1"][0].length)

        result = commoncode.getMergedRegionsFromList(regionList, keepPeak=True)
        self.assertEquals(10, result["1"][0].start)
        self.assertEquals(20, result["1"][0].stop)
        self.assertEquals(10, result["1"][0].length)
        self.assertEquals(3, result["1"][0].peakPos)
        self.assertEquals(40, result["1"][0].peakHeight)

        result = commoncode.getMergedRegionsFromList(regionList, keepPeak=True, keepLabel=True)
        self.assertEquals(10, result["1"][0].start)
        self.assertEquals(20, result["1"][0].stop)
        self.assertEquals(10, result["1"][0].length)
        self.assertEquals(3, result["1"][0].peakPos)
        self.assertEquals(40, result["1"][0].peakHeight)
        self.assertEquals("1", result["1"][0].label)

        regionEntry = string.join(["2", "chr2", "15", "40", "32", "17"], "\t")
        regionList.append(regionEntry)
        result = commoncode.getMergedRegionsFromList(regionList, keepPeak=True, keepLabel=True)
        self.assertEquals(10, result["1"][0].start)
        self.assertEquals(20, result["1"][0].stop)
        self.assertEquals(10, result["1"][0].length)
        self.assertEquals(3, result["1"][0].peakPos)
        self.assertEquals(40, result["1"][0].peakHeight)
        self.assertEquals("1", result["1"][0].label)
        self.assertEquals(15, result["2"][0].start)
        self.assertEquals(40, result["2"][0].stop)
        self.assertEquals(25, result["2"][0].length)
        self.assertEquals(32, result["2"][0].peakPos)
        self.assertEquals(17, result["2"][0].peakHeight)
        self.assertEquals("2", result["2"][0].label)

        regionEntry = string.join(["3", "chr1", "15", "40", "32", "17"], "\t")
        regionList.append(regionEntry)
        result = commoncode.getMergedRegionsFromList(regionList, keepPeak=True, keepLabel=True)
        self.assertEquals(10, result["1"][0].start)
        self.assertEquals(40, result["1"][0].stop)
        self.assertEquals(30, result["1"][0].length)
        self.assertEquals(3, result["1"][0].peakPos)
        self.assertEquals(40, result["1"][0].peakHeight)
        self.assertEquals("3", result["1"][0].label)
        self.assertEquals(15, result["2"][0].start)
        self.assertEquals(40, result["2"][0].stop)
        self.assertEquals(25, result["2"][0].length)
        self.assertEquals(32, result["2"][0].peakPos)
        self.assertEquals(17, result["2"][0].peakHeight)
        self.assertEquals("2", result["2"][0].label)

        regionEntry = string.join(["4", "chr2", "65", "88", "72", "7"], "\t")
        regionList.append(regionEntry)
        result = commoncode.getMergedRegionsFromList(regionList, keepPeak=True, keepLabel=True)
        self.assertEquals(10, result["1"][0].start)
        self.assertEquals(40, result["1"][0].stop)
        self.assertEquals(30, result["1"][0].length)
        self.assertEquals(3, result["1"][0].peakPos)
        self.assertEquals(40, result["1"][0].peakHeight)
        self.assertEquals("3", result["1"][0].label)
        self.assertEquals(15, result["2"][0].start)
        self.assertEquals(88, result["2"][0].stop)
        self.assertEquals(73, result["2"][0].length)
        self.assertEquals(32, result["2"][0].peakPos)
        self.assertEquals(17, result["2"][0].peakHeight)
        self.assertEquals("4", result["2"][0].label)

        result = commoncode.getMergedRegionsFromList(regionList, keepPeak=True, keepLabel=True, doMerge=False)
        self.assertEquals(10, result["1"][0].start)
        self.assertEquals(20, result["1"][0].stop)
        self.assertEquals(10, result["1"][0].length)
        self.assertEquals(3, result["1"][0].peakPos)
        self.assertEquals(40, result["1"][0].peakHeight)
        self.assertEquals("1", result["1"][0].label)
        self.assertEquals(15, result["1"][1].start)
        self.assertEquals(40, result["1"][1].stop)
        self.assertEquals(25, result["1"][1].length)
        self.assertEquals(32, result["1"][1].peakPos)
        self.assertEquals(17, result["1"][1].peakHeight)
        self.assertEquals("3", result["1"][1].label)
        self.assertEquals(15, result["2"][0].start)
        self.assertEquals(40, result["2"][0].stop)
        self.assertEquals(25, result["2"][0].length)
        self.assertEquals(32, result["2"][0].peakPos)
        self.assertEquals(17, result["2"][0].peakHeight)
        self.assertEquals("2", result["2"][0].label)
        self.assertEquals(65, result["2"][1].start)
        self.assertEquals(88, result["2"][1].stop)
        self.assertEquals(23, result["2"][1].length)
        self.assertEquals(72, result["2"][1].peakPos)
        self.assertEquals(7, result["2"][1].peakHeight)
        self.assertEquals("4", result["2"][1].label)

        regionList = ["# comment"]
        regionEntry = string.join(["1", "chr1", "10", "20", "5", "3", "40"], "\t")
        regionList.append(regionEntry)
        result = commoncode.getMergedRegionsFromList(regionList, keepPeak=True)
        self.assertEquals(10, result["1"][0].start)
        self.assertEquals(20, result["1"][0].stop)
        self.assertEquals(10, result["1"][0].length)
        self.assertEquals(3, result["1"][0].peakPos)
        self.assertEquals(40, result["1"][0].peakHeight)

        regionList = ["# pvalue"]
        regionEntry = string.join(["1", "chr1", "10", "20", "5", "3", "40", "any value"], "\t")
        regionList.append(regionEntry)
        result = commoncode.getMergedRegionsFromList(regionList, keepPeak=True)
        self.assertEquals(10, result["1"][0].start)
        self.assertEquals(20, result["1"][0].stop)
        self.assertEquals(10, result["1"][0].length)
        self.assertEquals(3, result["1"][0].peakPos)
        self.assertEquals(40, result["1"][0].peakHeight)

        result = commoncode.getMergedRegionsFromList(regionList, keepPeak=True, returnTop=1)
        self.assertEquals(10, result["1"][0].start)
        self.assertEquals(20, result["1"][0].stop)
        self.assertEquals(10, result["1"][0].length)
        self.assertEquals(3, result["1"][0].peakPos)
        self.assertEquals(40, result["1"][0].peakHeight)

        regionList = ["# readShift"]
        regionEntry = string.join(["1", "chr1", "10", "20", "5", "3", "40", "any value"], "\t")
        regionList.append(regionEntry)
        result = commoncode.getMergedRegionsFromList(regionList, keepPeak=True)
        self.assertEquals(10, result["1"][0].start)
        self.assertEquals(20, result["1"][0].stop)
        self.assertEquals(10, result["1"][0].length)
        self.assertEquals(3, result["1"][0].peakPos)
        self.assertEquals(40, result["1"][0].peakHeight)

        result = commoncode.getMergedRegionsFromList(regionList, keepPeak=True, returnTop=1)
        self.assertEquals(10, result["1"][0].start)
        self.assertEquals(20, result["1"][0].stop)
        self.assertEquals(10, result["1"][0].length)
        self.assertEquals(3, result["1"][0].peakPos)
        self.assertEquals(40, result["1"][0].peakHeight)

        regionList = ["# pvalue readShift"]
        regionEntry = string.join(["1", "chr1", "10", "20", "5", "3", "40", "any value", "any shift"], "\t")
        regionList.append(regionEntry)
        result = commoncode.getMergedRegionsFromList(regionList, keepPeak=True)
        self.assertEquals(10, result["1"][0].start)
        self.assertEquals(20, result["1"][0].stop)
        self.assertEquals(10, result["1"][0].length)
        self.assertEquals(3, result["1"][0].peakPos)
        self.assertEquals(40, result["1"][0].peakHeight)

        result = commoncode.getMergedRegionsFromList(regionList, keepPeak=True, returnTop=1)
        self.assertEquals(10, result["1"][0].start)
        self.assertEquals(20, result["1"][0].stop)
        self.assertEquals(10, result["1"][0].length)
        self.assertEquals(3, result["1"][0].peakPos)
        self.assertEquals(40, result["1"][0].peakHeight)

        #Test fails - the header line is required if there are fields after the peak which isn't so good
        #self.assertEquals(result, commoncode.getMergedRegionsFromList(regionList[1:], keepPeak=True))


    def testRegionsOverlap(self):
        self.assertTrue(commoncode.regionsOverlap(100, 200, 1, 300))
        self.assertTrue(commoncode.regionsOverlap(100, 200, 150, 300))
        self.assertTrue(commoncode.regionsOverlap(100, 500, 1, 300))
        self.assertTrue(commoncode.regionsOverlap(100, 200, 110, 160))

        self.assertFalse(commoncode.regionsOverlap(100, 200, 250, 300))
        self.assertFalse(commoncode.regionsOverlap(100, 200, 1, 60))

        self.assertFalse(commoncode.regionsOverlap(-200, -100, 1, 300))
        self.assertFalse(commoncode.regionsOverlap(100, 200, -300, -1))

        self.assertTrue(commoncode.regionsOverlap(-200, -100, -300, -1))

        self.assertTrue(commoncode.regionsOverlap(-100, -200, -300, -1))
        self.assertTrue(commoncode.regionsOverlap(-200, -100, -1, -300))
        self.assertTrue(commoncode.regionsOverlap(-100, -200, -1, -300))


    def testRegionsAreWithinDistance(self):
        self.assertTrue(commoncode.regionsAreWithinDistance(10, 20, 40, 50, 30))
        self.assertTrue(commoncode.regionsAreWithinDistance(10, 20, 1, 5, 5))
        self.assertTrue(commoncode.regionsAreWithinDistance(10, 20, 25, 50, 10))
        self.assertTrue(commoncode.regionsAreWithinDistance(10, 20, 1, 5, 5))

        self.assertFalse(commoncode.regionsAreWithinDistance(10, 20, 100, 150, 5))
        self.assertFalse(commoncode.regionsAreWithinDistance(100, 200, 10, 15, 5))

        self.assertTrue(commoncode.regionsAreWithinDistance(20, 10, 30, 150, 10))
        self.assertFalse(commoncode.regionsAreWithinDistance(20, 10, 100, 150, 5))
        self.assertFalse(commoncode.regionsAreWithinDistance(10, 20, 150, 100, 5))


    #TODO: write test
    def testFindPeak(self):
        hitList = []
        result = commoncode.findPeak(hitList, 0, 0)
        self.assertEquals([], result.topPos)
        self.assertEquals(0.0, result.numHits)
        self.assertEquals(array("f"), result.smoothArray)
        self.assertEquals(0.0, result.numPlus)

        hitList= [{"start": 4, "sense": "+", "weight": 0.5}]
        result = commoncode.findPeak(hitList, 0, 10)
        self.assertEquals([6, 7], result.topPos)
        self.assertEquals(1.0, result.numHits)
        self.assertEquals(array("f", [0.0, 0.0, 0.1111111119389534, 0.3333333432674408, 0.66666668653488159, 0.8888888955116272, 1.0, 1.0, 0.0, 0.0]), result.smoothArray)
        self.assertEquals(1.0, result.numPlus)

        result = commoncode.findPeak(hitList, 0, 10, doWeight=True)
        self.assertEquals([6, 7], result.topPos)
        self.assertEquals(0.5, result.numHits)
        self.assertEquals(array('f', [0.0, 0.0, 0.0555555559694767, 0.1666666716337204, 0.3333333432674408, 0.4444444477558136, 0.5, 0.5, 0.0, 0.0]), result.smoothArray)
        self.assertEquals(0.5, result.numPlus)

        result = commoncode.findPeak(hitList, 0, 10, shift="auto")
        self.assertEquals([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], result.topPos)
        self.assertEquals(0.0, result.numHits)
        self.assertEquals(array("f", [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]), result.smoothArray)
        self.assertEquals(0.0, result.numPlus)

        result = commoncode.findPeak(hitList, 0, 10, shift="auto")
        self.assertEquals([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], result.topPos)
        self.assertEquals(0.0, result.numHits)
        self.assertEquals(array("f", [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]), result.smoothArray)
        self.assertEquals(0.0, result.numPlus)
        self.assertEquals(6, result.shift)

        hitList= [{"start": 4, "sense": "+", "weight": 0.5}]
        result = commoncode.findPeak(hitList, 0, 10, shift=3)
        self.assertEquals([7], result.topPos)
        self.assertEquals(1.0, result.numHits)
        self.assertEquals(array('f', [0.0, 0.0, 0.0, 0.0, 0.0, 0.1111111119389534, 0.3333333432674408, 0.66666668653488159, 0.0, 0.0]), result.smoothArray)
        self.assertEquals(1.0, result.numPlus)
        self.assertEquals(3, result.shift)

        hitList= [{"start": 4, "sense": "+", "weight": 0.5}]
        result = commoncode.findPeak(hitList, 0, 10, leftPlus=True)
        self.assertEquals([6, 7], result.topPos)
        self.assertEquals(1.0, result.numHits)
        self.assertEquals(array('f', [0.0, 0.0, 0.1111111119389534, 0.3333333432674408, 0.66666668653488159, 0.8888888955116272, 1.0, 1.0, 0.0, 0.0]), result.smoothArray)
        self.assertEquals(1.0, result.numPlus)
        self.assertEquals(1.0, result.numLeftPlus)

        result = commoncode.findPeak(hitList, 0, 10, leftPlus=True, shift=3)
        self.assertEquals([7], result.topPos)
        self.assertEquals(1.0, result.numHits)
        self.assertEquals(array('f', [0.0, 0.0, 0.0, 0.0, 0.0, 0.1111111119389534, 0.3333333432674408, 0.66666668653488159, 0.0, 0.0]), result.smoothArray)
        self.assertEquals(1.0, result.numPlus)
        self.assertEquals(1.0, result.numLeftPlus)
        self.assertEquals(3, result.shift)


    #TODO: write test
    def testGetBestShiftForRegion(self):
        hitList = [{"start": 14, "sense": "-", "weight": 1.0},
                   {"start": 16, "sense": "-", "weight": 1.0},
                   {"start": 24, "sense": "+", "weight": 1.0},
                   {"start": 26, "sense": "+", "weight": 10.0}
        ]
        self.assertEquals(74, commoncode.getBestShiftForRegion(hitList, 0, 100))
        self.assertEquals(16, commoncode.getBestShiftForRegion(hitList, 0, 100, maxShift=30))
        self.assertEquals(0, commoncode.getBestShiftForRegion(hitList, 0, 100, maxShift=10))


    #TODO: write test
    def testFindPeakSequenceArray(self):
        pass


    #TODO: write test
    def testGetPeakPositionList(self):
        pass


    #TODO: write test
    def testGetFeaturesByChromDict(self):
        firstFeatures = {"I": (4123, 4219, "Y74C9A.3", "R", "3UTR"),
                         "II": (1866, 1910, "2L52.1", "F", "CDS"),
                         "III": (1270, 1506, "cTel54X.1", "R", "CDS"),
                         "IV": (694, 1064, "Y38C1AB.4", "F", "CDS"),
                         "V": (1479, 1578, "cTel3X.1", "F", "CDS"),
                         "X": (3622, 4099, "CE7X_3.1", "F", "CDS"),
                         "MtDNA": (112, 543, "MTCE.3", "F", "CDS")
        }
        featureDict = commoncode.getFeaturesByChromDict(self.genome)
        for chrom in featureDict.keys():
            self.assertTrue(chrom in self.celegansChroms)
            self.assertEquals(firstFeatures[chrom], featureDict[chrom][0])

        restrictList = ["almost certainly not a value feature"]
        featureDict = commoncode.getFeaturesByChromDict(self.genome, restrictList=restrictList)
        self.assertEquals({}, featureDict)

        restrictList = ["Y74C9A.3"]
        featureDict = commoncode.getFeaturesByChromDict(self.genome, restrictList=restrictList)
        self.assertEquals(["I"], featureDict.keys())
        featureDict, complementDict = commoncode.getFeaturesByChromDict(self.genome, restrictList=restrictList, regionComplement=True)
        result = {"I": [(0, 4123, "nonExon1", "F", "nonExon"),
                        (4219, 4220, "nonExon2", "F", "nonExon"),
                        (4357, 5194, "nonExon3", "F", "nonExon"),
                        (5295, 6036, "nonExon4", "F", "nonExon"),
                        (6326, 9726, "nonExon5", "F", "nonExon"),
                        (9845, 10094, "nonExon6", "F", "nonExon"),
                        (10147, 10148, "nonExon7", "F", "nonExon"),
                        (10231, 250000000, "nonExon8", "F", "nonExon")]
        }
        self.assertEquals(result, complementDict)

        additionalRegion = Region.Region(100, 150)
        additionalRegion.label = "new feature"
        regionDict = {"I": [additionalRegion]}
        featureDict = commoncode.getFeaturesByChromDict(self.genome, additionalRegionsDict=regionDict)
        result = (100, 150, "new feature", "+", "custom")
        self.assertEquals(result, featureDict["I"][0])
        


    def testGetLocusByChromDict(self):
        firstLoci = {"I": (4123, 10231, "Y74C9A.3", 6108),
                     "II": (1866, 4662, "2L52.1", 2796),
                     "III": (1270, 2916, "cTel54X.1", 1646),
                     "IV": (694, 14925, "Y38C1AB.4", 14231),
                     "V": (1479, 3038, "cTel3X.1", 1559),
                     "X": (3622, 7153, "CE7X_3.1", 3531),
                     "MtDNA": (112, 548, "MTCE.3", 436)
        }

        self.assertEquals({}, commoncode.getLocusByChromDict(self.genome, useCDS=False))
        self.assertEquals({}, commoncode.getLocusByChromDict(self.genome, upstream=1, downstream=1, useCDS=False))
        self.assertEquals({}, commoncode.getLocusByChromDict(self.genome, upstream=-1, downstream=-1, useCDS=False, lengthCDS=1))
        self.assertEquals({}, commoncode.getLocusByChromDict(self.genome, upstreamSpanTSS=True, lengthCDS=1))
        self.assertEquals({}, commoncode.getLocusByChromDict(self.genome, downstream=1, lengthCDS=1))
        self.assertEquals({}, commoncode.getLocusByChromDict(self.genome, upstream=1, lengthCDS=-1))

        locusDict = commoncode.getLocusByChromDict(self.genome)
        for chrom in locusDict.keys():
            self.assertTrue(chrom in self.celegansChroms)
            self.assertEquals(firstLoci[chrom], locusDict[chrom][0])

        additionalRegion = Region.Region(100, 150)
        additionalRegion.label = "new region"
        regionDict = {"I": [additionalRegion]}
        locusDict = commoncode.getLocusByChromDict(self.genome, additionalRegionsDict=regionDict)
        self.assertEquals((100, 150, "new region", 50), locusDict["I"][0])
        locusDict = commoncode.getLocusByChromDict(self.genome, additionalRegionsDict=regionDict, keepSense=True)
        self.assertEquals((100, 150, "new region", 50, "+"), locusDict["I"][0])

        # Long Test
        #locusDict = commoncode.getLocusByChromDict(self.genome, additionalRegionsDict=regionDict, useCDS=False, upstream=100)
        #self.assertEquals((150, 250, "new region", 100), locusDict["I"][0])

        # Long Test
        #locusDict = commoncode.getLocusByChromDict(self.genome, additionalRegionsDict=regionDict, useCDS=False, downstream=10)
        #self.assertEquals((90, 100, "new region", 10), locusDict["I"][0])


    def testComputeRegionBins(self):
        regionsByChromDict = {}
        hitDict = {}
        bins = 4
        readlen = 10
        result = ({}, {})
        self.assertEquals(result, commoncode.computeRegionBins(regionsByChromDict, hitDict, bins, readlen))

        regionsByChromDict = {"1": [("regionID", 1, 100, 100, "F")]}
        result = ({"regionID": [0.0, 0.0, 0.0, 0.0]}, {})
        self.assertEquals(result, commoncode.computeRegionBins(regionsByChromDict, hitDict, bins, readlen))

        regionsByChromDict = {"1": [("regionID", 1, 100, 100, "F")]}
        hitDict = {"1": [{"start": 1, "sense": "+", "weight": 1.0}]}
        result = ({"regionID": [1.0, 0.0, 0.0, 0.0]}, {"regionID": 100})
        self.assertEquals(result, commoncode.computeRegionBins(regionsByChromDict, hitDict, bins, readlen))

        regionsByChromDict = {"1": [("regionID", 1, 100, 100, "F")],
                              "2": [("regionID2", 1, 1000, 1000, "F")]
        }
        hitDict = {"1": [{"start": 1, "sense": "+", "weight": 1.0}],
                   "2": [{"start": 1, "sense": "+", "weight": 1.0}]
        }
        result = ({"regionID2": [1.0, 0.0, 0.0, 0.0], "regionID": [1.0, 0.0, 0.0, 0.0]}, {"regionID2": 1000, "regionID": 100})
        self.assertEquals(result, commoncode.computeRegionBins(regionsByChromDict, hitDict, bins, readlen))

        regionsByChromDict = {"1": [("regionID", 1, 100, 100, "F")]}
        hitDict = {"1": [{"start": 10, "sense": "+", "weight": 1.0}, {"start": 80, "sense": "+", "weight": 0.5}]}
        result = ({"regionID": [1.0, 0.0, 0.0, 0.5]}, {"regionID": 100})
        self.assertEquals(result, commoncode.computeRegionBins(regionsByChromDict, hitDict, bins, readlen))

        regionsByChromDict = {"1": [("regionID", 1, 100, 100, "F")]}
        hitDict = {"1": [{"start": 10, "sense": "+", "weight": 1.0}, {"start": 80, "sense": "+", "weight": 0.5}, {"start": 15, "sense": "+", "weight": 1.0}]}
        result = ({"regionID": [2.0, 0.0, 0.0, 0.5]}, {"regionID": 100})
        self.assertEquals(result, commoncode.computeRegionBins(regionsByChromDict, hitDict, bins, readlen))

        regionsByChromDict = {"1": [("regionID", 1, 100, 100, "F")]}
        hitDict = {"1": [{"start": 10, "sense": "+", "weight": 1.0}, {"start": 80, "sense": "+", "weight": 0.5}, {"start": 200, "sense": "+", "weight": 2.0}]}
        result = ({"regionID": [1.0, 0.0, 0.0, 0.5]}, {"regionID": 100})
        self.assertEquals(result, commoncode.computeRegionBins(regionsByChromDict, hitDict, bins, readlen))

        regionsByChromDict = {"1": [("regionID", 1, 100, 100, "F")]}
        hitDict = {"1": [{"start": 1, "sense": "+", "weight": 1.0}]}
        regionList = ["regionID"]
        result = ({"regionID": [1.0, 0.0, 0.0, 0.0]}, {"regionID": 100})
        self.assertEquals(result, commoncode.computeRegionBins(regionsByChromDict, hitDict, bins, readlen, regionList))

        regionsByChromDict = {"1": [("regionID", 1, 100, 100, "F")]}
        hitDict = {"1": [{"start": 1, "sense": "+", "weight": 1.0}]}
        regionList = ["empty region"]
        result = ({"empty region": [0.0, 0.0, 0.0, 0.0]}, {"regionID": 100})
        self.assertEquals(result, commoncode.computeRegionBins(regionsByChromDict, hitDict, bins, readlen, regionList))

        regionsByChromDict = {"1": [("regionID", 1, 100, 100, "F")],
                              "2": [("regionID2", 1, 1000, 1000, "F")]
        }
        hitDict = {"1": [{"start": 1, "sense": "+", "weight": 1.0}],
                   "2": [{"start": 1, "sense": "+", "weight": 1.0}]
        }
        regionList = ["regionID", "regionID2"]
        result = ({"regionID2": [1.0, 0.0, 0.0, 0.0], "regionID": [1.0, 0.0, 0.0, 0.0]}, {"regionID2": 1000, "regionID": 100})
        self.assertEquals(result, commoncode.computeRegionBins(regionsByChromDict, hitDict, bins, readlen, regionList))

        regionsByChromDict = {"1": [("regionID", 1, 100, 100, "F")],
                              "2": [("regionID2", 1, 1000, 1000, "F")]
        }
        hitDict = {"1": [{"start": 1, "sense": "+", "weight": 1.0}],
                   "2": [{"start": 1, "sense": "+", "weight": 1.0}]
        }
        regionList = ["empty region", "regionID2"]
        result = ({"regionID2": [1.0, 0.0, 0.0, 0.0], "empty region": [0.0, 0.0, 0.0, 0.0]}, {"regionID2": 1000, "regionID": 100})
        self.assertEquals(result, commoncode.computeRegionBins(regionsByChromDict, hitDict, bins, readlen, regionList))

        regionsByChromDict = {"1": [("regionID", 1, 100, 100, "F")],
                              "2": [("regionID2", 1, 1000, 1000, "F")]
        }
        hitDict = {"1": [{"start": 1, "sense": "+", "weight": 1.0}],
                   "2": [{"start": 1, "sense": "+", "weight": 1.0}]
        }
        regionList = ["regionID2"]
        result = ({"regionID2": [1.0, 0.0, 0.0, 0.0]}, {"regionID2": 1000, "regionID": 100})
        self.assertEquals(result, commoncode.computeRegionBins(regionsByChromDict, hitDict, bins, readlen, regionList))

        regionsByChromDict = {"1": [("regionID", 1, 100, 100, "F")]}
        hitDict = {"1": [{"start": 1, "sense": "+", "weight": 1.0}]}
        result = ({"regionID": [2.0, 0.0, 0.0, 0.0]}, {"regionID": 100})
        self.assertEquals(result, commoncode.computeRegionBins(regionsByChromDict, hitDict, bins, readlen, normalizedTag=2.0))

        regionsByChromDict = {"1": [(1, 100, "regionID", 100, "F")]}
        hitDict = {"1": [{"start": 1, "sense": "+", "weight": 1.0}]}
        result = ({"regionID": [1.0, 0.0, 0.0, 0.0]}, {"regionID": 100})
        self.assertEquals(result, commoncode.computeRegionBins(regionsByChromDict, hitDict, bins, readlen, defaultRegionFormat=False))

        regionsByChromDict = {"1": [("regionID", 1, 100, 100, "F")]}
        hitDict = {"1": [{"start": 10, "sense": "+", "weight": 1.0}]}
        fixedFirstBin = 20
        result = ({"regionID": [1.0, 0.0, 0.0, 0.0]}, {"regionID": 100})
        self.assertEquals(result, commoncode.computeRegionBins(regionsByChromDict, hitDict, bins, readlen, fixedFirstBin=fixedFirstBin))

        regionsByChromDict = {"1": [("regionID", 1, 100, 100, "F")]}
        hitDict = {"1": [{"start": 10, "sense": "+", "weight": 1.0}]}
        fixedFirstBin = 5
        result = ({"regionID": [0.0, 1.0, 0.0, 0.0]}, {"regionID": 100})
        self.assertEquals(result, commoncode.computeRegionBins(regionsByChromDict, hitDict, bins, readlen, fixedFirstBin=fixedFirstBin))

        regionsByChromDict = {"1": [("regionID", 1, 100, 100, "F")]}
        hitDict = {"1": [{"start": 10, "sense": "+", "weight": 1.0}, {"start": 85, "sense": "+", "weight": 0.5}]}
        fixedFirstBin = 20
        result = ({"regionID": [1.0, 0.5, 0.0, 0.0]}, {"regionID": 100})
        self.assertEquals(result, commoncode.computeRegionBins(regionsByChromDict, hitDict, bins, readlen, fixedFirstBin=fixedFirstBin))

        regionsByChromDict = {"1": [("regionID", 1, 100, 100, "F")]}
        hitDict = {"1": [{"start": 80, "sense": "+", "weight": 1.0}, {"start": 85, "sense": "+", "weight": 0.5}]}
        fixedFirstBin = 5
        result = ({"regionID": [0.0, 1.5, 0.0, 0.0]}, {"regionID": 100})
        self.assertEquals(result, commoncode.computeRegionBins(regionsByChromDict, hitDict, bins, readlen, fixedFirstBin=fixedFirstBin))

        regionsByChromDict = {"1": [("regionID", 1, 100, 100, "F")]}
        hitDict = {"1": [{"start": 10, "sense": "+", "weight": 1.0}, {"start": 85, "sense": "+", "weight": 0.5}]}
        binLength = 25
        result = ({"regionID": [1.0, 0.0, 0.0, 0.5]}, {"regionID": 100})
        self.assertEquals(result, commoncode.computeRegionBins(regionsByChromDict, hitDict, bins, readlen, binLength=binLength))

        regionsByChromDict = {"1": [("regionID", 1, 100, 100, "F")]}
        hitDict = {"1": [{"start": 10, "sense": "+", "weight": 1.0}, {"start": 85, "sense": "+", "weight": 0.5}]}
        binLength = 50
        result = ({"regionID": [1.0, 0.5, 0.0, 0.0]}, {"regionID": 100})
        self.assertEquals(result, commoncode.computeRegionBins(regionsByChromDict, hitDict, bins, readlen, binLength=binLength))

        regionsByChromDict = {"1": [("regionID", 1, 100, 100, "F")]}
        hitDict = {"1": [{"start": 10, "sense": "+", "weight": 1.0}, {"start": 85, "sense": "+", "weight": 0.5}]}
        binLength = 15
        result = ({"regionID": [1.0, 0.0, 0.0, 0.5]}, {"regionID": 100})
        self.assertEquals(result, commoncode.computeRegionBins(regionsByChromDict, hitDict, bins, readlen, binLength=binLength))

        regionsByChromDict = {"1": [("regionID", 1, 100, 100, "F")]}
        hitDict = {"1": [{"start": 10, "sense": "+", "weight": 1.0}, {"start": 40, "sense": "+", "weight": 0.7}, {"start": 85, "sense": "+", "weight": 0.5}]}
        binLength = 15
        result = ({"regionID": [1.0, 0.0, 0.7, 0.5]}, {"regionID": 100})
        self.assertEquals(result, commoncode.computeRegionBins(regionsByChromDict, hitDict, bins, readlen, binLength=binLength))

        regionsByChromDict = {"1": [("regionID", 1, 100, 100, "R")]}
        hitDict = {"1": [{"start": 10, "sense": "+", "weight": 1.0}, {"start": 40, "sense": "+", "weight": 0.7}, {"start": 85, "sense": "+", "weight": 0.5}]}
        result = ({"regionID": [0.5, 0.0, 0.7, 1.0]}, {"regionID": 100})
        self.assertEquals(result, commoncode.computeRegionBins(regionsByChromDict, hitDict, bins, readlen))
        result = ({"regionID": [0.5, 0.0, 0.7, 1.0]}, {"regionID": 100})
        fixedFirstBin = 10
        result = ({"regionID": [0.0, 2.2, 0.0, 0.0]}, {"regionID": 100})
        self.assertEquals(result, commoncode.computeRegionBins(regionsByChromDict, hitDict, bins, readlen, fixedFirstBin=fixedFirstBin))
        fixedFirstBin = 20
        result = ({"regionID": [0.5, 1.7, 0.0, 0.0]}, {"regionID": 100})
        self.assertEquals(result, commoncode.computeRegionBins(regionsByChromDict, hitDict, bins, readlen, fixedFirstBin=fixedFirstBin))
        binLength = 50
        result = ({"regionID": [0.5, 1.7, 0.0, 0.0]}, {"regionID": 100})
        self.assertEquals(result, commoncode.computeRegionBins(regionsByChromDict, hitDict, bins, readlen, binLength=binLength))
        binLength = 10
        result = ({"regionID": [0.0, 0.5, 0.0, 1.7]}, {"regionID": 100})
        self.assertEquals(result, commoncode.computeRegionBins(regionsByChromDict, hitDict, bins, readlen, binLength=binLength))


def suite():
    suite = unittest.TestSuite()
    suite.addTest(unittest.makeSuite(TestCommoncode))

    return suite


if __name__ == "__main__":
    #import sys;sys.argv = ['', 'Test.testName']
    unittest.main()