wup 0.2.65__tar.gz → 0.2.66__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. {wup-0.2.65/wup.egg-info → wup-0.2.66}/PKG-INFO +20 -9
  2. {wup-0.2.65 → wup-0.2.66}/README.md +6 -6
  3. {wup-0.2.65 → wup-0.2.66}/pyproject.toml +55 -3
  4. wup-0.2.66/tests/test_cli_bridge.py +35 -0
  5. wup-0.2.66/tests/test_control.py +18 -0
  6. wup-0.2.66/tests/test_endpoints_init_cli.py +68 -0
  7. wup-0.2.66/tests/test_status_data.py +34 -0
  8. wup-0.2.66/tests/test_sync.py +41 -0
  9. wup-0.2.66/tests/test_wup_generate.py +21 -0
  10. {wup-0.2.65 → wup-0.2.66}/wup/__init__.py +1 -1
  11. {wup-0.2.65 → wup-0.2.66}/wup/cli.py +125 -164
  12. wup-0.2.66/wup/cli_bridge.py +80 -0
  13. wup-0.2.66/wup/control.py +106 -0
  14. wup-0.2.66/wup/endpoints.py +44 -0
  15. wup-0.2.66/wup/generate.py +62 -0
  16. wup-0.2.66/wup/init_cli.py +60 -0
  17. wup-0.2.66/wup/paths.py +16 -0
  18. wup-0.2.66/wup/status_data.py +103 -0
  19. wup-0.2.66/wup/sync.py +70 -0
  20. wup-0.2.66/wup/validate.py +34 -0
  21. {wup-0.2.65 → wup-0.2.66/wup.egg-info}/PKG-INFO +20 -9
  22. {wup-0.2.65 → wup-0.2.66}/wup.egg-info/SOURCES.txt +15 -0
  23. wup-0.2.66/wup.egg-info/requires.txt +21 -0
  24. wup-0.2.65/wup.egg-info/requires.txt +0 -8
  25. {wup-0.2.65 → wup-0.2.66}/LICENSE +0 -0
  26. {wup-0.2.65 → wup-0.2.66}/setup.cfg +0 -0
  27. {wup-0.2.65 → wup-0.2.66}/tests/test_assistant.py +0 -0
  28. {wup-0.2.65 → wup-0.2.66}/tests/test_auto_detection.py +0 -0
  29. {wup-0.2.65 → wup-0.2.66}/tests/test_cli_filtering.py +0 -0
  30. {wup-0.2.65 → wup-0.2.66}/tests/test_e2e.py +0 -0
  31. {wup-0.2.65 → wup-0.2.66}/tests/test_health_summary_passed.py +0 -0
  32. {wup-0.2.65 → wup-0.2.66}/tests/test_monitoring_manifest.py +0 -0
  33. {wup-0.2.65 → wup-0.2.66}/tests/test_probe_mutex.py +0 -0
  34. {wup-0.2.65 → wup-0.2.66}/tests/test_service_inference.py +0 -0
  35. {wup-0.2.65 → wup-0.2.66}/tests/test_testql_monitor.py +0 -0
  36. {wup-0.2.65 → wup-0.2.66}/tests/test_testql_watcher.py +0 -0
  37. {wup-0.2.65 → wup-0.2.66}/tests/test_visual_diff_periodic_skip.py +0 -0
  38. {wup-0.2.65 → wup-0.2.66}/tests/test_visual_diff_progress.py +0 -0
  39. {wup-0.2.65 → wup-0.2.66}/tests/test_watch_exclude.py +0 -0
  40. {wup-0.2.65 → wup-0.2.66}/tests/test_web_client.py +0 -0
  41. {wup-0.2.65 → wup-0.2.66}/tests/test_wup.py +0 -0
  42. {wup-0.2.65 → wup-0.2.66}/wup/_ast_detector.py +0 -0
  43. {wup-0.2.65 → wup-0.2.66}/wup/_base_detector.py +0 -0
  44. {wup-0.2.65 → wup-0.2.66}/wup/_hash_detector.py +0 -0
  45. {wup-0.2.65 → wup-0.2.66}/wup/_yaml_detector.py +0 -0
  46. {wup-0.2.65 → wup-0.2.66}/wup/anomaly_detector.py +0 -0
  47. {wup-0.2.65 → wup-0.2.66}/wup/anomaly_models.py +0 -0
  48. {wup-0.2.65 → wup-0.2.66}/wup/assistant.py +0 -0
  49. {wup-0.2.65 → wup-0.2.66}/wup/assistant_discovery.py +0 -0
  50. {wup-0.2.65 → wup-0.2.66}/wup/assistant_validator.py +0 -0
  51. {wup-0.2.65 → wup-0.2.66}/wup/bus.py +0 -0
  52. {wup-0.2.65 → wup-0.2.66}/wup/cli_config_generator.py +0 -0
  53. {wup-0.2.65 → wup-0.2.66}/wup/cli_scanner.py +0 -0
  54. {wup-0.2.65 → wup-0.2.66}/wup/config.py +0 -0
  55. {wup-0.2.65 → wup-0.2.66}/wup/core.py +0 -0
  56. {wup-0.2.65 → wup-0.2.66}/wup/dependency_mapper.py +0 -0
  57. {wup-0.2.65 → wup-0.2.66}/wup/event_store.py +0 -0
  58. {wup-0.2.65 → wup-0.2.66}/wup/file_watcher/events/file_events.py +0 -0
  59. {wup-0.2.65 → wup-0.2.66}/wup/models/__init__.py +0 -0
  60. {wup-0.2.65 → wup-0.2.66}/wup/models/config.py +0 -0
  61. {wup-0.2.65 → wup-0.2.66}/wup/monitoring_manifest.py +0 -0
  62. {wup-0.2.65 → wup-0.2.66}/wup/planfile_reporter.py +0 -0
  63. {wup-0.2.65 → wup-0.2.66}/wup/testing/events/health_events.py +0 -0
  64. {wup-0.2.65 → wup-0.2.66}/wup/testing/events/test_results.py +0 -0
  65. {wup-0.2.65 → wup-0.2.66}/wup/testing/handlers/event_handlers.py +0 -0
  66. {wup-0.2.65 → wup-0.2.66}/wup/testing/handlers/health_handlers.py +0 -0
  67. {wup-0.2.65 → wup-0.2.66}/wup/testing/queries/health_queries.py +0 -0
  68. {wup-0.2.65 → wup-0.2.66}/wup/testql_cli_generator.py +0 -0
  69. {wup-0.2.65 → wup-0.2.66}/wup/testql_discovery.py +0 -0
  70. {wup-0.2.65 → wup-0.2.66}/wup/testql_monitor.py +0 -0
  71. {wup-0.2.65 → wup-0.2.66}/wup/testql_watcher.py +0 -0
  72. {wup-0.2.65 → wup-0.2.66}/wup/visual_diff.py +0 -0
  73. {wup-0.2.65 → wup-0.2.66}/wup/web_client.py +0 -0
  74. {wup-0.2.65 → wup-0.2.66}/wup.egg-info/dependency_links.txt +0 -0
  75. {wup-0.2.65 → wup-0.2.66}/wup.egg-info/entry_points.txt +0 -0
  76. {wup-0.2.65 → wup-0.2.66}/wup.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: wup
