#Change the CODE and OUTPUT strings to test your program

CODE = r'''abb1'''

OUTPUT = r'''My source has 4 characters.
1 is "a"
2 are "b"
1 is "1"
Besides unquoted numbers, my output has 383 characters.
34 are "
"
79 are " "
63 are """
2 are "'"
2 are ","
4 are "."
2 are "1"
2 are "B"
2 are "I"
2 are "M"
39 are "a"
4 are "b"
6 are "c"
4 are "d"
38 are "e"
3 are "g"
5 are "h"
4 are "i"
4 are "m"
3 are "n"
8 are "o"
3 are "p"
2 are "q"
38 are "r"
12 are "s"
8 are "t"
7 are "u"
3 are "y"
It's good to be a program.'''

#######################################################

import re

amountPattern = r'(\d+) (is|are) "(.)"\n'

class IntrospectionException(Exception):
	pass

def getClaimedAmounts(string, errorOnIs):
	groups = re.findall(amountPattern, string, re.DOTALL)

	for amount, verb, char in groups:
		if verb == 'is':
			if errorOnIs:
				raise IntrospectionException('\'1 is "%s"\' is unnecessary' % char)
			elif amount != '1':
				raise IntrospectionException('At "%s", %s must use "are"' % (char, amount))
		elif verb == 'are' and amount == '1':
			raise IntrospectionException('At "%s", 1 must use "is"' % char)

	amounts = {}
	for amount, verb, char in groups:
		if char in amounts:
			raise IntrospectionException('Duplicate "%s" found' % char)
		amounts[char] = int(amount)
	return amounts

def getActualAmounts(string):
	amounts = {}
	for char in string:
		if char in amounts:
			amounts[char] += 1
		else:
			amounts[char] = 1
	return amounts

def compareAmounts(claimed, actual):
	for char in actual:
		if char not in claimed:
			raise IntrospectionException('The amounts list is missing "%s"' % char)
	for char in actual: #loop separately so missing character errors are all found first
		if claimed[char] != actual[char]:
			raise IntrospectionException('The amount of "%s" characters is %d, not %d' % (char, actual[char], claimed[char]))
	if claimed != actual:
		raise IntrospectionException('The amounts are somehow incorrect')

def isCorrect(code, output):
	p1 = r'^My source has (\d+) characters\.\n'
	p2 = r'Besides unquoted numbers, my output has (\d+) characters\.\n'
	p3 = r"It's good to be a program\.$"
	p4 = '%s(%s)*%s(%s)*%s' % (p1, amountPattern, p2, amountPattern, p3)

	for p in [p1, p2, p3, p4]:
		if re.search(p, output, re.DOTALL) == None:
			raise IntrospectionException('Did not match the regex "%s"' % p)

	claimedCodeSize = int(re.search(p1, output).groups()[0])
	actualCodeSize = len(code)
	if claimedCodeSize != actualCodeSize:
		raise IntrospectionException('The code length is %d, not %d' % (actualCodeSize, claimedCodeSize))

	filteredOutput = re.sub(r'([^"])\d+([^"])', r'\1\2', output)

	claimedOutputSize = int(re.search(p2, output).groups()[0])
	actualOutputSize = len(filteredOutput)
	if claimedOutputSize != actualOutputSize:
		raise IntrospectionException('The output length (excluding unquoted numbers) is %d, not %d' % (actualOutputSize, claimedOutputSize))

	splitIndex = re.search(p2, output).start()

	claimedCodeAmounts = getClaimedAmounts(output[:splitIndex], False)
	actualCodeAmounts = getActualAmounts(code)
	compareAmounts(claimedCodeAmounts, actualCodeAmounts)

	claimedOutputAmounts = getClaimedAmounts(output[splitIndex:], True)
	actualOutputAmounts = getActualAmounts(filteredOutput)
	compareAmounts(claimedOutputAmounts, actualOutputAmounts)

def checkCorrectness():
	try:
		isCorrect(CODE, OUTPUT)
		print 'Everything is correct!'
	except IntrospectionException as e:
		print 'Failed: %s.' % e

checkCorrectness()