Commits

Guido Draheim  committed 2c3599e Merge

merge tag dvbcronrecording-0.4.18

  • Participants
  • Parent commits 8a8543d, d2cf50e
  • Branches dvbcronrecording

Comments (0)

Files changed (14)

 syntax: regexp
 ^src/TracSimpleRecorder\.egg-info$
 syntax: glob
+*.pyc
+syntax: glob
 *.egg-info
 syntax: regexp
 \.mo$
 syntax: regexp
 ^src/dvbcronrecording/locale/de/LC_MESSAGES/dvbcronrecording\.po$
 syntax: regexp
-^src/MANIFEST$
+^src/MANIFEST$
+syntax: regexp
+^\.settings$
+
 24d6992d570f23ffb0d5d033b8bde8c6957495eb dvbcronrecording-0.4.15
 9e2c68304789bef08fdd71ffb1455ee771383c9e dvbcronrecording-0.4.16
 395c51bb705e027352eb40dda3c2ebdc5409a74e dvbcronrecording-0.4.17
+4f6036dd024e926e9f5c8e84d58c76e82b0c0b8e dvbcronrecording-0.4.18

File .settings/org.eclipse.core.resources.prefs

-#Fri Sep 02 12:38:21 CEST 2011
-eclipse.preferences.version=1
-encoding//src/dvbcronrecording/channels.py=utf-8
-encoding//src/dvbcronrecording/channelsconf.py=utf-8
-encoding//src/dvbcronrecording/core.py=utf-8
-encoding//src/dvbcronrecording/db/tsab.py=utf-8
-encoding//src/dvbcronrecording/db/tsab2.py=utf-8
-encoding//src/dvbcronrecording/init.py=utf-8
-encoding//src/dvbcronrecording/tuning.py=utf-8
-encoding//src/setup.py=utf8
+PKG = dvbcronrecording
+SPECNAME = trac-$(PKG)-plugin
+
+prefix=/usr
+run: builds install
+all: builds install restart
+upd up: rpm update restart
+
+msg msgchk:
+	cd src && python setup.py copy_catalog
+	cd src && python setup.py extract_messages
+	cd src && python setup.py update_catalog
+	cd src && python setup.py compile_catalog
+	grep -B 2 'msgstr.*""' src/*/*/*/LC_MESSAGES/*.po | sed -e 's/^--$$//'
+msgfmt:
+	cd src && python setup.py copy_catalog
+	cd src && python setup.py compile_catalog
+	
+# builds: msgfmt
+builds: msgfmt
+	: cd src && python setup.py --help build 
+	cd src && python setup.py build --build-base=$(BUILDDIR)
+	
+install:
+	: cd src && python setup.py --help install 
+	cd src && sudo python setup.py build --build-base=$(BUILDDIR) \
+	    install --prefix=$(prefix) --root=/
+	
+clean:
+	cd src && sudo python setup.py clean --build-base=$(BUILDDIR)
+	
+tests unittest:
+	cd src && python setup.py build --build-base=$(BUILDDIR) \
+	   test $(CHECK)
+check:
+	PYTHONPATH=src \
+	python src/tests/computer_test.py -vv $(CHECK)
+test_%:
+	@ func1=`grep "def $@" src/tests/computer_test.py \
+	    | sed -e "s/.*def  *//" -e "s/[(].*//" -e q` \
+	; func2=`grep "def $@" src/tests/computer_tests.py \
+	    | sed -e "s/.*def  *//" -e "s/[(].*//" -e q` \
+	; if test -n "$$func1" \
+	; then echo $(MAKE) check CHECK=DvbComputerTests.$$func1 \
+	;           $(MAKE) check CHECK=DvbComputerTests.$$func1 \
+	; elif test -n "$$func2" \
+	; then echo $(MAKE) checks CHECK=DvbGeneratedTests.$$func2 \
+	;           $(MAKE) checks CHECK=DvbGeneratedTests.$$func2 \
+	; else echo "unknown $@"; exit 1 \
+	; fi
+
+genchecks:
+	PYTHONPATH=src \
+	python src/tests/computer_test.py ... 
+checks:
+	PYTHONPATH=src \
+	python src/tests/computer_tests.py -vv $(CHECK)
+
+
+RPMROOT=$(shell pwd)/rpm
+BUILDDIR = $(RPMROOT)/build
+RPMTEMP = '--define=_tmpath $(RPMROOT)/tmp'
+RPMBUILD =  rpmbuild '--define=_topdir $(RPMROOT)' \
+                     '--define=_builddir $(BUILDDIR)' \
+                $(RPMBUILDOPTIONS)
+
+# setuptools sdist is broken for package_data in 0.6c11 vs python 2.6.5, known bug!
+# It does simply not work - so use "make dist" instead of "setup.py sdist"
+sdist:
+	test -d $(RPMROOT)/SOURCES || mkdir -p $(RPMROOT)/SOURCES
+	cd src && python setup.py sdist --dist-dir $(RPMROOT)/SOURCES -v -v 
+dist: msgfmt
+	: cd src && python setup.py sdist --build-base=$(BUILDDIR) \
+	   --dist-dir SOURCES -v -v $X
+	test -d $(RPMROOT)/SOURCES || mkdir -p $(RPMROOT)/SOURCES
+	cd src && tar czvf $(RPMROOT)/SOURCES/$(PKG).tgz *.py *.cfg *.txt *.spec $(PKG)/
+	ls -l $(RPMROOT)/SOURCES/$(PKG).tgz
+	@ version=`cat $(SPECNAME).spec | sed -e '/define _version/!d' -e 's/.*_version //'` \
+	; echo mv $(RPMROOT)/SOURCES/$(PKG).tgz $(RPMROOT)/SOURCES/$(PKG)-$$version.tgz \
+	;      mv $(RPMROOT)/SOURCES/$(PKG).tgz $(RPMROOT)/SOURCES/$(PKG)-$$version.tgz
+
+rpm: dist
+	test -d $(RPMROOT)/RPMS || mkdir $(RPMROOT)/RPMS
+	test -d $(RPMROOT)/SRPMS || mkdir $(RPMROOT)/SRPMS
+	test -d $(RPMROOT)/BUILD || mkdir $(RPMROOT)/BUILD
+	test -d $(RPMROOT)/SPECS || mkdir $(RPMROOT)/SPECS
+	- test -d $(BUILDDIR)/$(PKG) && rm -rf $(BUILDDIR)/*
+	cp src/$(SPECNAME).spec $(RPMROOT)/SPECS/$(SPECNAME).spec
+	revision=`hg summary| sed -e '/parent:/!d' -e 's/parent: *//' -e 's/:.*//'` \
+	; if [ -n "$$revision" ]; then set -x \
+	;   sed -i -e "s/revision 0/revision $$revision/"  $(RPMROOT)/SPECS/$(SPECNAME).spec \
+	; else today=`date +%Y%m%d` \
+	;   sed -i -e "s/revision 0/revision 0.$$today/"  $(RPMROOT)/SPECS/$(SPECNAME).spec \
+	; fi
+	$(RPMBUILD) -ba $(RPMROOT)/SPECS/$(SPECNAME).spec
+
+update:
+	@ spec="$(RPMROOT)/SPECS/$(SPECNAME).spec" \
+	; version=`cat "$$spec" | sed -e '/define _version/!d' -e 's/.*_version *//'` \
+	; package=`cat "$$spec" | sed -e '/Name:/!d' -e 's/Name: *//'` \
+	; rev=`cat "$$spec" | sed -e '/define revision/!d' -e 's/.*revision *//' -e 's/ .*//'` \
+	; echo rpm -U --force $(RPMROOT)/RPMS/noarch/$$package-$$version.$$rev*.noarch.rpm \
+	;      rpm -U --force $(RPMROOT)/RPMS/noarch/$$package-$$version.$$rev*.noarch.rpm
+	   
+trac restart:
+	sudo /sbin/service tracd restart
+
+OSC_ROOT = /my/own/osc
+OSC_PROJECT = home:guidod:trac12
+OSC_PACKAGE = trac-dvbcronrecording-plugin
+OSC = $(OSC_ROOT)/$(OSC_PROJECT)/$(OSC_PACKAGE)
+osc: dist
+	@ version=`cat src/$(SPECNAME).spec | sed -e '/define _version/!d' -e 's/.*_version //'` \
+	; tarball="$(RPMROOT)/SOURCES/$(PKG)-$$version.tgz" \
+	; specpath="$(RPMROOT)/SPECS/$(SPECNAME).spec" \
+	; if [ -f "$$tarball" ]; then set -x \
+	;    (cd $(OSC) && osc rm *.tgz) \
+	;    cp -v "$$tarball" $(OSC)/ \
+	;    (cd $(OSC) && osc add `basename "$$tarball"` \
+	;    cp -v "$$specpath" $(OSC)/$(SPECNAME).spec \
+	;    (cd $(OSC) && osc ci -m "update $$version") \
+	; else : \
+	;    echo "failed to find $$tarball" \
+	; fi	  
+
+.PHONY: osc trac restart update install dist sdist msgfmt
+	

File src/GNUmakefile

-PKG = dvbcronrecording
-SPECNAME = trac-$(PKG)-plugin
-
-prefix=/usr
-run: builds install
-all: builds install restart
-upd up: rpm update restart
-
-
-msg msgchk:
-	python setup.py copy_catalog
-	python setup.py extract_messages
-	python setup.py update_catalog
-	python setup.py compile_catalog
-	grep -B 2 'msgstr.*""' */*/*/LC_MESSAGES/*.po | sed -e 's/^--$$//'
-msgfmt:
-	python setup.py copy_catalog
-	python setup.py compile_catalog
-	
-# builds: msgfmt
-builds: msgfmt
-	: python setup.py --help build 
-	python setup.py build --build-base=$(BUILDDIR)
-	
-install:
-	: python setup.py --help install 
-	sudo python setup.py build --build-base=$(BUILDDIR) \
-	    install --prefix=$(prefix) --root=/
-	
-clean:
-	sudo python setup.py clean --build-base=$(BUILDDIR)
-	
-tests unittest check:
-	python setup.py build --build-base=$(BUILDDIR) \
-	   test
-
-RPMROOT=$(dir $(shell pwd))/rpm
-BUILDDIR = $(RPMROOT)/build
-RPMTEMP = '--define=_tmpath $(RPMROOT)/tmp'
-RPMBUILD =  rpmbuild '--define=_topdir $(RPMROOT)' \
-                     '--define=_builddir $(BUILDDIR)' \
-                $(RPMBUILDOPTIONS)
-
-# setuptools sdist is broken for package_data in 0.6c11 vs python 2.6.5, known bug!
-# It does simply not work - so use "make dist" instead of "setup.py sdist"
-sdist:
-	test -d $(RPMROOT)/SOURCES || mkdir -p $(RPMROOT)/SOURCES
-	python setup.py sdist --dist-dir $(RPMROOT)/SOURCES -v -v 
-dist: msgfmt
-	: python setup.py sdist --build-base=$(BUILDDIR) \
-	   --dist-dir SOURCES -v -v $X
-	test -d $(RPMROOT)/SOURCES || mkdir -p $(RPMROOT)/SOURCES
-	tar czvf $(RPMROOT)/SOURCES/$(PKG).tgz *.py *.cfg *.txt *.spec $(PKG)/
-	ls -l $(RPMROOT)/SOURCES/$(PKG).tgz
-	@ version=`cat $(SPECNAME).spec | sed -e '/define _version/!d' -e 's/.*_version //'` \
-	; echo mv $(RPMROOT)/SOURCES/$(PKG).tgz $(RPMROOT)/SOURCES/$(PKG)-$$version.tgz \
-	;      mv $(RPMROOT)/SOURCES/$(PKG).tgz $(RPMROOT)/SOURCES/$(PKG)-$$version.tgz
-
-rpm: dist
-	test -d $(RPMROOT)/RPMS || mkdir $(RPMROOT)/RPMS
-	test -d $(RPMROOT)/SRPMS || mkdir $(RPMROOT)/SRPMS
-	test -d $(RPMROOT)/BUILD || mkdir $(RPMROOT)/BUILD
-	test -d $(RPMROOT)/SPECS || mkdir $(RPMROOT)/SPECS
-	- test -d $(BUILDDIR)/$(PKG) && rm -rf $(BUILDDIR)/*
-	cp $(SPECNAME).spec $(RPMROOT)/SPECS/$(SPECNAME).spec
-	revision=`hg summary| sed -e '/parent:/!d' -e 's/parent: *//' -e 's/:.*//'` \
-	; if [ -n "$$revision" ]; then set -x \
-	;   sed -i -e "s/revision 0/revision $$revision/"  $(RPMROOT)/SPECS/$(SPECNAME).spec \
-	; else today=`date +%Y%m%d` \
-	;   sed -i -e "s/revision 0/revision 0.$$today/"  $(RPMROOT)/SPECS/$(SPECNAME).spec \
-	; fi
-	$(RPMBUILD) -ba $(RPMROOT)/SPECS/$(SPECNAME).spec
-
-update:
-	@ spec="$(RPMROOT)/SPECS/$(SPECNAME).spec" \
-	; version=`cat "$$spec" | sed -e '/define _version/!d' -e 's/.*_version *//'` \
-	; package=`cat "$$spec" | sed -e '/Name:/!d' -e 's/Name: *//'` \
-	; rev=`cat "$$spec" | sed -e '/define revision/!d' -e 's/.*revision *//' -e 's/ .*//'` \
-	; echo rpm -U --force $(RPMROOT)/RPMS/noarch/$$package-$$version.$$rev*.noarch.rpm \
-	;      rpm -U --force $(RPMROOT)/RPMS/noarch/$$package-$$version.$$rev*.noarch.rpm
-	   
-trac restart:
-	sudo /sbin/service tracd restart
-
-OSC_ROOT = /my/own/osc
-OSC_PROJECT = home:guidod:trac12
-OSC_PACKAGE = trac-dvbcronrecording-plugin
-OSC = $(OSC_ROOT)/$(OSC_PROJECT)/$(OSC_PACKAGE)
-osc: dist
-	@ version=`cat $(SPECNAME).spec | sed -e '/define _version/!d' -e 's/.*_version //'` \
-	; tarball="$(RPMROOT)/SOURCES/$(PKG)-$$version.tgz" \
-	; specpath="$(RPMROOT)/SPECS/$(SPECNAME).spec" \
-	; if [ -f "$$tarball" ]; then set -x \
-	;    (cd $(OSC) && osc rm *.tgz) \
-	;    cp -v "$$tarball" $(OSC)/ \
-	;    (cd $(OSC) && osc add `basename "$$tarball"` \
-	;    cp -v "$$specpath" $(OSC)/$(SPECNAME).spec \
-	;    (cd $(OSC) && osc ci -m "update $$version") \
-	; else : \
-	;    echo "failed to find $$tarball" \
-	; fi	  
-
-.PHONY: osc trac restart update install dist sdist msgfmt
-
-	

File src/dvbcronrecording/computer.py

     from channels import DvbCronRecordingChannelsPlugin
 except:
     DvbCronRecordingChannelsPlugin = None
-    
+
 from translate import Translate
 
 DEBUG = False
     if value is None: return default
     try: return int(value)
     except Exception: return default
+    
+def ustar(text):
+    if text is None:
+        return "*"
+    return u"%s" % text
 
 class ChainEntry:
     def __init__(self):
         item.adapter = self.adapter
         return item
     def __unicode__(self):
-        return u"(%s) '%s'" % (unicode(self.months), unicode(self.title))
+        months = u",".join([unicode(month) for month in self.months])
+        x = u"{ "
+        if self.newtimeMMM == self.endtimeMMM and not self.extratimeM:
+            x += u" [--DELETED--]  "
+        else:
+            x += u" [%s-%s]+%s" % (MMMtoHHMM(self.newtimeMMM), MMMtoHHMM(self.endtimeMMM), self.extratimeM)
+        x += u" %s@%s" % (self.channelname, ustar(self.adapter))
+        x += u" (%s %s %s)" % (ustar(self.onlyday), ustar(months), ustar(self.weekday))
+        x += u" '%s'" % (unicode(self.title))
+        x += u" }"
+        return x
     def __str__(self):
         return unicode(self).encode("UTF-8")
     
         self.extratimeM = None
         self.adapter = None
     def __unicode__(self):
-        return u"["+unicode(",".join([unicode(item) for item in self.items]))+"]"
+        return u"[%s]" % (u",\n  ".join([unicode(item) for item in self.items]))
+    def __str__(self):
+        return unicode(self)
 
 class RecorderGroupPlan:
     def __init__(self):
         """ datetimeX, datetimeY, adapter from timelist_groups() """
         groups = sorted(self._groups, key = lambda x: (x.datetimeX, x.datetimeY, x.adapter))
         self._groups = groups
+    def __unicode__(self):
+        groups = [unicode(item) for item in self._groups]
+        return u"\n{%s}" % (u",\n ".join(groups))
+    def __str__(self):
+        return unicode(self)
 
 class RecorderFlatPlan:
     def __init__(self):
     def __init__(self):
         self._adapters = {}
         self._adapterlist = None
+        self._localtime = None
         self.logg = logging.getLogger(__name__)
-    
+    def localtime(self):
+        if self._localtime is not None:
+            return self._localtime # for unittests
+        return time.localtime()
     def adapters(self, channelname):
         if channelname in self._adapters:
             return self._adapters[channelname]
     def set_adapters_from_channels_list(self, channelslist):
         for entry in channelslist:
             channelname = entry.channelname
-            adapter = entry.adapter
+            adapter = ustar(entry.adapter)
             if channelname not in self._adapters:
                 self._adapters[channelname] = []
             if adapter not in self._adapters[channelname]:
         for adapters in self._adapters.values():
             for adapter in adapters:
                 if adapter and adapter not in adapterlist:
-                    adapterlist += [ adapter ]
+                    adapterlist += [ ustar(adapter) ]
         self._adapterlist = adapterlist
     def adapterlist(self):
         """ get the union of available adapters used in configured channels """
         if self._adapterlist is None:
-            self.updated_adapterlist()
+            self.update_adapterlist()
         adapterlist = self._adapterlist[:]
         if not adapterlist:
             return [ default_adapter ]
         return None
     
     def get_allowed_months(self, ahead = months_ahead):
-        this_month = time.localtime().tm_mon
+        this_month = self.localtime().tm_mon
         allowed = []
         for add_months in xrange(months_ahead):
             month = this_month + add_months
         return allowed
     
     def get_past_days_this_month(self):
-        today = time.localtime()
+        today = self.localtime()
         this_month = today.tm_mon
         this_day = today.tm_mday
         allowed = []
     def recordinglist_to_recorderitems(self, entries, ahead = months_ahead):
         allowed_months = self.get_allowed_months(ahead)
         past_days = self.get_past_days_this_month()
-        self.logg.debug("allowed_months %s" % (str(allowed_months)))    
+        self.logg.debug("    allowed_months %s" % (str(allowed_months)))    
         for entry in entries:
             if entry.status == "no": 
-                self.logg.debug("status disabled for %s", entry.title) 
+                self.logg.debug("    status disabled for %s", entry.title) 
                 continue
             item = RecorderItem()
             item.channelname = entry.channelname
             item.title = entry.title
             if not item.title:
-                self.logg.debug("item had not title") 
+                self.logg.debug("    item had not title") 
                 continue            
             if not item.channelname: 
-                self.logg.debug("no channel name for '%s", item.title) 
+                self.logg.debug("    no channel name for '%s", item.title) 
                 continue            
             m = re.match("(\d+)[.](\d+)[.]", entry.onlydate)
             if m:
-                self.logg.debug("onlydate %s for %s", entry.onlydate, item.title)
+                self.logg.debug("    onlydate %s for %s", entry.onlydate, item.title)
                 try:
                     onlyday = intnull(m.group(1))
                     onlymonth = intnull(m.group(2))
                     if not onlyday: continue
                     if not onlymonth: continue
                     if onlymonth not in allowed_months:
-                        self.logg.debug("onlymonth not in allowed_months '%s'", item.title) 
+                        self.logg.debug("    onlymonth not in allowed_months '%s'", item.title) 
                         continue
                     if (onlyday, onlymonth) in past_days: 
-                        self.logg.debug("(onlyday, onlymonth) in past_days '%s'", item.title) 
+                        self.logg.debug("    (onlyday, onlymonth) in past_days '%s'", item.title) 
                         continue
                     item.onlyday = onlyday
                     item.months = [ onlymonth ]
-                    self.logg.debug("onlyday %s onlymonths %s for %s", item.onlyday, item.months, item.title)
+                    self.logg.debug("    onlyday %s onlymonths %s for %s", item.onlyday, item.months, item.title)
                 except Exception:
-                    self.logg.debug("conversion error %s '%s'", entry.onlydate, item.title)
+                    self.logg.debug("    conversion error %s '%s'", entry.onlydate, item.title)
                 item.weekday = intnull(entry.weekday)
             else: 
                 item.weekday = intnull(entry.weekday)
                 if item.weekday is None:
-                    self.logg.debug("item.weekday is None '%s'", item.title) 
+                    self.logg.debug("    item.weekday is None '%s'", item.title) 
                     continue
                 if item.weekday >= 7: item.weekday = item.weekday % 7
             item.newtimeMMM = self.zero(self.minutes(entry.newtime))
             except: pass
             if item.channelname in self.rankup_channels:
                 item.rank += self.rankup_value
-            self.logg.debug("originally %s-%s '%s'" % (entry.newtime, entry.endtime, item.title))
+            self.logg.debug("    originally %s-%s '%s'" % (entry.newtime, entry.endtime, item.title))
             yield item
     def recordinglist_to_recordergroups(self, entries, ahead = months_ahead):
         recorderitems = list(self.recordinglist_to_recorderitems(entries, ahead))
             for month in item.months: 
                 if month not in onlymonths:
                     onlymonths.append(month)
-        self.logg.debug("onlymonths %s", onlymonths)
+        self.logg.debug("    onlymonths %s", onlymonths)
         regularmonths = [ month for month in xrange(1,13) if month not in onlymonths ]
-        self.logg.debug("regularmonths %s", regularmonths)
-        localtime = time.localtime()
+        self.logg.debug("    regularmonths %s", regularmonths)
+        localtime = self.localtime()
         this_month = localtime.tm_mon
         this_year = localtime.tm_year
         past_days = self.get_past_days_this_month()
                     # no generate the recordings for that day
                     items = self.clone_filtered_for_date(recorderitems, date)
                     for group in self.recordergroups_from_filtered(items):
-                        self.logg.debug("onlydate group %s", unicode(group))
+                        self.logg.debug("    onlydate group %s", unicode(group))
                         yield group
                 except ValueError:
                     pass # expected
         self.logg.debug("=======================================================")
         items = list(items)
         for item in items:
-            self.logg.debug("regular item %s", unicode(item))
+            self.logg.debug("    regular item %s", unicode(item))
         for group in self.recordergroups_from_filtered(items):
-            self.logg.debug("regular group %s", unicode(group))
+            self.logg.debug("    regular group %s", unicode(group))
             yield group
     def clone_filtered_for_date(self, recorderitems, date):
         for item in recorderitems:
             of newtime-endtime is the recording time interval. """
         yield self.adjust_recordergroup(group) 
     def adjust_recordergroup(self, group):
-        self.logg.debug("adjust group %s", unicode(group))
+        self.logg.debug("    adjust group %s", unicode(group))
         nextday = 0
         previous = None
         for item in group.items:
             nextday = 0
         return group
     def make_cronmonths(self, group):
-        self.logg.debug("adjust group %s", unicode(group))
+        self.logg.debug("    adjust group %s", unicode(group))
         for item in group.items:
             ranges = []
             months = item.months
         return plan
     def recordinglist_to_flat_recorderitems(self, entries, ahead = months_ahead):
         recorderitems = list(self.recordinglist_to_recorderitems(entries, ahead))
-        localtime = time.localtime()
+        localtime = self.localtime()
         this_month = localtime.tm_mon
         this_year = localtime.tm_year
         past_days = self.get_past_days_this_month()
         return plan
     def recordinglist_to_recordertimelist(self, entries, ahead = months_ahead):
         recorderitems = list(self.recordinglist_to_recorderitems(entries, ahead))
-        localtime = time.localtime()
+        localtime = self.localtime()
         this_month = localtime.tm_mon
         this_year = localtime.tm_year
         past_days = self.get_past_days_this_month()
             if month < this_month: year += 1
             for day in xrange(1,32):
                 if (day, month) in past_days: continue
+                date = None
                 try:
                     # ValueError if invalid day-of-month
                     date = datetime.datetime(year, month, day)
+                except ValueError, e:
+                    pass
+                if date is None:
+                    continue
+                try:
+                    # self.logg.debug("    %s datetime(%s,%s,%s)", len(recorderitems), year, month, day)
                     for item in recorderitems:
                         if item.onlyday: 
                             if item.onlyday != date.day: continue
                             if date.month not in item.months: continue
                         else:
                             if item.weekday != date.weekday(): continue
-                        self.logg.debug("* %s => [%s.%s.] w%s '%s'", date, item.onlyday, item.months, item.weekday, item.title)
+                        # self.logg.debug("    ITEM %s", item)
                         newtimeMMM = item.newtimeMMM
                         endtimeMMM = item.endtimeMMM
                         if endtimeMMM < newtimeMMM: endtimeMMM += 24 * 60
                         elem.adapters = self.adapters(item.channelname)
                         # elem.message += " (([%s .. %s] from %s..%s))" % (elem.datetimeX, elem.datetimeY, newtimeMMM, endtimeMMM)
                         yield elem
+                except Exception, e:
+                    self.logg.error("ERROR %s", e)
                 except:
-                    pass
+                    self.logg.error("FATAL ERROR")
     def adjust_recordertimelist(self, req, recordertimelist, adapter = None):
         """ recordertimelist contains absolute X Y dates """
         _ = Translate(PACKAGE, req.locale)
                 if previous.datetimeX > current.datetimeX:
                     if previous.datetimeY < current.datetimeY:
                         # previous is fully inside the current times -> delete
+                        self.logg.debug("    %s deleted as moved inside", previous.item.title)
                         previous.message += _(" deleted as moved inside")
                         previous.datetimeY = previous.datetimeX
                         previous.newtimeMMM = previous.endtimeMMM
                         previous = current
                         continue
                     else:
-                        msg = (u"previous starts after current\nPREV %s\nNEXT %s" 
-                               % (previous, current))
-                        raise Exception(msg)                        
+                        # we would actually need to swap it around
+                        # the previous gets a start time after current.
+                        self.logg.debug("    %s previous moved after next recording - swapped around,", previous.item.title)
+                        previous.message += _(" previous moved after next recording - swapped around,")
+                        previous.datetimeX = current.datetimeY
+                        previous.newtimeMMM = current.endtimeMMM + current.extratimeM
+                        # we try to keep the computation correct by letting
+                        # the previous item to stay.
+                        previous = previous
+                        continue 
+                        # msg = (u"previous starts after current\nPREV %s\nNEXT %s" 
+                        #        % (previous, current))
+                        # raise Exception(msg)                        
                 # move previous endtime down
                 if overlapM <= previous.extratimeM:
                     previous.extratimeM -= overlapM
                     previous.datetimeY -= overlapY
                     if current.item.channelname != previous.item.channelname:
                         previous.message += _(" extra minutes minus %03d,") % overlapM
+                        self.logg.debug("   ^%s extra minutes minus", previous.item.title)
                     else:
                         previous.message += _(" continues")
+                        self.logg.debug("   ^%s continues", previous.item.title)
                     previous = current
                 else: 
                     extraY = datetime.timedelta(minutes = previous.extratimeM)
                         previous.endtimeMMM = previous.newtimeMMM
                         previous.extratimeM = 0
                         previous.message += _(" deleted as next one starts %s,") % MMMtoHHMM(current.newtimeMMM)
+                        self.logg.debug("   ^%s deleted as next one starts", previous.item.title)
                     else:
                         if previous.datetimeY > current.datetimeX:
                             previous.datetimeY = current.datetimeX
                             previous.endtimeMMM = current.newtimeMMM
                             if current.item.channelname != previous.item.channelname:
                                 previous.message += _(" end time set to next start %s,") % MMMtoHHMM(current.newtimeMMM)
+                                self.logg.debug("   ^%s end time set to next start", previous.item.title)
                             else:
                                 previous.message += _(" continues")
+                                self.logg.debug("   ^%s continues", previous.item.title)
                         if previous.datetimeY - previous.datetimeX < minimum:
                             previous.deleted = True
                             previous.datetimeY = previous.datetimeX
                             previous.endtimeMMM = previous.newtimeMMM
                             previous.extratimeM = 0
                             previous.message += _(" and deleted as it is too short now")
+                            self.logg.debug("   ^%s and deleted as it is too short now", previous.item.title)
                         else:
                             previous = current
             else: # previous.item.rank >= current.item.rank
                 # ..move current starttime up
                 if previous.datetimeX > current.datetimeX:
                     if previous.datetimeX >= current.datetimeY:
-                        msg = (u"previous starts after current\nPREV %s\nNEXT %s" 
-                               % (previous, current))
-                        raise Exception(msg)
+                        previous.deleted = True
+                        previous.datetimeY = previous.datetimeX
+                        previous.endtimeMMM = previous.newtimeMMM
+                        previous.extratimeM = 0
+                        previous.message += _(" and deleted as it is moved inside the other recording")
+                        self.logg.debug("   ^%s and deleted as it is moved inside the other recording", previous.item.title)
                     else:
                         current.datetimeX = previous.datetimeX
                         current.newtimeMMM = previous.endtimeMMM
                         current.message += _(" set start time to previous start %s,") % MMMtoHHMM(current.newtimeMMM)
+                        self.logg.debug("   %s set start time to previous start", current.item.title)
                         assert previous.datetimeY > current.datetimeX
                 if current.datetimeY <= previous.datetimeY:
                     if previous.datetimeX > current.datetimeX:
-                        current.message+= _(" previous starts after current")
+                        current.message += _(" previous starts after current")
+                        self.logg.debug("   %s previous starts after current", current.item.title)
                     current.deleted = True
                     current.datetimeX = current.datetimeY
                     current.newtimeMMM = current.endtimeMMM
                     current.extratimeM = 0
                     current.message += _(" deleted as previous one ends %s,") % MMMtoHHMM(previous.endtimeMMM)
+                    self.logg.debug("   %s deleted as previous one ends", current.item.title)
                 else:
                     if current.datetimeX < previous.datetimeY:
                         current.datetimeX = previous.datetimeY
                         current.newtimeMMM = previous.endtimeMMM + previous.extratimeM
                         if current.item.channelname != previous.item.channelname:
                             current.message += _(" set start time to previous end %s,") % MMMtoHHMM(current.newtimeMMM)
+                            self.logg.debug("   %s set start time to previous end", current.item.title)
                         else:
                             current.message += _(" continues")
+                            self.logg.debug("   %s continues", current.item.title)
                     if current.datetimeY - current.datetimeX < minimum:
                         current.deleted = True
                         current.datetimeX = current.datetimeY
                         current.newtimeMMM = current.endtimeMMM
                         current.extratimeM = 0
                         current.message += _(" and deleted as it is too short now")
+                        self.logg.debug("   %s and deleted as it is too short now", current.item.title)
                     else:
                         previous = current
     def assign_adapters_for_timelist(self, recordertimelist):
                             previous.adapter = adapter
                             done = True; break
             if not done:
-                # can not split overlapping recordings to different adapers
+                self.logg.debug(" can not split overlapping recordings to different adapers")
                 pass
     def timelist_groups(self, req, timelist, adapter = None):
         _ = Translate(PACKAGE, req.locale)
         predeletes = []
         seen = ""
         for elem in timelist:
-            self.logg.debug("timelist_groups: adapter '%s' -vs- '%s'",
+            self.logg.debug("    timelist_groups: adapter '%s' -vs- '%s'",
                       adapter, elem.adapter)            
             if adapter is not None and elem.adapter is not None:
                 if adapter != elem.adapter:
             item.months = [ elem.datetimeX.month ]
             item.adapter = elem.adapter
             if item.newtimeMMM != elem.item.newtimeMMM:
+                self.logg.debug(" [%s]>>[%s]" % (MMMtoHHMM(elem.item.newtimeMMM), MMMtoHHMM(item.newtimeMMM))) 
                 item.message += " [%s]>>[%s]" % (MMMtoHHMM(elem.item.newtimeMMM), MMMtoHHMM(item.newtimeMMM))
             if item.endtimeMMM != elem.item.endtimeMMM:
+                self.logg.debug(" [%s]<<[%s]" % (MMMtoHHMM(item.endtimeMMM), MMMtoHHMM(elem.item.endtimeMMM)))
                 item.message += " [%s]<<[%s]" % (MMMtoHHMM(item.endtimeMMM), MMMtoHHMM(elem.item.endtimeMMM))
             # ==>
             if not group or elem.datetimeX > previous.datetimeY:
                 if group:
                     yield group ; previousgroup = group; group = None
                 item.message = " ."+item.message
-                if elem.deleted: 
+                if elem.deleted:
+                    self.logg.debug("   [DEL] %s", item.title) 
                     item.message += _(" [DEL]")
                     predeletes += [ item ]
                 else:
                 # HANDOVER
                 item.message = " :"+item.message
                 if elem.deleted: 
+                    self.logg.debug("   [DEL] %s", item.title)
                     item.message += _(" [DEL]")
                     group.items += [ item ]
                 else:
     def plan4(self, req, entries):
         """ main entry point """
         self.logg.info("plan4")
+        for elem in entries:
+            self.logg.debug("[0] %s", elem)
         timelist = list(self.recordinglist_to_recordertimelist(entries))
+        for elem in timelist:
+            self.logg.debug("[1] %s", elem)
         self.assign_adapters_for_timelist(timelist)
         old_deleted = 0
         for round in xrange(2):
             if old_deleted < new_deleted:
                 old_deleted = new_deleted
                 continue
+        for elem in timelist:
+            self.logg.debug("[2] %s", elem)
         timelist = sorted(timelist, key = lambda x: x.datetimeX )
         plan = RecorderGroupPlan()
         for adapter in self.adapterlist():
             for group in self.timelist_groups(req, timelist, adapter):
                 plan.addgroup(group)
-        self.logg.info("adapterlist = %s", self.adapterlist())
+        self.logg.info(" - adapterlist = %s", self.adapterlist())
+        for elem in timelist:
+            self.logg.debug("[3] %s", elem)
         if True:
             plan.timelist_sort()
             return self.new_reduce_regular_groups(plan)

File src/dvbcronrecording/dvbcronrecording.de.po

 msgstr " gelöscht denn die Aufnahme ist nun zu kurz"
 
 #
+msgid " and deleted as it is moved inside the other recording"
+msgstr " gelöscht denn Aufnahme liegt nun innerhalb der anderen"
+#
 msgid " previous starts after current"
 msgstr " vorherige Aufnahme startet nach aktueller"
 
 msgid " deleted as moved inside"
 msgstr " gelöscht da nun innerhalb"
 
-msgid "  set start time to previous start %s,"
+msgid " set start time to previous start %s,"
 msgstr " Startzeit gesetzt auf vorige Startzeit %s,"
+
+msgid " previous moved after next recording - swapped around,"
+msgstr " vorige verschoben hinter nächste Aufname - vertauscht,"

File src/dvbcronrecording/locale/dvbcronrecording.pot

-#: dvbcronrecording/computer.py:696
+#: dvbcronrecording/computer.py:692
+msgid " deleted as moved inside"
+msgstr ""
+
+#: dvbcronrecording/computer.py:702
+msgid " previous moved after next recording - swapped around,"
+msgstr ""
+
+#: dvbcronrecording/computer.py:717
 #, python-format
 msgid " extra minutes minus %03d,"
 msgstr ""
 
-#: dvbcronrecording/computer.py:698 dvbcronrecording/computer.py:717
-#: dvbcronrecording/computer.py:747
+#: dvbcronrecording/computer.py:719 dvbcronrecording/computer.py:738
+#: dvbcronrecording/computer.py:778
 msgid " continues"
 msgstr ""
 
-#: dvbcronrecording/computer.py:709
+#: dvbcronrecording/computer.py:730
 #, python-format
 msgid " deleted as next one starts %s,"
 msgstr ""
 
-#: dvbcronrecording/computer.py:715
+#: dvbcronrecording/computer.py:736
 #, python-format
 msgid " end time set to next start %s,"
 msgstr ""
 
-#: dvbcronrecording/computer.py:723 dvbcronrecording/computer.py:753
+#: dvbcronrecording/computer.py:744 dvbcronrecording/computer.py:784
 msgid " and deleted as it is too short now"
 msgstr ""
 
-#: dvbcronrecording/computer.py:730
+#: dvbcronrecording/computer.py:757
+#, python-format
+msgid " set start time to previous start %s,"
+msgstr ""
+
+#: dvbcronrecording/computer.py:761
 msgid " previous starts after current"
 msgstr ""
 
-#: dvbcronrecording/computer.py:735
+#: dvbcronrecording/computer.py:766
 #, python-format
 msgid " deleted as previous one ends %s,"
 msgstr ""
 
-#: dvbcronrecording/computer.py:745
+#: dvbcronrecording/computer.py:776
 #, python-format
 msgid " set start time to previous end %s,"
 msgstr ""
 
-#: dvbcronrecording/computer.py:837 dvbcronrecording/computer.py:855
+#: dvbcronrecording/computer.py:864 dvbcronrecording/computer.py:882
 msgid " [DEL]"
 msgstr ""
 

File src/dvbcronrecording/translate.py

+# -*- encoding: utf-8 -*-
 import pkg
 import os.path
 

File src/setup.py

   description = README,
   license = '''BSD''',
   message_extractors = extractors, cmdclass = cmdclass,
+  test_suite = 'tests'
 )

File src/tests/__init__.py

+

File src/tests/computer_test.py

+import unittest
+import time
+
+import logging
+_logg = logging.getLogger("TESTS")
+if not _logg.handlers:
+    _logg.addHandler(logging.StreamHandler())
+    _logg.setLevel(logging.INFO)
+
+from dvbcronrecording.computer import DvbCronRecordingPlanComputer
+from trac.core import ComponentManager
+
+# fix this...
+def get(self, instance, owner):
+     if instance is None:
+         return self
+     config = getattr(instance, 'config', None)
+     if config and isinstance(config, Configuration):
+         section = config[self.section]
+         value = self.accessor(section, self.name, self.default)
+         return value
+     return self.default
+ 
+from trac.config import Option
+Option.__get__ = get
+
+import collections
+Channel = collections.namedtuple("Channel",["channelname", "adapter"])
+Entry = collections.namedtuple("Entry",["channelname","title",
+    "newtime","endtime", "extratime", "weekday", "onlydate", "status", "priority"])
+Locale = collections.namedtuple("Locale",["language"])
+Request = collections.namedtuple("Request",["locale"])
+
+class DvbComputerTests(unittest.TestCase):
+    env = None
+    logg = _logg
+    def setUp(self):
+        if self.env is None:
+            self.env = ComponentManager() 
+        self.computer = DvbCronRecordingPlanComputer(self.env)
+        self.computer.logg = _logg
+        self.computer._localtime = time.localtime(1334887400)
+    # === END PREFIX ===
+    def test_01_options(self):
+        self.assertEqual("plan4", self.computer.algorithm, )
+        self.assertIn("3sat", self.computer.rankup_channels)
+        self.assertEqual(0.3, self.computer.rankup_value)
+        self.assertEqual(0.5, self.computer.onlydate_rankup)
+    def test_02_channels(self):
+        channellist = [Channel("3sat",1),Channel("arte",0), Channel("arte",1)]
+        self.computer.set_adapters_from_channels_list(channellist)
+        self.assertIn(u"1", self.computer.adapterlist())
+        self.assertEqual([u"1"], self.computer.adapters("3sat"))
+        self.assertEqual([u"0", u"1"], self.computer.adapters("arte"))
+    def test_03_entries(self):
+        a1 = Entry("arte","A1","22:30","23:30","0", "6", "", "ok",1)
+        req = Request(Locale("de"))
+        res = self.computer.plan4(req, [a1])
+        self.logg.info("RESULT:%s", res)
+        E = u"""
+{[{  [22:30-23:30]+0 arte@0 (* 1,2,3,4,5,6,7,8,9,10,11,12 6) 'A1' }]}"""
+        self.assertEqual(E, unicode(res))
+    def test_04_entries(self):
+        a1 = Entry("arte","A1","22:30","23:30","0", "", "22.04.", "ok",1)
+        req = Request(Locale("de"))
+        res = self.computer.plan4(req, [a1])
+        self.logg.info("RESULT:%s", res)
+        E = u"""
+{[{  [22:30-23:30]+0 arte@0 (22 4 6) 'A1' }]}"""
+        self.assertEqual(E, unicode(res))
+    def test_10_2entries_samegroupandcontinue(self):
+        a1 = Entry("arte","A1","22:30","23:30","0", "", "22.04.", "ok",1)
+        a2 = Entry("arte","A2","23:30","00:30","0", "", "22.04.", "ok",1)
+        req = Request(Locale("de"))
+        res = self.computer.plan4(req, [a1, a2])
+        self.logg.info("RESULT:%s", res)
+        E = u"""
+{[{  [22:30-23:30]+0 arte@0 (22 4 6) 'A1' },
+  {  [23:30-00:30]+0 arte@0 (22 4 6) 'A2' }]}"""
+        self.assertEqual(E, unicode(res))
+    def test_11_2entries_differentgroups(self):
+        a1 = Entry("arte","A1","22:30","23:30","0", "", "22.04.", "ok",1)
+        a2 = Entry("arte","A2","23:33","00:33","0", "", "22.04.", "ok",1)
+        req = Request(Locale("de"))
+        res = self.computer.plan4(req, [a1, a2])
+        self.logg.info("RESULT:%s", res)
+        E = u"""
+{[{  [22:30-23:30]+0 arte@0 (22 4 6) 'A1' }],
+ [{  [23:33-00:33]+0 arte@0 (22 4 6) 'A2' }]}"""
+        self.assertEqual(E, unicode(res))
+    def test_20_2entries_differentchannels0(self):
+        channellist = [Channel("3sat",0),Channel("arte",0), Channel("arte",1)]
+        self.computer.set_adapters_from_channels_list(channellist)
+        self.assertIn(u"1", self.computer.adapterlist())
+        a1 = Entry("arte","A1","22:30","23:30","0", "", "22.04.", "ok",1)
+        a2 = Entry("3sat","A2","22:33","23:33","0", "", "22.04.", "ok",1)
+        req = Request(Locale("de"))
+        res = self.computer.plan4(req, [a1, a2])
+        self.logg.info("RESULT:%s", res)
+        E = u"""
+{[{  [22:30-23:30]+0 arte@1 (22 4 6) 'A1' }],
+ [{  [22:33-23:33]+0 3sat@0 (22 4 6) 'A2' }]}"""
+        self.assertEqual(E, unicode(res))
+    def test_21_2entries_differentchannels1(self):
+        channellist = [Channel("3sat",1),Channel("arte",0), Channel("arte",1)]
+        self.computer.set_adapters_from_channels_list(channellist)
+        self.assertIn(u"1", self.computer.adapterlist())
+        a1 = Entry("arte","A1","22:30","23:30","0", "", "22.04.", "ok",1)
+        a2 = Entry("3sat","A2","22:33","23:33","0", "", "22.04.", "ok",1)
+        req = Request(Locale("de"))
+        res = self.computer.plan4(req, [a1, a2])
+        self.logg.info("RESULT:%s", res)
+        E = u"""
+{[{  [22:30-23:30]+0 arte@0 (22 4 6) 'A1' }],
+ [{  [22:33-23:33]+0 3sat@1 (22 4 6) 'A2' }]}"""
+        self.assertEqual(E, unicode(res))
+    def test_23_3entries_differentchannels0(self):
+        channellist = [Channel("3sat",0),Channel("arte",0), Channel("arte",1)]
+        self.computer.set_adapters_from_channels_list(channellist)
+        self.assertIn(u"1", self.computer.adapterlist())
+        a1 = Entry("arte","A1","22:30","23:30","0", "", "22.04.", "ok",1)
+        a2 = Entry("3sat","A2","22:33","23:33","0", "", "22.04.", "ok",1)
+        a3 = Entry("3sat","A3","23:33","00:33","0", "", "22.04.", "ok",1)
+        req = Request(Locale("de"))
+        res = self.computer.plan4(req, [a1, a2, a3])
+        self.logg.info("RESULT:%s", res)
+        E = u"""
+{[{  [22:30-23:30]+0 arte@1 (22 4 6) 'A1' }],
+ [{  [22:33-23:33]+0 3sat@0 (22 4 6) 'A2' },
+  {  [23:33-00:33]+0 3sat@0 (22 4 6) 'A3' }]}"""
+        self.assertEqual(E, unicode(res))
+    def test_24_3entries_differentchannels1(self):
+        channellist = [Channel("3sat",1),Channel("arte",0), Channel("arte",1)]
+        self.computer.set_adapters_from_channels_list(channellist)
+        self.assertIn(u"1", self.computer.adapterlist())
+        a1 = Entry("arte","A1","22:30","23:30","0", "", "22.04.", "ok",1)
+        a2 = Entry("3sat","A2","22:33","23:33","0", "", "22.04.", "ok",1)
+        a3 = Entry("3sat","A3","23:33","00:33","0", "", "22.04.", "ok",1)
+        req = Request(Locale("de"))
+        res = self.computer.plan4(req, [a1, a2, a3])
+        self.logg.info("RESULT:%s", res)
+        E = u"""
+{[{  [22:30-23:30]+0 arte@0 (22 4 6) 'A1' }],
+ [{  [22:33-23:33]+0 3sat@1 (22 4 6) 'A2' },
+  {  [23:33-00:33]+0 3sat@1 (22 4 6) 'A3' }]}"""
+        self.assertEqual(E, unicode(res))
+    def test_25_3entries_differentchannels_inside1(self):
+        channellist = [Channel("3sat",1),Channel("arte",0), Channel("arte",1)]
+        self.computer.set_adapters_from_channels_list(channellist)
+        self.assertIn(u"1", self.computer.adapterlist())
+        a1 = Entry("3sat","A1","22:33","23:33","0", "", "22.04.", "ok",1)
+        a2 = Entry("arte","A2","23:30","00:30","0", "", "22.04.", "ok",1)
+        a3 = Entry("3sat","A3","23:33","00:33","0", "", "22.04.", "ok",1)
+        req = Request(Locale("de"))
+        res = self.computer.plan4(req, [a1, a2, a3])
+        self.logg.info("RESULT:%s", res)
+        E = u"""
+{[{  [22:33-23:33]+0 3sat@1 (22 4 6) 'A1' },
+  {  [23:33-00:33]+0 3sat@1 (22 4 6) 'A3' }],
+ [{  [23:30-00:30]+0 arte@0 (22 4 6) 'A2' }]}"""
+        self.assertEqual(E, unicode(res))
+    def test_26_3entries_differentchannels_inside2(self):
+        channellist = [Channel("3sat",1),Channel("arte",0), Channel("arte",1)]
+        self.computer.set_adapters_from_channels_list(channellist)
+        self.assertIn(u"1", self.computer.adapterlist())
+        a1 = Entry("arte","A1","22:33","23:33","0", "", "22.04.", "ok",1)
+        a2 = Entry("3sat","A2","23:30","00:30","0", "", "22.04.", "ok",1)
+        a3 = Entry("arte","A3","23:33","00:33","0", "", "22.04.", "ok",1)
+        req = Request(Locale("de"))
+        res = self.computer.plan4(req, [a1, a2, a3])
+        self.logg.info("RESULT:%s", res)
+        E = u"""
+{[{  [22:33-23:33]+0 arte@0 (22 4 6) 'A1' },
+  {  [23:33-00:33]+0 arte@0 (22 4 6) 'A3' }],
+ [{  [23:30-00:30]+0 3sat@1 (22 4 6) 'A2' }]}"""
+        self.assertEqual(E, unicode(res))
+    def test_27_3entries_differentchannels_atend(self):
+        channellist = [Channel("3sat",1),Channel("arte",0), Channel("arte",1)]
+        self.computer.set_adapters_from_channels_list(channellist)
+        self.assertIn(u"1", self.computer.adapterlist())
+        a1 = Entry("arte","A1","22:33","23:33","0", "", "22.04.", "ok",1)
+        a2 = Entry("arte","A2","23:33","00:33","0", "", "22.04.", "ok",1)
+        a3 = Entry("3sat","A3","23:50","00:50","0", "", "22.04.", "ok",1)
+        req = Request(Locale("de"))
+        res = self.computer.plan4(req, [a1, a2, a3])
+        self.logg.info("RESULT:%s", res)
+        E = u"""
+{[{  [22:33-23:33]+0 arte@0 (22 4 6) 'A1' },
+  {  [23:33-00:33]+0 arte@0 (22 4 6) 'A2' }],
+ [{  [23:50-00:50]+0 3sat@1 (22 4 6) 'A3' }]}"""
+        self.assertEqual(E, unicode(res))
+    def test_28_3entries_differentchannels_nextday(self):
+        channellist = [Channel("3sat",1),Channel("arte",0), Channel("arte",1)]
+        self.computer.set_adapters_from_channels_list(channellist)
+        self.assertIn(u"1", self.computer.adapterlist())
+        a1 = Entry("arte","A1","22:33","23:33","0", "", "22.04.", "ok",1)
+        a2 = Entry("arte","A2","23:33","00:33","0", "", "22.04.", "ok",1)
+        a3 = Entry("3sat","A3","00:10","01:10","0", "", "23.04.", "ok",1)
+        req = Request(Locale("de"))
+        res = self.computer.plan4(req, [a1, a2, a3])
+        self.logg.info("RESULT:%s", res)
+        E = u"""
+{[{  [22:33-23:33]+0 arte@0 (22 4 6) 'A1' },
+  {  [23:33-00:33]+0 arte@0 (22 4 6) 'A2' }],
+ [{  [00:10-01:10]+0 3sat@1 (23 4 0) 'A3' }]}"""
+        self.assertEqual(E, unicode(res))
+    def test_40_4entries_samegroupandcontinue(self):
+        channellist = [Channel("pro7",0),Channel("arte",0)]
+        self.computer.set_adapters_from_channels_list(channellist)
+        self.assertNotIn(u"1", self.computer.adapterlist())
+        a1 = Entry("arte","A1","22:30","23:30","0", "", "22.04.", "ok",1)
+        a2 = Entry("arte","A2","23:30","00:30","3", "", "22.04.", "ok",1)
+        a3 = Entry("arte","A3","00:30","01:10","3", "", "23.04.", "ok",1)
+        a4 = Entry("arte","A4","01:10","01:50","5", "", "23.04.", "ok",1)
+        req = Request(Locale("de"))
+        res = self.computer.plan4(req, [a1, a2, a3, a4])
+        self.logg.info("RESULT:%s", res)
+        E = u"""
+{[{  [22:30-23:30]+0 arte@0 (22 4 6) 'A1' },
+  {  [23:30-00:30]+3 arte@0 (22 4 6) 'A2' },
+  {  [00:33-01:10]+3 arte@0 (23 4 0) 'A3' },
+  {  [01:13-01:50]+5 arte@0 (23 4 0) 'A4' }]}"""
+        self.assertEqual(E, unicode(res))
+    def test_41_4entries_overlap1(self):
+        channellist = [Channel("pro7",0),Channel("arte",0)]
+        self.computer.set_adapters_from_channels_list(channellist)
+        self.assertNotIn(u"1", self.computer.adapterlist())
+        a1 = Entry("pro7","A1","22:30","23:30","0", "", "22.04.", "ok",1)
+        a2 = Entry("arte","A2","23:20","00:30","3", "", "22.04.", "ok",1)
+        a3 = Entry("arte","A3","00:30","01:10","3", "", "23.04.", "ok",1)
+        a4 = Entry("arte","A4","01:10","01:50","5", "", "23.04.", "ok",1)
+        req = Request(Locale("de"))
+        res = self.computer.plan4(req, [a1, a2, a3, a4])
+        self.logg.info("RESULT:%s", res)
+        E = u"""
+{[{  [22:30-23:20]+0 pro7@0 (22 4 6) 'A1' },
+  {  [23:20-00:30]+3 arte@0 (22 4 6) 'A2' },
+  {  [00:33-01:10]+3 arte@0 (23 4 0) 'A3' },
+  {  [01:13-01:50]+5 arte@0 (23 4 0) 'A4' }]}"""
+        self.assertEqual(E, unicode(res))
+    def test_42_4entries_overlap2(self):
+        channellist = [Channel("pro7",0),Channel("arte",0)]
+        self.computer.set_adapters_from_channels_list(channellist)
+        self.assertNotIn(u"1", self.computer.adapterlist())
+        a1 = Entry("pro7","A1","22:30","00:40","0", "", "22.04.", "ok",1)
+        a2 = Entry("arte","A2","23:20","00:30","3", "", "22.04.", "ok",1)
+        a3 = Entry("arte","A3","00:30","01:10","3", "", "23.04.", "ok",1)
+        a4 = Entry("arte","A4","01:10","01:50","5", "", "23.04.", "ok",1)
+        req = Request(Locale("de"))
+        res = self.computer.plan4(req, [a1, a2, a3, a4])
+        self.logg.info("RESULT:%s", res)
+        E = u"""
+{[{  [22:30-23:20]+0 pro7@0 (22 4 6) 'A1' },
+  {  [23:20-00:30]+3 arte@0 (22 4 6) 'A2' },
+  {  [00:33-01:10]+3 arte@0 (23 4 0) 'A3' },
+  {  [01:13-01:50]+5 arte@0 (23 4 0) 'A4' }]}"""
+        self.assertEqual(E, unicode(res))
+    def test_43_4entries_delete_start1(self): 
+        channellist = [Channel("pro7",0),Channel("arte",0)]
+        self.computer.set_adapters_from_channels_list(channellist)
+        self.assertNotIn(u"1", self.computer.adapterlist())
+        a1 = Entry("pro7","A1","23:20","23:40","0", "", "22.04.", "ok",1)
+        a2 = Entry("arte","A2","23:20","00:30","3", "", "22.04.", "ok",1)
+        a3 = Entry("arte","A3","00:30","01:10","3", "", "23.04.", "ok",1)
+        a4 = Entry("arte","A4","01:10","01:50","5", "", "23.04.", "ok",1)
+        req = Request(Locale("de"))
+        res = self.computer.plan4(req, [a1, a2, a3, a4])
+        self.logg.info("RESULT:%s", res)
+        E = u"""
+{[{  [--DELETED--]   pro7@0 (22 4 6) 'A1' },
+  {  [23:20-00:30]+3 arte@0 (22 4 6) 'A2' },
+  {  [00:33-01:10]+3 arte@0 (23 4 0) 'A3' },
+  {  [01:13-01:50]+5 arte@0 (23 4 0) 'A4' }]}"""
+        self.assertEqual(E, unicode(res))
+    def test_44_4entries_delete_start2(self): 
+        channellist = [Channel("pro7",0),Channel("arte",0)]
+        self.computer.set_adapters_from_channels_list(channellist)
+        self.assertNotIn(u"1", self.computer.adapterlist())
+        a1 = Entry("pro7","A1","23:20","00:40","0", "", "22.04.", "ok",1)
+        a2 = Entry("arte","A2","23:20","00:30","3", "", "22.04.", "ok",1)
+        a3 = Entry("arte","A3","00:30","01:10","3", "", "23.04.", "ok",1)
+        a4 = Entry("arte","A4","01:10","01:50","5", "", "23.04.", "ok",1)
+        req = Request(Locale("de"))
+        res = self.computer.plan4(req, [a1, a2, a3, a4])
+        self.logg.info("RESULT:%s", res)
+        E = u"""
+{[{  [--DELETED--]   pro7@0 (22 4 6) 'A1' },
+  {  [23:20-00:30]+3 arte@0 (22 4 6) 'A2' },
+  {  [00:33-01:10]+3 arte@0 (23 4 0) 'A3' },
+  {  [01:13-01:50]+5 arte@0 (23 4 0) 'A4' }]}"""
+        self.assertEqual(E, unicode(res))
+    def test_45_4entries_delete_inside1(self):
+        channellist = [Channel("pro7",0),Channel("arte",0)]
+        self.computer.set_adapters_from_channels_list(channellist)
+        self.assertNotIn(u"1", self.computer.adapterlist())
+        a1 = Entry("arte","A1","23:20","00:30","3", "", "22.04.", "ok",1)
+        a2 = Entry("pro7","A2","23:40","00:20","0", "", "22.04.", "ok",1)
+        a3 = Entry("arte","A3","00:30","01:10","3", "", "23.04.", "ok",1)
+        a4 = Entry("arte","A4","01:10","01:50","5", "", "23.04.", "ok",1)
+        req = Request(Locale("de"))
+        res = self.computer.plan4(req, [a1, a2, a3, a4])
+        self.logg.info("RESULT:%s", res)
+        E = u"""
+{[{  [23:20-00:30]+3 arte@0 (22 4 6) 'A1' },
+  {  [--DELETED--]   pro7@0 (23 4 0) 'A2' },
+  {  [00:33-01:10]+3 arte@0 (23 4 0) 'A3' },
+  {  [01:13-01:50]+5 arte@0 (23 4 0) 'A4' }]}"""
+        self.assertEqual(E, unicode(res))
+    def test_46_4entries_delete2_inside1(self): 
+        channellist = [Channel("pro7",0),Channel("arte",0),Channel("3sat",0)]
+        self.computer.set_adapters_from_channels_list(channellist)
+        self.assertNotIn(u"1", self.computer.adapterlist())
+        a1 = Entry("arte","A1","23:20","00:30","3", "", "22.04.", "ok",1)
+        a2 = Entry("pro7","A2","23:40","00:20","0", "", "22.04.", "ok",1)
+        a3 = Entry("3sat","A3","00:10","01:10","3", "", "23.04.", "ok",1)
+        a4 = Entry("arte","A4","01:10","01:50","5", "", "23.04.", "ok",1)
+        req = Request(Locale("de"))
+        res = self.computer.plan4(req, [a1, a2, a3, a4])
+        self.logg.info("RESULT:%s", res)
+        E = u"""
+{[{  [23:20-00:30]+3 arte@0 (22 4 6) 'A1' },
+  {  [--DELETED--]   pro7@0 (23 4 0) 'A2' },
+  {  [00:33-01:10]+3 3sat@0 (23 4 0) 'A3' },
+  {  [01:13-01:50]+5 arte@0 (23 4 0) 'A4' }]}"""
+        self.assertEqual(E, unicode(res))
+    def test_47_4entries_delete3_inside1(self): 
+        _logg.error(" FIXME all wrong ")
+        channellist = [Channel("pro7",0),Channel("arte",0),Channel("3sat",0)]
+        self.computer.set_adapters_from_channels_list(channellist)
+        self.assertNotIn(u"1", self.computer.adapterlist())
+        a1 = Entry("arte","A1","23:20","00:30","3", "", "22.04.", "ok",1)
+        a2 = Entry("pro7","A2","23:40","00:20","0", "", "22.04.", "ok",1)
+        a3 = Entry("3sat","A3","23:40","01:10","3", "", "22.04.", "ok",1)
+        a4 = Entry("arte","A4","01:10","01:50","5", "", "23.04.", "ok",1)
+        req = Request(Locale("de"))
+        res = self.computer.plan4(req, [a1, a2, a3, a4])
+        self.logg.info("RESULT:%s", res)
+        E = u"""
+{[{  [23:20-00:30]+3 arte@0 (22 4 6) 'A1' },
+  {  [--DELETED--]   pro7@0 (23 4 0) 'A2' },
+  {  [00:33-01:10]+3 3sat@0 (23 4 0) 'A3' },
+  {  [01:13-01:50]+5 arte@0 (23 4 0) 'A4' }]}"""
+        self.assertEqual(E, unicode(res))
+    def test_48_4entries_delete_spanover(self): 
+        _logg.error(" FIXME all wrong ")
+        channellist = [Channel("pro7",0),Channel("arte",0),Channel("3sat",0)]
+        self.computer.set_adapters_from_channels_list(channellist)
+        self.assertNotIn(u"1", self.computer.adapterlist())
+        a1 = Entry("arte","A1","23:20","00:30","3", "", "22.04.", "ok",1)
+        a2 = Entry("pro7","A2","23:40","01:30","0", "", "22.04.", "ok",1)
+        a3 = Entry("3sat","A3","23:40","01:10","3", "", "22.04.", "ok",1)
+        a4 = Entry("arte","A4","01:10","01:50","5", "", "23.04.", "ok",1)
+        req = Request(Locale("de"))
+        res = self.computer.plan4(req, [a1, a2, a3, a4])
+        self.logg.info("RESULT:%s", res)
+        E = u"""
+{[{  [23:20-00:30]+3 arte@0 (22 4 6) 'A1' },
+  {  [00:33-01:10]+3 3sat@0 (23 4 0) 'A3' },
+  {  [01:13-01:50]+5 arte@0 (23 4 0) 'A4' },
+  {  [--DELETED--]   pro7@0 (23 4 0) 'A2' }]}"""
+        self.assertEqual(E, unicode(res))
+    def test_49_4entries_delete_spantoend(self): 
+        _logg.error(" FIXME all wrong ")
+        channellist = [Channel("pro7",0),Channel("arte",0),Channel("3sat",0)]
+        self.computer.set_adapters_from_channels_list(channellist)
+        self.assertNotIn(u"1", self.computer.adapterlist())
+        a1 = Entry("arte","A1","23:20","00:30","3", "", "22.04.", "ok",1)
+        a2 = Entry("pro7","A2","23:40","01:50","0", "", "22.04.", "ok",1)
+        a3 = Entry("3sat","A3","23:40","01:10","3", "", "22.04.", "ok",1)
+        a4 = Entry("arte","A4","01:10","01:50","5", "", "23.04.", "ok",1)
+        req = Request(Locale("de"))
+        res = self.computer.plan4(req, [a1, a2, a3, a4])
+        self.logg.info("RESULT:%s", res)
+        E = u"""
+{[{  [23:20-00:30]+3 arte@0 (22 4 6) 'A1' },
+  {  [00:33-01:10]+3 3sat@0 (23 4 0) 'A3' },
+  {  [01:13-01:50]+5 arte@0 (23 4 0) 'A4' },
+  {  [--DELETED--]   pro7@0 (23 4 0) 'A2' }]}"""
+        self.assertEqual(E, unicode(res))
+    def test_49_4entries_nondelete_move_behind(self): 
+        _logg.error(" FIXME all wrong ")
+        channellist = [Channel("pro7",0),Channel("arte",0),Channel("3sat",0)]
+        self.computer.set_adapters_from_channels_list(channellist)
+        self.assertNotIn(u"1", self.computer.adapterlist())
+        a1 = Entry("arte","A1","23:20","00:30","3", "", "22.04.", "ok",1)
+        a2 = Entry("pro7","A2","23:40","02:20","0", "", "22.04.", "ok",1)
+        a3 = Entry("3sat","A3","23:40","01:10","3", "", "22.04.", "ok",1)
+        a4 = Entry("arte","A4","01:10","01:50","5", "", "23.04.", "ok",1)
+        req = Request(Locale("de"))
+        res = self.computer.plan4(req, [a1, a2, a3, a4])
+        self.logg.info("RESULT:%s", res)
+        E = u"""
+{[{  [23:20-00:30]+3 arte@0 (22 4 6) 'A1' },
+  {  [00:33-01:10]+3 3sat@0 (23 4 0) 'A3' },
+  {  [01:13-01:50]+5 arte@0 (23 4 0) 'A4' },
+  {  [01:55-02:20]+0 pro7@0 (23 4 0) 'A2' }]}"""
+        self.assertEqual(E, unicode(res))
+    def test_50_4entries_nondelete_move_behind2(self): 
+        _logg.error(" FIXME all wrong ")
+        channellist = [Channel("pro7",0),Channel("arte",0),Channel("3sat",0)]
+        self.computer.set_adapters_from_channels_list(channellist)
+        self.assertNotIn(u"1", self.computer.adapterlist())
+        a1 = Entry("arte","A1","23:20","00:30","3", "", "22.04.", "ok",1)
+        a2 = Entry("pro7","A2","23:20","02:20","0", "", "22.04.", "ok",1)
+        a3 = Entry("3sat","A3","23:40","01:10","3", "", "22.04.", "ok",1)
+        a4 = Entry("arte","A4","01:10","01:50","5", "", "23.04.", "ok",1)
+        req = Request(Locale("de"))
+        res = self.computer.plan4(req, [a1, a2, a3, a4])
+        self.logg.info("RESULT:%s", res)
+        E = u"""
+{[{  [23:20-00:30]+3 arte@0 (22 4 6) 'A1' },
+  {  [00:33-01:10]+3 3sat@0 (23 4 0) 'A3' },
+  {  [01:13-01:50]+5 arte@0 (23 4 0) 'A4' },
+  {  [01:55-02:20]+0 pro7@0 (23 4 0) 'A2' }]}"""
+        self.assertEqual(E, unicode(res))
+        
+# === START POSTFIX ===
+def _generate(f):
+    x = """        #
+        channellist = [Channel("pro7",0),Channel("arte",0),Channel("arte",1),Channel("3sat",0)]
+        self.computer.set_adapters_from_channels_list(channellist)
+        self.assertIn(u"1", self.computer.adapterlist())
+    """
+    y = """        #
+        req = Request(Locale("de"))
+        res = self.computer.plan4(req, [a1, a2, a3])
+        self.logg.info("RESULT:%s", res)
+    """
+    
+    times = [ "23:30",  "23:40",  "23:50",  "00:00",  "00:10",  "00:20"]
+    dates = [ "22.04.", "22.04.", "22.04.", "23.04.", "23.04.", "23.04."]
+    channels = ["arte", "pro7", "3sat"]
+    for a1 in xrange(len(times)-2):
+        for a2 in xrange(a1+1, len(times)-1):
+            for a3 in xrange(a2+1, len(times)):
+                for e1 in xrange(a1+1, len(times)-2):
+                    for e2 in xrange(a2+1, len(times)-1):
+                        for e3 in xrange(a3+1, len(times)):
+                            for c1 in xrange(len(channels)):
+                                for c2 in xrange(len(channels)):
+                                    for c3 in xrange(len(channels)):
+                                        print >> f, "    def test_%s%s%s%s%s%s%s%s%s(self):" % (a1,a2,a3,e1,e2,e3,c1,c2,c3)
+                                        print >> f, x.rstrip()
+                                        print >> f, '        a1 = Entry("%s","A1","%s","%s","3", "", "%s", "ok",1)' % (channels[c1], times[a1], times[e1], dates[a1])
+                                        print >> f, '        a2 = Entry("%s","A2","%s","%s","3", "", "%s", "ok",1)' % (channels[c2], times[a2], times[e2], dates[a2])
+                                        print >> f, '        a3 = Entry("%s","A3","%s","%s","3", "", "%s", "ok",1)' % (channels[c3], times[a3], times[e3], dates[a3])
+                                        print >> f, y.rstrip()
+                
+
+def generate():
+    f = open(str(__file__).replace("test.py", "tests.py"), "w")
+    with f:
+        prefix = True
+        postfix = False
+        for line in open(__file__):
+            line = line.replace("DvbComputerTests", "DvbGeneratedTests")
+            if prefix:
+                f.write(line)
+                if ("END %s" % "PREFIX") in line:
+                    prefix = False
+            elif not postfix: 
+                if ("START %s" % "POSTFIX") in line:
+                    postfix = True
+                    _generate(f)
+            if postfix:
+                f.write(line)
+
+if __name__ == "__main__":
+    import sys
+    for arg in sys.argv:
+        if arg.startswith("-vv"):
+            print "log level DEBUG"
+            _logg.setLevel(logging.DEBUG)
+        if arg.startswith("..."):
+            generate()
+            sys.exit(0)
+    unittest.main()