#!/usr/bin/python
# Copyright 2013 Marshall Clow
# Distributed under the Boost Software License, Version 1.0.
# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
#
#  Usage: boostLog <run1.xml> <run2.xml>
#
# Summarizes the runs, and then shows the differences in the results

import sys

import xml.etree.ElementTree as ET

def test_result ( node ):
	return node[-1].attrib [ 'result' ] == 'succeed'

def summarize ( doc ):
	root = doc.getroot ()
	print "Source: %s (revision %s)" % ( root.attrib [ 'tag' ], root.attrib [ 'revision' ])
	print "Date:   ", root.attrib [ 'timestamp' ]
		
	testLog = root.findall ( "./test-log" )

	emptyToolsetCount = 0
	for t in testLog:
		if t.attrib [ "toolset" ] == "":
			emptyToolsetCount += 1
	if emptyToolsetCount > 0:
		print "%5d tests have empty toolset names" % emptyToolsetCount

	emptyLibraryCount = 0
	for t in testLog:
		if t.attrib [ "library" ] == "":
			emptyLibraryCount += 1
	if emptyLibraryCount > 0:
		print "%5d tests have empty library names" % emptyLibraryCount

	emptyTestNameCount = 0
	for t in testLog:
		if t.attrib [ "test-name" ] == "":
			emptyTestNameCount += 1
	if emptyTestNameCount > 0:
		print "%5d tests have empty test names" % emptyTestNameCount

	toolsetCounts = {}
	toolsetSuccess = {}
	for t in testLog:
		ts = t.attrib [ "toolset" ]
		if toolsetCounts.has_key ( ts ):
			toolsetCounts [ ts ] = toolsetCounts [ ts ] + 1
		else:
			toolsetCounts [ ts ] = 1
		if test_result ( t ):
			if toolsetSuccess.has_key ( ts ):
				toolsetSuccess [ ts ] = toolsetSuccess [ ts ] + 1
			else:
				toolsetSuccess [ ts ] = 1

	print "Test count by toolset (%d total tests)" % len(testLog)
	calcCount = 0
	for k, v in toolsetCounts.items():
		print "%6d\t(%d failed)\t%s" % ( v, v - toolsetSuccess[k], k )
		calcCount += v
	if calcCount != len(testLog):
		print "ERROR!! sum (%d) != # of tests (%d)" % ( calcCount, len(testLog))
	print
	

# def build_set ( tests ):
# 	st = set()
# 	for t in tests:
# 		if t.attrib [ "test-name" ] != "":
# 			s = "%s:%s:%s" % ( t.attrib [ 'toolset' ], t.attrib [ "library" ], t.attrib [ "test-name" ] )
# #	Pretend for the moment that this isn't happening
# # 			if s in st:
# # 				print "Warning: Duplicate triple [ toolset:library;test-name ] ( %s )" % s
# # 			else:
# 			st.add (s)
# 	return st

def build_dict ( tests ):
	d = {}
	for t in tests:
		if t.attrib [ "test-name" ] != "":
			s = "%s:%s:%s" % ( t.attrib [ "library" ], t.attrib [ "test-name" ], t.attrib [ 'toolset' ] )
#	Pretend for the moment that this isn't happening
#  			if s in d.keys ():
#  				print "Warning: Duplicate triple [ library:test-name:toolset ] ( %s )" % s
			d [ s ] = test_result ( t )
	return d
	
def differences ( old_tests, new_tests ):
	old_d = build_dict ( old_tests.getroot ().findall ( "./test-log" ))
	old_s = set(old_d.keys ())

	new_d = build_dict ( new_tests.getroot ().findall ( "./test-log" ))
	new_s = set(new_d.keys ())
	
	added   = new_s - old_s
	removed = old_s - new_s
	if len(removed) > 0:
		print "There were %d tests removed" % len(removed)
		print "Removed tests"
		for t in removed:
			print "  %s" % (t)
		print
	
	if len(added) > 0:
		print "There were %d tests added"   % len(added)
	#	Print the results for the new tests
		addedFailCount = 0
		for t in added:
			if not new_d [ t ]:
				addedFailCount += 1
		if addedFailCount == 0:
			print "  All added tests succeeded"
			print
		else:
			print "Added Test results"
			for t in added:
				print "  %s\t%s" % (t, ("Failed", "Succeeded") [ new_d [ t ]])
			print
	
	newFailCount = 0
	for t,r in new_d.items ():
		if not r and old_d.has_key(t) and old_d[t]:
			newFailCount += 1
	print "New failing tests (%d)" % newFailCount
	for t,r in new_d.items ():
		if not r and old_d.has_key(t) and old_d[t]:
			print "  %s" % t
	print
	
	newSuccessCount = 0
	for t,r in new_d.items ():
		if r and old_d.has_key(t) and not old_d[t]:
			newSuccessCount += 1
	print "New Passing tests (%d)" % newSuccessCount
# 	for t,r in new_d.items ():
# 		if r and old_d.has_key(t) and not old_d[t]:
# 			print "  %s" % t
	print
	return
	
			
def main ():
	old_tests = None
	new_tests = None
	if len ( sys.argv ) >= 2:
		old_tests = ET.parse ( sys.argv[1] )
	if len ( sys.argv ) == 3:
		new_tests = ET.parse ( sys.argv[2] )

	if old_tests != None:
		summarize ( old_tests )

	if new_tests != None:
		summarize ( new_tests )

	if old_tests != None and new_tests != None:
		differences ( old_tests, new_tests )
		
main ()

