#!/usr/bin/python

'''Unit tests for linked_string_mod'''

import sys

import linked_string_mod

ASCII_LOWERCASE = 'abcdefghijklmnopqrstuvwxyz'

def ten_chunk_str():
	'''Test converting a linked string of 10.0 chunks to a str'''
	value = ASCII_LOWERCASE[:20]

	linked_string = linked_string_mod.Linked_string(chunk_size = 2, initial_value = value)

	if str(linked_string) == value:
		return True
	else:
		print >> sys.stderr, "ten_chunk_str: str(linked_string) != %s" % value
		print >> sys.stderr, "%s != %s" % (str(linked_string), value)
		return False

def ten_chunk_reverse():
	'''Test reversing a linked string of 10.0 chunks'''
	value = ASCII_LOWERCASE[:20]

	linked_string = linked_string_mod.Linked_string(chunk_size = 2, initial_value = value)
	linked_string.reverse()

	value = value[::-1]

	if str(linked_string) == value:
		return True
	else:
		print >> sys.stderr, "ten_chunk_reverse: str(linked_string) != %s" % value
		print >> sys.stderr, "%s != %s" % (str(linked_string), value)
		return False

def three_chunk_str():
	'''Test converting a linked string of 1.66 chunks to a str'''
	value = ASCII_LOWERCASE[:5]

	linked_string = linked_string_mod.Linked_string(chunk_size = 2, initial_value = value)

	if str(linked_string) == value:
		return True
	else:
		print >> sys.stderr, "three_chunk_str: str(linked_string) != %s" % value
		print >> sys.stderr, "%s != %s" % (str(linked_string), value)
		return False

def three_chunk_reverse():
	'''Test reversing a linked string of 2.5 chunks'''
	value = ASCII_LOWERCASE[:5]

	linked_string = linked_string_mod.Linked_string(chunk_size = 2, initial_value = value)
	linked_string.reverse()

	value = value[::-1]

	if str(linked_string) == value:
		return True
	else:
		print >> sys.stderr, "three_chunk_reverse: str(linked_string) != %s" % value
		print >> sys.stderr, "%s != %s" % (str(linked_string), value)
		return False

def two_chunk_str():
	'''Test converting a linked string of 1.66 chunks to a str'''
	value = ASCII_LOWERCASE[:5]

	linked_string = linked_string_mod.Linked_string(chunk_size = 3, initial_value = value)

	if str(linked_string) == value:
		return True
	else:
		print >> sys.stderr, "two_chunk_str: str(linked_string) != %s" % value
		print >> sys.stderr, "%s != %s" % (str(linked_string), value)
		return False

def two_chunk_reverse():
	'''Test reversing a string with 1.66 chunks'''
	value = ASCII_LOWERCASE[:5]

	linked_string = linked_string_mod.Linked_string(chunk_size = 3, initial_value = value)
	linked_string.reverse()

	value = value[::-1]

	if str(linked_string) == value:
		return True
	else:
		print >> sys.stderr, "two_chunk_reverse: str(linked_string) != %s" % value
		print >> sys.stderr, "%s != %s" % (str(linked_string), value)
		return False

def one_chunk_reverse():
	'''Test reversing a string with 0.5 chunks'''
	value = ASCII_LOWERCASE[:5]

	linked_string = linked_string_mod.Linked_string(chunk_size = 10, initial_value = value)
	linked_string.reverse()

	value = value[::-1]

	if str(linked_string) == value:
		return True
	else:
		print >> sys.stderr, "one_chunk_reverse: str(linked_string) != %s" % value
		print >> sys.stderr, "%s != %s" % (str(linked_string), value)
		return False

def one_chunk_len():
	'''Test taking the length of a string with 0.5 chunks'''
	value = ASCII_LOWERCASE[:5]

	linked_string = linked_string_mod.Linked_string(chunk_size = 10, initial_value = value)

	if len(linked_string) == len(value):
		return True
	else:
		print >> sys.stderr, "len(linked_string) != %d" % len(value)
		print >> sys.stderr, "%s != %s" % (len(linked_string), len(value))
		return False

