Index: /main/waeup.sirp/trunk/src/waeup/sirp/students/tests/sample_student_data.csv
===================================================================
--- /main/waeup.sirp/trunk/src/waeup/sirp/students/tests/sample_student_data.csv	(revision 6840)
+++ /main/waeup.sirp/trunk/src/waeup/sirp/students/tests/sample_student_data.csv	(revision 6840)
@@ -0,0 +1,4 @@
+firstname,lastname,fullname,reg_number,date_of_birth,matric_number
+Aaren,Pieri,Aaren Pieri,1,1990-01-02,100000
+Aaren,Finau,Aaren Finau,2,1990-01-03,100001
+Aaren,Berson,Aaren Berson,3,1990-01-04,100002
Index: /main/waeup.sirp/trunk/src/waeup/sirp/students/tests/sample_studycourse_data.csv
===================================================================
--- /main/waeup.sirp/trunk/src/waeup/sirp/students/tests/sample_studycourse_data.csv	(revision 6840)
+++ /main/waeup.sirp/trunk/src/waeup/sirp/students/tests/sample_studycourse_data.csv	(revision 6840)
@@ -0,0 +1,4 @@
+reg_number,certificate,current_session,current_level
+1,CERT1,2008,100
+2,CERT1,2008,100
+3,CERT1,2008,100
Index: /main/waeup.sirp/trunk/src/waeup/sirp/students/tests/test_batching.py
===================================================================
--- /main/waeup.sirp/trunk/src/waeup/sirp/students/tests/test_batching.py	(revision 6840)
+++ /main/waeup.sirp/trunk/src/waeup/sirp/students/tests/test_batching.py	(revision 6840)
@@ -0,0 +1,217 @@
+##
+## test_batching.py
+## Login : <uli@pu.smp.net>
+## Started on  Tue Aug 24 02:04:44 2010 Uli Fouquet
+## $Id$
+## 
+## Copyright (C) 2011 Uli Fouquet & Henrik Bettermann
+## This program is free software; you can redistribute it and/or modify
+## it under the terms of the GNU General Public License as published by
+## the Free Software Foundation; either version 2 of the License, or
+## (at your option) any later version.
+## 
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+## 
+## You should have received a copy of the GNU General Public License
+## along with this program; if not, write to the Free Software
+## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+##
+"""Unit tests for students-related data importers.
+"""
+import os
+import shutil
+import tempfile
+import unittest
+from zope.component import createObject
+from zope.component.hooks import setSite, clearSite
+from zope.interface.verify import verifyClass, verifyObject
+
+from waeup.sirp.app import University
+from waeup.sirp.university.faculty import Faculty
+from waeup.sirp.university.department import Department
+from waeup.sirp.students.batching import (
+    StudentProcessor, StudentStudyCourseProcessor)
+from waeup.sirp.students.student import Student
+from waeup.sirp.students.studycourse import StudentStudyCourse
+from waeup.sirp.testing import FunctionalLayer, FunctionalTestCase
+from waeup.sirp.interfaces import IBatchProcessor
+
+STUDENT_SAMPLE_DATA = open(
+    os.path.join(os.path.dirname(__file__), 'sample_student_data.csv'),
+    'rb').read()
+
+STUDENT_HEADER_FIELDS = STUDENT_SAMPLE_DATA.split(
+    '\n')[0].split(',')
+
+STUDYCOURSE_SAMPLE_DATA = open(
+    os.path.join(os.path.dirname(__file__), 'sample_studycourse_data.csv'),
+    'rb').read()
+
+STUDYCOURSE_HEADER_FIELDS = STUDYCOURSE_SAMPLE_DATA.split(
+    '\n')[0].split(',')
+
+class StudentImporterTest(FunctionalTestCase):
+
+    layer = FunctionalLayer
+
+    def setUp(self):
+        super(StudentImporterTest, self).setUp()
+        # Setup a sample site for each test
+        app = University()
+        self.dc_root = tempfile.mkdtemp()
+        app['datacenter'].setStoragePath(self.dc_root)
+
+        # Prepopulate the ZODB...
+        self.getRootFolder()['app'] = app
+        # we add the site immediately after creation to the
+        # ZODB. Catalogs and other local utilities are not setup
+        # before that step.
+        self.app = self.getRootFolder()['app']
+        # Set site here. Some of the following setup code might need
+        # to access grok.getSite() and should get our new app then
+        setSite(app)
+
+        # Add student with subobjects
+        student = Student()
+        student.fullname = u'Anna Tester'
+        student.reg_number = u'123'
+        student.matric_number = u'234'
+        self.app['students'].addStudent(student)
+        self.student = self.app['students'][student.student_id]
+        self.importer = StudentProcessor()
+        self.workdir = tempfile.mkdtemp()
+        self.csv_file = os.path.join(self.workdir, 'sample_student_data.csv')
+        open(self.csv_file, 'wb').write(STUDENT_SAMPLE_DATA)
+
+    def tearDown(self):
+        super(StudentImporterTest, self).tearDown()
+        shutil.rmtree(self.workdir)
+        shutil.rmtree(self.dc_root)
+        clearSite()
+        return
+
+    def test_interface(self):
+        # Make sure we fulfill the interface contracts.
+        assert verifyObject(IBatchProcessor, self.importer) is True
+        assert verifyClass(
+            IBatchProcessor, StudentProcessor) is True
+
+    def test_parentsExist(self):
+        assert self.importer.parentsExist(None, dict()) is False
+        assert self.importer.parentsExist(None, self.app) is True
+
+    def test_entryExists(self):
+        assert self.importer.entryExists(
+            dict(student_id='ID_NONE'), self.app) is False
+        assert self.importer.entryExists(
+            dict(student_id=self.student.student_id), self.app) is True
+
+    def test_getParent(self):
+        parent = self.importer.getParent(None, self.app)
+        assert parent is self.app['students']
+
+    def test_getEntry(self):
+        assert self.importer.getEntry(
+            dict(student_id='ID_NONE'), self.app) is None
+        assert self.importer.getEntry(
+            dict(student_id=self.student.student_id), self.app) is self.student
+
+    def test_addEntry(self):
+        new_student = Student()
+        self.importer.addEntry(
+            new_student, dict(), self.app)
+        assert len(self.app['students'].keys()) == 2
+
+    def test_delEntry(self):
+        self.importer.delEntry(dict(student_id=self.student.student_id), self.app)
+        assert self.student.student_id not in self.app['students'].keys()
+
+    def test_import(self):
+        num, num_warns, fin_file, fail_file = self.importer.doImport(
+            self.csv_file, STUDENT_HEADER_FIELDS)
+        assert len(self.app['students'].keys()) == 4
+        shutil.rmtree(os.path.dirname(fin_file))
+
+class StudentStudyCourseImporterTest(FunctionalTestCase):
+
+    layer = FunctionalLayer
+
+    def setUp(self):
+        super(StudentStudyCourseImporterTest, self).setUp()
+        app = University()
+        self.dc_root = tempfile.mkdtemp()
+        app['datacenter'].setStoragePath(self.dc_root)
+
+        self.getRootFolder()['app'] = app
+        self.app = self.getRootFolder()['app']
+        setSite(app)
+
+        self.workdir = tempfile.mkdtemp()
+        self.importer = StudentStudyCourseProcessor()
+        self.csv_file = os.path.join(self.workdir, 'sample_studycourse_data.csv')
+        open(self.csv_file, 'wb').write(STUDYCOURSE_SAMPLE_DATA)
+
+        # Import students with subobjects
+        student_file = os.path.join(self.workdir, 'sample_student_data.csv')
+        open(student_file, 'wb').write(STUDENT_SAMPLE_DATA)
+        num, num_warns, fin_file, fail_file = StudentProcessor().doImport(
+            student_file, STUDENT_HEADER_FIELDS)
+        shutil.rmtree(os.path.dirname(fin_file))
+
+        # Populate university
+        self.certificate = createObject('waeup.Certificate')
+        self.certificate.code = 'CERT1'
+        self.certificate.application_category = 'basic'
+        self.certificate.start_level = 100
+        self.certificate.end_level = 500
+        self.app['faculties']['fac1'] = Faculty()
+        self.app['faculties']['fac1']['dep1'] = Department()
+        self.app['faculties']['fac1']['dep1'].certificates.addCertificate(
+            self.certificate)
+        return
+
+    def tearDown(self):
+        super(StudentStudyCourseImporterTest, self).tearDown()
+        shutil.rmtree(self.workdir)
+        shutil.rmtree(self.dc_root)
+        clearSite()
+        return
+
+    def test_interface(self):
+        # Make sure we fulfill the interface contracts.
+        assert verifyObject(IBatchProcessor, self.importer) is True
+        assert verifyClass(
+            IBatchProcessor, StudentStudyCourseProcessor) is True
+
+    def test_entryExists(self):
+        assert self.importer.entryExists(
+            dict(reg_number='REG_NONE'), self.app) is False
+        student = self.importer.entryExists(dict(reg_number='1'), self.app)
+        self.assertEqual(student.reg_number, u'1')
+
+    def test_getEntry(self):
+        studycourse = self.importer.getEntry(dict(reg_number='1'), self.app)
+        student = studycourse.__parent__
+        s_id = student.student_id
+        assert studycourse is self.app['students'][s_id]['studycourse']
+
+    def test_import(self):
+        num, num_warns, fin_file, fail_file = self.importer.doImport(
+            self.csv_file, STUDYCOURSE_HEADER_FIELDS,'update')
+        studycourse = self.importer.getEntry(dict(reg_number='1'), self.app)
+        self.assertEqual(studycourse.certificate.code, u'CERT1')
+        shutil.rmtree(os.path.dirname(fin_file))
+
+def test_suite():
+    suite = unittest.TestSuite()
+    for testcase in [
+        StudentImporterTest,StudentStudyCourseImporterTest,
+        ]:
+        suite.addTest(unittest.TestLoader().loadTestsFromTestCase(
+                testcase
+                )
+        )
+    return suite
