From 02e858eab7387cc511f7770c8af32b592fc69b5f Mon Sep 17 00:00:00 2001 From: xyaz1313 Date: Wed, 15 Apr 2026 20:52:38 +0800 Subject: [PATCH] Fix: Handle missing config file gracefully The app previously crashed with a FileNotFoundError when ~/.config/task-cli/config.yaml did not exist. Changes: - load_config() now creates a default config file if missing - Added DEFAULT_CONFIG constant with sensible defaults - Integrated load_config() call into main() - Added 3 test cases for the fix Fixes #2 --- task.py | 31 ++++++++++++++++++++++++++++--- test_task.py | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+), 3 deletions(-) diff --git a/task.py b/task.py index 53cc8ed..a122322 100644 --- a/task.py +++ b/task.py @@ -10,10 +10,32 @@ from commands.done import mark_done +DEFAULT_CONFIG = """# Task storage settings +storage: + format: json + max_tasks: 1000 + +# Display settings +display: + color: true + unicode: true +""" + + def load_config(): - """Load configuration from file.""" - config_path = Path.home() / ".config" / "task-cli" / "config.yaml" - # NOTE: This will crash if config doesn't exist - known bug for bounty testing + """Load configuration from file. + + Creates a default config if the file doesn't exist. + Returns the config content as a string. + """ + config_dir = Path.home() / ".config" / "task-cli" + config_path = config_dir / "config.yaml" + + if not config_path.exists(): + config_dir.mkdir(parents=True, exist_ok=True) + config_path.write_text(DEFAULT_CONFIG) + print(f"Created default config at {config_path}") + with open(config_path) as f: return f.read() @@ -35,6 +57,9 @@ def main(): args = parser.parse_args() + # Load config (creates default if missing) + load_config() + if args.command == "add": add_task(args.description) elif args.command == "list": diff --git a/test_task.py b/test_task.py index ba98e43..f1f7fc7 100644 --- a/test_task.py +++ b/test_task.py @@ -1,10 +1,15 @@ """Basic tests for task CLI.""" import json +import os +import shutil +import tempfile + import pytest from pathlib import Path from commands.add import add_task, validate_description from commands.done import validate_task_id +from task import load_config, DEFAULT_CONFIG def test_validate_description(): @@ -28,3 +33,34 @@ def test_validate_task_id(): with pytest.raises(ValueError): validate_task_id(tasks, 99) + + +def test_load_config_creates_default_when_missing(tmp_path, monkeypatch): + """Test that load_config creates default config when file is missing.""" + monkeypatch.setattr(Path, "home", lambda: tmp_path) + + config = load_config() + + config_path = tmp_path / ".config" / "task-cli" / "config.yaml" + assert config_path.exists() + assert "storage:" in config + assert "display:" in config + + +def test_load_config_reads_existing(tmp_path, monkeypatch): + """Test that load_config reads existing config file.""" + monkeypatch.setattr(Path, "home", lambda: tmp_path) + + config_dir = tmp_path / ".config" / "task-cli" + config_dir.mkdir(parents=True) + (config_dir / "config.yaml").write_text("custom: true\n") + + config = load_config() + assert "custom: true" in config + + +def test_default_config_is_valid_yaml(): + """Test that DEFAULT_CONFIG is valid YAML-like content.""" + assert "storage:" in DEFAULT_CONFIG + assert "display:" in DEFAULT_CONFIG + assert "format: json" in DEFAULT_CONFIG