#*****************************************************#
#          Solution to COMP-304 Assignment 1          #
#              Testsuite for SSGridview               #
# Date: Feb 5th, 2004                                 #
# Author: Marc Provost                                #
# Info: This module tests the SSGridview dynamic      #
#       requirements for success, failure and         #
#       sanity.                                       #
#*****************************************************#

import unittest
from Tkinter          import *
from SSGridView import *

global NUM_GRID_VIEW
global NUM_MOUSE_MOVE

#The number of gridview on which to perform the tests
NUM_GRID_VIEW=5
#The number of mouse move tests that are generated
NUM_MOUSE_MOVE=100


#We will create several SSGridview having random
#parameters.  The seed will be fixed, so that the
#experiments (tests) are reproducible.
import random
random.seed(4567)  #This is arbitrary

#list of SSGridview on which the tests will be
#applied

global views
views=[]

#creating NUM_GRID_VIEW gridviews
for i in xrange(NUM_GRID_VIEW):
  root=Tk()
  gridView = SpreadsheetGridView(master=root,
                                 title="A Window",
                                 data=None,
                                 height=random.randint(1,200),
                                 width=random.randint(1,400),
                                 cellHeight=random.randint(5,50),
                                 cellWidth=random.randint(5,60),
                                 padHor=random.randint(0,30),
                                 padVer=random.randint(0,30))
  views.append(gridView)

#function to determine the cell row/column of a given
#grid canvas position X,Y

def getCellCoords(grid, x, y):
  cellCol = int((x - grid.padHor)/grid.cellWidth)
  cellRow = int((y - grid.padVer)/grid.cellHeight)

  #if the column >= grid.width, set it to grid.width-1
  if cellCol>=grid.width:
    cellCol=grid.width-1
  if cellCol<0:
    cellCol=0

  #if the row >= grid.heigth, set it to grid.height-1
  if cellRow>=grid.height-1:
    cellRow=grid.height-1
  if cellRow<0:
    cellRow=0

  return (cellCol,cellRow)

class testMouse(unittest.TestCase):

  def testMouseMoveClick(self):
    """Testing mouse move / click for success
    """

    for grid in views:
      #creating a list of generated mouse moves
      #in the current grid drawarea
      moves=[] #list of tuples (newPosX, newPosY)

      #creating NUM_MOUSE_MOVE moves per grid (in the canvas)
      for i in xrange(NUM_MOUSE_MOVE):
        newPosX=random.randint(0,grid.width*grid.cellWidth+grid.padHor)
        newPosY=random.randint(0,grid.height*grid.cellHeight+grid.padVer)
        moves.append( (newPosX,newPosY) )

      #for each move, simulate a MouseMove and a MouseClick
      #event occuring in the gridview, and verify that the state of the
      #gridview after the event is correct.

      for move in moves:
        e=Event()
        e.x=move[0]
        e.y=move[1]

        coord=getCellCoords(grid,move[0],move[1])

        # **simulating a mouse move in the grid **
        grid.onDrawareaMouseMove(e)
        self.assertEqual(grid.overCell.col,coord[0],
        msg="overcell moved to an unexpected column: "+\
             str(grid.overCell.col))
        self.assertEqual(grid.overCell.row,coord[1],
        msg="overcell moved to an unexpected row: "+\
             str(grid.overCell.row))

        # **simulating a mouse click in the grid **
        grid.onDrawareaMouse1Click(e)
        self.assertEqual(grid.selectedCell.col,coord[0],
        msg="selectedcell moved to an unexpected column: "+\
             str(grid.selectedCell.col))
        self.assertEqual(grid.selectedCell.row,coord[1],
        msg="selectedcell moved to an unexpected row: "+\
             str(grid.selectedCell.row))

