diff options
Diffstat (limited to 'tests')
| -rw-r--r-- | tests/CMakeLists.txt | 8 | ||||
| -rw-r--r-- | tests/CTestCustom.template | 7 | ||||
| -rwxr-xr-x | tests/test_pretty_print.py | 922 | 
3 files changed, 426 insertions, 511 deletions
| diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 519f1e1..d76f498 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -934,6 +934,14 @@ string(REPLACE __header__ "Generated by cmake from ${CMAKE_CURRENT_SOURCE_DIR}/C  string(REPLACE __cmake_system_name__ ${CMAKE_SYSTEM_NAME} TMP ${TMP})  string(REPLACE __openscad_binpath__ ${OPENSCAD_BINPATH} TMP ${TMP}) +set(OPENSCAD_UPLOAD_TESTS $ENV{OPENSCAD_UPLOAD_TESTS}) +if (OPENSCAD_UPLOAD_TESTS) +  set(UPLOADARG "--upload") +endif() +if (UPLOADARG) +  string(REPLACE __openscad_upload_tests__ ${UPLOADARG} TMP ${TMP}) +endif() +  if (MINGW_CROSS_ENV_DIR)    string(REPLACE __wine__ wine TMP ${TMP})  else() diff --git a/tests/CTestCustom.template b/tests/CTestCustom.template index 3f82d73..a01f2b5 100644 --- a/tests/CTestCustom.template +++ b/tests/CTestCustom.template @@ -63,7 +63,12 @@ endif()  message("running '__openscad_binpath__ --info' to generate sysinfo.txt")  execute_process(COMMAND __wine__ __openscad_binpath__ --info OUTPUT_FILE sysinfo.txt) -set(CTEST_CUSTOM_POST_TEST ${CTEST_CUSTOM_POST_TEST} "__cmake_current_binary_dir__/test_pretty_print") + +if("${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}.${CMAKE_PATCH_VERSION}" VERSION_LESS 2.8.12) +  set(CTEST_CUSTOM_POST_TEST ${CTEST_CUSTOM_POST_TEST} "__cmake_current_binary_dir__/test_pretty_print") +else() +  set(CTEST_CUSTOM_POST_TEST ${CTEST_CUSTOM_POST_TEST} "__python__ __cmake_current_source_dir__/test_pretty_print.py --builddir=__cmake_current_binary_dir__ __openscad_upload_tests__") +endif()  if ( ${debug_openscad_template} )    foreach(post_test ${CTEST_CUSTOM_POST_TEST} ) diff --git a/tests/test_pretty_print.py b/tests/test_pretty_print.py index a31b1a8..0f86cb6 100755 --- a/tests/test_pretty_print.py +++ b/tests/test_pretty_print.py @@ -25,544 +25,446 @@  # todo  # -# 1. Note: Wiki code is deprecated. All future development should move to  -# create html output (or even xml output). Wiki design was based on the  -# wrong assumption of easily accessible public wiki servers with  -# auto-upload scripts available. wiki code should be removed and code  -# simplified. -# -# to still use wiki, use args '--wiki' and/or '--wiki-upload'  -# -# 2. why is hash differing - -import string,sys,re,os,hashlib,subprocess,textwrap,time,platform +# 1. why is hash differing + +import string +import sys +import re +import os +import hashlib +import subprocess +import time +import platform +try: +    from urllib.request import urlopen +    from urllib.parse import urlencode +except: +    from urllib2 import urlopen +    from urllib import urlencode  def tryread(filename): -	data = None -	try: -		f = open(filename,'rb') -		data = f.read() -		f.close() -	except Exception, e: -		print 'couldn\'t open ',filename -		print type(e), e -	return data - -def trysave(filename,data): -	dir = os.path.dirname(filename) -	try: -		if not os.path.isdir(dir): -			if not dir == '': -				debug( 'creating' + dir) -				os.mkdir(dir) -		f=open(filename,'wb') -		f.write(data) -		f.close() -	except Exception, e: -		print 'problem writing to',filename -		print type(e), e -		return None -	return True - -def ezsearch(pattern,str): -	x = re.search(pattern,str,re.DOTALL|re.MULTILINE) -	if x and len(x.groups())>0: return x.group(1).strip() -	return '' -	 +    data = None +    try: +        f = open(filename,'rb') +        data = f.read() +        f.close() +    except Exception as e: +        print 'couldn\'t open ',filename +        print type(e), e +    return data + +def trysave(filename, data): +    dir = os.path.dirname(filename) +    try: +        if not os.path.isdir(dir): +            if not dir == '': +                debug( 'creating' + dir) +                os.mkdir(dir) +        f=open(filename,'wb') +        f.write(data) +        f.close() +    except Exception as e: +        print 'problem writing to',filename +        print type(e), e +        return None +    return True + +def ezsearch(pattern, str): +    x = re.search(pattern,str,re.DOTALL|re.MULTILINE) +    if x and len(x.groups())>0: return x.group(1).strip() +    return '' +      def read_gitinfo(): -	# won't work if run from outside of branch.  -	try: -		data = subprocess.Popen(['git','remote','-v'],stdout=subprocess.PIPE).stdout.read() -		origin = ezsearch('^origin *?(.*?)\(fetch.*?$',data) -		upstream = ezsearch('^upstream *?(.*?)\(fetch.*?$',data) -		data = subprocess.Popen(['git','branch'],stdout=subprocess.PIPE).stdout.read() -		branch = ezsearch('^\*(.*?)$',data) -		out  = 'Git branch: ' + branch + ' from origin ' + origin + '\n' -		out += 'Git upstream: ' + upstream + '\n' -	except: -		out = 'Problem running git' -	return out +    # won't work if run from outside of branch.  +    try: +        data = subprocess.Popen(['git', 'remote', '-v'], stdout=subprocess.PIPE).stdout.read() +        origin = ezsearch('^origin *?(.*?)\(fetch.*?$', data) +        upstream = ezsearch('^upstream *?(.*?)\(fetch.*?$', data) +        data = subprocess.Popen(['git', 'branch'], stdout=subprocess.PIPE).stdout.read() +        branch = ezsearch('^\*(.*?)$', data) +        out = 'Git branch: ' + branch + ' from origin ' + origin + '\n' +        out += 'Git upstream: ' + upstream + '\n' +    except: +        out = 'Problem running git' +    return out  def read_sysinfo(filename): -	data = tryread(filename) -	if not data:  -		sinfo = platform.sys.platform -		sinfo += '\nsystem cannot create offscreen GL framebuffer object' -		sinfo += '\nsystem cannot create GL based images' -		sysid = platform.sys.platform+'_no_GL_renderer' -		return sinfo, sysid +    data = tryread(filename) +    if not data:  +        sinfo = platform.sys.platform +        sinfo += '\nsystem cannot create offscreen GL framebuffer object' +        sinfo += '\nsystem cannot create GL based images' +        sysid = platform.sys.platform+'_no_GL_renderer' +        return sinfo, sysid -	machine = ezsearch('Machine:(.*?)\n',data) -	machine = machine.replace(' ','-').replace('/','-') +    machine = ezsearch('Machine:(.*?)\n',data) +    machine = machine.replace(' ','-').replace('/','-') -	osinfo = ezsearch('OS info:(.*?)\n',data) -	osplain = osinfo.split(' ')[0].strip().replace('/','-') -	if 'windows' in osinfo.lower(): osplain = 'win' +    osinfo = ezsearch('OS info:(.*?)\n',data) +    osplain = osinfo.split(' ')[0].strip().replace('/','-') +    if 'windows' in osinfo.lower(): +        osplain = 'win' -	renderer = ezsearch('GL Renderer:(.*?)\n',data) -	tmp = renderer.split(' ') -	tmp = string.join(tmp[0:3],'-') -	tmp = tmp.split('/')[0] -	renderer = tmp +    renderer = ezsearch('GL Renderer:(.*?)\n',data) +    tmp = renderer.split(' ') +    tmp = string.join(tmp[0:3],'-') +    tmp = tmp.split('/')[0] +    renderer = tmp -	data += read_gitinfo() +    data += read_gitinfo() -	data += 'Image comparison: ImageMagick' +    data += 'Image comparison: ImageMagick' -	data = data.strip() +    data = data.strip() -	# create 4 letter hash and stick on end of sysid -	nondate_data = re.sub("\n.*?ompile date.*?\n","\n",data).strip() -	hexhash = hashlib.md5() -	hexhash.update(nondate_data) -	hexhash = hexhash.hexdigest()[-4:].upper() -	hash = '' -	for c in hexhash: hash += chr(ord(c)+97-48)  +    # create 4 letter hash and stick on end of sysid +    nondate_data = re.sub("\n.*?ompile date.*?\n", "\n", data).strip() +    hexhash = hashlib.md5(nondate_data).hexdigest()[-4:].upper() +    hash_ = ''.join(chr(ord(c) + 97 - 48) for c in hexhash) -	sysid = osplain + '_' + machine + '_' + renderer + '_' + hash -	sysid = sysid.replace('(','_').replace(')','_') -	sysid = sysid.lower() +    sysid = '_'.join([osplain, machine, renderer, hash_]) +    sysid = sysid.replace('(', '_').replace(')', '_') +    sysid = sysid.lower() -	return data, sysid +    return data, sysid  class Test: -	def __init__(self,fullname,time,passed,output,type,actualfile,expectedfile,scadfile,log): -		self.fullname,self.time,self.passed,self.output = \ -			fullname, time, passed, output -		self.type, self.actualfile, self.expectedfile, self.scadfile = \ -			type, actualfile, expectedfile, scadfile -		self.fulltestlog = log -		 -	def __str__(self): -		x = 'fullname: ' + self.fullname -		x+= '\nactualfile: ' + self.actualfile -		x+= '\nexpectedfile: ' + self.expectedfile -		x+= '\ntesttime: ' + self.time -		x+= '\ntesttype: ' + self.type -		x+= '\npassed: ' + str(self.passed) -		x+= '\nscadfile: ' + self.scadfile -		x+= '\noutput bytes: ' + str(len(self.output)) -		x+= '\ntestlog bytes: ' + str(len(self.fulltestlog)) -		x+= '\n' -		return x +    def __init__(self, fullname, subpr, passed, output, type, actualfile, +                 expectedfile, scadfile, log): +        self.fullname, self.time = fullname, time +        self.passed, self.output = passed, output +        self.type, self.actualfile = type, actualfile +        self.expectedfile, self.scadfile = expectedfile, scadfile +        self.fulltestlog = log +         +    def __str__(self): +        x = 'fullname: ' + self.fullname +        x+= '\nactualfile: ' + self.actualfile +        x+= '\nexpectedfile: ' + self.expectedfile +        x+= '\ntesttime: ' + self.time +        x+= '\ntesttype: ' + self.type +        x+= '\npassed: ' + str(self.passed) +        x+= '\nscadfile: ' + self.scadfile +        x+= '\noutput bytes: ' + str(len(self.output)) +        x+= '\ntestlog bytes: ' + str(len(self.fulltestlog)) +        x+= '\n' +        return x  def parsetest(teststring): -	patterns = ["Test:(.*?)\n", # fullname -		"Test time =(.*?) sec\n", -		"Test time.*?Test (Passed)", # pass/fail -		"Output:(.*?)<end of output>", -		'Command:.*?-s" "(.*?)"', # type -		"^ actual .*?:(.*?)\n", -		"^ expected .*?:(.*?)\n", -		'Command:.*?(testdata.*?)"' # scadfile  -		] -	hits = map( lambda pattern: ezsearch(pattern,teststring), patterns ) -	test = Test(hits[0],hits[1],hits[2]=='Passed',hits[3],hits[4],hits[5],hits[6],hits[7],teststring) -	if len(test.actualfile) > 0: test.actualfile_data = tryread(test.actualfile) -	if len(test.expectedfile) > 0: test.expectedfile_data = tryread(test.expectedfile) -	return test +    patterns = ["Test:(.*?)\n", # fullname +        "Test time =(.*?) sec\n", +        "Test time.*?Test (Passed)", # pass/fail +        "Output:(.*?)<end of output>", +        'Command:.*?-s" "(.*?)"', # type +        "^ actual .*?:(.*?)\n", +        "^ expected .*?:(.*?)\n", +        'Command:.*?(testdata.*?)"' # scadfile  +        ] +    hits = map( lambda pattern: ezsearch(pattern, teststring), patterns) +    test = Test(hits[0], hits[1], hits[2]=='Passed', hits[3], hits[4], hits[5],  +                hits[6], hits[7], teststring) +    if len(test.actualfile) > 0: +        test.actualfile_data = tryread(test.actualfile) +    if len(test.expectedfile) > 0: +        test.expectedfile_data = tryread(test.expectedfile) +    return test  def parselog(data): -	startdate = ezsearch('Start testing: (.*?)\n',data) -	enddate = ezsearch('End testing: (.*?)\n',data) -	pattern = '([0-9]*/[0-9]* Testing:.*?time elapsed.*?\n)' -	test_chunks = re.findall(pattern,data,re.S) -	tests = map( parsetest, test_chunks ) -	tests = sorted(tests, key = lambda t:t.passed) -	return startdate, tests, enddate +    startdate = ezsearch('Start testing: (.*?)\n', data) +    enddate = ezsearch('End testing: (.*?)\n', data) +    pattern = '([0-9]*/[0-9]* Testing:.*?time elapsed.*?\n)' +    test_chunks = re.findall(pattern,data, re.S) +    tests = map( parsetest, test_chunks ) +    tests = sorted(tests, key = lambda t: t.passed) +    return startdate, tests, enddate  def load_makefiles(builddir): -	filelist = [] -	for root, dirs, files in os.walk(builddir): -		for fname in files: filelist += [ os.path.join(root, fname) ] -	files  = filter(lambda x: 'build.make' in os.path.basename(x), filelist) -	files += filter(lambda x: 'flags.make' in os.path.basename(x), filelist) -	files = filter(lambda x: 'esting' not in x and 'emporary' not in x, files) -	result = {} -	for fname in files: -		result[fname.replace(builddir,'')] = open(fname,'rb').read() -	return result - -def wikify_filename(fname, wiki_rootpath, sysid): -	wikifname = fname.replace('/','_').replace('\\','_').strip('.') -	return wiki_rootpath + '_' + sysid + '_' + wikifname - -def towiki(wiki_rootpath, startdate, tests, enddate, sysinfo, sysid, makefiles): - -	wiki_template = """ -<h3>[[WIKI_ROOTPATH]] test run report</h3> - -'''Sysid''': SYSID - -'''Result summary''': NUMPASSED / NUMTESTS tests passed ( PERCENTPASSED % ) <br> - -'''System info''': -<pre> -SYSINFO -</pre> - -start time: STARTDATE <br> -end time  : ENDDATE <br> - -'''Image tests''' - -<REPEAT1> -{| border=1 cellspacing=0 cellpadding=1 -|- -| colspan=2 | FTESTNAME   -|- -| Expected image || Actual image -|- -| [[File:EXPECTEDFILE|250px]] || ACTUALFILE_WIKI -|} - -<pre> -TESTLOG -</pre> - - - -</REPEAT1> - - -'''Text tests''' - -<REPEAT2> -{|border=1 cellspacing=0 cellpadding=1 -|- -| FTESTNAME -|} - -<pre> -TESTLOG -</pre> - - -</REPEAT2> - -'''build.make and flags.make''' -<REPEAT3> -*[[MAKEFILE_NAME]] -</REPEAT3> -""" -	txtpages = {} -	imgs = {} -	passed_tests = filter(lambda x: x.passed, tests) -	failed_tests = filter(lambda x: not x.passed, tests) - -	tests_to_report = failed_tests -	if include_passed: tests_to_report = tests - -	try: percent = str(int(100.0*len(passed_tests) / len(tests))) -	except ZeroDivisionError: percent = 'n/a' -	s = wiki_template -	repeat1 = ezsearch('(<REPEAT1>.*?</REPEAT1>)',s) -	repeat2 = ezsearch('(<REPEAT2>.*?</REPEAT2>)',s) -	repeat3 = ezsearch('(<REPEAT3>.*?</REPEAT3>)',s) -	dic = { 'STARTDATE': startdate, 'ENDDATE': enddate, 'WIKI_ROOTPATH': wiki_rootpath, -		'SYSINFO': sysinfo, 'SYSID':sysid,  -		'NUMTESTS':len(tests), 'NUMPASSED':len(passed_tests), 'PERCENTPASSED':percent } -	for key in dic.keys(): -		s = s.replace(key,str(dic[key])) - -	for t in tests_to_report: -		if t.type in ('txt', 'ast', 'csg', 'term', 'echo'): -			newchunk = re.sub('FTESTNAME',t.fullname,repeat2) -			newchunk = newchunk.replace('TESTLOG',t.fulltestlog) -			s = s.replace(repeat2, newchunk+repeat2) -		elif t.type=='png': -			tmp = t.actualfile.replace(builddir,'') -			wikiname_a = wikify_filename(tmp,wiki_rootpath,sysid) -			tmp = t.expectedfile.replace(os.path.dirname(builddir),'') -			wikiname_e = wikify_filename(tmp,wiki_rootpath,sysid) -			if hasattr(t, 'expectedfile_data'):  -                                imgs[wikiname_e] = t.expectedfile_data -			if t.actualfile:  -				actualfile_wiki = '[[File:'+wikiname_a+'|250px]]' -                                if hasattr(t, 'actualfile_data'):  -                                        imgs[wikiname_a] = t.actualfile_data -			else: -				actualfile_wiki = 'No image generated.' -			newchunk = re.sub('FTESTNAME',t.fullname,repeat1) -			newchunk = newchunk.replace('ACTUALFILE_WIKI',actualfile_wiki) -			newchunk = newchunk.replace('EXPECTEDFILE',wikiname_e) -			newchunk = newchunk.replace('TESTLOG',t.fulltestlog) -			s = s.replace(repeat1, newchunk+repeat1) -		else: -			raise Exception("Unknown test type %r"%t.type) - -	makefiles_wikinames = {} -	for mf in sorted(makefiles.keys()): -		tmp = mf.replace('CMakeFiles','').replace('.dir','') -		wikiname = wikify_filename(tmp,wiki_rootpath,sysid) -		newchunk = re.sub('MAKEFILE_NAME',wikiname,repeat3) -		s = s.replace(repeat3, newchunk+repeat3) -		makefiles_wikinames[mf] = wikiname - -	s = s.replace(repeat1,'') -	s = s.replace(repeat2,'') -	s = s.replace(repeat3,'') -	s = re.sub('<REPEAT.*?>\n','',s) -	s = re.sub('</REPEAT.*?>','',s) - -	mainpage_wikiname = wiki_rootpath + '_' + sysid + '_test_report' -	txtpages[ mainpage_wikiname ] = s -	for mf in sorted(makefiles.keys()): -		txtpages[ makefiles_wikinames[ mf ] ] = '\n*Subreport from [['+mainpage_wikiname+']]\n\n\n<pre>\n'+makefiles[mf]+'\n</pre>' - -	return imgs, txtpages - -def png_encode64( fname, width=250 ): -	# en.wikipedia.org/wiki/Data_URI_scheme -	try: -		f = open( fname, "rb" ) -		data = f.read() -	except: -		data = '' -	data_uri = data.encode("base64").replace("\n","") -	tag  = '<img' -	tag += ' style="border:1px solid gray"' -	tag += ' src="data:image/png;base64,' -	tag +=   data_uri + '"' -	tag += ' width="'+str(width)+'"' -	if data =='': -		tag += ' alt="error: no image generated"' -	else: -		tag += ' alt="openscad_test_image"' -	tag += ' />\n' -	return tag - -def tohtml(wiki_rootpath, startdate, tests, enddate, sysinfo, sysid, makefiles): -	# kludge. assume wiki stuff has alreayd run and dumped files properly -	head = '<html><head><title>'+wiki_rootpath+' test run for '+sysid +'</title></head><body>' -	tail = '</body></html>' - -	passed_tests = filter(lambda x: x.passed, tests) -	failed_tests = filter(lambda x: not x.passed, tests) -	try: percent = str(int(100.0*len(passed_tests) / len(tests))) -	except ZeroDivisionError: percent = 'n/a' - -	tests_to_report = failed_tests -	if include_passed: tests_to_report = tests - -	s='' - -	s+= '\n<h3>' -	s+= '\nSystem info\n' -	s+= '\n</h3><p>' -	s+= '<pre>'+sysinfo+'</pre>\n' - -	s+= '\n<pre>' -	s+= '\nSTARTDATE: '+ startdate -	s+= '\nENDDATE: '+ enddate -	s+= '\nWIKI_ROOTPATH: '+ wiki_rootpath -	s+= '\nSYSID: '+sysid -	s+= '\nNUMTESTS: '+str(len(tests)) -	s+= '\nNUMPASSED: '+str(len(passed_tests)) -	s+= '\nPERCENTPASSED: '+ percent -	s+= '\n</pre>' - -	if not include_passed: -		s+= '<h3>Failed tests:</h3>\n' - -	if len(tests_to_report)==0: -		s+= '<p>none</p>' - -	for t in tests_to_report: -		if t.type in ('txt', 'ast', 'csg', 'term', 'echo'): -			s+='\n<pre>'+t.fullname+'</pre>\n' -			s+='<p><pre>'+t.fulltestlog+'</pre>\n\n' -		elif t.type=='png': -			tmp = t.actualfile.replace(builddir,'') -			wikiname_a = wikify_filename(tmp,wiki_rootpath,sysid) -			tmp = t.expectedfile.replace(os.path.dirname(builddir),'') -			wikiname_e = wikify_filename(tmp,wiki_rootpath,sysid) -			# imgtag_e = <img src='+wikiname_e+' width=250/>' -			# imatag_a = <img src='+wikiname_a+' width=250/>' -			imgtag_e = png_encode64( t.expectedfile, 250 ) -			imgtag_a = png_encode64( t.actualfile, 250 ) -			s+='<table>' -			s+='\n<tr><td colspan=2>'+t.fullname -			s+='\n<tr><td>Expected<td>Actual' -			s+='\n<tr><td>' + imgtag_e + '</td>' -			s+='\n    <td>' + imgtag_a + '</td>' -			s+='\n</table>' -			s+='\n<pre>' -			s+=t.fulltestlog -			s+='\n</pre>' -		else: -			raise Exception("Unknown test type %r"%t.type) - -	s+='\n\n<p>\n\n' - -	s+= '<h3> CMake .build files </h3>\n' -	s+= '\n<pre>' -	makefiles_wikinames = {} -	for mf in sorted(makefiles.keys()): -		mfname = mf.strip().lstrip(os.path.sep) -		text = open(os.path.join(builddir,mfname)).read() -		s+= '</pre><h4>'+mfname+'</h4><pre>' -		s+= text -		tmp = mf.replace('CMakeFiles','').replace('.dir','') -		wikiname = wikify_filename(tmp,wiki_rootpath,sysid) -		# s += '\n<a href='+wikiname+'>'+wikiname+'</a><br>' -	s+= '\n</pre>' -	s+='\n' - -	return head + s + tail - -def wiki_login(wikiurl,api_php_path,botname,botpass): -	site = mwclient.Site(wikiurl,api_php_path) -	site.login(botname,botpass) -	return site - -def wiki_upload(wikiurl,api_php_path,botname,botpass,filedata,wikipgname): -	counter = 0 -	done = False -	descrip = 'test' -	time.sleep(1) -	while not done: -		try: -			print 'login',botname,'to',wikiurl -			site = wiki_login(wikiurl,api_php_path,botname,botpass) -			print 'uploading...', -			if wikipgname.endswith('png'): -				site.upload(filedata,wikipgname,descrip,ignore=True) -			else: -				page = site.Pages[wikipgname] -				text = page.edit() -				page.save(filedata) -			done = True -			print 'transfer ok' -		except Exception, e: -			print 'Error:', type(e),e -			counter += 1 -			if counter>maxretry:  -				print 'giving up. please try a different wiki site' -				done = True -			else: -				print 'wiki',wikiurl,'down. retrying in 15 seconds' -				time.sleep(15)	 - -def upload(wikiurl,api_php_path='/',wiki_rootpath='test', sysid='null', botname='cakebaby',botpass='anniew',wikidir='.',dryrun=True): -	wetrun = not dryrun -	if dryrun: print 'dry run' -	try: -		global mwclient -		import mwclient -	except: -		print 'please download mwclient 0.6.5 and unpack here:', os.getcwd() -		sys.exit() - -	if wetrun: site = wiki_login(wikiurl,api_php_path,botname,botpass) - -	wikifiles = os.listdir(wikidir) -	testreport_page = filter( lambda x: 'test_report' in x, wikifiles ) -	if (len(testreport_page)>1):  -		print 'multiple test reports found, please clean dir',wikidir -		sys.exit() - -	rootpage = testreport_page[0] -	print 'add',rootpage,' to main report page ',wiki_rootpath -	if wetrun: -		page = site.Pages[wiki_rootpath] -		text = page.edit() -		if not '[['+rootpage+']]' in text: -			page.save(text +'\n*[['+rootpage+']]\n') - -	wikifiles = os.listdir(wikidir) -	wikifiles = filter(lambda x: not x.endswith('html'), wikifiles) - -	print 'upload wiki pages:' -	for wikiname in wikifiles: -		filename = os.path.join(wikidir,wikiname) -		filedata = tryread(filename) -		print 'upload',len(filedata),'bytes from',wikiname -		if wetrun and len(filedata)>0:  -			wiki_upload(wikiurl,api_php_path,botname,botpass,filedata,wikiname) -		if len(filedata)==0:  -			print 'cancelling empty upload' +    filelist = [] +    for root, dirs, files in os.walk(builddir): +        for fname in files: filelist += [ os.path.join(root, fname) ] +    files = [file for file in filelist if 'build.make' in os.path.basename(file)  +             or 'flags.make' in os.path.basename(file)] +    files = [file for file in files if 'esting' not in file and 'emporary' not in file] +    result = {} +    for fname in files: +        result[fname.replace(builddir, '')] = tryread(fname) +    return result + + +def png_encode64(fname, width=250, data=None): +    # en.wikipedia.org/wiki/Data_URI_scheme +    data = data or tryread(fname) or '' +    data_uri = data.encode('base64').replace('\n', '') +    tag = '''<img src="data:image/png;base64,%s" width="%s" %s/>''' +    if data == '': +        alt = 'alt="error: no image generated" ' +    else: +        alt = 'alt="openscad_test_image" ' +    tag %= (data_uri, width, alt) +    return tag +  def findlogfile(builddir): -	logpath = os.path.join(builddir,'Testing','Temporary') -	logfilename = os.path.join(logpath,'LastTest.log.tmp') -	if not os.path.isfile(logfilename): -		logfilename = os.path.join(logpath,'LastTest.log') -	if not os.path.isfile(logfilename): -		print 'cant find and/or open logfile',logfilename -		sys.exit() -	return logpath, logfilename +    logpath = os.path.join(builddir, 'Testing', 'Temporary') +    logfilename = os.path.join(logpath, 'LastTest.log.tmp') +    if not os.path.isfile(logfilename): +        logfilename = os.path.join(logpath, 'LastTest.log') +    if not os.path.isfile(logfilename): +        print 'can\'t find and/or open logfile', logfilename +        sys.exit() +    return logfilename + +# --- Templating --- +     +class Templates(object): +    html_template = '''<html> +    <head><title>Test run for {sysid}</title> +    {style} +    </head> +    <body> +        <h1>{project_name} test run report</h1> +        <p> +            <b>Sysid</b>:  {sysid} +        </p> +        <p> +            <b>Result summary</b>:  {numpassed} / {numtests} tests passed ({percent}%) +        </p> +         +        <h2>System info</h2> +        <pre>{sysinfo}</pre> +             +        <p>start time: {startdate}</p> +        <p>end time: {enddate}</p> + +        <h2>Image tests</h2> +        {image_tests} + +        <h2>Text tests</h2> +        {text_tests} + +        <h2>build.make and flags.make</h2> +        {makefiles} +    </body></html>''' + +    style = ''' +    <style> +        body { +            color: black; +        } + +        table { +            border-collapse: collapse; +        } + +        table td, th { +            border: 2px solid gray; +        } + +        .text-name { +            border: 2px solid black; +            padding: 0.14em; +        } +    </style>''' + +    image_template = '''<table> +    <tbody> +    <tr><td colspan="2">{test_name}</td></tr> +    <tr><td> Expected image </td><td> Actual image </td></tr> +    <tr><td> {expected} </td><td> {actual} </td></tr> +    </tbody> +    </table> + +    <pre> +    {test_log} +    </pre> +    ''' + +    text_template = ''' +    <span class="text-name">{test_name}</span> + +    <pre> +    {test_log} +    </pre> +    ''' + +    makefile_template = ''' +    <h4>{name}</h4> +    <pre> +        {text} +    </pre> +    ''' + +    def __init__(self, **defaults): +        self.filled = {} +        self.defaults = defaults + +    def fill(self, template, *args, **kwargs): +        kwds = self.defaults.copy() +        kwds.update(kwargs) +        return getattr(self, template).format(*args, **kwds) + +    def add(self, template, var, *args, **kwargs): +        self.filled[var] = self.filled.get(var, '') + self.fill(template, *args, **kwargs) +        return self.filled[var] + +    def get(self, var): +        return self.filled.get(var, '') + + +def to_html(project_name, startdate, tests, enddate, sysinfo, sysid, makefiles): +    passed_tests = [test for test in tests if test.passed] +    failed_tests = [test for test in tests if not test.passed] + +    report_tests = failed_tests +    if include_passed: +        report_tests = tests + +    percent = '%.0f' % (100.0 * len(passed_tests) / len(tests)) if tests else 'n/a' + +    templates = Templates() +    for test in report_tests: +        if test.type in ('txt', 'ast', 'csg', 'term', 'echo'): +            templates.add('text_template', 'text_tests', +                          test_name=test.fullname, +                          test_log=test.fulltestlog) +        elif test.type == 'png': +            actual_img = png_encode64(test.actualfile, +                                  data=vars(test).get('actualfile_data')) +            expected_img = png_encode64(test.expectedfile, +                                    data=vars(test).get('expectedfile_data')) +            templates.add('image_template', 'image_tests', +                          test_name=test.fullname, +                          test_log=test.fulltestlog, +                          actual=actual_img, +                          expected=expected_img) +        else: +            raise TypeError('Unknown test type %r' % test.type) +     +    for mf in sorted(makefiles.keys()): +        mfname = mf.strip().lstrip(os.path.sep) +        text = open(os.path.join(builddir, mfname)).read() +        templates.add('makefile_template', 'makefiles', name=mfname, text=text) + +    text_tests = templates.get('text_tests') +    image_tests = templates.get('image_tests') +    makefiles_str = templates.get('makefiles') + +    return templates.fill('html_template', style=Templates.style, +                          sysid=sysid, sysinfo=sysinfo, +                          startdate=startdate, enddate=enddate, +                          project_name=project_name, +                          numtests=len(tests), +                          numpassed=len(passed_tests), +                          percent=percent, image_tests=image_tests, +                          text_tests=text_tests, makefiles=makefiles_str) + +# --- End Templating --- + +# --- Web Upload --- + +def postify(data): +    return urlencode(data).encode() + +def create_page(): +    data = { +        'action': 'create', +        'type': 'html' +    } +    try: +        response = urlopen('http://www.dinkypage.com', data=postify(data)) +    except: +        return None +    return response.geturl() + +def upload_html(page_url, title, html): +    data = { +        'mode': 'editor', +        'title': title, +        'html': html, +        'ajax': '1' +    } +    try: +        response = urlopen(page_url, data=postify(data)) +    except: +        return False +    return 'success' in response.read().decode() + +# --- End Web Upload ---  def debug(x): -	if debug_test_pp: print 'test_pretty_print: '+x +    if debug_test_pp: +        print 'test_pretty_print: ' + x -debug_test_pp=False -builddir=os.getcwd() +debug_test_pp = False +include_passed = False +builddir = os.getcwd()  def main(): -	#wikisite = 'cakebaby.referata.com' -	#wiki_api_path = '' -	global wikisite, wiki_api_path, wiki_rootpath, builddir, debug_test_pp -	global maxretry, dry, include_passed - -	wikisite = 'cakebaby.wikia.com' -	wiki_api_path = '/' -	wiki_rootpath = 'OpenSCAD' -	if '--debug' in string.join(sys.argv): debug_test_pp=True -	maxretry = 10 - -	if bool(os.getenv("TEST_GENERATE")): sys.exit(0) - -	include_passed = False -	if '--include-passed' in sys.argv: include_passed = True - -	dry = False -	debug( 'running test_pretty_print' ) -	if '--dryrun' in sys.argv: dry=True -	suffix = ezsearch('--suffix=(.*?) ',string.join(sys.argv)+' ') -	builddir = ezsearch('--builddir=(.*?) ',string.join(sys.argv)+' ') -	if builddir=='': builddir=os.getcwd() -	debug( 'build dir set to ' +  builddir ) - -	sysinfo, sysid = read_sysinfo(os.path.join(builddir,'sysinfo.txt')) -	makefiles = load_makefiles(builddir) -	logpath, logfilename = findlogfile(builddir) -	testlog = tryread(logfilename) -	startdate, tests, enddate = parselog(testlog) -	if debug_test_pp: -		print 'found sysinfo.txt,', -		print 'found', len(makefiles),'makefiles,', -		print 'found', len(tests),'test results' - -	imgs, txtpages = towiki(wiki_rootpath, startdate, tests, enddate, sysinfo, sysid, makefiles) - -	wikidir = os.path.join(logpath,sysid+'_report') -	debug( 'erasing files in ' + wikidir ) -	try: map(lambda x:os.remove(os.path.join(wikidir,x)), os.listdir(wikidir)) -	except: pass -	debug( 'output dir:\n' + wikidir.replace(os.getcwd(),'') ) -	debug( 'writing ' + str(len(imgs)) + ' images' ) -	debug( 'writing ' + str(len(txtpages)-1) + ' text pages' ) -	debug( 'writing index.html ' ) -	if '--wiki' in string.join(sys.argv): -		print "wiki output is deprecated" -		for pgname in sorted(imgs): trysave( os.path.join(wikidir,pgname), imgs[pgname]) -		for pgname in sorted(txtpages): trysave( os.path.join(wikidir,pgname), txtpages[pgname]) - -	htmldata = tohtml(wiki_rootpath, startdate, tests, enddate, sysinfo, sysid, makefiles) -	html_basename = sysid+'_report.html' -	html_filename = os.path.join(builddir,'Testing','Temporary',html_basename) -	debug('saving ' +html_filename + ' ' + str(len(htmldata)) + ' bytes') -	trysave( html_filename, htmldata ) -	print "report saved:", html_filename.replace(os.getcwd()+os.path.sep,'') - -	if '--wiki-upload' in sys.argv: -		print "wiki upload is deprecated." -		upload(wikisite,wiki_api_path,wiki_rootpath,sysid,'openscadbot', -			'tobdacsnepo',wikidir,dryrun=dry) -		print 'upload attempt complete' - -	debug( 'test_pretty_print complete' ) +    global builddir, debug_test_pp +    global maxretry, dry, include_passed +    project_name = 'OpenSCAD' +     +    if bool(os.getenv("TEST_GENERATE")): +        sys.exit(0) +     +    # --- Command Line Parsing --- +     +    if '--debug' in ' '.join(sys.argv): +        debug_test_pp = True +    maxretry = 10 + +    if '--include-passed' in sys.argv: +        include_passed = True + +    dry = False +    debug('running test_pretty_print') +    if '--dryrun' in sys.argv: +        dry = True + +    suffix = ezsearch('--suffix=(.*?) ', ' '.join(sys.argv) + ' ') +    builddir = ezsearch('--builddir=(.*?) ', ' '.join(sys.argv) + ' ') +    if not builddir: +        builddir = os.getcwd() +    debug('build dir set to ' +  builddir) + +    upload = False +    if '--upload' in sys.argv: +        upload = True +        debug('will upload test report') + +    # Workaround for old cmake's not being able to pass parameters +    # to CTEST_CUSTOM_POST_TEST +    if bool(os.getenv("OPENSCAD_UPLOAD_TESTS")): +        upload = True +     +    # --- End Command Line Parsing --- + +    sysinfo, sysid = read_sysinfo(os.path.join(builddir, 'sysinfo.txt')) +    makefiles = load_makefiles(builddir) +    logfilename = findlogfile(builddir) +    testlog = tryread(logfilename) +    startdate, tests, enddate = parselog(testlog) +    if debug_test_pp: +        print 'found sysinfo.txt,', +        print 'found', len(makefiles),'makefiles,', +        print 'found', len(tests),'test results' + + +    html = to_html(project_name, startdate, tests, enddate, sysinfo, sysid, makefiles) +    html_basename = sysid + '_report.html' +    html_filename = os.path.join(builddir, 'Testing', 'Temporary', html_basename) +    debug('saving ' + html_filename + ' ' + str(len(html)) + ' bytes') +    trysave(html_filename, html) + +    if upload: +        page_url = create_page() +        if upload_html(page_url, title='OpenSCAD test results', html=html): +            share_url = page_url.partition('?')[0] +            print 'html report uploaded at', share_url +        else: +            print 'could not upload html report' + +    debug('test_pretty_print complete')  if __name__=='__main__': -	main() +    main() | 
