diff --git a/.Jules/palette.md b/.Jules/palette.md index 96bd45d..e0a5f9e 100644 --- a/.Jules/palette.md +++ b/.Jules/palette.md @@ -5,3 +5,7 @@ ## 2025-02-28 - Structured CLI Reports **Learning:** Dense numerical data in CLI output is hard to parse. Using ASCII box-drawing characters and alignment to create a "dashboard" or "invoice" style summary significantly improves readability and perceived quality. **Action:** When summarizing simulation or batch job results, always format the final report as a structured table or box rather than a list of print statements. + +## 2025-06-15 - CLI Input Hygiene +**Learning:** Default validation errors (stack traces, unhandled exceptions) break the "tool" illusion and feel amateur. Friendly, upfront validation with color-coded errors (e.g. "Error: Days must be positive") establishes trust and guides the user. +**Action:** Always validate CLI arguments explicitly before execution and use `sys.exit(1)` with a clear message. diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml deleted file mode 100644 index 9fd45e0..0000000 --- a/.github/workflows/rust.yml +++ /dev/null @@ -1,22 +0,0 @@ -name: Rust - -on: - push: - branches: [ "main" ] - pull_request: - branches: [ "main" ] - -env: - CARGO_TERM_COLOR: always - -jobs: - build: - - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v4 - - name: Build - run: cargo build --verbose - - name: Run tests - run: cargo test --verbose diff --git a/bitcoin_trading_simulation.py b/bitcoin_trading_simulation.py index cb07d20..d54bf40 100644 --- a/bitcoin_trading_simulation.py +++ b/bitcoin_trading_simulation.py @@ -142,6 +142,20 @@ def countdown(quiet=False): if args.no_color: Colors.disable() + # Input validation + if args.days <= 0: + print(f"{Colors.FAIL}Error: Days must be a positive integer.{Colors.ENDC}", file=sys.stderr) + sys.exit(1) + if args.initial_cash <= 0: + print(f"{Colors.FAIL}Error: Initial cash must be positive.{Colors.ENDC}", file=sys.stderr) + sys.exit(1) + if args.initial_price <= 0: + print(f"{Colors.FAIL}Error: Initial price must be positive.{Colors.ENDC}", file=sys.stderr) + sys.exit(1) + if args.volatility < 0: + print(f"{Colors.FAIL}Error: Volatility must be non-negative.{Colors.ENDC}", file=sys.stderr) + sys.exit(1) + # Simulate prices prices = simulate_bitcoin_prices(days=args.days, initial_price=args.initial_price, volatility=args.volatility) diff --git a/test_cli_args.py b/test_cli_args.py new file mode 100644 index 0000000..f7226ef --- /dev/null +++ b/test_cli_args.py @@ -0,0 +1,33 @@ +import subprocess +import sys +import pytest + +def run_simulation(args): + """Runs the simulation script with the given arguments.""" + cmd = [sys.executable, "bitcoin_trading_simulation.py"] + args + return subprocess.run(cmd, capture_output=True, text=True) + +def test_invalid_days(): + result = run_simulation(["--days", "-5"]) + assert result.returncode != 0, "Simulation should fail with negative days" + assert "days must be a positive integer" in result.stderr.lower() or "days must be a positive integer" in result.stdout.lower() + +def test_invalid_initial_cash(): + result = run_simulation(["--initial-cash", "-1000"]) + assert result.returncode != 0, "Simulation should fail with negative cash" + assert "initial cash must be positive" in result.stderr.lower() or "initial cash must be positive" in result.stdout.lower() + +def test_invalid_initial_price(): + result = run_simulation(["--initial-price", "-500"]) + assert result.returncode != 0, "Simulation should fail with negative price" + assert "initial price must be positive" in result.stderr.lower() or "initial price must be positive" in result.stdout.lower() + +def test_invalid_volatility(): + result = run_simulation(["--volatility", "-0.1"]) + assert result.returncode != 0, "Simulation should fail with negative volatility" + assert "volatility must be non-negative" in result.stderr.lower() or "volatility must be non-negative" in result.stdout.lower() + +def test_valid_run(): + # Run with quiet mode to speed up test + result = run_simulation(["--days", "10", "--quiet"]) + assert result.returncode == 0, "Valid simulation should succeed"