from pathlib import Path
import xml.etree.ElementTree as ET
from xml.dom import minidom
import json,hashlib,sys,datetime
r=Path(__file__).resolve().parent
fixtures={'compact':b'<batch><row>north</row><row>south</row></batch>','preformatted':b'<batch>\n  <row>north</row>\n  <row>south</row>\n</batch>','mixed-fresh':b'<note>Ship <part code="N7">cobalt</part> today.</note>','preserve-inherited':b'<doc xml:space="preserve"><group><v>  cobalt  </v><v>teal</v></group></doc>','preserve-reset':b'<doc xml:space="preserve"><group xml:space="default"><v>  cobalt  </v><v>teal</v></group></doc>','pad-fresh':b'<memo xml:space="preserve"><pad>   </pad><v>cobalt</v></memo>'}
sha=lambda b:hashlib.sha256(b).hexdigest()
def read(b):
 e=ET.fromstring(b);return {'tag':e.tag,'joined_text':''.join(e.itertext()),'elements':[{'tag':x.tag,'text':x.text,'tail':x.tail,'attributes':x.attrib}for x in e.iter()]}
def domtext(n):
 return ''.join(c.data if c.nodeType in [c.TEXT_NODE,c.CDATA_SECTION_NODE] else domtext(c) for c in n.childNodes)
rows=[]
def transform(data,route):
 if route=='elementtree':
  e=ET.fromstring(data);ET.indent(e,space='  ');return ET.tostring(e,encoding='utf-8')
 return minidom.parseString(data).toprettyxml(indent='  ',encoding='utf-8')
for name,b in fixtures.items():
 (r/(name+'.xml')).write_bytes(b);original=read(b)
 for route in ['elementtree','minidom']:
  first=transform(b,route);second=transform(first,route)
  saved=[]
  for k,out in [(1,first),(2,second)]:
   n=f'{name}-{route}-pass{k}.xml';(r/n).write_bytes(out);back=read(out);saved.append({'pass':k,'file':n,'bytes':len(out),'sha256':sha(out),'reparsed':back,'independent_dom_joined_text':domtext(minidom.parseString(out).documentElement),'joined_text_equal_original':original['joined_text']==back['joined_text']})
  rows.append({'fixture':name,'path':route,'input_file':name+'.xml','input_bytes':len(b),'input_sha256':sha(b),'original':original,'passes':saved,'second_equals_first_bytes':first==second,'second_equals_first_text':saved[0]['reparsed']['joined_text']==saved[1]['reparsed']['joined_text'],'first_text_length':len(saved[0]['reparsed']['joined_text']),'second_text_length':len(saved[1]['reparsed']['joined_text'])})
d={'date':datetime.datetime.now(datetime.timezone.utc).isoformat(),'python':sys.version.split()[0],'elementtree_version':ET.VERSION,'minidom':'Python standard library bundled with '+sys.version.split()[0],'method':'ET.indent plus ET.tostring versus minidom.toprettyxml; both2-space indentation, default behavior, no filters. All output reparsed with ET, text and tail kept including whitespace. New locally constructed fixtures, not online converters.','rows':rows};assert all(y['independent_dom_joined_text']==y['reparsed']['joined_text']for x in rows for y in x['passes'])
(r/'results.json').write_text(json.dumps(d,indent=2,ensure_ascii=False),encoding='utf-8')
print(json.dumps([{'fixture':x['fixture'],'path':x['path'],'input':x['input_bytes'],'p1':x['passes'][0]['bytes'],'p2':x['passes'][1]['bytes'],'idempotent':x['second_equals_first_bytes'],'text1':x['first_text_length'],'text2':x['second_text_length']}for x in rows]))
