Category Weighting
------------------

Import helper to print the gradebook:

    >>> from schooltool.gradebook.browser.ftests import printGradebook

Log in as manager:

    >>> manager = Browser('manager', 'schooltool')

Administrator checks activity categories available for teachers:

    >>> manager.getLink('Manage').click()
    >>> manager.getLink('Activity Categories').click()
    >>> manager.printQuery('id("field.categories")/option/@value')
    assignment
    essay
    exam
    homework
    journal
    lab
    presentation
    project

Now, set up a school year (2005-2006) with two terms (Fall and
Spring):

    >>> from schooltool.app.browser.ftests import setup
    >>> setup.setUpBasicSchool()

Set up a course:

    >>> setup.addCourse('Physics I', '2005-2006')

Set up persons:

    >>> from schooltool.basicperson.browser.ftests.setup import addPerson
    >>> addPerson('Paul', 'Cardune', 'paul', 'pwd', browser=manager)
    >>> addPerson('Tom', 'Hoffman', 'tom', 'pwd', browser=manager)
    >>> addPerson('Claudia', 'Richter', 'claudia', 'pwd', browser=manager)
    >>> addPerson('Stephan', 'Richter', 'stephan', 'pwd', browser=manager)

Set up a section with instructor and students for the Fall:

    >>> setup.addSection('Physics I', '2005-2006', 'Fall',
    ...                  instructors=['Stephan'],
    ...                  members=['Tom', 'Claudia', 'Paul'])

Log in as teacher:

    >>> stephan = Browser('stephan', 'pwd')

Add some activities to the default worksheet:

    >>> stephan.getLink('Gradebook').click()

    >>> stephan.getLink('New Activity').click()
    >>> stephan.getControl('Title').value = 'HW 1'
    >>> stephan.getControl('Description').value = 'First homework'
    >>> stephan.getControl('Category').displayValue = ['Homework']
    >>> stephan.getControl('Maximum').value = '50'
    >>> stephan.getControl('Add').click()

    >>> stephan.getLink('New Activity').click()
    >>> stephan.getControl('Title').value = 'Quiz 1'
    >>> stephan.getControl('Description').value = 'First quiz'
    >>> stephan.getControl('Category').displayValue = ['Exam']
    >>> stephan.getControl('Maximum').value = '100'
    >>> stephan.getControl('Add').click()

    >>> stephan.getLink('New Activity').click()
    >>> stephan.getControl('Title').value = 'HW 2'
    >>> stephan.getControl('Description').value = 'Second homework'
    >>> stephan.getControl('Category').displayValue = ['Homework']
    >>> stephan.getControl('Maximum').value = '50'
    >>> stephan.getControl('Add').click()

    >>> stephan.getLink('New Activity').click()
    >>> stephan.getControl('Title').value = 'Quiz 2'
    >>> stephan.getControl('Description').value = 'Second quiz'
    >>> stephan.getControl('Category').displayValue = ['Exam']
    >>> stephan.getControl('Maximum').value = '100'
    >>> stephan.getControl('Add').click()

Add grades for the first three activities for Paul:

    >>> stephan.getControl(name='Activity_paul').value = '40'
    >>> stephan.getControl(name='Activity-2_paul').value = '90'
    >>> stephan.getControl(name='Activity-3_paul').value = '45'

Add grades for the first three activities for Tom:

    >>> stephan.getControl(name='Activity_tom').value = '45'
    >>> stephan.getControl(name='Activity-2_tom').value = '80'
    >>> stephan.getControl(name='Activity-3_tom').value = '50'

Add grades for the first three activities for Claudia:

    >>> stephan.getControl(name='Activity_claudia').value = '50'
    >>> stephan.getControl(name='Activity-2_claudia').value = '95'
    >>> stephan.getControl(name='Activity-3_claudia').value = '50'
    >>> stephan.getControl('Save').click()

By default the Average column is calculated normally:

    >>> printGradebook(stephan.contents)
    +----------+
    | *Sheet1* |
    +----------+
    +------------------+-------+-------+---------+---------+---------+---------+
    | Name             | Total | Ave.  | HW1     | Quiz1   | HW2     | Quiz2   |
    +------------------+-------+-------+---------+---------+---------+---------+
    | Cardune, Paul    | 175.0 | 87.5% | [40___] | [90___] | [45___] | [_____] |
    | Hoffman, Tom     | 175.0 | 87.5% | [45___] | [80___] | [50___] | [_____] |
    | Richter, Claudia | 195.0 | 97.5% | [50___] | [95___] | [50___] | [_____] |
    +------------------+-------+-------+---------+---------+---------+---------+

