@@ -77,19 +77,38 @@ def filter_tojson(data, separators=(',', ':'), indent=None) -> str:
7777def jinja_env (exercise : pathlib .Path ) -> jinja2 .Environment :
7878 """Return a configured Jinja env with filters added."""
7979 env = jinja2 .Environment (loader = jinja2 .FileSystemLoader (exercise / ".meta" ))
80+ # Shell quoting
8081 env .filters ["quote" ] = shlex .quote
82+ # JSON formatting, default to compact form (`jq -c`).
8183 env .filters ["tojson" ] = filter_tojson
84+ # String escaping, ANSI-C style.
8285 env .filters ["repr" ] = repr
86+ # Return a dict with only specified keys kepts.
8387 env .filters ["camel_to_snake" ] = lambda x : re .sub (r"([a-z])([A-Z])" , (lambda m : f"{ m .group (1 )} _{ m .group (2 ).lower ()} " ), x )
8488 env .filters ["format_list" ] = lambda x : shlex .quote (
8589 "[" + "," .join (f'"{ i } "' if isinstance (i , str ) else str (i ) for i in x ) + "]"
8690 )
8791 return env
8892
8993
94+ def bool_to_str (obj ):
95+ """Convert boolean values to strings."""
96+ if isinstance (obj , dict ):
97+ return {key : bool_to_str (val ) for key , val in obj .items ()}
98+ if isinstance (obj , list ):
99+ return [bool_to_str (val ) for val in obj ]
100+ if obj is True :
101+ return "true"
102+ if obj is False :
103+ return "false"
104+ return obj
105+
106+
90107def generate (specs : pathlib .Path , exercise : pathlib .Path ) -> None :
91108 """Generate and write test file for a given spec and exercise."""
92109 cases = get_cases (specs , exercise )
110+ for case in cases :
111+ case ["expected" ] = bool_to_str (case ["expected" ])
93112
94113 timestamp = datetime .datetime .now (tz = datetime .UTC ).replace (microsecond = 0 ).isoformat ()
95114 header = textwrap .dedent (f"""\
@@ -106,18 +125,23 @@ def generate(specs: pathlib.Path, exercise: pathlib.Path) -> None:
106125 }
107126
108127 # Render the template.
109- out = jinja_env (exercise ).get_template ("template.j2" ).render (data ).strip ()
128+ try :
129+ template = jinja_env (exercise ).get_template ("template.j2" )
130+ out = template .render (data )
131+ except jinja2 .exceptions .TemplateAssertionError as e :
132+ e .add_note (f"Error rendering template for { exercise .name } " )
133+ raise
110134
111135 # Check for changes or the lack thereof.
112136 test_file = exercise / json .loads ((exercise / ".meta/config.json" ).read_text ())["files" ]["test" ][0 ]
113137 if test_file .exists ():
114- old_content = [i for i in test_file .read_text ().strip (). splitlines () if "generated on" not in i ]
138+ old_content = [i for i in test_file .read_text ().splitlines () if "generated on" not in i ]
115139 new_content = [i for i in out .splitlines () if "generated on" not in i ]
116140 if old_content == new_content :
117141 return
118142
119143 # Write the test file.
120- test_file .write_text (out + " \n " )
144+ test_file .write_text (out )
121145
122146
123147def argparser () -> argparse .ArgumentParser :
0 commit comments