#!/usr/bin/env python3 """Compile thermodynamics rejection cases against this checkout's runtime.""" from pathlib import Path import os import subprocess import tempfile ROOT = Path(__file__).resolve().parents[1] NODE_CASES = [ ('thermal reservoir,reservoir width=0', 'Thermal component dimensions must be positive'), ('heat engine,thermal device size=0', 'Thermal device size must be positive'), ('pv diagram,pv height=0', 'PV dimensions and axis maxima must be positive'), ('isothermal process,pv max volume=0', 'PV dimensions and axis maxima must be positive'), ('isothermal process,pv start volume=-1', 'PV start state must lie inside positive axis limits'), ('isothermal process,pv end volume=5', 'PV end volume must be positive distinct'), ('isothermal process,pv end volume=.1', 'PV end pressure must lie inside positive axis limits'), ('isochoric process,pv end pressure=3', 'Isochoric start and end pressures must differ'), ('adiabatic process,pv gamma=1', 'Adiabatic gamma must exceed 1'), ('polytropic process,pv exponent=11', 'Polytropic exponent magnitude must not exceed 10'), ('rectangular cycle,pv low volume=3', 'Cycle states must be positive ordered'), ('carnot cycle,carnot temperature ratio=1', 'Carnot requires positive state'), ('carnot cycle,pv max volume=2', 'Carnot cycle exceeds the PV axis limits'), # Previously these impossible states reached PGF's power overflow first. ('carnot cycle,carnot temperature ratio=.5,pv gamma=1.01', 'Carnot cycle exceeds the PV axis limits'), ('carnot cycle,carnot temperature ratio=.01', 'Carnot cycle exceeds the PV axis limits'), ('carnot cycle,carnot expansion ratio=10000', 'Carnot cycle exceeds the PV axis limits'), ('polytropic process,pv start volume=3,pv end volume=.1,pv exponent=10', 'PV end pressure must lie inside positive axis limits'), ('carnot cycle,carnot expansion ratio=1', 'Carnot requires positive state'), ('carnot cycle,pv gamma=1', 'Carnot requires positive state'), ] PIC_CASES = [ (r'\pic {heat engine diagram={thermo diagram separation=.5cm}};', 'Thermal diagram separation must clear device and reservoirs'), (r'\pic {heat pump diagram={thermo diagram work length=0cm}};', 'Thermal diagram separation must clear device and reservoirs'), ] def main(): env = os.environ.copy() env['TEXINPUTS'] = str(ROOT) + os.pathsep cases = [(r'\node[' + options + r'] (N) {};', diagnostic) for options, diagnostic in NODE_CASES] + PIC_CASES with tempfile.TemporaryDirectory(prefix='tikzphysics-thermodynamics-') as folder: work = Path(folder) for index, (body, diagnostic) in enumerate(cases): source = (r'\documentclass{article}\usepackage{tikzphysics}\begin{document}' r'\begin{tikzpicture}' + body + r'\end{tikzpicture}\end{document}') (work / 'case.tex').write_text(source) proc = subprocess.run( ['pdflatex', '-interaction=nonstopmode', '-halt-on-error', 'case.tex'], cwd=work, env=env, capture_output=True, text=True, timeout=60) # TeX may hard-wrap a diagnostic inside a word. normalized = ''.join(proc.stdout.split()) if proc.returncode == 0 or ''.join(diagnostic.split()) not in normalized: raise SystemExit(f'FAIL case {index}: {body}\n{proc.stdout[-2500:]}') print(f'PASS: rejected {body}') print(f'All {len(cases)} invalid-input cases rejected with the intended diagnostic.') if __name__ == '__main__': main()