"""Tests for the cut list / board-feet / shopping estimate.""" import pytest from woodshop.cutlist import board_feet, cut_rows, nominal_dims, shopping from woodshop.scene import Scene def test_nominal_dims(): assert nominal_dims("2x4") == (2.0, 4.0) assert nominal_dims("4x4") == (4.0, 4.0) def test_board_feet_uses_nominal(): # 2x4 at 96in = (2*4*96)/144 = 5.333 bd-ft assert board_feet("2x4", 96) == pytest.approx(5.3333, abs=1e-3) def test_cut_rows_groups_and_counts(): s = Scene() s.place("2x4", 48) s.place("2x4", 48) s.place("2x4", 29) rows = cut_rows(s) by_len = {r["length_in"]: r for r in rows} assert by_len[48.0]["count"] == 2 assert by_len[29.0]["count"] == 1 assert by_len[48.0]["board_feet"] == pytest.approx(board_feet("2x4", 48) * 2) def test_shopping_rounds_up_with_waste(): s = Scene() s.place("2x4", 48) s.place("2x4", 48) # 96in total -> with 10% waste = 105.6 -> 2 sticks of 96in assert shopping(s) == {"2x4": 2} def test_empty_shopping(): assert shopping(Scene()) == {} def test_end_tenon_extends_cut_length(): from woodshop.cutlist import cut_length s = Scene() s.place("2x4", 24) assert cut_length(s.get_part("p1")) == 24 s.add_feature("p1", "tenon", face="end_b", depth_in=1.5) # protrudes 1.5" assert cut_length(s.get_part("p1")) == 25.5 # the cut row and board-feet reflect the longer piece assert cut_rows(s)[0]["length_in"] == 25.5 assert cut_rows(s)[0]["board_feet"] == pytest.approx(board_feet("2x4", 25.5)) def test_plywood_uses_sqft_and_sheets(): from woodshop.cutlist import cut_rows, shopping, format_cutlist s = Scene() s.place("ply-3/4", 48, width_in=24) # 48 × 24 = 8 sq ft row = cut_rows(s)[0] assert row["plywood"] and row["sq_ft"] == pytest.approx(8.0) assert shopping(s)["ply-3/4"] == 1 # well under a 32 sq-ft sheet assert "sq ft" in format_cutlist(s) and "sheet" in format_cutlist(s) def test_cut_feature_does_not_change_cut_length(): from woodshop.cutlist import cut_length s = Scene() s.place("2x4", 24) s.add_feature("p1", "mortise", face="top", width_in=1, height_in=1, depth_in=0.5) assert cut_length(s.get_part("p1")) == 24 # cuts don't reduce stock you buy