--- a +++ b/tests/spec/test_specs.py @@ -0,0 +1,152 @@ +import pytest + +from ehrql.docs.specs import ( + build_chapter, + build_section, + concatenate_optional_text, + get_series_code, + get_title_for_test_fn, +) + + +def test_concatenate_optional_text_present(): + first_dict = {"a": 0, "b": 1} + text = "test" + combined_dict = concatenate_optional_text(first_dict, text) + assert "text" in combined_dict, "optional text not present" + assert combined_dict["text"] == "test", "incorrect value for optional text" + + +def test_concatenate_optional_text_absent(): + first_dict = {"a": 0, "b": 1} + text = None + combined_dict = concatenate_optional_text(first_dict, text) + assert "text" not in combined_dict, "optional text present" + + +def test_build_chapter_empty_sections(): + chapter = build_chapter(1, "dummy", []) + assert chapter["id"] == 1 + assert chapter["title"] == "Dummy chapter for testing spec generation" + assert chapter["text"] == "This chapter should not appear in the table of contents" + + +def test_build_section(): + section = build_section(1, "dummy", "test_dummy") + assert section["id"] == 1 + assert section["title"] == "Dummy section for testing spec generation" + assert section["text"] == "This section should not appear in the table of contents" + paragraphs = section["paragraphs"] + assert len(paragraphs) == 2 + for paragraph in paragraphs: + if paragraph["id"] == "1.1": + assert paragraph["text"] == "this docstring should appear in the spec", ( + "paragraph text not found when docstring present" + ) + continue + if paragraph["id"] == "1.2": + assert "text" not in paragraph, ( + "paragraph text found when no docstring present" + ) + continue + assert False, "expected paragraph ids not found" + + +def test_where_with_expr(): + pass + + +test_where_with_expr.title = "Find rows where an expression is matched" + + +def test_where_with_constant_true(): + pass + + +@pytest.mark.parametrize( + "test_fn,title", + [ + (test_where_with_expr, "Find rows where an expression is matched"), + (test_where_with_constant_true, "Where with constant true"), + ], +) +def test_get_title_for_test_fn(test_fn, title): + assert get_title_for_test_fn(test_fn) == title + + +@pytest.mark.parametrize( + "source_lines,source_index,includes_population,expected", + [ + ( + # single line + ['p.d1.is_before("2000-01-20"),'], + 0, + False, + 'p.d1.is_before("2000-01-20")', + ), + ( + # multiple lines + [ + "case(", + " when(p.i1 < 8).then(p.i1),", + " when(p.i1 > 8).then(100),", + "),", + ], + 0, + False, + "case(\n when(p.i1 < 8).then(p.i1),\n when(p.i1 > 8).then(100),\n)", + ), + ( + # real test function; multiple lines, series starts after table_data + [ + " spec_test(", + " table_data,", + " case(", + " when(p.i1 < 8).then(p.i1),", + " when(p.i1 > 8).then(100),", + " ),", + " {", + " 1: 6,", + " 2: 7,", + " 3: None,", + " 4: 100,", + " 5: None,", + " },", + " )", + ], + 2, + False, + "case(\n when(p.i1 < 8).then(p.i1),\n when(p.i1 > 8).then(100),\n)", + ), + ( + # incomplete series definition; this should never happen as it should only exist if + # there's a syntax error in a specs tests, which would raise an error earlier than + # this code + ["p.d1.is_before("], + 0, + False, + "p.d1.is_before(", + ), + ( + # with population definition + ['p.d1.is_before("2000-01-20"),', "population=p.b1"], + 0, + True, + 'p.d1.is_before("2000-01-20")\ndefine_population(p.b1)', + ), + ( + # incomplete population definition; this should also never happen + ['p.d1.is_before("2000-01-20"),', 'population=p.d2.is_before("2000-01-'], + 0, + True, + 'p.d1.is_before("2000-01-20")\ndefine_population(p.d2.is_before("2000-01-)', + ), + ], +) +def test_get_series_code(source_lines, source_index, includes_population, expected): + assert ( + get_series_code( + source_lines, source_index, define_population=includes_population + ) + == expected + )