#!/usr/bin/env python3 """ Tests for cli/upload_skill.py functionality """ import os import tempfile import unittest import zipfile from pathlib import Path from skill_seekers.cli.upload_skill import upload_skill_api class TestUploadSkillAPI(unittest.TestCase): """Test upload_skill_api function""" def setUp(self): """Store original API key state""" self.original_api_key = os.environ.get("ANTHROPIC_API_KEY") def tearDown(self): """Restore original API key state""" if self.original_api_key: os.environ["ANTHROPIC_API_KEY"] = self.original_api_key elif "ANTHROPIC_API_KEY" in os.environ: del os.environ["ANTHROPIC_API_KEY"] def create_test_zip(self, tmpdir): """Helper to create a test .zip file""" zip_path = Path(tmpdir) / "test-skill.zip" with zipfile.ZipFile(zip_path, "w") as zf: zf.writestr("SKILL.md", "---\nname: test\n---\n# Test Skill") zf.writestr("references/index.md", "# Index") return zip_path def test_upload_without_api_key(self): """Test that upload fails gracefully without API key""" # Remove API key if "ANTHROPIC_API_KEY" in os.environ: del os.environ["ANTHROPIC_API_KEY"] with tempfile.TemporaryDirectory() as tmpdir: zip_path = self.create_test_zip(tmpdir) success, message = upload_skill_api(zip_path) self.assertFalse(success) # Check for api_key (with underscore) in message self.assertTrue("api_key" in message.lower() or "api key" in message.lower()) def test_upload_with_nonexistent_file(self): """Test upload with nonexistent file""" os.environ["ANTHROPIC_API_KEY"] = "sk-ant-test-key" success, message = upload_skill_api("/nonexistent/file.zip") self.assertFalse(success) self.assertIn("not found", message.lower()) def test_upload_with_invalid_zip(self): """Test upload with invalid zip file (not a zip)""" os.environ["ANTHROPIC_API_KEY"] = "sk-ant-test-key" with tempfile.NamedTemporaryFile(suffix=".zip", delete=False) as tmpfile: tmpfile.write(b"Not a valid zip file") tmpfile.flush() try: success, message = upload_skill_api(tmpfile.name) # Should either fail validation or detect invalid zip self.assertFalse(success) finally: os.unlink(tmpfile.name) def test_upload_accepts_path_object(self): """Test that upload_skill_api accepts Path objects""" os.environ["ANTHROPIC_API_KEY"] = "sk-ant-test-key" with tempfile.TemporaryDirectory() as tmpdir: zip_path = self.create_test_zip(tmpdir) # This should not raise TypeError try: success, message = upload_skill_api(Path(zip_path)) except TypeError: self.fail("upload_skill_api should accept Path objects") class TestUploadSkillCLI(unittest.TestCase): """Test upload_skill.py command-line interface""" def test_cli_help_output(self): """Test that skill-seekers upload --help works""" import subprocess try: result = subprocess.run( ["skill-seekers", "upload", "--help"], capture_output=True, text=True, timeout=5 ) # argparse may return 0 or 2 for --help self.assertIn(result.returncode, [0, 2]) output = result.stdout + result.stderr self.assertTrue("usage:" in output.lower() or "upload" in output.lower()) except FileNotFoundError: self.skipTest("skill-seekers command not installed") def test_cli_executes_without_errors(self): """Test that skill-seekers-upload entry point works""" import subprocess try: result = subprocess.run( ["skill-seekers-upload", "--help"], capture_output=True, text=True, timeout=5 ) # argparse may return 0 or 2 for --help self.assertIn(result.returncode, [0, 2]) except FileNotFoundError: self.skipTest("skill-seekers-upload command not installed") def test_cli_requires_zip_argument(self): """Test that CLI requires zip file argument""" import subprocess result = subprocess.run(["python3", "cli/upload_skill.py"], capture_output=True, text=True) # Should fail or show usage self.assertTrue( result.returncode != 0 or "usage" in result.stderr.lower() or "usage" in result.stdout.lower() ) if __name__ == "__main__": unittest.main()