# frozen_string_literal: true require "test_helper" class GeneratorTest < Minitest::Test def test_one_piece_multicolor_package Dir.mktmpdir do |dir| data = MoonModel::DataSet.new(make_data(File.join(dir, "data.gz"))) config = MoonModel::Config.new( "size" => { "value" => 40 }, "resolution" => { "longitude_segments" => 24 }, "palette" => [{ "name" => "dark", "hex" => "#222222" }, { "name" => "light", "hex" => "#DDDDDD" }], "grid" => { "enabled" => true, "color_name" => "light" }, "output" => { "name" => "test" } ) result = MoonModel::Generator.new(config, data_set: data, output_dir: File.join(dir, "out")).generate path = File.join(result[:output_dir], "moon.3mf") assert File.file?(path) Zip::File.open(path) do |zip| model = zip.read("3D/3dmodel.model") assert_includes model, "" end assert File.file?(File.join(result[:output_dir], "manifest.md")) assert_in_delta 40.0, result[:statistics]["final_envelope_mm"], 0.01 end end def test_segmented_box_outputs_parts_keys_and_stand Dir.mktmpdir do |dir| data = MoonModel::DataSet.new(make_data(File.join(dir, "data.gz"))) config = MoonModel::Config.new("purpose" => "box", "size" => { "value" => 50 }, "stand" => { "enabled" => true }, "resolution" => { "longitude_segments" => 24 }) result = MoonModel::Generator.new(config, data_set: data, output_dir: File.join(dir, "out")).generate assert_equal 8, Dir[File.join(result[:output_dir], "north_*.3mf")].length + Dir[File.join(result[:output_dir], "south_*.3mf")].length assert File.file?(File.join(result[:output_dir], "assembly_keys.3mf")) assert File.file?(File.join(result[:output_dir], "orbital_triskelion_stand.3mf")) manifest = File.read(File.join(result[:output_dir], "manifest.md")) assert_includes manifest, "Stand style: Orbital triskelion" assert_includes manifest, "Terrain envelope v2 (rotation independent)" assert_includes manifest, "Guaranteed Moon clearance above hub/base: 10.00 mm" assert_includes manifest, "Stand dimensions:" end end def test_invalid_preflight_does_not_create_output_directory Dir.mktmpdir do |dir| data = MoonModel::DataSet.new(make_data(File.join(dir, "data.gz"))) config = MoonModel::Config.new("size" => { "value" => 40, "meaning" => "datum" }, "vertical_exaggeration" => 100_000, "resolution" => { "longitude_segments" => 24 }) output = File.join(dir, "out") assert_raises(ArgumentError) { MoonModel::Generator.new(config, data_set: data, output_dir: output).generate } refute Dir.exist?(output) end end def test_revision_atomically_replaces_obsolete_files Dir.mktmpdir do |dir| data = MoonModel::DataSet.new(make_data(File.join(dir, "data.gz"))) output = File.join(dir, "named_moon") common = { "size" => { "value" => 40 }, "resolution" => { "longitude_segments" => 24 }, "output" => { "name" => "Named Moon" } } MoonModel::Generator.new(MoonModel::Config.new(common), data_set: data, output_dir: output).generate assert File.file?(File.join(output, "moon.3mf")) revised = MoonModel::Config.new(common.merge("assembly" => "eight_piece")) MoonModel::Generator.new(revised, data_set: data, output_dir: output).generate refute File.exist?(File.join(output, "moon.3mf")) assert File.file?(File.join(output, "north_1.3mf")) assert MoonModel::Generator.generated_directory?(output) end end def test_refuses_to_replace_unrelated_directory Dir.mktmpdir do |dir| output = File.join(dir, "not_a_model") Dir.mkdir(output) File.write(File.join(output, "keep.txt"), "important") data = MoonModel::DataSet.new(make_data(File.join(dir, "data.gz"))) config = MoonModel::Config.new("size" => { "value" => 40 }, "resolution" => { "longitude_segments" => 24 }) assert_raises(ArgumentError) { MoonModel::Generator.new(config, data_set: data, output_dir: output).generate } assert_equal "important", File.read(File.join(output, "keep.txt")) end end def test_failed_atomic_install_restores_previous_model Dir.mktmpdir do |dir| data = MoonModel::DataSet.new(make_data(File.join(dir, "data.gz"))) output = File.join(dir, "recoverable") common = { "size" => { "value" => 40 }, "resolution" => { "longitude_segments" => 24 }, "output" => { "name" => "Recoverable" } } MoonModel::Generator.new(MoonModel::Config.new(common), data_set: data, output_dir: output).generate original = File.binread(File.join(output, "moon.3mf")) failing_class = Class.new(MoonModel::Generator) do private def rename_path(from, to) @rename_count = @rename_count.to_i + 1 raise IOError, "simulated install failure" if @rename_count == 2 super end end error = assert_raises(IOError) do failing_class.new(MoonModel::Config.new(common.merge("assembly" => "eight_piece")), data_set: data, output_dir: output).generate end assert_equal "simulated install failure", error.message assert_equal original, File.binread(File.join(output, "moon.3mf")) assert_empty Dir[File.join(dir, ".recoverable.*")] end end def test_safe_model_name_and_default_build_directory config = MoonModel::Config.new("output" => { "name" => "My 8-inch Moon!" }) generator = MoonModel::Generator.new(config) assert_equal "My_8-inch_Moon", MoonModel::Generator.safe_name("My 8-inch Moon!") assert_equal File.expand_path("../build/My_8-inch_Moon", __dir__), generator.output_dir assert_raises(ArgumentError) { MoonModel::Generator.safe_name("...") } end end