tweak the fit of the parts
This commit is contained in:
@@ -80,6 +80,35 @@ class ConfigTest < Minitest::Test
|
||||
assert_in_delta 95.6, subject.dimensions["length"], 0.01
|
||||
end
|
||||
|
||||
def test_insert_defaults_match_selected_hardware
|
||||
parameters = config.parameters
|
||||
|
||||
assert_in_delta 4.0, parameters["m25_insert_length"], 0.001
|
||||
assert_in_delta 3.1, parameters["m25_insert_hole_diameter"], 0.001
|
||||
assert_in_delta 3.5, parameters["m25_insert_outer_diameter"], 0.001
|
||||
assert_in_delta 5.0, parameters["tripod_insert_length"], 0.001
|
||||
assert_in_delta 7.2, parameters["tripod_insert_hole_diameter"], 0.001
|
||||
assert_in_delta 8.0, parameters["tripod_insert_outer_diameter"], 0.001
|
||||
end
|
||||
|
||||
def test_tripod_floor_tracks_insert_length
|
||||
subject = config
|
||||
subject.parameters["tripod_insert_enabled"] = true
|
||||
|
||||
assert_in_delta 7.0, subject.dimensions["floor"], 0.001
|
||||
end
|
||||
|
||||
def test_insert_coupon_uses_finished_pilot_ranges
|
||||
source = FeatherCaseWizard::MODEL_SOURCE.read
|
||||
|
||||
assert_includes source,
|
||||
"m25_coupon_steps = [-0.15, -0.075, 0, 0.075, 0.15];"
|
||||
assert_includes source,
|
||||
"tripod_coupon_steps = [-0.3, -0.15, 0, 0.15, 0.3];"
|
||||
assert_includes source, "bore_d = diameter;"
|
||||
refute_includes source, "bore_d = diameter + hole_compensation;"
|
||||
end
|
||||
|
||||
def test_oled_buttons_and_selected_coupons_are_printable
|
||||
subject = config
|
||||
subject.parameters["top_profile"] = "oled128x64"
|
||||
@@ -90,6 +119,71 @@ class ConfigTest < Minitest::Test
|
||||
assert_equal %w[body lid buttons fit_coupon], subject.printable_parts
|
||||
end
|
||||
|
||||
def test_combined_battery_and_tripod_case_adds_partition_clearance
|
||||
subject = config
|
||||
subject.parameters["battery_enabled"] = true
|
||||
subject.parameters["tripod_insert_enabled"] = true
|
||||
|
||||
assert_in_delta 88.6, subject.dimensions["length"], 0.01
|
||||
assert_in_delta 59.06, subject.dimensions["width"], 0.01
|
||||
assert_in_delta 31.25, subject.dimensions["height"], 0.01
|
||||
end
|
||||
|
||||
def test_legacy_round_switch_fields_migrate_to_rocker_defaults
|
||||
data = config.data
|
||||
data["parameters"]["switch_hole_diameter"] = 12.0
|
||||
data["parameters"]["switch_body_length"] = 24.0
|
||||
|
||||
subject = FeatherCaseWizard::Config.new(data)
|
||||
|
||||
refute subject.parameters.key?("switch_hole_diameter")
|
||||
refute subject.parameters.key?("switch_body_length")
|
||||
assert_equal [12.9, 19.4], subject.parameters["rocker_cutout_size"]
|
||||
assert_equal [15.0, 21.0, 21.0], subject.parameters["rocker_body_size"]
|
||||
end
|
||||
|
||||
def test_battery_partition_requires_three_06_mm_lines
|
||||
subject = config
|
||||
subject.parameters["battery_partition_thickness"] = 1.19
|
||||
|
||||
error = assert_raises(FeatherCaseWizard::ConfigError) { subject.validate! }
|
||||
assert_match(/battery_partition_thickness/, error.message)
|
||||
end
|
||||
|
||||
def test_insert_entry_cannot_be_smaller_than_pilot
|
||||
subject = config
|
||||
subject.parameters["m25_insert_outer_diameter"] = 3.0
|
||||
|
||||
error = assert_raises(FeatherCaseWizard::ConfigError) { subject.validate! }
|
||||
assert_match(/m25_insert_outer_diameter/, error.message)
|
||||
end
|
||||
|
||||
def test_lid_artwork_adds_base_and_accent_parts
|
||||
subject = config
|
||||
subject.parameters["lid_label"] = "GPS"
|
||||
subject.parameters["lid_logo_enabled"] = true
|
||||
|
||||
assert subject.lid_artwork?
|
||||
assert_equal %w[body lid lid_base lid_accent], subject.printable_parts
|
||||
end
|
||||
|
||||
def test_lid_artwork_rejects_oled_profile
|
||||
subject = config
|
||||
subject.parameters["top_profile"] = "oled128x64"
|
||||
subject.parameters["lid_label"] = "OLED"
|
||||
|
||||
error = assert_raises(FeatherCaseWizard::ConfigError) { subject.validate! }
|
||||
assert_match(/not supported with the OLED profile/, error.message)
|
||||
end
|
||||
|
||||
def test_lid_artwork_orientation_is_named
|
||||
subject = config
|
||||
subject.parameters["lid_art_orientation"] = "diagonal"
|
||||
|
||||
error = assert_raises(FeatherCaseWizard::ConfigError) { subject.validate! }
|
||||
assert_match(/orientation/, error.message)
|
||||
end
|
||||
|
||||
def test_wall_local_cutouts_map_to_model_coordinates
|
||||
subject = config
|
||||
length = subject.dimensions["length"]
|
||||
|
||||
@@ -68,6 +68,30 @@ class PackageBuilderTest < Minitest::Test
|
||||
end
|
||||
end
|
||||
|
||||
def test_builds_aligned_multicolor_lid_package_when_artwork_is_enabled
|
||||
Dir.mktmpdir do |directory|
|
||||
root = Pathname(directory)
|
||||
tools = create_fake_tools(root)
|
||||
model = root.join("model.scad")
|
||||
renderer = root.join("renderer.py")
|
||||
File.write(model, "cube([1,1,1]);\n")
|
||||
File.write(renderer, "# test renderer\n")
|
||||
config = FeatherCaseWizard::Config.create(name: "IMU", slug: "imu")
|
||||
config.parameters["lid_label"] = "IMU"
|
||||
config.parameters["lid_logo_enabled"] = true
|
||||
|
||||
destination = build(config, root.join("cases"), tools, model, renderer)
|
||||
|
||||
%w[lid lid_base lid_accent].each do |part|
|
||||
assert destination.join("exports/3mf/#{part}.3mf").file?
|
||||
end
|
||||
assert destination.join("exports/3mf/lid_multicolor.3mf").file?
|
||||
assert destination.join("source/assets/NME-fixed.svg").file?
|
||||
assert destination.join("tools/package_multimaterial_3mf.py").file?
|
||||
assert destination.join("previews/lid_multicolor_top.png").file?
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def build(config, root, tools, model, renderer)
|
||||
@@ -93,14 +117,26 @@ class PackageBuilderTest < Minitest::Test
|
||||
#!/usr/bin/env ruby
|
||||
require "fileutils"
|
||||
args = ARGV[(ARGV.index("--") + 1)..]
|
||||
_mesh, output, basename, selected = args
|
||||
views = selected ? selected.split(",") : %w[iso front back left right top]
|
||||
multicolor = ARGV[ARGV.index("--python") + 1].include?("render_multicolor")
|
||||
if multicolor
|
||||
_base, _accent, output, basename = args
|
||||
views = %w[iso top]
|
||||
else
|
||||
_mesh, output, basename, selected = args
|
||||
views = selected ? selected.split(",") : %w[iso front back left right top]
|
||||
end
|
||||
FileUtils.mkdir_p(output)
|
||||
views.each { |view| File.binwrite(File.join(output, "\#{basename}_\#{view}.png"), "png") }
|
||||
RUBY
|
||||
FileUtils.chmod(0o755, [openscad, blender])
|
||||
python = bin.join("python3")
|
||||
File.write(python, <<~RUBY)
|
||||
#!/usr/bin/env ruby
|
||||
File.binwrite(ARGV[3], "multipart")
|
||||
RUBY
|
||||
FileUtils.chmod(0o755, [openscad, blender, python])
|
||||
FeatherCaseWizard::Toolchain.new(
|
||||
env: {"PATH" => bin.to_s, "OPENSCAD" => openscad.to_s, "BLENDER" => blender.to_s}
|
||||
env: {"PATH" => bin.to_s, "OPENSCAD" => openscad.to_s,
|
||||
"BLENDER" => blender.to_s, "PYTHON" => python.to_s}
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -9,6 +9,7 @@ class ToolchainTest < Minitest::Test
|
||||
|
||||
assert_match(/OpenSCAD/, error.message)
|
||||
assert_match(/Blender/, error.message)
|
||||
assert_match(/Python 3/, error.message)
|
||||
assert_match(/apt-get/, error.message)
|
||||
end
|
||||
|
||||
@@ -18,13 +19,14 @@ class ToolchainTest < Minitest::Test
|
||||
File.write(executable, "#!/bin/sh\nexit 0\n")
|
||||
FileUtils.chmod(0o755, executable)
|
||||
toolchain = FeatherCaseWizard::Toolchain.new(
|
||||
env: {"PATH" => "", "OPENSCAD" => executable, "BLENDER" => executable}
|
||||
env: {"PATH" => "", "OPENSCAD" => executable, "BLENDER" => executable,
|
||||
"PYTHON" => executable}
|
||||
)
|
||||
|
||||
assert_equal executable, toolchain.openscad
|
||||
assert_equal executable, toolchain.blender
|
||||
assert_equal executable, toolchain.python
|
||||
assert_same toolchain, toolchain.check!
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
+4
-4
@@ -6,8 +6,8 @@ require_relative "test_helper"
|
||||
class WizardTest < Minitest::Test
|
||||
def test_minimal_new_case_flow_and_confirmation
|
||||
input = StringIO.new(
|
||||
["Demo Case", "", "1", "1", "", "n", "n", "", "", "n", "n", "1",
|
||||
"n", "n", "n", "n", "y"].join("\n") + "\n"
|
||||
["Demo Case", "", "1", "1", "", "n", "n", "", "", "n", "n", "n", "n",
|
||||
"1", "n", "n", "n", "n", "y"].join("\n") + "\n"
|
||||
)
|
||||
output = StringIO.new
|
||||
wizard = FeatherCaseWizard::Wizard.new(ui: HighLine.new(input, output))
|
||||
@@ -24,8 +24,8 @@ class WizardTest < Minitest::Test
|
||||
config = FeatherCaseWizard::Config.create(name: "GPS", slug: "gps")
|
||||
config.parameters["top_profile"] = "gps"
|
||||
input = StringIO.new(
|
||||
["", "", "", "", "n", "n", "", "", "n", "n", "1", "n", "n", "n",
|
||||
"n"].join("\n") + "\n"
|
||||
["", "", "", "", "n", "n", "", "", "n", "n", "n", "n", "1", "n",
|
||||
"n", "n", "n"].join("\n") + "\n"
|
||||
)
|
||||
wizard = FeatherCaseWizard::Wizard.new(ui: HighLine.new(input, StringIO.new))
|
||||
|
||||
|
||||
Reference in New Issue
Block a user