# frozen_string_literal: true require_relative 'test_helper' # ─── Enable ─────────────────────────────────────────────────────────────────── class TestEnable < Minitest::Test include TestHelpers def setup setup_temp_dirs end def teardown teardown_temp_dirs end def test_enable_new_plugin_creates_file_and_adds_entry op = make_operation(PluginConfig::Operations::Enable) result = op.call assert_includes %w[created_and_enabled enabled], result[:status] assert_equal 'test-plugin@test-marketplace', result[:plugin] assert result[:verified], 'Expected verified to be true' assert_includes result[:enabled_plugins], 'test-plugin@test-marketplace' end def test_enable_adds_to_existing_settings create_settings('other-plugin@other-marketplace' => true) op = make_operation(PluginConfig::Operations::Enable) result = op.call assert_equal 'enabled', result[:status] assert_includes result[:enabled_plugins], 'other-plugin@other-marketplace' assert_includes result[:enabled_plugins], 'test-plugin@test-marketplace' end def test_enable_already_enabled_returns_already_enabled create_settings('test-plugin@test-marketplace' => true) op = make_operation(PluginConfig::Operations::Enable) result = op.call assert_equal 'already_enabled', result[:status] assert result[:verified] end def test_enabled_plugins_sorted_alphabetically create_settings('z-plugin@z-marketplace' => true, 'a-plugin@a-marketplace' => true) op = make_operation(PluginConfig::Operations::Enable) result = op.call expected = ['a-plugin@a-marketplace', 'test-plugin@test-marketplace', 'z-plugin@z-marketplace'] assert_equal expected, result[:enabled_plugins] end def test_verified_flag_is_true_on_success op = make_operation(PluginConfig::Operations::Enable) result = op.call assert result[:verified] end end # ─── Disable ────────────────────────────────────────────────────────────────── class TestDisable < Minitest::Test include TestHelpers def setup setup_temp_dirs end def teardown teardown_temp_dirs end def test_disable_existing_plugin_removes_entry create_settings('test-plugin@test-marketplace' => true) op = make_operation(PluginConfig::Operations::Disable) result = op.call assert_equal 'disabled', result[:status] refute_includes result[:remaining_plugins], 'test-plugin@test-marketplace' end def test_disable_nonexistent_plugin_returns_not_found create_settings({}) op = make_operation(PluginConfig::Operations::Disable) result = op.call assert_equal 'not_found', result[:status] end def test_disable_preserves_other_plugins create_settings( 'test-plugin@test-marketplace' => true, 'keep-me@other' => true ) op = make_operation(PluginConfig::Operations::Disable) result = op.call assert_equal 'disabled', result[:status] assert_includes result[:remaining_plugins], 'keep-me@other' refute_includes result[:remaining_plugins], 'test-plugin@test-marketplace' end def test_verified_flag_confirms_key_absent create_settings('test-plugin@test-marketplace' => true) op = make_operation(PluginConfig::Operations::Disable) result = op.call assert result[:verified] end end # ─── Register ───────────────────────────────────────────────────────────────── class TestRegister < Minitest::Test include TestHelpers def setup setup_temp_dirs end def teardown teardown_temp_dirs end def test_register_new_plugin_adds_to_marketplace create_marketplace(plugins: []) op = make_operation(PluginConfig::Operations::Register, description: 'A test plugin') result = op.call assert_equal 'registered', result[:status] assert result[:verified] data = JSON.parse(File.read(marketplace_path)) names = data['plugins'].map { |p| p['name'] } assert_includes names, 'test-plugin' end def test_register_already_present_returns_already_registered create_marketplace(plugins: [{ 'name' => 'test-plugin', 'source' => './test-plugin', 'description' => '' }]) op = make_operation(PluginConfig::Operations::Register) result = op.call assert_equal 'already_registered', result[:status] assert result[:verified] end def test_plugins_array_sorted_by_name create_marketplace(plugins: [{ 'name' => 'z-plugin', 'source' => './z-plugin', 'description' => '' }]) op = make_operation(PluginConfig::Operations::Register, plugin: 'a-plugin') result = op.call data = JSON.parse(File.read(marketplace_path)) names = data['plugins'].map { |p| p['name'] } assert_equal %w[a-plugin z-plugin], names end def test_description_is_stored_correctly create_marketplace(plugins: []) op = make_operation(PluginConfig::Operations::Register, description: 'My description') result = op.call data = JSON.parse(File.read(marketplace_path)) plugin_entry = data['plugins'].find { |p| p['name'] == 'test-plugin' } assert_equal 'My description', plugin_entry['description'] end end # ─── Unregister ─────────────────────────────────────────────────────────────── class TestUnregister < Minitest::Test include TestHelpers def setup setup_temp_dirs end def teardown teardown_temp_dirs end def test_unregister_existing_plugin create_marketplace(plugins: [{ 'name' => 'test-plugin', 'source' => './test-plugin', 'description' => '' }]) op = make_operation(PluginConfig::Operations::Unregister) result = op.call assert_equal 'unregistered', result[:status] assert result[:verified] data = JSON.parse(File.read(marketplace_path)) names = data['plugins'].map { |p| p['name'] } refute_includes names, 'test-plugin' end def test_unregister_nonexistent_returns_not_found create_marketplace(plugins: []) op = make_operation(PluginConfig::Operations::Unregister) result = op.call assert_equal 'not_found', result[:status] end def test_unregister_preserves_other_plugins create_marketplace(plugins: [ { 'name' => 'keep-me', 'source' => './keep-me', 'description' => '' }, { 'name' => 'test-plugin', 'source' => './test-plugin', 'description' => '' } ]) op = make_operation(PluginConfig::Operations::Unregister) result = op.call data = JSON.parse(File.read(marketplace_path)) names = data['plugins'].map { |p| p['name'] } assert_includes names, 'keep-me' refute_includes names, 'test-plugin' end end # ─── Audit ──────────────────────────────────────────────────────────────────── class TestAudit < Minitest::Test include TestHelpers def setup setup_temp_dirs # Create installed_plugins in temp location; override the path @installed_path = File.join(@tmpdir, 'installed_plugins.json') end def teardown teardown_temp_dirs end def test_clean_state_returns_ok # Create all required files with correct entries create_marketplace(plugins: [{ 'name' => 'test-plugin', 'source' => './test-plugin', 'description' => '' }]) create_settings('test-plugin@test-marketplace' => true) # Need to stub installed_plugins_path - create a subclass op = make_audit_op_with_installed({ 'test-plugin@test-marketplace' => { 'status' => 'enabled' } }) result = op.call assert_equal 'ok', result[:status] assert_empty result[:issues] end def test_missing_marketplace_entry_reports_issue_with_fix create_marketplace(plugins: []) # plugin not registered create_settings('test-plugin@test-marketplace' => true) op = make_audit_op_with_installed({ 'test-plugin@test-marketplace' => { 'status' => 'enabled' } }) result = op.call assert_equal 'issues_found', result[:status] marketplace_check = result[:checks][:marketplace] assert_equal 'issue', marketplace_check[:status] assert marketplace_check[:fix] end def test_missing_settings_entry_reports_issue_with_fix create_marketplace(plugins: [{ 'name' => 'test-plugin', 'source' => './test-plugin', 'description' => '' }]) create_settings({}) # plugin not enabled op = make_audit_op_with_installed({ 'test-plugin@test-marketplace' => { 'status' => 'enabled' } }) result = op.call assert_equal 'issues_found', result[:status] settings_check = result[:checks][:settings] assert_equal 'issue', settings_check[:status] assert settings_check[:fix] end def test_multiple_issues_all_reported create_marketplace(plugins: []) # not registered create_settings({}) # not enabled op = make_audit_op_with_installed({}) # not installed result = op.call assert_equal 'issues_found', result[:status] assert result[:issues].length >= 2, "Expected at least 2 issues, got #{result[:issues].length}" end private # Create an Audit subclass that overrides installed_plugins_path to use temp dir def make_audit_op_with_installed(installed_plugins) installed_path = @installed_path create_installed_plugins(installed_path, installed_plugins) params = { plugin: 'test-plugin', marketplace: 'test-marketplace', project: @project_dir, marketplace_file: marketplace_path } op = PluginConfig::Operations::Audit.new(params) # Override the installed_plugins_path method op.define_singleton_method(:installed_plugins_path) { installed_path } op end end # ─── List ───────────────────────────────────────────────────────────────────── class TestList < Minitest::Test include TestHelpers def setup setup_temp_dirs end def teardown teardown_temp_dirs end def test_list_returns_all_enabled_plugins create_settings( 'b-plugin@marketplace' => true, 'a-plugin@marketplace' => true ) op = make_operation(PluginConfig::Operations::List) result = op.call assert_equal 'ok', result[:status] assert_equal %w[a-plugin@marketplace b-plugin@marketplace], result[:enabled_plugins] assert_equal 2, result[:count] end def test_list_empty_settings_returns_empty_array create_settings({}) op = make_operation(PluginConfig::Operations::List) result = op.call assert_equal 'ok', result[:status] assert_empty result[:enabled_plugins] assert_equal 0, result[:count] end def test_list_missing_file_returns_empty_array # Don't create settings file op = make_operation(PluginConfig::Operations::List) result = op.call assert_equal 'ok', result[:status] assert_empty result[:enabled_plugins] assert_equal 0, result[:count] end end