Feature: Habit Tracker with Streak Calculation #1
4
dashboard/habits.json
Normal file
4
dashboard/habits.json
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"lastUpdated": "2026-02-10T10:57:00.000Z",
|
||||
"habits": []
|
||||
}
|
||||
110
dashboard/test_habits_schema.py
Normal file
110
dashboard/test_habits_schema.py
Normal file
@@ -0,0 +1,110 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Test suite for habits.json schema validation
|
||||
"""
|
||||
import json
|
||||
import os
|
||||
from datetime import datetime
|
||||
|
||||
|
||||
def test_habits_file_exists():
|
||||
"""Test that habits.json file exists"""
|
||||
assert os.path.exists('dashboard/habits.json'), "habits.json should exist in dashboard/"
|
||||
print("✓ habits.json file exists")
|
||||
|
||||
|
||||
def test_valid_json():
|
||||
"""Test that habits.json is valid JSON"""
|
||||
try:
|
||||
with open('dashboard/habits.json', 'r') as f:
|
||||
data = json.load(f)
|
||||
print("✓ habits.json is valid JSON")
|
||||
return data
|
||||
except json.JSONDecodeError as e:
|
||||
raise AssertionError(f"habits.json is not valid JSON: {e}")
|
||||
|
||||
|
||||
def test_root_structure(data):
|
||||
"""Test that root structure has required fields"""
|
||||
assert 'lastUpdated' in data, "Root should have 'lastUpdated' field"
|
||||
assert 'habits' in data, "Root should have 'habits' field"
|
||||
print("✓ Root structure has lastUpdated and habits fields")
|
||||
|
||||
|
||||
def test_last_updated_format(data):
|
||||
"""Test that lastUpdated is a valid ISO timestamp"""
|
||||
try:
|
||||
datetime.fromisoformat(data['lastUpdated'].replace('Z', '+00:00'))
|
||||
print("✓ lastUpdated is valid ISO timestamp")
|
||||
except (ValueError, AttributeError) as e:
|
||||
raise AssertionError(f"lastUpdated is not a valid ISO timestamp: {e}")
|
||||
|
||||
|
||||
def test_habits_is_array(data):
|
||||
"""Test that habits is an array"""
|
||||
assert isinstance(data['habits'], list), "habits should be an array"
|
||||
print("✓ habits is an array")
|
||||
|
||||
|
||||
def test_habit_schema():
|
||||
"""Test habit schema structure with sample data"""
|
||||
# Sample habit to validate schema
|
||||
sample_habit = {
|
||||
"id": "habit-123",
|
||||
"name": "Bazin",
|
||||
"frequency": "daily",
|
||||
"createdAt": "2026-02-10T10:57:00.000Z",
|
||||
"completions": ["2026-02-10T10:00:00.000Z", "2026-02-09T10:00:00.000Z"]
|
||||
}
|
||||
|
||||
# Validate required fields
|
||||
required_fields = ['id', 'name', 'frequency', 'createdAt', 'completions']
|
||||
for field in required_fields:
|
||||
assert field in sample_habit, f"Habit should have '{field}' field"
|
||||
|
||||
# Validate types
|
||||
assert isinstance(sample_habit['id'], str), "id should be string"
|
||||
assert isinstance(sample_habit['name'], str), "name should be string"
|
||||
assert sample_habit['frequency'] in ['daily', 'weekly'], "frequency should be 'daily' or 'weekly'"
|
||||
assert isinstance(sample_habit['completions'], list), "completions should be array"
|
||||
|
||||
# Validate ISO dates
|
||||
datetime.fromisoformat(sample_habit['createdAt'].replace('Z', '+00:00'))
|
||||
for completion in sample_habit['completions']:
|
||||
datetime.fromisoformat(completion.replace('Z', '+00:00'))
|
||||
|
||||
print("✓ Habit schema structure is valid")
|
||||
|
||||
|
||||
def test_initial_state(data):
|
||||
"""Test that initial file has empty habits array"""
|
||||
assert len(data['habits']) == 0, "Initial habits array should be empty"
|
||||
print("✓ Initial habits array is empty")
|
||||
|
||||
|
||||
def run_all_tests():
|
||||
"""Run all schema validation tests"""
|
||||
print("Running habits.json schema validation tests...\n")
|
||||
|
||||
try:
|
||||
test_habits_file_exists()
|
||||
data = test_valid_json()
|
||||
test_root_structure(data)
|
||||
test_last_updated_format(data)
|
||||
test_habits_is_array(data)
|
||||
test_habit_schema()
|
||||
test_initial_state(data)
|
||||
|
||||
print("\n✅ All tests passed!")
|
||||
return True
|
||||
except AssertionError as e:
|
||||
print(f"\n❌ Test failed: {e}")
|
||||
return False
|
||||
except Exception as e:
|
||||
print(f"\n❌ Unexpected error: {e}")
|
||||
return False
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
success = run_all_tests()
|
||||
exit(0 if success else 1)
|
||||
Reference in New Issue
Block a user