--- a +++ b/tests/unit/test_renderers.py @@ -0,0 +1,237 @@ +import textwrap +from itertools import product + +import pytest + +from ehrql.query_engines.in_memory_database import ( + PatientColumn, + PatientTable, +) +from ehrql.renderers import DISPLAY_RENDERERS + + +TABLE = PatientTable.parse( + """ + | i1 | i2 + --+-----+----- + 1 | 101 | 111 + 2 | 201 | 211 + 3 | 301 | 311 + 4 | 401 | 411 + 5 | 501 | 511 + """ +) + + +@pytest.mark.parametrize("render_format", ["ascii", "html"]) +def test_render_table(render_format): + expected_output = { + "ascii": textwrap.dedent( + """ + patient_id | i1 | i2 + ------------------+-------------------+------------------ + 1 | 101 | 111 + 2 | 201 | 211 + 3 | 301 | 311 + 4 | 401 | 411 + 5 | 501 | 511 + """ + ).strip(), + "html": ( + "<!-- start debug output -->" + "<table>" + "<thead>" + "<tr><th>patient_id</th><th>i1</th><th>i2</th></tr>" + "</thead>" + "<tbody>" + "<tr><td>1</td><td>101</td><td>111</td></tr>" + "<tr><td>2</td><td>201</td><td>211</td></tr>" + "<tr><td>3</td><td>301</td><td>311</td></tr>" + "<tr><td>4</td><td>401</td><td>411</td></tr>" + "<tr><td>5</td><td>501</td><td>511</td></tr>" + "</tbody>" + "</table>" + "<!-- end debug output -->" + ), + } + rendered = DISPLAY_RENDERERS[render_format](list(TABLE.to_records())).strip() + assert rendered == expected_output[render_format], rendered + + +@pytest.mark.parametrize("render_format", ["ascii", "html"]) +def test_render_column(render_format): + expected_output = expected_output = { + "ascii": textwrap.dedent( + """ + patient_id | value + ------------------+------------------ + 1 | 101 + 2 | 201 + """ + ).strip(), + "html": ( + "<!-- start debug output -->" + "<table>" + "<thead>" + "<tr><th>patient_id</th><th>value</th></tr>" + "</thead>" + "<tbody>" + "<tr><td>1</td><td>101</td></tr>" + "<tr><td>2</td><td>201</td></tr>" + "</tbody>" + "</table>" + "<!-- end debug output -->" + ), + } + + c = PatientColumn.parse( + """ + 1 | 101 + 2 | 201 + """ + ) + rendered = DISPLAY_RENDERERS[render_format](list(c.to_records())).strip() + assert rendered == expected_output[render_format], rendered + + +@pytest.mark.parametrize("render_format", ["ascii", "html"]) +def test_render_table_head(render_format): + expected_output = { + "ascii": textwrap.dedent( + """ + patient_id | i1 | i2 + ------------------+-------------------+------------------ + 1 | 101 | 111 + 2 | 201 | 211 + ... | ... | ... + """ + ).strip(), + "html": ( + "<!-- start debug output -->" + "<table>" + "<thead>" + "<tr><th>patient_id</th><th>i1</th><th>i2</th></tr>" + "</thead>" + "<tbody>" + "<tr><td>1</td><td>101</td><td>111</td></tr>" + "<tr><td>2</td><td>201</td><td>211</td></tr>" + "<tr><td>…</td><td>…</td><td>…</td></tr>" + "</tbody>" + "</table>" + "<!-- end debug output -->" + ), + } + + truncated = DISPLAY_RENDERERS[render_format](list(TABLE.to_records()), head=2) + assert truncated == expected_output[render_format], truncated + + +@pytest.mark.parametrize("render_format", ["ascii", "html"]) +def test_render_table_tail(render_format): + expected_output = { + "ascii": textwrap.dedent( + """ + patient_id | i1 | i2 + ------------------+-------------------+------------------ + ... | ... | ... + 4 | 401 | 411 + 5 | 501 | 511 + """ + ).strip(), + "html": ( + "<!-- start debug output -->" + "<table>" + "<thead>" + "<tr><th>patient_id</th><th>i1</th><th>i2</th></tr>" + "</thead>" + "<tbody>" + "<tr><td>…</td><td>…</td><td>…</td></tr>" + "<tr><td>4</td><td>401</td><td>411</td></tr>" + "<tr><td>5</td><td>501</td><td>511</td></tr>" + "</tbody>" + "</table>" + "<!-- end debug output -->" + ), + } + + truncated = DISPLAY_RENDERERS[render_format](list(TABLE.to_records()), tail=2) + assert truncated == expected_output[render_format], truncated + + +@pytest.mark.parametrize("render_format", ["ascii", "html"]) +def test_render_table_head_and_tail(render_format): + expected_output = { + "ascii": textwrap.dedent( + """ + patient_id | i1 | i2 + ------------------+-------------------+------------------ + 1 | 101 | 111 + 2 | 201 | 211 + ... | ... | ... + 4 | 401 | 411 + 5 | 501 | 511 + """ + ).strip(), + "html": ( + "<!-- start debug output -->" + "<table>" + "<thead>" + "<tr><th>patient_id</th><th>i1</th><th>i2</th></tr>" + "</thead>" + "<tbody>" + "<tr><td>1</td><td>101</td><td>111</td></tr>" + "<tr><td>2</td><td>201</td><td>211</td></tr>" + "<tr><td>…</td><td>…</td><td>…</td></tr>" + "<tr><td>4</td><td>401</td><td>411</td></tr>" + "<tr><td>5</td><td>501</td><td>511</td></tr>" + "</tbody>" + "</table>" + "<!-- end debug output -->" + ), + } + + truncated = DISPLAY_RENDERERS[render_format]( + list(TABLE.to_records()), head=2, tail=2 + ) + assert truncated == expected_output[render_format], truncated + + +@pytest.mark.parametrize( + "render_format,head_tail", + list(product(["ascii"], [(0, 0), (2, 3), (5, 0), (0, 6), (3, 3)])), +) +def test_render_table_bad_head_tail(render_format, head_tail): + expected_output = { + "ascii": textwrap.dedent( + """ + patient_id | i1 | i2 + ------------------+-------------------+------------------ + 1 | 101 | 111 + 2 | 201 | 211 + 3 | 301 | 311 + 4 | 401 | 411 + 5 | 501 | 511 + """ + ).strip(), + "html": ( + "<!-- start debug output -->" + "<table>" + "<thead>" + "<tr><th>patient_id</th><th>i1</th><th>i2</th></tr>" + "</thead>" + "<tbody>" + "<tr><td>1</td><td>101</td><td>111</td></tr>" + "<tr><td>2</td><td>201</td><td>211</td></tr>" + "<tr><td>3</td><td>301</td><td>311</td></tr>" + "<tr><td>4</td><td>401</td><td>411</td></tr>" + "<tr><td>5</td><td>501</td><td>511</td></tr>" + "</tbody>" + "</table>" + "<!-- end debug output -->" + ), + } + head, tail = head_tail + truncated = DISPLAY_RENDERERS[render_format]( + list(TABLE.to_records()), head=head, tail=tail + ) + assert truncated == expected_output[render_format], (truncated, head, tail)