Let's create some category weights for the current worksheet. Note
that the categories are ordered alphabetically.

    >>> def printCategoryWeights(browser):
    ...     for label in browser.queryHTML('//label/text()'):
    ...         value = browser.getControl(label).value
    ...         print "%s: %s" % (label, repr(value))
    >>> stephan.getLink('Weight Categories').click()
    >>> stephan.printQuery('//h3/text()')
    Category weights for worksheet Sheet1
    >>> printCategoryWeights(stephan)
    Assignment: ''
    Essay: ''
    Exam: ''
    Homework: ''
    Journal: ''
    Lab: ''
    Presentation: ''
    Project: ''

First we'll show what happens when a value is invalid.  The only valid weights
will be numbers between 0 and 100.

    >>> stephan.getControl('Assignment').value = u'bad value'
    >>> stephan.getControl('Update').click()
    >>> stephan.printQuery('//div[@class="message"]/text()')
    bad value is not a valid weight.
    >>> stephan.getControl('Assignment').value = u'-1'
    >>> stephan.getControl('Update').click()
    >>> stephan.printQuery('//div[@class="message"]/text()')
    -1 is not a valid weight.
    >>> stephan.getControl('Assignment').value = u'101'
    >>> stephan.getControl('Update').click()
    >>> stephan.printQuery('//div[@class="message"]/text()')
    101 is not a valid weight.

We'll fill in valid values for Assignment, Homework and Exam, but they
will not add up to 100.  We should get an error message to that
effect.

    >>> stephan.getControl('Assignment').value = u'99'
    >>> stephan.getControl('Exam').value = u'99'
    >>> stephan.getControl('Homework').value = u'99'
    >>> stephan.getControl('Update').click()
    >>> stephan.printQuery('//div[@class="message"]/text()')
    Category weights must add up to 100.

If we get the weights to add up to 100, hitting 'Update' will succeed
and return us to the gradebook.  There we will note the effect of the
weighting in the Average column.

    >>> stephan.getControl('Assignment').value = u'20'
    >>> stephan.getControl('Exam').value = u'50'
    >>> stephan.getControl('Homework').value = u'30'
    >>> stephan.getControl('Update').click()
    >>> printGradebook(stephan.contents)
    +----------+
    | *Sheet1* |
    +----------+
    +------------------+-------+-------+---------+---------+---------+---------+
    | Name             | Total | Ave.  | HW1     | Quiz1   | HW2     | Quiz2   |
    +------------------+-------+-------+---------+---------+---------+---------+
    | Cardune, Paul    | 175.0 | 88.1% | [40___] | [90___] | [45___] | [_____] |
    | Hoffman, Tom     | 175.0 | 85.6% | [45___] | [80___] | [50___] | [_____] |
    | Richter, Claudia | 195.0 | 96.9% | [50___] | [95___] | [50___] | [_____] |
    +------------------+-------+-------+---------+---------+---------+---------+

Finally, we'll test hitting the 'Cancel' button.  It should return to the
gradebook without changing the weights.

    >>> stephan.getLink('Weight Categories').click()
    >>> printCategoryWeights(stephan)
    Assignment: '20'
    Essay: ''
    Exam: '50'
    Homework: '30'
    Journal: ''
    Lab: ''
    Presentation: ''
    Project: ''
    >>> stephan.getControl('Exam').value = u'85'
    >>> stephan.getControl('Cancel').click()
    >>> stephan.getLink('Weight Categories').click()
    >>> printCategoryWeights(stephan)
    Assignment: '20'
    Essay: ''
    Exam: '50'
    Homework: '30'
    Journal: ''
    Lab: ''
    Presentation: ''
    Project: ''

Let's add a new Assignment activity:

    >>> stephan.getLink('New Activity').click()
    >>> stephan.getControl('Title').value = 'Experiment'
    >>> stephan.getControl('Description').value = 'First assignment'
    >>> stephan.getControl('Category').displayValue = ['Assignment']
    >>> stephan.getControl('Maximum').value = '10'
    >>> stephan.getControl('Add').click()

Let's grade the new assignment for Paul and Tom:

    >>> stephan.getControl(name='Activity-5_paul').value = '9'
    >>> stephan.getControl(name='Activity-5_tom').value = '7'
    >>> stephan.getControl('Save').click()

Note how the Average changed for Paul and Tom, but not for Claudia:

    >>> printGradebook(stephan.contents)
    +----------+
    | *Sheet1* |
    +----------+
    +------------------+-------+-------+---------+---------+---------+---------+---------+
    | Name             | Total | Ave.  | HW1     | Quiz1   | HW2     | Quiz2   | Exper   |
    +------------------+-------+-------+---------+---------+---------+---------+---------+
    | Cardune, Paul    | 184.0 | 88.5% | [40___] | [90___] | [45___] | [_____] | [9____] |
    | Hoffman, Tom     | 182.0 | 82.5% | [45___] | [80___] | [50___] | [_____] | [7____] |
    | Richter, Claudia | 195.0 | 96.9% | [50___] | [95___] | [50___] | [_____] | [_____] |
    +------------------+-------+-------+---------+---------+---------+---------+---------+