3
- Version: 0.2.65
3
+ Version: 0.2.66
4
4
  Summary: WUP (What's Up) - Intelligent file watcher for regression testing in large projects
5
5
  Author-email: Tom Sapletta <tom@sapletta.com>
6
6
  License-Expression: Apache-2.0
@@ -10,11 +10,10 @@ Keywords: wup,watcher,testing,regression,file-monitoring
10
10
  Classifier: Development Status :: 3 - Alpha
11
11
  Classifier: Intended Audience :: Developers
12
12
  Classifier: Programming Language :: Python :: 3
13
- Classifier: Programming Language :: Python :: 3.9
14
13
  Classifier: Programming Language :: Python :: 3.10
15
14
  Classifier: Programming Language :: Python :: 3.11
16
15
  Classifier: Programming Language :: Python :: 3.12
17
- Requires-Python: >=3.9
16
+ Requires-Python: >=3.10
18
17
  Description-Content-Type: text/markdown
19
18
  License-File: LICENSE
20
19
  Requires-Dist: watchdog>=4.0.0
@@ -22,6 +21,18 @@ Requires-Dist: psutil>=5.9.0
22
21
  Requires-Dist: rich>=13.0.0
23
22
  Requires-Dist: typer>=0.9.0
24
23
  Requires-Dist: pyyaml>=6.0
24
+ Provides-Extra: dev
25
+ Requires-Dist: pytest>=7.0.0; extra == "dev"
26
+ Requires-Dist: goal>=2.1.0; extra == "dev"
27
+ Requires-Dist: costs>=0.1.20; extra == "dev"
28
+ Requires-Dist: pfix>=0.1.60; extra == "dev"
29
+ Requires-Dist: uri2wup; extra == "dev"
30
+ Requires-Dist: dsl2wup; extra == "dev"
31
+ Requires-Dist: nlp2wup; extra == "dev"
32
+ Requires-Dist: cli2wup; extra == "dev"
33
+ Requires-Dist: mcp2wup; extra == "dev"
34
+ Requires-Dist: rest2wup; extra == "dev"
35
+ Requires-Dist: httpx>=0.27; extra == "dev"
25
36
  Provides-Extra: visual
26
37
  Requires-Dist: playwright<2,>=1.40; extra == "visual"
27
38
  Dynamic: license-file
@@ -31,17 +42,17 @@ Dynamic: license-file
31
42
 
32
43
  ## AI Cost Tracking
33
44
 
34
- ![PyPI](https://img.shields.io/badge/pypi-costs-blue) ![Version](https://img.shields.io/badge/version-0.2.65-blue) ![Python](https://img.shields.io/badge/python-3.9+-blue) ![License](https://img.shields.io/badge/license-Apache--2.0-green)
35
- ![AI Cost](https://img.shields.io/badge/AI%20Cost-$3.50-orange) ![Human Time](https://img.shields.io/badge/Human%20Time-33.2h-blue) ![Model](https://img.shields.io/badge/Model-openrouter%2Fqwen%2Fqwen3--coder--next-lightgrey)
45
+ ![PyPI](https://img.shields.io/badge/pypi-costs-blue) ![Version](https://img.shields.io/badge/version-0.2.66-blue) ![Python](https://img.shields.io/badge/python-3.9+-blue) ![License](https://img.shields.io/badge/license-Apache--2.0-green)
46
+ ![AI Cost](https://img.shields.io/badge/AI%20Cost-$3.34-orange) ![Human Time](https://img.shields.io/badge/Human%20Time-35.2h-blue) ![Model](https://img.shields.io/badge/Model-openrouter%2Fqwen%2Fqwen3--coder--next-lightgrey)
36
47
 
37
- - 🤖 **LLM usage:** $3.4955 (77 commits)
38
- - 👤 **Human dev:** ~$3318 (33.2h @ $100/h, 30min dedup)
48
+ - 🤖 **LLM usage:** $3.3376 (79 commits)
49
+ - 👤 **Human dev:** ~$3518 (35.2h @ $100/h, 30min dedup)
39
50
 
40
- Generated on 2026-06-03 using [openrouter/qwen/qwen3-coder-next](https://openrouter.ai/qwen/qwen3-coder-next)
51
+ Generated on 2026-06-08 using [openrouter/qwen/qwen3-coder-next](https://openrouter.ai/qwen/qwen3-coder-next)
41
52
 
42
53
  ---
43
54
 
44
- ![PyPI](https://img.shields.io/badge/pypi-wup-blue) ![Version](https://img.shields.io/badge/version-0.2.65-blue) ![Python](https://img.shields.io/badge/python-3.9+-blue) ![License](https://img.shields.io/badge/license-Apache--2.0-green)
55
+ ![PyPI](https://img.shields.io/badge/pypi-wup-blue) ![Version](https://img.shields.io/badge/version-0.2.66-blue) ![Python](https://img.shields.io/badge/python-3.9+-blue) ![License](https://img.shields.io/badge/license-Apache--2.0-green)
45
56
 
46
57
  **WUP (What's Up)** - Intelligent file watcher for regression testing in large projects.
47
58
 
@@ -3,17 +3,17 @@
3
3
 
4
4
  ## AI Cost Tracking
5
5
 
6
- ![PyPI](https://img.shields.io/badge/pypi-costs-blue) ![Version](https://img.shields.io/badge/version-0.2.65-blue) ![Python](https://img.shields.io/badge/python-3.9+-blue) ![License](https://img.shields.io/badge/license-Apache--2.0-green)
7
- ![AI Cost](https://img.shields.io/badge/AI%20Cost-$3.50-orange) ![Human Time](https://img.shields.io/badge/Human%20Time-33.2h-blue) ![Model](https://img.shields.io/badge/Model-openrouter%2Fqwen%2Fqwen3--coder--next-lightgrey)
6
+ ![PyPI](https://img.shields.io/badge/pypi-costs-blue) ![Version](https://img.shields.io/badge/version-0.2.66-blue) ![Python](https://img.shields.io/badge/python-3.9+-blue) ![License](https://img.shields.io/badge/license-Apache--2.0-green)
7
+ ![AI Cost](https://img.shields.io/badge/AI%20Cost-$3.34-orange) ![Human Time](https://img.shields.io/badge/Human%20Time-35.2h-blue) ![Model](https://img.shields.io/badge/Model-openrouter%2Fqwen%2Fqwen3--coder--next-lightgrey)
8
8
 
9
- - 🤖 **LLM usage:** $3.4955 (77 commits)
10
- - 👤 **Human dev:** ~$3318 (33.2h @ $100/h, 30min dedup)
9
+ - 🤖 **LLM usage:** $3.3376 (79 commits)
10
+ - 👤 **Human dev:** ~$3518 (35.2h @ $100/h, 30min dedup)
11
11
 
12
- Generated on 2026-06-03 using [openrouter/qwen/qwen3-coder-next](https://openrouter.ai/qwen/qwen3-coder-next)
12
+ Generated on 2026-06-08 using [openrouter/qwen/qwen3-coder-next](https://openrouter.ai/qwen/qwen3-coder-next)
13
13
 
14
14
  ---
15
15
 
16
- ![PyPI](https://img.shields.io/badge/pypi-wup-blue) ![Version](https://img.shields.io/badge/version-0.2.65-blue) ![Python](https://img.shields.io/badge/python-3.9+-blue) ![License](https://img.shields.io/badge/license-Apache--2.0-green)
16
+ ![PyPI](https://img.shields.io/badge/pypi-wup-blue) ![Version](https://img.shields.io/badge/version-0.2.66-blue) ![Python](https://img.shields.io/badge/python-3.9+-blue) ![License](https://img.shields.io/badge/license-Apache--2.0-green)
17
17
 
18
18
  **WUP (What's Up)** - Intelligent file watcher for regression testing in large projects.
19
19
 
@@ -4,10 +4,10 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "wup"
7
- version = "0.2.65"
7
+ version = "0.2.66"
8
8
  description = "WUP (What's Up) - Intelligent file watcher for regression testing in large projects"
9
9
  readme = "README.md"
10
- requires-python = ">=3.9"
10
+ requires-python = ">=3.10"
11
11
  authors = [
12
12
  {name = "Tom Sapletta", email = "tom@sapletta.com"},
13
13
  ]
@@ -23,7 +23,6 @@ classifiers = [
23
23
  "Development Status :: 3 - Alpha",
24
24
  "Intended Audience :: Developers",
25
25
  "Programming Language :: Python :: 3",
26
- "Programming Language :: Python :: 3.9",
27
26
  "Programming Language :: Python :: 3.10",
28
27
  "Programming Language :: Python :: 3.11",
29
28
  "Programming Language :: Python :: 3.12",
@@ -31,10 +30,63 @@ classifiers = [
31
30
  license = "Apache-2.0"
32
31
 
33
32
  [project.optional-dependencies]
33
+ dev = [
34
+ "pytest>=7.0.0",
35
+ "goal>=2.1.0",
36
+ "costs>=0.1.20",
37
+ "pfix>=0.1.60",
38
+ "uri2wup",
39
+ "dsl2wup",
40
+ "nlp2wup",
41
+ "cli2wup",
42
+ "mcp2wup",
43
+ "rest2wup",
44
+ "httpx>=0.27",
45
+ ]
34
46
  visual = [
35
47
  "playwright>=1.40,<2",
36
48
  ]
37
49
 
50
+ [dependency-groups]
51
+ dev = [
52
+ "pytest>=7.0.0",
53
+ "goal>=2.1.0",
54
+ "costs>=0.1.20",
55
+ "pfix>=0.1.60",
56
+ "uri2wup",
57
+ "dsl2wup",
58
+ "nlp2wup",
59
+ "cli2wup",
60
+ "mcp2wup",
61
+ "rest2wup",
62
+ "httpx>=0.27",
63
+ ]
64
+
65
+ [tool.uv.workspace]
66
+ members = [
67
+ ".",
68
+ "packages/uri2wup",
69
+ "packages/dsl2wup",
70
+ "packages/nlp2wup",
71
+ "packages/cli2wup",
72
+ "packages/mcp2wup",
73
+ "packages/rest2wup",
74
+ ]
75
+
76
+ [tool.uv.sources]
77
+ wup = { workspace = true }
78
+ uri2wup = { workspace = true }
79
+ dsl2wup = { workspace = true }
80
+ nlp2wup = { workspace = true }
81
+ cli2wup = { workspace = true }
82
+ mcp2wup = { workspace = true }
83
+ rest2wup = { workspace = true }
84
+
85
+ [tool.pytest.ini_options]
86
+ testpaths = ["tests", "packages"]
87
+ python_files = ["test_*.py"]
88
+ addopts = "-ra --tb=short"
89
+
38
90
  [tool.setuptools.packages.find]
39
91
  include = ["wup*"]
40
92
 
@@ -0,0 +1,35 @@
1
+ """Tests for wup.cli_bridge → bus delegation."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from pathlib import Path
6
+
7
+ from wup.cli_bridge import run_init, run_map_deps, run_validate
8
+
9
+
10
+ def test_bridge_init(tmp_path: Path) -> None:
11
+ result = run_init(project=str(tmp_path), out="wup.yaml")
12
+ assert result["ok"]
13
+ assert (tmp_path / "wup.yaml").exists()
14
+
15
+
16
+ def test_bridge_map_deps(tmp_path: Path) -> None:
17
+ (tmp_path / "app.py").write_text("from fastapi import FastAPI\napp = FastAPI()\n", encoding="utf-8")
18
+ (tmp_path / "wup.yaml").write_text(
19
+ "project:\n name: demo\nwatch:\n paths: []\nservices: []\n",
20
+ encoding="utf-8",
21
+ )
22
+ result = run_map_deps(project=str(tmp_path), out="deps.json", framework="auto")
23
+ assert result["ok"]
24
+ assert (tmp_path / "deps.json").exists()
25
+
26
+
27
+ def test_bridge_validate(tmp_path: Path) -> None:
28
+ config = tmp_path / "wup.yaml"
29
+ config.write_text(
30
+ "project:\n name: demo\n description: test\nwatch:\n paths: []\n"
31
+ "services:\n - name: api\n type: web\n",
32
+ encoding="utf-8",
33
+ )
34
+ result = run_validate(path=str(config), project=str(tmp_path))
35
+ assert "ok" in result
@@ -0,0 +1,18 @@
1
+ """Tests for wup.control shim."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from pathlib import Path
6
+
7
+ from wup.control import dispatch_validate
8
+
9
+
10
+ def test_dispatch_validate_shim(tmp_path: Path) -> None:
11
+ config = tmp_path / "wup.yaml"
12
+ config.write_text(
13
+ "project:\n name: demo\n description: test\nwatch:\n paths: []\nservices: []\n",
14
+ encoding="utf-8",
15
+ )
16
+ result = dispatch_validate(str(config), project=str(tmp_path))
17
+ assert "ok" in result
18
+ assert result["action"] == "validate"
@@ -0,0 +1,68 @@
1
+ """Tests for endpoints + init_cli domain and bus."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from pathlib import Path
6
+
7
+ import yaml
8
+
9
+ from dsl2wup import dispatch
10
+ from wup.endpoints import discover_testql_endpoints
11
+ from wup.init_cli import setup_cli_project
12
+
13
+
14
+ def _write_scenario(dir_path: Path, name: str = "smoke.testql.toon.yaml") -> Path:
15
+ dir_path.mkdir(parents=True, exist_ok=True)
16
+ scenario = dir_path / name
17
+ scenario.write_text(
18
+ yaml.safe_dump(
19
+ {
20
+ "name": "smoke",
21
+ "service": "api",
22
+ "steps": [{"request": {"method": "GET", "url": "/health"}}],
23
+ }
24
+ ),
25
+ encoding="utf-8",
26
+ )
27
+ return scenario
28
+
29
+
30
+ def test_discover_testql_endpoints(tmp_path: Path) -> None:
31
+ scen = tmp_path / "scenarios"
32
+ _write_scenario(scen)
33
+ result = discover_testql_endpoints(scen, out=tmp_path / "deps.json")
34
+ assert result["ok"]
35
+ assert (tmp_path / "deps.json").exists()
36
+
37
+
38
+ def test_endpoints_via_bus(tmp_path: Path) -> None:
39
+ scen = tmp_path / "scenarios"
40
+ _write_scenario(scen)
41
+ result = dispatch(f"ENDPOINTS {scen} OUT {tmp_path / 'out.json'}")
42
+ assert result.ok
43
+ assert (tmp_path / "out.json").exists()
44
+
45
+
46
+ def test_init_cli_via_bus(tmp_path: Path) -> None:
47
+ (tmp_path / "pyproject.toml").write_text(
48
+ '[project]\nname = "demo"\n\n[project.scripts]\n demo = "demo:main"\n',
49
+ encoding="utf-8",
50
+ )
51
+ (tmp_path / "demo").mkdir()
52
+ (tmp_path / "demo" / "__init__.py").write_text("def main(): pass\n", encoding="utf-8")
53
+ result = dispatch(f"INIT_CLI {tmp_path} OUT wup.yaml SCENARIOS testql-scenarios")
54
+ assert result.ok
55
+ assert (tmp_path / "wup.yaml").exists()
56
+ assert (tmp_path / "testql-scenarios").is_dir()
57
+
58
+
59
+ def test_setup_cli_project_core(tmp_path: Path) -> None:
60
+ (tmp_path / "pyproject.toml").write_text(
61
+ '[project]\nname = "demo"\n\n[project.scripts]\n demo = "demo:main"\n',
62
+ encoding="utf-8",
63
+ )
64
+ (tmp_path / "demo").mkdir()
65
+ (tmp_path / "demo" / "__init__.py").write_text("def main(): pass\n", encoding="utf-8")
66
+ payload = setup_cli_project(tmp_path)
67
+ assert payload["ok"]
68
+ assert payload["commands"] >= 1
@@ -0,0 +1,34 @@
1
+ """Tests for STATUS snapshot."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import json
6
+ from pathlib import Path
7
+
8
+ from dsl2wup import dispatch
9
+ from wup.paths import health_state_path
10
+ from wup.status_data import collect_status_snapshot
11
+
12
+
13
+ def test_collect_status_snapshot(tmp_path: Path) -> None:
14
+ (tmp_path / "wup.yaml").write_text(
15
+ "project:\n name: demo\n description: t\nwatch:\n paths: []\nservices:\n - name: api\n type: web\n",
16
+ encoding="utf-8",
17
+ )
18
+ state = health_state_path(tmp_path)
19
+ state.parent.mkdir(parents=True, exist_ok=True)
20
+ state.write_text(json.dumps({"api": {"status": "up"}}), encoding="utf-8")
21
+ snap = collect_status_snapshot(tmp_path)
22
+ assert snap["ok"]
23
+ assert snap["project_name"] == "demo"
24
+ assert "api" in snap["health"]
25
+
26
+
27
+ def test_status_via_bus(tmp_path: Path) -> None:
28
+ (tmp_path / "wup.yaml").write_text(
29
+ "project:\n name: demo\nwatch:\n paths: []\nservices:\n - name: api\n type: web\n",
30
+ encoding="utf-8",
31
+ )
32
+ result = dispatch(f"STATUS PROJECT {tmp_path} FILE wup.yaml")
33
+ assert result.ok
34
+ assert result.data["project_name"] == "demo"
@@ -0,0 +1,41 @@
1
+ """Tests for wup.sync."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from pathlib import Path
6
+
7
+ import yaml
8
+
9
+ from wup.sync import sync_testql_manifest
10
+
11
+
12
+ def _minimal_config(path: Path) -> None:
13
+ path.write_text(
14
+ yaml.safe_dump(
15
+ {
16
+ "project": {"name": "demo", "description": "test"},
17
+ "watch": {"paths": [], "exclude_patterns": [], "file_types": []},
18
+ "services": [{"name": "api", "type": "web"}],
19
+ "testql": {"scenario_dir": "scenarios", "endpoints_by_service": {"api": ["/health"]}},
20
+ },
21
+ sort_keys=False,
22
+ ),
23
+ encoding="utf-8",
24
+ )
25
+
26
+
27
+ def test_sync_writes_manifest(tmp_path: Path) -> None:
28
+ cfg = tmp_path / "wup.yaml"
29
+ _minimal_config(cfg)
30
+ result = sync_testql_manifest(tmp_path, config_file=str(cfg), write=True)
31
+ assert result["ok"]
32
+ text = cfg.read_text(encoding="utf-8")
33
+ assert "BEGIN WUP MONITORING MANIFEST" in text
34
+
35
+
36
+ def test_sync_merge_endpoints_flag(tmp_path: Path) -> None:
37
+ cfg = tmp_path / "wup.yaml"
38
+ _minimal_config(cfg)
39
+ result = sync_testql_manifest(tmp_path, config_file=str(cfg), merge_endpoints=True, write=True)
40
+ assert result["ok"]
41
+ assert "merge_endpoints" in result
@@ -0,0 +1,21 @@
1
+ """Tests for wup.generate."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from pathlib import Path
6
+
7
+ from wup.generate import generate_wup_config
8
+
9
+
10
+ def test_generate_fastapi_config(tmp_path: Path) -> None:
11
+ result = generate_wup_config(tmp_path, hint="fastapi project", out="wup.yaml")
12
+ assert result["ok"]
13
+ assert (tmp_path / "wup.yaml").exists()
14
+ assert result["framework"] == "fastapi"
15
+ assert result["services"] >= 1
16
+
17
+
18
+ def test_generate_refuses_existing_without_overwrite(tmp_path: Path) -> None:
19
+ (tmp_path / "wup.yaml").write_text("project:\n name: x\n", encoding="utf-8")
20
+ result = generate_wup_config(tmp_path, hint="flask", out="wup.yaml")
21
+ assert not result["ok"]
@@ -7,7 +7,7 @@ WUP monitors file changes and runs intelligent regression tests using a 3-layer
7
7
  3. Detail Layer: Full tests with blame reports (only on failure)
8
8
  """
9
9
 
10
- __version__ = "0.2.65"
10
+ __version__ = "0.2.66"
11
11
  __author__ = "Tom Sapletta"
12
12
 
13
13
  from .config import load_config, save_config, get_default_config