def two_chunk_len():
	'''Test taking the length of a string with 2.66 chunks'''
	value = ASCII_LOWERCASE[:5]

	linked_string = linked_string_mod.Linked_string(chunk_size = 3, initial_value = value)

	if len(linked_string) == len(value):
		return True
	else:
		print >> sys.stderr, "len(linked_string) != %d" % len(value)
		print >> sys.stderr, "%s != %s" % (len(linked_string), len(value))
		return False

def three_chunk_len():
	'''Test creating a string with 2.5 chunks'''
	value = ASCII_LOWERCASE[:5]

	linked_string = linked_string_mod.Linked_string(chunk_size = 2, initial_value = value)

	if len(linked_string) == len(value):
		return True
	else:
		print >> sys.stderr, "len(linked_string) != %d" % len(value)
		print >> sys.stderr, "%s != %s" % (len(linked_string), len(value))
		return False

def ten_chunk_len():
	'''Test creating a string with 20 chunks'''
	value = ASCII_LOWERCASE[:20]

	linked_string = linked_string_mod.Linked_string(chunk_size = 2, initial_value = value)

	if len(linked_string) == len(value):
		return True
	else:
		print >> sys.stderr, "len(linked_string) != %d" % len(value)
		print >> sys.stderr, "%s != %s" % (len(linked_string), len(value))
		return False

def one_chunk_str():
	'''Test creating a string with but one (partial) chunk'''
	value = ASCII_LOWERCASE[:5]

	linked_string = linked_string_mod.Linked_string(chunk_size = 10, initial_value = value)

	if str(linked_string) == value:
		return True
	else:
		print >> sys.stderr, "one_chunk_str: str(linked_string) != %s" % value
		print >> sys.stderr, "%s != %s" % (str(linked_string), value)
		return False

def iterate():
	'''Test iterating over the characters of a string'''
	expected_value = ASCII_LOWERCASE[:]
	
	linked_string = linked_string_mod.Linked_string(chunk_size = 5, initial_value = expected_value)

	result_list = []
	for character in linked_string:
		result_list.append(character)
	actual_value = ''.join(result_list)

	if actual_value == expected_value:
		return True
	else:
		print >> sys.stderr, "Iteration problems"
		return False

def appends_with_partial():
	'''Test appending to the end of a string, when the number of values appended is not evenly divisible by the chunk size'''
	expected_value = ASCII_LOWERCASE[:]
	
	linked_string = linked_string_mod.Linked_string(chunk_size = 5, initial_value = '')

	for character in expected_value:
		linked_string.append(character)

	actual_value = str(linked_string)

	if actual_value == expected_value:
		return True
	else:
		print >> sys.stderr, "append_with_partial: error"
		return False

def extended_delitem_evens():
	'''Test simple delitem'''
	initial_value = ASCII_LOWERCASE
	expected_value = 'bdfhjlnprtvxz'

	linked_string = linked_string_mod.Linked_string(chunk_size = 3, initial_value = initial_value)

	del linked_string[::2]

	actual_value = linked_string

	if actual_value == expected_value:
		return True
	else:
		print >> sys.stderr, "extended_delitem: error: %s != %s" % (expected_value, actual_value)
		return False

def simple_delitem():
	'''Test simple delitem'''
	initial_value = 'abcdefg'
	expected_value = 'abcefg'
	
	linked_string = linked_string_mod.Linked_string(chunk_size = 2, initial_value = initial_value)

	del linked_string[3]

	actual_value = linked_string

	if actual_value == expected_value:
		return True
	else:
		print >> sys.stderr, "simple_delitem: error"
		return False

def many_start_delitems():
	'''Test many simple delitems'''
	initial_value = 'abcdefg'
	expected_value = ''
	
	linked_string = linked_string_mod.Linked_string(chunk_size = 2, initial_value = initial_value)

	while linked_string:
		del linked_string[0]

	actual_value = linked_string

	if actual_value == expected_value:
		return True
	else:
		print >> sys.stderr, "many_delitems: error"
		return False
  	
def many_end_delitems():
	'''Test many simple delitems'''
	initial_value = '0123456789' * 10
	expected_value = ''
	
	linked_string = linked_string_mod.Linked_string(chunk_size = 9, initial_value = initial_value)

	while linked_string:
		del linked_string[-1]

	actual_value = linked_string

	if actual_value == expected_value:
		return True
	else:
		print >> sys.stderr, "many_delitems: error"
		return False
  	
