xmind2testcase-lq 1.5.0.1__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 (53) hide show
  1. xmind2testcase_lq-1.5.0.1/LICENSE +22 -0
  2. xmind2testcase_lq-1.5.0.1/PKG-INFO +132 -0
  3. xmind2testcase_lq-1.5.0.1/README.md +110 -0
  4. xmind2testcase_lq-1.5.0.1/pyproject.toml +42 -0
  5. xmind2testcase_lq-1.5.0.1/setup.cfg +4 -0
  6. xmind2testcase_lq-1.5.0.1/xmind2testcase_lq/__about__.py +15 -0
  7. xmind2testcase_lq-1.5.0.1/xmind2testcase_lq/__init__.py +0 -0
  8. xmind2testcase_lq-1.5.0.1/xmind2testcase_lq/cli.py +117 -0
  9. xmind2testcase_lq-1.5.0.1/xmind2testcase_lq/config.py +80 -0
  10. xmind2testcase_lq-1.5.0.1/xmind2testcase_lq/const.py +28 -0
  11. xmind2testcase_lq-1.5.0.1/xmind2testcase_lq/metadata.py +123 -0
  12. xmind2testcase_lq-1.5.0.1/xmind2testcase_lq/parser.py +283 -0
  13. xmind2testcase_lq-1.5.0.1/xmind2testcase_lq/testlink.py +158 -0
  14. xmind2testcase_lq-1.5.0.1/xmind2testcase_lq/utils.py +140 -0
  15. xmind2testcase_lq-1.5.0.1/xmind2testcase_lq/webtool/__init__.py +0 -0
  16. xmind2testcase_lq-1.5.0.1/xmind2testcase_lq/webtool/application.py +299 -0
  17. xmind2testcase_lq-1.5.0.1/xmind2testcase_lq/webtool/schema.sql +9 -0
  18. xmind2testcase_lq-1.5.0.1/xmind2testcase_lq/webtool/static/css/custom.css +280 -0
  19. xmind2testcase_lq-1.5.0.1/xmind2testcase_lq/webtool/static/css/pure-min.css +11 -0
  20. xmind2testcase_lq-1.5.0.1/xmind2testcase_lq/webtool/static/css/style.css +718 -0
  21. xmind2testcase_lq-1.5.0.1/xmind2testcase_lq/webtool/static/guide/XMind/346/265/213/350/257/225/347/224/250/344/276/213/346/250/241/346/235/277.xmind +0 -0
  22. xmind2testcase_lq-1.5.0.1/xmind2testcase_lq/webtool/static/guide/demo1_convert_result.png +0 -0
  23. xmind2testcase_lq-1.5.0.1/xmind2testcase_lq/webtool/static/guide/demo2_convert_result.png +0 -0
  24. xmind2testcase_lq-1.5.0.1/xmind2testcase_lq/webtool/static/guide/index.html +200 -0
  25. xmind2testcase_lq-1.5.0.1/xmind2testcase_lq/webtool/static/guide/index.md +120 -0
  26. xmind2testcase_lq-1.5.0.1/xmind2testcase_lq/webtool/static/guide/pypi_upload.png +0 -0
  27. xmind2testcase_lq-1.5.0.1/xmind2testcase_lq/webtool/static/guide/testcase_json_demo.png +0 -0
  28. xmind2testcase_lq-1.5.0.1/xmind2testcase_lq/webtool/static/guide/testcase_template_demo1.png +0 -0
  29. xmind2testcase_lq-1.5.0.1/xmind2testcase_lq/webtool/static/guide/testcase_template_demo2.png +0 -0
  30. xmind2testcase_lq-1.5.0.1/xmind2testcase_lq/webtool/static/guide/testcase_template_demo3.png +0 -0
  31. xmind2testcase_lq-1.5.0.1/xmind2testcase_lq/webtool/static/guide/testlink.png +0 -0
  32. xmind2testcase_lq-1.5.0.1/xmind2testcase_lq/webtool/static/guide/testlink_import_result.png +0 -0
  33. xmind2testcase_lq-1.5.0.1/xmind2testcase_lq/webtool/static/guide/testlink_select_file.png +0 -0
  34. xmind2testcase_lq-1.5.0.1/xmind2testcase_lq/webtool/static/guide/testlink_testcase_view.png +0 -0
  35. xmind2testcase_lq-1.5.0.1/xmind2testcase_lq/webtool/static/guide/testsuite_json_demo.png +0 -0
  36. xmind2testcase_lq-1.5.0.1/xmind2testcase_lq/webtool/static/guide/webtool.png +0 -0
  37. xmind2testcase_lq-1.5.0.1/xmind2testcase_lq/webtool/static/guide/webtool_cli.png +0 -0
  38. xmind2testcase_lq-1.5.0.1/xmind2testcase_lq/webtool/static/guide/xmind_testcase_demo.png +0 -0
  39. xmind2testcase_lq-1.5.0.1/xmind2testcase_lq/webtool/static/guide/xmind_testcase_template_rule.png +0 -0
  40. xmind2testcase_lq-1.5.0.1/xmind2testcase_lq/webtool/static/guide/xmind_testcase_template_rule1.png +0 -0
  41. xmind2testcase_lq-1.5.0.1/xmind2testcase_lq/webtool/static/guide/xmind_to_testcase_preview.png +0 -0
  42. xmind2testcase_lq-1.5.0.1/xmind2testcase_lq/webtool/static/guide/zentao_import_file.png +0 -0
  43. xmind2testcase_lq-1.5.0.1/xmind2testcase_lq/webtool/static/guide/zentao_import_result.png +0 -0
  44. xmind2testcase_lq-1.5.0.1/xmind2testcase_lq/webtool/static/guide/zentao_testcase_template.png +0 -0
  45. xmind2testcase_lq-1.5.0.1/xmind2testcase_lq/webtool/templates/index.html +76 -0
  46. xmind2testcase_lq-1.5.0.1/xmind2testcase_lq/webtool/templates/preview.html +82 -0
  47. xmind2testcase_lq-1.5.0.1/xmind2testcase_lq/zentao.py +152 -0
  48. xmind2testcase_lq-1.5.0.1/xmind2testcase_lq.egg-info/PKG-INFO +132 -0
  49. xmind2testcase_lq-1.5.0.1/xmind2testcase_lq.egg-info/SOURCES.txt +51 -0
  50. xmind2testcase_lq-1.5.0.1/xmind2testcase_lq.egg-info/dependency_links.txt +1 -0
  51. xmind2testcase_lq-1.5.0.1/xmind2testcase_lq.egg-info/entry_points.txt +2 -0
  52. xmind2testcase_lq-1.5.0.1/xmind2testcase_lq.egg-info/requires.txt +3 -0
  53. xmind2testcase_lq-1.5.0.1/xmind2testcase_lq.egg-info/top_level.txt +1 -0
