diff --git a/.github/ workflows/test.yml b/.github/ workflows/test.yml new file mode 100644 index 0000000..9ce05ec --- /dev/null +++ b/.github/ workflows/test.yml @@ -0,0 +1,35 @@ +name: test + +on: + push: + branches: + - main + paths: + - 'tests/**' + pull_request: + types: [ opened, synchronize ] + paths: + - 'modules/apihelper/**' + - 'modules/wiki/**' + - 'tests/**' + +jobs: + pytest: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Set up Python 3.10 + uses: actions/setup-python@v3 + with: + python-version: "3.10" + - name: Install poetry + run: | + pip install --upgrade poetry + poetry config virtualenvs.create false + - name: Install dependencies + run: | + poetry install + poetry install --extras test + - name: Test with pytest + run: | + python -m pytest \ No newline at end of file diff --git a/.gitignore b/.gitignore index 425ab24..1bfefd1 100644 --- a/.gitignore +++ b/.gitignore @@ -40,6 +40,10 @@ logs/ ### private plugins ### plugins/private + +# Unit test / coverage reports +.pytest_cache + ### mtp ### paimon.session PaimonBot.session diff --git a/poetry.lock b/poetry.lock index 364cc16..35d7787 100644 --- a/poetry.lock +++ b/poetry.lock @@ -316,6 +316,14 @@ sortedcontainers = ">=2.4.0,<3.0.0" aioredis = ["aioredis (>=2.0.1,<3.0.0)"] lua = ["lupa (>=1.13,<2.0)"] +[[package]] +name = "flaky" +version = "3.7.0" +description = "Plugin for nose or pytest that automatically reruns flaky tests." +category = "main" +optional = true +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" + [[package]] name = "frozenlist" version = "1.3.1" @@ -326,7 +334,7 @@ python-versions = ">=3.7" [[package]] name = "genshin" -version = "1.2.3" +version = "1.2.4" description = "An API wrapper for Genshin Impact." category = "main" optional = false @@ -347,7 +355,7 @@ geetest = ["rsa"] type = "git" url = "https://github.com/thesadru/genshin.py" reference = "HEAD" -resolved_reference = "082bfc02d8d0e53d840e5d66a66bfc2e5da8a2bb" +resolved_reference = "e195dea14a28450fe9ee819e6e77399a4111e785" [[package]] name = "greenlet" @@ -445,6 +453,14 @@ zipp = {version = ">=3.1.0", markers = "python_version < \"3.10\""} docs = ["jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx"] testing = ["pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)"] +[[package]] +name = "iniconfig" +version = "1.1.1" +description = "iniconfig: brain-dead simple config-ini parsing" +category = "main" +optional = true +python-versions = "*" + [[package]] name = "Jinja2" version = "3.1.2" @@ -459,6 +475,20 @@ MarkupSafe = ">=2.0" [package.extras] i18n = ["Babel (>=2.7)"] +[[package]] +name = "lxml" +version = "4.9.1" +description = "Powerful and Pythonic XML processing library combining libxml2/libxslt with the ElementTree API." +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, != 3.4.*" + +[package.extras] +cssselect = ["cssselect (>=0.7)"] +html5 = ["html5lib"] +htmlsoup = ["BeautifulSoup4"] +source = ["Cython (>=0.29.7)"] + [[package]] name = "Mako" version = "1.2.2" @@ -564,6 +594,26 @@ pyee = "8.1.0" typing-extensions = {version = "*", markers = "python_version <= \"3.8\""} websockets = "10.1" +[[package]] +name = "pluggy" +version = "1.0.0" +description = "plugin and hook calling mechanisms for python" +category = "main" +optional = true +python-versions = ">=3.6" + +[package.extras] +dev = ["pre-commit", "tox"] +testing = ["pytest", "pytest-benchmark"] + +[[package]] +name = "py" +version = "1.11.0" +description = "library with cross-python path, ini-parsing, io, code, log facilities" +category = "main" +optional = true +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" + [[package]] name = "pyaes" version = "1.6.1" @@ -666,6 +716,40 @@ category = "main" optional = true python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +[[package]] +name = "pytest" +version = "7.1.3" +description = "pytest: simple powerful testing with Python" +category = "main" +optional = true +python-versions = ">=3.7" + +[package.dependencies] +attrs = ">=19.2.0" +colorama = {version = "*", markers = "sys_platform == \"win32\""} +iniconfig = "*" +packaging = "*" +pluggy = ">=0.12,<2.0" +py = ">=1.8.2" +tomli = ">=1.0.0" + +[package.extras] +testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "xmlschema"] + +[[package]] +name = "pytest-asyncio" +version = "0.19.0" +description = "Pytest support for asyncio" +category = "main" +optional = true +python-versions = ">=3.7" + +[package.dependencies] +pytest = ">=6.1.0" + +[package.extras] +testing = ["coverage (>=6.2)", "flaky (>=3.5.0)", "hypothesis (>=5.7.1)", "mypy (>=0.931)", "pytest-trio (>=0.7.0)"] + [[package]] name = "python-dotenv" version = "0.20.0" @@ -1003,11 +1087,12 @@ testing = ["func-timeout", "jaraco.itertools", "pytest (>=6)", "pytest-black (>= [extras] pyro = ["Pyrogram", "TgCrypto"] +test = ["pytest", "pytest-asyncio", "flaky"] [metadata] lock-version = "1.1" python-versions = "^3.8" -content-hash = "46df07459129ef3f1c644654d98d7d641479c2acedd6cdb3339c1d3714f93517" +content-hash = "b9b3558891d59a03b92eed308b100ed99a0fbad101ef5aaab27c4b66dc940246" [metadata.files] aiofiles = [ @@ -1219,6 +1304,10 @@ fakeredis = [ {file = "fakeredis-1.9.1-py3-none-any.whl", hash = "sha256:b9830f68dafafc0abe6c037775765166e9e2ff6b0da8abd3838eb2c3910f8e65"}, {file = "fakeredis-1.9.1.tar.gz", hash = "sha256:e884776d7d0216e9c6c514527718259cfbd555777b36ba403ae680bd1489f7a1"}, ] +flaky = [ + {file = "flaky-3.7.0-py2.py3-none-any.whl", hash = "sha256:d6eda73cab5ae7364504b7c44670f70abed9e75f77dd116352f662817592ec9c"}, + {file = "flaky-3.7.0.tar.gz", hash = "sha256:3ad100780721a1911f57a165809b7ea265a7863305acb66708220820caf8aa0d"}, +] frozenlist = [ {file = "frozenlist-1.3.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:5f271c93f001748fc26ddea409241312a75e13466b06c94798d1a341cf0e6989"}, {file = "frozenlist-1.3.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9c6ef8014b842f01f5d2b55315f1af5cbfde284eb184075c189fd657c2fd8204"}, @@ -1362,10 +1451,86 @@ importlib-resources = [ {file = "importlib_resources-5.9.0-py3-none-any.whl", hash = "sha256:f78a8df21a79bcc30cfd400bdc38f314333de7c0fb619763f6b9dabab8268bb7"}, {file = "importlib_resources-5.9.0.tar.gz", hash = "sha256:5481e97fb45af8dcf2f798952625591c58fe599d0735d86b10f54de086a61681"}, ] +iniconfig = [ + {file = "iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"}, + {file = "iniconfig-1.1.1.tar.gz", hash = "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32"}, +] Jinja2 = [ {file = "Jinja2-3.1.2-py3-none-any.whl", hash = "sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61"}, {file = "Jinja2-3.1.2.tar.gz", hash = "sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852"}, ] +lxml = [ + {file = "lxml-4.9.1-cp27-cp27m-macosx_10_15_x86_64.whl", hash = "sha256:98cafc618614d72b02185ac583c6f7796202062c41d2eeecdf07820bad3295ed"}, + {file = "lxml-4.9.1-cp27-cp27m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c62e8dd9754b7debda0c5ba59d34509c4688f853588d75b53c3791983faa96fc"}, + {file = "lxml-4.9.1-cp27-cp27m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:21fb3d24ab430fc538a96e9fbb9b150029914805d551deeac7d7822f64631dfc"}, + {file = "lxml-4.9.1-cp27-cp27m-win32.whl", hash = "sha256:86e92728ef3fc842c50a5cb1d5ba2bc66db7da08a7af53fb3da79e202d1b2cd3"}, + {file = "lxml-4.9.1-cp27-cp27m-win_amd64.whl", hash = "sha256:4cfbe42c686f33944e12f45a27d25a492cc0e43e1dc1da5d6a87cbcaf2e95627"}, + {file = "lxml-4.9.1-cp27-cp27mu-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:dad7b164905d3e534883281c050180afcf1e230c3d4a54e8038aa5cfcf312b84"}, + {file = "lxml-4.9.1-cp27-cp27mu-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:a614e4afed58c14254e67862456d212c4dcceebab2eaa44d627c2ca04bf86837"}, + {file = "lxml-4.9.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:f9ced82717c7ec65a67667bb05865ffe38af0e835cdd78728f1209c8fffe0cad"}, + {file = "lxml-4.9.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:d9fc0bf3ff86c17348dfc5d322f627d78273eba545db865c3cd14b3f19e57fa5"}, + {file = "lxml-4.9.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:e5f66bdf0976ec667fc4594d2812a00b07ed14d1b44259d19a41ae3fff99f2b8"}, + {file = "lxml-4.9.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:fe17d10b97fdf58155f858606bddb4e037b805a60ae023c009f760d8361a4eb8"}, + {file = "lxml-4.9.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:8caf4d16b31961e964c62194ea3e26a0e9561cdf72eecb1781458b67ec83423d"}, + {file = "lxml-4.9.1-cp310-cp310-win32.whl", hash = "sha256:4780677767dd52b99f0af1f123bc2c22873d30b474aa0e2fc3fe5e02217687c7"}, + {file = "lxml-4.9.1-cp310-cp310-win_amd64.whl", hash = "sha256:b122a188cd292c4d2fcd78d04f863b789ef43aa129b233d7c9004de08693728b"}, + {file = "lxml-4.9.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:be9eb06489bc975c38706902cbc6888f39e946b81383abc2838d186f0e8b6a9d"}, + {file = "lxml-4.9.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:f1be258c4d3dc609e654a1dc59d37b17d7fef05df912c01fc2e15eb43a9735f3"}, + {file = "lxml-4.9.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:927a9dd016d6033bc12e0bf5dee1dde140235fc8d0d51099353c76081c03dc29"}, + {file = "lxml-4.9.1-cp35-cp35m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9232b09f5efee6a495a99ae6824881940d6447debe272ea400c02e3b68aad85d"}, + {file = "lxml-4.9.1-cp35-cp35m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:04da965dfebb5dac2619cb90fcf93efdb35b3c6994fea58a157a834f2f94b318"}, + {file = "lxml-4.9.1-cp35-cp35m-win32.whl", hash = "sha256:4d5bae0a37af799207140652a700f21a85946f107a199bcb06720b13a4f1f0b7"}, + {file = "lxml-4.9.1-cp35-cp35m-win_amd64.whl", hash = "sha256:4878e667ebabe9b65e785ac8da4d48886fe81193a84bbe49f12acff8f7a383a4"}, + {file = "lxml-4.9.1-cp36-cp36m-macosx_10_15_x86_64.whl", hash = "sha256:1355755b62c28950f9ce123c7a41460ed9743c699905cbe664a5bcc5c9c7c7fb"}, + {file = "lxml-4.9.1-cp36-cp36m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:bcaa1c495ce623966d9fc8a187da80082334236a2a1c7e141763ffaf7a405067"}, + {file = "lxml-4.9.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6eafc048ea3f1b3c136c71a86db393be36b5b3d9c87b1c25204e7d397cee9536"}, + {file = "lxml-4.9.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:13c90064b224e10c14dcdf8086688d3f0e612db53766e7478d7754703295c7c8"}, + {file = "lxml-4.9.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:206a51077773c6c5d2ce1991327cda719063a47adc02bd703c56a662cdb6c58b"}, + {file = "lxml-4.9.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:e8f0c9d65da595cfe91713bc1222af9ecabd37971762cb830dea2fc3b3bb2acf"}, + {file = "lxml-4.9.1-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:8f0a4d179c9a941eb80c3a63cdb495e539e064f8054230844dcf2fcb812b71d3"}, + {file = "lxml-4.9.1-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:830c88747dce8a3e7525defa68afd742b4580df6aa2fdd6f0855481e3994d391"}, + {file = "lxml-4.9.1-cp36-cp36m-win32.whl", hash = "sha256:1e1cf47774373777936c5aabad489fef7b1c087dcd1f426b621fda9dcc12994e"}, + {file = "lxml-4.9.1-cp36-cp36m-win_amd64.whl", hash = "sha256:5974895115737a74a00b321e339b9c3f45c20275d226398ae79ac008d908bff7"}, + {file = "lxml-4.9.1-cp37-cp37m-macosx_10_15_x86_64.whl", hash = "sha256:1423631e3d51008871299525b541413c9b6c6423593e89f9c4cfbe8460afc0a2"}, + {file = "lxml-4.9.1-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:2aaf6a0a6465d39b5ca69688fce82d20088c1838534982996ec46633dc7ad6cc"}, + {file = "lxml-4.9.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:9f36de4cd0c262dd9927886cc2305aa3f2210db437aa4fed3fb4940b8bf4592c"}, + {file = "lxml-4.9.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:ae06c1e4bc60ee076292e582a7512f304abdf6c70db59b56745cca1684f875a4"}, + {file = "lxml-4.9.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:57e4d637258703d14171b54203fd6822fda218c6c2658a7d30816b10995f29f3"}, + {file = "lxml-4.9.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:6d279033bf614953c3fc4a0aa9ac33a21e8044ca72d4fa8b9273fe75359d5cca"}, + {file = "lxml-4.9.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:a60f90bba4c37962cbf210f0188ecca87daafdf60271f4c6948606e4dabf8785"}, + {file = "lxml-4.9.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:6ca2264f341dd81e41f3fffecec6e446aa2121e0b8d026fb5130e02de1402785"}, + {file = "lxml-4.9.1-cp37-cp37m-win32.whl", hash = "sha256:27e590352c76156f50f538dbcebd1925317a0f70540f7dc8c97d2931c595783a"}, + {file = "lxml-4.9.1-cp37-cp37m-win_amd64.whl", hash = "sha256:eea5d6443b093e1545ad0210e6cf27f920482bfcf5c77cdc8596aec73523bb7e"}, + {file = "lxml-4.9.1-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:f05251bbc2145349b8d0b77c0d4e5f3b228418807b1ee27cefb11f69ed3d233b"}, + {file = "lxml-4.9.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:487c8e61d7acc50b8be82bda8c8d21d20e133c3cbf41bd8ad7eb1aaeb3f07c97"}, + {file = "lxml-4.9.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:8d1a92d8e90b286d491e5626af53afef2ba04da33e82e30744795c71880eaa21"}, + {file = "lxml-4.9.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:b570da8cd0012f4af9fa76a5635cd31f707473e65a5a335b186069d5c7121ff2"}, + {file = "lxml-4.9.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5ef87fca280fb15342726bd5f980f6faf8b84a5287fcc2d4962ea8af88b35130"}, + {file = "lxml-4.9.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:93e414e3206779ef41e5ff2448067213febf260ba747fc65389a3ddaa3fb8715"}, + {file = "lxml-4.9.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:6653071f4f9bac46fbc30f3c7838b0e9063ee335908c5d61fb7a4a86c8fd2036"}, + {file = "lxml-4.9.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:32a73c53783becdb7eaf75a2a1525ea8e49379fb7248c3eeefb9412123536387"}, + {file = "lxml-4.9.1-cp38-cp38-win32.whl", hash = "sha256:1a7c59c6ffd6ef5db362b798f350e24ab2cfa5700d53ac6681918f314a4d3b94"}, + {file = "lxml-4.9.1-cp38-cp38-win_amd64.whl", hash = "sha256:1436cf0063bba7888e43f1ba8d58824f085410ea2025befe81150aceb123e345"}, + {file = "lxml-4.9.1-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:4beea0f31491bc086991b97517b9683e5cfb369205dac0148ef685ac12a20a67"}, + {file = "lxml-4.9.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:41fb58868b816c202e8881fd0f179a4644ce6e7cbbb248ef0283a34b73ec73bb"}, + {file = "lxml-4.9.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:bd34f6d1810d9354dc7e35158aa6cc33456be7706df4420819af6ed966e85448"}, + {file = "lxml-4.9.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:edffbe3c510d8f4bf8640e02ca019e48a9b72357318383ca60e3330c23aaffc7"}, + {file = "lxml-4.9.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6d949f53ad4fc7cf02c44d6678e7ff05ec5f5552b235b9e136bd52e9bf730b91"}, + {file = "lxml-4.9.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:079b68f197c796e42aa80b1f739f058dcee796dc725cc9a1be0cdb08fc45b000"}, + {file = "lxml-4.9.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9c3a88d20e4fe4a2a4a84bf439a5ac9c9aba400b85244c63a1ab7088f85d9d25"}, + {file = "lxml-4.9.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:4e285b5f2bf321fc0857b491b5028c5f276ec0c873b985d58d7748ece1d770dd"}, + {file = "lxml-4.9.1-cp39-cp39-win32.whl", hash = "sha256:ef72013e20dd5ba86a8ae1aed7f56f31d3374189aa8b433e7b12ad182c0d2dfb"}, + {file = "lxml-4.9.1-cp39-cp39-win_amd64.whl", hash = "sha256:10d2017f9150248563bb579cd0d07c61c58da85c922b780060dcc9a3aa9f432d"}, + {file = "lxml-4.9.1-pp37-pypy37_pp73-macosx_10_15_x86_64.whl", hash = "sha256:0538747a9d7827ce3e16a8fdd201a99e661c7dee3c96c885d8ecba3c35d1032c"}, + {file = "lxml-4.9.1-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:0645e934e940107e2fdbe7c5b6fb8ec6232444260752598bc4d09511bd056c0b"}, + {file = "lxml-4.9.1-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:6daa662aba22ef3258934105be2dd9afa5bb45748f4f702a3b39a5bf53a1f4dc"}, + {file = "lxml-4.9.1-pp38-pypy38_pp73-macosx_10_15_x86_64.whl", hash = "sha256:603a464c2e67d8a546ddaa206d98e3246e5db05594b97db844c2f0a1af37cf5b"}, + {file = "lxml-4.9.1-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:c4b2e0559b68455c085fb0f6178e9752c4be3bba104d6e881eb5573b399d1eb2"}, + {file = "lxml-4.9.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:0f3f0059891d3254c7b5fb935330d6db38d6519ecd238ca4fce93c234b4a0f73"}, + {file = "lxml-4.9.1-pp39-pypy39_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:c852b1530083a620cb0de5f3cd6826f19862bafeaf77586f1aef326e49d95f0c"}, + {file = "lxml-4.9.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:287605bede6bd36e930577c5925fcea17cb30453d96a7b4c63c14a257118dbb9"}, + {file = "lxml-4.9.1.tar.gz", hash = "sha256:fe749b052bb7233fe5d072fcb549221a8cb1a16725c47c37e42b0b9cb3ff2c3f"}, +] Mako = [ {file = "Mako-1.2.2-py3-none-any.whl", hash = "sha256:8efcb8004681b5f71d09c983ad5a9e6f5c40601a6ec469148753292abc0da534"}, {file = "Mako-1.2.2.tar.gz", hash = "sha256:3724869b363ba630a272a5f89f68c070352137b8fd1757650017b7e06fda163f"}, @@ -1588,6 +1753,14 @@ playwright = [ {file = "playwright-1.25.2-py3-none-win32.whl", hash = "sha256:b49680ad62a6e070ef857475256bc4f2cfb3242de96c12a2cae35b36564c78cb"}, {file = "playwright-1.25.2-py3-none-win_amd64.whl", hash = "sha256:68ae739f82b78717123eb9d1b28b4619f0b368b88ef73c633681e267680697cd"}, ] +pluggy = [ + {file = "pluggy-1.0.0-py2.py3-none-any.whl", hash = "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3"}, + {file = "pluggy-1.0.0.tar.gz", hash = "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159"}, +] +py = [ + {file = "py-1.11.0-py2.py3-none-any.whl", hash = "sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378"}, + {file = "py-1.11.0.tar.gz", hash = "sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719"}, +] pyaes = [ {file = "pyaes-1.6.1.tar.gz", hash = "sha256:02c1b1405c38d3c370b085fb952dd8bea3fadcee6411ad99f312cc129c536d8f"}, ] @@ -1658,6 +1831,14 @@ PySocks = [ {file = "PySocks-1.7.1-py3-none-any.whl", hash = "sha256:2725bd0a9925919b9b51739eea5f9e2bae91e83288108a9ad338b2e3a4435ee5"}, {file = "PySocks-1.7.1.tar.gz", hash = "sha256:3f8804571ebe159c380ac6de37643bb4685970655d3bba243530d6558b799aa0"}, ] +pytest = [ + {file = "pytest-7.1.3-py3-none-any.whl", hash = "sha256:1377bda3466d70b55e3f5cecfa55bb7cfcf219c7964629b967c37cf0bda818b7"}, + {file = "pytest-7.1.3.tar.gz", hash = "sha256:4f365fec2dff9c1162f834d9f18af1ba13062db0c708bf7b946f8a5c76180c39"}, +] +pytest-asyncio = [ + {file = "pytest-asyncio-0.19.0.tar.gz", hash = "sha256:ac4ebf3b6207259750bc32f4c1d8fcd7e79739edbc67ad0c58dd150b1d072fed"}, + {file = "pytest_asyncio-0.19.0-py3-none-any.whl", hash = "sha256:7a97e37cfe1ed296e2e84941384bdd37c376453912d397ed39293e0916f521fa"}, +] python-dotenv = [ {file = "python-dotenv-0.20.0.tar.gz", hash = "sha256:b7e3b04a59693c42c36f9ab1cc2acc46fa5df8c78e178fc33a8d4cd05c8d498f"}, {file = "python_dotenv-0.20.0-py3-none-any.whl", hash = "sha256:d92a187be61fe482e4fd675b6d52200e7be63a12b724abbf931a40ce4fa92938"}, diff --git a/pyproject.toml b/pyproject.toml index f95f32c..6514024 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -30,9 +30,21 @@ rich = "^12.5.1" enkanetwork-py = { git = "https://github.com/mrwan200/EnkaNetwork.py" } TgCrypto = { version = "^1.2.3", optional = true } Pyrogram = { version = "^2.0.51", optional = true } +pytest = { version = "^7.1.3", optional = true } +pytest-asyncio = { version = "^0.19.0", optional = true } +flaky = { version = "^3.7.0", optional = true } +lxml = "^4.9.1" [tool.poetry.extras] pyro = ["Pyrogram", "TgCrypto"] +test = ["pytest", "pytest-asyncio", "flaky"] + +[tool.pytest.ini_options] +asyncio_mode = "auto" +log_cli = true +log_cli_level = "INFO" +log_cli_format = "%(message)s" +log_cli_date_format = "%Y-%m-%d %H:%M:%S" [build-system] requires = ["poetry-core"] diff --git a/tests/data/test_artifact.jpg b/tests/data/test_artifact.jpg new file mode 100644 index 0000000..30cc80d Binary files /dev/null and b/tests/data/test_artifact.jpg differ diff --git a/tests/model/apihelper/test_artifact.py b/tests/model/apihelper/test_artifact.py deleted file mode 100644 index 31c7838..0000000 --- a/tests/model/apihelper/test_artifact.py +++ /dev/null @@ -1,29 +0,0 @@ -import unittest -from unittest import IsolatedAsyncioTestCase - -from modules.apihelper.artifact import ArtifactOcrRate - - -class TestArtifact(IsolatedAsyncioTestCase): - def setUp(self): - self.artifact_rate = ArtifactOcrRate() - - async def test_get_artifact_attr(self): - await self.artifact_rate.get_artifact_attr(b"") - - async def test_rate_artifact(self): - artifact_attr = { - 'name': '翠绿的猎人之冠', 'pos': '理之冠', 'star': 5, 'level': 20, - 'main_item': {'type': 'cr', 'name': '暴击率', 'value': '31.1%'}, - 'sub_item': [{'type': 'hp', 'name': '生命值', 'value': '9.3%'}, - {'type': 'df', 'name': '防御力', 'value': '46'}, - {'type': 'atk', 'name': '攻击力', 'value': '49'}, - {'type': 'cd', 'name': '暴击伤害', 'value': '10.9%'}]} - await self.artifact_rate.rate_artifact(artifact_attr) - - async def asyncTearDown(self) -> None: - await self.artifact_rate.close() - - -if __name__ == "__main__": - unittest.main() diff --git a/tests/model/wiki/test_wiki.py b/tests/model/wiki/test_wiki.py deleted file mode 100644 index 175d67f..0000000 --- a/tests/model/wiki/test_wiki.py +++ /dev/null @@ -1,95 +0,0 @@ -import unittest -from unittest import IsolatedAsyncioTestCase - -from modules.wiki.character import Character -from modules.wiki.material import Material -from modules.wiki.weapon import Weapon - - -class TestWeapon(IsolatedAsyncioTestCase): - async def test_get_by_id(self): - weapon = await Weapon.get_by_id('11417') - self.assertEqual(weapon.name, '原木刀') - self.assertEqual(weapon.rarity, 4) - self.assertEqual(weapon.attack, 43.73) - self.assertEqual(weapon.attribute.type.value, '元素充能效率') - self.assertEqual(weapon.affix.name, '森林的瑞佑') - - async def test_get_by_name(self): - weapon = await Weapon.get_by_name('风鹰剑') - self.assertEqual(weapon.id, 11501) - self.assertEqual(weapon.rarity, 5) - self.assertEqual(weapon.attack, 47.54) - self.assertEqual(weapon.attribute.type.value, '物理伤害加成') - self.assertEqual(weapon.affix.name, '西风之鹰的抗争') - self.assertTrue('听凭风引,便是正义与自由之风' in weapon.story) - - async def test_get_full_gen(self): - async for weapon in Weapon.full_data_generator(): - self.assertIsInstance(weapon, Weapon) - - async def test_get_full(self): - full_data = await Weapon.get_full_data() - for weapon in full_data: - self.assertIsInstance(weapon, Weapon) - - async def test_name_list(self): - from httpx import URL - async for name in Weapon._name_list_generator(with_url=True): - self.assertIsInstance(name[0], str) - self.assertIsInstance(name[1], URL) - - -class TestCharacter(IsolatedAsyncioTestCase): - async def test_get_by_id(self): - character = await Character.get_by_id('ayaka_002') - self.assertEqual(character.name, '神里绫华') - self.assertEqual(character.title, '白鹭霜华') - self.assertEqual(character.occupation, '社奉行') - self.assertEqual(character.association.value, '稻妻') - self.assertEqual(character.cn_cv, '小N') - - async def test_get_by_name(self): - character = await Character.get_by_name('神里绫华') - self.assertEqual(character.id, 'ayaka_002') - self.assertEqual(character.title, '白鹭霜华') - self.assertEqual(character.occupation, '社奉行') - self.assertEqual(character.association.value, '稻妻') - self.assertEqual(character.cn_cv, '小N') - - main_character = await Character.get_by_name('荧') - self.assertEqual(main_character.constellation, '旅人座') - self.assertEqual(main_character.cn_cv, '宴宁&多多poi') - - async def test_get_full(self): - async for character in Character.full_data_generator(): - self.assertIsInstance(character, Character) - - -class TestMaterial(IsolatedAsyncioTestCase): - async def test_get_full_gen(self): - async for material in Material.full_data_generator(): - self.assertIsInstance(material, Material) - - async def test_get_full(self): - material_list = await Material.get_full_data() - for material in material_list: - self.assertIsInstance(material, Material) - - -class TestAll(IsolatedAsyncioTestCase): - async def test_all_get_full(self): - import asyncio - materials, weapons, characters = tuple(await asyncio.gather( - Material.get_full_data(), - Weapon.get_full_data(), - Character.get_full_data(), - return_exceptions=True - )) - self.assertEqual(len(materials), 120) - self.assertEqual(len(weapons), 151) - self.assertEqual(len(characters), 58) - - -if __name__ == "__main__": - unittest.main() diff --git a/tests/run.py b/tests/run.py deleted file mode 100644 index 4e5a74a..0000000 --- a/tests/run.py +++ /dev/null @@ -1,18 +0,0 @@ -import os -import unittest - -main_suite = unittest.TestSuite() - -for parent, dirs, _ in os.walk("."): - for dirname in dirs: - if dirname == "__pycache__": - continue - discover = unittest.defaultTestLoader.discover( - start_dir=parent + os.sep + dirname, pattern='test_*.py', - top_level_dir=parent + os.sep + dirname) - main_suite.addTest(discover) - - -if __name__ == "__main__": - runner = unittest.TextTestRunner(verbosity=2) - runner.run(main_suite) diff --git a/tests/service/test_game.py b/tests/service/test_game.py deleted file mode 100644 index bab29cc..0000000 --- a/tests/service/test_game.py +++ /dev/null @@ -1,37 +0,0 @@ -import unittest -from unittest import IsolatedAsyncioTestCase - -from modules.apihelper.hyperion import Hyperion - - -class TestGame(IsolatedAsyncioTestCase): - - def setUp(self): - self.hyperion = Hyperion() - - async def test_get_strategy(self): - test_collection_id_list = [839176, 839179, 839181] - test_result = ["温迪", "胡桃", "雷电将军"] - - async def get_post_id(_collection_id: int, character_name: str) -> str: - post_full_in_collection = await self.hyperion.get_post_full_in_collection(_collection_id) - if post_full_in_collection.error: - raise RuntimeError(f"获取收藏信息错误,错误信息为:{post_full_in_collection.message}") - for post_data in post_full_in_collection.data["posts"]: - topics = post_data["topics"] - for topic in topics: - if character_name == topic["name"]: - return topic["name"] - return "" - - for index, _ in enumerate(test_collection_id_list): - second = test_result[index] - first = await get_post_id(test_collection_id_list[index], second) - self.assertEqual(first, second) - - async def asyncTearDown(self) -> None: - await self.hyperion.close() - - -if __name__ == "__main__": - unittest.main() diff --git a/tests/test_artifact.py b/tests/test_artifact.py new file mode 100644 index 0000000..d98b25e --- /dev/null +++ b/tests/test_artifact.py @@ -0,0 +1,42 @@ +import logging + +import pytest +import pytest_asyncio +from flaky import flaky + +from modules.apihelper.artifact import ArtifactOcrRate + +LOGGER = logging.getLogger(__name__) + + +@pytest_asyncio.fixture +async def artifact_rate(): + _artifact_rate = ArtifactOcrRate() + yield _artifact_rate + await _artifact_rate.close() + + +# noinspection PyShadowingNames +@pytest.mark.asyncio +class TestArtifactOcrRate: + + @staticmethod + @flaky(3, 1) + async def test_rate_artifact(artifact_rate): + artifact_attr = { + 'name': '翠绿的猎人之冠', 'pos': '理之冠', 'star': 5, 'level': 20, + 'main_item': {'type': 'cr', 'name': '暴击率', 'value': '31.1%'}, + 'sub_item': [{'type': 'hp', 'name': '生命值', 'value': '9.3%'}, + {'type': 'df', 'name': '防御力', 'value': '46'}, + {'type': 'atk', 'name': '攻击力', 'value': '49'}, + {'type': 'cd', 'name': '暴击伤害', 'value': '10.9%'}]} + assert await artifact_rate.rate_artifact(artifact_attr) + + @staticmethod + @flaky(3, 1) + async def test_ocr_artifact(artifact_rate): + with open("tests/data/test_artifact.jpg", "rb") as f: + photo = f.read() + data = await artifact_rate.get_artifact_attr(photo) + LOGGER.info(data.text) + assert data.status_code == 200 diff --git a/tests/test_game.py b/tests/test_game.py new file mode 100644 index 0000000..b7ad280 --- /dev/null +++ b/tests/test_game.py @@ -0,0 +1,36 @@ +import pytest +import pytest_asyncio +from flaky import flaky + +from modules.apihelper.hyperion import Hyperion + + +@pytest_asyncio.fixture +async def hyperion(): + _hyperion = Hyperion() + yield _hyperion + await _hyperion.close() + + +# noinspection PyShadowingNames +@pytest.mark.asyncio +@flaky(3, 1) +async def test_get_strategy(hyperion): + test_collection_id_list = [839176, 839179, 839181] + test_result = ["温迪", "胡桃", "雷电将军"] + + async def get_post_id(_collection_id: int, character_name: str) -> str: + post_full_in_collection = await hyperion.get_post_full_in_collection(_collection_id) + if post_full_in_collection.error: + raise RuntimeError(f"获取收藏信息错误,错误信息为:{post_full_in_collection.message}") + for post_data in post_full_in_collection.data["posts"]: + topics = post_data["topics"] + for topic in topics: + if character_name == topic["name"]: + return topic["name"] + return "" + + for index, _ in enumerate(test_collection_id_list): + second = test_result[index] + first = await get_post_id(test_collection_id_list[index], second) + assert first == second diff --git a/tests/test_wiki.py b/tests/test_wiki.py new file mode 100644 index 0000000..21f08ad --- /dev/null +++ b/tests/test_wiki.py @@ -0,0 +1,152 @@ +import asyncio +import logging +from random import sample, randint +from typing import Type + +import pytest +from flaky import flaky + +from modules.wiki.base import WikiModel +from modules.wiki.character import Character +from modules.wiki.material import Material +from modules.wiki.weapon import Weapon + +LOGGER = logging.getLogger(__name__) + + +@pytest.fixture(scope="session") +def event_loop(): + loop = asyncio.get_event_loop() + asyncio.set_event_loop(loop) + yield loop + loop.close() + + +@pytest.mark.asyncio +class TestWeapon: + + @staticmethod + @flaky(3, 1) + async def test_get_by_id(): + weapon = await Weapon.get_by_id('i_n11417') + assert weapon.name == '原木刀' + assert weapon.rarity == 4 + assert weapon.attack == 43.73 + assert weapon.attribute.type.value == '元素充能效率' + assert weapon.affix.name == '森林的瑞佑' + + @staticmethod + @flaky(3, 1) + async def test_get_by_name(): + weapon = await Weapon.get_by_name('风鹰剑') + assert weapon.id == 'i_n11501' + assert weapon.rarity == 5 + assert weapon.attack == 47.54 + assert weapon.attribute.type.value == '物理伤害加成' + assert weapon.affix.name == '西风之鹰的抗争' + assert '听凭风引,便是正义与自由之风' in weapon.story + + @staticmethod + @flaky(3, 1) + async def test_name_list(): + from httpx import URL + async for name in Weapon._name_list_generator(with_url=True): + assert isinstance(name[0], str) + assert isinstance(name[1], URL) + + +@pytest.mark.asyncio +class TestCharacter: + + @staticmethod + @flaky(3, 1) + async def test_get_by_id(): + character = await Character.get_by_id('ayaka_002') + assert character.name == '神里绫华' + assert character.title == '白鹭霜华' + assert character.occupation == '社奉行' + assert character.association.value == '稻妻' + assert character.cn_cv == '小N' + + @staticmethod + @flaky(3, 1) + async def test_get_by_name(): + character = await Character.get_by_name('神里绫华') + assert character.name == '神里绫华' + assert character.title == '白鹭霜华' + assert character.occupation == '社奉行' + assert character.association.value == '稻妻' + assert character.cn_cv == '小N' + main_character = await Character.get_by_name('荧') + assert main_character.constellation == '旅人座' + assert main_character.cn_cv == '宴宁&多多poi' + + @staticmethod + @flaky(3, 1) + async def test_name_list(): + from httpx import URL + async for name in Character._name_list_generator(with_url=True): + assert isinstance(name[0], str) + assert isinstance(name[1], URL) + + +@pytest.mark.asyncio +class TestMaterial: + + @staticmethod + @flaky(3, 1) + async def test_get_by_id(): + material = await Material.get_by_id('i_504') + assert material.name == '高塔孤王的碎梦' + assert material.type == '武器突破素材' + assert '合成获得' in material.source + assert '巴巴托斯' in material.description + + @staticmethod + @flaky(3, 1) + async def test_get_by_name(): + material = await Material.get_by_name('地脉的新芽') + assert material.id == 'i_73' + assert material.type == '角色培养素材' + assert '60级以上深渊法师掉落' in material.source + assert '勃发' in material.description + + @staticmethod + @flaky(3, 1) + async def test_name_list(): + from httpx import URL + async for name in Material._name_list_generator(with_url=True): + assert isinstance(name[0], str) + assert isinstance(name[1], URL) + + +@pytest.mark.asyncio +class TestAll: + + @staticmethod + @flaky(3, 1) + async def make_test(target: Type[WikiModel]): + from httpx import URL + name_list = await target.get_name_list(with_url=True) + name_len = len(name_list) + assert name_len != 0 + test_len = randint(1, max(2, int(len(name_list) * 0.3))) # nosec + LOGGER.info("得到了 %d 条 %s 的数据, 将会测试其中的 %s 条数据", name_len, target.__name__, test_len) + for name, url in sample(name_list, test_len): + assert isinstance(name, str) + assert isinstance(url, URL) + instance = await target._scrape(url) + assert isinstance(instance, target) + LOGGER.info("%s is ok.", instance.name) + + @flaky(3, 1) + async def test_random_material(self): + await self.make_test(Material) + + @flaky(3, 1) + async def test_random_weapon(self): + await self.make_test(Weapon) + + @flaky(3, 1) + async def test_random_character(self): + await self.make_test(Character)