Now, let's give Homeworks the 100% of weight:

    >>> stephan.getLink('Weight Categories').click()
    >>> stephan.getControl('Assignment').value = ''
    >>> stephan.getControl('Exam').value = ''
    >>> stephan.getControl('Homework').value = '100'
    >>> stephan.getControl('Update').click()

Let's go back to check that the values of the weights were stored
correctly:

    >>> stephan.getLink('Weight Categories').click()
    >>> printCategoryWeights(stephan)
    Assignment: ''
    Essay: ''
    Exam: ''
    Homework: '100'
    Journal: ''
    Lab: ''
    Presentation: ''
    Project: ''

The Averages have changed:

    >>> stephan.getControl('Cancel').click()
    >>> printGradebook(stephan.contents)
    +----------+
    | *Sheet1* |
    +----------+
    +------------------+-------+--------+---------+---------+---------+---------+---------+
    | Name             | Total | Ave.   | HW1     | Quiz1   | HW2     | Quiz2   | Exper   |
    +------------------+-------+--------+---------+---------+---------+---------+---------+
    | Cardune, Paul    | 184.0 | 85.0%  | [40___] | [90___] | [45___] | [_____] | [9____] |
    | Hoffman, Tom     | 182.0 | 95.0%  | [45___] | [80___] | [50___] | [_____] | [7____] |
    | Richter, Claudia | 195.0 | 100.0% | [50___] | [95___] | [50___] | [_____] | [_____] |
    +------------------+-------+--------+---------+---------+---------+---------+---------+

Let's test that explicit zeros are saved:

    >>> stephan.getLink('Weight Categories').click()
    >>> stephan.getControl('Assignment').value = '0.0'
    >>> stephan.getControl('Essay').value = '0'
    >>> stephan.getControl('Exam').value = '   '
    >>> stephan.getControl('Lab').value = '0'
    >>> stephan.getControl('Project').value = '0'
    >>> stephan.getControl('Update').click()

    >>> stephan.getLink('Weight Categories').click()
    >>> printCategoryWeights(stephan)
    Assignment: '0'
    Essay: '0'
    Exam: ''
    Homework: '100'
    Journal: ''
    Lab: '0'
    Presentation: ''
    Project: '0'

Since all these weights are zero, they shouldn't affect the averages:

    >>> stephan.getControl('Cancel').click()
    >>> printGradebook(stephan.contents)
    +----------+
    | *Sheet1* |
    +----------+
    +------------------+-------+--------+---------+---------+---------+---------+---------+
    | Name             | Total | Ave.   | HW1     | Quiz1   | HW2     | Quiz2   | Exper   |
    +------------------+-------+--------+---------+---------+---------+---------+---------+
    | Cardune, Paul    | 184.0 | 85.0%  | [40___] | [90___] | [45___] | [_____] | [9____] |
    | Hoffman, Tom     | 182.0 | 95.0%  | [45___] | [80___] | [50___] | [_____] | [7____] |
    | Richter, Claudia | 195.0 | 100.0% | [50___] | [95___] | [50___] | [_____] | [_____] |
    +------------------+-------+--------+---------+---------+---------+---------+---------+

Divide by zero bug
------------------

Until we fixed the bug, there was a case that crashed the gradebook where there
was a score for a non-wieghted category but no score for a weighted one.  To
prove that the bug has been fixed, we will remove all the scores for Claudia
and add one for the 'Experiment' activity whose category, 'Assignment', has a
weight of zero.

    >>> stephan.getControl(name='Activity_claudia').value = '0'
    >>> stephan.getControl(name='Activity-2_claudia').value = '0'
    >>> stephan.getControl(name='Activity-3_claudia').value = '0'
    >>> stephan.getControl(name='Activity-3_claudia').value = '0'
    >>> stephan.getControl(name='Activity-5_claudia').value = '50'
    >>> stephan.getControl('Save').click()

It didn't crash.  We see that Claudia has an average of zero even though she
has a score for 'Experiment' because it has a weight of zero.

    >>> printGradebook(stephan.contents)
    +----------+
    | *Sheet1* |
    +----------+
    +------------------+-------+-------+---------+---------+---------+---------+---------+
    | Name             | Total | Ave.  | HW1     | Quiz1   | HW2     | Quiz2   | Exper   |
    +------------------+-------+-------+---------+---------+---------+---------+---------+
    | Cardune, Paul    | 184.0 | 85.0% | [40___] | [90___] | [45___] | [_____] | [9____] |
    | Hoffman, Tom     | 182.0 | 95.0% | [45___] | [80___] | [50___] | [_____] | [7____] |
    | Richter, Claudia | 50.0  | 0.0%  | [0____] | [0____] | [0____] | [_____] | [50___] |
    +------------------+-------+-------+---------+---------+---------+---------+---------+

