build_subcommand_sort(subparsers)
build_subcommand_analyze(subparsers)
build_subcommand_day(subparsers)
+ build_subcommand_log(subparsers)
build_subcommand_recipe(subparsers)
build_subcommand_calc(subparsers)
build_subcommand_bug(subparsers)
"report", help="submit/report all bugs"
)
bug_report_parser.set_defaults(func=parser_funcs.bugs_report)
+
+
+# noinspection PyUnresolvedReferences,PyProtectedMember
+def build_subcommand_log(subparsers: argparse._SubParsersAction) -> None:
+ """Log management: add, view, analyze"""
+ log_parser = subparsers.add_parser("log", help="manage daily food logs")
+ log_subparsers = log_parser.add_subparsers(dest="subcommand", required=True)
+
+ # ADD
+ add_parser = log_subparsers.add_parser("add", help="add food to log")
+ add_parser.add_argument("food_id", type=int, help="food ID")
+ add_parser.add_argument("grams", type=float, help="amount in grams")
+ add_parser.add_argument("-d", "--date", help="date YYYY-MM-DD (default: today)")
+ add_parser.set_defaults(func=parser_funcs.log_add)
+
+ # VIEW
+ view_parser = log_subparsers.add_parser("view", help="view log entries")
+ view_parser.add_argument("-d", "--date", help="date YYYY-MM-DD (default: today)")
+ view_parser.set_defaults(func=parser_funcs.log_view)
+
+ # ANALYZE
+ anl_parser = log_subparsers.add_parser("anl", help="analyze log")
+ anl_parser.add_argument("-d", "--date", help="date YYYY-MM-DD (default: today)")
+ anl_parser.set_defaults(func=parser_funcs.log_analyze)
--- /dev/null
+"""
+Tests for log service.
+"""
+
+import os
+import shutil
+import tempfile
+import unittest
+from unittest.mock import patch
+
+from ntclient.services.logs import log_add, log_analyze, log_view
+
+
+class TestLogs(unittest.TestCase):
+ """Test class for log service"""
+
+ def setUp(self):
+ """Setup temp dir"""
+ self.test_dir = tempfile.mkdtemp()
+ self.patcher = patch("ntclient.services.logs.NUTRA_HOME", self.test_dir)
+ self.mock_home = self.patcher.start()
+
+ def tearDown(self):
+ """Cleanup"""
+ self.patcher.stop()
+ shutil.rmtree(self.test_dir)
+
+ @patch("ntclient.services.logs.sql_food_details")
+ def test_log_add(self, mock_sql):
+ """Test adding to log"""
+ # Mock food exists
+ mock_sql.return_value = [
+ (1001, 100, "Test Food", "", "", "", "", "", 0, "", 0, 0, 0, 0)
+ ]
+
+ log_add(1001, 150.0, "2099-01-01")
+
+ log_path = os.path.join(self.test_dir, "2099-01-01.csv")
+ self.assertTrue(os.path.exists(log_path))
+ with open(log_path, "r", encoding="utf-8") as f:
+ content = f.read()
+ self.assertIn("1001,150.0", content)
+
+ @patch("ntclient.services.logs.sql_food_details")
+ def test_log_add_invalid_food(self, mock_sql):
+ """Test adding invalid food"""
+ mock_sql.return_value = [] # Food not found
+
+ # Should print error and not create file (or not append)
+ # Using print capture could be added, but for now check file state
+ log_add(9999, 150.0, "2099-01-02")
+
+ log_path = os.path.join(self.test_dir, "2099-01-02.csv")
+ self.assertFalse(os.path.exists(log_path))
+
+ @patch("ntclient.services.logs.sql_food_details")
+ @patch("ntclient.services.logs.read_log")
+ def test_log_view(self, mock_read, mock_sql):
+ """Test viewing log"""
+ mock_read.return_value = [{"id": "1001", "grams": "150.0"}]
+ # Mock needs 3 elements: id, ..., name
+ mock_sql.return_value = [(1001, 100, "Test Food")]
+
+ # Just ensure no exception
+ log_view("2099-01-01")
+
+ @patch("ntclient.services.logs.day_analyze")
+ def test_log_analyze(self, mock_analyze):
+ """Test analyzing log"""
+ # Create dummy log
+ log_path = os.path.join(self.test_dir, "2099-01-01.csv")
+ with open(log_path, "w", encoding="utf-8") as f:
+ f.write("id,grams\n1001,100")
+
+ log_analyze("2099-01-01")
+ mock_analyze.assert_called_once()
+
+
+if __name__ == "__main__":
+ unittest.main()