From 9b742f9cf2840b5073e15c8d4a05413f83bb405b Mon Sep 17 00:00:00 2001 From: Joshua King Date: Thu, 10 Sep 2026 15:25:44 -0400 Subject: [PATCH] feat: create custom_components/nestquest package structure and manifest.json --- custom_components/nestquest/__init__.py | 23 ++++++++++ custom_components/nestquest/const.py | 2 + custom_components/nestquest/manifest.json | 12 +++++ pyproject.toml | 13 ++++++ tests/test_manifest.py | 55 +++++++++++++++++++++++ 5 files changed, 105 insertions(+) create mode 100644 custom_components/nestquest/__init__.py create mode 100644 custom_components/nestquest/const.py create mode 100644 custom_components/nestquest/manifest.json create mode 100644 pyproject.toml create mode 100644 tests/test_manifest.py diff --git a/custom_components/nestquest/__init__.py b/custom_components/nestquest/__init__.py new file mode 100644 index 0000000..4ffccf8 --- /dev/null +++ b/custom_components/nestquest/__init__.py @@ -0,0 +1,23 @@ +"""The NestQuest integration.""" +from __future__ import annotations + +import logging +from homeassistant.core import HomeAssistant +from homeassistant.config_entries import ConfigEntry + +from .const import DOMAIN + +_LOGGER = logging.getLogger(__name__) + +async def async_setup(hass: HomeAssistant, config: dict) -> bool: + """Set up the NestQuest component from YAML (not supported).""" + return True + +async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: + """Set up NestQuest from a config entry.""" + hass.data.setdefault(DOMAIN, {}) + return True + +async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: + """Unload a config entry.""" + return True diff --git a/custom_components/nestquest/const.py b/custom_components/nestquest/const.py new file mode 100644 index 0000000..5da908d --- /dev/null +++ b/custom_components/nestquest/const.py @@ -0,0 +1,2 @@ +"""Constants for the NestQuest integration.""" +DOMAIN = "nestquest" diff --git a/custom_components/nestquest/manifest.json b/custom_components/nestquest/manifest.json new file mode 100644 index 0000000..9336ee0 --- /dev/null +++ b/custom_components/nestquest/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "nestquest", + "name": "NestQuest", + "codeowners": ["@overseer"], + "config_flow": true, + "documentation": "https://code.cubecraftlabs.com/Maniacs_Mansion/NestQuest", + "integration_type": "hub", + "iot_class": "local_polling", + "issue_tracker": "https://code.cubecraftlabs.com/Maniacs_Mansion/NestQuest/issues", + "requirements": [], + "version": "0.1.0" +} diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..64967c1 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,13 @@ +[project] +name = "nestquest" +version = "0.1.0" +description = "NestQuest Home Assistant Integration" +readme = "README.md" +requires-python = ">=3.11" +dependencies = [ + "pytest>=8.0.0", +] + +[tool.pytest.ini_options] +testpaths = ["tests"] +pythonpath = ["."] diff --git a/tests/test_manifest.py b/tests/test_manifest.py new file mode 100644 index 0000000..ee5bb13 --- /dev/null +++ b/tests/test_manifest.py @@ -0,0 +1,55 @@ +"""Tests for the manifest.json file of NestQuest.""" +from __future__ import annotations + +import json +from pathlib import Path + +import pytest + +MANIFEST_PATH = Path(__file__).parent.parent / "custom_components" / "nestquest" / "manifest.json" + + +@pytest.fixture +def manifest() -> dict: + """Load and parse manifest.json.""" + assert MANIFEST_PATH.exists(), f"manifest.json does not exist at {MANIFEST_PATH}" + with open(MANIFEST_PATH, encoding="utf-8") as f: + data = json.load(f) + return data + + +def test_manifest_is_valid_json(manifest: dict) -> None: + """Verify manifest.json is valid JSON and parsed into a dictionary.""" + assert isinstance(manifest, dict) + + +def test_manifest_domain(manifest: dict) -> None: + """Verify domain is nestquest.""" + assert manifest.get("domain") == "nestquest" + + +def test_manifest_config_flow(manifest: dict) -> None: + """Verify config_flow is True.""" + assert manifest.get("config_flow") is True + + +def test_manifest_iot_class(manifest: dict) -> None: + """Verify iot_class is local_polling.""" + assert manifest.get("iot_class") == "local_polling" + + +def test_manifest_requirements(manifest: dict) -> None: + """Verify requirements is an empty list.""" + assert manifest.get("requirements") == [] + + +@pytest.mark.parametrize( + "key", + ["name", "version", "documentation", "issue_tracker", "codeowners"], +) +def test_manifest_required_keys_exist_and_non_empty(manifest: dict, key: str) -> None: + """Verify required keys exist and are non-empty.""" + assert key in manifest, f"Key '{key}' missing from manifest.json" + val = manifest[key] + assert val is not None, f"Key '{key}' is None" + assert len(val) > 0, f"Key '{key}' is empty"