def simple_setitem():
	'''Test simple indexing'''
	initial_value = 'abcdefg'
	expected_value = 'abcxefg'
	
	linked_string = linked_string_mod.Linked_string(chunk_size = 2, initial_value = initial_value)

	linked_string[3] = 'x'

	actual_value = linked_string

	if actual_value == expected_value:
		return True
	else:
		print >> sys.stderr, "simple_setitem: error"
		return False

def simple_indexing():
	'''Test simple indexing'''
	expected_value = ASCII_LOWERCASE[:]
	
	linked_string = linked_string_mod.Linked_string(chunk_size = 5, initial_value = expected_value)

	list_ = []
	for index in xrange(0, len(expected_value)):
		list_.append(linked_string[index])

	actual_value = ''.join(list_)

	if actual_value == expected_value:
		return True
	else:
		print >> sys.stderr, "simple_indexing: error"
		return False

def simple_negative_indexing():
	'''Test simple negative indexing'''
	initial_value = ASCII_LOWERCASE[:]

	linked_string = linked_string_mod.Linked_string(chunk_size = 5, initial_value = initial_value)

	expected_value = 'y'

	actual_value = linked_string[-2]

	if actual_value == expected_value:
		return True
	else:
		print >> sys.stderr, "simple_negative_indexing: error"
		return False

def extended_indexing():
	'''Test extended indexing'''
	expected_value = ASCII_LOWERCASE[5:20]
	
	linked_string = linked_string_mod.Linked_string(chunk_size = 5, initial_value = ASCII_LOWERCASE)

	actual_value = linked_string[5:20]

	if actual_value == expected_value:
		return True
	else:
		print >> sys.stderr, "extended_indexing: error"
		print 'expected: %s, actual: %s' % (expected_value, actual_value)
		return False

	
def appends_with_complete():
	'''Test appending to the end of a string, when the number of values appended is evenly divisible by the chunk size'''

	expected_value = ASCII_LOWERCASE[:25]

	linked_string = linked_string_mod.Linked_string(chunk_size = 5, initial_value = '')

	for character in expected_value:
		linked_string.append(character)

	actual_value = str(linked_string)

	if actual_value == expected_value:
		return True
	else:
		print >> sys.stderr, "append_with_partial: error"
		return False

def test_equal_ls():
	'''test if two linked strings are equal'''
	ls1 = linked_string_mod.Linked_string(chunk_size = 2, initial_value = ASCII_LOWERCASE)
	ls2 = linked_string_mod.Linked_string(chunk_size = 2, initial_value = ASCII_LOWERCASE)

	if ls1 == ls2:
		return True
	else:
		print >> 'test_equal_ls: not equal'
		return False
	
def test_equal_ls_and_str():
	'''Test if a linked string a str compare equal'''
	ls1 = linked_string_mod.Linked_string(chunk_size = 2, initial_value = ASCII_LOWERCASE)
	str1 = ASCII_LOWERCASE[:]

	if ls1 == str1:
		return True
	else:
		print >> 'test_equal_ls_and_str: not equal'
		return False
	
def test_lt_ls_same_length():
	'''Test if two linked strings have a < relationship when they're of the same length'''
	ls1 = 'ababab'
	ls2 = 'abcdef'

	if ls1 < ls2:
		return True
	else:
		print >> 'test_lt_ls_same_length: error'
		return False
	
def test_gt_ls_same_length():
	'''Test if two linked strings have a > relationship when they're of the same length'''
	ls1 = 'abcdef'
	ls2 = 'ababab'

	if ls1 > ls2:
		return True
	else:
		print >> 'test_gt_ls_same_length: error'
		return False
	
def test_lt_ls_different_length():
	'''Test if two linked strings have a < relationship when they're equal up to a common prefix'''
	ls1 = ASCII_LOWERCASE[:19]
	ls2 = ASCII_LOWERCASE[:20]

	if ls1 < ls2:
		return True
	else:
		print >> 'test_lt_ls_different_length: error'
		return False
	