@@ -0,0 +1,22 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2019 Devin https://zhangchuzhao.site
4
+ Copyright (c) 2017 Toby Qin
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ of this software and associated documentation files (the "Software"), to deal
8
+ in the Software without restriction, including without limitation the rights
9
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ copies of the Software, and to permit persons to whom the Software is
11
+ furnished to do so, subject to the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be included in all
14
+ copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ SOFTWARE.
@@ -0,0 +1,132 @@
1
+ Metadata-Version: 2.4
2
+ Name: xmind2testcase-lq
3
+ Version: 1.5.0.1
4
+ Summary: XMind2TestCase 的定制分支:面向禅道导入的中文测试用例转换,用例编号前缀可配置
5
+ Author: liqin
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://gitee.com/QiLi1998/xmind2testcase-lq
8
+ Project-URL: Repository, https://gitee.com/QiLi1998/xmind2testcase-lq
9
+ Project-URL: 上游项目, https://github.com/zhuifengshen/xmind2testcase
10
+ Keywords: xmind,testcase,zentao,testlink,思维导图,测试用例,xmind2testcase
11
+ Classifier: Programming Language :: Python :: 3
12
+ Classifier: Operating System :: OS Independent
13
+ Classifier: Natural Language :: Chinese (Simplified)
14
+ Classifier: Topic :: Software Development :: Testing
15
+ Requires-Python: >=3.8
16
+ Description-Content-Type: text/markdown
17
+ License-File: LICENSE
18
+ Requires-Dist: xmind
19
+ Requires-Dist: flask
20
+ Requires-Dist: arrow
21
+ Dynamic: license-file
22
+
23
+ # xmind2testcase-lq
24
+
25
+ > **这是 [xmind2testcase](https://github.com/zhuifengshen/xmind2testcase) 的定制分支(fork),不是上游官方版本。**
26
+ > 面向「XMind 思维导图 → 禅道(ZenTao)测试用例 CSV」这一条链路做了调整,
27
+ > 并把原本写死在源码里的项目相关信息改成了可配置项。
28
+
29
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
30
+
31
+ ## 与上游的主要差异
32
+
33
+ | 方面 | 上游 `xmind2testcase` 1.5.0 | 本分支 `xmind2testcase-lq` |
34
+ |---|---|---|
35
+ | 导入包名 | `xmind2testcase` | `xmind2testcase_lq` |
36
+ | 禅道 CSV 表头 | 9 列(所属模块 / 用例标题 / …) | **10 列**(用例编号 / 用例描述 / 测试类型 / 前置条件 / 操作步骤 / 期望结果 / 通过准则 / 实际输出 / 测试结论 / 测试用例优先级) |
37
+ | 用例编号 | 无此列 | `<前缀>-<xmind文件名>-001`,**前缀可配置** |
38
+ | 用例编号前缀 | — | 参数 `case_id_prefix` > 环境变量 `XMIND2TESTCASE_CASE_ID_PREFIX` > 空 |
39
+ | 测试类型 | `1` / `2`(手动 / 自动) | 中文类型:正向功能 / 反向功能 / 接口 / 性能 / 界面 / 安全性 |
40
+ | 优先级映射 | 高 / 中 / 低 | 一级 / 二级 / 三级 / 四级 |
41
+ | 前置条件拼接 | 用 `\n----\n` 分隔 | 直接相连(逐条去空白) |
42
+ | 期望结果 | 只取第一条 | 支持多条,逐条编号后用换行连接 |
43
+ | 只取行数据 | 无 | 新增 `xmind_to_rows()`,不落盘 |
44
+ | 日志文件 | 无(或写死路径) | 环境变量 `XMIND2TESTCASE_LOG` 控制,目录自动创建 |
45
+ | `webtool` 包位置 | 顶层包 `webtool` | 收进 `xmind2testcase_lq.webtool`,不污染全局命名空间 |
46
+ | CLI 命令 | `xmind2testcase` | `xmind2testcase-lq` |
47
+
48
+ 完整的逐文件差异见 [FORK_NOTES.md](FORK_NOTES.md)。
49
+
50
+ ## 安装
51
+
52
+ ```bash
53
+ pip install xmind2testcase-lq
54
+ ```
55
+
56
+ 从源码安装:
57
+
58
+ ```bash
59
+ git clone https://gitee.com/QiLi1998/xmind2testcase-lq.git
60
+ cd xmind2testcase-lq
61
+ pip install .
62
+ ```
63
+
64
+ ## 使用
65
+
66
+ ### 作为库调用
67
+
68
+ ```python
69
+ from xmind2testcase_lq.zentao import xmind_to_rows, xmind_to_zentao_csv_file
70
+
71
+ # 不设置前缀:编号形如 登录功能-001
72
+ rows = xmind_to_rows("用例.xmind")
73
+
74
+ # 显式指定前缀:编号形如 我的项目-登录功能-001
75
+ rows = xmind_to_rows("用例.xmind", case_id_prefix="我的项目")
76
+
77
+ # 直接落盘成 CSV
78
+ csv_path = xmind_to_zentao_csv_file("用例.xmind", case_id_prefix="我的项目")
79
+ ```
80
+
81
+ `rows` 第一行是表头,其后每行是一条用例。
82
+
83
+ ### 通过环境变量配置
84
+
85
+ 适合不想改代码、或要走命令行的情况:
86
+
87
+ ```bash
88
+ # Linux / macOS
89
+ export XMIND2TESTCASE_CASE_ID_PREFIX="我的项目"
90
+
91
+ # Windows PowerShell
92
+ $env:XMIND2TESTCASE_CASE_ID_PREFIX = "我的项目"
93
+ ```
94
+
95
+ ```python
96
+ rows = xmind_to_rows("用例.xmind") # 自动读取上面的环境变量
97
+ ```
98
+
99
+ ### 命令行
100
+
101
+ ```bash
102
+ xmind2testcase-lq 用例.xmind -csv
103
+ xmind2testcase-lq 用例.xmind -csv --case-id-prefix=我的项目
104
+ xmind2testcase-lq 用例.xmind # 同时输出 json / xml / csv
105
+ xmind2testcase-lq webtool 8000 # 启动本地 Web 转换工具
106
+ ```
107
+
108
+ ## 配置项
109
+
110
+ 全部通过环境变量控制,也可以用函数参数覆盖(参数优先级更高)。
111
+
112
+ | 环境变量 | 作用 | 默认值 |
113
+ |---|---|---|
114
+ | `XMIND2TESTCASE_CASE_ID_PREFIX` | 用例编号前缀 | 空(编号不含前缀) |
115
+ | `XMIND2TESTCASE_LOG` | 日志文件路径,父目录不存在时自动创建 | 空(只输出到控制台) |
116
+ | `XMIND2TESTCASE_LOG_LEVEL` | 日志级别 | `INFO` |
117
+
118
+ > 设计原则:**源码中不出现任何本机路径或具体项目名**,所有环境相关信息都走配置。
119
+
120
+ ## 已知问题
121
+
122
+ - `xmind2testcase_lq.webtool` 会把 `running.log`、`uploads/`、`data.db3`
123
+ 写在**包目录内**(沿用上游行为)。在只读的 site-packages 或受限环境下运行
124
+ `xmind2testcase-lq webtool` 可能失败。命令行转换功能不受影响。
125
+
126
+ ## 许可证与致谢
127
+
128
+ 本项目基于 MIT 许可证发布,完整许可证文本见 [LICENSE](LICENSE)。
129
+
130
+ 上游项目:[zhuifengshen/xmind2testcase](https://github.com/zhuifengshen/xmind2testcase),
131
+ 版权归 Devin 与 Toby Qin 所有。本分支保留了原始的 MIT 版权声明,仅在
132
+ 上游 1.5.0 基础上做了上述定制改动。
@@ -0,0 +1,110 @@
1
+ # xmind2testcase-lq
2
+
3
+ > **这是 [xmind2testcase](https://github.com/zhuifengshen/xmind2testcase) 的定制分支(fork),不是上游官方版本。**
4
+ > 面向「XMind 思维导图 → 禅道(ZenTao)测试用例 CSV」这一条链路做了调整,
5
+ > 并把原本写死在源码里的项目相关信息改成了可配置项。
6
+
7
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
8
+
9
+ ## 与上游的主要差异
10
+
11
+ | 方面 | 上游 `xmind2testcase` 1.5.0 | 本分支 `xmind2testcase-lq` |
12
+ |---|---|---|
13
+ | 导入包名 | `xmind2testcase` | `xmind2testcase_lq` |
14
+ | 禅道 CSV 表头 | 9 列(所属模块 / 用例标题 / …) | **10 列**(用例编号 / 用例描述 / 测试类型 / 前置条件 / 操作步骤 / 期望结果 / 通过准则 / 实际输出 / 测试结论 / 测试用例优先级) |
15
+ | 用例编号 | 无此列 | `<前缀>-<xmind文件名>-001`,**前缀可配置** |
16
+ | 用例编号前缀 | — | 参数 `case_id_prefix` > 环境变量 `XMIND2TESTCASE_CASE_ID_PREFIX` > 空 |
17
+ | 测试类型 | `1` / `2`(手动 / 自动) | 中文类型:正向功能 / 反向功能 / 接口 / 性能 / 界面 / 安全性 |
18
+ | 优先级映射 | 高 / 中 / 低 | 一级 / 二级 / 三级 / 四级 |
19
+ | 前置条件拼接 | 用 `\n----\n` 分隔 | 直接相连(逐条去空白) |
20
+ | 期望结果 | 只取第一条 | 支持多条,逐条编号后用换行连接 |
21
+ | 只取行数据 | 无 | 新增 `xmind_to_rows()`,不落盘 |
22
+ | 日志文件 | 无(或写死路径) | 环境变量 `XMIND2TESTCASE_LOG` 控制,目录自动创建 |
23
+ | `webtool` 包位置 | 顶层包 `webtool` | 收进 `xmind2testcase_lq.webtool`,不污染全局命名空间 |
24
+ | CLI 命令 | `xmind2testcase` | `xmind2testcase-lq` |
25
+
26
+ 完整的逐文件差异见 [FORK_NOTES.md](FORK_NOTES.md)。
27
+
28
+ ## 安装
29
+
30
+ ```bash
31
+ pip install xmind2testcase-lq
32
+ ```
33
+
34
+ 从源码安装:
35
+
36
+ ```bash
37
+ git clone https://gitee.com/QiLi1998/xmind2testcase-lq.git
38
+ cd xmind2testcase-lq
39
+ pip install .
40
+ ```
41
+
42
+ ## 使用
43
+
44
+ ### 作为库调用
45
+
46
+ ```python
47
+ from xmind2testcase_lq.zentao import xmind_to_rows, xmind_to_zentao_csv_file
48
+
49
+ # 不设置前缀:编号形如 登录功能-001
50
+ rows = xmind_to_rows("用例.xmind")
51
+
52
+ # 显式指定前缀:编号形如 我的项目-登录功能-001
53
+ rows = xmind_to_rows("用例.xmind", case_id_prefix="我的项目")
54
+
55
+ # 直接落盘成 CSV
56
+ csv_path = xmind_to_zentao_csv_file("用例.xmind", case_id_prefix="我的项目")
57
+ ```
58
+
59
+ `rows` 第一行是表头,其后每行是一条用例。
60
+
61
+ ### 通过环境变量配置
62
+
63
+ 适合不想改代码、或要走命令行的情况:
64
+
65
+ ```bash
66
+ # Linux / macOS
67
+ export XMIND2TESTCASE_CASE_ID_PREFIX="我的项目"
68
+
69
+ # Windows PowerShell
70
+ $env:XMIND2TESTCASE_CASE_ID_PREFIX = "我的项目"
71
+ ```
72
+
73
+ ```python
74
+ rows = xmind_to_rows("用例.xmind") # 自动读取上面的环境变量
75
+ ```
76
+
77
+ ### 命令行
78
+
79
+ ```bash
80
+ xmind2testcase-lq 用例.xmind -csv
81
+ xmind2testcase-lq 用例.xmind -csv --case-id-prefix=我的项目
82
+ xmind2testcase-lq 用例.xmind # 同时输出 json / xml / csv
83
+ xmind2testcase-lq webtool 8000 # 启动本地 Web 转换工具
84
+ ```
85
+
86
+ ## 配置项
87
+
88
+ 全部通过环境变量控制,也可以用函数参数覆盖(参数优先级更高)。
89
+
90
+ | 环境变量 | 作用 | 默认值 |
91
+ |---|---|---|
92
+ | `XMIND2TESTCASE_CASE_ID_PREFIX` | 用例编号前缀 | 空(编号不含前缀) |
93
+ | `XMIND2TESTCASE_LOG` | 日志文件路径,父目录不存在时自动创建 | 空(只输出到控制台) |
94
+ | `XMIND2TESTCASE_LOG_LEVEL` | 日志级别 | `INFO` |
95
+
96
+ > 设计原则:**源码中不出现任何本机路径或具体项目名**,所有环境相关信息都走配置。
97
+
98
+ ## 已知问题
99
+
100
+ - `xmind2testcase_lq.webtool` 会把 `running.log`、`uploads/`、`data.db3`
101
+ 写在**包目录内**(沿用上游行为)。在只读的 site-packages 或受限环境下运行
102
+ `xmind2testcase-lq webtool` 可能失败。命令行转换功能不受影响。
103
+
104
+ ## 许可证与致谢
105
+
106
+ 本项目基于 MIT 许可证发布,完整许可证文本见 [LICENSE](LICENSE)。
107
+
108
+ 上游项目:[zhuifengshen/xmind2testcase](https://github.com/zhuifengshen/xmind2testcase),
109
+ 版权归 Devin 与 Toby Qin 所有。本分支保留了原始的 MIT 版权声明,仅在
110
+ 上游 1.5.0 基础上做了上述定制改动。
@@ -0,0 +1,42 @@
1
+ [build-system]
2
+ requires = ["setuptools>=77", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "xmind2testcase-lq"
7
+ dynamic = ["version"]
8
+ description = "XMind2TestCase 的定制分支:面向禅道导入的中文测试用例转换,用例编号前缀可配置"
9
+ readme = "README.md"
10
+ requires-python = ">=3.8"
11
+ license = "MIT"
12
+ license-files = ["LICENSE"]
13
+ authors = [{ name = "liqin" }]
14
+ keywords = ["xmind", "testcase", "zentao", "testlink", "思维导图", "测试用例", "xmind2testcase"]
15
+ classifiers = [
16
+ "Programming Language :: Python :: 3",
17
+ "Operating System :: OS Independent",
18
+ "Natural Language :: Chinese (Simplified)",
19
+ "Topic :: Software Development :: Testing",
20
+ ]
21
+ dependencies = [
22
+ "xmind",
23
+ "flask",
24
+ "arrow",
25
+ ]
26
+
27
+ [project.urls]
28
+ Homepage = "https://gitee.com/QiLi1998/xmind2testcase-lq"
29
+ Repository = "https://gitee.com/QiLi1998/xmind2testcase-lq"
30
+ "上游项目" = "https://github.com/zhuifengshen/xmind2testcase"
31
+
32
+ [project.scripts]
33
+ xmind2testcase-lq = "xmind2testcase_lq.cli:cli_main"
34
+
35
+ [tool.setuptools.dynamic]
36
+ version = { attr = "xmind2testcase_lq.__about__.__version__" }
37
+
38
+ [tool.setuptools.packages.find]
39
+ include = ["xmind2testcase_lq*"]
40
+
41
+ [tool.setuptools.package-data]
42
+ "xmind2testcase_lq.webtool" = ["schema.sql", "templates/*", "static/css/*", "static/guide/*"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,15 @@
1
+ __title__ = 'xmind2testcase-lq'
2
+ __description__ = 'XMind2TestCase 的定制分支:面向禅道导入的中文测试用例转换,用例编号前缀可配置'
3
+ __keywords__ = 'xmind, testcase, zentao, testlink, 思维导图, 测试用例, xmind2testcase'
4
+ __url__ = 'https://gitee.com/QiLi1998/xmind2testcase-lq'
5
+ __author__ = 'liqin'
6
+ __author_email__ = ''
7
+ __version__ = '1.5.0.1'
8
+ __license__ = 'MIT'
9
+ __cake__ = u'\u2728 \U0001f370 \u2728'
10
+
11
+ # 上游溯源信息(MIT 许可证要求保留原始版权声明,见 LICENSE)
12
+ __upstream_title__ = 'xmind2testcase'
13
+ __upstream_version__ = '1.5.0'
14
+ __upstream_url__ = 'https://github.com/zhuifengshen/xmind2testcase'
15
+ __upstream_author__ = 'Devin'
@@ -0,0 +1,117 @@
1
+ #!/usr/bin/env python
2
+ # _*_ coding:utf-8 _*_
3
+ """命令行入口。
4
+
5
+ 与上游的差异
6
+ ------------
7
+ * 日志文件路径改为由环境变量 ``XMIND2TESTCASE_LOG`` 控制(见
8
+ :mod:`xmind2testcase_lq.config`),**不再写死本机绝对路径**;
9
+ 未设置时只输出到控制台。
10
+ * ``webtool`` 改为**延迟导入**。上游在模块顶层就 ``import webtool``,
11
+ 而 ``webtool.application`` 在导入时会自行配置 root logger,
12
+ 导致紧随其后的 ``logging.basicConfig`` 永远被跳过(哑配置)。
13
+ 改为延迟导入后日志配置才真正生效,同时让不依赖 Flask 的场景可以更轻量地导入本模块。
14
+ * 新增 ``--case-id-prefix=XXX`` 选项,等价于设置
15
+ ``XMIND2TESTCASE_CASE_ID_PREFIX``。
16
+ """
17
+ import logging
18
+ import sys
19
+ from pathlib import Path
20
+
21
+ from xmind2testcase_lq import config
22
+ from xmind2testcase_lq.testlink import xmind_to_testlink_xml_file
23
+ from xmind2testcase_lq.utils import get_absolute_path, xmind_testcase_to_json_file
24
+ from xmind2testcase_lq.zentao import xmind_to_zentao_csv_file
25
+
26
+ _log_file = config.resolve_log_file()
27
+ if _log_file:
28
+ Path(_log_file).parent.mkdir(parents=True, exist_ok=True)
29
+ logging.basicConfig(
30
+ level=config.resolve_log_level(),
31
+ filename=_log_file,
32
+ filemode='a',
33
+ format=config.LOG_FORMAT,
34
+ datefmt=config.LOG_DATE_FORMAT,
35
+ force=True,
36
+ )
37
+
38
+ using_doc = """
39
+ Xmind2Testcase is a tool to parse xmind file into testcase file, which will help you generate a testlink recognized
40
+ xml file or a zentao recognized cvs file, then you can import it into testlink or zentao.
41
+
42
+ Usage:
43
+ xmind2testcase-lq [path_to_xmind_file] [-csv] [-xml] [-json]
44
+ xmind2testcase-lq [webtool] [port_num]
45
+
46
+ Example:
47
+ xmind2testcase-lq /path/to/testcase.xmind => output testcase.csv、testcase.xml、testcase.json
48
+ xmind2testcase-lq /path/to/testcase.xmind -csv => output testcase.csv
49
+ xmind2testcase-lq /path/to/testcase.xmind -xml => output testcase.xml
50
+ xmind2testcase-lq /path/to/testcase.xmind -json => output testcase.json
51
+ xmind2testcase-lq webtool => launch the web testcase conversion tool locally: 127.0.0.1:5001
52
+ xmind2testcase-lq webtool 8000 => launch the web testcase conversion tool locally: 127.0.0.1:8000
53
+
54
+ Options:
55
+ --case-id-prefix=<前缀> 用例编号前缀,例如 --case-id-prefix=我的项目
56
+ 等价于设置环境变量 XMIND2TESTCASE_CASE_ID_PREFIX
57
+ """
58
+
59
+
60
+ def _pop_case_id_prefix(argv):
61
+ """从 argv 中摘出 --case-id-prefix=XXX,返回 (剩余参数, 前缀或 None)"""
62
+ rest, prefix = [], None
63
+ for arg in argv:
64
+ if arg.startswith('--case-id-prefix='):
65
+ prefix = arg.split('=', 1)[1]
66
+ else:
67
+ rest.append(arg)
68
+ return rest, prefix
69
+
70
+
71
+ def cli_main():
72
+ argv, case_id_prefix = _pop_case_id_prefix(sys.argv)
73
+ prefix = config.resolve_case_id_prefix(case_id_prefix)
74
+
75
+ if len(argv) > 1 and argv[1].endswith('.xmind'):
76
+ xmind_file = get_absolute_path(argv[1])
77
+ logging.info('Start to convert XMind file: %s', xmind_file)
78
+
79
+ if len(argv) == 3 and argv[2] == '-json':
80
+ testlink_json_file = xmind_testcase_to_json_file(xmind_file)
81
+ logging.info('Convert XMind file to testcase json file successfully: %s', testlink_json_file)
82
+ elif len(argv) == 3 and argv[2] == '-xml':
83
+ testlink_xml_file = xmind_to_testlink_xml_file(xmind_file)
84
+ logging.info('Convert XMind file to testlink xml files successfully: %s', testlink_xml_file)
85
+ elif len(argv) == 3 and argv[2] == '-csv':
86
+ zentao_csv_file = xmind_to_zentao_csv_file(xmind_file, case_id_prefix=prefix)
87
+ logging.info('Convert XMind file to zentao csv file successfully: %s', zentao_csv_file)
88
+ else:
89
+ testlink_json_file = xmind_testcase_to_json_file(xmind_file)
90
+ testlink_xml_file = xmind_to_testlink_xml_file(xmind_file)
91
+ zentao_csv_file = xmind_to_zentao_csv_file(xmind_file, case_id_prefix=prefix)
92
+ logging.info('Convert XMind file successfully: \n'
93
+ '1、 testcase json file(%s)\n'
94
+ '2、 testlink xml file(%s)\n'
95
+ '3、 zentao csv file(%s)',
96
+ testlink_json_file,
97
+ testlink_xml_file,
98
+ zentao_csv_file)
99
+ elif len(argv) > 1 and argv[1] == 'webtool':
100
+ # 延迟导入:避免只用命令行转换功能时也拉起 Flask 及其日志配置
101
+ from xmind2testcase_lq.webtool.application import launch
102
+
103
+ if len(argv) == 3:
104
+ try:
105
+ port = int(argv[2])
106
+ launch(port=port)
107
+ except ValueError:
108
+ launch()
109
+ else:
110
+ launch()
111
+
112
+ else:
113
+ print(using_doc)
114
+
115
+
116
+ if __name__ == '__main__':
117
+ cli_main()
@@ -0,0 +1,80 @@
1
+ """xmind2testcase_lq 的定制项集中配置。
2
+
3
+ 为什么需要这个模块
4
+ ------------------
5
+ 上游代码把两处**与具体环境绑定**的值直接写死在源码里,公开发布会有问题:
6
+
7
+ * ``zentao.py`` 把用例编号前缀写死成某个内网项目名 —— 一旦发布到公共源,
8
+ 这个名称就永久公开且无法撤回;
9
+ * ``cli.py`` 把日志文件写死成本机绝对路径(``D:/...``)—— 换一台机器就不成立。
10
+
11
+ 本模块把这些值集中到一处,按 **显式参数 > 环境变量 > 通用默认值** 的顺序解析,
12
+ 源码中不再出现任何本机路径或内网业务信息。
13
+
14
+ 环境变量
15
+ --------
16
+ ``XMIND2TESTCASE_CASE_ID_PREFIX``
17
+ 用例编号前缀,默认空串。
18
+ 设置后编号形如 ``<前缀>-<xmind文件名>-001``;未设置时形如 ``<xmind文件名>-001``。
19
+ ``XMIND2TESTCASE_LOG``
20
+ CLI 日志文件路径,默认空串(不写文件,只输出到控制台)。父目录不存在时自动创建。
21
+ ``XMIND2TESTCASE_LOG_LEVEL``
22
+ 日志级别,默认 ``INFO``。
23
+
24
+ 用法
25
+ ----
26
+ ::
27
+
28
+ import os
29
+ os.environ["XMIND2TESTCASE_CASE_ID_PREFIX"] = "我的项目"
30
+ from xmind2testcase_lq.zentao import xmind_to_rows
31
+ rows = xmind_to_rows("用例.xmind")
32
+
33
+ 也可以绕开环境变量,直接传参(优先级更高)::
34
+
35
+ rows = xmind_to_rows("用例.xmind", case_id_prefix="我的项目")
36
+ """
37
+ from __future__ import annotations
38
+
39
+ import logging
40
+ import os
41
+ from typing import Optional
42
+
43
+ ENV_CASE_ID_PREFIX = "XMIND2TESTCASE_CASE_ID_PREFIX"
44
+ ENV_LOG_FILE = "XMIND2TESTCASE_LOG"
45
+ ENV_LOG_LEVEL = "XMIND2TESTCASE_LOG_LEVEL"
46
+
47
+ # 内置默认值:保持通用,不含任何业务信息
48
+ DEFAULT_CASE_ID_PREFIX = ""
49
+ DEFAULT_LOG_LEVEL = "INFO"
50
+
51
+ # 与上游一致的日志格式
52
+ LOG_FORMAT = "%(asctime)s %(name)s %(levelname)s [%(module)s - %(funcName)s]: %(message)s"
53
+ LOG_DATE_FORMAT = "%Y/%m/%d %H:%M:%S"
54
+
55
+
56
+ def resolve_case_id_prefix(explicit: Optional[str] = None) -> str:
57
+ """解析用例编号前缀。显式参数 > 环境变量 > 空串。"""
58
+ if explicit is not None:
59
+ return explicit.strip()
60
+ return os.environ.get(ENV_CASE_ID_PREFIX, DEFAULT_CASE_ID_PREFIX).strip()
61
+
62
+
63
+ def resolve_log_file(explicit: Optional[str] = None) -> str:
64
+ """解析日志文件路径。返回空串表示不写文件。"""
65
+ if explicit is not None:
66
+ return explicit.strip()
67
+ return os.environ.get(ENV_LOG_FILE, "").strip()
68
+
69
+
70
+ def resolve_log_level(explicit: Optional[str] = None) -> int:
71
+ """解析日志级别,返回 ``logging`` 模块的整型常量;无法识别时回退 INFO。"""
72
+ raw = explicit if explicit is not None else os.environ.get(ENV_LOG_LEVEL, DEFAULT_LOG_LEVEL)
73
+ name = (raw or DEFAULT_LOG_LEVEL).strip().upper()
74
+ return getattr(logging, name, logging.INFO)
75
+
76
+
77
+ def build_case_id(prefix: str, xmind_filename: str, case_index: int) -> str:
78
+ """拼装用例编号:``<前缀>-<xmind文件名>-<三位序号>``,前缀为空时自动省略。"""
79
+ parts = [p for p in (prefix.strip(), xmind_filename.strip(), f"{case_index:03d}") if p]
80
+ return "-".join(parts)
@@ -0,0 +1,28 @@
1
+ #!/usr/bin/env python
2
+ # _*_ coding:utf-8 _*_
3
+
4
+
5
+ TAG_XML = 'xml'
6
+
7
+ TAG_TESTSUITE = 'testsuite'
8
+ TAG_DETAILS = 'details'
9
+
10
+ TAG_TESTCASE = 'testcase'
11
+ TAG_VERSION = 'version'
12
+ TAG_SUMMARY = 'summary'
13
+ TAG_PRECONDITIONS = 'preconditions'
14
+ TAG_IMPORTANCE = 'importance'
15
+ TAG_ESTIMATED_EXEC_DURATION = 'estimated_exec_duration'
16
+ TAG_STATUS = 'status'
17
+ TAG_IS_OPEN = 'is_open'
18
+ TAG_ACTIVE = 'active'
19
+ TAG_STEPS = 'steps'
20
+ TAG_STEP = 'step'
21
+ TAG_STEP_NUMBER = 'step_number'
22
+ TAG_ACTIONS = 'actions'
23
+ TAG_EXPECTEDRESULTS = 'expectedresults'
24
+ TAG_EXECUTION_TYPE = 'execution_type'
25
+
26
+ ATTR_NMAE = 'name'
27
+ ATTR_ID = 'id'
28
+ ATTR_INTERNALID = 'internalid'
@@ -0,0 +1,123 @@
1
+ #!/usr/bin/env python
2
+ # _*_ coding:utf-8 _*_
3
+
4
+ """
5
+ testlink.testlink
6
+ """
7
+
8
+
9
+ class TestSuite(object):
10
+
11
+ def __init__(self, name='', details='', testcase_list=None, sub_suites=None, statistics=None):
12
+ """
13
+ TestSuite
14
+ :param name: test suite name
15
+ :param details: test suite detail infomation
16
+ :param testcase_list: test case list
17
+ :param sub_suites: sub test suite list
18
+ :param statistics: testsuite statistics info {'case_num': 0, 'non_execution': 0, 'pass': 0, 'failed': 0, 'blocked': 0, 'skipped': 0}
19
+ """
20
+ self.name = name
21
+ self.details = details
22
+ self.testcase_list = testcase_list
23
+ self.sub_suites = sub_suites
24
+ self.statistics = statistics
25
+
26
+ def to_dict(self):
27
+ data = {
28
+ 'name': self.name,
29
+ 'details': self.details,
30
+ 'testcase_list': [],
31
+ 'sub_suites': []
32
+ }
33
+
34
+ if self.sub_suites:
35
+ for suite in self.sub_suites:
36
+ data['sub_suites'].append(suite.to_dict())
37
+
38
+ if self.testcase_list:
39
+ for case in self.testcase_list:
40
+ data['testcase_list'].append(case.to_dict())
41
+
42
+ if self.statistics:
43
+ data['statistics'] = self.statistics
44
+
45
+ return data
46
+
47
+
48
+ class TestCase(object):
49
+
50
+ def __init__(self, name='', version=1, summary='', preconditions='', execution_type=1, importance=2, estimated_exec_duration=3, status=7, result=0, steps=None):
51
+ """
52
+ TestCase
53
+ :param name: test case name
54
+ :param version: test case version infomation
55
+ :param summary: test case summary infomation
56
+ :param preconditions: test case pre condition
57
+ :param execution_type: manual:1 or automate:2
58
+ :param importance: high:1, middle:2, low:3
59
+ :param estimated_exec_duration: estimated execution duration
60
+ :param status: draft:1, ready ro review:2, review in progress:3, rework:4, obsolete:5, future:6, final:7
61
+ :param result: non-execution:0, pass:1, failed:2, blocked:3, skipped:4
62
+ :param steps: test case step list
63
+ """
64
+ self.name = name
65
+ self.version = version
66
+ self.summary = summary
67
+ self.preconditions = preconditions
68
+ self.execution_type = execution_type
69
+ self.importance = importance
70
+ self.estimated_exec_duration = estimated_exec_duration
71
+ self.status = status
72
+ self.result = result
73
+ self.steps = steps
74
+
75
+ def to_dict(self):
76
+ data = {
77
+ 'name': self.name,
78
+ 'version': self.version, # TODO(devin): get version content
79
+ 'summary': self.summary,
80
+ 'preconditions': self.preconditions,
81
+ 'execution_type': self.execution_type,
82
+ 'importance': self.importance,
83
+ 'estimated_exec_duration': self.estimated_exec_duration, # TODO(devin): get estimated content
84
+ 'status': self.status, # TODO(devin): get status content
85
+ 'result': self.result,
86
+ 'steps': []
87
+ }
88
+
89
+ if self.steps:
90
+ for step in self.steps:
91
+ data['steps'].append(step.to_dict())
92
+
93
+ return data
94
+
95
+
96
+ class TestStep(object):
97
+
98
+ def __init__(self, step_number=1, actions='', expectedresults='', execution_type=1, result=0):
99
+ """
100
+ TestStep
101
+ :param step_number: test step number
102
+ :param actions: test step actions
103
+ :param expectedresults: test step expected results
104
+ :param execution_type: test step execution type
105
+ :param result: non-execution:0, pass:1, failed:2, blocked:3, skipped:4
106
+ """
107
+ self.step_number = step_number
108
+ self.actions = actions
109
+ self.expectedresults = expectedresults
110
+ self.execution_type = execution_type # TODO(devin): get execution type content
111
+ self.result = result
112
+
113
+ def to_dict(self):
114
+ data = {
115
+ 'step_number': self.step_number,
116
+ 'actions': self.actions,
117
+ 'expectedresults': self.expectedresults,
118
+ 'execution_type': self.execution_type,
119
+ 'result': self.result
120
+ }
121
+
122
+ return data
123
+