# -*- coding: utf-8 -*- """Panel Analysis Handling page pre-fill: `face_lifters` / `edge_lifters` read straight off Panel Lift's own `job['panel']['lifters']`, split face vs edge the way `knowledge.handling.lifter_groups` groups them for the rest of the tool. """ from vibe import knowledge from vibe import pa_lifters def _know(): know = knowledge._deep_copy(knowledge.DEFAULTS) know['handling']['lifter_groups'] = { 'face': {'families': ['FACE_X']}, 'edge_top': {'families': ['EDGE_Y']}, } return know def _lifter(family, x, y, on_edge=False, mark='m'): return {'family': family, 'mark': mark, 'x': x, 'y': y, 'on_edge': on_edge} # --------------------------------------------------------------- lifter_lines def test_face_and_edge_split_by_knowledge_groups(): know = _know() lifters = [ _lifter('FACE_X_ANCHOR', 2.5, 0.75, mark='f1'), _lifter('EDGE_Y_ANCHOR', 25.0, 2.25, mark='e1'), ] face_text, edge_text, why = pa_lifters.lifter_lines(lifters, 3.0, know) assert face_text == '2.50 @ 0.25' assert edge_text == '25.00 @ 0.75' assert 'FACE_X_ANCHOR' in why assert 'EDGE_Y_ANCHOR' in why assert '1 face lifter' in why assert '1 edge lifter' in why def test_on_edge_flag_counts_as_edge_even_off_the_edge_top_family_list(): know = _know() lifters = [_lifter('SOME_OTHER_FAMILY', 10.0, 1.5, on_edge=True)] face_text, edge_text, why = pa_lifters.lifter_lines(lifters, 3.0, know) assert face_text == '' assert edge_text == '10.00 @ 0.50' def test_family_matching_neither_group_and_not_on_edge_is_unclassified(): know = _know() lifters = [_lifter('MYSTERY_FAMILY', 5.0, 1.0)] face_text, edge_text, why = pa_lifters.lifter_lines(lifters, 2.0, know) assert face_text == '' assert edge_text == '' assert 'MYSTERY_FAMILY' in why assert 'matched neither' in why def test_lines_sorted_by_x_then_frac_same_x_is_a_row(): know = _know() lifters = [ _lifter('FACE_X_A', 10.0, 2.0, mark='a'), _lifter('FACE_X_B', 2.0, 1.0, mark='b'), _lifter('FACE_X_C', 10.0, 1.0, mark='c'), ] face_text, _edge_text, _why = pa_lifters.lifter_lines(lifters, 4.0, know) assert face_text == ('2.00 @ 0.25\n' '10.00 @ 0.25\n' '10.00 @ 0.50') def test_missing_x_or_y_is_skipped_and_counted_in_why(): know = _know() lifters = [ _lifter('FACE_X_A', None, 1.0, mark='a'), _lifter('FACE_X_B', 2.0, None, mark='b'), _lifter('FACE_X_C', 2.0, 1.0, mark='c'), ] face_text, _edge_text, why = pa_lifters.lifter_lines(lifters, 4.0, know) assert face_text == '2.00 @ 0.25' assert '2 lifters skipped' in why def test_no_width_skips_every_lifter_and_says_so(): know = _know() lifters = [_lifter('FACE_X_A', 2.0, 1.0)] face_text, edge_text, why = pa_lifters.lifter_lines(lifters, None, know) assert face_text == '' and edge_text == '' assert '1 lifter skipped' in why def test_empty_lifter_list(): know = _know() face_text, edge_text, why = pa_lifters.lifter_lines([], 4.0, know) assert face_text == '' and edge_text == '' assert '0 face lifters' in why assert '0 edge lifters' in why # ---------------------------------------------------------------- read_lifters def test_read_lifters_from_a_job_dict(): know = _know() job = {'panel': {'width_ft': 3.0, 'lifters': [ _lifter('FACE_X_ANCHOR', 2.5, 0.75), _lifter('EDGE_Y_ANCHOR', 25.0, 2.25), ]}} out = pa_lifters.read_lifters(job, know) assert out['face_lifters'] == '2.50 @ 0.25' assert out['edge_lifters'] == '25.00 @ 0.75' assert 'lifters_basis' in out def test_read_lifters_omits_empty_text_but_keeps_basis(): know = _know() job = {'panel': {'width_ft': 3.0, 'lifters': [ _lifter('FACE_X_ANCHOR', 2.5, 0.75), ]}} out = pa_lifters.read_lifters(job, know) assert 'face_lifters' in out assert 'edge_lifters' not in out assert 'lifters_basis' in out def test_read_lifters_no_job_is_empty_dict(): know = _know() assert pa_lifters.read_lifters(None, know) == {} def test_read_lifters_no_lifters_key_is_empty_dict(): know = _know() assert pa_lifters.read_lifters({'panel': {'width_ft': 3.0}}, know) == {} assert pa_lifters.read_lifters( {'panel': {'width_ft': 3.0, 'lifters': []}}, know) == {} def test_read_lifters_is_defensive_on_bad_input(): know = _know() # 'panel' is not a dict -- .get on a list raises AttributeError inside; # this must come back {} rather than propagate. assert pa_lifters.read_lifters({'panel': ['not', 'a', 'dict']}, know) \ == {} # ----------------------------------------------------------- parse_lifter_lines def test_parse_lifter_lines_round_trip(): text = '2.50 @ 0.25\n10.00 @ 0.50' rows, problems = pa_lifters.parse_lifter_lines(text) assert problems == [] assert rows == [{'x_ft': 2.5, 'frac': 0.25}, {'x_ft': 10.0, 'frac': 0.5}] def test_parse_lifter_lines_blank_text(): assert pa_lifters.parse_lifter_lines('') == ([], []) assert pa_lifters.parse_lifter_lines(None) == ([], []) assert pa_lifters.parse_lifter_lines(' \n \n') == ([], []) def test_parse_lifter_lines_refuses_the_whole_field_on_one_bad_line(): text = '2.50 @ 0.25\nnot a lifter line\n10.00 @ 0.50' rows, problems = pa_lifters.parse_lifter_lines(text) assert rows == [] assert len(problems) == 1 assert 'line 2' in problems[0] def test_parse_lifter_lines_bad_numbers_named_by_line(): rows, problems = pa_lifters.parse_lifter_lines('abc @ 0.25') assert rows == [] assert 'line 1' in problems[0] and 'x_ft' in problems[0] rows, problems = pa_lifters.parse_lifter_lines('2.5 @ xyz') assert rows == [] assert 'line 1' in problems[0] and 'frac' in problems[0]