def test_gt_ls_different_length():
	'''Test if two linked strings have a > relationship when they're equal up to a common prefix'''
	ls1 = ASCII_LOWERCASE[:20]
	ls2 = ASCII_LOWERCASE[:19]

	if ls1 > ls2:
		return True
	else:
		print >> 'test_gt_ls_same_length: error'
		return False
	
def test_extend():
	'''Test appending characters to the end of a linked string'''
	ls1 = linked_string_mod.Linked_string(ASCII_LOWERCASE[:10])
	ls2 = linked_string_mod.Linked_string(ASCII_LOWERCASE[10:20])

	ls1.extend(ls2)

	if ls1 == ASCII_LOWERCASE[:20]:
		return True
	else:
		print >> sys.stderr, 'test_extend: error'
		return False

def test_iadd():
	'''Test appending characters to the end of a linked string'''
	ls1 = linked_string_mod.Linked_string(ASCII_LOWERCASE[:10])
	ls2 = linked_string_mod.Linked_string(ASCII_LOWERCASE[10:20])

	ls1 += ls2

	if ls1 == ASCII_LOWERCASE[:20]:
		return True
	else:
		print >> sys.stderr, 'test_iadd: error'
		return False

def test_add():
	'''Test appending characters to the end of a linked string'''
	ls1 = linked_string_mod.Linked_string(ASCII_LOWERCASE[:10])
	ls2 = linked_string_mod.Linked_string(ASCII_LOWERCASE[10:20])

	ls3 = ls1 + ls2

	if ls3 == ASCII_LOWERCASE[:20]:
		return True
	else:
		print >> sys.stderr, 'test_add: error'
		return False

def slice_highest_first():
	'''Test our means of reversing slices'''

	all_good = True

	for slice_, length in [ \
		(slice(0, 100, 1), 100),
		(slice(7, 100, 11), 100),
		(slice(0, 100, 1), 50),
		(slice(7, 100, 11), 50),
		(slice(0, 100, 1), 150),
		(slice(7, 100, 11), 150),
		(slice(100, 0, -1), 100),
		(slice(100, 7, -11), 100),
		(slice(100, 0, -1), 50),
		(slice(100, 7, -11), 50),
		(slice(100, 0, -1), 150),
		(slice(100, 7, -11), 150),
		]:
		#print >> sys.stderr, "Blee", slice_, length
		expected_value = linked_string_mod.simplistic_highest_first(slice_, length)
		actual_value = list(linked_string_mod.finessed_highest_first(slice_, length))
		if actual_value != expected_value:
			print >> sys.stderr, "Bad reverse_slice: %s, %s\nactual  : %s !=\nexpected: %s\n" % (slice_, length, actual_value, expected_value)
			all_good = False

	return all_good

def main():
	'''Main function'''

	all_good = True

	all_good &= slice_highest_first()

	all_good &= one_chunk_str()
	all_good &= two_chunk_str()
	all_good &= three_chunk_str()
	all_good &= ten_chunk_str()

	all_good &= one_chunk_reverse()
	all_good &= two_chunk_reverse()
	all_good &= three_chunk_reverse()
	all_good &= ten_chunk_reverse()

	all_good &= one_chunk_len()
	all_good &= two_chunk_len()
	all_good &= three_chunk_len()
	all_good &= ten_chunk_reverse()

	all_good &= iterate()

	all_good &= appends_with_partial()
	all_good &= appends_with_complete()

	all_good &= simple_indexing()
	all_good &= simple_negative_indexing()
	all_good &= extended_indexing()

	all_good &= simple_setitem()

	all_good &= simple_delitem()
	all_good &= many_start_delitems()
	all_good &= many_end_delitems()

	all_good &= extended_delitem_evens()

	all_good &= test_equal_ls()
	all_good &= test_equal_ls_and_str()

	all_good &= test_lt_ls_same_length()
	all_good &= test_gt_ls_same_length()

	all_good &= test_lt_ls_different_length()
	all_good &= test_gt_ls_different_length()

	all_good &= test_extend()
	all_good &= test_iadd()
	all_good &= test_add()

	if all_good:
		print >> sys.stderr, "All tests passed"
		sys.exit(0)
	else:
		print >> sys.stderr, "One or more tests failed"
		sys.exit(1)

main()