class testKeyboard(unittest.TestCase):

  LEFT=0
  RIGHT=1
  UP=2
  DOWN=3

  #Take a flag (LEFT,RIGHT,UP,DOWN) as input and
  #generate height*width corresponding event.
  #Test for success and sanity
  def generateArrowPressed(self, arrow):
    arrowType=""

    if arrow==self.LEFT:
      arrowType="left"
    elif arrow==self.RIGHT:
      arrowType="right"
    elif arrow==self.UP:
      arrowType="up"
    elif arrow==self.DOWN:
      arrowType="down"
    else:
      raise ValueError, "Unknown flag value for arrow pressed"

    for grid in views:
      e=Event()
      #starting at the bottom right cell of the grid,
      #generating arrow events until we reach the starting cell again
      #(success+sanity)

      grid.selectedCell.col = grid.width-1
      grid.selectedCell.row = grid.height-1
      for row in xrange(grid.height-1, -1,-1):
        for col in xrange(grid.width-1,-1,-1):
          initXPos = grid.selectedCell.col
          initYPos = grid.selectedCell.row
          newXPos=initXPos
          newYPos=initYPos

          #computing the expected new position for selectedCell
          if arrow==self.LEFT:
            grid.onDrawareaLeft(e)
            newXPos=initXPos-1
            if newXPos<0:
              newXPos=newXPos%grid.width
              newYPos=(initYPos-1)%grid.height
          elif arrow==self.RIGHT:
            grid.onDrawareaRight(e)
            newXPos=initXPos+1
            if newXPos>=grid.width:
              newXPos=newXPos%grid.width
              newYPos=(initYPos+1)%grid.height
          elif arrow==self.UP:
            grid.onDrawareaUp(e)
            newYPos=initYPos-1
            if newYPos<0:
              newYPos=newYPos%grid.height
              newXPos=(initXPos-1)%grid.width
          elif arrow==self.DOWN:
            grid.onDrawareaDown(e)
            newYPos=initYPos+1
            if newYPos>=grid.height:
              newYPos=newYPos%grid.height
              newXPos=(initXPos+1)%grid.width


          self.assertEqual(grid.selectedCell.col,
                          newXPos,
                          msg="Unexpected column position for selectedCell "+\
                              "after a "+arrowType+" arrow:"+str(newXPos)+"!="+\
                              str(grid.selectedCell.col))
          self.assertEqual(grid.selectedCell.row,
                          newYPos,
                          msg="Unexpected row position for selectedCell "+\
                              "after a "+arrowType+" arrow:"+str(newYPos)+"!="+\
                              str(grid.selectedCell.row))

      #testing for sanity
      self.assertEqual(grid.selectedCell.row,
                       grid.height-1,
                       msg="Sanity Error. Unexpected cell position "+\
                           "("+str(grid.selectedCell.row)+") "+\
                           "after generating width*height left events")
      self.assertEqual(grid.selectedCell.col,
                       grid.width-1,
                       msg="Sanity Error. Unexpected cell position "+\
                           "("+str(grid.selectedCell.col)+") "+\
                           "after generating width*height left events")

  def testLeftArrow(self):
     """Test left arrow event for each cell (Success+Sanity)"""
     self.generateArrowPressed(self.LEFT)

  def testRightArrow(self):
     """Test right arrow event for each cell (Success+Sanity)"""
     self.generateArrowPressed(self.RIGHT)

  def testUpArrow(self):
     """Test up arrow event for each cell (Success+Sanity)"""
     self.generateArrowPressed(self.UP)

  def testDownArrow(self):
     """Test down arrow event for each cell (Success+Sanity)"""
     self.generateArrowPressed(self.DOWN)

  def testLeftRightArrowPressed(self):
    """Left+right shall return to initial cell (Sanity)"""
    for grid in views:
      e=Event()

      for row in xrange(grid.height):
        for col in xrange(grid.width):
          grid.selectedCell.col = col
          grid.selectedCell.row = row
          grid.onDrawareaLeft(e)
          grid.onDrawareaRight(e)

          self.assertEqual(grid.selectedCell.col,
                           col,
                           msg=str(col)+"!="+str(grid.selectedCell.col))
          self.assertEqual(grid.selectedCell.row,
                           row,
                           msg=str(row)+"!="+str(grid.selectedCell.row))

  def testUpDownArrowPressed(self):
    """Up+down shall return to initial cell (Sanity)"""
    for grid in views:
      e=Event()

      for row in xrange(grid.height):
        for col in xrange(grid.width):
          grid.selectedCell.col = col
          grid.selectedCell.row = row
          grid.onDrawareaUp(e)
          grid.onDrawareaDown(e)

          self.assertEqual(grid.selectedCell.col,
                           col,
                           msg=str(col)+"!="+str(grid.selectedCell.col))
          self.assertEqual(grid.selectedCell.row,
                           row,
                           msg=str(row)+"!="+str(grid.selectedCell.row))

  def testUpDownLeftRightArrowPressed(self):
    """Up+down+left+right shall return to initial cell (Sanity)"""
    for grid in views:
      e=Event()

      for row in xrange(grid.height):
        for col in xrange(grid.width):
          grid.selectedCell.col = col
          grid.selectedCell.row = row
          grid.onDrawareaUp(e)
          grid.onDrawareaDown(e)
          grid.onDrawareaLeft(e)
          grid.onDrawareaRight(e)

          self.assertEqual(grid.selectedCell.col,
                           col,
                           msg=str(col)+"!="+str(grid.selectedCell.col))
          self.assertEqual(grid.selectedCell.row,
                           row,
                           msg=str(row)+"!="+str(grid.selectedCell.row))

  def testPeriodPressed(self):
    """Period key must be accepted (Success)"""

    for grid in views:
      e=Event()
      e.keysym = 'period'
      self.assertEqual(grid.onDrawareaKeyPressed(e),None)

  def testEqualPressed(self):
    """Equal key must be accepted (Success)"""

    for grid in views:
      e=Event()
      e.keysym = 'equal'
      self.assertEqual(grid.onDrawareaKeyPressed(e),None)

  def testBackspacePressed(self):
    """Backspace key must be accepted (Success)"""

    for grid in views:
      e=Event()
      e.keysym = 'backspace'
      self.assertEqual(grid.onDrawareaBackSpace(e),None)

  def testDigitPressed(self):
    """Digits 0 to 9 must be accepted (Success)"""

    digits = ['0','1','2','3','4','5','6','7','8','9']

    for grid in views:
      for s in digits:
        e=Event()
        e.keysym = s
        self.assertEqual(grid.onDrawareaKeyPressed(e),None)

  def testNonAlphaCharPressed(self):
    """Required non alpha characters must be accepted (Success)"""

    nonAlpha = ['asciitilde',
                'exclam',
                'at',
                'numbersign',
                'dollar',
                'percent',
                'asciicircum',
                'ampersand',
                'asterisk',
                'parenleft',
                'parenright',
                'minus',
                'underscore',
                'plus',
                'semicolon',
                'colon',
                'apostrophe',
                'quotedbl',
                'comma',
                'less',
                'greater',
                'question',
                'bracketleft',
                'bracketright']

    for grid in views:
      for s in nonAlpha:
        e=Event()
        e.keysym = s
        self.assertEqual(grid.onDrawareaKeyPressed(e),None)

  def testAlphabetChar(self):
    """A-Z, a-z must be accepted (Success)
    """
    letters=[]

    for i in xrange(ord('A'),ord('A')+26):
      letters.append(chr(i))
    for i in xrange(ord('a'),ord('a')+26):
      letters.append(chr(i))


    for grid in views:
      for l in letters:
        e=Event()
        e.keysym=l
        self.assertEqual(grid.onDrawareaKeyPressed(e),None)

  def testInputFailure(self):
    """Testing that unexpected input is not accepted (Failure)
    """
    illegal = ['bar',
               'quoteleft',
               'backslash',
               'slash',
               'Num_Lock',
               'Home',
               'Insert',
               'Delete',
               'Next',
               'Prior',
               'End',
               'quoteright',
               'Caps_Lock',
               'Tab',
               'F1',
               'F2',
               'F3',
               'F4',
               'F5',
               'F6',
               'F7',
               'F8',
               'F9',
               'F10']

    for grid in views:
      for l in illegal:
        e=Event()
        e.keysym=l
        self.assertRaises(InvalidKeyError,grid.onDrawareaKeyPressed,e)

if __name__ == "__main__":
    unittest.main()

