Compare commits
158 Commits
v0.4.2
..
8ef291efd8
| Author | SHA1 | Date | |
|---|---|---|---|
| 8ef291efd8 | |||
| 92be9c50bf | |||
| f0e5ecd5de | |||
| e2c44583e8 | |||
| 5da741f3a9 | |||
| 35c5eb65cb | |||
| 7e53a26e5f | |||
|
|
436b3f85d0 | ||
| 9c1a9cc3c5 | |||
| 82f30f126d | |||
|
|
9599ac28ca | ||
|
|
e71a699ed8 | ||
| ff4eb8ca98 | |||
| b69973b9af | |||
| 3e133fa147 | |||
| ae506789ab | |||
| c3fa689617 | |||
| b51e42b4b2 | |||
| d4bea91186 | |||
| d47dadeb88 | |||
| b807904c6c | |||
| ee1bee22eb | |||
| f6c4c1623f | |||
| 49fd086b92 | |||
| 35dce0bf01 | |||
| 71240373c0 | |||
| 659023d561 | |||
| a0073b65ad | |||
| cba53e0841 | |||
| e50fb88bfc | |||
| ad58912baf | |||
| c4e8d64710 | |||
| ca4319001c | |||
| ebc58b831d | |||
|
|
b1572c903c | ||
|
|
5b73924e2a | ||
| 97ce258a8d | |||
| fedec79a95 | |||
| 8e74709b9c | |||
|
|
be09e1d932 | ||
|
|
d95417d075 | ||
| 2e3e511e3b | |||
| 8555052cc4 | |||
| 80bc6793c7 | |||
| 049a0c5d49 | |||
| ae9cb77e6d | |||
| 126ed5ed72 | |||
| 63ae64cebd | |||
| 0b29351366 | |||
| 4ea39f74fe | |||
| 76fcf5e67f | |||
| 11457736e6 | |||
| e2a6af1cbd | |||
| 20ea15009d | |||
| 00ab0f27f7 | |||
| 1f4870d082 | |||
| e96af7410e | |||
| 345bb8ce03 | |||
| dbcfc77ad4 | |||
| e653532212 | |||
| 8e7e31f64d | |||
| bff3795cc6 | |||
| 8782f1353d | |||
| f08f255a46 | |||
| 02870043ec | |||
| 154e491922 | |||
| ef5e702255 | |||
| cb4cd93bcd | |||
|
|
ee034c9caf | ||
| c133a4ecd2 | |||
| f09a2efa5e | |||
| 49983f4173 | |||
| 0f9894e1be | |||
|
|
8c0dffec31 | ||
|
|
0085d944ea | ||
|
|
89cf0e66a6 | ||
|
|
baef436f78 | ||
| cf00d7992e | |||
| f25829f3c1 | |||
| 8c783bc405 | |||
| 0048d71b74 | |||
| c633347ecc | |||
|
|
ecd6a0ec32 | ||
| 30507d9d01 | |||
| 6245a794d5 | |||
| 5c822e4890 | |||
| cab06fe43f | |||
| b4ff5f3351 | |||
| 0834802481 | |||
| 3afd74dcbf | |||
| b1a0bdfbb6 | |||
| 6d38bc5e1d | |||
| 5ba1ba15c9 | |||
| db05d2abfb | |||
| 1840c4e39a | |||
| c5a3f424d6 | |||
| 04aa6b81b5 | |||
| 5ff3b9b996 | |||
| 228e4a61a4 | |||
| df38ea5413 | |||
| 709f6ca6ca | |||
| b012fc29e4 | |||
| bdad723aef | |||
| f97d46cec3 | |||
| 7381eaef57 | |||
| 72c922b311 | |||
|
|
fd14a8152c | ||
| 5cb60c317d | |||
| 847de75713 | |||
| 58723cf3e8 | |||
| c613168bfb | |||
|
|
6f83de77f2 | ||
|
|
3f6ef3beb4 | ||
| 14e50c1465 | |||
| 0aa9fdca14 | |||
|
|
dc50820abc | ||
|
|
81afce78ad | ||
| 8a0b912601 | |||
| 85105a953e | |||
| 40f3452d08 | |||
| a287a5c903 | |||
| f30e5270d8 | |||
| 104bcd7bb2 | |||
| fd6fcfc98f | |||
| f87e02cd7c | |||
| 9b63b10118 | |||
| 111485e7c4 | |||
|
|
0167753cfe | ||
|
|
73131cc518 | ||
| 25576757bb | |||
| 105c8f3a82 | |||
| 5164d81492 | |||
| 319e5f1ac2 | |||
|
|
b24c2fbeb1 | ||
| bc5053c39c | |||
|
|
f06a031c93 | ||
|
|
8d450dea5a | ||
| c4ace8c53f | |||
| 78f104f558 | |||
| e8a6f740b9 | |||
|
|
6f3c6ec840 | ||
|
|
47a3ef1d8b | ||
|
|
367e9bf33b | ||
|
|
f122b02424 | ||
|
|
3a09c17f0a | ||
|
|
6773abb04e | ||
| b757d66d7a | |||
| 81cb7a750c | |||
| 3be59108a9 | |||
| fac9c45aee | |||
| 184bd2b510 | |||
| fda69178b9 | |||
| 652bbcd5d4 | |||
| fd35106df8 | |||
|
|
5ead5bc3d6 | ||
| 3ce0003315 | |||
|
|
ee94059a15 | ||
| 844742053d |
@@ -0,0 +1,4 @@
|
|||||||
|
--artifact-server-path=./.act/artifacts
|
||||||
|
--cache-server-path=./.act/cache
|
||||||
|
--container-options --privileged
|
||||||
|
--env ACT=true
|
||||||
@@ -76,15 +76,15 @@ jobs:
|
|||||||
RUSTDOCFLAGS: --cfg docsrs
|
RUSTDOCFLAGS: --cfg docsrs
|
||||||
msrv:
|
msrv:
|
||||||
# check that we can build using the minimal rust version that is specified by this crate
|
# check that we can build using the minimal rust version that is specified by this crate
|
||||||
name: 1.82.0 / check
|
name: 1.89.0 / check
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Install 1.82.0
|
- name: Install 1.89.0
|
||||||
uses: dtolnay/rust-toolchain@master
|
uses: dtolnay/rust-toolchain@master
|
||||||
with:
|
with:
|
||||||
toolchain: 1.82.0
|
toolchain: 1.89.0
|
||||||
|
|
||||||
- name: cargo +1.82.0 check
|
- name: cargo +1.89.0 check
|
||||||
run: cargo check
|
run: cargo check
|
||||||
|
|||||||
+375
-187
@@ -8,9 +8,9 @@ on:
|
|||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
inputs:
|
inputs:
|
||||||
bump_type:
|
bump_type:
|
||||||
description: "Specify the type of version bump"
|
description: 'Specify the type of version bump'
|
||||||
required: true
|
required: true
|
||||||
default: "patch"
|
default: 'patch'
|
||||||
type: choice
|
type: choice
|
||||||
options:
|
options:
|
||||||
- patch
|
- patch
|
||||||
@@ -23,6 +23,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Configure SSH for Git
|
- name: Configure SSH for Git
|
||||||
|
if: env.ACT != 'true'
|
||||||
run: |
|
run: |
|
||||||
mkdir -p ~/.ssh
|
mkdir -p ~/.ssh
|
||||||
echo "${{ secrets.RELEASE_BOT_SSH_KEY }}" > ~/.ssh/id_ed25519
|
echo "${{ secrets.RELEASE_BOT_SSH_KEY }}" > ~/.ssh/id_ed25519
|
||||||
@@ -30,20 +31,27 @@ jobs:
|
|||||||
ssh-keyscan -H github.com >> ~/.ssh/known_hosts
|
ssh-keyscan -H github.com >> ~/.ssh/known_hosts
|
||||||
|
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
|
if: env.ACT != 'true'
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
ssh-key: ${{ secrets.RELEASE_BOT_SSH_KEY }}
|
ssh-key: ${{ secrets.RELEASE_BOT_SSH_KEY }}
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Checkout repository
|
||||||
|
if: env.ACT == 'true'
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
- name: Set up Python
|
- name: Set up Python
|
||||||
uses: actions/setup-python@v4
|
uses: actions/setup-python@v4
|
||||||
with:
|
with:
|
||||||
python-version: "3.10"
|
python-version: '3.10'
|
||||||
|
|
||||||
- name: Install Commitizen
|
- name: Install Commitizen
|
||||||
run: |
|
run: |
|
||||||
python -m pip install --upgrade pip
|
python3 -m pip install --upgrade pip
|
||||||
pip install commitizen
|
pip3 install commitizen==4.8.3
|
||||||
npm install -g conventional-changelog-cli
|
npm install -g conventional-changelog-cli
|
||||||
|
|
||||||
- name: Configure Git user
|
- name: Configure Git user
|
||||||
@@ -62,12 +70,6 @@ jobs:
|
|||||||
- name: Install Rust stable
|
- name: Install Rust stable
|
||||||
uses: dtolnay/rust-toolchain@stable
|
uses: dtolnay/rust-toolchain@stable
|
||||||
|
|
||||||
- name: Update the Cargo.lock
|
|
||||||
run: |
|
|
||||||
cargo update
|
|
||||||
git add Cargo.lock
|
|
||||||
git commit -m "chore: Bump the version in Cargo.lock"
|
|
||||||
|
|
||||||
- name: Get the new version tag
|
- name: Get the new version tag
|
||||||
id: version
|
id: version
|
||||||
run: |
|
run: |
|
||||||
@@ -84,25 +86,154 @@ jobs:
|
|||||||
echo "Previous tag: $PREV_TAG"
|
echo "Previous tag: $PREV_TAG"
|
||||||
echo "prev_version=$PREV_TAG" >> $GITHUB_ENV
|
echo "prev_version=$PREV_TAG" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Bump Cargo.toml version
|
||||||
|
shell: bash
|
||||||
|
working-directory: ${{ github.workspace }}
|
||||||
|
env:
|
||||||
|
VERSION: ${{ env.version }}
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
: "${VERSION:?env.version is empty}"
|
||||||
|
|
||||||
|
# Ignore Act's local artifact dir noise
|
||||||
|
echo artifacts/ >> .git/info/exclude || true
|
||||||
|
|
||||||
|
# Edit the version line right after name="managarr"
|
||||||
|
sed -E -i '
|
||||||
|
/^[[:space:]]*name[[:space:]]*=[[:space:]]*"managarr"[[:space:]]*$/ {
|
||||||
|
n
|
||||||
|
s|^[[:space:]]*version[[:space:]]*=[[:space:]]*"[^"]*"|version = "'"$VERSION"'"|
|
||||||
|
}
|
||||||
|
' Cargo.toml
|
||||||
|
|
||||||
|
cargo update || true
|
||||||
|
|
||||||
|
# Git config that helps in containers (Act)
|
||||||
|
git config user.name "github-actions[bot]"
|
||||||
|
git config user.email "github-actions[bot]@users.noreply.github.com"
|
||||||
|
git config --global --add safe.directory "$GITHUB_WORKSPACE"
|
||||||
|
|
||||||
|
# Debug: show what changed
|
||||||
|
git status --porcelain
|
||||||
|
git diff --name-only -- Cargo.toml Cargo.lock || true
|
||||||
|
|
||||||
|
# Only commit if one of these files actually changed
|
||||||
|
if ! git diff --quiet -- Cargo.toml Cargo.lock; then
|
||||||
|
# Stage only modifications of already tracked files (won't pick up artifacts/)
|
||||||
|
git add -u -- Cargo.toml Cargo.lock
|
||||||
|
git commit -m "chore: bump Cargo.toml to $VERSION"
|
||||||
|
else
|
||||||
|
echo "No changes to commit (already at $VERSION)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Bump validate_theme_derive/Cargo.toml version
|
||||||
|
shell: bash
|
||||||
|
working-directory: ${{ github.workspace }}/proc_macros/validate_theme_derive
|
||||||
|
env:
|
||||||
|
VERSION: ${{ env.version }}
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
: "${VERSION:?env.version is empty}"
|
||||||
|
|
||||||
|
# Ignore Act's local artifact dir noise
|
||||||
|
echo artifacts/ >> .git/info/exclude || true
|
||||||
|
|
||||||
|
# Edit the version line right after name="managarr"
|
||||||
|
sed -E -i '
|
||||||
|
/^[[:space:]]*name[[:space:]]*=[[:space:]]*"managarr"[[:space:]]*$/ {
|
||||||
|
n
|
||||||
|
s|^[[:space:]]*version[[:space:]]*=[[:space:]]*"[^"]*"|version = "'"$VERSION"'"|
|
||||||
|
}
|
||||||
|
' Cargo.toml
|
||||||
|
|
||||||
|
cargo update || true
|
||||||
|
|
||||||
|
# Git config that helps in containers (Act)
|
||||||
|
git config user.name "github-actions[bot]"
|
||||||
|
git config user.email "github-actions[bot]@users.noreply.github.com"
|
||||||
|
git config --global --add safe.directory "$GITHUB_WORKSPACE"
|
||||||
|
|
||||||
|
# Debug: show what changed
|
||||||
|
git status --porcelain
|
||||||
|
git diff --name-only -- Cargo.toml || true
|
||||||
|
|
||||||
|
# Only commit if one of these files actually changed
|
||||||
|
if ! git diff --quiet -- Cargo.toml; then
|
||||||
|
# Stage only modifications of already tracked files (won't pick up artifacts/)
|
||||||
|
git add -u -- Cargo.toml
|
||||||
|
git commit -m "chore: bump validate_theme_derive Cargo.toml to $VERSION"
|
||||||
|
else
|
||||||
|
echo "No changes to commit (already at $VERSION)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Bump enum_display_style_derive/Cargo.toml version
|
||||||
|
shell: bash
|
||||||
|
working-directory: ${{ github.workspace }}/proc_macros/enum_display_style_derive
|
||||||
|
env:
|
||||||
|
VERSION: ${{ env.version }}
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
: "${VERSION:?env.version is empty}"
|
||||||
|
|
||||||
|
# Ignore Act's local artifact dir noise
|
||||||
|
echo artifacts/ >> .git/info/exclude || true
|
||||||
|
|
||||||
|
# Edit the version line right after name="managarr"
|
||||||
|
sed -E -i '
|
||||||
|
/^[[:space:]]*name[[:space:]]*=[[:space:]]*"managarr"[[:space:]]*$/ {
|
||||||
|
n
|
||||||
|
s|^[[:space:]]*version[[:space:]]*=[[:space:]]*"[^"]*"|version = "'"$VERSION"'"|
|
||||||
|
}
|
||||||
|
' Cargo.toml
|
||||||
|
|
||||||
|
cargo update || true
|
||||||
|
|
||||||
|
# Git config that helps in containers (Act)
|
||||||
|
git config user.name "github-actions[bot]"
|
||||||
|
git config user.email "github-actions[bot]@users.noreply.github.com"
|
||||||
|
git config --global --add safe.directory "$GITHUB_WORKSPACE"
|
||||||
|
|
||||||
|
# Debug: show what changed
|
||||||
|
git status --porcelain
|
||||||
|
git diff --name-only -- Cargo.toml || true
|
||||||
|
|
||||||
|
# Only commit if one of these files actually changed
|
||||||
|
if ! git diff --quiet -- Cargo.toml; then
|
||||||
|
# Stage only modifications of already tracked files (won't pick up artifacts/)
|
||||||
|
git add -u -- Cargo.toml
|
||||||
|
git commit -m "chore: bump enum_display_style_derive Cargo.toml to $VERSION"
|
||||||
|
else
|
||||||
|
echo "No changes to commit (already at $VERSION)"
|
||||||
|
fi
|
||||||
|
|
||||||
- name: Generate changelog for the version bump
|
- name: Generate changelog for the version bump
|
||||||
id: changelog
|
id: changelog
|
||||||
run: |
|
run: |
|
||||||
changelog=$(conventional-changelog -p angular -i CHANGELOG.md -s --from ${{ env.prev_version }} --to ${{ env.version }})
|
conventional-changelog -p angular -i CHANGELOG.md --from ${{ env.prev_version }} --to v${{ env.version }} > artifacts/changelog.md
|
||||||
echo "$changelog" > artifacts/changelog.md
|
|
||||||
echo "changelog_body=$(cat artifacts/changelog.md)" >> $GITHUB_ENV
|
|
||||||
|
|
||||||
- name: Push changes
|
- name: Push changes
|
||||||
|
if: env.ACT != 'true'
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
run: |
|
run: |
|
||||||
git push origin --follow-tags
|
git push origin --follow-tags
|
||||||
|
|
||||||
- name: Upload artifacts
|
- name: Upload artifacts
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: artifacts
|
|
||||||
path: artifacts
|
path: artifacts
|
||||||
|
|
||||||
|
- name: Upload the changed Cargo files (Act)
|
||||||
|
if: env.ACT == 'true'
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: bumped-cargo-files
|
||||||
|
path: |
|
||||||
|
Cargo.toml
|
||||||
|
Cargo.lock
|
||||||
|
proc_macros/validate_theme_derive/Cargo.toml
|
||||||
|
proc_macros/enum_display_style_derive/Cargo.toml
|
||||||
|
|
||||||
build-release-artifacts:
|
build-release-artifacts:
|
||||||
name: build-release
|
name: build-release
|
||||||
needs: [bump-version]
|
needs: [bump-version]
|
||||||
@@ -130,7 +261,7 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Check if actor is repository owner
|
- name: Check if actor is repository owner
|
||||||
if: ${{ github.actor != github.repository_owner }}
|
if: ${{ github.actor != github.repository_owner && env.ACT != 'true' }}
|
||||||
run: |
|
run: |
|
||||||
echo "You are not authorized to run this workflow."
|
echo "You are not authorized to run this workflow."
|
||||||
exit 1
|
exit 1
|
||||||
@@ -141,10 +272,18 @@ jobs:
|
|||||||
fetch-depth: 1
|
fetch-depth: 1
|
||||||
|
|
||||||
- name: Ensure repository is up-to-date
|
- name: Ensure repository is up-to-date
|
||||||
|
if: env.ACT != 'true'
|
||||||
run: |
|
run: |
|
||||||
git fetch --all
|
git fetch --all
|
||||||
git pull
|
git pull
|
||||||
|
|
||||||
|
- name: Get bumped Cargo files (Act)
|
||||||
|
if: env.ACT == 'true'
|
||||||
|
uses: actions/download-artifact@v4
|
||||||
|
with:
|
||||||
|
name: bumped-cargo-files
|
||||||
|
path: ${{ github.workspace }}
|
||||||
|
|
||||||
- uses: actions/cache@v3
|
- uses: actions/cache@v3
|
||||||
name: Cache Cargo registry
|
name: Cache Cargo registry
|
||||||
with:
|
with:
|
||||||
@@ -236,28 +375,36 @@ jobs:
|
|||||||
cp target/${{ matrix.job.target }}/release/${{ env.RELEASE_NAME }}.sha256 artifacts/
|
cp target/${{ matrix.job.target }}/release/${{ env.RELEASE_NAME }}.sha256 artifacts/
|
||||||
|
|
||||||
- name: Upload artifacts
|
- name: Upload artifacts
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: artifacts
|
name: artifacts-${{ env.RELEASE_NAME }}
|
||||||
path: artifacts
|
path: artifacts
|
||||||
|
overwrite: true
|
||||||
|
|
||||||
publish-github-release:
|
publish-github-release:
|
||||||
name: publish-github-release
|
name: publish-github-release
|
||||||
needs: [build-release-artifacts]
|
needs: [build-release-artifacts]
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
|
- name: Check if actor is repository owner
|
||||||
|
if: ${{ github.actor != github.repository_owner && env.ACT != 'true' }}
|
||||||
|
run: |
|
||||||
|
echo "You are not authorized to run this workflow."
|
||||||
|
exit 1
|
||||||
|
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
- name: Download all artifacts
|
- name: Download all artifacts
|
||||||
uses: actions/download-artifact@v3
|
uses: actions/download-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: artifacts
|
|
||||||
path: artifacts
|
path: artifacts
|
||||||
|
merge-multiple: true
|
||||||
|
|
||||||
- name: Ensure repository is up-to-date
|
- name: Ensure repository is up-to-date
|
||||||
|
if: env.ACT != 'true'
|
||||||
run: |
|
run: |
|
||||||
git fetch --all
|
git fetch --all
|
||||||
git pull
|
git pull
|
||||||
@@ -266,10 +413,14 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
release_version="$(cat ./artifacts/release-version)"
|
release_version="$(cat ./artifacts/release-version)"
|
||||||
echo "RELEASE_VERSION=$release_version" >> $GITHUB_ENV
|
echo "RELEASE_VERSION=$release_version" >> $GITHUB_ENV
|
||||||
changelog_body="$(cat ./artifacts/changelog.md)"
|
|
||||||
echo "changelog_body=$(cat artifacts/changelog.md)" >> $GITHUB_ENV
|
- name: Validate release environment variables
|
||||||
|
run: |
|
||||||
|
echo "Release version: ${{ env.RELEASE_VERSION }}"
|
||||||
|
echo "Changelog body: $(cat artifacts/changelog.md)"
|
||||||
|
|
||||||
- name: Create a GitHub Release
|
- name: Create a GitHub Release
|
||||||
|
if: env.ACT != 'true'
|
||||||
uses: softprops/action-gh-release@v1
|
uses: softprops/action-gh-release@v1
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
@@ -300,201 +451,238 @@ jobs:
|
|||||||
artifacts/managarr-armv7-musl.tar.gz
|
artifacts/managarr-armv7-musl.tar.gz
|
||||||
artifacts/managarr-armv7-musl.sha256
|
artifacts/managarr-armv7-musl.sha256
|
||||||
tag_name: v${{ env.RELEASE_VERSION }}
|
tag_name: v${{ env.RELEASE_VERSION }}
|
||||||
name: "v${{ env.RELEASE_VERSION }}"
|
name: 'v${{ env.RELEASE_VERSION }}'
|
||||||
body: ${{ env.changelog_body }}
|
body_path: artifacts/changelog.md
|
||||||
draft: false
|
draft: false
|
||||||
prerelease: false
|
prerelease: false
|
||||||
|
|
||||||
- name: Upload artifacts
|
- name: Upload artifacts
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: artifacts
|
|
||||||
path: artifacts
|
path: artifacts
|
||||||
|
overwrite: true
|
||||||
|
|
||||||
# publish-chocolatey-package:
|
publish-chocolatey-package:
|
||||||
# needs: [publish-github-release]
|
needs: [publish-github-release]
|
||||||
# name: Publish Chocolatey Package
|
name: Publish Chocolatey Package
|
||||||
# runs-on: windows-latest
|
runs-on: windows-latest
|
||||||
# steps:
|
steps:
|
||||||
# - name: Checkout repository
|
- name: Check if actor is repository owner
|
||||||
# uses: actions/checkout@v4
|
if: ${{ github.actor != github.repository_owner && env.ACT != 'true' }}
|
||||||
# with:
|
run: |
|
||||||
# fetch-depth: 1
|
echo "You are not authorized to run this workflow."
|
||||||
|
exit 1
|
||||||
|
|
||||||
# - name: Get release artifacts
|
- name: Checkout repository
|
||||||
# uses: actions/download-artifact@v3
|
uses: actions/checkout@v4
|
||||||
# with:
|
with:
|
||||||
# name: artifacts
|
fetch-depth: 1
|
||||||
# path: artifacts
|
|
||||||
|
|
||||||
# - name: Set release assets and version
|
- name: Get release artifacts
|
||||||
# shell: pwsh
|
uses: actions/download-artifact@v4
|
||||||
# run: |
|
with:
|
||||||
# # Read the first column from the SHA256 file
|
path: artifacts
|
||||||
# $windows_sha = Get-Content ./artifacts/managarr-windows.sha256 | ForEach-Object { $_.Split(' ')[0] }
|
merge-multiple: true
|
||||||
# Add-Content -Path $env:GITHUB_ENV -Value "WINDOWS_SHA=$windows_sha"
|
|
||||||
|
|
||||||
# # Read the release version from the release-version file
|
- name: Set release assets and version
|
||||||
# $release_version = Get-Content ./artifacts/release-version
|
shell: pwsh
|
||||||
# Add-Content -Path $env:GITHUB_ENV -Value "RELEASE_VERSION=$release_version"
|
run: |
|
||||||
|
# Read the first column from the SHA256 file
|
||||||
|
$windows_sha = Get-Content ./artifacts/managarr-windows.sha256 | ForEach-Object { $_.Split(' ')[0] }
|
||||||
|
Add-Content -Path $env:GITHUB_ENV -Value "WINDOWS_SHA=$windows_sha"
|
||||||
|
|
||||||
# - name: Validate release environment variables
|
# Read the release version from the release-version file
|
||||||
# run: |
|
$release_version = Get-Content ./artifacts/release-version
|
||||||
# echo "Release SHA windows: ${{ env.WINDOWS_SHA }}"
|
Add-Content -Path $env:GITHUB_ENV -Value "RELEASE_VERSION=$release_version"
|
||||||
# echo "Release version: ${{ env.RELEASE_VERSION }}"
|
|
||||||
|
|
||||||
# - name: Package and Publish package to Chocolatey
|
- name: Validate release environment variables
|
||||||
# run: |
|
run: |
|
||||||
# mkdir ./deployment/chocolatey/tools
|
echo "Release SHA windows: ${{ env.WINDOWS_SHA }}"
|
||||||
# # Run packaging script
|
echo "Release version: ${{ env.RELEASE_VERSION }}"
|
||||||
# python "./deployment/chocolatey/packager.py" ${{ env.RELEASE_VERSION }} "./deployment/chocolatey/managarr.nuspec.template" "./deployment/chocolatey/managarr.nuspec" ${{ env.WINDOWS_SHA }}
|
|
||||||
# python "./deployment/chocolatey/packager.py" ${{ env.RELEASE_VERSION }} "./deployment/chocolatey/chocolateyinstall.ps1.template" "./deployment/chocolatey/tools/chocolateyinstall.ps1" ${{ env.WINDOWS_SHA }}
|
|
||||||
|
|
||||||
# # Publish to Chocolatey
|
- name: Package and Publish package to Chocolatey
|
||||||
# cd ./deployment/chocolatey
|
if: env.ACT != 'true'
|
||||||
# choco pack
|
run: |
|
||||||
# echo y | choco install managarr -dv -s .
|
mkdir ./deployment/chocolatey/tools
|
||||||
# $version = managarr --version
|
# Run packaging script
|
||||||
# $version = $version -replace " ", "."
|
python "./deployment/chocolatey/packager.py" ${{ env.RELEASE_VERSION }} "./deployment/chocolatey/managarr.nuspec.template" "./deployment/chocolatey/managarr.nuspec" ${{ env.WINDOWS_SHA }}
|
||||||
# choco push $version.nupkg -s https://push.chocolatey.org/ --api-key ${{ secrets.CHOCOLATEY_API_KEY }};
|
python "./deployment/chocolatey/packager.py" ${{ env.RELEASE_VERSION }} "./deployment/chocolatey/chocolateyinstall.ps1.template" "./deployment/chocolatey/tools/chocolateyinstall.ps1" ${{ env.WINDOWS_SHA }}
|
||||||
|
|
||||||
# publish-homebrew-formula:
|
# Publish to Chocolatey
|
||||||
# needs: [publish-github-release]
|
cd ./deployment/chocolatey
|
||||||
# name: Update Homebrew formulas
|
choco pack
|
||||||
# runs-on: ubuntu-latest
|
echo y | choco install managarr -dv -s .
|
||||||
# steps:
|
$version = managarr --version
|
||||||
# - name: Checkout repository
|
$version = $version -replace " ", "."
|
||||||
# uses: actions/checkout@v4
|
choco push $version.nupkg -s https://push.chocolatey.org/ --api-key ${{ secrets.CHOCOLATEY_API_KEY }};
|
||||||
# with:
|
|
||||||
# fetch-depth: 1
|
|
||||||
|
|
||||||
# - name: Get release artifacts
|
publish-homebrew-formula:
|
||||||
# uses: actions/download-artifact@v3
|
needs: [publish-github-release]
|
||||||
# with:
|
name: Update Homebrew formulas
|
||||||
# name: artifacts
|
runs-on: ubuntu-latest
|
||||||
# path: artifacts
|
steps:
|
||||||
|
- name: Check if actor is repository owner
|
||||||
|
if: ${{ github.actor != github.repository_owner && env.ACT != 'true' }}
|
||||||
|
run: |
|
||||||
|
echo "You are not authorized to run this workflow."
|
||||||
|
exit 1
|
||||||
|
|
||||||
# - name: Set release assets and version
|
- name: Checkout repository
|
||||||
# shell: bash
|
uses: actions/checkout@v4
|
||||||
# run: |
|
with:
|
||||||
# # Set environment variables
|
fetch-depth: 1
|
||||||
# macos_sha="$(cat ./artifacts/managarr-macos.sha256 | awk '{print $1}')"
|
|
||||||
# echo "MACOS_SHA=$macos_sha" >> $GITHUB_ENV
|
|
||||||
# macos_sha_arm="$(cat ./artifacts/managarr-macos-arm64.sha256 | awk '{print $1}')"
|
|
||||||
# echo "MACOS_SHA_ARM=$macos_sha_arm" >> $GITHUB_ENV
|
|
||||||
# linux_sha="$(cat ./artifacts/managarr-linux-musl.sha256 | awk '{print $1}')"
|
|
||||||
# echo "LINUX_SHA=$linux_sha" >> $GITHUB_ENV
|
|
||||||
# release_version="$(cat ./artifacts/release-version)"
|
|
||||||
# echo "RELEASE_VERSION=$release_version" >> $GITHUB_ENV
|
|
||||||
|
|
||||||
# - name: Validate release environment variables
|
- name: Get release artifacts
|
||||||
# run: |
|
uses: actions/download-artifact@v4
|
||||||
# echo "Release SHA macos: ${{ env.MACOS_SHA }}"
|
with:
|
||||||
# echo "Release SHA macos-arm: ${{ env.MACOS_SHA_ARM }}"
|
path: artifacts
|
||||||
# echo "Release SHA linux musl: ${{ env.LINUX_SHA }}"
|
merge-multiple: true
|
||||||
# echo "Release version: ${{ env.RELEASE_VERSION }}"
|
|
||||||
|
|
||||||
# - name: Execute Homebrew packaging script
|
- name: Set release assets and version
|
||||||
# run: |
|
shell: bash
|
||||||
# # run packaging script
|
run: |
|
||||||
# python "./deployment/homebrew/packager.py" ${{ env.RELEASE_VERSION }} "./deployment/homebrew/managarr.rb.template" "./managarr.rb" ${{ env.MACOS_SHA }} ${{ env.MACOS_SHA_ARM }} ${{ env.LINUX_SHA }}
|
# Set environment variables
|
||||||
|
macos_sha="$(cat ./artifacts/managarr-macos.sha256 | awk '{print $1}')"
|
||||||
|
echo "MACOS_SHA=$macos_sha" >> $GITHUB_ENV
|
||||||
|
macos_sha_arm="$(cat ./artifacts/managarr-macos-arm64.sha256 | awk '{print $1}')"
|
||||||
|
echo "MACOS_SHA_ARM=$macos_sha_arm" >> $GITHUB_ENV
|
||||||
|
linux_sha="$(cat ./artifacts/managarr-linux-musl.sha256 | awk '{print $1}')"
|
||||||
|
echo "LINUX_SHA=$linux_sha" >> $GITHUB_ENV
|
||||||
|
release_version="$(cat ./artifacts/release-version)"
|
||||||
|
echo "RELEASE_VERSION=$release_version" >> $GITHUB_ENV
|
||||||
|
|
||||||
# - name: Push changes to Homebrew tap
|
- name: Validate release environment variables
|
||||||
# env:
|
run: |
|
||||||
# TOKEN: ${{ secrets.MANAGARR_GITHUB_TOKEN }}
|
echo "Release SHA macos: ${{ env.MACOS_SHA }}"
|
||||||
# run: |
|
echo "Release SHA macos-arm: ${{ env.MACOS_SHA_ARM }}"
|
||||||
# # push to Git
|
echo "Release SHA linux musl: ${{ env.LINUX_SHA }}"
|
||||||
# git config --global user.name "Dark-Alex-17"
|
echo "Release version: ${{ env.RELEASE_VERSION }}"
|
||||||
# git config --global user.email "alex.j.tusa@gmail.com"
|
|
||||||
# git clone https://Dark-Alex-17:${{ secrets.MANAGARR_GITHUB_TOKEN }}@github.com/Dark-Alex-17/homebrew-managarr.git
|
|
||||||
# rm homebrew-managarr/Formula/managarr.rb
|
|
||||||
# cp managarr.rb homebrew-managarr/Formula
|
|
||||||
# cd homebrew-managarr
|
|
||||||
# git add .
|
|
||||||
# git diff-index --quiet HEAD || git commit -am "Update formula for Managarr release ${{ env.RELEASE_VERSION }}"
|
|
||||||
# git push https://$TOKEN@github.com/Dark-Alex-17/homebrew-managarr.git
|
|
||||||
|
|
||||||
# publish-docker-image:
|
- name: Execute Homebrew packaging script
|
||||||
# needs: [publish-github-release]
|
if: env.ACT != 'true'
|
||||||
# name: Publishing Docker image to Docker Hub
|
run: |
|
||||||
# runs-on: ubuntu-latest
|
# run packaging script
|
||||||
# steps:
|
python "./deployment/homebrew/packager.py" ${{ env.RELEASE_VERSION }} "./deployment/homebrew/managarr.rb.template" "./managarr.rb" ${{ env.MACOS_SHA }} ${{ env.MACOS_SHA_ARM }} ${{ env.LINUX_SHA }}
|
||||||
# - name: Checkout repository
|
|
||||||
# uses: actions/checkout@v4
|
|
||||||
# with:
|
|
||||||
# fetch-depth: 1
|
|
||||||
|
|
||||||
# - name: Get release artifacts
|
- name: Push changes to Homebrew tap
|
||||||
# uses: actions/download-artifact@v3
|
if: env.ACT != 'true'
|
||||||
# with:
|
env:
|
||||||
# name: artifacts
|
TOKEN: ${{ secrets.MANAGARR_GITHUB_TOKEN }}
|
||||||
# path: artifacts
|
run: |
|
||||||
|
# push to Git
|
||||||
|
git config --global user.name "Dark-Alex-17"
|
||||||
|
git config --global user.email "alex.j.tusa@gmail.com"
|
||||||
|
git clone https://Dark-Alex-17:${{ secrets.MANAGARR_GITHUB_TOKEN }}@github.com/Dark-Alex-17/homebrew-managarr.git
|
||||||
|
rm homebrew-managarr/Formula/managarr.rb
|
||||||
|
cp managarr.rb homebrew-managarr/Formula
|
||||||
|
cd homebrew-managarr
|
||||||
|
git add .
|
||||||
|
git diff-index --quiet HEAD || git commit -am "Update formula for Managarr release ${{ env.RELEASE_VERSION }}"
|
||||||
|
git push https://$TOKEN@github.com/Dark-Alex-17/homebrew-managarr.git
|
||||||
|
|
||||||
# - name: Set version variable
|
publish-docker-image:
|
||||||
# run: |
|
needs: [publish-github-release]
|
||||||
# version="$(cat artifacts/release-version)"
|
name: Publishing Docker image to Docker Hub
|
||||||
# echo "version=$version" >> $GITHUB_ENV
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Check if actor is repository owner
|
||||||
|
if: ${{ github.actor != github.repository_owner && env.ACT != 'true' }}
|
||||||
|
run: |
|
||||||
|
echo "You are not authorized to run this workflow."
|
||||||
|
exit 1
|
||||||
|
|
||||||
# - name: Validate release environment variables
|
- name: Checkout repository
|
||||||
# run: |
|
uses: actions/checkout@v4
|
||||||
# echo "Release version: ${{ env.version }}"
|
with:
|
||||||
|
fetch-depth: 1
|
||||||
|
|
||||||
# - name: Set up QEMU
|
- name: Get release artifacts
|
||||||
# uses: docker/setup-qemu-action@v3
|
uses: actions/download-artifact@v4
|
||||||
|
with:
|
||||||
|
path: artifacts
|
||||||
|
merge-multiple: true
|
||||||
|
|
||||||
# - name: Set up Docker Buildx
|
- name: Ensure repository is up-to-date
|
||||||
# uses: docker/setup-buildx-action@v3
|
if: env.ACT != 'true'
|
||||||
|
run: |
|
||||||
|
git fetch --all
|
||||||
|
git pull
|
||||||
|
|
||||||
# - name: Login to Docker Hub
|
- name: Set version variable
|
||||||
# uses: docker/login-action@v3
|
run: |
|
||||||
# with:
|
version="$(cat artifacts/release-version)"
|
||||||
# username: ${{ secrets.DOCKER_USERNAME }}
|
echo "version=$version" >> $GITHUB_ENV
|
||||||
# password: ${{ secrets.DOCKER_PASSWORD }}
|
|
||||||
|
|
||||||
# - name: Push to Docker Hub
|
- name: Validate release environment variables
|
||||||
# uses: docker/build-push-action@v5
|
run: |
|
||||||
# with:
|
echo "Release version: ${{ env.version }}"
|
||||||
# context: .
|
|
||||||
# file: Dockerfile
|
|
||||||
# platforms: linux/amd64,linux/arm64
|
|
||||||
# push: true
|
|
||||||
# tags: darkalex17/managarr:latest, darkalex17/managarr:${{ env.version }}
|
|
||||||
|
|
||||||
# publish-crate:
|
- name: Set up QEMU
|
||||||
# needs: publish-github-release
|
uses: docker/setup-qemu-action@v3
|
||||||
# name: Publish Crate
|
|
||||||
# runs-on: ubuntu-latest
|
|
||||||
# steps:
|
|
||||||
# - name: Check if actor is repository owner
|
|
||||||
# if: ${{ github.actor != github.repository_owner }}
|
|
||||||
# run: |
|
|
||||||
# echo "You are not authorized to run this workflow."
|
|
||||||
# exit 1
|
|
||||||
|
|
||||||
# - name: Checkout
|
- name: Set up Docker Buildx
|
||||||
# uses: actions/checkout@v4
|
uses: docker/setup-buildx-action@v3
|
||||||
# with:
|
|
||||||
# fetch-depth: 0
|
|
||||||
|
|
||||||
# - name: Ensure repository is up-to-date
|
- name: Login to Docker Hub
|
||||||
# run: |
|
if: env.ACT != 'true'
|
||||||
# git fetch --all
|
uses: docker/login-action@v3
|
||||||
# git pull
|
with:
|
||||||
|
username: ${{ secrets.DOCKER_USERNAME }}
|
||||||
|
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||||
|
|
||||||
# - uses: actions/cache@v3
|
- name: Push to Docker Hub
|
||||||
# name: Cache Cargo registry
|
uses: docker/build-push-action@v5
|
||||||
# with:
|
with:
|
||||||
# path: ~/.cargo/registry
|
context: .
|
||||||
# key: ${{ runner.os }}-cargo-registry-${{ hashFiles('Cargo.lock') }}
|
file: Dockerfile
|
||||||
|
platforms: linux/amd64,linux/arm64
|
||||||
|
push: ${{ env.ACT != 'true' }}
|
||||||
|
tags: darkalex17/managarr:latest, darkalex17/managarr:${{ env.version }}
|
||||||
|
|
||||||
# - uses: actions/cache@v3
|
publish-crate:
|
||||||
# with:
|
needs: publish-github-release
|
||||||
# path: ~/.cargo/bin
|
name: Publish Crate
|
||||||
# key: ${{ runner.os }}-cargo-bin-${{ hashFiles('.github/workflows/release.yml') }}
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Check if actor is repository owner
|
||||||
|
if: ${{ github.actor != github.repository_owner && env.ACT != 'true' }}
|
||||||
|
run: |
|
||||||
|
echo "You are not authorized to run this workflow."
|
||||||
|
exit 1
|
||||||
|
|
||||||
# - name: Install Rust stable
|
- name: Checkout
|
||||||
# uses: dtolnay/rust-toolchain@stable
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
# - uses: katyo/publish-crates@v2
|
- name: Get bumped Cargo files (Act)
|
||||||
# with:
|
if: env.ACT == 'true'
|
||||||
# registry-token: ${{ secrets.CARGO_REGISTRY_TOKEN }}
|
uses: actions/download-artifact@v4
|
||||||
|
with:
|
||||||
|
name: bumped-cargo-files
|
||||||
|
path: ${{ github.workspace }}
|
||||||
|
|
||||||
|
- name: Ensure repository is up-to-date
|
||||||
|
if: env.ACT != 'true'
|
||||||
|
run: |
|
||||||
|
git fetch --all
|
||||||
|
git pull
|
||||||
|
|
||||||
|
- uses: actions/cache@v3
|
||||||
|
name: Cache Cargo registry
|
||||||
|
with:
|
||||||
|
path: ~/.cargo/registry
|
||||||
|
key: ${{ runner.os }}-cargo-registry-${{ hashFiles('Cargo.lock') }}
|
||||||
|
|
||||||
|
- uses: actions/cache@v3
|
||||||
|
with:
|
||||||
|
path: ~/.cargo/bin
|
||||||
|
key: ${{ runner.os }}-cargo-bin-${{ hashFiles('.github/workflows/release.yml') }}
|
||||||
|
|
||||||
|
- name: Install Rust stable
|
||||||
|
uses: dtolnay/rust-toolchain@stable
|
||||||
|
|
||||||
|
- uses: katyo/publish-crates@v2
|
||||||
|
if: env.ACT != 'true'
|
||||||
|
with:
|
||||||
|
registry-token: ${{ secrets.CARGO_REGISTRY_TOKEN }}
|
||||||
|
|||||||
+40
-39
@@ -48,51 +48,51 @@ jobs:
|
|||||||
- name: cargo test --locked
|
- name: cargo test --locked
|
||||||
run: cargo test --locked --all-features --all-targets
|
run: cargo test --locked --all-features --all-targets
|
||||||
|
|
||||||
minimal-versions:
|
# minimal-versions:
|
||||||
# This action chooses the oldest version of the dependencies permitted by Cargo.toml to ensure
|
# # This action chooses the oldest version of the dependencies permitted by Cargo.toml to ensure
|
||||||
# that this crate is compatible with the minimal version that this crate and its dependencies
|
# # that this crate is compatible with the minimal version that this crate and its dependencies
|
||||||
# require. This will pickup issues where this create relies on functionality that was introduced
|
# # require. This will pickup issues where this create relies on functionality that was introduced
|
||||||
# later than the actual version specified (e.g., when we choose just a major version, but a
|
# # later than the actual version specified (e.g., when we choose just a major version, but a
|
||||||
# method was added after this version).
|
# # method was added after this version).
|
||||||
#
|
# #
|
||||||
# This particular check can be difficult to get to succeed as often transitive dependencies may
|
# # This particular check can be difficult to get to succeed as often transitive dependencies may
|
||||||
# be incorrectly specified (e.g., a dependency specifies 1.0 but really requires 1.1.5). There
|
# # be incorrectly specified (e.g., a dependency specifies 1.0 but really requires 1.1.5). There
|
||||||
# is an alternative flag available -Zdirect-minimal-versions that uses the minimal versions for
|
# # is an alternative flag available -Zdirect-minimal-versions that uses the minimal versions for
|
||||||
# direct dependencies of this crate, while selecting the maximal versions for the transitive
|
# # direct dependencies of this crate, while selecting the maximal versions for the transitive
|
||||||
# dependencies. Alternatively, you can add a line in your Cargo.toml to artificially increase
|
# # dependencies. Alternatively, you can add a line in your Cargo.toml to artificially increase
|
||||||
# the minimal dependency, which you do with e.g.:
|
# # the minimal dependency, which you do with e.g.:
|
||||||
# ```toml
|
# # ```toml
|
||||||
# # for minimal-versions
|
# # # for minimal-versions
|
||||||
# [target.'cfg(any())'.dependencies]
|
# # [target.'cfg(any())'.dependencies]
|
||||||
# openssl = { version = "0.10.55", optional = true } # needed to allow foo to build with -Zminimal-versions
|
# # openssl = { version = "0.10.55", optional = true } # needed to allow foo to build with -Zminimal-versions
|
||||||
# ```
|
# # ```
|
||||||
# The optional = true is necessary in case that dependency isn't otherwise transitively required
|
# # The optional = true is necessary in case that dependency isn't otherwise transitively required
|
||||||
# by your library, and the target bit is so that this dependency edge never actually affects
|
# # by your library, and the target bit is so that this dependency edge never actually affects
|
||||||
# Cargo build order. See also
|
# # Cargo build order. See also
|
||||||
# https://github.com/jonhoo/fantoccini/blob/fde336472b712bc7ebf5b4e772023a7ba71b2262/Cargo.toml#L47-L49.
|
# # https://github.com/jonhoo/fantoccini/blob/fde336472b712bc7ebf5b4e772023a7ba71b2262/Cargo.toml#L47-L49.
|
||||||
# This action is run on ubuntu with the stable toolchain, as it is not expected to fail
|
# # This action is run on ubuntu with the stable toolchain, as it is not expected to fail
|
||||||
runs-on: ubuntu-latest
|
# runs-on: ubuntu-latest
|
||||||
name: ubuntu / stable / minimal-versions
|
# name: ubuntu / stable / minimal-versions
|
||||||
steps:
|
# steps:
|
||||||
- uses: actions/checkout@v4
|
# - uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Install Rust stable
|
# - name: Install Rust stable
|
||||||
uses: dtolnay/rust-toolchain@stable
|
# uses: dtolnay/rust-toolchain@stable
|
||||||
|
|
||||||
- name: Install nightly for -Zdirect-minimal-versions
|
# - name: Install nightly for -Zdirect-minimal-versions
|
||||||
uses: dtolnay/rust-toolchain@nightly
|
# uses: dtolnay/rust-toolchain@nightly
|
||||||
|
|
||||||
- name: rustup default stable
|
# - name: rustup default stable
|
||||||
run: rustup default stable
|
# run: rustup default stable
|
||||||
|
|
||||||
- name: cargo update -Zdirect-minimal-versions
|
# - name: cargo update -Zdirect-minimal-versions
|
||||||
run: cargo +nightly update -Zdirect-minimal-versions
|
# run: cargo +nightly update -Zdirect-minimal-versions
|
||||||
|
|
||||||
- name: cargo test
|
# - name: cargo test
|
||||||
run: cargo test --locked --all-features --all-targets
|
# run: cargo test --locked --all-features --all-targets
|
||||||
|
|
||||||
- name: Cache Cargo dependencies
|
# - name: Cache Cargo dependencies
|
||||||
uses: Swatinem/rust-cache@v2
|
# uses: Swatinem/rust-cache@v2
|
||||||
|
|
||||||
os-check:
|
os-check:
|
||||||
# run cargo test on mac and windows
|
# run cargo test on mac and windows
|
||||||
@@ -175,6 +175,7 @@ jobs:
|
|||||||
uses: Swatinem/rust-cache@v2
|
uses: Swatinem/rust-cache@v2
|
||||||
|
|
||||||
- name: Upload to codecov.io
|
- name: Upload to codecov.io
|
||||||
|
if: env.ACT != 'true'
|
||||||
uses: codecov/codecov-action@v4
|
uses: codecov/codecov-action@v4
|
||||||
with:
|
with:
|
||||||
fail_ci_if_error: true
|
fail_ci_if_error: true
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
/target
|
/target
|
||||||
/.idea/
|
/.idea/
|
||||||
/.scannerwork/
|
/.scannerwork/
|
||||||
|
/.act/
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
[keys.normal.backspace]
|
||||||
|
b = ":sh zellij run -x '4%%' --width '92%%' -f -n Build -- just build"
|
||||||
|
r = ":sh zellij run -x '3%%' -y '8%%' --width '95%%' --height '90%%' -fc -n 'Run' -- just run"
|
||||||
|
t = ":sh zellij run -x '4%%' --width '92%%' -f -n Tests -- just test"
|
||||||
|
l = ":sh zellij run -x '4%%' --width '92%%' -f -n Lint -- just lint"
|
||||||
+103
@@ -5,6 +5,109 @@ All notable changes to this project will be documented in this file.
|
|||||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
|
## v0.6.3 (2025-12-13)
|
||||||
|
|
||||||
|
### Fix
|
||||||
|
|
||||||
|
- Wrapped all Sonarr use of Language with Option to fix the 'null' array issue in the new Sonarr API
|
||||||
|
|
||||||
|
## v0.6.2 (2025-12-12)
|
||||||
|
|
||||||
|
### Fix
|
||||||
|
|
||||||
|
- Fixed breaking Sonarr Episode file API calls after recent Sonarr API update
|
||||||
|
|
||||||
|
### Refactor
|
||||||
|
|
||||||
|
- Replaced all modulo usages of tick_until_poll with is_multiple_of
|
||||||
|
|
||||||
|
## v0.6.1 (2025-09-02)
|
||||||
|
|
||||||
|
### Fix
|
||||||
|
|
||||||
|
- Fixed UI bugs introduced as part of the hotkey refactor
|
||||||
|
|
||||||
|
### Refactor
|
||||||
|
|
||||||
|
- Updated crate to publish properly with the procedural macros
|
||||||
|
|
||||||
|
## v0.6.0 (2025-08-29)
|
||||||
|
|
||||||
|
### Feat
|
||||||
|
|
||||||
|
- Support for custom headers to be added to every request to each server to support alternative authentication mechanisms [#47]
|
||||||
|
- Refactor all keybinding tips into a dynamically changing menu that can be invoked via '?' [#32]
|
||||||
|
- Display total disk usage for series in the Library view to mirror Radarr functionality [#44]
|
||||||
|
- Pagination support for jumping 20 items at a time in all table views [#45]
|
||||||
|
- Support toggling Movie monitoring directly from the library view [#43]
|
||||||
|
- Support toggling Movie monitoring from the CLI
|
||||||
|
- Support toggling Series monitoring directly from the Sonarr library view [#43]
|
||||||
|
- Support toggling Series monitoring from the CLI
|
||||||
|
- Fixed the Radarr downloads tab to display more than 10 downloads at a time and added a new --count flag to the CLI for specifying the number of downloads to return
|
||||||
|
- Fetch more than 10 downloads when listing Sonarr downloads, and add a --count flag to the CLI to specify how many downloads to fetch
|
||||||
|
- Support alternative keymappings for all keys, featuring hjkl movements
|
||||||
|
- Added the Eldritch theme and updated documentation
|
||||||
|
- Write built in themes to the themes file on first run so users can define custom themes
|
||||||
|
- Created a theme validation macro to verify theme configurations before allowing the TUI to start
|
||||||
|
- Initial support for custom user-defined themes
|
||||||
|
|
||||||
|
### Fix
|
||||||
|
|
||||||
|
- Marked Radarr studios as nullable to prevent crashes
|
||||||
|
- Fixed a bug where the Sonarr API was returning empty values for seeders when searching for season releases
|
||||||
|
- Improve fault tolerance for tag associations in Radarr and Sonarr
|
||||||
|
- Upgraded to the most recent version of Tokio to mitigate CWE-664
|
||||||
|
- Updated all dependencies and updated openssl to the most recent version to mitigate CWE-416
|
||||||
|
- Updated the name of the should_ignore_quit_key to ignore_special_keys_for_textbox_input to give a better idea of what the flag is used for; also added alt keybinding for backspace
|
||||||
|
- Marked videoCodecs as Option to resolve #38
|
||||||
|
- Marked the `Season.statistics` field as `Option` so that a panic does not happen for outdated Sonarr data. This resolves #35
|
||||||
|
- When adding a film from the Collection Details modal, the render order was wrong: Radarr Library -> Collection Table -> Add Movie Prompt (missing the Collection details prompt too). Correct order is: Collection Table -> Collection Details Modal -> Add Movie Modal
|
||||||
|
- Fixed a bug that was rendering encompassing blocks after other widgets were rendered, thus overwriting the custom styles on each previously rendered widget
|
||||||
|
- change the name of the theme configuration file to 'themes'
|
||||||
|
- Ensure key events are only processed on key press to avoid duplicates
|
||||||
|
- Updated ring dependency to mitigate CWE-770
|
||||||
|
- Modified the Sonarr DownloadRecord so that the episode_id is optional to prevent crashes for weird downloads
|
||||||
|
|
||||||
|
### Refactor
|
||||||
|
|
||||||
|
- Network module is now broken out into similar directory structures for each servarr to mimic the rest of the project to make it easier to develop and maintain
|
||||||
|
- Refactored the IndexerTestResut model into the general Servarr models
|
||||||
|
- Renamed 'ctrl-*' keyboard shortcuts to 'C-*' to simplify and shrink the on-screen help
|
||||||
|
- Formatted files using rustfmt
|
||||||
|
- Reformatted code to make the format checks pass
|
||||||
|
- Created a derive macro for defining the display style of Enum models and removed the use of the EnumDisplayStyle trait
|
||||||
|
- Expanded the serde_enum_from macro to further reduce code duplication
|
||||||
|
|
||||||
|
## v0.5.1 (2025-03-01)
|
||||||
|
|
||||||
|
### Feat
|
||||||
|
|
||||||
|
- CLI Support for multiple Servarr instances
|
||||||
|
- Support for multiple servarr definitions - no tests [skip ci]
|
||||||
|
- Support for loading Servarr API tokens from a file
|
||||||
|
- Tweaked the implementation for environment variables in the config a bit
|
||||||
|
- var interpolation
|
||||||
|
|
||||||
|
### Fix
|
||||||
|
|
||||||
|
- Updated openssl to 0.10.70 to mitigate CVE-2025-24898
|
||||||
|
- Addressed rustfmt complaints
|
||||||
|
- Corrected typo in the managarr.nuspec.template
|
||||||
|
|
||||||
|
### Refactor
|
||||||
|
|
||||||
|
- Updated dependencies
|
||||||
|
- Addressed Cargo fmt complaints
|
||||||
|
- Added a debug line for logging to output the config used when starting Managarr
|
||||||
|
- Updated the 2018 idiom lint to the 2021_compatibility lint
|
||||||
|
- Removed unnecessary clones in the networking module to speed up network request handling
|
||||||
|
- Corrected some clone instead of copy behaviors in the command line handlers
|
||||||
|
- Removed unnecessary clone from stateful table
|
||||||
|
- Removed unnecessary clone call from extract_and_add_tag_ids_vec method
|
||||||
|
- Reduced the number of clones necessary when building modal structs
|
||||||
|
- Refactored a handful of Option calls to use take instead
|
||||||
|
- Renamed KeyEventHandler::with to KeyEventHandler::new to keep with Rust best practices and conventions
|
||||||
|
|
||||||
## v0.4.2 (2024-12-21)
|
## v0.4.2 (2024-12-21)
|
||||||
|
|
||||||
### Fix
|
### Fix
|
||||||
|
|||||||
+40
-2
@@ -1,6 +1,23 @@
|
|||||||
# Contributing
|
# Contributing
|
||||||
Contributors are very welcome! **No contribution is too small and all contributions are valued.**
|
Contributors are very welcome! **No contribution is too small and all contributions are valued.**
|
||||||
|
|
||||||
|
## License and Attribution
|
||||||
|
|
||||||
|
#### _If you plan on contributing to the base project, no attribution is needed!_ Feel free to proceed to the [next steps](CONTRIBUTING.md#Rust).
|
||||||
|
|
||||||
|
Otherwise, below are key points to understand from the [Managarr License, Version 1.0](LICENSE):
|
||||||
|
1. **Non-Commercial Use**:
|
||||||
|
- Managarr is licensed solely for non-commercial purposes. Any commercial use of Managarr (e.g., selling or offering as a paid service) requires separate permission.
|
||||||
|
|
||||||
|
2. **Attribution when Forking and Redistributing Without Contributing back to Main Project**:
|
||||||
|
- **If you fork the project and distribute it separately** (e.g., publish or _publicly_ host it independently from the original project), you are required to provide attribution.
|
||||||
|
- You may credit the original author by using any of the following phrasing:
|
||||||
|
- "Thanks to Alexander J. Clarke (Dark-Alex-17) for creating the original Managarr project!"
|
||||||
|
- "Forked from the Managarr project, created by Alexander J. Clarke (Dark-Alex-17)"
|
||||||
|
- "This software is based on the original Managarr project by Alexander J. Clarke (Dark-Alex-17)"
|
||||||
|
- "Inspired by Alexander J. Clarke (Dark-Alex-17)'s Managarr project"
|
||||||
|
- If changes are made to the base Managarr project, please note those modifications and provide the new attribution accordingly.
|
||||||
|
|
||||||
## Rust
|
## Rust
|
||||||
You'll need to have the stable Rust toolchain installed in order to develop Managarr.
|
You'll need to have the stable Rust toolchain installed in order to develop Managarr.
|
||||||
|
|
||||||
@@ -46,12 +63,33 @@ cz commit
|
|||||||
## Setup workspace
|
## Setup workspace
|
||||||
|
|
||||||
1. Clone this repo
|
1. Clone this repo
|
||||||
2. Run `cargo test` to setup hooks
|
2. Run `cargo test` to set up hooks
|
||||||
3. Make changes
|
3. Make changes
|
||||||
4. Run the application using `make run` or `cargo run`
|
4. Run the application using `just run` or `just run`
|
||||||
|
- Install `just` (`cargo install just`) if you haven't already to use the [justfile](./justfile) in this project.
|
||||||
5. Commit changes. This will trigger pre-commit hooks that will run format, test and lint. If there are errors or warnings from Clippy, please fix them.
|
5. Commit changes. This will trigger pre-commit hooks that will run format, test and lint. If there are errors or warnings from Clippy, please fix them.
|
||||||
6. Push your code to a new branch named after the feature/bug/etc. you're adding. This will trigger pre-push hooks that will run lint and test.
|
6. Push your code to a new branch named after the feature/bug/etc. you're adding. This will trigger pre-push hooks that will run lint and test.
|
||||||
7. Create a PR
|
7. Create a PR
|
||||||
|
|
||||||
|
### CI/CD Testing with Act
|
||||||
|
If you also are planning on testing out your changes before pushing them with [Act](https://github.com/nektos/act), you will need to set up `act`,
|
||||||
|
`docker`, and configure your local system to run different architectures:
|
||||||
|
|
||||||
|
1. Install `docker` by following the instructions on the [official Docker installation page](https://docs.docker.com/get-docker/).
|
||||||
|
2. Install `act` by following the instructions on the [official Act installation page](https://nektosact.com/installation/index.html).
|
||||||
|
3. Install `binfmt` on your system once so that `act` can run the correct architecture for the CI/CD workflows.
|
||||||
|
You can do this by running:
|
||||||
|
```shell
|
||||||
|
sudo docker run --rm --privileged tonistiigi/binfmt --install all
|
||||||
|
```
|
||||||
|
|
||||||
|
Then, you can run workflows locally without having to commit and see if the GitHub action passes or fails.
|
||||||
|
|
||||||
|
**For example**: To test the [release.yml](.github/workflows/release.yml) workflow locally, you can run:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
act -W .github/workflows/release.yml --input_type bump=minor
|
||||||
|
```
|
||||||
|
|
||||||
## Questions? Reach out to me!
|
## Questions? Reach out to me!
|
||||||
If you encounter any questions while developing Managarr, please don't hesitate to reach out to me at alex.j.tusa@gmail.com. I'm happy to help contributors, new and experienced in any way I can!
|
If you encounter any questions while developing Managarr, please don't hesitate to reach out to me at alex.j.tusa@gmail.com. I'm happy to help contributors, new and experienced in any way I can!
|
||||||
|
|||||||
Generated
+1204
-570
File diff suppressed because it is too large
Load Diff
+27
-10
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "managarr"
|
name = "managarr"
|
||||||
version = "0.4.2"
|
version = "0.6.3"
|
||||||
authors = ["Alex Clarke <alex.j.tusa@gmail.com>"]
|
authors = ["Alex Clarke <alex.j.tusa@gmail.com>"]
|
||||||
description = "A TUI and CLI to manage your Servarrs"
|
description = "A TUI and CLI to manage your Servarrs"
|
||||||
keywords = ["managarr", "ratatui", "dashboard", "servarr", "tui"]
|
keywords = ["managarr", "ratatui", "dashboard", "servarr", "tui"]
|
||||||
@@ -8,11 +8,17 @@ documentation = "https://github.com/Dark-Alex-17/managarr"
|
|||||||
repository = "https://github.com/Dark-Alex-17/managarr"
|
repository = "https://github.com/Dark-Alex-17/managarr"
|
||||||
homepage = "https://github.com/Dark-Alex-17/managarr"
|
homepage = "https://github.com/Dark-Alex-17/managarr"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
edition = "2021"
|
edition = "2024"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
rust-version = "1.82.0"
|
rust-version = "1.89.0"
|
||||||
exclude = [".github", "CONTRIBUTING.md", "*.log", "tags"]
|
exclude = [".github", "CONTRIBUTING.md", "*.log", "tags"]
|
||||||
|
|
||||||
|
[workspace]
|
||||||
|
members = [
|
||||||
|
"proc_macros/enum_display_style_derive",
|
||||||
|
"proc_macros/validate_theme_derive",
|
||||||
|
]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = "1.0.68"
|
anyhow = "1.0.68"
|
||||||
backtrace = "0.3.74"
|
backtrace = "0.3.74"
|
||||||
@@ -34,33 +40,44 @@ serde_json = "1.0.91"
|
|||||||
serde = { version = "1.0.214", features = ["derive"] }
|
serde = { version = "1.0.214", features = ["derive"] }
|
||||||
strum = { version = "0.26.3", features = ["derive"] }
|
strum = { version = "0.26.3", features = ["derive"] }
|
||||||
strum_macros = "0.26.4"
|
strum_macros = "0.26.4"
|
||||||
tokio = { version = "1.36.0", features = ["full"] }
|
tokio = { version = "1.44.2", features = ["full"] }
|
||||||
tokio-util = "0.7.8"
|
tokio-util = "0.7.8"
|
||||||
ratatui = { version = "0.29.0", features = [
|
ratatui = { version = "0.29.0", features = [
|
||||||
"all-widgets",
|
"all-widgets",
|
||||||
"unstable-widget-ref",
|
"unstable-widget-ref",
|
||||||
] }
|
] }
|
||||||
urlencoding = "2.1.2"
|
urlencoding = "2.1.2"
|
||||||
clap = { version = "4.5.20", features = ["derive", "cargo", "env"] }
|
clap = { version = "4.5.20", features = [
|
||||||
|
"derive",
|
||||||
|
"cargo",
|
||||||
|
"env",
|
||||||
|
"wrap_help",
|
||||||
|
] }
|
||||||
clap_complete = "4.5.33"
|
clap_complete = "4.5.33"
|
||||||
itertools = "0.13.0"
|
itertools = "0.14.0"
|
||||||
ctrlc = "3.4.5"
|
ctrlc = "3.4.5"
|
||||||
colored = "2.1.0"
|
colored = "3.0.0"
|
||||||
async-trait = "0.1.83"
|
async-trait = "0.1.83"
|
||||||
dirs-next = "2.0.0"
|
dirs-next = "2.0.0"
|
||||||
managarr-tree-widget = "0.24.0"
|
managarr-tree-widget = "0.24.0"
|
||||||
indicatif = "0.17.9"
|
indicatif = "0.17.9"
|
||||||
derive_setters = "0.1.6"
|
derive_setters = "0.1.6"
|
||||||
deunicode = "1.6.0"
|
deunicode = "1.6.0"
|
||||||
paste = "1.0.15"
|
openssl = { version = "0.10.70", features = ["vendored"] }
|
||||||
openssl = { version = "0.10.68", features = ["vendored"] }
|
veil = "0.2.0"
|
||||||
|
validate_theme_derive = "0.1.0"
|
||||||
|
enum_display_style_derive = "0.1.0"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
assert_cmd = "2.0.16"
|
assert_cmd = "2.0.16"
|
||||||
mockall = "0.13.0"
|
mockall = "0.13.0"
|
||||||
mockito = "1.0.0"
|
mockito = "1.0.0"
|
||||||
pretty_assertions = "1.3.0"
|
pretty_assertions = "1.3.0"
|
||||||
rstest = "0.23.0"
|
proptest = "1.6.0"
|
||||||
|
rstest = "0.25.0"
|
||||||
|
serial_test = "3.2.0"
|
||||||
|
assertables = "9.8.2"
|
||||||
|
insta = "1.41.1"
|
||||||
|
|
||||||
[dev-dependencies.cargo-husky]
|
[dev-dependencies.cargo-husky]
|
||||||
version = "1"
|
version = "1"
|
||||||
|
|||||||
+2
-1
@@ -1,4 +1,4 @@
|
|||||||
FROM rust:1.82 AS builder
|
FROM rust:1.89 AS builder
|
||||||
WORKDIR /usr/src
|
WORKDIR /usr/src
|
||||||
|
|
||||||
# Download and compile Rust dependencies in an empty project and cache as a separate Docker layer
|
# Download and compile Rust dependencies in an empty project and cache as a separate Docker layer
|
||||||
@@ -6,6 +6,7 @@ RUN USER=root cargo new --bin managarr-temp
|
|||||||
|
|
||||||
WORKDIR /usr/src/managarr-temp
|
WORKDIR /usr/src/managarr-temp
|
||||||
COPY Cargo.* .
|
COPY Cargo.* .
|
||||||
|
COPY proc_macros ./proc_macros
|
||||||
RUN cargo build --release
|
RUN cargo build --release
|
||||||
# remove src from empty project
|
# remove src from empty project
|
||||||
RUN rm -r src
|
RUN rm -r src
|
||||||
|
|||||||
@@ -1,16 +1,53 @@
|
|||||||
MIT License
|
Managarr License
|
||||||
|
Version 1.0, 2025
|
||||||
|
|
||||||
Copyright (c) 2023 Alexander J. Clarke
|
Copyright (c) 2025 Alexander J. Clarke (Dark-Alex-17)
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to use,
|
||||||
in the Software without restriction, including without limitation the rights
|
copy, modify, merge, publish, and distribute the Software solely for
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
non-commercial purposes, subject to the following conditions:
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
1. Attribution:
|
||||||
copies or substantial portions of the Software.
|
- The above copyright notice, this permission notice, and a prominent notice stating
|
||||||
|
that the Software is part of the "Managarr" project shall be included in all copies or
|
||||||
|
substantial portions of the Software **when the Software is forked and redistributed separately** from the original project.
|
||||||
|
- If you fork the software and **distribute it separately** without merging it back into the original base project (the Managarr repository), you must provide attribution to the original author.
|
||||||
|
You may use any of the following forms of attribution:
|
||||||
|
- "Thanks to Alexander J. Clarke (Dark-Alex-17) for creating the original Managarr project!"
|
||||||
|
- "Forked from the Managarr project, created by Alexander J. Clarke (Dark-Alex-17)"
|
||||||
|
- "This software is based on the original Managarr project by Alexander J. Clarke (Dark-Alex-17)"
|
||||||
|
- "Inspired by Alexander J. Clarke (Dark-Alex-17)'s Managarr project"
|
||||||
|
- If you modify the software, the attribution must also note that changes were made and describe those modifications, if feasible.
|
||||||
|
|
||||||
|
2. Non-Commercial Use Only:
|
||||||
|
The use of this Software for commercial purposes, including but not limited
|
||||||
|
to sale, licensing, or use in any product or service for monetary
|
||||||
|
compensation, is strictly prohibited without prior written permission from
|
||||||
|
Alexander J. Clarke (Dark-Alex-17).
|
||||||
|
|
||||||
|
For avoidance of doubt:
|
||||||
|
- **Allowed:** Private use, educational purposes, research, or any usage
|
||||||
|
that does not directly generate revenue.
|
||||||
|
- **Prohibited:** Selling, sublicensing, or incorporating the Software into
|
||||||
|
commercial products or services.
|
||||||
|
|
||||||
|
3. Modifications and Derivatives:
|
||||||
|
- Any modifications or derivative works based on this Software must clearly
|
||||||
|
document all changes made and prominently credit the original "Managarr"
|
||||||
|
project as described in section 1.
|
||||||
|
- Derivative works must retain this license, the original copyright notice,
|
||||||
|
and all terms and conditions described herein. This applies to the entire
|
||||||
|
derivative work, even if combined with other software.
|
||||||
|
|
||||||
|
4. Warranty Disclaimer:
|
||||||
|
This Software is provided "as is," without warranty of any kind, express
|
||||||
|
or implied, including but not limited to the warranties of merchantability,
|
||||||
|
fitness for a particular purpose, and noninfringement. In no event shall the
|
||||||
|
authors or copyright holders be liable for any claim, damages, or other
|
||||||
|
liability, whether in an action of contract, tort, or otherwise, arising
|
||||||
|
from, out of, or in connection with the Software or the use or other
|
||||||
|
dealings in the Software.
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
|||||||
@@ -1,47 +0,0 @@
|
|||||||
#!make
|
|
||||||
VERSION := latest
|
|
||||||
IMG_NAME := darkalex17/managarr
|
|
||||||
IMAGE := ${IMG_NAME}:${VERSION}
|
|
||||||
|
|
||||||
default: run
|
|
||||||
|
|
||||||
.PHONY: test test-cov build run lint lint-fix fmt analyze sonar release delete-tag
|
|
||||||
|
|
||||||
test:
|
|
||||||
@cargo test
|
|
||||||
|
|
||||||
## Run all tests with coverage - `cargo install cargo-tarpaulin`
|
|
||||||
test-cov:
|
|
||||||
@cargo tarpaulin
|
|
||||||
|
|
||||||
build: test
|
|
||||||
@cargo build --release
|
|
||||||
|
|
||||||
docker:
|
|
||||||
@DOCKER_BUILDKIT=1 docker build --rm -t ${IMAGE} .
|
|
||||||
|
|
||||||
run:
|
|
||||||
@CARGO_INCREMENTAL=1 cargo fmt && make lint && cargo run
|
|
||||||
|
|
||||||
lint:
|
|
||||||
@find . | grep '\.\/src\/.*\.rs$$' | xargs touch && CARGO_INCREMENTAL=0 cargo clippy --all-targets --workspace
|
|
||||||
|
|
||||||
lint-fix:
|
|
||||||
@cargo fix
|
|
||||||
|
|
||||||
fmt:
|
|
||||||
@cargo fmt
|
|
||||||
|
|
||||||
minimal-versions:
|
|
||||||
@cargo +nightly update -Zdirect-minimal-versions
|
|
||||||
|
|
||||||
## Analyze for unsafe usage - `cargo install cargo-geiger`
|
|
||||||
analyze:
|
|
||||||
@cargo geiger
|
|
||||||
|
|
||||||
release:
|
|
||||||
@git tag -a ${V} -m "Release ${V}" && git push origin ${V}
|
|
||||||
|
|
||||||
delete-tag:
|
|
||||||
@git tag -d ${V} && git push --delete origin ${V}
|
|
||||||
|
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
# managarr - A TUI and CLI to manage your Servarrs
|
# managarr - A TUI and CLI to manage your Servarrs
|
||||||
|
|
||||||

|

|
||||||

|

|
||||||

|

|
||||||

|

|
||||||
[](https://crates.io/crates/managarr)
|
[](https://crates.io/crates/managarr)
|
||||||
@@ -10,6 +10,8 @@
|
|||||||

|

|
||||||
[](https://github.com/Dark-Alex-17/managarr/releases)
|
[](https://github.com/Dark-Alex-17/managarr/releases)
|
||||||

|

|
||||||
|
[](https://matrix.to/#/#managarr:matrix.org)
|
||||||
|
|
||||||
|
|
||||||
Managarr is a TUI and CLI to help you manage your HTPC (Home Theater PC). Built with 🤎 in Rust!
|
Managarr is a TUI and CLI to help you manage your HTPC (Home Theater PC). Built with 🤎 in Rust!
|
||||||
|
|
||||||
@@ -26,7 +28,7 @@ Managarr is a TUI and CLI to help you manage your HTPC (Home Theater PC). Built
|
|||||||
- [ ]  [Bazarr](https://www.bazarr.media/)
|
- [ ]  [Bazarr](https://www.bazarr.media/)
|
||||||
- [ ]  [Tautulli](https://tautulli.com/)
|
- [ ]  [Tautulli](https://tautulli.com/)
|
||||||
|
|
||||||
## Try Before You Buy
|
## Try Out the Demo
|
||||||
To try out Managarr before linking it to your HTPC, you can use the purpose built [managarr-demo](https://github.com/Dark-Alex-17/managarr-demo) repository.
|
To try out Managarr before linking it to your HTPC, you can use the purpose built [managarr-demo](https://github.com/Dark-Alex-17/managarr-demo) repository.
|
||||||
Simply run the following command to start a demo:
|
Simply run the following command to start a demo:
|
||||||
|
|
||||||
@@ -61,7 +63,7 @@ Please note that you will need to create and popular your configuration file fir
|
|||||||
**Note:** If you run into errors using relative file paths when mounting the volume with the configuration file, try using an absolute path.
|
**Note:** If you run into errors using relative file paths when mounting the volume with the configuration file, try using an absolute path.
|
||||||
|
|
||||||
### Homebrew (Mac and Linux)
|
### Homebrew (Mac and Linux)
|
||||||
To install Managarr from Homebrew, install the Managarr tap and then you'll be able to install Managarr:
|
To install Managarr from Homebrew, install the Managarr tap. Then you'll be able to install Managarr:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
brew tap Dark-Alex-17/managarr
|
brew tap Dark-Alex-17/managarr
|
||||||
@@ -76,6 +78,16 @@ To upgrade to a newer version of Managarr:
|
|||||||
brew upgrade managarr
|
brew upgrade managarr
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Nix (Externally Maintained)
|
||||||
|
To install Managarr on NixOS, you can use the following command:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
nix-env --install managarr
|
||||||
|
|
||||||
|
# Alternatively, for non-NixOS users, you can spawn a temporary shell with Managarr available like so:
|
||||||
|
nix-shell -p managarr
|
||||||
|
```
|
||||||
|
|
||||||
### Chocolatey (Windows)
|
### Chocolatey (Windows)
|
||||||
The Managarr Chocolatey package is located [here](https://community.chocolatey.org/packages/managarr). Please note that validation
|
The Managarr Chocolatey package is located [here](https://community.chocolatey.org/packages/managarr). Please note that validation
|
||||||
of Chocolatey packages take quite some time, and thus the package may not be available immediately after a new release.
|
of Chocolatey packages take quite some time, and thus the package may not be available immediately after a new release.
|
||||||
@@ -84,7 +96,7 @@ of Chocolatey packages take quite some time, and thus the package may not be ava
|
|||||||
choco install managarr
|
choco install managarr
|
||||||
|
|
||||||
# Some newer releases may require a version number, so you can specify it like so:
|
# Some newer releases may require a version number, so you can specify it like so:
|
||||||
choco install managarr --version=0.4.1
|
choco install managarr --version=0.5.0
|
||||||
```
|
```
|
||||||
|
|
||||||
To upgrade to the latest and greatest version of Managarr:
|
To upgrade to the latest and greatest version of Managarr:
|
||||||
@@ -92,7 +104,7 @@ To upgrade to the latest and greatest version of Managarr:
|
|||||||
choco upgrade managarr
|
choco upgrade managarr
|
||||||
|
|
||||||
# To upgrade to a specific version:
|
# To upgrade to a specific version:
|
||||||
choco upgrade managarr --version=0.4.2
|
choco upgrade managarr --version=0.5.0
|
||||||
```
|
```
|
||||||
|
|
||||||
### Manual
|
### Manual
|
||||||
@@ -107,16 +119,16 @@ Binaries are available on the [releases](https://github.com/Dark-Alex-17/managar
|
|||||||
#### Windows Instructions
|
#### Windows Instructions
|
||||||
To use a binary from the releases page on Windows, do the following:
|
To use a binary from the releases page on Windows, do the following:
|
||||||
|
|
||||||
1. Download the latest binary [binary](https://github.com/Dark-Alex-17/managarr/releases) for your OS.
|
1. Download the latest [binary](https://github.com/Dark-Alex-17/managarr/releases) for your OS.
|
||||||
2. Use 7-Zip or TarTool to unpack the Tar file.
|
2. Use 7-Zip or TarTool to unpack the Tar file.
|
||||||
3. Run the executable `managarr.exe`!
|
3. Run the executable `managarr.exe`!
|
||||||
|
|
||||||
#### Linux/MacOS Instructions
|
#### Linux/MacOS Instructions
|
||||||
To use a binary from the releases page on Linux/MacOS, do the following:
|
To use a binary from the releases page on Linux/MacOS, do the following:
|
||||||
|
|
||||||
1. Download the latest binary [binary](https://github.com/Dark-Alex-17/managarr/releases) for your OS.
|
1. Download the latest [binary](https://github.com/Dark-Alex-17/managarr/releases) for your OS.
|
||||||
2. `cd` to the directory where you downloaded the binary.
|
2. `cd` to the directory where you downloaded the binary.
|
||||||
3. Extract the binary with `tar -C /usr/local/bin -xzf managarr-<arch>.tar.gz` (NB: This may require `sudo`)
|
3. Extract the binary with `tar -C /usr/local/bin -xzf managarr-<arch>.tar.gz` (Note: This may require `sudo`)
|
||||||
4. Now you can run `managarr`!
|
4. Now you can run `managarr`!
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
@@ -154,21 +166,21 @@ Key:
|
|||||||
|
|
||||||
| TUI | CLI | Feature |
|
| TUI | CLI | Feature |
|
||||||
|-----|-----|--------------------------------------------------------------------------------------------------------------------|
|
|-----|-----|--------------------------------------------------------------------------------------------------------------------|
|
||||||
| ✅ | ✅ | View your library, downloads, blocklist, episodes |
|
| ✅ | ✅ | View your library, downloads, blocklist, episodes |
|
||||||
| ✅ | ✅ | View details of a specific series, or episode including description, history, downloaded file info, or the credits |
|
| ✅ | ✅ | View details of a specific series, or episode including description, history, downloaded file info, or the credits |
|
||||||
| 🚫 | ✅ | View your host and security configs from the CLI to programmatically fetch the API token, among other settings |
|
| 🚫 | ✅ | View your host and security configs from the CLI to programmatically fetch the API token, among other settings |
|
||||||
| ✅ | ✅ | Search your library |
|
| ✅ | ✅ | Search your library |
|
||||||
| ✅ | ✅ | Add series to your library |
|
| ✅ | ✅ | Add series to your library |
|
||||||
| ✅ | ✅ | Delete series, downloads, indexers, root folders, and episode files |
|
| ✅ | ✅ | Delete series, downloads, indexers, root folders, and episode files |
|
||||||
| ✅ | ✅ | Trigger automatic searches for series, seasons, or episodes |
|
| ✅ | ✅ | Trigger automatic searches for series, seasons, or episodes |
|
||||||
| ✅ | ✅ | Trigger refresh and disk scan for series and downloads |
|
| ✅ | ✅ | Trigger refresh and disk scan for series and downloads |
|
||||||
| ✅ | ✅ | Manually search for series, seasons, or episodes |
|
| ✅ | ✅ | Manually search for series, seasons, or episodes |
|
||||||
| ✅ | ✅ | Edit your series and indexers |
|
| ✅ | ✅ | Edit your series and indexers |
|
||||||
| ✅ | ✅ | Manage your tags |
|
| ✅ | ✅ | Manage your tags |
|
||||||
| ✅ | ✅ | Manage your root folders |
|
| ✅ | ✅ | Manage your root folders |
|
||||||
| ✅ | ✅ | Manage your blocklist |
|
| ✅ | ✅ | Manage your blocklist |
|
||||||
| ✅ | ✅ | View and browse logs, tasks, events queues, and updates |
|
| ✅ | ✅ | View and browse logs, tasks, events queues, and updates |
|
||||||
| ✅ | ✅ | Manually trigger scheduled tasks |
|
| ✅ | ✅ | Manually trigger scheduled tasks |
|
||||||
|
|
||||||
### Readarr
|
### Readarr
|
||||||
|
|
||||||
@@ -194,6 +206,19 @@ Key:
|
|||||||
|
|
||||||
- [ ] Support for Tautulli
|
- [ ] Support for Tautulli
|
||||||
|
|
||||||
|
### Themes
|
||||||
|
Managarr ships with a few themes out of the box. Here's a few examples:
|
||||||
|
|
||||||
|
#### Default
|
||||||
|

|
||||||
|
#### Dracula
|
||||||
|

|
||||||
|
#### Watermelon Dark
|
||||||
|

|
||||||
|
|
||||||
|
You can also create your own custom themes as well. To learn more about what themes are built-in to Managarr and how
|
||||||
|
to create your own custom themes, check out the [Themes README](themes/README.md).
|
||||||
|
|
||||||
### The Managarr CLI
|
### The Managarr CLI
|
||||||
Managarr can be used in one of two ways: As a TUI, or as a CLI for managing your Servarrs.
|
Managarr can be used in one of two ways: As a TUI, or as a CLI for managing your Servarrs.
|
||||||
|
|
||||||
@@ -206,7 +231,7 @@ To see all available commands, simply run `managarr --help`:
|
|||||||
|
|
||||||
```shell
|
```shell
|
||||||
$ managarr --help
|
$ managarr --help
|
||||||
managarr 0.4.0
|
managarr 0.5.1
|
||||||
Alex Clarke <alex.j.tusa@gmail.com>
|
Alex Clarke <alex.j.tusa@gmail.com>
|
||||||
|
|
||||||
A TUI and CLI to manage your Servarrs
|
A TUI and CLI to manage your Servarrs
|
||||||
@@ -221,10 +246,15 @@ Commands:
|
|||||||
help Print this message or the help of the given subcommand(s)
|
help Print this message or the help of the given subcommand(s)
|
||||||
|
|
||||||
Options:
|
Options:
|
||||||
--disable-spinner Disable the spinner (can sometimes make parsing output challenging) [env: MANAGARR_DISABLE_SPINNER=]
|
--disable-spinner Disable the spinner (can sometimes make parsing output challenging) [env: MANAGARR_DISABLE_SPINNER=]
|
||||||
--config <CONFIG> The Managarr configuration file to use [env: MANAGARR_CONFIG_FILE=]
|
--config-file <CONFIG_FILE> The Managarr configuration file to use [env: MANAGARR_CONFIG_FILE=]
|
||||||
-h, --help Print help
|
--themes-file <THEMES_FILE> The Managarr themes file to use [env: MANAGARR_THEMES_FILE=]
|
||||||
-V, --version Print version
|
--theme <THEME> The name of the Managarr theme to use [env: MANAGARR_THEME=]
|
||||||
|
--servarr-name <SERVARR_NAME> For multi-instance configurations, you need to specify the name of the instance configuration that you want to use.
|
||||||
|
This is useful when you have multiple instances of the same Servarr defined in your config file.
|
||||||
|
By default, if left empty, the first configured Servarr instance listed in the config file will be used.
|
||||||
|
-h, --help Print help
|
||||||
|
-V, --version Print version
|
||||||
```
|
```
|
||||||
|
|
||||||
All subcommands also have detailed help menus to show you how to use them. For example, to see all available commands for Sonarr, you would run:
|
All subcommands also have detailed help menus to show you how to use them. For example, to see all available commands for Sonarr, you would run:
|
||||||
@@ -295,44 +325,99 @@ where you may have more than one instance of a given Servarr running. Thus, you
|
|||||||
config file using the `--config` flag:
|
config file using the `--config` flag:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
managarr --config /path/to/config.yml
|
managarr --config-file /path/to/config.yml
|
||||||
```
|
```
|
||||||
|
|
||||||
### Example Configuration:
|
### Example Configuration:
|
||||||
```yaml
|
```yaml
|
||||||
|
theme: default
|
||||||
radarr:
|
radarr:
|
||||||
host: 192.168.0.78
|
- host: 192.168.0.78
|
||||||
port: 7878
|
port: 7878
|
||||||
api_token: someApiToken1234567890
|
api_token: someApiToken1234567890
|
||||||
ssl_cert_path: /path/to/radarr.crt # Required to enable SSL
|
ssl_cert_path: /path/to/radarr.crt # Required to enable SSL
|
||||||
sonarr:
|
sonarr:
|
||||||
uri: http://htpc.local/sonarr # Example of using the 'uri' key instead of 'host' and 'port'
|
- uri: http://htpc.local/sonarr # Example of using the 'uri' key instead of 'host' and 'port'
|
||||||
api_token: someApiToken1234567890
|
api_token: someApiToken1234567890
|
||||||
|
|
||||||
|
- name: Anime Sonarr # An example of a custom name for a secondary Sonarr instance
|
||||||
|
host: 192.168.0.89
|
||||||
|
port: 8989
|
||||||
|
api_token: someApiToken1234567890
|
||||||
readarr:
|
readarr:
|
||||||
host: 192.168.0.87
|
- host: 192.168.0.87
|
||||||
port: 8787
|
port: 8787
|
||||||
api_token: someApiToken1234567890
|
api_token_file: /root/.config/readarr_api_token # Example of loading the API token from a file instead of hardcoding it in the configuration file
|
||||||
lidarr:
|
lidarr:
|
||||||
host: 192.168.0.86
|
- host: 192.168.0.86
|
||||||
port: 8686
|
port: 8686
|
||||||
api_token: someApiToken1234567890
|
api_token: ${MY_LIDARR_API_TOKEN} # Example of configuring using environment variables
|
||||||
whisparr:
|
whisparr:
|
||||||
host: 192.168.0.69
|
- host: 192.168.0.69
|
||||||
port: 6969
|
port: 6969
|
||||||
api_token: someApiToken1234567890
|
api_token: someApiToken1234567890
|
||||||
ssl_cert_path: /path/to/whisparr.crt
|
ssl_cert_path: /path/to/whisparr.crt
|
||||||
|
custom_headers: # Example of adding custom headers to all requests to the Servarr instance
|
||||||
|
traefik-auth-bypass-key: someBypassKey1234567890
|
||||||
|
SOME-OTHER-CUSTOM-HEADER: ${MY_CUSTOM_HEADER_VALUE}
|
||||||
bazarr:
|
bazarr:
|
||||||
host: 192.168.0.67
|
- host: 192.168.0.67
|
||||||
port: 6767
|
port: 6767
|
||||||
api_token: someApiToken1234567890
|
api_token: someApiToken1234567890
|
||||||
prowlarr:
|
prowlarr:
|
||||||
host: 192.168.0.96
|
- host: 192.168.0.96
|
||||||
port: 9696
|
port: 9696
|
||||||
api_token: someApiToken1234567890
|
api_token: someApiToken1234567890
|
||||||
tautulli:
|
tautulli:
|
||||||
host: 192.168.0.81
|
- host: 192.168.0.81
|
||||||
port: 8181
|
port: 8181
|
||||||
api_token: someApiToken1234567890
|
api_token: someApiToken1234567890
|
||||||
|
```
|
||||||
|
|
||||||
|
### Example Multi-Instance Configuration:
|
||||||
|
```yaml
|
||||||
|
theme: default
|
||||||
|
radarr:
|
||||||
|
- host: 192.168.0.78 # No name specified, so this instance's name will default to 'Radarr 1'
|
||||||
|
port: 7878
|
||||||
|
api_token: someApiToken1234567890
|
||||||
|
ssl_cert_path: /path/to/radarr.crt
|
||||||
|
|
||||||
|
- name: International Movies
|
||||||
|
host: 192.168.0.79
|
||||||
|
port: 7878
|
||||||
|
api_token: someApiToken1234567890
|
||||||
|
sonarr:
|
||||||
|
- name: Anime
|
||||||
|
weight: 1 # This instance will be the first tab in the TUI
|
||||||
|
uri: http://htpc.local/sonarr
|
||||||
|
api_token: someApiToken1234567890
|
||||||
|
|
||||||
|
- name: TV Shows
|
||||||
|
weight: 2 # This instance will be the second tab in the TUI
|
||||||
|
host: 192.168.0.89
|
||||||
|
port: 8989
|
||||||
|
api_token: someApiToken1234567890
|
||||||
|
```
|
||||||
|
|
||||||
|
In this configuration, you can see that we have multiple instances of Radarr and Sonarr configured. The `weight` key is
|
||||||
|
used to specify the order in which the tabs will appear in the TUI. The lower the weight, the further to the left the
|
||||||
|
tab will appear. If no weight is specified, then tabs will be ordered in the order they appear in the configuration
|
||||||
|
file.
|
||||||
|
|
||||||
|
When no `name` is specified for a Servarr instance, the name will default to the name of the Servarr with a number
|
||||||
|
appended to it. For example, if you have two Radarr instances and neither has a name, they will be named `Radarr 1` and
|
||||||
|
`Radarr 2`, respectively.
|
||||||
|
|
||||||
|
In this example configuration, the tabs in the TUI would appear as follows:
|
||||||
|
|
||||||
|
`Anime | TV Shows | Radarr 1 | International Movies`
|
||||||
|
|
||||||
|
### Specify Which Servarr Instance to Use in the CLI
|
||||||
|
If you have multiple instances of the same Servarr running, you can specify which instance you want to use by using the `--servarr-name` flag:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
managarr --servarr-name "International Movies"
|
||||||
```
|
```
|
||||||
|
|
||||||
## Environment Variables
|
## Environment Variables
|
||||||
|
|||||||
@@ -1,5 +1,14 @@
|
|||||||
coverage:
|
coverage:
|
||||||
range: "80..100"
|
range: "80..100"
|
||||||
|
status:
|
||||||
|
project:
|
||||||
|
default:
|
||||||
|
threshold: 0
|
||||||
|
target: 80%
|
||||||
|
patch:
|
||||||
|
default:
|
||||||
|
threshold: 0
|
||||||
|
target: 80%
|
||||||
|
|
||||||
ignore:
|
ignore:
|
||||||
- "**/*_tests.rs"
|
- "**/*_tests.rs"
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ This is a nuspec. It mostly adheres to https://docs.nuget.org/create/Nuspec-Refe
|
|||||||
<tags>cli cross-platform terminal servarr tui sonarr radarr rust</tags>
|
<tags>cli cross-platform terminal servarr tui sonarr radarr rust</tags>
|
||||||
<summary>A TUI and CLI for managing *arr servers.</summary>
|
<summary>A TUI and CLI for managing *arr servers.</summary>
|
||||||
<description>
|
<description>
|
||||||
A TUI and CLI for managing *arr servers. Build with love in Rust!
|
A TUI and CLI for managing *arr servers. Built with love in Rust!
|
||||||
|
|
||||||
**Usage**
|
**Usage**
|
||||||
To use, run `managarr` in a terminal.
|
To use, run `managarr` in a terminal.
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
# Documentation: https://docs.brew.sh/Formula-Cookbook
|
# Documentation: https://docs.brew.sh/Formula-Cookbook
|
||||||
# https://rubydoc.brew.sh/Formula
|
# https://rubydoc.brew.sh/Formula
|
||||||
class Managarr < Formula
|
class Managarr < Formula
|
||||||
desc "A fast and simple dashboard for Kubernetes written in Rust"
|
desc "Managarr is a TUI and CLI to help you manage your HTPC (Home Theater PC)"
|
||||||
homepage "https://github.com/Dark-Alex-17/managarr"
|
homepage "https://github.com/Dark-Alex-17/managarr"
|
||||||
if OS.mac? and Hardware::CPU.arm?
|
if OS.mac? and Hardware::CPU.arm?
|
||||||
url "https://github.com/Dark-Alex-17/managarr/releases/download/v$version/managarr-macos-arm64.tar.gz"
|
url "https://github.com/Dark-Alex-17/managarr/releases/download/v$version/managarr-macos-arm64.tar.gz"
|
||||||
|
|||||||
@@ -0,0 +1,81 @@
|
|||||||
|
VERSION := "latest"
|
||||||
|
IMG_NAME := "darkalex17/managarr"
|
||||||
|
IMAGE := "{{IMG_NAME}}:{{VERSION}}"
|
||||||
|
|
||||||
|
|
||||||
|
# List all recipes
|
||||||
|
default:
|
||||||
|
@just --list
|
||||||
|
|
||||||
|
# Format all files
|
||||||
|
[group: 'style']
|
||||||
|
fmt:
|
||||||
|
@cargo fmt --all
|
||||||
|
|
||||||
|
alias clippy := lint
|
||||||
|
# Run Clippy to inspect all files
|
||||||
|
[group: 'style']
|
||||||
|
lint:
|
||||||
|
@cargo clippy --all
|
||||||
|
|
||||||
|
alias clippy-fix := lint-fix
|
||||||
|
# Automatically fix clippy issues where possible
|
||||||
|
[group: 'style']
|
||||||
|
lint-fix:
|
||||||
|
@cargo fix
|
||||||
|
|
||||||
|
# Analyze the project for unsafe usage
|
||||||
|
[group: 'style']
|
||||||
|
@analyze:
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
cargo geiger -h > /dev/null 2>&1 | cargo install cargo-geiger
|
||||||
|
cargo geiger
|
||||||
|
|
||||||
|
# Run all tests
|
||||||
|
[group: 'test']
|
||||||
|
test:
|
||||||
|
@cargo test --all
|
||||||
|
|
||||||
|
# Run all tests with coverage
|
||||||
|
[group:'test']
|
||||||
|
@test-cov:
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
cargo tarpaulin -h > /dev/null 2>&1 || cargo install cargo-tarpaulin
|
||||||
|
cargo tarpaulin
|
||||||
|
|
||||||
|
# Run all doc tests
|
||||||
|
[group: 'test']
|
||||||
|
doctest:
|
||||||
|
@cargo test --all --doc
|
||||||
|
|
||||||
|
# Run all proptests
|
||||||
|
[group: 'test']
|
||||||
|
proptest:
|
||||||
|
@cargo test proptest
|
||||||
|
|
||||||
|
# Run all snapshot tests
|
||||||
|
[group: 'test']
|
||||||
|
snapshot-tests:
|
||||||
|
@cargo test snapshot
|
||||||
|
|
||||||
|
# Review snapshot test changes
|
||||||
|
[group: 'test']
|
||||||
|
@snapshot-review:
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
cargo insta -h > /dev/null 2>&1 || cargo install cargo-insta
|
||||||
|
cargo insta review
|
||||||
|
|
||||||
|
# Build and run the binary for the current system
|
||||||
|
run:
|
||||||
|
@cargo run
|
||||||
|
|
||||||
|
# Build the project for the current system architecture
|
||||||
|
[group: 'build']
|
||||||
|
[arg('build_type', pattern="debug|release")]
|
||||||
|
build build_type='debug':
|
||||||
|
@cargo build {{ if build_type == "release" { "--release" } else { "" } }}
|
||||||
|
|
||||||
|
# Build the docker image
|
||||||
|
[group: 'build']
|
||||||
|
build-docker:
|
||||||
|
@DOCKER_BUILDKIT=1 docker build --rm -t {{IMAGE}}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
[package]
|
||||||
|
name = "enum_display_style_derive"
|
||||||
|
version = "0.6.1"
|
||||||
|
edition = "2024"
|
||||||
|
authors = ["Alex Clarke <alex.j.tusa@gmail.com>"]
|
||||||
|
description = "A proc-macro to derive a `Display` and `FromStr` implementation for enums with a `style` attribute."
|
||||||
|
license = "MIT"
|
||||||
|
documentation = "https://github.com/Dark-Alex-17/managarr"
|
||||||
|
repository = "https://github.com/Dark-Alex-17/managarr"
|
||||||
|
homepage = "https://github.com/Dark-Alex-17/managarr"
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
proc-macro = true
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
quote = "1.0.39"
|
||||||
|
syn = "2.0.99"
|
||||||
|
darling = "0.20.10"
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
mod macro_models;
|
||||||
|
|
||||||
|
use crate::macro_models::DisplayStyleArgs;
|
||||||
|
use darling::FromVariant;
|
||||||
|
use quote::quote;
|
||||||
|
use syn::{Data, DeriveInput, parse_macro_input};
|
||||||
|
|
||||||
|
/// Derive macro for generating a `to_display_str` method for an enum.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// Using default values for the display style:
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use enum_display_style_derive::EnumDisplayStyle;
|
||||||
|
///
|
||||||
|
/// #[derive(EnumDisplayStyle)]
|
||||||
|
/// enum Weekend {
|
||||||
|
/// Saturday,
|
||||||
|
/// Sunday,
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// assert_eq!(Weekend::Saturday.to_display_str(), "Saturday");
|
||||||
|
/// assert_eq!(Weekend::Sunday.to_display_str(), "Sunday");
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// Using custom values for the display style:
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use enum_display_style_derive::EnumDisplayStyle;
|
||||||
|
///
|
||||||
|
/// #[derive(EnumDisplayStyle)]
|
||||||
|
/// enum MonitorStatus {
|
||||||
|
/// #[display_style(name = "Monitor Transactions")]
|
||||||
|
/// Active,
|
||||||
|
/// #[display_style(name = "Don't Monitor Transactions")]
|
||||||
|
/// None,
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// assert_eq!(MonitorStatus::Active.to_display_str(), "Monitor Transactions");
|
||||||
|
/// assert_eq!(MonitorStatus::None.to_display_str(), "Don't Monitor Transactions");
|
||||||
|
/// ```
|
||||||
|
#[proc_macro_derive(EnumDisplayStyle, attributes(display_style))]
|
||||||
|
pub fn enum_display_style_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
||||||
|
let input = parse_macro_input!(input as DeriveInput);
|
||||||
|
let enum_name = &input.ident;
|
||||||
|
|
||||||
|
let mut match_arms = Vec::new();
|
||||||
|
|
||||||
|
if let Data::Enum(data_enum) = &input.data {
|
||||||
|
let variants = &data_enum.variants;
|
||||||
|
|
||||||
|
for variant in variants {
|
||||||
|
let variant_ident = &variant.ident;
|
||||||
|
let variant_display_name = DisplayStyleArgs::from_variant(variant)
|
||||||
|
.unwrap()
|
||||||
|
.name
|
||||||
|
.unwrap_or_else(|| variant_ident.to_string());
|
||||||
|
|
||||||
|
match_arms.push(quote! {
|
||||||
|
#enum_name::#variant_ident => #variant_display_name,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
quote! {
|
||||||
|
impl<'a> #enum_name {
|
||||||
|
pub fn to_display_str(self) -> &'a str {
|
||||||
|
match self {
|
||||||
|
#(#match_arms)*
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.into()
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
use darling::FromVariant;
|
||||||
|
|
||||||
|
#[derive(Debug, FromVariant)]
|
||||||
|
#[darling(attributes(display_style))]
|
||||||
|
pub struct DisplayStyleArgs {
|
||||||
|
pub name: Option<String>,
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
[package]
|
||||||
|
name = "validate_theme_derive"
|
||||||
|
version = "0.6.1"
|
||||||
|
edition = "2024"
|
||||||
|
authors = ["Alex Clarke <alex.j.tusa@gmail.com>"]
|
||||||
|
description = "A proc-macro to validate a theme."
|
||||||
|
license = "MIT"
|
||||||
|
documentation = "https://github.com/Dark-Alex-17/managarr"
|
||||||
|
repository = "https://github.com/Dark-Alex-17/managarr"
|
||||||
|
homepage = "https://github.com/Dark-Alex-17/managarr"
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
proc-macro = true
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
quote = "1.0.39"
|
||||||
|
syn = "2.0.99"
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
log = "0.4.17"
|
||||||
@@ -0,0 +1,106 @@
|
|||||||
|
use proc_macro::TokenStream;
|
||||||
|
use quote::quote;
|
||||||
|
use syn::{Data, DeriveInput, Fields, parse_macro_input};
|
||||||
|
|
||||||
|
/// Derive macro for generating a `validate` method for a Theme struct.
|
||||||
|
/// The `validate` method ensures that all values with the `validate` attribute are not `None`.
|
||||||
|
/// Otherwise, an error message it output to both the log file and stdout and the program exits.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// Valid themes pass through the program transitively without any messages being output.
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use validate_theme_derive::ValidateTheme;
|
||||||
|
///
|
||||||
|
/// #[derive(ValidateTheme, Default)]
|
||||||
|
/// struct Theme {
|
||||||
|
/// pub name: String,
|
||||||
|
/// #[validate]
|
||||||
|
/// pub good: Option<Style>,
|
||||||
|
/// #[validate]
|
||||||
|
/// pub bad: Option<Style>,
|
||||||
|
/// pub ugly: Option<Style>,
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// struct Style {
|
||||||
|
/// color: String,
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// let theme = Theme {
|
||||||
|
/// good: Some(Style { color: "Green".to_owned() }),
|
||||||
|
/// bad: Some(Style { color: "Red".to_owned() }),
|
||||||
|
/// ..Theme::default()
|
||||||
|
/// };
|
||||||
|
///
|
||||||
|
/// // Since only `good` and `bad` have the `validate` attribute, the `validate` method will only check those fields.
|
||||||
|
/// theme.validate();
|
||||||
|
/// // Since both `good` and `bad` have values, the program will not exit and no message is output.
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// Invalid themes will output an error message to both the log file and stdout and the program will exit.
|
||||||
|
///
|
||||||
|
/// ```should_panic
|
||||||
|
/// use validate_theme_derive::ValidateTheme;
|
||||||
|
///
|
||||||
|
/// #[derive(ValidateTheme, Default)]
|
||||||
|
/// struct Theme {
|
||||||
|
/// pub name: String,
|
||||||
|
/// #[validate]
|
||||||
|
/// pub good: Option<Style>,
|
||||||
|
/// #[validate]
|
||||||
|
/// pub bad: Option<Style>,
|
||||||
|
/// pub ugly: Option<Style>,
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// struct Style {
|
||||||
|
/// color: String,
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// let theme = Theme {
|
||||||
|
/// bad: Some(Style { color: "Red".to_owned() }),
|
||||||
|
/// ..Theme::default()
|
||||||
|
/// };
|
||||||
|
///
|
||||||
|
/// // Since `good` has the `validate` attribute and since `good` is `None`, the `validate` method will output an error message and exit the program.
|
||||||
|
/// theme.validate();
|
||||||
|
/// ```
|
||||||
|
#[proc_macro_derive(ValidateTheme, attributes(validate))]
|
||||||
|
pub fn derive_validate_theme(input: TokenStream) -> TokenStream {
|
||||||
|
let input = parse_macro_input!(input as DeriveInput);
|
||||||
|
let struct_name = &input.ident;
|
||||||
|
|
||||||
|
let mut validation_checks = Vec::new();
|
||||||
|
|
||||||
|
if let Data::Struct(data_struct) = &input.data
|
||||||
|
&& let Fields::Named(fields) = &data_struct.fields
|
||||||
|
{
|
||||||
|
for field in &fields.named {
|
||||||
|
let field_name = &field.ident;
|
||||||
|
|
||||||
|
let has_validate_attr = field
|
||||||
|
.attrs
|
||||||
|
.iter()
|
||||||
|
.any(|attr| attr.path().is_ident("validate"));
|
||||||
|
|
||||||
|
if has_validate_attr {
|
||||||
|
validation_checks.push(quote! {
|
||||||
|
if self.#field_name.is_none() {
|
||||||
|
log::error!("{} is missing a color value.", stringify!(#field_name));
|
||||||
|
eprintln!("{} is missing a color value.", stringify!(#field_name));
|
||||||
|
std::process::exit(1);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
quote! {
|
||||||
|
impl #struct_name {
|
||||||
|
pub fn validate(&self) {
|
||||||
|
#(#validation_checks)*
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.into()
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
# Seeds for failure cases proptest has generated in the past. It is
|
||||||
|
# automatically read and these particular cases re-run before any
|
||||||
|
# novel cases are generated.
|
||||||
|
#
|
||||||
|
# It is recommended to check this file in to source control so that
|
||||||
|
# everyone who runs the test benefits from these saved cases.
|
||||||
|
cc 56330c025ad79db641d0eb9f429ab74e95822e1fb015b58f0e158ea674cd42a1 # shrinks to list_size = 1, page_ops = 1
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
# Seeds for failure cases proptest has generated in the past. It is
|
||||||
|
# automatically read and these particular cases re-run before any
|
||||||
|
# novel cases are generated.
|
||||||
|
#
|
||||||
|
# It is recommended to check this file in to source control so that
|
||||||
|
# everyone who runs the test benefits from these saved cases.
|
||||||
|
cc fb4b58aa3015a125fc33a78dfaf27981db4191247151b327a351fc445e07c231 # shrinks to input = "j"
|
||||||
|
cc d6ec17d4d3f635f0a095ade650a316d26abc1f9fe2b6d9cf67bf2f8b4ebedb60 # shrinks to backspace_count = 0
|
||||||
|
cc cd46ee46e18cf86c940fb89c7206f0b482909880b8f2eabe3dd20682b9912c8a # shrinks to input = "h"
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
# Seeds for failure cases proptest has generated in the past. It is
|
||||||
|
# automatically read and these particular cases re-run before any
|
||||||
|
# novel cases are generated.
|
||||||
|
#
|
||||||
|
# It is recommended to check this file in to source control so that
|
||||||
|
# everyone who runs the test benefits from these saved cases.
|
||||||
|
cc 24ae243412a324cb46c36cb4f629ddd4c9326b1479d1186d9b5545ac5e86dbba # shrinks to num_scroll_attempts = 0
|
||||||
|
cc c06a1cc1e4740b2498c50d7be64715bf09ef3ac4cf3bb3642f960578a3e06c74 # shrinks to is_loading = false, num_items = 1
|
||||||
|
cc 930207899afea2d389c7fa3974e31c2eb1803e71bcbd8179246c795903905ec7 # shrinks to parent_width = 20, parent_height = 12, percent_x = 1, percent_y = 1
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 382 KiB After Width: | Height: | Size: 340 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 211 KiB After Width: | Height: | Size: 241 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 203 KiB After Width: | Height: | Size: 220 KiB |
+350
-83
@@ -1,51 +1,67 @@
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::models::Route;
|
|
||||||
use anyhow::anyhow;
|
use anyhow::anyhow;
|
||||||
use pretty_assertions::assert_eq;
|
use pretty_assertions::{assert_eq, assert_str_eq};
|
||||||
use rstest::rstest;
|
use reqwest::header::{HeaderMap, HeaderName, HeaderValue};
|
||||||
|
use serde_json::Value;
|
||||||
|
use serial_test::serial;
|
||||||
use tokio::sync::mpsc;
|
use tokio::sync::mpsc;
|
||||||
|
|
||||||
use crate::app::context_clues::{build_context_clue_string, SERVARR_CONTEXT_CLUES};
|
use crate::app::{App, AppConfig, Data, ServarrConfig, interpolate_env_vars};
|
||||||
use crate::app::{App, AppConfig, Data, ServarrConfig};
|
|
||||||
use crate::models::servarr_data::radarr::radarr_data::{ActiveRadarrBlock, RadarrData};
|
use crate::models::servarr_data::radarr::radarr_data::{ActiveRadarrBlock, RadarrData};
|
||||||
use crate::models::servarr_data::sonarr::sonarr_data::{ActiveSonarrBlock, SonarrData};
|
use crate::models::servarr_data::sonarr::sonarr_data::{ActiveSonarrBlock, SonarrData};
|
||||||
use crate::models::{HorizontallyScrollableText, TabRoute};
|
use crate::models::{HorizontallyScrollableText, TabRoute};
|
||||||
use crate::network::radarr_network::RadarrEvent;
|
|
||||||
use crate::network::NetworkEvent;
|
use crate::network::NetworkEvent;
|
||||||
|
use crate::network::radarr_network::RadarrEvent;
|
||||||
use tokio_util::sync::CancellationToken;
|
use tokio_util::sync::CancellationToken;
|
||||||
|
|
||||||
#[rstest]
|
#[test]
|
||||||
fn test_app_new(
|
fn test_app_new() {
|
||||||
#[values(ActiveRadarrBlock::default(), ActiveSonarrBlock::default())] servarr: impl Into<Route>
|
let radarr_config_1 = ServarrConfig {
|
||||||
+ Copy,
|
name: Some("Radarr Test".to_owned()),
|
||||||
) {
|
..ServarrConfig::default()
|
||||||
let (title, config) = match servarr.into() {
|
|
||||||
Route::Radarr(_, _) => (
|
|
||||||
"Radarr",
|
|
||||||
AppConfig {
|
|
||||||
radarr: Some(ServarrConfig::default()),
|
|
||||||
..AppConfig::default()
|
|
||||||
},
|
|
||||||
),
|
|
||||||
Route::Sonarr(_, _) => (
|
|
||||||
"Sonarr",
|
|
||||||
AppConfig {
|
|
||||||
sonarr: Some(ServarrConfig::default()),
|
|
||||||
..AppConfig::default()
|
|
||||||
},
|
|
||||||
),
|
|
||||||
_ => unreachable!(),
|
|
||||||
};
|
};
|
||||||
let tab_route = |title: &'static str| TabRoute {
|
let radarr_config_2 = ServarrConfig {
|
||||||
title,
|
weight: Some(3),
|
||||||
route: servarr.into(),
|
..ServarrConfig::default()
|
||||||
help: format!(
|
|
||||||
"<↑↓> scroll | ←→ change tab | {} ",
|
|
||||||
build_context_clue_string(&SERVARR_CONTEXT_CLUES)
|
|
||||||
),
|
|
||||||
contextual_help: None,
|
|
||||||
};
|
};
|
||||||
|
let sonarr_config_1 = ServarrConfig {
|
||||||
|
name: Some("Sonarr Test".to_owned()),
|
||||||
|
weight: Some(1),
|
||||||
|
..ServarrConfig::default()
|
||||||
|
};
|
||||||
|
let sonarr_config_2 = ServarrConfig::default();
|
||||||
|
let config = AppConfig {
|
||||||
|
theme: None,
|
||||||
|
radarr: Some(vec![radarr_config_1.clone(), radarr_config_2.clone()]),
|
||||||
|
sonarr: Some(vec![sonarr_config_1.clone(), sonarr_config_2.clone()]),
|
||||||
|
};
|
||||||
|
let expected_tab_routes = vec![
|
||||||
|
TabRoute {
|
||||||
|
title: "Sonarr Test".to_owned(),
|
||||||
|
route: ActiveSonarrBlock::default().into(),
|
||||||
|
contextual_help: None,
|
||||||
|
config: Some(sonarr_config_1),
|
||||||
|
},
|
||||||
|
TabRoute {
|
||||||
|
title: "Radarr 1".to_owned(),
|
||||||
|
route: ActiveRadarrBlock::default().into(),
|
||||||
|
contextual_help: None,
|
||||||
|
config: Some(radarr_config_2),
|
||||||
|
},
|
||||||
|
TabRoute {
|
||||||
|
title: "Radarr Test".to_owned(),
|
||||||
|
route: ActiveRadarrBlock::default().into(),
|
||||||
|
contextual_help: None,
|
||||||
|
config: Some(radarr_config_1),
|
||||||
|
},
|
||||||
|
TabRoute {
|
||||||
|
title: "Sonarr 1".to_owned(),
|
||||||
|
route: ActiveSonarrBlock::default().into(),
|
||||||
|
contextual_help: None,
|
||||||
|
config: Some(sonarr_config_2),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
let app = App::new(
|
let app = App::new(
|
||||||
mpsc::channel::<NetworkEvent>(500).0,
|
mpsc::channel::<NetworkEvent>(500).0,
|
||||||
@@ -53,21 +69,21 @@ mod tests {
|
|||||||
CancellationToken::new(),
|
CancellationToken::new(),
|
||||||
);
|
);
|
||||||
|
|
||||||
assert!(app.navigation_stack.is_empty());
|
assert_is_empty!(app.navigation_stack);
|
||||||
assert_eq!(app.get_current_route(), servarr.into());
|
assert_eq!(app.get_current_route(), ActiveSonarrBlock::default().into());
|
||||||
assert!(app.network_tx.is_some());
|
assert_some!(app.network_tx);
|
||||||
assert!(!app.cancellation_token.is_cancelled());
|
assert!(!app.cancellation_token.is_cancelled());
|
||||||
assert!(app.is_first_render);
|
assert!(app.is_first_render);
|
||||||
assert_eq!(app.error, HorizontallyScrollableText::default());
|
assert_eq!(app.error, HorizontallyScrollableText::default());
|
||||||
assert_eq!(app.server_tabs.index, 0);
|
assert_eq!(app.server_tabs.index, 0);
|
||||||
assert_eq!(app.server_tabs.tabs, vec![tab_route(title)]);
|
assert_eq!(app.server_tabs.tabs, expected_tab_routes);
|
||||||
assert_eq!(app.tick_until_poll, 400);
|
assert_eq!(app.tick_until_poll, 400);
|
||||||
assert_eq!(app.ticks_until_scroll, 4);
|
assert_eq!(app.ticks_until_scroll, 4);
|
||||||
assert_eq!(app.tick_count, 0);
|
assert_eq!(app.tick_count, 0);
|
||||||
assert!(!app.is_loading);
|
assert!(!app.is_loading);
|
||||||
assert!(!app.is_routing);
|
assert!(!app.is_routing);
|
||||||
assert!(!app.should_refresh);
|
assert!(!app.should_refresh);
|
||||||
assert!(!app.should_ignore_quit_key);
|
assert!(!app.ignore_special_keys_for_textbox_input);
|
||||||
assert!(!app.cli_mode);
|
assert!(!app.cli_mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -75,48 +91,25 @@ mod tests {
|
|||||||
fn test_app_default() {
|
fn test_app_default() {
|
||||||
let app = App::default();
|
let app = App::default();
|
||||||
|
|
||||||
assert!(app.navigation_stack.is_empty());
|
assert_is_empty!(app.navigation_stack);
|
||||||
assert!(app.network_tx.is_none());
|
assert_none!(app.network_tx);
|
||||||
assert!(!app.cancellation_token.is_cancelled());
|
assert!(!app.cancellation_token.is_cancelled());
|
||||||
assert!(app.is_first_render);
|
assert!(app.is_first_render);
|
||||||
assert_eq!(app.error, HorizontallyScrollableText::default());
|
assert_eq!(app.error, HorizontallyScrollableText::default());
|
||||||
assert_eq!(app.server_tabs.index, 0);
|
assert_eq!(app.server_tabs.index, 0);
|
||||||
assert_eq!(
|
|
||||||
app.server_tabs.tabs,
|
|
||||||
vec![
|
|
||||||
TabRoute {
|
|
||||||
title: "Radarr",
|
|
||||||
route: ActiveRadarrBlock::Movies.into(),
|
|
||||||
help: format!(
|
|
||||||
"<↑↓> scroll | ←→ change tab | {} ",
|
|
||||||
build_context_clue_string(&SERVARR_CONTEXT_CLUES)
|
|
||||||
),
|
|
||||||
contextual_help: None,
|
|
||||||
},
|
|
||||||
TabRoute {
|
|
||||||
title: "Sonarr",
|
|
||||||
route: ActiveSonarrBlock::Series.into(),
|
|
||||||
help: format!(
|
|
||||||
"<↑↓> scroll | ←→ change tab | {} ",
|
|
||||||
build_context_clue_string(&SERVARR_CONTEXT_CLUES)
|
|
||||||
),
|
|
||||||
contextual_help: None,
|
|
||||||
},
|
|
||||||
]
|
|
||||||
);
|
|
||||||
assert_eq!(app.tick_until_poll, 400);
|
assert_eq!(app.tick_until_poll, 400);
|
||||||
assert_eq!(app.ticks_until_scroll, 4);
|
assert_eq!(app.ticks_until_scroll, 4);
|
||||||
assert_eq!(app.tick_count, 0);
|
assert_eq!(app.tick_count, 0);
|
||||||
assert!(!app.is_loading);
|
assert!(!app.is_loading);
|
||||||
assert!(!app.is_routing);
|
assert!(!app.is_routing);
|
||||||
assert!(!app.should_refresh);
|
assert!(!app.should_refresh);
|
||||||
assert!(!app.should_ignore_quit_key);
|
assert!(!app.ignore_special_keys_for_textbox_input);
|
||||||
assert!(!app.cli_mode);
|
assert!(!app.cli_mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_navigation_stack_methods() {
|
fn test_navigation_stack_methods() {
|
||||||
let mut app = App::default();
|
let mut app = App::test_default();
|
||||||
let default_route = app.server_tabs.tabs.first().unwrap().route;
|
let default_route = app.server_tabs.tabs.first().unwrap().route;
|
||||||
|
|
||||||
assert_eq!(app.get_current_route(), default_route);
|
assert_eq!(app.get_current_route(), default_route);
|
||||||
@@ -153,7 +146,7 @@ mod tests {
|
|||||||
let mut app = App {
|
let mut app = App {
|
||||||
is_loading: true,
|
is_loading: true,
|
||||||
should_refresh: false,
|
should_refresh: false,
|
||||||
..App::default()
|
..App::test_default()
|
||||||
};
|
};
|
||||||
app.cancellation_token.cancel();
|
app.cancellation_token.cancel();
|
||||||
|
|
||||||
@@ -171,7 +164,7 @@ mod tests {
|
|||||||
fn test_reset_tick_count() {
|
fn test_reset_tick_count() {
|
||||||
let mut app = App {
|
let mut app = App {
|
||||||
tick_count: 2,
|
tick_count: 2,
|
||||||
..App::default()
|
..App::test_default()
|
||||||
};
|
};
|
||||||
|
|
||||||
app.reset_tick_count();
|
app.reset_tick_count();
|
||||||
@@ -198,7 +191,7 @@ mod tests {
|
|||||||
error: "Test error".to_owned().into(),
|
error: "Test error".to_owned().into(),
|
||||||
is_first_render: false,
|
is_first_render: false,
|
||||||
data,
|
data,
|
||||||
..App::default()
|
..App::test_default()
|
||||||
};
|
};
|
||||||
|
|
||||||
app.reset();
|
app.reset();
|
||||||
@@ -212,7 +205,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_handle_error() {
|
fn test_handle_error() {
|
||||||
let mut app = App::default();
|
let mut app = App::test_default();
|
||||||
let test_string = "Testing";
|
let test_string = "Testing";
|
||||||
|
|
||||||
app.handle_error(anyhow!(test_string));
|
app.handle_error(anyhow!(test_string));
|
||||||
@@ -231,7 +224,7 @@ mod tests {
|
|||||||
let mut app = App {
|
let mut app = App {
|
||||||
tick_until_poll: 2,
|
tick_until_poll: 2,
|
||||||
network_tx: Some(sync_network_tx),
|
network_tx: Some(sync_network_tx),
|
||||||
..App::default()
|
..App::test_default()
|
||||||
};
|
};
|
||||||
|
|
||||||
assert_eq!(app.tick_count, 0);
|
assert_eq!(app.tick_count, 0);
|
||||||
@@ -255,7 +248,7 @@ mod tests {
|
|||||||
tick_until_poll: 2,
|
tick_until_poll: 2,
|
||||||
network_tx: Some(sync_network_tx),
|
network_tx: Some(sync_network_tx),
|
||||||
is_first_render: true,
|
is_first_render: true,
|
||||||
..App::default()
|
..App::test_default()
|
||||||
};
|
};
|
||||||
|
|
||||||
assert_eq!(app.tick_count, 0);
|
assert_eq!(app.tick_count, 0);
|
||||||
@@ -276,7 +269,7 @@ mod tests {
|
|||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
sync_network_rx.recv().await.unwrap(),
|
sync_network_rx.recv().await.unwrap(),
|
||||||
RadarrEvent::GetDownloads.into()
|
RadarrEvent::GetDownloads(500).into()
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
sync_network_rx.recv().await.unwrap(),
|
sync_network_rx.recv().await.unwrap(),
|
||||||
@@ -309,7 +302,7 @@ mod tests {
|
|||||||
tick_until_poll: 2,
|
tick_until_poll: 2,
|
||||||
tick_count: 2,
|
tick_count: 2,
|
||||||
is_routing: true,
|
is_routing: true,
|
||||||
..App::default()
|
..App::test_default()
|
||||||
};
|
};
|
||||||
|
|
||||||
app.on_tick().await;
|
app.on_tick().await;
|
||||||
@@ -322,7 +315,7 @@ mod tests {
|
|||||||
tick_until_poll: 2,
|
tick_until_poll: 2,
|
||||||
tick_count: 2,
|
tick_count: 2,
|
||||||
should_refresh: true,
|
should_refresh: true,
|
||||||
..App::default()
|
..App::test_default()
|
||||||
};
|
};
|
||||||
|
|
||||||
app.on_tick().await;
|
app.on_tick().await;
|
||||||
@@ -333,18 +326,292 @@ mod tests {
|
|||||||
fn test_app_config_default() {
|
fn test_app_config_default() {
|
||||||
let app_config = AppConfig::default();
|
let app_config = AppConfig::default();
|
||||||
|
|
||||||
assert!(app_config.radarr.is_none());
|
assert_none!(app_config.radarr);
|
||||||
assert!(app_config.sonarr.is_none());
|
assert_none!(app_config.sonarr);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_servarr_config_default() {
|
fn test_servarr_config_default() {
|
||||||
let servarr_config = ServarrConfig::default();
|
let servarr_config = ServarrConfig::default();
|
||||||
|
|
||||||
assert_eq!(servarr_config.host, Some("localhost".to_string()));
|
assert_none!(servarr_config.name);
|
||||||
assert_eq!(servarr_config.port, None);
|
assert_some_eq_x!(&servarr_config.host, "localhost");
|
||||||
assert_eq!(servarr_config.uri, None);
|
assert_none!(servarr_config.port);
|
||||||
assert!(servarr_config.api_token.is_empty());
|
assert_none!(servarr_config.uri);
|
||||||
assert_eq!(servarr_config.ssl_cert_path, None);
|
assert_none!(servarr_config.weight);
|
||||||
|
assert_some_eq_x!(&servarr_config.api_token, "");
|
||||||
|
assert_none!(servarr_config.api_token_file);
|
||||||
|
assert_none!(servarr_config.ssl_cert_path);
|
||||||
|
assert_none!(servarr_config.custom_headers);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn serialize_header_map_basic() {
|
||||||
|
let mut header_map = HeaderMap::new();
|
||||||
|
header_map.insert(
|
||||||
|
HeaderName::from_static("x-api-key"),
|
||||||
|
HeaderValue::from_static("abc123"),
|
||||||
|
);
|
||||||
|
header_map.insert(
|
||||||
|
HeaderName::from_static("header-1"),
|
||||||
|
HeaderValue::from_static("test"),
|
||||||
|
);
|
||||||
|
|
||||||
|
let config = ServarrConfig {
|
||||||
|
custom_headers: Some(header_map),
|
||||||
|
..ServarrConfig::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
let v: Value = serde_json::to_value(&config).expect("serialize ok");
|
||||||
|
let custom = v.get("custom_headers").unwrap();
|
||||||
|
assert!(custom.is_object());
|
||||||
|
let obj = custom.as_object().unwrap();
|
||||||
|
|
||||||
|
assert_some_eq_x!(obj.get("x-api-key"), "abc123");
|
||||||
|
assert_some_eq_x!(obj.get("header-1"), "test");
|
||||||
|
|
||||||
|
assert_none!(obj.get("X-Api-Key"));
|
||||||
|
assert_none!(obj.get("HEADER-1"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn serialize_header_map_none_is_null() {
|
||||||
|
let config = ServarrConfig::default();
|
||||||
|
let v: Value = serde_json::to_value(&config).expect("serialize ok");
|
||||||
|
assert!(v.get("custom_headers").unwrap().is_null());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[serial]
|
||||||
|
fn test_deserialize_optional_env_var_is_present() {
|
||||||
|
unsafe { std::env::set_var("TEST_VAR_DESERIALIZE_OPTION", "localhost") };
|
||||||
|
let yaml_data = r#"
|
||||||
|
host: ${TEST_VAR_DESERIALIZE_OPTION}
|
||||||
|
api_token: "test123"
|
||||||
|
"#;
|
||||||
|
|
||||||
|
let config: ServarrConfig = serde_yaml::from_str(yaml_data).unwrap();
|
||||||
|
|
||||||
|
assert_some_eq_x!(&config.host, "localhost");
|
||||||
|
unsafe { std::env::remove_var("TEST_VAR_DESERIALIZE_OPTION") };
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[serial]
|
||||||
|
fn test_deserialize_optional_env_var_does_not_overwrite_non_env_value() {
|
||||||
|
unsafe { std::env::set_var("TEST_VAR_DESERIALIZE_OPTION_NO_OVERWRITE", "localhost") };
|
||||||
|
let yaml_data = r#"
|
||||||
|
host: www.example.com
|
||||||
|
api_token: "test123"
|
||||||
|
"#;
|
||||||
|
|
||||||
|
let config: ServarrConfig = serde_yaml::from_str(yaml_data).unwrap();
|
||||||
|
|
||||||
|
assert_some_eq_x!(&config.host, "www.example.com");
|
||||||
|
unsafe { std::env::remove_var("TEST_VAR_DESERIALIZE_OPTION_NO_OVERWRITE") };
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_deserialize_optional_env_var_empty() {
|
||||||
|
let yaml_data = r#"
|
||||||
|
api_token: "test123"
|
||||||
|
"#;
|
||||||
|
|
||||||
|
let config: ServarrConfig = serde_yaml::from_str(yaml_data).unwrap();
|
||||||
|
|
||||||
|
assert_none!(config.port);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[serial]
|
||||||
|
fn test_deserialize_optional_env_var_header_map_is_present() {
|
||||||
|
unsafe { std::env::set_var("TEST_VAR_DESERIALIZE_HEADER_OPTION", "localhost") };
|
||||||
|
let expected_custom_headers = {
|
||||||
|
let mut headers = HeaderMap::new();
|
||||||
|
headers.insert("X-Api-Host", "localhost".parse().unwrap());
|
||||||
|
headers.insert("api-token", "test123".parse().unwrap());
|
||||||
|
headers
|
||||||
|
};
|
||||||
|
let yaml_data = r#"
|
||||||
|
custom_headers:
|
||||||
|
X-Api-Host: ${TEST_VAR_DESERIALIZE_HEADER_OPTION}
|
||||||
|
api-token: "test123"
|
||||||
|
"#;
|
||||||
|
|
||||||
|
let config: ServarrConfig = serde_yaml::from_str(yaml_data).unwrap();
|
||||||
|
|
||||||
|
assert_some_eq_x!(&config.custom_headers, &expected_custom_headers);
|
||||||
|
unsafe { std::env::remove_var("TEST_VAR_DESERIALIZE_HEADER_OPTION") };
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[serial]
|
||||||
|
fn test_deserialize_optional_env_var_header_map_does_not_overwrite_non_env_value() {
|
||||||
|
unsafe {
|
||||||
|
std::env::set_var(
|
||||||
|
"TEST_VAR_DESERIALIZE_HEADER_OPTION_NO_OVERWRITE",
|
||||||
|
"localhost",
|
||||||
|
)
|
||||||
|
};
|
||||||
|
let expected_custom_headers = {
|
||||||
|
let mut headers = HeaderMap::new();
|
||||||
|
headers.insert("X-Api-Host", "www.example.com".parse().unwrap());
|
||||||
|
headers.insert("api-token", "test123".parse().unwrap());
|
||||||
|
headers
|
||||||
|
};
|
||||||
|
let yaml_data = r#"
|
||||||
|
custom_headers:
|
||||||
|
X-Api-Host: www.example.com
|
||||||
|
api-token: "test123"
|
||||||
|
"#;
|
||||||
|
|
||||||
|
let config: ServarrConfig = serde_yaml::from_str(yaml_data).unwrap();
|
||||||
|
|
||||||
|
assert_some_eq_x!(&config.custom_headers, &expected_custom_headers);
|
||||||
|
unsafe { std::env::remove_var("TEST_VAR_DESERIALIZE_HEADER_OPTION_NO_OVERWRITE") };
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_deserialize_optional_env_var_header_map_empty() {
|
||||||
|
let yaml_data = r#"
|
||||||
|
api_token: "test123"
|
||||||
|
"#;
|
||||||
|
|
||||||
|
let config: ServarrConfig = serde_yaml::from_str(yaml_data).unwrap();
|
||||||
|
|
||||||
|
assert_none!(config.custom_headers);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[serial]
|
||||||
|
fn test_deserialize_optional_u16_env_var_is_present() {
|
||||||
|
unsafe { std::env::set_var("TEST_VAR_DESERIALIZE_OPTION_U16", "1") };
|
||||||
|
let yaml_data = r#"
|
||||||
|
port: ${TEST_VAR_DESERIALIZE_OPTION_U16}
|
||||||
|
api_token: "test123"
|
||||||
|
"#;
|
||||||
|
|
||||||
|
let config: ServarrConfig = serde_yaml::from_str(yaml_data).unwrap();
|
||||||
|
|
||||||
|
assert_some_eq_x!(config.port, 1);
|
||||||
|
unsafe { std::env::remove_var("TEST_VAR_DESERIALIZE_OPTION_U16") };
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[serial]
|
||||||
|
fn test_deserialize_optional_u16_env_var_does_not_overwrite_non_env_value() {
|
||||||
|
unsafe { std::env::set_var("TEST_VAR_DESERIALIZE_OPTION_U16_UNUSED", "1") };
|
||||||
|
let yaml_data = r#"
|
||||||
|
port: 1234
|
||||||
|
api_token: "test123"
|
||||||
|
"#;
|
||||||
|
|
||||||
|
let config: ServarrConfig = serde_yaml::from_str(yaml_data).unwrap();
|
||||||
|
|
||||||
|
assert_some_eq_x!(config.port, 1234);
|
||||||
|
unsafe { std::env::remove_var("TEST_VAR_DESERIALIZE_OPTION_U16_UNUSED") };
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_deserialize_optional_u16_env_var_invalid_number() {
|
||||||
|
let yaml_data = r#"
|
||||||
|
port: "hi"
|
||||||
|
api_token: "test123"
|
||||||
|
"#;
|
||||||
|
let result: Result<ServarrConfig, _> = serde_yaml::from_str(yaml_data);
|
||||||
|
|
||||||
|
assert_err!(&result);
|
||||||
|
let err = result.unwrap_err().to_string();
|
||||||
|
assert_contains!(err, "invalid digit found in string");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_deserialize_optional_u16_env_var_empty() {
|
||||||
|
let yaml_data = r#"
|
||||||
|
api_token: "test123"
|
||||||
|
"#;
|
||||||
|
|
||||||
|
let config: ServarrConfig = serde_yaml::from_str(yaml_data).unwrap();
|
||||||
|
|
||||||
|
assert_none!(config.port);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[serial]
|
||||||
|
fn test_interpolate_env_vars() {
|
||||||
|
unsafe { std::env::set_var("TEST_VAR_INTERPOLATION", "testing") };
|
||||||
|
|
||||||
|
let var = interpolate_env_vars("${TEST_VAR_INTERPOLATION}");
|
||||||
|
|
||||||
|
assert_str_eq!(var, "testing");
|
||||||
|
unsafe { std::env::remove_var("TEST_VAR_INTERPOLATION") };
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_interpolate_env_vars_defaults_to_original_string_if_not_in_yaml_interpolation_format() {
|
||||||
|
let var = interpolate_env_vars("TEST_VAR_INTERPOLATION_NON_YAML");
|
||||||
|
|
||||||
|
assert_str_eq!(var, "TEST_VAR_INTERPOLATION_NON_YAML");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[serial]
|
||||||
|
fn test_interpolate_env_vars_scrubs_all_unnecessary_characters() {
|
||||||
|
unsafe {
|
||||||
|
std::env::set_var(
|
||||||
|
"TEST_VAR_INTERPOLATION_UNNECESSARY_CHARACTERS",
|
||||||
|
r#"""
|
||||||
|
`"'https://dontdo:this@testing.com/query?test=%20query#results'"` {([\|$!])}
|
||||||
|
"""#,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
let var = interpolate_env_vars("${TEST_VAR_INTERPOLATION_UNNECESSARY_CHARACTERS}");
|
||||||
|
|
||||||
|
assert_str_eq!(
|
||||||
|
var,
|
||||||
|
"https://dontdo:this@testing.com/query?test=%20query#results"
|
||||||
|
);
|
||||||
|
unsafe { std::env::remove_var("TEST_VAR_INTERPOLATION_UNNECESSARY_CHARACTERS") };
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_interpolate_env_vars_scrubs_all_unnecessary_characters_from_non_environment_variable() {
|
||||||
|
let var = interpolate_env_vars("https://dontdo:this@testing.com/query?test=%20query#results");
|
||||||
|
|
||||||
|
assert_str_eq!(
|
||||||
|
var,
|
||||||
|
"https://dontdo:this@testing.com/query?test=%20query#results"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_servarr_config_redacted_debug() {
|
||||||
|
let name = "Servarr".to_owned();
|
||||||
|
let host = "localhost".to_owned();
|
||||||
|
let port = 1234;
|
||||||
|
let uri = "http://localhost:1234".to_owned();
|
||||||
|
let weight = 100;
|
||||||
|
let api_token = "thisisatest".to_owned();
|
||||||
|
let api_token_file = "/root/.config/api_token".to_owned();
|
||||||
|
let ssl_cert_path = "/some/path".to_owned();
|
||||||
|
let mut custom_headers = HeaderMap::new();
|
||||||
|
custom_headers.insert("X-Custom-Header", "value".parse().unwrap());
|
||||||
|
let expected_str = format!(
|
||||||
|
"ServarrConfig {{ name: Some(\"{name}\"), host: Some(\"{host}\"), port: Some({port}), uri: Some(\"{uri}\"), weight: Some({weight}), api_token: Some(\"***********\"), api_token_file: Some(\"{api_token_file}\"), ssl_cert_path: Some(\"{ssl_cert_path}\"), custom_headers: Some({{\"x-custom-header\": \"value\"}}) }}"
|
||||||
|
);
|
||||||
|
let servarr_config = ServarrConfig {
|
||||||
|
name: Some(name),
|
||||||
|
host: Some(host),
|
||||||
|
port: Some(port),
|
||||||
|
uri: Some(uri),
|
||||||
|
weight: Some(weight),
|
||||||
|
api_token: Some(api_token),
|
||||||
|
api_token_file: Some(api_token_file),
|
||||||
|
ssl_cert_path: Some(ssl_cert_path),
|
||||||
|
custom_headers: Some(custom_headers),
|
||||||
|
};
|
||||||
|
|
||||||
|
assert_str_eq!(format!("{servarr_config:?}"), expected_str);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,20 +1,41 @@
|
|||||||
use crate::app::key_binding::{KeyBinding, DEFAULT_KEYBINDINGS};
|
use crate::app::App;
|
||||||
|
use crate::app::key_binding::{DEFAULT_KEYBINDINGS, KeyBinding};
|
||||||
|
use crate::app::radarr::radarr_context_clues::RadarrContextClueProvider;
|
||||||
|
use crate::app::sonarr::sonarr_context_clues::SonarrContextClueProvider;
|
||||||
|
use crate::models::Route;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
#[path = "context_clues_tests.rs"]
|
#[path = "context_clues_tests.rs"]
|
||||||
mod context_clues_tests;
|
mod context_clues_tests;
|
||||||
|
|
||||||
pub(in crate::app) type ContextClue = (KeyBinding, &'static str);
|
pub type ContextClue = (KeyBinding, &'static str);
|
||||||
|
|
||||||
pub fn build_context_clue_string(context_clues: &[(KeyBinding, &str)]) -> String {
|
pub trait ContextClueProvider {
|
||||||
context_clues
|
fn get_context_clues(_app: &mut App<'_>) -> Option<&'static [ContextClue]>;
|
||||||
.iter()
|
|
||||||
.map(|(key_binding, desc)| format!("{} {desc}", key_binding.key))
|
|
||||||
.collect::<Vec<String>>()
|
|
||||||
.join(" | ")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub static SERVARR_CONTEXT_CLUES: [ContextClue; 3] = [
|
pub struct ServarrContextClueProvider;
|
||||||
|
|
||||||
|
impl ContextClueProvider for ServarrContextClueProvider {
|
||||||
|
fn get_context_clues(app: &mut App<'_>) -> Option<&'static [ContextClue]> {
|
||||||
|
match app.get_current_route() {
|
||||||
|
Route::Radarr(_, _) => RadarrContextClueProvider::get_context_clues(app),
|
||||||
|
Route::Sonarr(_, _) => SonarrContextClueProvider::get_context_clues(app),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub static SERVARR_CONTEXT_CLUES: [ContextClue; 10] = [
|
||||||
|
(DEFAULT_KEYBINDINGS.up, "scroll up"),
|
||||||
|
(DEFAULT_KEYBINDINGS.down, "scroll down"),
|
||||||
|
(DEFAULT_KEYBINDINGS.left, "previous tab"),
|
||||||
|
(DEFAULT_KEYBINDINGS.right, "next tab"),
|
||||||
|
(DEFAULT_KEYBINDINGS.pg_up, DEFAULT_KEYBINDINGS.pg_up.desc),
|
||||||
|
(
|
||||||
|
DEFAULT_KEYBINDINGS.pg_down,
|
||||||
|
DEFAULT_KEYBINDINGS.pg_down.desc,
|
||||||
|
),
|
||||||
(
|
(
|
||||||
DEFAULT_KEYBINDINGS.next_servarr,
|
DEFAULT_KEYBINDINGS.next_servarr,
|
||||||
DEFAULT_KEYBINDINGS.next_servarr.desc,
|
DEFAULT_KEYBINDINGS.next_servarr.desc,
|
||||||
@@ -24,6 +45,7 @@ pub static SERVARR_CONTEXT_CLUES: [ContextClue; 3] = [
|
|||||||
DEFAULT_KEYBINDINGS.previous_servarr.desc,
|
DEFAULT_KEYBINDINGS.previous_servarr.desc,
|
||||||
),
|
),
|
||||||
(DEFAULT_KEYBINDINGS.quit, DEFAULT_KEYBINDINGS.quit.desc),
|
(DEFAULT_KEYBINDINGS.quit, DEFAULT_KEYBINDINGS.quit.desc),
|
||||||
|
(DEFAULT_KEYBINDINGS.help, DEFAULT_KEYBINDINGS.help.desc),
|
||||||
];
|
];
|
||||||
|
|
||||||
pub static BARE_POPUP_CONTEXT_CLUES: [ContextClue; 1] =
|
pub static BARE_POPUP_CONTEXT_CLUES: [ContextClue; 1] =
|
||||||
|
|||||||
+209
-149
@@ -1,212 +1,272 @@
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use pretty_assertions::{assert_eq, assert_str_eq};
|
|
||||||
|
|
||||||
use crate::app::context_clues::{
|
use crate::app::context_clues::{
|
||||||
BARE_POPUP_CONTEXT_CLUES, BLOCKLIST_CONTEXT_CLUES, CONFIRMATION_PROMPT_CONTEXT_CLUES,
|
BARE_POPUP_CONTEXT_CLUES, BLOCKLIST_CONTEXT_CLUES, CONFIRMATION_PROMPT_CONTEXT_CLUES,
|
||||||
DOWNLOADS_CONTEXT_CLUES, INDEXERS_CONTEXT_CLUES, ROOT_FOLDERS_CONTEXT_CLUES,
|
ContextClueProvider, DOWNLOADS_CONTEXT_CLUES, INDEXERS_CONTEXT_CLUES,
|
||||||
SERVARR_CONTEXT_CLUES, SYSTEM_CONTEXT_CLUES,
|
ROOT_FOLDERS_CONTEXT_CLUES, SERVARR_CONTEXT_CLUES, SYSTEM_CONTEXT_CLUES,
|
||||||
|
ServarrContextClueProvider,
|
||||||
};
|
};
|
||||||
use crate::app::{context_clues::build_context_clue_string, key_binding::DEFAULT_KEYBINDINGS};
|
use crate::app::{App, key_binding::DEFAULT_KEYBINDINGS};
|
||||||
|
use crate::models::servarr_data::ActiveKeybindingBlock;
|
||||||
#[test]
|
use crate::models::servarr_data::radarr::radarr_data::ActiveRadarrBlock;
|
||||||
fn test_build_context_clue_string() {
|
use crate::models::servarr_data::sonarr::sonarr_data::ActiveSonarrBlock;
|
||||||
let test_context_clues_array = [
|
|
||||||
(DEFAULT_KEYBINDINGS.add, "add"),
|
|
||||||
(DEFAULT_KEYBINDINGS.delete, "delete"),
|
|
||||||
];
|
|
||||||
|
|
||||||
assert_str_eq!(
|
|
||||||
build_context_clue_string(&test_context_clues_array),
|
|
||||||
"<a> add | <del> delete"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_servarr_context_clues() {
|
fn test_servarr_context_clues() {
|
||||||
let mut servarr_context_clues_iter = SERVARR_CONTEXT_CLUES.iter();
|
let mut servarr_context_clues_iter = SERVARR_CONTEXT_CLUES.iter();
|
||||||
|
|
||||||
let (key_binding, description) = servarr_context_clues_iter.next().unwrap();
|
assert_some_eq_x!(
|
||||||
|
servarr_context_clues_iter.next(),
|
||||||
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.next_servarr);
|
&(DEFAULT_KEYBINDINGS.up, "scroll up")
|
||||||
assert_str_eq!(*description, DEFAULT_KEYBINDINGS.next_servarr.desc);
|
);
|
||||||
|
assert_some_eq_x!(
|
||||||
let (key_binding, description) = servarr_context_clues_iter.next().unwrap();
|
servarr_context_clues_iter.next(),
|
||||||
|
&(DEFAULT_KEYBINDINGS.down, "scroll down")
|
||||||
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.previous_servarr);
|
);
|
||||||
assert_str_eq!(*description, DEFAULT_KEYBINDINGS.previous_servarr.desc);
|
assert_some_eq_x!(
|
||||||
|
servarr_context_clues_iter.next(),
|
||||||
let (key_binding, description) = servarr_context_clues_iter.next().unwrap();
|
&(DEFAULT_KEYBINDINGS.left, "previous tab")
|
||||||
|
);
|
||||||
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.quit);
|
assert_some_eq_x!(
|
||||||
assert_str_eq!(*description, DEFAULT_KEYBINDINGS.quit.desc);
|
servarr_context_clues_iter.next(),
|
||||||
assert_eq!(servarr_context_clues_iter.next(), None);
|
&(DEFAULT_KEYBINDINGS.right, "next tab")
|
||||||
|
);
|
||||||
|
assert_some_eq_x!(
|
||||||
|
servarr_context_clues_iter.next(),
|
||||||
|
&(DEFAULT_KEYBINDINGS.pg_up, DEFAULT_KEYBINDINGS.pg_up.desc)
|
||||||
|
);
|
||||||
|
assert_some_eq_x!(
|
||||||
|
servarr_context_clues_iter.next(),
|
||||||
|
&(
|
||||||
|
DEFAULT_KEYBINDINGS.pg_down,
|
||||||
|
DEFAULT_KEYBINDINGS.pg_down.desc
|
||||||
|
)
|
||||||
|
);
|
||||||
|
assert_some_eq_x!(
|
||||||
|
servarr_context_clues_iter.next(),
|
||||||
|
&(
|
||||||
|
DEFAULT_KEYBINDINGS.next_servarr,
|
||||||
|
DEFAULT_KEYBINDINGS.next_servarr.desc
|
||||||
|
)
|
||||||
|
);
|
||||||
|
assert_some_eq_x!(
|
||||||
|
servarr_context_clues_iter.next(),
|
||||||
|
&(
|
||||||
|
DEFAULT_KEYBINDINGS.previous_servarr,
|
||||||
|
DEFAULT_KEYBINDINGS.previous_servarr.desc
|
||||||
|
)
|
||||||
|
);
|
||||||
|
assert_some_eq_x!(
|
||||||
|
servarr_context_clues_iter.next(),
|
||||||
|
&(DEFAULT_KEYBINDINGS.quit, DEFAULT_KEYBINDINGS.quit.desc)
|
||||||
|
);
|
||||||
|
assert_some_eq_x!(
|
||||||
|
servarr_context_clues_iter.next(),
|
||||||
|
&(DEFAULT_KEYBINDINGS.help, DEFAULT_KEYBINDINGS.help.desc)
|
||||||
|
);
|
||||||
|
assert_none!(servarr_context_clues_iter.next());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_bare_popup_context_clues() {
|
fn test_bare_popup_context_clues() {
|
||||||
let mut bare_popup_context_clues_iter = BARE_POPUP_CONTEXT_CLUES.iter();
|
let mut bare_popup_context_clues_iter = BARE_POPUP_CONTEXT_CLUES.iter();
|
||||||
|
|
||||||
let (key_binding, description) = bare_popup_context_clues_iter.next().unwrap();
|
assert_some_eq_x!(
|
||||||
|
bare_popup_context_clues_iter.next(),
|
||||||
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.esc);
|
&(DEFAULT_KEYBINDINGS.esc, DEFAULT_KEYBINDINGS.esc.desc)
|
||||||
assert_str_eq!(*description, DEFAULT_KEYBINDINGS.esc.desc);
|
);
|
||||||
assert_eq!(bare_popup_context_clues_iter.next(), None);
|
assert_none!(bare_popup_context_clues_iter.next());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_downloads_context_clues() {
|
fn test_downloads_context_clues() {
|
||||||
let mut downloads_context_clues_iter = DOWNLOADS_CONTEXT_CLUES.iter();
|
let mut downloads_context_clues_iter = DOWNLOADS_CONTEXT_CLUES.iter();
|
||||||
|
|
||||||
let (key_binding, description) = downloads_context_clues_iter.next().unwrap();
|
assert_some_eq_x!(
|
||||||
|
downloads_context_clues_iter.next(),
|
||||||
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.refresh);
|
&(
|
||||||
assert_str_eq!(*description, DEFAULT_KEYBINDINGS.refresh.desc);
|
DEFAULT_KEYBINDINGS.refresh,
|
||||||
|
DEFAULT_KEYBINDINGS.refresh.desc
|
||||||
let (key_binding, description) = downloads_context_clues_iter.next().unwrap();
|
)
|
||||||
|
);
|
||||||
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.delete);
|
assert_some_eq_x!(
|
||||||
assert_str_eq!(*description, DEFAULT_KEYBINDINGS.delete.desc);
|
downloads_context_clues_iter.next(),
|
||||||
|
&(DEFAULT_KEYBINDINGS.delete, DEFAULT_KEYBINDINGS.delete.desc)
|
||||||
let (key_binding, description) = downloads_context_clues_iter.next().unwrap();
|
);
|
||||||
|
assert_some_eq_x!(
|
||||||
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.update);
|
downloads_context_clues_iter.next(),
|
||||||
assert_str_eq!(*description, "update downloads");
|
&(DEFAULT_KEYBINDINGS.update, "update downloads")
|
||||||
assert_eq!(downloads_context_clues_iter.next(), None);
|
);
|
||||||
|
assert_none!(downloads_context_clues_iter.next());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_blocklist_context_clues() {
|
fn test_blocklist_context_clues() {
|
||||||
let mut blocklist_context_clues_iter = BLOCKLIST_CONTEXT_CLUES.iter();
|
let mut blocklist_context_clues_iter = BLOCKLIST_CONTEXT_CLUES.iter();
|
||||||
|
|
||||||
let (key_binding, description) = blocklist_context_clues_iter.next().unwrap();
|
assert_some_eq_x!(
|
||||||
|
blocklist_context_clues_iter.next(),
|
||||||
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.refresh);
|
&(
|
||||||
assert_str_eq!(*description, DEFAULT_KEYBINDINGS.refresh.desc);
|
DEFAULT_KEYBINDINGS.refresh,
|
||||||
|
DEFAULT_KEYBINDINGS.refresh.desc
|
||||||
let (key_binding, description) = blocklist_context_clues_iter.next().unwrap();
|
)
|
||||||
|
);
|
||||||
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.sort);
|
assert_some_eq_x!(
|
||||||
assert_str_eq!(*description, DEFAULT_KEYBINDINGS.sort.desc);
|
blocklist_context_clues_iter.next(),
|
||||||
|
&(DEFAULT_KEYBINDINGS.sort, DEFAULT_KEYBINDINGS.sort.desc)
|
||||||
let (key_binding, description) = blocklist_context_clues_iter.next().unwrap();
|
);
|
||||||
|
assert_some_eq_x!(
|
||||||
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.submit);
|
blocklist_context_clues_iter.next(),
|
||||||
assert_str_eq!(*description, "details");
|
&(DEFAULT_KEYBINDINGS.submit, "details")
|
||||||
|
);
|
||||||
let (key_binding, description) = blocklist_context_clues_iter.next().unwrap();
|
assert_some_eq_x!(
|
||||||
|
blocklist_context_clues_iter.next(),
|
||||||
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.delete);
|
&(DEFAULT_KEYBINDINGS.delete, DEFAULT_KEYBINDINGS.delete.desc)
|
||||||
assert_str_eq!(*description, DEFAULT_KEYBINDINGS.delete.desc);
|
);
|
||||||
|
assert_some_eq_x!(
|
||||||
let (key_binding, description) = blocklist_context_clues_iter.next().unwrap();
|
blocklist_context_clues_iter.next(),
|
||||||
|
&(DEFAULT_KEYBINDINGS.clear, "clear blocklist")
|
||||||
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.clear);
|
);
|
||||||
assert_str_eq!(*description, "clear blocklist");
|
assert_none!(blocklist_context_clues_iter.next());
|
||||||
assert_eq!(blocklist_context_clues_iter.next(), None);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_confirmation_prompt_context_clues() {
|
fn test_confirmation_prompt_context_clues() {
|
||||||
let mut confirmation_prompt_context_clues_iter = CONFIRMATION_PROMPT_CONTEXT_CLUES.iter();
|
let mut confirmation_prompt_context_clues_iter = CONFIRMATION_PROMPT_CONTEXT_CLUES.iter();
|
||||||
|
|
||||||
let (key_binding, description) = confirmation_prompt_context_clues_iter.next().unwrap();
|
assert_some_eq_x!(
|
||||||
|
confirmation_prompt_context_clues_iter.next(),
|
||||||
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.confirm);
|
&(DEFAULT_KEYBINDINGS.confirm, "submit")
|
||||||
assert_str_eq!(*description, "submit");
|
);
|
||||||
|
assert_some_eq_x!(
|
||||||
let (key_binding, description) = confirmation_prompt_context_clues_iter.next().unwrap();
|
confirmation_prompt_context_clues_iter.next(),
|
||||||
|
&(DEFAULT_KEYBINDINGS.esc, "cancel")
|
||||||
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.esc);
|
);
|
||||||
assert_str_eq!(*description, "cancel");
|
assert_none!(confirmation_prompt_context_clues_iter.next());
|
||||||
assert_eq!(confirmation_prompt_context_clues_iter.next(), None);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_root_folders_context_clues() {
|
fn test_root_folders_context_clues() {
|
||||||
let mut root_folders_context_clues_iter = ROOT_FOLDERS_CONTEXT_CLUES.iter();
|
let mut root_folders_context_clues_iter = ROOT_FOLDERS_CONTEXT_CLUES.iter();
|
||||||
|
|
||||||
let (key_binding, description) = root_folders_context_clues_iter.next().unwrap();
|
assert_some_eq_x!(
|
||||||
|
root_folders_context_clues_iter.next(),
|
||||||
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.add);
|
&(DEFAULT_KEYBINDINGS.add, DEFAULT_KEYBINDINGS.add.desc)
|
||||||
assert_str_eq!(*description, DEFAULT_KEYBINDINGS.add.desc);
|
);
|
||||||
|
assert_some_eq_x!(
|
||||||
let (key_binding, description) = root_folders_context_clues_iter.next().unwrap();
|
root_folders_context_clues_iter.next(),
|
||||||
|
&(DEFAULT_KEYBINDINGS.delete, DEFAULT_KEYBINDINGS.delete.desc)
|
||||||
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.delete);
|
);
|
||||||
assert_str_eq!(*description, DEFAULT_KEYBINDINGS.delete.desc);
|
assert_some_eq_x!(
|
||||||
|
root_folders_context_clues_iter.next(),
|
||||||
let (key_binding, description) = root_folders_context_clues_iter.next().unwrap();
|
&(
|
||||||
|
DEFAULT_KEYBINDINGS.refresh,
|
||||||
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.refresh);
|
DEFAULT_KEYBINDINGS.refresh.desc
|
||||||
assert_str_eq!(*description, DEFAULT_KEYBINDINGS.refresh.desc);
|
)
|
||||||
assert_eq!(root_folders_context_clues_iter.next(), None);
|
);
|
||||||
|
assert_none!(root_folders_context_clues_iter.next());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_indexers_context_clues() {
|
fn test_indexers_context_clues() {
|
||||||
let mut indexers_context_clues_iter = INDEXERS_CONTEXT_CLUES.iter();
|
let mut indexers_context_clues_iter = INDEXERS_CONTEXT_CLUES.iter();
|
||||||
|
|
||||||
let (key_binding, description) = indexers_context_clues_iter.next().unwrap();
|
assert_some_eq_x!(
|
||||||
|
indexers_context_clues_iter.next(),
|
||||||
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.submit);
|
&(DEFAULT_KEYBINDINGS.submit, "edit indexer")
|
||||||
assert_str_eq!(*description, "edit indexer");
|
);
|
||||||
|
assert_some_eq_x!(
|
||||||
let (key_binding, description) = indexers_context_clues_iter.next().unwrap();
|
indexers_context_clues_iter.next(),
|
||||||
|
&(
|
||||||
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.settings);
|
DEFAULT_KEYBINDINGS.settings,
|
||||||
assert_str_eq!(*description, DEFAULT_KEYBINDINGS.settings.desc);
|
DEFAULT_KEYBINDINGS.settings.desc
|
||||||
|
)
|
||||||
let (key_binding, description) = indexers_context_clues_iter.next().unwrap();
|
);
|
||||||
|
assert_some_eq_x!(
|
||||||
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.delete);
|
indexers_context_clues_iter.next(),
|
||||||
assert_str_eq!(*description, DEFAULT_KEYBINDINGS.delete.desc);
|
&(DEFAULT_KEYBINDINGS.delete, DEFAULT_KEYBINDINGS.delete.desc)
|
||||||
|
);
|
||||||
let (key_binding, description) = indexers_context_clues_iter.next().unwrap();
|
assert_some_eq_x!(
|
||||||
|
indexers_context_clues_iter.next(),
|
||||||
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.test);
|
&(DEFAULT_KEYBINDINGS.test, "test indexer")
|
||||||
assert_str_eq!(*description, "test indexer");
|
);
|
||||||
|
assert_some_eq_x!(
|
||||||
let (key_binding, description) = indexers_context_clues_iter.next().unwrap();
|
indexers_context_clues_iter.next(),
|
||||||
|
&(DEFAULT_KEYBINDINGS.test_all, "test all indexers")
|
||||||
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.test_all);
|
);
|
||||||
assert_str_eq!(*description, "test all indexers");
|
assert_some_eq_x!(
|
||||||
|
indexers_context_clues_iter.next(),
|
||||||
let (key_binding, description) = indexers_context_clues_iter.next().unwrap();
|
&(
|
||||||
|
DEFAULT_KEYBINDINGS.refresh,
|
||||||
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.refresh);
|
DEFAULT_KEYBINDINGS.refresh.desc
|
||||||
assert_str_eq!(*description, DEFAULT_KEYBINDINGS.refresh.desc);
|
)
|
||||||
assert_eq!(indexers_context_clues_iter.next(), None);
|
);
|
||||||
|
assert_none!(indexers_context_clues_iter.next());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_system_context_clues() {
|
fn test_system_context_clues() {
|
||||||
let mut system_context_clues_iter = SYSTEM_CONTEXT_CLUES.iter();
|
let mut system_context_clues_iter = SYSTEM_CONTEXT_CLUES.iter();
|
||||||
|
|
||||||
let (key_binding, description) = system_context_clues_iter.next().unwrap();
|
assert_some_eq_x!(
|
||||||
|
system_context_clues_iter.next(),
|
||||||
|
&(DEFAULT_KEYBINDINGS.tasks, "open tasks")
|
||||||
|
);
|
||||||
|
assert_some_eq_x!(
|
||||||
|
system_context_clues_iter.next(),
|
||||||
|
&(DEFAULT_KEYBINDINGS.events, "open events")
|
||||||
|
);
|
||||||
|
assert_some_eq_x!(
|
||||||
|
system_context_clues_iter.next(),
|
||||||
|
&(DEFAULT_KEYBINDINGS.logs, "open logs")
|
||||||
|
);
|
||||||
|
assert_some_eq_x!(
|
||||||
|
system_context_clues_iter.next(),
|
||||||
|
&(DEFAULT_KEYBINDINGS.update, "open updates")
|
||||||
|
);
|
||||||
|
assert_some_eq_x!(
|
||||||
|
system_context_clues_iter.next(),
|
||||||
|
&(
|
||||||
|
DEFAULT_KEYBINDINGS.refresh,
|
||||||
|
DEFAULT_KEYBINDINGS.refresh.desc
|
||||||
|
)
|
||||||
|
);
|
||||||
|
assert_none!(system_context_clues_iter.next());
|
||||||
|
}
|
||||||
|
|
||||||
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.tasks);
|
#[test]
|
||||||
assert_str_eq!(*description, "open tasks");
|
fn test_servarr_context_clue_provider_delegates_to_radarr_provider() {
|
||||||
|
let mut app = App::test_default();
|
||||||
|
app.push_navigation_stack(ActiveRadarrBlock::SystemTasks.into());
|
||||||
|
|
||||||
let (key_binding, description) = system_context_clues_iter.next().unwrap();
|
let context_clues = ServarrContextClueProvider::get_context_clues(&mut app);
|
||||||
|
|
||||||
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.events);
|
assert_some_eq_x!(
|
||||||
assert_str_eq!(*description, "open events");
|
context_clues,
|
||||||
|
&crate::app::radarr::radarr_context_clues::SYSTEM_TASKS_CONTEXT_CLUES,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
let (key_binding, description) = system_context_clues_iter.next().unwrap();
|
#[test]
|
||||||
|
fn test_servarr_context_clue_provider_delegates_to_sonarr_provider() {
|
||||||
|
let mut app = App::test_default();
|
||||||
|
app.push_navigation_stack(ActiveSonarrBlock::SystemTasks.into());
|
||||||
|
|
||||||
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.logs);
|
let context_clues = ServarrContextClueProvider::get_context_clues(&mut app);
|
||||||
assert_str_eq!(*description, "open logs");
|
|
||||||
|
|
||||||
let (key_binding, description) = system_context_clues_iter.next().unwrap();
|
assert_some_eq_x!(
|
||||||
|
context_clues,
|
||||||
|
&crate::app::sonarr::sonarr_context_clues::SYSTEM_TASKS_CONTEXT_CLUES,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.update);
|
#[test]
|
||||||
assert_str_eq!(*description, "open updates");
|
fn test_servarr_context_clue_provider_unsupported_route_returns_none() {
|
||||||
|
let mut app = App::test_default();
|
||||||
|
app.push_navigation_stack(ActiveKeybindingBlock::Help.into());
|
||||||
|
|
||||||
let (key_binding, description) = system_context_clues_iter.next().unwrap();
|
let context_clues = ServarrContextClueProvider::get_context_clues(&mut app);
|
||||||
|
|
||||||
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.refresh);
|
assert_none!(context_clues);
|
||||||
assert_str_eq!(*description, DEFAULT_KEYBINDINGS.refresh.desc);
|
|
||||||
assert_eq!(system_context_clues_iter.next(), None);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+79
-1
@@ -14,6 +14,8 @@ generate_keybindings! {
|
|||||||
down,
|
down,
|
||||||
left,
|
left,
|
||||||
right,
|
right,
|
||||||
|
pg_down,
|
||||||
|
pg_up,
|
||||||
backspace,
|
backspace,
|
||||||
next_servarr,
|
next_servarr,
|
||||||
previous_servarr,
|
previous_servarr,
|
||||||
@@ -21,6 +23,7 @@ generate_keybindings! {
|
|||||||
search,
|
search,
|
||||||
auto_search,
|
auto_search,
|
||||||
settings,
|
settings,
|
||||||
|
help,
|
||||||
filter,
|
filter,
|
||||||
sort,
|
sort,
|
||||||
edit,
|
edit,
|
||||||
@@ -44,128 +47,203 @@ generate_keybindings! {
|
|||||||
#[derive(Clone, Copy, Eq, PartialEq, Debug)]
|
#[derive(Clone, Copy, Eq, PartialEq, Debug)]
|
||||||
pub struct KeyBinding {
|
pub struct KeyBinding {
|
||||||
pub key: Key,
|
pub key: Key,
|
||||||
|
pub alt: Option<Key>,
|
||||||
pub desc: &'static str,
|
pub desc: &'static str,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const DEFAULT_KEYBINDINGS: KeyBindings = KeyBindings {
|
pub const DEFAULT_KEYBINDINGS: KeyBindings = KeyBindings {
|
||||||
add: KeyBinding {
|
add: KeyBinding {
|
||||||
key: Key::Char('a'),
|
key: Key::Char('a'),
|
||||||
|
alt: None,
|
||||||
desc: "add",
|
desc: "add",
|
||||||
},
|
},
|
||||||
up: KeyBinding {
|
up: KeyBinding {
|
||||||
key: Key::Up,
|
key: Key::Up,
|
||||||
|
alt: Some(Key::Char('k')),
|
||||||
desc: "up",
|
desc: "up",
|
||||||
},
|
},
|
||||||
down: KeyBinding {
|
down: KeyBinding {
|
||||||
key: Key::Down,
|
key: Key::Down,
|
||||||
|
alt: Some(Key::Char('j')),
|
||||||
desc: "down",
|
desc: "down",
|
||||||
},
|
},
|
||||||
left: KeyBinding {
|
left: KeyBinding {
|
||||||
key: Key::Left,
|
key: Key::Left,
|
||||||
|
alt: Some(Key::Char('h')),
|
||||||
desc: "left",
|
desc: "left",
|
||||||
},
|
},
|
||||||
right: KeyBinding {
|
right: KeyBinding {
|
||||||
key: Key::Right,
|
key: Key::Right,
|
||||||
|
alt: Some(Key::Char('l')),
|
||||||
desc: "right",
|
desc: "right",
|
||||||
},
|
},
|
||||||
|
pg_down: KeyBinding {
|
||||||
|
key: Key::PgDown,
|
||||||
|
alt: Some(Key::Ctrl('d')),
|
||||||
|
desc: "page down",
|
||||||
|
},
|
||||||
|
pg_up: KeyBinding {
|
||||||
|
key: Key::PgUp,
|
||||||
|
alt: Some(Key::Ctrl('u')),
|
||||||
|
desc: "page up",
|
||||||
|
},
|
||||||
backspace: KeyBinding {
|
backspace: KeyBinding {
|
||||||
key: Key::Backspace,
|
key: Key::Backspace,
|
||||||
|
alt: Some(Key::Ctrl('h')),
|
||||||
desc: "backspace",
|
desc: "backspace",
|
||||||
},
|
},
|
||||||
next_servarr: KeyBinding {
|
next_servarr: KeyBinding {
|
||||||
key: Key::Tab,
|
key: Key::Tab,
|
||||||
|
alt: None,
|
||||||
desc: "next servarr",
|
desc: "next servarr",
|
||||||
},
|
},
|
||||||
previous_servarr: KeyBinding {
|
previous_servarr: KeyBinding {
|
||||||
key: Key::BackTab,
|
key: Key::BackTab,
|
||||||
|
alt: None,
|
||||||
desc: "previous servarr",
|
desc: "previous servarr",
|
||||||
},
|
},
|
||||||
clear: KeyBinding {
|
clear: KeyBinding {
|
||||||
key: Key::Char('c'),
|
key: Key::Char('c'),
|
||||||
|
alt: None,
|
||||||
desc: "clear",
|
desc: "clear",
|
||||||
},
|
},
|
||||||
auto_search: KeyBinding {
|
auto_search: KeyBinding {
|
||||||
key: Key::Char('S'),
|
key: Key::Char('S'),
|
||||||
|
alt: None,
|
||||||
desc: "auto search",
|
desc: "auto search",
|
||||||
},
|
},
|
||||||
search: KeyBinding {
|
search: KeyBinding {
|
||||||
key: Key::Char('s'),
|
key: Key::Char('s'),
|
||||||
|
alt: None,
|
||||||
desc: "search",
|
desc: "search",
|
||||||
},
|
},
|
||||||
settings: KeyBinding {
|
settings: KeyBinding {
|
||||||
key: Key::Char('S'),
|
key: Key::Char('S'),
|
||||||
|
alt: None,
|
||||||
desc: "settings",
|
desc: "settings",
|
||||||
},
|
},
|
||||||
|
help: KeyBinding {
|
||||||
|
key: Key::Char('?'),
|
||||||
|
alt: None,
|
||||||
|
desc: "show/hide keybindings",
|
||||||
|
},
|
||||||
filter: KeyBinding {
|
filter: KeyBinding {
|
||||||
key: Key::Char('f'),
|
key: Key::Char('f'),
|
||||||
|
alt: None,
|
||||||
desc: "filter",
|
desc: "filter",
|
||||||
},
|
},
|
||||||
sort: KeyBinding {
|
sort: KeyBinding {
|
||||||
key: Key::Char('o'),
|
key: Key::Char('o'),
|
||||||
|
alt: None,
|
||||||
desc: "sort",
|
desc: "sort",
|
||||||
},
|
},
|
||||||
edit: KeyBinding {
|
edit: KeyBinding {
|
||||||
key: Key::Char('e'),
|
key: Key::Char('e'),
|
||||||
|
alt: None,
|
||||||
desc: "edit",
|
desc: "edit",
|
||||||
},
|
},
|
||||||
events: KeyBinding {
|
events: KeyBinding {
|
||||||
key: Key::Char('e'),
|
key: Key::Char('e'),
|
||||||
|
alt: None,
|
||||||
desc: "events",
|
desc: "events",
|
||||||
},
|
},
|
||||||
logs: KeyBinding {
|
logs: KeyBinding {
|
||||||
key: Key::Char('l'),
|
key: Key::Char('L'),
|
||||||
|
alt: None,
|
||||||
desc: "logs",
|
desc: "logs",
|
||||||
},
|
},
|
||||||
tasks: KeyBinding {
|
tasks: KeyBinding {
|
||||||
key: Key::Char('t'),
|
key: Key::Char('t'),
|
||||||
|
alt: None,
|
||||||
desc: "tasks",
|
desc: "tasks",
|
||||||
},
|
},
|
||||||
test: KeyBinding {
|
test: KeyBinding {
|
||||||
key: Key::Char('t'),
|
key: Key::Char('t'),
|
||||||
|
alt: None,
|
||||||
desc: "test",
|
desc: "test",
|
||||||
},
|
},
|
||||||
test_all: KeyBinding {
|
test_all: KeyBinding {
|
||||||
key: Key::Char('T'),
|
key: Key::Char('T'),
|
||||||
|
alt: None,
|
||||||
desc: "test all",
|
desc: "test all",
|
||||||
},
|
},
|
||||||
toggle_monitoring: KeyBinding {
|
toggle_monitoring: KeyBinding {
|
||||||
key: Key::Char('m'),
|
key: Key::Char('m'),
|
||||||
|
alt: None,
|
||||||
desc: "toggle monitoring",
|
desc: "toggle monitoring",
|
||||||
},
|
},
|
||||||
refresh: KeyBinding {
|
refresh: KeyBinding {
|
||||||
key: Key::Ctrl('r'),
|
key: Key::Ctrl('r'),
|
||||||
|
alt: None,
|
||||||
desc: "refresh",
|
desc: "refresh",
|
||||||
},
|
},
|
||||||
update: KeyBinding {
|
update: KeyBinding {
|
||||||
key: Key::Char('u'),
|
key: Key::Char('u'),
|
||||||
|
alt: None,
|
||||||
desc: "update",
|
desc: "update",
|
||||||
},
|
},
|
||||||
home: KeyBinding {
|
home: KeyBinding {
|
||||||
key: Key::Home,
|
key: Key::Home,
|
||||||
|
alt: None,
|
||||||
desc: "home",
|
desc: "home",
|
||||||
},
|
},
|
||||||
end: KeyBinding {
|
end: KeyBinding {
|
||||||
key: Key::End,
|
key: Key::End,
|
||||||
|
alt: None,
|
||||||
desc: "end",
|
desc: "end",
|
||||||
},
|
},
|
||||||
delete: KeyBinding {
|
delete: KeyBinding {
|
||||||
key: Key::Delete,
|
key: Key::Delete,
|
||||||
|
alt: None,
|
||||||
desc: "delete",
|
desc: "delete",
|
||||||
},
|
},
|
||||||
submit: KeyBinding {
|
submit: KeyBinding {
|
||||||
key: Key::Enter,
|
key: Key::Enter,
|
||||||
|
alt: None,
|
||||||
desc: "submit",
|
desc: "submit",
|
||||||
},
|
},
|
||||||
confirm: KeyBinding {
|
confirm: KeyBinding {
|
||||||
key: Key::Ctrl('s'),
|
key: Key::Ctrl('s'),
|
||||||
|
alt: None,
|
||||||
desc: "submit",
|
desc: "submit",
|
||||||
},
|
},
|
||||||
quit: KeyBinding {
|
quit: KeyBinding {
|
||||||
key: Key::Char('q'),
|
key: Key::Char('q'),
|
||||||
|
alt: None,
|
||||||
desc: "quit",
|
desc: "quit",
|
||||||
},
|
},
|
||||||
esc: KeyBinding {
|
esc: KeyBinding {
|
||||||
key: Key::Esc,
|
key: Key::Esc,
|
||||||
|
alt: None,
|
||||||
desc: "close",
|
desc: "close",
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! matches_key {
|
||||||
|
($binding:ident, $key:expr) => {
|
||||||
|
$crate::app::key_binding::DEFAULT_KEYBINDINGS.$binding.key == $key
|
||||||
|
|| ($crate::app::key_binding::DEFAULT_KEYBINDINGS
|
||||||
|
.$binding
|
||||||
|
.alt
|
||||||
|
.is_some()
|
||||||
|
&& $crate::app::key_binding::DEFAULT_KEYBINDINGS
|
||||||
|
.$binding
|
||||||
|
.alt
|
||||||
|
.unwrap()
|
||||||
|
== $key)
|
||||||
|
};
|
||||||
|
($binding:ident, $key:expr, $ignore_special_keys:expr) => {
|
||||||
|
$crate::app::key_binding::DEFAULT_KEYBINDINGS.$binding.key == $key
|
||||||
|
|| !$ignore_special_keys
|
||||||
|
&& ($crate::app::key_binding::DEFAULT_KEYBINDINGS
|
||||||
|
.$binding
|
||||||
|
.alt
|
||||||
|
.is_some()
|
||||||
|
&& $crate::app::key_binding::DEFAULT_KEYBINDINGS
|
||||||
|
.$binding
|
||||||
|
.alt
|
||||||
|
.unwrap()
|
||||||
|
== $key)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|||||||
@@ -3,46 +3,90 @@ mod test {
|
|||||||
use pretty_assertions::{assert_eq, assert_str_eq};
|
use pretty_assertions::{assert_eq, assert_str_eq};
|
||||||
use rstest::rstest;
|
use rstest::rstest;
|
||||||
|
|
||||||
use crate::app::key_binding::{KeyBinding, DEFAULT_KEYBINDINGS};
|
use crate::app::key_binding::{DEFAULT_KEYBINDINGS, KeyBinding};
|
||||||
use crate::event::Key;
|
use crate::event::Key;
|
||||||
|
use crate::matches_key;
|
||||||
|
|
||||||
#[rstest]
|
#[rstest]
|
||||||
#[case(DEFAULT_KEYBINDINGS.add, Key::Char('a'), "add")]
|
#[case(DEFAULT_KEYBINDINGS.add, Key::Char('a'), None, "add")]
|
||||||
#[case(DEFAULT_KEYBINDINGS.up, Key::Up, "up")]
|
#[case(DEFAULT_KEYBINDINGS.up, Key::Up, Some(Key::Char('k')), "up")]
|
||||||
#[case(DEFAULT_KEYBINDINGS.down, Key::Down, "down")]
|
#[case(DEFAULT_KEYBINDINGS.down, Key::Down, Some(Key::Char('j')), "down")]
|
||||||
#[case(DEFAULT_KEYBINDINGS.left, Key::Left, "left")]
|
#[case(DEFAULT_KEYBINDINGS.left, Key::Left, Some(Key::Char('h')), "left")]
|
||||||
#[case(DEFAULT_KEYBINDINGS.right, Key::Right, "right")]
|
#[case(DEFAULT_KEYBINDINGS.right, Key::Right, Some(Key::Char('l')), "right")]
|
||||||
#[case(DEFAULT_KEYBINDINGS.backspace, Key::Backspace, "backspace")]
|
#[case(DEFAULT_KEYBINDINGS.pg_down, Key::PgDown, Some(Key::Ctrl('d')), "page down")]
|
||||||
#[case(DEFAULT_KEYBINDINGS.next_servarr, Key::Tab, "next servarr")]
|
#[case(DEFAULT_KEYBINDINGS.pg_up, Key::PgUp, Some(Key::Ctrl('u')), "page up")]
|
||||||
#[case(DEFAULT_KEYBINDINGS.previous_servarr, Key::BackTab, "previous servarr")]
|
#[case(DEFAULT_KEYBINDINGS.backspace, Key::Backspace, Some(Key::Ctrl('h')), "backspace")]
|
||||||
#[case(DEFAULT_KEYBINDINGS.clear, Key::Char('c'), "clear")]
|
#[case(DEFAULT_KEYBINDINGS.next_servarr, Key::Tab, None, "next servarr")]
|
||||||
#[case(DEFAULT_KEYBINDINGS.auto_search, Key::Char('S'), "auto search")]
|
#[case(DEFAULT_KEYBINDINGS.previous_servarr, Key::BackTab, None, "previous servarr")]
|
||||||
#[case(DEFAULT_KEYBINDINGS.search, Key::Char('s'), "search")]
|
#[case(DEFAULT_KEYBINDINGS.clear, Key::Char('c'), None, "clear")]
|
||||||
#[case(DEFAULT_KEYBINDINGS.settings, Key::Char('S'), "settings")]
|
#[case(DEFAULT_KEYBINDINGS.auto_search, Key::Char('S'), None, "auto search")]
|
||||||
#[case(DEFAULT_KEYBINDINGS.filter, Key::Char('f'), "filter")]
|
#[case(DEFAULT_KEYBINDINGS.search, Key::Char('s'), None, "search")]
|
||||||
#[case(DEFAULT_KEYBINDINGS.sort, Key::Char('o'), "sort")]
|
#[case(DEFAULT_KEYBINDINGS.settings, Key::Char('S'), None, "settings")]
|
||||||
#[case(DEFAULT_KEYBINDINGS.edit, Key::Char('e'), "edit")]
|
#[case(DEFAULT_KEYBINDINGS.help, Key::Char('?'), None, "show/hide keybindings")]
|
||||||
#[case(DEFAULT_KEYBINDINGS.events, Key::Char('e'), "events")]
|
#[case(DEFAULT_KEYBINDINGS.filter, Key::Char('f'), None, "filter")]
|
||||||
#[case(DEFAULT_KEYBINDINGS.logs, Key::Char('l'), "logs")]
|
#[case(DEFAULT_KEYBINDINGS.sort, Key::Char('o'), None, "sort")]
|
||||||
#[case(DEFAULT_KEYBINDINGS.tasks, Key::Char('t'), "tasks")]
|
#[case(DEFAULT_KEYBINDINGS.edit, Key::Char('e'), None, "edit")]
|
||||||
#[case(DEFAULT_KEYBINDINGS.test, Key::Char('t'), "test")]
|
#[case(DEFAULT_KEYBINDINGS.events, Key::Char('e'), None, "events")]
|
||||||
#[case(DEFAULT_KEYBINDINGS.test_all, Key::Char('T'), "test all")]
|
#[case(DEFAULT_KEYBINDINGS.logs, Key::Char('L'), None, "logs")]
|
||||||
#[case(DEFAULT_KEYBINDINGS.toggle_monitoring, Key::Char('m'), "toggle monitoring")]
|
#[case(DEFAULT_KEYBINDINGS.tasks, Key::Char('t'), None, "tasks")]
|
||||||
#[case(DEFAULT_KEYBINDINGS.refresh, Key::Ctrl('r'), "refresh")]
|
#[case(DEFAULT_KEYBINDINGS.test, Key::Char('t'), None, "test")]
|
||||||
#[case(DEFAULT_KEYBINDINGS.update, Key::Char('u'), "update")]
|
#[case(DEFAULT_KEYBINDINGS.test_all, Key::Char('T'), None, "test all")]
|
||||||
#[case(DEFAULT_KEYBINDINGS.home, Key::Home, "home")]
|
#[case(DEFAULT_KEYBINDINGS.toggle_monitoring, Key::Char('m'), None, "toggle monitoring")]
|
||||||
#[case(DEFAULT_KEYBINDINGS.end, Key::End, "end")]
|
#[case(DEFAULT_KEYBINDINGS.refresh, Key::Ctrl('r'), None, "refresh")]
|
||||||
#[case(DEFAULT_KEYBINDINGS.delete, Key::Delete, "delete")]
|
#[case(DEFAULT_KEYBINDINGS.update, Key::Char('u'), None, "update")]
|
||||||
#[case(DEFAULT_KEYBINDINGS.submit, Key::Enter, "submit")]
|
#[case(DEFAULT_KEYBINDINGS.home, Key::Home, None, "home")]
|
||||||
#[case(DEFAULT_KEYBINDINGS.confirm, Key::Ctrl('s'), "submit")]
|
#[case(DEFAULT_KEYBINDINGS.end, Key::End, None, "end")]
|
||||||
#[case(DEFAULT_KEYBINDINGS.quit, Key::Char('q'), "quit")]
|
#[case(DEFAULT_KEYBINDINGS.delete, Key::Delete, None, "delete")]
|
||||||
#[case(DEFAULT_KEYBINDINGS.esc, Key::Esc, "close")]
|
#[case(DEFAULT_KEYBINDINGS.submit, Key::Enter, None, "submit")]
|
||||||
|
#[case(DEFAULT_KEYBINDINGS.confirm, Key::Ctrl('s'), None, "submit")]
|
||||||
|
#[case(DEFAULT_KEYBINDINGS.quit, Key::Char('q'), None, "quit")]
|
||||||
|
#[case(DEFAULT_KEYBINDINGS.esc, Key::Esc, None, "close")]
|
||||||
fn test_default_key_bindings_and_descriptions(
|
fn test_default_key_bindings_and_descriptions(
|
||||||
#[case] key_binding: KeyBinding,
|
#[case] key_binding: KeyBinding,
|
||||||
#[case] expected_key: Key,
|
#[case] expected_key: Key,
|
||||||
|
#[case] expected_alt_key: Option<Key>,
|
||||||
#[case] expected_desc: &str,
|
#[case] expected_desc: &str,
|
||||||
) {
|
) {
|
||||||
assert_eq!(key_binding.key, expected_key);
|
assert_eq!(key_binding.key, expected_key);
|
||||||
|
assert_eq!(key_binding.alt, expected_alt_key);
|
||||||
assert_str_eq!(key_binding.desc, expected_desc);
|
assert_str_eq!(key_binding.desc, expected_desc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_matches_key_macro() {
|
||||||
|
let key = Key::Char('t');
|
||||||
|
|
||||||
|
assert!(matches_key!(test, key));
|
||||||
|
assert!(!matches_key!(test, Key::Char('T')));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_matches_key_macro_with_alt_keybinding() {
|
||||||
|
let alt_key = Key::Char('k');
|
||||||
|
let key = Key::Up;
|
||||||
|
|
||||||
|
assert!(matches_key!(up, key));
|
||||||
|
assert!(matches_key!(up, alt_key));
|
||||||
|
assert!(!matches_key!(up, Key::Char('t')));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_matches_key_macro_with_alt_keybinding_uses_alt_key_when_ignore_special_keys_is_false() {
|
||||||
|
let alt_key = Key::Char('k');
|
||||||
|
let key = Key::Up;
|
||||||
|
|
||||||
|
assert!(matches_key!(up, key, false));
|
||||||
|
assert!(matches_key!(up, alt_key, false));
|
||||||
|
assert!(!matches_key!(up, Key::Char('t'), false));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_matches_key_macro_with_alt_keybinding_ignores_alt_key_when_ignore_special_keys_is_true() {
|
||||||
|
let alt_key = Key::Char('k');
|
||||||
|
let key = Key::Up;
|
||||||
|
|
||||||
|
assert!(matches_key!(up, key, true));
|
||||||
|
assert!(!matches_key!(up, alt_key, true));
|
||||||
|
assert!(!matches_key!(up, Key::Char('t'), true));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+278
-73
@@ -1,16 +1,22 @@
|
|||||||
use std::process;
|
use anyhow::{Error, Result, anyhow};
|
||||||
|
|
||||||
use anyhow::{anyhow, Error};
|
|
||||||
use colored::Colorize;
|
use colored::Colorize;
|
||||||
|
use itertools::Itertools;
|
||||||
use log::{debug, error};
|
use log::{debug, error};
|
||||||
|
use regex::Regex;
|
||||||
|
use reqwest::header::{HeaderMap, HeaderName, HeaderValue};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
use std::{fs, process};
|
||||||
use tokio::sync::mpsc::Sender;
|
use tokio::sync::mpsc::Sender;
|
||||||
use tokio_util::sync::CancellationToken;
|
use tokio_util::sync::CancellationToken;
|
||||||
|
use veil::Redact;
|
||||||
|
|
||||||
use crate::app::context_clues::{build_context_clue_string, SERVARR_CONTEXT_CLUES};
|
|
||||||
use crate::cli::Command;
|
use crate::cli::Command;
|
||||||
use crate::models::servarr_data::radarr::radarr_data::{ActiveRadarrBlock, RadarrData};
|
use crate::models::servarr_data::radarr::radarr_data::{ActiveRadarrBlock, RadarrData};
|
||||||
use crate::models::servarr_data::sonarr::sonarr_data::{ActiveSonarrBlock, SonarrData};
|
use crate::models::servarr_data::sonarr::sonarr_data::{ActiveSonarrBlock, SonarrData};
|
||||||
|
use crate::models::servarr_models::KeybindingItem;
|
||||||
|
use crate::models::stateful_table::StatefulTable;
|
||||||
use crate::models::{HorizontallyScrollableText, Route, TabRoute, TabState};
|
use crate::models::{HorizontallyScrollableText, Route, TabRoute, TabState};
|
||||||
use crate::network::NetworkEvent;
|
use crate::network::NetworkEvent;
|
||||||
|
|
||||||
@@ -29,6 +35,7 @@ pub struct App<'a> {
|
|||||||
pub cancellation_token: CancellationToken,
|
pub cancellation_token: CancellationToken,
|
||||||
pub is_first_render: bool,
|
pub is_first_render: bool,
|
||||||
pub server_tabs: TabState,
|
pub server_tabs: TabState,
|
||||||
|
pub keymapping_table: Option<StatefulTable<KeybindingItem>>,
|
||||||
pub error: HorizontallyScrollableText,
|
pub error: HorizontallyScrollableText,
|
||||||
pub tick_until_poll: u64,
|
pub tick_until_poll: u64,
|
||||||
pub ticks_until_scroll: u64,
|
pub ticks_until_scroll: u64,
|
||||||
@@ -36,13 +43,12 @@ pub struct App<'a> {
|
|||||||
pub is_routing: bool,
|
pub is_routing: bool,
|
||||||
pub is_loading: bool,
|
pub is_loading: bool,
|
||||||
pub should_refresh: bool,
|
pub should_refresh: bool,
|
||||||
pub should_ignore_quit_key: bool,
|
pub ignore_special_keys_for_textbox_input: bool,
|
||||||
pub cli_mode: bool,
|
pub cli_mode: bool,
|
||||||
pub config: AppConfig,
|
|
||||||
pub data: Data<'a>,
|
pub data: Data<'a>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> App<'a> {
|
impl App<'_> {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
network_tx: Sender<NetworkEvent>,
|
network_tx: Sender<NetworkEvent>,
|
||||||
config: AppConfig,
|
config: AppConfig,
|
||||||
@@ -50,35 +56,72 @@ impl<'a> App<'a> {
|
|||||||
) -> Self {
|
) -> Self {
|
||||||
let mut server_tabs = Vec::new();
|
let mut server_tabs = Vec::new();
|
||||||
|
|
||||||
if config.radarr.is_some() {
|
if let Some(radarr_configs) = config.radarr {
|
||||||
server_tabs.push(TabRoute {
|
let mut unnamed_idx = 0;
|
||||||
title: "Radarr",
|
let radarr_tabs = radarr_configs.into_iter().map(|radarr_config| {
|
||||||
route: ActiveRadarrBlock::Movies.into(),
|
let name = if let Some(name) = radarr_config.name.clone() {
|
||||||
help: format!(
|
name
|
||||||
"<↑↓> scroll | ←→ change tab | {} ",
|
} else {
|
||||||
build_context_clue_string(&SERVARR_CONTEXT_CLUES)
|
unnamed_idx += 1;
|
||||||
),
|
format!("Radarr {unnamed_idx}")
|
||||||
contextual_help: None,
|
};
|
||||||
|
|
||||||
|
TabRoute {
|
||||||
|
title: name,
|
||||||
|
route: ActiveRadarrBlock::Movies.into(),
|
||||||
|
contextual_help: None,
|
||||||
|
config: Some(radarr_config),
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
server_tabs.extend(radarr_tabs);
|
||||||
}
|
}
|
||||||
|
|
||||||
if config.sonarr.is_some() {
|
if let Some(sonarr_configs) = config.sonarr {
|
||||||
server_tabs.push(TabRoute {
|
let mut unnamed_idx = 0;
|
||||||
title: "Sonarr",
|
let sonarr_tabs = sonarr_configs.into_iter().map(|sonarr_config| {
|
||||||
route: ActiveSonarrBlock::Series.into(),
|
let name = if let Some(name) = sonarr_config.name.clone() {
|
||||||
help: format!(
|
name
|
||||||
"<↑↓> scroll | ←→ change tab | {} ",
|
} else {
|
||||||
build_context_clue_string(&SERVARR_CONTEXT_CLUES)
|
unnamed_idx += 1;
|
||||||
),
|
format!("Sonarr {unnamed_idx}")
|
||||||
contextual_help: None,
|
};
|
||||||
|
|
||||||
|
TabRoute {
|
||||||
|
title: name,
|
||||||
|
route: ActiveSonarrBlock::Series.into(),
|
||||||
|
contextual_help: None,
|
||||||
|
config: Some(sonarr_config),
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
server_tabs.extend(sonarr_tabs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let weight_sorted_tabs = server_tabs
|
||||||
|
.into_iter()
|
||||||
|
.sorted_by(|tab1, tab2| {
|
||||||
|
Ord::cmp(
|
||||||
|
tab1
|
||||||
|
.config
|
||||||
|
.as_ref()
|
||||||
|
.unwrap()
|
||||||
|
.weight
|
||||||
|
.as_ref()
|
||||||
|
.unwrap_or(&1000),
|
||||||
|
tab2
|
||||||
|
.config
|
||||||
|
.as_ref()
|
||||||
|
.unwrap()
|
||||||
|
.weight
|
||||||
|
.as_ref()
|
||||||
|
.unwrap_or(&1000),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
App {
|
App {
|
||||||
network_tx: Some(network_tx),
|
network_tx: Some(network_tx),
|
||||||
config,
|
|
||||||
cancellation_token,
|
cancellation_token,
|
||||||
server_tabs: TabState::new(server_tabs),
|
server_tabs: TabState::new(weight_sorted_tabs),
|
||||||
..App::default()
|
..App::default()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -90,12 +133,12 @@ impl<'a> App<'a> {
|
|||||||
self.is_loading = true;
|
self.is_loading = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(network_tx) = &self.network_tx {
|
if let Some(network_tx) = &self.network_tx
|
||||||
if let Err(e) = network_tx.send(action).await {
|
&& let Err(e) = network_tx.send(action).await
|
||||||
self.is_loading = false;
|
{
|
||||||
error!("Failed to send event. {e:?}");
|
self.is_loading = false;
|
||||||
self.handle_error(anyhow!(e));
|
error!("Failed to send event. {e:?}");
|
||||||
}
|
self.handle_error(anyhow!(e));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -118,7 +161,10 @@ impl<'a> App<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn on_tick(&mut self) {
|
pub async fn on_tick(&mut self) {
|
||||||
if self.tick_count % self.tick_until_poll == 0 || self.is_routing || self.should_refresh {
|
if self.tick_count.is_multiple_of(self.tick_until_poll)
|
||||||
|
|| self.is_routing
|
||||||
|
|| self.should_refresh
|
||||||
|
{
|
||||||
match self.get_current_route() {
|
match self.get_current_route() {
|
||||||
Route::Radarr(active_radarr_block, _) => self.radarr_on_tick(active_radarr_block).await,
|
Route::Radarr(active_radarr_block, _) => self.radarr_on_tick(active_radarr_block).await,
|
||||||
Route::Sonarr(active_sonarr_block, _) => self.sonarr_on_tick(active_sonarr_block).await,
|
Route::Sonarr(active_sonarr_block, _) => self.sonarr_on_tick(active_sonarr_block).await,
|
||||||
@@ -158,55 +204,63 @@ impl<'a> App<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_current_route(&self) -> Route {
|
pub fn get_current_route(&self) -> Route {
|
||||||
*self
|
*self.navigation_stack.last().unwrap_or(
|
||||||
.navigation_stack
|
&self
|
||||||
.last()
|
.server_tabs
|
||||||
.unwrap_or(&self.server_tabs.tabs.first().unwrap().route)
|
.tabs
|
||||||
|
.first()
|
||||||
|
.expect("At least one server tab must exist")
|
||||||
|
.route,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Default for App<'a> {
|
impl Default for App<'_> {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
App {
|
App {
|
||||||
navigation_stack: Vec::new(),
|
navigation_stack: Vec::new(),
|
||||||
network_tx: None,
|
network_tx: None,
|
||||||
cancellation_token: CancellationToken::new(),
|
cancellation_token: CancellationToken::new(),
|
||||||
|
keymapping_table: None,
|
||||||
error: HorizontallyScrollableText::default(),
|
error: HorizontallyScrollableText::default(),
|
||||||
is_first_render: true,
|
is_first_render: true,
|
||||||
server_tabs: TabState::new(vec![
|
server_tabs: TabState::new(Vec::new()),
|
||||||
TabRoute {
|
|
||||||
title: "Radarr",
|
|
||||||
route: ActiveRadarrBlock::Movies.into(),
|
|
||||||
help: format!(
|
|
||||||
"<↑↓> scroll | ←→ change tab | {} ",
|
|
||||||
build_context_clue_string(&SERVARR_CONTEXT_CLUES)
|
|
||||||
),
|
|
||||||
contextual_help: None,
|
|
||||||
},
|
|
||||||
TabRoute {
|
|
||||||
title: "Sonarr",
|
|
||||||
route: ActiveSonarrBlock::Series.into(),
|
|
||||||
help: format!(
|
|
||||||
"<↑↓> scroll | ←→ change tab | {} ",
|
|
||||||
build_context_clue_string(&SERVARR_CONTEXT_CLUES)
|
|
||||||
),
|
|
||||||
contextual_help: None,
|
|
||||||
},
|
|
||||||
]),
|
|
||||||
tick_until_poll: 400,
|
tick_until_poll: 400,
|
||||||
ticks_until_scroll: 4,
|
ticks_until_scroll: 4,
|
||||||
tick_count: 0,
|
tick_count: 0,
|
||||||
is_loading: false,
|
is_loading: false,
|
||||||
is_routing: false,
|
is_routing: false,
|
||||||
should_refresh: false,
|
should_refresh: false,
|
||||||
should_ignore_quit_key: false,
|
ignore_special_keys_for_textbox_input: false,
|
||||||
cli_mode: false,
|
cli_mode: false,
|
||||||
config: AppConfig::default(),
|
|
||||||
data: Data::default(),
|
data: Data::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
impl App<'_> {
|
||||||
|
pub fn test_default() -> Self {
|
||||||
|
App {
|
||||||
|
server_tabs: TabState::new(vec![
|
||||||
|
TabRoute {
|
||||||
|
title: "Radarr".to_owned(),
|
||||||
|
route: ActiveRadarrBlock::Movies.into(),
|
||||||
|
contextual_help: None,
|
||||||
|
config: Some(ServarrConfig::default()),
|
||||||
|
},
|
||||||
|
TabRoute {
|
||||||
|
title: "Sonarr".to_owned(),
|
||||||
|
route: ActiveSonarrBlock::Series.into(),
|
||||||
|
contextual_help: None,
|
||||||
|
config: Some(ServarrConfig::default()),
|
||||||
|
},
|
||||||
|
]),
|
||||||
|
..App::default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct Data<'a> {
|
pub struct Data<'a> {
|
||||||
pub radarr_data: RadarrData<'a>,
|
pub radarr_data: RadarrData<'a>,
|
||||||
@@ -215,8 +269,9 @@ pub struct Data<'a> {
|
|||||||
|
|
||||||
#[derive(Debug, Deserialize, Serialize, Default, Clone)]
|
#[derive(Debug, Deserialize, Serialize, Default, Clone)]
|
||||||
pub struct AppConfig {
|
pub struct AppConfig {
|
||||||
pub radarr: Option<ServarrConfig>,
|
pub theme: Option<String>,
|
||||||
pub sonarr: Option<ServarrConfig>,
|
pub radarr: Option<Vec<ServarrConfig>>,
|
||||||
|
pub sonarr: Option<Vec<ServarrConfig>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AppConfig {
|
impl AppConfig {
|
||||||
@@ -228,20 +283,19 @@ impl AppConfig {
|
|||||||
process::exit(1);
|
process::exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(radarr_config) = &self.radarr {
|
if let Some(radarr_configs) = &self.radarr {
|
||||||
radarr_config.validate();
|
radarr_configs.iter().for_each(|config| config.validate());
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(sonarr_config) = &self.sonarr {
|
if let Some(sonarr_configs) = &self.sonarr {
|
||||||
sonarr_config.validate();
|
sonarr_configs.iter().for_each(|config| config.validate());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn verify_config_present_for_cli(&self, command: &Command) {
|
pub fn verify_config_present_for_cli(&self, command: &Command) {
|
||||||
let msg = |servarr: &str| {
|
let msg = |servarr: &str| {
|
||||||
log_and_print_error(format!(
|
log_and_print_error(format!(
|
||||||
"{} configuration missing; Unable to run any {} commands.",
|
"{servarr} configuration missing; Unable to run any {servarr} commands."
|
||||||
servarr, servarr
|
|
||||||
))
|
))
|
||||||
};
|
};
|
||||||
match command {
|
match command {
|
||||||
@@ -256,15 +310,47 @@ impl AppConfig {
|
|||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn post_process_initialization(&mut self) {
|
||||||
|
if let Some(radarr_configs) = self.radarr.as_mut() {
|
||||||
|
for radarr_config in radarr_configs {
|
||||||
|
radarr_config.post_process_initialization();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(sonarr_configs) = self.sonarr.as_mut() {
|
||||||
|
for sonarr_config in sonarr_configs {
|
||||||
|
sonarr_config.post_process_initialization();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, Serialize, Clone)]
|
#[derive(Redact, Deserialize, Serialize, Clone, PartialEq, Eq)]
|
||||||
pub struct ServarrConfig {
|
pub struct ServarrConfig {
|
||||||
|
#[serde(default, deserialize_with = "deserialize_optional_env_var")]
|
||||||
|
pub name: Option<String>,
|
||||||
|
#[serde(default, deserialize_with = "deserialize_optional_env_var")]
|
||||||
pub host: Option<String>,
|
pub host: Option<String>,
|
||||||
|
#[serde(default, deserialize_with = "deserialize_u16_env_var")]
|
||||||
pub port: Option<u16>,
|
pub port: Option<u16>,
|
||||||
|
#[serde(default, deserialize_with = "deserialize_optional_env_var")]
|
||||||
pub uri: Option<String>,
|
pub uri: Option<String>,
|
||||||
pub api_token: String,
|
#[serde(default, deserialize_with = "deserialize_u16_env_var")]
|
||||||
|
pub weight: Option<u16>,
|
||||||
|
#[serde(default, deserialize_with = "deserialize_optional_env_var")]
|
||||||
|
#[redact]
|
||||||
|
pub api_token: Option<String>,
|
||||||
|
#[serde(default, deserialize_with = "deserialize_optional_env_var")]
|
||||||
|
pub api_token_file: Option<String>,
|
||||||
|
#[serde(default, deserialize_with = "deserialize_optional_env_var")]
|
||||||
pub ssl_cert_path: Option<String>,
|
pub ssl_cert_path: Option<String>,
|
||||||
|
#[serde(
|
||||||
|
default,
|
||||||
|
deserialize_with = "deserialize_optional_env_var_header_map",
|
||||||
|
serialize_with = "serialize_header_map"
|
||||||
|
)]
|
||||||
|
pub custom_headers: Option<HeaderMap>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ServarrConfig {
|
impl ServarrConfig {
|
||||||
@@ -273,22 +359,141 @@ impl ServarrConfig {
|
|||||||
log_and_print_error("'host' or 'uri' is required for configuration".to_owned());
|
log_and_print_error("'host' or 'uri' is required for configuration".to_owned());
|
||||||
process::exit(1);
|
process::exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if self.api_token_file.is_none() && self.api_token.is_none() {
|
||||||
|
log_and_print_error(
|
||||||
|
"'api_token' or 'api_token_path' is required for configuration".to_owned(),
|
||||||
|
);
|
||||||
|
process::exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn post_process_initialization(&mut self) {
|
||||||
|
if let Some(api_token_file) = self.api_token_file.as_ref() {
|
||||||
|
if !PathBuf::from(api_token_file).exists() {
|
||||||
|
log_and_print_error(format!(
|
||||||
|
"The specified {api_token_file} API token file does not exist"
|
||||||
|
));
|
||||||
|
process::exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
let api_token = fs::read_to_string(api_token_file)
|
||||||
|
.map_err(|e| anyhow!(e))
|
||||||
|
.unwrap();
|
||||||
|
self.api_token = Some(api_token.trim().to_owned());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for ServarrConfig {
|
impl Default for ServarrConfig {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
ServarrConfig {
|
ServarrConfig {
|
||||||
|
name: None,
|
||||||
host: Some("localhost".to_string()),
|
host: Some("localhost".to_string()),
|
||||||
port: None,
|
port: None,
|
||||||
uri: None,
|
uri: None,
|
||||||
api_token: "".to_string(),
|
weight: None,
|
||||||
|
api_token: Some(String::new()),
|
||||||
|
api_token_file: None,
|
||||||
ssl_cert_path: None,
|
ssl_cert_path: None,
|
||||||
|
custom_headers: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn log_and_print_error(error: String) {
|
pub fn log_and_print_error(error: String) {
|
||||||
error!("{}", error);
|
error!("{error}");
|
||||||
eprintln!("error: {}", error.red());
|
eprintln!("error: {}", error.red());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn serialize_header_map<S>(headers: &Option<HeaderMap>, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
|
where
|
||||||
|
S: serde::Serializer,
|
||||||
|
{
|
||||||
|
if let Some(headers) = headers {
|
||||||
|
let mut map = HashMap::new();
|
||||||
|
for (name, value) in headers.iter() {
|
||||||
|
let name_str = name.as_str().to_string();
|
||||||
|
let value_str = value
|
||||||
|
.to_str()
|
||||||
|
.map_err(serde::ser::Error::custom)?
|
||||||
|
.to_string();
|
||||||
|
|
||||||
|
map.insert(name_str, value_str);
|
||||||
|
}
|
||||||
|
map.serialize(serializer)
|
||||||
|
} else {
|
||||||
|
serializer.serialize_none()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn deserialize_optional_env_var<'de, D>(deserializer: D) -> Result<Option<String>, D::Error>
|
||||||
|
where
|
||||||
|
D: serde::Deserializer<'de>,
|
||||||
|
{
|
||||||
|
let s: Option<String> = Option::deserialize(deserializer)?;
|
||||||
|
match s {
|
||||||
|
Some(value) => {
|
||||||
|
let interpolated = interpolate_env_vars(&value);
|
||||||
|
Ok(Some(interpolated))
|
||||||
|
}
|
||||||
|
None => Ok(None),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn deserialize_optional_env_var_header_map<'de, D>(
|
||||||
|
deserializer: D,
|
||||||
|
) -> Result<Option<HeaderMap>, D::Error>
|
||||||
|
where
|
||||||
|
D: serde::Deserializer<'de>,
|
||||||
|
{
|
||||||
|
let opt: Option<HashMap<String, String>> = Option::deserialize(deserializer)?;
|
||||||
|
match opt {
|
||||||
|
Some(map) => {
|
||||||
|
let mut header_map = HeaderMap::new();
|
||||||
|
for (k, v) in map.iter() {
|
||||||
|
let name = HeaderName::from_bytes(k.as_bytes()).map_err(serde::de::Error::custom)?;
|
||||||
|
let value_str = interpolate_env_vars(v);
|
||||||
|
let value = HeaderValue::from_str(&value_str).map_err(serde::de::Error::custom)?;
|
||||||
|
header_map.insert(name, value);
|
||||||
|
}
|
||||||
|
Ok(Some(header_map))
|
||||||
|
}
|
||||||
|
None => Ok(None),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn deserialize_u16_env_var<'de, D>(deserializer: D) -> Result<Option<u16>, D::Error>
|
||||||
|
where
|
||||||
|
D: serde::Deserializer<'de>,
|
||||||
|
{
|
||||||
|
let s: Option<String> = Option::deserialize(deserializer)?;
|
||||||
|
match s {
|
||||||
|
Some(value) => {
|
||||||
|
let interpolated = interpolate_env_vars(&value);
|
||||||
|
interpolated
|
||||||
|
.parse::<u16>()
|
||||||
|
.map(Some)
|
||||||
|
.map_err(serde::de::Error::custom)
|
||||||
|
}
|
||||||
|
None => Ok(None),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn interpolate_env_vars(s: &str) -> String {
|
||||||
|
let result = s.to_string();
|
||||||
|
let scrubbing_regex = Regex::new(r#"[\s{}!$^()\[\]\\|`'"]+"#).unwrap();
|
||||||
|
let var_regex = Regex::new(r"\$\{(.*?)}").unwrap();
|
||||||
|
|
||||||
|
var_regex
|
||||||
|
.replace_all(s, |caps: ®ex::Captures<'_>| {
|
||||||
|
if let Some(mat) = caps.get(1)
|
||||||
|
&& let Ok(value) = std::env::var(mat.as_str())
|
||||||
|
{
|
||||||
|
return scrubbing_regex.replace_all(&value, "").to_string();
|
||||||
|
}
|
||||||
|
|
||||||
|
scrubbing_regex.replace_all(&result, "").to_string()
|
||||||
|
})
|
||||||
|
.to_string()
|
||||||
|
}
|
||||||
|
|||||||
+9
-18
@@ -8,7 +8,7 @@ pub mod radarr_context_clues;
|
|||||||
#[path = "radarr_tests.rs"]
|
#[path = "radarr_tests.rs"]
|
||||||
mod radarr_tests;
|
mod radarr_tests;
|
||||||
|
|
||||||
impl<'a> App<'a> {
|
impl App<'_> {
|
||||||
pub(super) async fn dispatch_by_radarr_block(&mut self, active_radarr_block: &ActiveRadarrBlock) {
|
pub(super) async fn dispatch_by_radarr_block(&mut self, active_radarr_block: &ActiveRadarrBlock) {
|
||||||
match active_radarr_block {
|
match active_radarr_block {
|
||||||
ActiveRadarrBlock::Blocklist => {
|
ActiveRadarrBlock::Blocklist => {
|
||||||
@@ -40,7 +40,7 @@ impl<'a> App<'a> {
|
|||||||
}
|
}
|
||||||
ActiveRadarrBlock::Downloads => {
|
ActiveRadarrBlock::Downloads => {
|
||||||
self
|
self
|
||||||
.dispatch_network_event(RadarrEvent::GetDownloads.into())
|
.dispatch_network_event(RadarrEvent::GetDownloads(500).into())
|
||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
ActiveRadarrBlock::RootFolders => {
|
ActiveRadarrBlock::RootFolders => {
|
||||||
@@ -59,7 +59,7 @@ impl<'a> App<'a> {
|
|||||||
.dispatch_network_event(RadarrEvent::GetMovies.into())
|
.dispatch_network_event(RadarrEvent::GetMovies.into())
|
||||||
.await;
|
.await;
|
||||||
self
|
self
|
||||||
.dispatch_network_event(RadarrEvent::GetDownloads.into())
|
.dispatch_network_event(RadarrEvent::GetDownloads(500).into())
|
||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
ActiveRadarrBlock::Indexers => {
|
ActiveRadarrBlock::Indexers => {
|
||||||
@@ -157,12 +157,9 @@ impl<'a> App<'a> {
|
|||||||
async fn check_for_radarr_prompt_action(&mut self) {
|
async fn check_for_radarr_prompt_action(&mut self) {
|
||||||
if self.data.radarr_data.prompt_confirm {
|
if self.data.radarr_data.prompt_confirm {
|
||||||
self.data.radarr_data.prompt_confirm = false;
|
self.data.radarr_data.prompt_confirm = false;
|
||||||
if let Some(radarr_event) = &self.data.radarr_data.prompt_confirm_action {
|
if let Some(radarr_event) = self.data.radarr_data.prompt_confirm_action.take() {
|
||||||
self
|
self.dispatch_network_event(radarr_event.into()).await;
|
||||||
.dispatch_network_event(radarr_event.clone().into())
|
|
||||||
.await;
|
|
||||||
self.should_refresh = true;
|
self.should_refresh = true;
|
||||||
self.data.radarr_data.prompt_confirm_action = None;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -188,7 +185,7 @@ impl<'a> App<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.tick_count % self.tick_until_poll == 0 {
|
if self.tick_count.is_multiple_of(self.tick_until_poll) {
|
||||||
self.refresh_radarr_metadata().await;
|
self.refresh_radarr_metadata().await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -204,7 +201,7 @@ impl<'a> App<'a> {
|
|||||||
.dispatch_network_event(RadarrEvent::GetRootFolders.into())
|
.dispatch_network_event(RadarrEvent::GetRootFolders.into())
|
||||||
.await;
|
.await;
|
||||||
self
|
self
|
||||||
.dispatch_network_event(RadarrEvent::GetDownloads.into())
|
.dispatch_network_event(RadarrEvent::GetDownloads(500).into())
|
||||||
.await;
|
.await;
|
||||||
self
|
self
|
||||||
.dispatch_network_event(RadarrEvent::GetDiskSpace.into())
|
.dispatch_network_event(RadarrEvent::GetDiskSpace.into())
|
||||||
@@ -231,7 +228,7 @@ impl<'a> App<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async fn extract_movie_id(&self) -> i64 {
|
async fn extract_movie_id(&self) -> i64 {
|
||||||
self.data.radarr_data.movies.current_selection().clone().id
|
self.data.radarr_data.movies.current_selection().id
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn extract_movie_search_query(&self) -> String {
|
async fn extract_movie_search_query(&self) -> String {
|
||||||
@@ -246,12 +243,6 @@ impl<'a> App<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async fn extract_radarr_indexer_id(&self) -> i64 {
|
async fn extract_radarr_indexer_id(&self) -> i64 {
|
||||||
self
|
self.data.radarr_data.indexers.current_selection().id
|
||||||
.data
|
|
||||||
.radarr_data
|
|
||||||
.indexers
|
|
||||||
.current_selection()
|
|
||||||
.clone()
|
|
||||||
.id
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,25 @@
|
|||||||
use crate::app::context_clues::ContextClue;
|
use crate::app::App;
|
||||||
|
use crate::app::context_clues::{
|
||||||
|
BARE_POPUP_CONTEXT_CLUES, CONFIRMATION_PROMPT_CONTEXT_CLUES, ContextClue, ContextClueProvider,
|
||||||
|
};
|
||||||
use crate::app::key_binding::DEFAULT_KEYBINDINGS;
|
use crate::app::key_binding::DEFAULT_KEYBINDINGS;
|
||||||
|
use crate::models::Route;
|
||||||
|
use crate::models::servarr_data::radarr::radarr_data::{
|
||||||
|
ADD_MOVIE_BLOCKS, ActiveRadarrBlock, EDIT_COLLECTION_BLOCKS, EDIT_INDEXER_BLOCKS,
|
||||||
|
EDIT_MOVIE_BLOCKS, INDEXER_SETTINGS_BLOCKS, MOVIE_DETAILS_BLOCKS,
|
||||||
|
};
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
#[path = "radarr_context_clues_tests.rs"]
|
#[path = "radarr_context_clues_tests.rs"]
|
||||||
mod radarr_context_clues_tests;
|
mod radarr_context_clues_tests;
|
||||||
|
|
||||||
pub static LIBRARY_CONTEXT_CLUES: [ContextClue; 10] = [
|
pub static LIBRARY_CONTEXT_CLUES: [ContextClue; 11] = [
|
||||||
(DEFAULT_KEYBINDINGS.add, DEFAULT_KEYBINDINGS.add.desc),
|
(DEFAULT_KEYBINDINGS.add, DEFAULT_KEYBINDINGS.add.desc),
|
||||||
(DEFAULT_KEYBINDINGS.edit, DEFAULT_KEYBINDINGS.edit.desc),
|
(DEFAULT_KEYBINDINGS.edit, DEFAULT_KEYBINDINGS.edit.desc),
|
||||||
|
(
|
||||||
|
DEFAULT_KEYBINDINGS.toggle_monitoring,
|
||||||
|
DEFAULT_KEYBINDINGS.toggle_monitoring.desc,
|
||||||
|
),
|
||||||
(DEFAULT_KEYBINDINGS.sort, DEFAULT_KEYBINDINGS.sort.desc),
|
(DEFAULT_KEYBINDINGS.sort, DEFAULT_KEYBINDINGS.sort.desc),
|
||||||
(DEFAULT_KEYBINDINGS.delete, DEFAULT_KEYBINDINGS.delete.desc),
|
(DEFAULT_KEYBINDINGS.delete, DEFAULT_KEYBINDINGS.delete.desc),
|
||||||
(DEFAULT_KEYBINDINGS.search, DEFAULT_KEYBINDINGS.search.desc),
|
(DEFAULT_KEYBINDINGS.search, DEFAULT_KEYBINDINGS.search.desc),
|
||||||
@@ -49,7 +61,7 @@ pub static MOVIE_DETAILS_CONTEXT_CLUES: [ContextClue; 5] = [
|
|||||||
(DEFAULT_KEYBINDINGS.esc, DEFAULT_KEYBINDINGS.esc.desc),
|
(DEFAULT_KEYBINDINGS.esc, DEFAULT_KEYBINDINGS.esc.desc),
|
||||||
];
|
];
|
||||||
|
|
||||||
pub static MANUAL_MOVIE_SEARCH_CONTEXT_CLUES: [ContextClue; 6] = [
|
pub static MANUAL_MOVIE_SEARCH_CONTEXT_CLUES: [ContextClue; 7] = [
|
||||||
(
|
(
|
||||||
DEFAULT_KEYBINDINGS.refresh,
|
DEFAULT_KEYBINDINGS.refresh,
|
||||||
DEFAULT_KEYBINDINGS.refresh.desc,
|
DEFAULT_KEYBINDINGS.refresh.desc,
|
||||||
@@ -61,12 +73,10 @@ pub static MANUAL_MOVIE_SEARCH_CONTEXT_CLUES: [ContextClue; 6] = [
|
|||||||
DEFAULT_KEYBINDINGS.auto_search,
|
DEFAULT_KEYBINDINGS.auto_search,
|
||||||
DEFAULT_KEYBINDINGS.auto_search.desc,
|
DEFAULT_KEYBINDINGS.auto_search.desc,
|
||||||
),
|
),
|
||||||
|
(DEFAULT_KEYBINDINGS.submit, "details"),
|
||||||
(DEFAULT_KEYBINDINGS.esc, DEFAULT_KEYBINDINGS.esc.desc),
|
(DEFAULT_KEYBINDINGS.esc, DEFAULT_KEYBINDINGS.esc.desc),
|
||||||
];
|
];
|
||||||
|
|
||||||
pub static MANUAL_MOVIE_SEARCH_CONTEXTUAL_CONTEXT_CLUES: [ContextClue; 1] =
|
|
||||||
[(DEFAULT_KEYBINDINGS.submit, "details")];
|
|
||||||
|
|
||||||
pub static ADD_MOVIE_SEARCH_RESULTS_CONTEXT_CLUES: [ContextClue; 2] = [
|
pub static ADD_MOVIE_SEARCH_RESULTS_CONTEXT_CLUES: [ContextClue; 2] = [
|
||||||
(DEFAULT_KEYBINDINGS.submit, "details"),
|
(DEFAULT_KEYBINDINGS.submit, "details"),
|
||||||
(DEFAULT_KEYBINDINGS.esc, "edit search"),
|
(DEFAULT_KEYBINDINGS.esc, "edit search"),
|
||||||
@@ -82,3 +92,54 @@ pub static COLLECTION_DETAILS_CONTEXT_CLUES: [ContextClue; 3] = [
|
|||||||
(DEFAULT_KEYBINDINGS.edit, "edit collection"),
|
(DEFAULT_KEYBINDINGS.edit, "edit collection"),
|
||||||
(DEFAULT_KEYBINDINGS.esc, DEFAULT_KEYBINDINGS.esc.desc),
|
(DEFAULT_KEYBINDINGS.esc, DEFAULT_KEYBINDINGS.esc.desc),
|
||||||
];
|
];
|
||||||
|
|
||||||
|
pub(in crate::app) struct RadarrContextClueProvider;
|
||||||
|
|
||||||
|
impl ContextClueProvider for RadarrContextClueProvider {
|
||||||
|
fn get_context_clues(app: &mut App<'_>) -> Option<&'static [ContextClue]> {
|
||||||
|
let Route::Radarr(active_radarr_block, context_option) = app.get_current_route() else {
|
||||||
|
panic!("RadarrContextClueProvider::get_context_clues called with non-Radarr route");
|
||||||
|
};
|
||||||
|
match active_radarr_block {
|
||||||
|
_ if MOVIE_DETAILS_BLOCKS.contains(&active_radarr_block) => app
|
||||||
|
.data
|
||||||
|
.radarr_data
|
||||||
|
.movie_info_tabs
|
||||||
|
.get_active_route_contextual_help(),
|
||||||
|
ActiveRadarrBlock::TestAllIndexers
|
||||||
|
| ActiveRadarrBlock::AddMovieSearchInput
|
||||||
|
| ActiveRadarrBlock::AddMovieEmptySearchResults
|
||||||
|
| ActiveRadarrBlock::SystemLogs
|
||||||
|
| ActiveRadarrBlock::SystemUpdates => Some(&BARE_POPUP_CONTEXT_CLUES),
|
||||||
|
_ if context_option.unwrap_or(active_radarr_block)
|
||||||
|
== ActiveRadarrBlock::ViewMovieOverview =>
|
||||||
|
{
|
||||||
|
Some(&BARE_POPUP_CONTEXT_CLUES)
|
||||||
|
}
|
||||||
|
ActiveRadarrBlock::SystemTasks => Some(&SYSTEM_TASKS_CONTEXT_CLUES),
|
||||||
|
_ if EDIT_COLLECTION_BLOCKS.contains(&active_radarr_block)
|
||||||
|
|| EDIT_INDEXER_BLOCKS.contains(&active_radarr_block)
|
||||||
|
|| INDEXER_SETTINGS_BLOCKS.contains(&active_radarr_block)
|
||||||
|
|| EDIT_MOVIE_BLOCKS.contains(&active_radarr_block) =>
|
||||||
|
{
|
||||||
|
Some(&CONFIRMATION_PROMPT_CONTEXT_CLUES)
|
||||||
|
}
|
||||||
|
ActiveRadarrBlock::AddMoviePrompt
|
||||||
|
| ActiveRadarrBlock::AddMovieSelectMonitor
|
||||||
|
| ActiveRadarrBlock::AddMovieSelectMinimumAvailability
|
||||||
|
| ActiveRadarrBlock::AddMovieSelectQualityProfile
|
||||||
|
| ActiveRadarrBlock::AddMovieSelectRootFolder
|
||||||
|
| ActiveRadarrBlock::AddMovieTagsInput
|
||||||
|
| ActiveRadarrBlock::SystemTaskStartConfirmPrompt => Some(&CONFIRMATION_PROMPT_CONTEXT_CLUES),
|
||||||
|
_ if ADD_MOVIE_BLOCKS.contains(&active_radarr_block) => {
|
||||||
|
Some(&ADD_MOVIE_SEARCH_RESULTS_CONTEXT_CLUES)
|
||||||
|
}
|
||||||
|
ActiveRadarrBlock::CollectionDetails => Some(&COLLECTION_DETAILS_CONTEXT_CLUES),
|
||||||
|
_ => app
|
||||||
|
.data
|
||||||
|
.radarr_data
|
||||||
|
.main_tabs
|
||||||
|
.get_active_route_contextual_help(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,114 +1,118 @@
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use pretty_assertions::{assert_eq, assert_str_eq};
|
use crate::app::App;
|
||||||
|
use crate::app::context_clues::{
|
||||||
|
BARE_POPUP_CONTEXT_CLUES, BLOCKLIST_CONTEXT_CLUES, CONFIRMATION_PROMPT_CONTEXT_CLUES,
|
||||||
|
ContextClue, ContextClueProvider, DOWNLOADS_CONTEXT_CLUES, INDEXERS_CONTEXT_CLUES,
|
||||||
|
ROOT_FOLDERS_CONTEXT_CLUES, SYSTEM_CONTEXT_CLUES,
|
||||||
|
};
|
||||||
use crate::app::key_binding::DEFAULT_KEYBINDINGS;
|
use crate::app::key_binding::DEFAULT_KEYBINDINGS;
|
||||||
use crate::app::radarr::radarr_context_clues::{
|
use crate::app::radarr::radarr_context_clues::{
|
||||||
ADD_MOVIE_SEARCH_RESULTS_CONTEXT_CLUES, COLLECTIONS_CONTEXT_CLUES,
|
ADD_MOVIE_SEARCH_RESULTS_CONTEXT_CLUES, COLLECTION_DETAILS_CONTEXT_CLUES,
|
||||||
COLLECTION_DETAILS_CONTEXT_CLUES, LIBRARY_CONTEXT_CLUES,
|
COLLECTIONS_CONTEXT_CLUES, LIBRARY_CONTEXT_CLUES, MANUAL_MOVIE_SEARCH_CONTEXT_CLUES,
|
||||||
MANUAL_MOVIE_SEARCH_CONTEXTUAL_CONTEXT_CLUES, MANUAL_MOVIE_SEARCH_CONTEXT_CLUES,
|
MOVIE_DETAILS_CONTEXT_CLUES, RadarrContextClueProvider, SYSTEM_TASKS_CONTEXT_CLUES,
|
||||||
MOVIE_DETAILS_CONTEXT_CLUES, SYSTEM_TASKS_CONTEXT_CLUES,
|
|
||||||
};
|
};
|
||||||
|
use crate::models::servarr_data::radarr::radarr_data::{ActiveRadarrBlock, RadarrData};
|
||||||
|
use crate::models::servarr_data::sonarr::sonarr_data::ActiveSonarrBlock;
|
||||||
|
use pretty_assertions::assert_eq;
|
||||||
|
use rstest::rstest;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_library_context_clues() {
|
fn test_library_context_clues() {
|
||||||
let mut library_context_clues_iter = LIBRARY_CONTEXT_CLUES.iter();
|
let mut library_context_clues_iter = LIBRARY_CONTEXT_CLUES.iter();
|
||||||
|
|
||||||
let (key_binding, description) = library_context_clues_iter.next().unwrap();
|
assert_some_eq_x!(
|
||||||
|
library_context_clues_iter.next(),
|
||||||
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.add);
|
&(DEFAULT_KEYBINDINGS.add, DEFAULT_KEYBINDINGS.add.desc)
|
||||||
assert_str_eq!(*description, DEFAULT_KEYBINDINGS.add.desc);
|
);
|
||||||
|
assert_some_eq_x!(
|
||||||
let (key_binding, description) = library_context_clues_iter.next().unwrap();
|
library_context_clues_iter.next(),
|
||||||
|
&(DEFAULT_KEYBINDINGS.edit, DEFAULT_KEYBINDINGS.edit.desc)
|
||||||
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.edit);
|
);
|
||||||
assert_str_eq!(*description, DEFAULT_KEYBINDINGS.edit.desc);
|
assert_some_eq_x!(
|
||||||
|
library_context_clues_iter.next(),
|
||||||
let (key_binding, description) = library_context_clues_iter.next().unwrap();
|
&(
|
||||||
|
DEFAULT_KEYBINDINGS.toggle_monitoring,
|
||||||
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.sort);
|
DEFAULT_KEYBINDINGS.toggle_monitoring.desc
|
||||||
assert_str_eq!(*description, DEFAULT_KEYBINDINGS.sort.desc);
|
)
|
||||||
|
);
|
||||||
let (key_binding, description) = library_context_clues_iter.next().unwrap();
|
assert_some_eq_x!(
|
||||||
|
library_context_clues_iter.next(),
|
||||||
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.delete);
|
&(DEFAULT_KEYBINDINGS.sort, DEFAULT_KEYBINDINGS.sort.desc)
|
||||||
assert_str_eq!(*description, DEFAULT_KEYBINDINGS.delete.desc);
|
);
|
||||||
|
assert_some_eq_x!(
|
||||||
let (key_binding, description) = library_context_clues_iter.next().unwrap();
|
library_context_clues_iter.next(),
|
||||||
|
&(DEFAULT_KEYBINDINGS.delete, DEFAULT_KEYBINDINGS.delete.desc)
|
||||||
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.search);
|
);
|
||||||
assert_str_eq!(*description, DEFAULT_KEYBINDINGS.search.desc);
|
assert_some_eq_x!(
|
||||||
|
library_context_clues_iter.next(),
|
||||||
let (key_binding, description) = library_context_clues_iter.next().unwrap();
|
&(DEFAULT_KEYBINDINGS.search, DEFAULT_KEYBINDINGS.search.desc)
|
||||||
|
);
|
||||||
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.filter);
|
assert_some_eq_x!(
|
||||||
assert_str_eq!(*description, DEFAULT_KEYBINDINGS.filter.desc);
|
library_context_clues_iter.next(),
|
||||||
|
&(DEFAULT_KEYBINDINGS.filter, DEFAULT_KEYBINDINGS.filter.desc)
|
||||||
let (key_binding, description) = library_context_clues_iter.next().unwrap();
|
);
|
||||||
|
assert_some_eq_x!(
|
||||||
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.refresh);
|
library_context_clues_iter.next(),
|
||||||
assert_str_eq!(*description, DEFAULT_KEYBINDINGS.refresh.desc);
|
&(
|
||||||
|
DEFAULT_KEYBINDINGS.refresh,
|
||||||
let (key_binding, description) = library_context_clues_iter.next().unwrap();
|
DEFAULT_KEYBINDINGS.refresh.desc
|
||||||
|
)
|
||||||
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.update);
|
);
|
||||||
assert_str_eq!(*description, "update all");
|
assert_some_eq_x!(
|
||||||
|
library_context_clues_iter.next(),
|
||||||
let (key_binding, description) = library_context_clues_iter.next().unwrap();
|
&(DEFAULT_KEYBINDINGS.update, "update all")
|
||||||
|
);
|
||||||
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.submit);
|
assert_some_eq_x!(
|
||||||
assert_str_eq!(*description, "details");
|
library_context_clues_iter.next(),
|
||||||
|
&(DEFAULT_KEYBINDINGS.submit, "details")
|
||||||
let (key_binding, description) = library_context_clues_iter.next().unwrap();
|
);
|
||||||
|
assert_some_eq_x!(
|
||||||
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.esc);
|
library_context_clues_iter.next(),
|
||||||
assert_str_eq!(*description, "cancel filter");
|
&(DEFAULT_KEYBINDINGS.esc, "cancel filter")
|
||||||
assert_eq!(library_context_clues_iter.next(), None);
|
);
|
||||||
|
assert_none!(library_context_clues_iter.next());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_collections_context_clues() {
|
fn test_collections_context_clues() {
|
||||||
let mut collections_context_clues = COLLECTIONS_CONTEXT_CLUES.iter();
|
let mut collections_context_clues = COLLECTIONS_CONTEXT_CLUES.iter();
|
||||||
|
|
||||||
let (key_binding, description) = collections_context_clues.next().unwrap();
|
assert_some_eq_x!(
|
||||||
|
collections_context_clues.next(),
|
||||||
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.search);
|
&(DEFAULT_KEYBINDINGS.search, DEFAULT_KEYBINDINGS.search.desc)
|
||||||
assert_str_eq!(*description, DEFAULT_KEYBINDINGS.search.desc);
|
);
|
||||||
|
assert_some_eq_x!(
|
||||||
let (key_binding, description) = collections_context_clues.next().unwrap();
|
collections_context_clues.next(),
|
||||||
|
&(DEFAULT_KEYBINDINGS.edit, DEFAULT_KEYBINDINGS.edit.desc)
|
||||||
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.edit);
|
);
|
||||||
assert_str_eq!(*description, DEFAULT_KEYBINDINGS.edit.desc);
|
assert_some_eq_x!(
|
||||||
|
collections_context_clues.next(),
|
||||||
let (key_binding, description) = collections_context_clues.next().unwrap();
|
&(DEFAULT_KEYBINDINGS.sort, DEFAULT_KEYBINDINGS.sort.desc)
|
||||||
|
);
|
||||||
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.sort);
|
assert_some_eq_x!(
|
||||||
assert_str_eq!(*description, DEFAULT_KEYBINDINGS.sort.desc);
|
collections_context_clues.next(),
|
||||||
|
&(DEFAULT_KEYBINDINGS.filter, DEFAULT_KEYBINDINGS.filter.desc)
|
||||||
let (key_binding, description) = collections_context_clues.next().unwrap();
|
);
|
||||||
|
assert_some_eq_x!(
|
||||||
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.filter);
|
collections_context_clues.next(),
|
||||||
assert_str_eq!(*description, DEFAULT_KEYBINDINGS.filter.desc);
|
&(
|
||||||
|
DEFAULT_KEYBINDINGS.refresh,
|
||||||
let (key_binding, description) = collections_context_clues.next().unwrap();
|
DEFAULT_KEYBINDINGS.refresh.desc
|
||||||
|
)
|
||||||
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.refresh);
|
);
|
||||||
assert_str_eq!(*description, DEFAULT_KEYBINDINGS.refresh.desc);
|
assert_some_eq_x!(
|
||||||
|
collections_context_clues.next(),
|
||||||
let (key_binding, description) = collections_context_clues.next().unwrap();
|
&(DEFAULT_KEYBINDINGS.update, "update all")
|
||||||
|
);
|
||||||
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.update);
|
assert_some_eq_x!(
|
||||||
assert_str_eq!(*description, "update all");
|
collections_context_clues.next(),
|
||||||
|
&(DEFAULT_KEYBINDINGS.submit, "details")
|
||||||
let (key_binding, description) = collections_context_clues.next().unwrap();
|
);
|
||||||
|
assert_some_eq_x!(
|
||||||
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.submit);
|
collections_context_clues.next(),
|
||||||
assert_str_eq!(*description, "details");
|
&(DEFAULT_KEYBINDINGS.esc, "cancel filter")
|
||||||
|
);
|
||||||
let (key_binding, description) = collections_context_clues.next().unwrap();
|
|
||||||
|
|
||||||
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.esc);
|
|
||||||
assert_str_eq!(*description, "cancel filter");
|
|
||||||
assert_eq!(collections_context_clues.next(), None);
|
assert_eq!(collections_context_clues.next(), None);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -116,30 +120,32 @@ mod tests {
|
|||||||
fn test_movie_details_context_clues() {
|
fn test_movie_details_context_clues() {
|
||||||
let mut movie_details_context_clues_iter = MOVIE_DETAILS_CONTEXT_CLUES.iter();
|
let mut movie_details_context_clues_iter = MOVIE_DETAILS_CONTEXT_CLUES.iter();
|
||||||
|
|
||||||
let (key_binding, description) = movie_details_context_clues_iter.next().unwrap();
|
assert_some_eq_x!(
|
||||||
|
movie_details_context_clues_iter.next(),
|
||||||
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.refresh);
|
&(
|
||||||
assert_str_eq!(*description, DEFAULT_KEYBINDINGS.refresh.desc);
|
DEFAULT_KEYBINDINGS.refresh,
|
||||||
|
DEFAULT_KEYBINDINGS.refresh.desc
|
||||||
let (key_binding, description) = movie_details_context_clues_iter.next().unwrap();
|
)
|
||||||
|
);
|
||||||
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.update);
|
assert_some_eq_x!(
|
||||||
assert_str_eq!(*description, DEFAULT_KEYBINDINGS.update.desc);
|
movie_details_context_clues_iter.next(),
|
||||||
|
&(DEFAULT_KEYBINDINGS.update, DEFAULT_KEYBINDINGS.update.desc)
|
||||||
let (key_binding, description) = movie_details_context_clues_iter.next().unwrap();
|
);
|
||||||
|
assert_some_eq_x!(
|
||||||
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.edit);
|
movie_details_context_clues_iter.next(),
|
||||||
assert_str_eq!(*description, DEFAULT_KEYBINDINGS.edit.desc);
|
&(DEFAULT_KEYBINDINGS.edit, DEFAULT_KEYBINDINGS.edit.desc)
|
||||||
|
);
|
||||||
let (key_binding, description) = movie_details_context_clues_iter.next().unwrap();
|
assert_some_eq_x!(
|
||||||
|
movie_details_context_clues_iter.next(),
|
||||||
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.auto_search);
|
&(
|
||||||
assert_str_eq!(*description, DEFAULT_KEYBINDINGS.auto_search.desc);
|
DEFAULT_KEYBINDINGS.auto_search,
|
||||||
|
DEFAULT_KEYBINDINGS.auto_search.desc
|
||||||
let (key_binding, description) = movie_details_context_clues_iter.next().unwrap();
|
)
|
||||||
|
);
|
||||||
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.esc);
|
assert_some_eq_x!(
|
||||||
assert_str_eq!(*description, DEFAULT_KEYBINDINGS.esc.desc);
|
movie_details_context_clues_iter.next(),
|
||||||
|
&(DEFAULT_KEYBINDINGS.esc, DEFAULT_KEYBINDINGS.esc.desc)
|
||||||
|
);
|
||||||
assert_eq!(movie_details_context_clues_iter.next(), None);
|
assert_eq!(movie_details_context_clues_iter.next(), None);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -147,53 +153,41 @@ mod tests {
|
|||||||
fn test_manual_movie_search_context_clues() {
|
fn test_manual_movie_search_context_clues() {
|
||||||
let mut manual_movie_search_context_clues_iter = MANUAL_MOVIE_SEARCH_CONTEXT_CLUES.iter();
|
let mut manual_movie_search_context_clues_iter = MANUAL_MOVIE_SEARCH_CONTEXT_CLUES.iter();
|
||||||
|
|
||||||
let (key_binding, description) = manual_movie_search_context_clues_iter.next().unwrap();
|
assert_some_eq_x!(
|
||||||
|
manual_movie_search_context_clues_iter.next(),
|
||||||
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.refresh);
|
&(
|
||||||
assert_str_eq!(*description, DEFAULT_KEYBINDINGS.refresh.desc);
|
DEFAULT_KEYBINDINGS.refresh,
|
||||||
|
DEFAULT_KEYBINDINGS.refresh.desc
|
||||||
let (key_binding, description) = manual_movie_search_context_clues_iter.next().unwrap();
|
)
|
||||||
|
|
||||||
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.update);
|
|
||||||
assert_str_eq!(*description, DEFAULT_KEYBINDINGS.update.desc);
|
|
||||||
|
|
||||||
let (key_binding, description) = manual_movie_search_context_clues_iter.next().unwrap();
|
|
||||||
|
|
||||||
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.edit);
|
|
||||||
assert_str_eq!(*description, DEFAULT_KEYBINDINGS.edit.desc);
|
|
||||||
|
|
||||||
let (key_binding, description) = manual_movie_search_context_clues_iter.next().unwrap();
|
|
||||||
|
|
||||||
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.sort);
|
|
||||||
assert_str_eq!(*description, DEFAULT_KEYBINDINGS.sort.desc);
|
|
||||||
|
|
||||||
let (key_binding, description) = manual_movie_search_context_clues_iter.next().unwrap();
|
|
||||||
|
|
||||||
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.auto_search);
|
|
||||||
assert_str_eq!(*description, DEFAULT_KEYBINDINGS.auto_search.desc);
|
|
||||||
|
|
||||||
let (key_binding, description) = manual_movie_search_context_clues_iter.next().unwrap();
|
|
||||||
|
|
||||||
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.esc);
|
|
||||||
assert_str_eq!(*description, DEFAULT_KEYBINDINGS.esc.desc);
|
|
||||||
assert_eq!(manual_movie_search_context_clues_iter.next(), None);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_manual_movie_search_contextual_context_clues() {
|
|
||||||
let mut manual_movie_search_contextual_context_clues_iter =
|
|
||||||
MANUAL_MOVIE_SEARCH_CONTEXTUAL_CONTEXT_CLUES.iter();
|
|
||||||
|
|
||||||
let (key_binding, description) = manual_movie_search_contextual_context_clues_iter
|
|
||||||
.next()
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.submit);
|
|
||||||
assert_str_eq!(*description, "details");
|
|
||||||
assert_eq!(
|
|
||||||
manual_movie_search_contextual_context_clues_iter.next(),
|
|
||||||
None
|
|
||||||
);
|
);
|
||||||
|
assert_some_eq_x!(
|
||||||
|
manual_movie_search_context_clues_iter.next(),
|
||||||
|
&(DEFAULT_KEYBINDINGS.update, DEFAULT_KEYBINDINGS.update.desc)
|
||||||
|
);
|
||||||
|
assert_some_eq_x!(
|
||||||
|
manual_movie_search_context_clues_iter.next(),
|
||||||
|
&(DEFAULT_KEYBINDINGS.edit, DEFAULT_KEYBINDINGS.edit.desc)
|
||||||
|
);
|
||||||
|
assert_some_eq_x!(
|
||||||
|
manual_movie_search_context_clues_iter.next(),
|
||||||
|
&(DEFAULT_KEYBINDINGS.sort, DEFAULT_KEYBINDINGS.sort.desc)
|
||||||
|
);
|
||||||
|
assert_some_eq_x!(
|
||||||
|
manual_movie_search_context_clues_iter.next(),
|
||||||
|
&(
|
||||||
|
DEFAULT_KEYBINDINGS.auto_search,
|
||||||
|
DEFAULT_KEYBINDINGS.auto_search.desc
|
||||||
|
)
|
||||||
|
);
|
||||||
|
assert_some_eq_x!(
|
||||||
|
manual_movie_search_context_clues_iter.next(),
|
||||||
|
&(DEFAULT_KEYBINDINGS.submit, "details")
|
||||||
|
);
|
||||||
|
assert_some_eq_x!(
|
||||||
|
manual_movie_search_context_clues_iter.next(),
|
||||||
|
&(DEFAULT_KEYBINDINGS.esc, DEFAULT_KEYBINDINGS.esc.desc)
|
||||||
|
);
|
||||||
|
assert_eq!(manual_movie_search_context_clues_iter.next(), None);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -201,15 +195,14 @@ mod tests {
|
|||||||
let mut add_movie_search_results_context_clues_iter =
|
let mut add_movie_search_results_context_clues_iter =
|
||||||
ADD_MOVIE_SEARCH_RESULTS_CONTEXT_CLUES.iter();
|
ADD_MOVIE_SEARCH_RESULTS_CONTEXT_CLUES.iter();
|
||||||
|
|
||||||
let (key_binding, description) = add_movie_search_results_context_clues_iter.next().unwrap();
|
assert_some_eq_x!(
|
||||||
|
add_movie_search_results_context_clues_iter.next(),
|
||||||
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.submit);
|
&(DEFAULT_KEYBINDINGS.submit, "details")
|
||||||
assert_str_eq!(*description, "details");
|
);
|
||||||
|
assert_some_eq_x!(
|
||||||
let (key_binding, description) = add_movie_search_results_context_clues_iter.next().unwrap();
|
add_movie_search_results_context_clues_iter.next(),
|
||||||
|
&(DEFAULT_KEYBINDINGS.esc, "edit search")
|
||||||
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.esc);
|
);
|
||||||
assert_str_eq!(*description, "edit search");
|
|
||||||
assert_eq!(add_movie_search_results_context_clues_iter.next(), None);
|
assert_eq!(add_movie_search_results_context_clues_iter.next(), None);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -217,15 +210,14 @@ mod tests {
|
|||||||
fn test_system_tasks_context_clues() {
|
fn test_system_tasks_context_clues() {
|
||||||
let mut system_tasks_context_clues_iter = SYSTEM_TASKS_CONTEXT_CLUES.iter();
|
let mut system_tasks_context_clues_iter = SYSTEM_TASKS_CONTEXT_CLUES.iter();
|
||||||
|
|
||||||
let (key_binding, description) = system_tasks_context_clues_iter.next().unwrap();
|
assert_some_eq_x!(
|
||||||
|
system_tasks_context_clues_iter.next(),
|
||||||
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.submit);
|
&(DEFAULT_KEYBINDINGS.submit, "start task")
|
||||||
assert_str_eq!(*description, "start task");
|
);
|
||||||
|
assert_some_eq_x!(
|
||||||
let (key_binding, description) = system_tasks_context_clues_iter.next().unwrap();
|
system_tasks_context_clues_iter.next(),
|
||||||
|
&(DEFAULT_KEYBINDINGS.esc, DEFAULT_KEYBINDINGS.esc.desc)
|
||||||
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.esc);
|
);
|
||||||
assert_str_eq!(*description, DEFAULT_KEYBINDINGS.esc.desc);
|
|
||||||
assert_eq!(system_tasks_context_clues_iter.next(), None);
|
assert_eq!(system_tasks_context_clues_iter.next(), None);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -233,20 +225,255 @@ mod tests {
|
|||||||
fn test_collection_details_context_clues() {
|
fn test_collection_details_context_clues() {
|
||||||
let mut collection_details_context_clues_iter = COLLECTION_DETAILS_CONTEXT_CLUES.iter();
|
let mut collection_details_context_clues_iter = COLLECTION_DETAILS_CONTEXT_CLUES.iter();
|
||||||
|
|
||||||
let (key_binding, description) = collection_details_context_clues_iter.next().unwrap();
|
assert_some_eq_x!(
|
||||||
|
collection_details_context_clues_iter.next(),
|
||||||
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.submit);
|
&(DEFAULT_KEYBINDINGS.submit, "show overview/add movie")
|
||||||
assert_str_eq!(*description, "show overview/add movie");
|
);
|
||||||
|
assert_some_eq_x!(
|
||||||
let (key_binding, description) = collection_details_context_clues_iter.next().unwrap();
|
collection_details_context_clues_iter.next(),
|
||||||
|
&(DEFAULT_KEYBINDINGS.edit, "edit collection")
|
||||||
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.edit);
|
);
|
||||||
assert_str_eq!(*description, "edit collection");
|
assert_some_eq_x!(
|
||||||
|
collection_details_context_clues_iter.next(),
|
||||||
let (key_binding, description) = collection_details_context_clues_iter.next().unwrap();
|
&(DEFAULT_KEYBINDINGS.esc, DEFAULT_KEYBINDINGS.esc.desc)
|
||||||
|
);
|
||||||
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.esc);
|
|
||||||
assert_str_eq!(*description, DEFAULT_KEYBINDINGS.esc.desc);
|
|
||||||
assert_eq!(collection_details_context_clues_iter.next(), None);
|
assert_eq!(collection_details_context_clues_iter.next(), None);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[should_panic(
|
||||||
|
expected = "RadarrContextClueProvider::get_context_clues called with non-Radarr route"
|
||||||
|
)]
|
||||||
|
fn test_radarr_context_clue_provider_get_context_clues_non_radarr_route() {
|
||||||
|
let mut app = App::test_default();
|
||||||
|
app.push_navigation_stack(ActiveSonarrBlock::default().into());
|
||||||
|
|
||||||
|
// This should panic because the route is not a Radarr route
|
||||||
|
RadarrContextClueProvider::get_context_clues(&mut app);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
#[case(ActiveRadarrBlock::TestAllIndexers, None)]
|
||||||
|
#[case(ActiveRadarrBlock::AddMovieSearchInput, None)]
|
||||||
|
#[case(ActiveRadarrBlock::AddMovieEmptySearchResults, None)]
|
||||||
|
#[case(ActiveRadarrBlock::SystemLogs, None)]
|
||||||
|
#[case(ActiveRadarrBlock::SystemUpdates, None)]
|
||||||
|
#[case(ActiveRadarrBlock::ViewMovieOverview, None)]
|
||||||
|
#[case(
|
||||||
|
ActiveRadarrBlock::CollectionDetails,
|
||||||
|
Some(ActiveRadarrBlock::ViewMovieOverview)
|
||||||
|
)]
|
||||||
|
fn test_radarr_context_clue_provider_bare_popup_context_clues(
|
||||||
|
#[case] active_radarr_block: ActiveRadarrBlock,
|
||||||
|
#[case] context_option: Option<ActiveRadarrBlock>,
|
||||||
|
) {
|
||||||
|
let mut app = App::test_default();
|
||||||
|
app.push_navigation_stack((active_radarr_block, context_option).into());
|
||||||
|
|
||||||
|
let context_clues = RadarrContextClueProvider::get_context_clues(&mut app);
|
||||||
|
|
||||||
|
assert_some_eq_x!(context_clues, &BARE_POPUP_CONTEXT_CLUES);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
#[case(0, ActiveRadarrBlock::MovieDetails, &MOVIE_DETAILS_CONTEXT_CLUES)]
|
||||||
|
#[case(1, ActiveRadarrBlock::MovieHistory, &MOVIE_DETAILS_CONTEXT_CLUES)]
|
||||||
|
#[case(2, ActiveRadarrBlock::FileInfo, &MOVIE_DETAILS_CONTEXT_CLUES)]
|
||||||
|
#[case(3, ActiveRadarrBlock::Cast, &MOVIE_DETAILS_CONTEXT_CLUES)]
|
||||||
|
#[case(4, ActiveRadarrBlock::Crew, &MOVIE_DETAILS_CONTEXT_CLUES)]
|
||||||
|
#[case(5, ActiveRadarrBlock::ManualSearch, &MANUAL_MOVIE_SEARCH_CONTEXT_CLUES)]
|
||||||
|
fn test_radarr_context_clue_provider_movie_details_block_context_clues(
|
||||||
|
#[case] index: usize,
|
||||||
|
#[case] active_radarr_block: ActiveRadarrBlock,
|
||||||
|
#[case] expected_context_clues: &[ContextClue],
|
||||||
|
) {
|
||||||
|
let mut app = App::test_default();
|
||||||
|
app.data.radarr_data = RadarrData::default();
|
||||||
|
app.data.radarr_data.movie_info_tabs.set_index(index);
|
||||||
|
app.push_navigation_stack(active_radarr_block.into());
|
||||||
|
|
||||||
|
let context_clues = RadarrContextClueProvider::get_context_clues(&mut app);
|
||||||
|
|
||||||
|
assert_some_eq_x!(context_clues, expected_context_clues);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
fn test_radarr_context_clue_provider_confirmation_prompt_context_clues(
|
||||||
|
#[values(
|
||||||
|
ActiveRadarrBlock::AddMoviePrompt,
|
||||||
|
ActiveRadarrBlock::AddMovieSelectMonitor,
|
||||||
|
ActiveRadarrBlock::AddMovieSelectMinimumAvailability,
|
||||||
|
ActiveRadarrBlock::AddMovieSelectQualityProfile,
|
||||||
|
ActiveRadarrBlock::AddMovieSelectRootFolder,
|
||||||
|
ActiveRadarrBlock::AddMovieTagsInput,
|
||||||
|
ActiveRadarrBlock::SystemTaskStartConfirmPrompt
|
||||||
|
)]
|
||||||
|
active_radarr_block: ActiveRadarrBlock,
|
||||||
|
) {
|
||||||
|
let mut app = App::test_default();
|
||||||
|
app.data.radarr_data = RadarrData::default();
|
||||||
|
app.push_navigation_stack(active_radarr_block.into());
|
||||||
|
|
||||||
|
let context_clues = RadarrContextClueProvider::get_context_clues(&mut app);
|
||||||
|
|
||||||
|
assert_some_eq_x!(context_clues, &CONFIRMATION_PROMPT_CONTEXT_CLUES);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
fn test_radarr_context_clue_provider_confirmation_prompt_context_clues_edit_collection_blocks(
|
||||||
|
#[values(
|
||||||
|
ActiveRadarrBlock::EditCollectionPrompt,
|
||||||
|
ActiveRadarrBlock::EditCollectionConfirmPrompt,
|
||||||
|
ActiveRadarrBlock::EditCollectionRootFolderPathInput,
|
||||||
|
ActiveRadarrBlock::EditCollectionSelectMinimumAvailability,
|
||||||
|
ActiveRadarrBlock::EditCollectionSelectQualityProfile,
|
||||||
|
ActiveRadarrBlock::EditCollectionToggleSearchOnAdd,
|
||||||
|
ActiveRadarrBlock::EditCollectionToggleMonitored
|
||||||
|
)]
|
||||||
|
active_radarr_block: ActiveRadarrBlock,
|
||||||
|
) {
|
||||||
|
let mut app = App::test_default();
|
||||||
|
app.data.radarr_data = RadarrData::default();
|
||||||
|
app.push_navigation_stack(active_radarr_block.into());
|
||||||
|
|
||||||
|
let context_clues = RadarrContextClueProvider::get_context_clues(&mut app);
|
||||||
|
|
||||||
|
assert_some_eq_x!(context_clues, &CONFIRMATION_PROMPT_CONTEXT_CLUES);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
fn test_radarr_context_clue_provider_confirmation_prompt_context_clues_edit_indexer_blocks(
|
||||||
|
#[values(
|
||||||
|
ActiveRadarrBlock::EditIndexerPrompt,
|
||||||
|
ActiveRadarrBlock::EditIndexerConfirmPrompt,
|
||||||
|
ActiveRadarrBlock::EditIndexerApiKeyInput,
|
||||||
|
ActiveRadarrBlock::EditIndexerNameInput,
|
||||||
|
ActiveRadarrBlock::EditIndexerSeedRatioInput,
|
||||||
|
ActiveRadarrBlock::EditIndexerToggleEnableRss,
|
||||||
|
ActiveRadarrBlock::EditIndexerToggleEnableAutomaticSearch,
|
||||||
|
ActiveRadarrBlock::EditIndexerToggleEnableInteractiveSearch,
|
||||||
|
ActiveRadarrBlock::EditIndexerPriorityInput,
|
||||||
|
ActiveRadarrBlock::EditIndexerUrlInput,
|
||||||
|
ActiveRadarrBlock::EditIndexerTagsInput
|
||||||
|
)]
|
||||||
|
active_radarr_block: ActiveRadarrBlock,
|
||||||
|
) {
|
||||||
|
let mut app = App::test_default();
|
||||||
|
app.data.radarr_data = RadarrData::default();
|
||||||
|
app.push_navigation_stack(active_radarr_block.into());
|
||||||
|
|
||||||
|
let context_clues = RadarrContextClueProvider::get_context_clues(&mut app);
|
||||||
|
|
||||||
|
assert_some_eq_x!(context_clues, &CONFIRMATION_PROMPT_CONTEXT_CLUES);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
fn test_radarr_context_clue_provider_confirmation_prompt_context_clues_indexer_settings_blocks(
|
||||||
|
#[values(
|
||||||
|
ActiveRadarrBlock::AllIndexerSettingsPrompt,
|
||||||
|
ActiveRadarrBlock::IndexerSettingsAvailabilityDelayInput,
|
||||||
|
ActiveRadarrBlock::IndexerSettingsConfirmPrompt,
|
||||||
|
ActiveRadarrBlock::IndexerSettingsMaximumSizeInput,
|
||||||
|
ActiveRadarrBlock::IndexerSettingsMinimumAgeInput,
|
||||||
|
ActiveRadarrBlock::IndexerSettingsRetentionInput,
|
||||||
|
ActiveRadarrBlock::IndexerSettingsRssSyncIntervalInput,
|
||||||
|
ActiveRadarrBlock::IndexerSettingsToggleAllowHardcodedSubs,
|
||||||
|
ActiveRadarrBlock::IndexerSettingsTogglePreferIndexerFlags,
|
||||||
|
ActiveRadarrBlock::IndexerSettingsWhitelistedSubtitleTagsInput
|
||||||
|
)]
|
||||||
|
active_radarr_block: ActiveRadarrBlock,
|
||||||
|
) {
|
||||||
|
let mut app = App::test_default();
|
||||||
|
app.data.radarr_data = RadarrData::default();
|
||||||
|
app.push_navigation_stack(active_radarr_block.into());
|
||||||
|
|
||||||
|
let context_clues = RadarrContextClueProvider::get_context_clues(&mut app);
|
||||||
|
|
||||||
|
assert_some_eq_x!(context_clues, &CONFIRMATION_PROMPT_CONTEXT_CLUES);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
fn test_radarr_context_clue_provider_confirmation_prompt_context_clues_edit_movie_blocks(
|
||||||
|
#[values(
|
||||||
|
ActiveRadarrBlock::EditMoviePrompt,
|
||||||
|
ActiveRadarrBlock::EditMovieConfirmPrompt,
|
||||||
|
ActiveRadarrBlock::EditMoviePathInput,
|
||||||
|
ActiveRadarrBlock::EditMovieSelectMinimumAvailability,
|
||||||
|
ActiveRadarrBlock::EditMovieSelectQualityProfile,
|
||||||
|
ActiveRadarrBlock::EditMovieTagsInput,
|
||||||
|
ActiveRadarrBlock::EditMovieToggleMonitored
|
||||||
|
)]
|
||||||
|
active_radarr_block: ActiveRadarrBlock,
|
||||||
|
) {
|
||||||
|
let mut app = App::test_default();
|
||||||
|
app.data.radarr_data = RadarrData::default();
|
||||||
|
app.push_navigation_stack(active_radarr_block.into());
|
||||||
|
|
||||||
|
let context_clues = RadarrContextClueProvider::get_context_clues(&mut app);
|
||||||
|
|
||||||
|
assert_some_eq_x!(context_clues, &CONFIRMATION_PROMPT_CONTEXT_CLUES);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
fn test_radarr_context_clue_provider_add_movie_search_results_context_clues(
|
||||||
|
#[values(
|
||||||
|
ActiveRadarrBlock::AddMovieSearchResults,
|
||||||
|
ActiveRadarrBlock::AddMovieAlreadyInLibrary
|
||||||
|
)]
|
||||||
|
active_radarr_block: ActiveRadarrBlock,
|
||||||
|
) {
|
||||||
|
let mut app = App::test_default();
|
||||||
|
app.data.radarr_data = RadarrData::default();
|
||||||
|
app.push_navigation_stack(active_radarr_block.into());
|
||||||
|
|
||||||
|
let context_clues = RadarrContextClueProvider::get_context_clues(&mut app);
|
||||||
|
|
||||||
|
assert_some_eq_x!(context_clues, &ADD_MOVIE_SEARCH_RESULTS_CONTEXT_CLUES);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_radarr_context_clue_provider_collection_details_context_clues() {
|
||||||
|
let mut app = App::test_default();
|
||||||
|
app.data.radarr_data = RadarrData::default();
|
||||||
|
app.push_navigation_stack(ActiveRadarrBlock::CollectionDetails.into());
|
||||||
|
|
||||||
|
let context_clues = RadarrContextClueProvider::get_context_clues(&mut app);
|
||||||
|
|
||||||
|
assert_some_eq_x!(context_clues, &COLLECTION_DETAILS_CONTEXT_CLUES);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_radarr_context_clue_provider_system_tasks_context_clues() {
|
||||||
|
let mut app = App::test_default();
|
||||||
|
app.data.radarr_data = RadarrData::default();
|
||||||
|
|
||||||
|
app.push_navigation_stack(ActiveRadarrBlock::SystemTasks.into());
|
||||||
|
|
||||||
|
let context_clues = RadarrContextClueProvider::get_context_clues(&mut app);
|
||||||
|
|
||||||
|
assert_some_eq_x!(context_clues, &SYSTEM_TASKS_CONTEXT_CLUES);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
#[case(0, ActiveRadarrBlock::Movies, &LIBRARY_CONTEXT_CLUES)]
|
||||||
|
#[case(1, ActiveRadarrBlock::Collections, &COLLECTIONS_CONTEXT_CLUES)]
|
||||||
|
#[case(2, ActiveRadarrBlock::Downloads, &DOWNLOADS_CONTEXT_CLUES)]
|
||||||
|
#[case(3, ActiveRadarrBlock::Blocklist, &BLOCKLIST_CONTEXT_CLUES)]
|
||||||
|
#[case(4, ActiveRadarrBlock::RootFolders, &ROOT_FOLDERS_CONTEXT_CLUES)]
|
||||||
|
#[case(5, ActiveRadarrBlock::Indexers, &INDEXERS_CONTEXT_CLUES)]
|
||||||
|
#[case(6, ActiveRadarrBlock::System, &SYSTEM_CONTEXT_CLUES)]
|
||||||
|
fn test_radarr_context_clue_provider_radarr_blocks_context_clues(
|
||||||
|
#[case] index: usize,
|
||||||
|
#[case] active_radarr_block: ActiveRadarrBlock,
|
||||||
|
#[case] expected_context_clues: &[ContextClue],
|
||||||
|
) {
|
||||||
|
let mut app = App::test_default();
|
||||||
|
app.data.radarr_data = RadarrData::default();
|
||||||
|
app.data.radarr_data.main_tabs.set_index(index);
|
||||||
|
app.push_navigation_stack(active_radarr_block.into());
|
||||||
|
|
||||||
|
let context_clues = RadarrContextClueProvider::get_context_clues(&mut app);
|
||||||
|
|
||||||
|
assert_some_eq_x!(context_clues, expected_context_clues);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,15 +3,15 @@ mod tests {
|
|||||||
use pretty_assertions::assert_eq;
|
use pretty_assertions::assert_eq;
|
||||||
use tokio::sync::mpsc;
|
use tokio::sync::mpsc;
|
||||||
|
|
||||||
use crate::app::radarr::ActiveRadarrBlock;
|
|
||||||
use crate::app::App;
|
use crate::app::App;
|
||||||
|
use crate::app::radarr::ActiveRadarrBlock;
|
||||||
use crate::models::radarr_models::{
|
use crate::models::radarr_models::{
|
||||||
AddMovieBody, AddMovieOptions, Collection, CollectionMovie, Credit, Movie, RadarrRelease,
|
AddMovieBody, AddMovieOptions, Collection, CollectionMovie, Credit, Movie, RadarrRelease,
|
||||||
};
|
};
|
||||||
use crate::models::servarr_data::radarr::modals::MovieDetailsModal;
|
use crate::models::servarr_data::radarr::modals::MovieDetailsModal;
|
||||||
use crate::models::servarr_models::Indexer;
|
use crate::models::servarr_models::Indexer;
|
||||||
use crate::network::radarr_network::RadarrEvent;
|
|
||||||
use crate::network::NetworkEvent;
|
use crate::network::NetworkEvent;
|
||||||
|
use crate::network::radarr_network::RadarrEvent;
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_dispatch_by_blocklist_block() {
|
async fn test_dispatch_by_blocklist_block() {
|
||||||
@@ -140,7 +140,7 @@ mod tests {
|
|||||||
assert!(app.is_loading);
|
assert!(app.is_loading);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
sync_network_rx.recv().await.unwrap(),
|
sync_network_rx.recv().await.unwrap(),
|
||||||
RadarrEvent::GetDownloads.into()
|
RadarrEvent::GetDownloads(500).into()
|
||||||
);
|
);
|
||||||
assert!(!app.data.radarr_data.prompt_confirm);
|
assert!(!app.data.radarr_data.prompt_confirm);
|
||||||
assert_eq!(app.tick_count, 0);
|
assert_eq!(app.tick_count, 0);
|
||||||
@@ -186,7 +186,7 @@ mod tests {
|
|||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
sync_network_rx.recv().await.unwrap(),
|
sync_network_rx.recv().await.unwrap(),
|
||||||
RadarrEvent::GetDownloads.into()
|
RadarrEvent::GetDownloads(500).into()
|
||||||
);
|
);
|
||||||
assert!(!app.data.radarr_data.prompt_confirm);
|
assert!(!app.data.radarr_data.prompt_confirm);
|
||||||
assert_eq!(app.tick_count, 0);
|
assert_eq!(app.tick_count, 0);
|
||||||
@@ -467,7 +467,7 @@ mod tests {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_dispatch_by_cast_crew_blocks_cast_and_crew_non_empty() {
|
async fn test_dispatch_by_cast_crew_blocks_cast_and_crew_non_empty() {
|
||||||
let mut app = App::default();
|
let mut app = App::test_default();
|
||||||
|
|
||||||
for active_radarr_block in &[ActiveRadarrBlock::Cast, ActiveRadarrBlock::Crew] {
|
for active_radarr_block in &[ActiveRadarrBlock::Cast, ActiveRadarrBlock::Crew] {
|
||||||
let mut movie_details_modal = MovieDetailsModal::default();
|
let mut movie_details_modal = MovieDetailsModal::default();
|
||||||
@@ -511,7 +511,7 @@ mod tests {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_dispatch_by_manual_search_block_movie_releases_non_empty() {
|
async fn test_dispatch_by_manual_search_block_movie_releases_non_empty() {
|
||||||
let mut app = App::default();
|
let mut app = App::test_default();
|
||||||
let mut movie_details_modal = MovieDetailsModal::default();
|
let mut movie_details_modal = MovieDetailsModal::default();
|
||||||
movie_details_modal
|
movie_details_modal
|
||||||
.movie_releases
|
.movie_releases
|
||||||
@@ -531,7 +531,7 @@ mod tests {
|
|||||||
async fn test_dispatch_by_manual_search_block_is_loading() {
|
async fn test_dispatch_by_manual_search_block_is_loading() {
|
||||||
let mut app = App {
|
let mut app = App {
|
||||||
is_loading: true,
|
is_loading: true,
|
||||||
..App::default()
|
..App::test_default()
|
||||||
};
|
};
|
||||||
|
|
||||||
app
|
app
|
||||||
@@ -545,7 +545,7 @@ mod tests {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_check_for_radarr_prompt_action_no_prompt_confirm() {
|
async fn test_check_for_radarr_prompt_action_no_prompt_confirm() {
|
||||||
let mut app = App::default();
|
let mut app = App::test_default();
|
||||||
app.data.radarr_data.prompt_confirm = false;
|
app.data.radarr_data.prompt_confirm = false;
|
||||||
|
|
||||||
app.check_for_radarr_prompt_action().await;
|
app.check_for_radarr_prompt_action().await;
|
||||||
@@ -591,7 +591,7 @@ mod tests {
|
|||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
sync_network_rx.recv().await.unwrap(),
|
sync_network_rx.recv().await.unwrap(),
|
||||||
RadarrEvent::GetDownloads.into()
|
RadarrEvent::GetDownloads(500).into()
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
sync_network_rx.recv().await.unwrap(),
|
sync_network_rx.recv().await.unwrap(),
|
||||||
@@ -625,7 +625,7 @@ mod tests {
|
|||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
sync_network_rx.recv().await.unwrap(),
|
sync_network_rx.recv().await.unwrap(),
|
||||||
RadarrEvent::GetDownloads.into()
|
RadarrEvent::GetDownloads(500).into()
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
sync_network_rx.recv().await.unwrap(),
|
sync_network_rx.recv().await.unwrap(),
|
||||||
@@ -650,7 +650,7 @@ mod tests {
|
|||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
sync_network_rx.recv().await.unwrap(),
|
sync_network_rx.recv().await.unwrap(),
|
||||||
RadarrEvent::GetDownloads.into()
|
RadarrEvent::GetDownloads(500).into()
|
||||||
);
|
);
|
||||||
assert!(!app.data.radarr_data.prompt_confirm);
|
assert!(!app.data.radarr_data.prompt_confirm);
|
||||||
}
|
}
|
||||||
@@ -675,7 +675,7 @@ mod tests {
|
|||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
sync_network_rx.recv().await.unwrap(),
|
sync_network_rx.recv().await.unwrap(),
|
||||||
RadarrEvent::GetDownloads.into()
|
RadarrEvent::GetDownloads(500).into()
|
||||||
);
|
);
|
||||||
assert!(app.should_refresh);
|
assert!(app.should_refresh);
|
||||||
assert!(!app.data.radarr_data.prompt_confirm);
|
assert!(!app.data.radarr_data.prompt_confirm);
|
||||||
@@ -692,7 +692,7 @@ mod tests {
|
|||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
sync_network_rx.recv().await.unwrap(),
|
sync_network_rx.recv().await.unwrap(),
|
||||||
RadarrEvent::GetDownloads.into()
|
RadarrEvent::GetDownloads(500).into()
|
||||||
);
|
);
|
||||||
assert!(app.is_loading);
|
assert!(app.is_loading);
|
||||||
assert!(app.should_refresh);
|
assert!(app.should_refresh);
|
||||||
@@ -722,14 +722,14 @@ mod tests {
|
|||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
sync_network_rx.recv().await.unwrap(),
|
sync_network_rx.recv().await.unwrap(),
|
||||||
RadarrEvent::GetDownloads.into()
|
RadarrEvent::GetDownloads(500).into()
|
||||||
);
|
);
|
||||||
assert!(app.is_loading);
|
assert!(app.is_loading);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_populate_movie_collection_table_unfiltered() {
|
async fn test_populate_movie_collection_table_unfiltered() {
|
||||||
let mut app = App::default();
|
let mut app = App::test_default();
|
||||||
app.data.radarr_data.collections.set_items(vec![Collection {
|
app.data.radarr_data.collections.set_items(vec![Collection {
|
||||||
movies: Some(vec![CollectionMovie::default()]),
|
movies: Some(vec![CollectionMovie::default()]),
|
||||||
..Collection::default()
|
..Collection::default()
|
||||||
@@ -742,7 +742,7 @@ mod tests {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_populate_movie_collection_table_filtered() {
|
async fn test_populate_movie_collection_table_filtered() {
|
||||||
let mut app = App::default();
|
let mut app = App::test_default();
|
||||||
app
|
app
|
||||||
.data
|
.data
|
||||||
.radarr_data
|
.radarr_data
|
||||||
@@ -759,7 +759,7 @@ mod tests {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_extract_movie_id() {
|
async fn test_extract_movie_id() {
|
||||||
let mut app = App::default();
|
let mut app = App::test_default();
|
||||||
app.data.radarr_data.movies.set_items(vec![Movie {
|
app.data.radarr_data.movies.set_items(vec![Movie {
|
||||||
id: 1,
|
id: 1,
|
||||||
..Movie::default()
|
..Movie::default()
|
||||||
@@ -770,7 +770,7 @@ mod tests {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_extract_radarr_indexer_id() {
|
async fn test_extract_radarr_indexer_id() {
|
||||||
let mut app = App::default();
|
let mut app = App::test_default();
|
||||||
app.data.radarr_data.indexers.set_items(vec![Indexer {
|
app.data.radarr_data.indexers.set_items(vec![Indexer {
|
||||||
id: 1,
|
id: 1,
|
||||||
..Indexer::default()
|
..Indexer::default()
|
||||||
@@ -785,7 +785,7 @@ mod tests {
|
|||||||
network_tx: Some(sync_network_tx),
|
network_tx: Some(sync_network_tx),
|
||||||
tick_count: 1,
|
tick_count: 1,
|
||||||
is_first_render: false,
|
is_first_render: false,
|
||||||
..App::default()
|
..App::test_default()
|
||||||
};
|
};
|
||||||
app.data.radarr_data.prompt_confirm = true;
|
app.data.radarr_data.prompt_confirm = true;
|
||||||
|
|
||||||
|
|||||||
+16
-20
@@ -11,7 +11,7 @@ pub mod sonarr_context_clues;
|
|||||||
#[path = "sonarr_tests.rs"]
|
#[path = "sonarr_tests.rs"]
|
||||||
mod sonarr_tests;
|
mod sonarr_tests;
|
||||||
|
|
||||||
impl<'a> App<'a> {
|
impl App<'_> {
|
||||||
pub(super) async fn dispatch_by_sonarr_block(&mut self, active_sonarr_block: &ActiveSonarrBlock) {
|
pub(super) async fn dispatch_by_sonarr_block(&mut self, active_sonarr_block: &ActiveSonarrBlock) {
|
||||||
match active_sonarr_block {
|
match active_sonarr_block {
|
||||||
ActiveSonarrBlock::Series => {
|
ActiveSonarrBlock::Series => {
|
||||||
@@ -53,7 +53,7 @@ impl<'a> App<'a> {
|
|||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
self
|
self
|
||||||
.dispatch_network_event(SonarrEvent::GetDownloads.into())
|
.dispatch_network_event(SonarrEvent::GetDownloads(500).into())
|
||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
ActiveSonarrBlock::SeasonHistory => {
|
ActiveSonarrBlock::SeasonHistory => {
|
||||||
@@ -94,21 +94,20 @@ impl<'a> App<'a> {
|
|||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
ActiveSonarrBlock::ManualEpisodeSearch => {
|
ActiveSonarrBlock::ManualEpisodeSearch => {
|
||||||
if let Some(season_details_modal) = self.data.sonarr_data.season_details_modal.as_ref() {
|
if let Some(season_details_modal) = self.data.sonarr_data.season_details_modal.as_ref()
|
||||||
if let Some(episode_details_modal) = season_details_modal.episode_details_modal.as_ref() {
|
&& let Some(episode_details_modal) = season_details_modal.episode_details_modal.as_ref()
|
||||||
if episode_details_modal.episode_releases.is_empty() {
|
&& episode_details_modal.episode_releases.is_empty()
|
||||||
self
|
{
|
||||||
.dispatch_network_event(
|
self
|
||||||
SonarrEvent::GetEpisodeReleases(self.extract_episode_id().await).into(),
|
.dispatch_network_event(
|
||||||
)
|
SonarrEvent::GetEpisodeReleases(self.extract_episode_id().await).into(),
|
||||||
.await;
|
)
|
||||||
}
|
.await;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ActiveSonarrBlock::Downloads => {
|
ActiveSonarrBlock::Downloads => {
|
||||||
self
|
self
|
||||||
.dispatch_network_event(SonarrEvent::GetDownloads.into())
|
.dispatch_network_event(SonarrEvent::GetDownloads(500).into())
|
||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
ActiveSonarrBlock::Blocklist => {
|
ActiveSonarrBlock::Blocklist => {
|
||||||
@@ -187,12 +186,9 @@ impl<'a> App<'a> {
|
|||||||
async fn check_for_sonarr_prompt_action(&mut self) {
|
async fn check_for_sonarr_prompt_action(&mut self) {
|
||||||
if self.data.sonarr_data.prompt_confirm {
|
if self.data.sonarr_data.prompt_confirm {
|
||||||
self.data.sonarr_data.prompt_confirm = false;
|
self.data.sonarr_data.prompt_confirm = false;
|
||||||
if let Some(sonarr_event) = &self.data.sonarr_data.prompt_confirm_action {
|
if let Some(sonarr_event) = self.data.sonarr_data.prompt_confirm_action.take() {
|
||||||
self
|
self.dispatch_network_event(sonarr_event.into()).await;
|
||||||
.dispatch_network_event(sonarr_event.clone().into())
|
|
||||||
.await;
|
|
||||||
self.should_refresh = true;
|
self.should_refresh = true;
|
||||||
self.data.sonarr_data.prompt_confirm_action = None;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -218,7 +214,7 @@ impl<'a> App<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.tick_count % self.tick_until_poll == 0 {
|
if self.tick_count.is_multiple_of(self.tick_until_poll) {
|
||||||
self.refresh_sonarr_metadata().await;
|
self.refresh_sonarr_metadata().await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -237,7 +233,7 @@ impl<'a> App<'a> {
|
|||||||
.dispatch_network_event(SonarrEvent::GetRootFolders.into())
|
.dispatch_network_event(SonarrEvent::GetRootFolders.into())
|
||||||
.await;
|
.await;
|
||||||
self
|
self
|
||||||
.dispatch_network_event(SonarrEvent::GetDownloads.into())
|
.dispatch_network_event(SonarrEvent::GetDownloads(500).into())
|
||||||
.await;
|
.await;
|
||||||
self
|
self
|
||||||
.dispatch_network_event(SonarrEvent::GetDiskSpace.into())
|
.dispatch_network_event(SonarrEvent::GetDiskSpace.into())
|
||||||
|
|||||||
@@ -1,4 +1,12 @@
|
|||||||
use crate::app::{context_clues::ContextClue, key_binding::DEFAULT_KEYBINDINGS};
|
use crate::app::context_clues::{
|
||||||
|
BARE_POPUP_CONTEXT_CLUES, CONFIRMATION_PROMPT_CONTEXT_CLUES, ContextClueProvider,
|
||||||
|
};
|
||||||
|
use crate::app::{App, context_clues::ContextClue, key_binding::DEFAULT_KEYBINDINGS};
|
||||||
|
use crate::models::Route;
|
||||||
|
use crate::models::servarr_data::sonarr::sonarr_data::{
|
||||||
|
ADD_SERIES_BLOCKS, ActiveSonarrBlock, EDIT_INDEXER_BLOCKS, EDIT_SERIES_BLOCKS,
|
||||||
|
EPISODE_DETAILS_BLOCKS, INDEXER_SETTINGS_BLOCKS, SEASON_DETAILS_BLOCKS, SERIES_DETAILS_BLOCKS,
|
||||||
|
};
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
#[path = "sonarr_context_clues_tests.rs"]
|
#[path = "sonarr_context_clues_tests.rs"]
|
||||||
@@ -9,9 +17,13 @@ pub static ADD_SERIES_SEARCH_RESULTS_CONTEXT_CLUES: [ContextClue; 2] = [
|
|||||||
(DEFAULT_KEYBINDINGS.esc, "edit search"),
|
(DEFAULT_KEYBINDINGS.esc, "edit search"),
|
||||||
];
|
];
|
||||||
|
|
||||||
pub static SERIES_CONTEXT_CLUES: [ContextClue; 10] = [
|
pub static SERIES_CONTEXT_CLUES: [ContextClue; 11] = [
|
||||||
(DEFAULT_KEYBINDINGS.add, DEFAULT_KEYBINDINGS.add.desc),
|
(DEFAULT_KEYBINDINGS.add, DEFAULT_KEYBINDINGS.add.desc),
|
||||||
(DEFAULT_KEYBINDINGS.edit, DEFAULT_KEYBINDINGS.edit.desc),
|
(DEFAULT_KEYBINDINGS.edit, DEFAULT_KEYBINDINGS.edit.desc),
|
||||||
|
(
|
||||||
|
DEFAULT_KEYBINDINGS.toggle_monitoring,
|
||||||
|
DEFAULT_KEYBINDINGS.toggle_monitoring.desc,
|
||||||
|
),
|
||||||
(DEFAULT_KEYBINDINGS.sort, DEFAULT_KEYBINDINGS.sort.desc),
|
(DEFAULT_KEYBINDINGS.sort, DEFAULT_KEYBINDINGS.sort.desc),
|
||||||
(DEFAULT_KEYBINDINGS.delete, DEFAULT_KEYBINDINGS.delete.desc),
|
(DEFAULT_KEYBINDINGS.delete, DEFAULT_KEYBINDINGS.delete.desc),
|
||||||
(DEFAULT_KEYBINDINGS.search, DEFAULT_KEYBINDINGS.search.desc),
|
(DEFAULT_KEYBINDINGS.search, DEFAULT_KEYBINDINGS.search.desc),
|
||||||
@@ -75,12 +87,7 @@ pub static SERIES_HISTORY_CONTEXT_CLUES: [ContextClue; 9] = [
|
|||||||
(DEFAULT_KEYBINDINGS.esc, "cancel filter/close"),
|
(DEFAULT_KEYBINDINGS.esc, "cancel filter/close"),
|
||||||
];
|
];
|
||||||
|
|
||||||
pub static SEASON_DETAILS_CONTEXTUAL_CONTEXT_CLUES: [ContextClue; 2] = [
|
pub static SEASON_DETAILS_CONTEXT_CLUES: [ContextClue; 7] = [
|
||||||
(DEFAULT_KEYBINDINGS.submit, "episode details"),
|
|
||||||
(DEFAULT_KEYBINDINGS.delete, "delete episode"),
|
|
||||||
];
|
|
||||||
|
|
||||||
pub static SEASON_DETAILS_CONTEXT_CLUES: [ContextClue; 5] = [
|
|
||||||
(
|
(
|
||||||
DEFAULT_KEYBINDINGS.refresh,
|
DEFAULT_KEYBINDINGS.refresh,
|
||||||
DEFAULT_KEYBINDINGS.refresh.desc,
|
DEFAULT_KEYBINDINGS.refresh.desc,
|
||||||
@@ -95,9 +102,11 @@ pub static SEASON_DETAILS_CONTEXT_CLUES: [ContextClue; 5] = [
|
|||||||
DEFAULT_KEYBINDINGS.auto_search.desc,
|
DEFAULT_KEYBINDINGS.auto_search.desc,
|
||||||
),
|
),
|
||||||
(DEFAULT_KEYBINDINGS.esc, DEFAULT_KEYBINDINGS.esc.desc),
|
(DEFAULT_KEYBINDINGS.esc, DEFAULT_KEYBINDINGS.esc.desc),
|
||||||
|
(DEFAULT_KEYBINDINGS.submit, "episode details"),
|
||||||
|
(DEFAULT_KEYBINDINGS.delete, "delete episode"),
|
||||||
];
|
];
|
||||||
|
|
||||||
pub static SEASON_HISTORY_CONTEXT_CLUES: [ContextClue; 6] = [
|
pub static SEASON_HISTORY_CONTEXT_CLUES: [ContextClue; 7] = [
|
||||||
(
|
(
|
||||||
DEFAULT_KEYBINDINGS.refresh,
|
DEFAULT_KEYBINDINGS.refresh,
|
||||||
DEFAULT_KEYBINDINGS.refresh.desc,
|
DEFAULT_KEYBINDINGS.refresh.desc,
|
||||||
@@ -109,10 +118,11 @@ pub static SEASON_HISTORY_CONTEXT_CLUES: [ContextClue; 6] = [
|
|||||||
DEFAULT_KEYBINDINGS.auto_search,
|
DEFAULT_KEYBINDINGS.auto_search,
|
||||||
DEFAULT_KEYBINDINGS.auto_search.desc,
|
DEFAULT_KEYBINDINGS.auto_search.desc,
|
||||||
),
|
),
|
||||||
|
(DEFAULT_KEYBINDINGS.submit, "details"),
|
||||||
(DEFAULT_KEYBINDINGS.esc, "cancel filter/close"),
|
(DEFAULT_KEYBINDINGS.esc, "cancel filter/close"),
|
||||||
];
|
];
|
||||||
|
|
||||||
pub static MANUAL_SEASON_SEARCH_CONTEXT_CLUES: [ContextClue; 4] = [
|
pub static MANUAL_SEASON_SEARCH_CONTEXT_CLUES: [ContextClue; 5] = [
|
||||||
(
|
(
|
||||||
DEFAULT_KEYBINDINGS.refresh,
|
DEFAULT_KEYBINDINGS.refresh,
|
||||||
DEFAULT_KEYBINDINGS.refresh.desc,
|
DEFAULT_KEYBINDINGS.refresh.desc,
|
||||||
@@ -122,10 +132,11 @@ pub static MANUAL_SEASON_SEARCH_CONTEXT_CLUES: [ContextClue; 4] = [
|
|||||||
DEFAULT_KEYBINDINGS.auto_search.desc,
|
DEFAULT_KEYBINDINGS.auto_search.desc,
|
||||||
),
|
),
|
||||||
(DEFAULT_KEYBINDINGS.sort, DEFAULT_KEYBINDINGS.sort.desc),
|
(DEFAULT_KEYBINDINGS.sort, DEFAULT_KEYBINDINGS.sort.desc),
|
||||||
|
(DEFAULT_KEYBINDINGS.submit, "details"),
|
||||||
(DEFAULT_KEYBINDINGS.esc, DEFAULT_KEYBINDINGS.esc.desc),
|
(DEFAULT_KEYBINDINGS.esc, DEFAULT_KEYBINDINGS.esc.desc),
|
||||||
];
|
];
|
||||||
|
|
||||||
pub static MANUAL_EPISODE_SEARCH_CONTEXT_CLUES: [ContextClue; 4] = [
|
pub static MANUAL_EPISODE_SEARCH_CONTEXT_CLUES: [ContextClue; 5] = [
|
||||||
(
|
(
|
||||||
DEFAULT_KEYBINDINGS.refresh,
|
DEFAULT_KEYBINDINGS.refresh,
|
||||||
DEFAULT_KEYBINDINGS.refresh.desc,
|
DEFAULT_KEYBINDINGS.refresh.desc,
|
||||||
@@ -135,12 +146,10 @@ pub static MANUAL_EPISODE_SEARCH_CONTEXT_CLUES: [ContextClue; 4] = [
|
|||||||
DEFAULT_KEYBINDINGS.auto_search.desc,
|
DEFAULT_KEYBINDINGS.auto_search.desc,
|
||||||
),
|
),
|
||||||
(DEFAULT_KEYBINDINGS.sort, DEFAULT_KEYBINDINGS.sort.desc),
|
(DEFAULT_KEYBINDINGS.sort, DEFAULT_KEYBINDINGS.sort.desc),
|
||||||
|
(DEFAULT_KEYBINDINGS.submit, "details"),
|
||||||
(DEFAULT_KEYBINDINGS.esc, DEFAULT_KEYBINDINGS.esc.desc),
|
(DEFAULT_KEYBINDINGS.esc, DEFAULT_KEYBINDINGS.esc.desc),
|
||||||
];
|
];
|
||||||
|
|
||||||
pub static DETAILS_CONTEXTUAL_CONTEXT_CLUES: [ContextClue; 1] =
|
|
||||||
[(DEFAULT_KEYBINDINGS.submit, "details")];
|
|
||||||
|
|
||||||
pub static EPISODE_DETAILS_CONTEXT_CLUES: [ContextClue; 3] = [
|
pub static EPISODE_DETAILS_CONTEXT_CLUES: [ContextClue; 3] = [
|
||||||
(
|
(
|
||||||
DEFAULT_KEYBINDINGS.refresh,
|
DEFAULT_KEYBINDINGS.refresh,
|
||||||
@@ -153,7 +162,84 @@ pub static EPISODE_DETAILS_CONTEXT_CLUES: [ContextClue; 3] = [
|
|||||||
(DEFAULT_KEYBINDINGS.esc, DEFAULT_KEYBINDINGS.esc.desc),
|
(DEFAULT_KEYBINDINGS.esc, DEFAULT_KEYBINDINGS.esc.desc),
|
||||||
];
|
];
|
||||||
|
|
||||||
|
pub static SELECTABLE_EPISODE_DETAILS_CONTEXT_CLUES: [ContextClue; 4] = [
|
||||||
|
(
|
||||||
|
DEFAULT_KEYBINDINGS.refresh,
|
||||||
|
DEFAULT_KEYBINDINGS.refresh.desc,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
DEFAULT_KEYBINDINGS.auto_search,
|
||||||
|
DEFAULT_KEYBINDINGS.auto_search.desc,
|
||||||
|
),
|
||||||
|
(DEFAULT_KEYBINDINGS.submit, "details"),
|
||||||
|
(DEFAULT_KEYBINDINGS.esc, DEFAULT_KEYBINDINGS.esc.desc),
|
||||||
|
];
|
||||||
|
|
||||||
pub static SYSTEM_TASKS_CONTEXT_CLUES: [ContextClue; 2] = [
|
pub static SYSTEM_TASKS_CONTEXT_CLUES: [ContextClue; 2] = [
|
||||||
(DEFAULT_KEYBINDINGS.submit, "start task"),
|
(DEFAULT_KEYBINDINGS.submit, "start task"),
|
||||||
(DEFAULT_KEYBINDINGS.esc, DEFAULT_KEYBINDINGS.esc.desc),
|
(DEFAULT_KEYBINDINGS.esc, DEFAULT_KEYBINDINGS.esc.desc),
|
||||||
];
|
];
|
||||||
|
|
||||||
|
pub(in crate::app) struct SonarrContextClueProvider;
|
||||||
|
|
||||||
|
impl ContextClueProvider for SonarrContextClueProvider {
|
||||||
|
fn get_context_clues(app: &mut App<'_>) -> Option<&'static [ContextClue]> {
|
||||||
|
let Route::Sonarr(active_sonarr_block, _) = app.get_current_route() else {
|
||||||
|
panic!("SonarrContextClueProvider::get_context_clues called with non-Sonarr route");
|
||||||
|
};
|
||||||
|
match active_sonarr_block {
|
||||||
|
_ if SERIES_DETAILS_BLOCKS.contains(&active_sonarr_block) => app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.series_info_tabs
|
||||||
|
.get_active_route_contextual_help(),
|
||||||
|
_ if SEASON_DETAILS_BLOCKS.contains(&active_sonarr_block) => app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.season_details_modal
|
||||||
|
.as_ref()
|
||||||
|
.unwrap()
|
||||||
|
.season_details_tabs
|
||||||
|
.get_active_route_contextual_help(),
|
||||||
|
_ if EPISODE_DETAILS_BLOCKS.contains(&active_sonarr_block) => app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.season_details_modal
|
||||||
|
.as_ref()
|
||||||
|
.unwrap()
|
||||||
|
.episode_details_modal
|
||||||
|
.as_ref()
|
||||||
|
.unwrap()
|
||||||
|
.episode_details_tabs
|
||||||
|
.get_active_route_contextual_help(),
|
||||||
|
ActiveSonarrBlock::TestAllIndexers
|
||||||
|
| ActiveSonarrBlock::AddSeriesSearchInput
|
||||||
|
| ActiveSonarrBlock::AddSeriesEmptySearchResults
|
||||||
|
| ActiveSonarrBlock::SystemLogs
|
||||||
|
| ActiveSonarrBlock::SystemUpdates => Some(&BARE_POPUP_CONTEXT_CLUES),
|
||||||
|
_ if EDIT_INDEXER_BLOCKS.contains(&active_sonarr_block)
|
||||||
|
|| INDEXER_SETTINGS_BLOCKS.contains(&active_sonarr_block)
|
||||||
|
|| EDIT_SERIES_BLOCKS.contains(&active_sonarr_block) =>
|
||||||
|
{
|
||||||
|
Some(&CONFIRMATION_PROMPT_CONTEXT_CLUES)
|
||||||
|
}
|
||||||
|
ActiveSonarrBlock::AddSeriesPrompt
|
||||||
|
| ActiveSonarrBlock::AddSeriesSelectMonitor
|
||||||
|
| ActiveSonarrBlock::AddSeriesSelectSeriesType
|
||||||
|
| ActiveSonarrBlock::AddSeriesSelectQualityProfile
|
||||||
|
| ActiveSonarrBlock::AddSeriesSelectLanguageProfile
|
||||||
|
| ActiveSonarrBlock::AddSeriesSelectRootFolder
|
||||||
|
| ActiveSonarrBlock::AddSeriesTagsInput
|
||||||
|
| ActiveSonarrBlock::SystemTaskStartConfirmPrompt => Some(&CONFIRMATION_PROMPT_CONTEXT_CLUES),
|
||||||
|
_ if ADD_SERIES_BLOCKS.contains(&active_sonarr_block) => {
|
||||||
|
Some(&ADD_SERIES_SEARCH_RESULTS_CONTEXT_CLUES)
|
||||||
|
}
|
||||||
|
ActiveSonarrBlock::SystemTasks => Some(&SYSTEM_TASKS_CONTEXT_CLUES),
|
||||||
|
_ => app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.main_tabs
|
||||||
|
.get_active_route_contextual_help(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -16,7 +16,7 @@ mod tests {
|
|||||||
},
|
},
|
||||||
sonarr_models::{Season, Series, SonarrRelease},
|
sonarr_models::{Season, Series, SonarrRelease},
|
||||||
},
|
},
|
||||||
network::{sonarr_network::SonarrEvent, NetworkEvent},
|
network::{NetworkEvent, sonarr_network::SonarrEvent},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@@ -107,7 +107,7 @@ mod tests {
|
|||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
sync_network_rx.recv().await.unwrap(),
|
sync_network_rx.recv().await.unwrap(),
|
||||||
SonarrEvent::GetDownloads.into()
|
SonarrEvent::GetDownloads(500).into()
|
||||||
);
|
);
|
||||||
assert!(!app.data.sonarr_data.prompt_confirm);
|
assert!(!app.data.sonarr_data.prompt_confirm);
|
||||||
assert_eq!(app.tick_count, 0);
|
assert_eq!(app.tick_count, 0);
|
||||||
@@ -185,7 +185,7 @@ mod tests {
|
|||||||
async fn test_dispatch_by_manual_season_search_block_is_loading() {
|
async fn test_dispatch_by_manual_season_search_block_is_loading() {
|
||||||
let mut app = App {
|
let mut app = App {
|
||||||
is_loading: true,
|
is_loading: true,
|
||||||
..App::default()
|
..App::test_default()
|
||||||
};
|
};
|
||||||
|
|
||||||
app
|
app
|
||||||
@@ -199,7 +199,7 @@ mod tests {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_dispatch_by_manual_season_search_block_season_releases_non_empty() {
|
async fn test_dispatch_by_manual_season_search_block_season_releases_non_empty() {
|
||||||
let mut app = App::default();
|
let mut app = App::test_default();
|
||||||
let mut season_details_modal = SeasonDetailsModal::default();
|
let mut season_details_modal = SeasonDetailsModal::default();
|
||||||
season_details_modal
|
season_details_modal
|
||||||
.season_releases
|
.season_releases
|
||||||
@@ -304,7 +304,7 @@ mod tests {
|
|||||||
async fn test_dispatch_by_manual_episode_search_block_is_loading() {
|
async fn test_dispatch_by_manual_episode_search_block_is_loading() {
|
||||||
let mut app = App {
|
let mut app = App {
|
||||||
is_loading: true,
|
is_loading: true,
|
||||||
..App::default()
|
..App::test_default()
|
||||||
};
|
};
|
||||||
|
|
||||||
app
|
app
|
||||||
@@ -318,7 +318,7 @@ mod tests {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_dispatch_by_manual_episode_search_block_episode_releases_non_empty() {
|
async fn test_dispatch_by_manual_episode_search_block_episode_releases_non_empty() {
|
||||||
let mut app = App::default();
|
let mut app = App::test_default();
|
||||||
let mut episode_details_modal = EpisodeDetailsModal::default();
|
let mut episode_details_modal = EpisodeDetailsModal::default();
|
||||||
episode_details_modal
|
episode_details_modal
|
||||||
.episode_releases
|
.episode_releases
|
||||||
@@ -366,7 +366,7 @@ mod tests {
|
|||||||
assert!(app.is_loading);
|
assert!(app.is_loading);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
sync_network_rx.recv().await.unwrap(),
|
sync_network_rx.recv().await.unwrap(),
|
||||||
SonarrEvent::GetDownloads.into()
|
SonarrEvent::GetDownloads(500).into()
|
||||||
);
|
);
|
||||||
assert!(!app.data.sonarr_data.prompt_confirm);
|
assert!(!app.data.sonarr_data.prompt_confirm);
|
||||||
assert_eq!(app.tick_count, 0);
|
assert_eq!(app.tick_count, 0);
|
||||||
@@ -554,7 +554,7 @@ mod tests {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_check_for_sonarr_prompt_action_no_prompt_confirm() {
|
async fn test_check_for_sonarr_prompt_action_no_prompt_confirm() {
|
||||||
let mut app = App::default();
|
let mut app = App::test_default();
|
||||||
app.data.sonarr_data.prompt_confirm = false;
|
app.data.sonarr_data.prompt_confirm = false;
|
||||||
|
|
||||||
app.check_for_sonarr_prompt_action().await;
|
app.check_for_sonarr_prompt_action().await;
|
||||||
@@ -604,7 +604,7 @@ mod tests {
|
|||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
sync_network_rx.recv().await.unwrap(),
|
sync_network_rx.recv().await.unwrap(),
|
||||||
SonarrEvent::GetDownloads.into()
|
SonarrEvent::GetDownloads(500).into()
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
sync_network_rx.recv().await.unwrap(),
|
sync_network_rx.recv().await.unwrap(),
|
||||||
@@ -642,7 +642,7 @@ mod tests {
|
|||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
sync_network_rx.recv().await.unwrap(),
|
sync_network_rx.recv().await.unwrap(),
|
||||||
SonarrEvent::GetDownloads.into()
|
SonarrEvent::GetDownloads(500).into()
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
sync_network_rx.recv().await.unwrap(),
|
sync_network_rx.recv().await.unwrap(),
|
||||||
@@ -667,7 +667,7 @@ mod tests {
|
|||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
sync_network_rx.recv().await.unwrap(),
|
sync_network_rx.recv().await.unwrap(),
|
||||||
SonarrEvent::GetDownloads.into()
|
SonarrEvent::GetDownloads(500).into()
|
||||||
);
|
);
|
||||||
assert!(!app.data.sonarr_data.prompt_confirm);
|
assert!(!app.data.sonarr_data.prompt_confirm);
|
||||||
}
|
}
|
||||||
@@ -692,7 +692,7 @@ mod tests {
|
|||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
sync_network_rx.recv().await.unwrap(),
|
sync_network_rx.recv().await.unwrap(),
|
||||||
SonarrEvent::GetDownloads.into()
|
SonarrEvent::GetDownloads(500).into()
|
||||||
);
|
);
|
||||||
assert!(app.should_refresh);
|
assert!(app.should_refresh);
|
||||||
assert!(!app.data.sonarr_data.prompt_confirm);
|
assert!(!app.data.sonarr_data.prompt_confirm);
|
||||||
@@ -709,7 +709,7 @@ mod tests {
|
|||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
sync_network_rx.recv().await.unwrap(),
|
sync_network_rx.recv().await.unwrap(),
|
||||||
SonarrEvent::GetDownloads.into()
|
SonarrEvent::GetDownloads(500).into()
|
||||||
);
|
);
|
||||||
assert!(app.is_loading);
|
assert!(app.is_loading);
|
||||||
assert!(app.should_refresh);
|
assert!(app.should_refresh);
|
||||||
@@ -743,14 +743,14 @@ mod tests {
|
|||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
sync_network_rx.recv().await.unwrap(),
|
sync_network_rx.recv().await.unwrap(),
|
||||||
SonarrEvent::GetDownloads.into()
|
SonarrEvent::GetDownloads(500).into()
|
||||||
);
|
);
|
||||||
assert!(app.is_loading);
|
assert!(app.is_loading);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_populate_seasons_table_unfiltered() {
|
async fn test_populate_seasons_table_unfiltered() {
|
||||||
let mut app = App::default();
|
let mut app = App::test_default();
|
||||||
app.data.sonarr_data.series.set_items(vec![Series {
|
app.data.sonarr_data.series.set_items(vec![Series {
|
||||||
seasons: Some(vec![Season::default()]),
|
seasons: Some(vec![Season::default()]),
|
||||||
..Series::default()
|
..Series::default()
|
||||||
@@ -770,7 +770,7 @@ mod tests {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_populate_seasons_table_filtered() {
|
async fn test_populate_seasons_table_filtered() {
|
||||||
let mut app = App::default();
|
let mut app = App::test_default();
|
||||||
app.data.sonarr_data.series.set_filtered_items(vec![Series {
|
app.data.sonarr_data.series.set_filtered_items(vec![Series {
|
||||||
seasons: Some(vec![Season::default()]),
|
seasons: Some(vec![Season::default()]),
|
||||||
..Series::default()
|
..Series::default()
|
||||||
@@ -790,7 +790,7 @@ mod tests {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_extract_episode_id() {
|
async fn test_extract_episode_id() {
|
||||||
let mut app = App::default();
|
let mut app = App::test_default();
|
||||||
let mut season_details_modal = SeasonDetailsModal::default();
|
let mut season_details_modal = SeasonDetailsModal::default();
|
||||||
season_details_modal.episodes.set_items(vec![Episode {
|
season_details_modal.episodes.set_items(vec![Episode {
|
||||||
id: 1,
|
id: 1,
|
||||||
@@ -804,14 +804,14 @@ mod tests {
|
|||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
#[should_panic(expected = "Season details have not been loaded")]
|
#[should_panic(expected = "Season details have not been loaded")]
|
||||||
async fn test_extract_episode_id_requires_season_details_modal_to_be_some() {
|
async fn test_extract_episode_id_requires_season_details_modal_to_be_some() {
|
||||||
let app = App::default();
|
let app = App::test_default();
|
||||||
|
|
||||||
assert_eq!(app.extract_episode_id().await, 0);
|
assert_eq!(app.extract_episode_id().await, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_extract_series_id() {
|
async fn test_extract_series_id() {
|
||||||
let mut app = App::default();
|
let mut app = App::test_default();
|
||||||
app.data.sonarr_data.series.set_items(vec![Series {
|
app.data.sonarr_data.series.set_items(vec![Series {
|
||||||
id: 1,
|
id: 1,
|
||||||
..Series::default()
|
..Series::default()
|
||||||
@@ -822,7 +822,7 @@ mod tests {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_extract_series_id_season_number_tuple() {
|
async fn test_extract_series_id_season_number_tuple() {
|
||||||
let mut app = App::default();
|
let mut app = App::test_default();
|
||||||
app.data.sonarr_data.series.set_items(vec![Series {
|
app.data.sonarr_data.series.set_items(vec![Series {
|
||||||
id: 1,
|
id: 1,
|
||||||
..Series::default()
|
..Series::default()
|
||||||
@@ -837,7 +837,7 @@ mod tests {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_extract_add_new_series_search_query() {
|
async fn test_extract_add_new_series_search_query() {
|
||||||
let mut app = App::default();
|
let mut app = App::test_default();
|
||||||
app.data.sonarr_data.add_series_search = Some("test search".into());
|
app.data.sonarr_data.add_series_search = Some("test search".into());
|
||||||
|
|
||||||
assert_str_eq!(
|
assert_str_eq!(
|
||||||
@@ -849,14 +849,14 @@ mod tests {
|
|||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
#[should_panic(expected = "Add series search is empty")]
|
#[should_panic(expected = "Add series search is empty")]
|
||||||
async fn test_extract_add_new_series_search_query_panics_when_the_query_is_not_set() {
|
async fn test_extract_add_new_series_search_query_panics_when_the_query_is_not_set() {
|
||||||
let app = App::default();
|
let app = App::test_default();
|
||||||
|
|
||||||
app.extract_add_new_series_search_query().await;
|
app.extract_add_new_series_search_query().await;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_extract_sonarr_indexer_id() {
|
async fn test_extract_sonarr_indexer_id() {
|
||||||
let mut app = App::default();
|
let mut app = App::test_default();
|
||||||
app.data.sonarr_data.indexers.set_items(vec![Indexer {
|
app.data.sonarr_data.indexers.set_items(vec![Indexer {
|
||||||
id: 1,
|
id: 1,
|
||||||
..Indexer::default()
|
..Indexer::default()
|
||||||
@@ -871,7 +871,7 @@ mod tests {
|
|||||||
network_tx: Some(sync_network_tx),
|
network_tx: Some(sync_network_tx),
|
||||||
tick_count: 1,
|
tick_count: 1,
|
||||||
is_first_render: false,
|
is_first_render: false,
|
||||||
..App::default()
|
..App::test_default()
|
||||||
};
|
};
|
||||||
app.data.sonarr_data.prompt_confirm = true;
|
app.data.sonarr_data.prompt_confirm = true;
|
||||||
|
|
||||||
|
|||||||
+14
-14
@@ -2,16 +2,18 @@
|
|||||||
mod tests {
|
mod tests {
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use clap::{error::ErrorKind, CommandFactory};
|
use clap::{CommandFactory, error::ErrorKind};
|
||||||
use mockall::predicate::eq;
|
use mockall::predicate::eq;
|
||||||
use rstest::rstest;
|
use rstest::rstest;
|
||||||
use serde_json::json;
|
use serde_json::json;
|
||||||
use tokio::sync::Mutex;
|
use tokio::sync::Mutex;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
Cli,
|
||||||
app::App,
|
app::App,
|
||||||
cli::{handle_command, mutex_flags_or_option, radarr::RadarrCommand, sonarr::SonarrCommand},
|
cli::{handle_command, mutex_flags_or_option, radarr::RadarrCommand, sonarr::SonarrCommand},
|
||||||
models::{
|
models::{
|
||||||
|
Serdeable,
|
||||||
radarr_models::{
|
radarr_models::{
|
||||||
BlocklistItem as RadarrBlocklistItem, BlocklistResponse as RadarrBlocklistResponse,
|
BlocklistItem as RadarrBlocklistItem, BlocklistResponse as RadarrBlocklistResponse,
|
||||||
RadarrSerdeable,
|
RadarrSerdeable,
|
||||||
@@ -20,12 +22,10 @@ mod tests {
|
|||||||
BlocklistItem as SonarrBlocklistItem, BlocklistResponse as SonarrBlocklistResponse,
|
BlocklistItem as SonarrBlocklistItem, BlocklistResponse as SonarrBlocklistResponse,
|
||||||
SonarrSerdeable,
|
SonarrSerdeable,
|
||||||
},
|
},
|
||||||
Serdeable,
|
|
||||||
},
|
},
|
||||||
network::{
|
network::{
|
||||||
radarr_network::RadarrEvent, sonarr_network::SonarrEvent, MockNetworkTrait, NetworkEvent,
|
MockNetworkTrait, NetworkEvent, radarr_network::RadarrEvent, sonarr_network::SonarrEvent,
|
||||||
},
|
},
|
||||||
Cli,
|
|
||||||
};
|
};
|
||||||
use pretty_assertions::assert_eq;
|
use pretty_assertions::assert_eq;
|
||||||
|
|
||||||
@@ -33,7 +33,7 @@ mod tests {
|
|||||||
fn test_servarr_subcommand_requires_subcommand(#[values("radarr", "sonarr")] subcommand: &str) {
|
fn test_servarr_subcommand_requires_subcommand(#[values("radarr", "sonarr")] subcommand: &str) {
|
||||||
let result = Cli::command().try_get_matches_from(["managarr", subcommand]);
|
let result = Cli::command().try_get_matches_from(["managarr", subcommand]);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert_err!(&result);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
result.unwrap_err().kind(),
|
result.unwrap_err().kind(),
|
||||||
ErrorKind::DisplayHelpOnMissingArgumentOrSubcommand
|
ErrorKind::DisplayHelpOnMissingArgumentOrSubcommand
|
||||||
@@ -45,21 +45,21 @@ mod tests {
|
|||||||
let result =
|
let result =
|
||||||
Cli::command().try_get_matches_from(["managarr", "radarr", "get", "all-indexer-settings"]);
|
Cli::command().try_get_matches_from(["managarr", "radarr", "get", "all-indexer-settings"]);
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_sonarr_subcommand_delegates_to_sonarr() {
|
fn test_sonarr_subcommand_delegates_to_sonarr() {
|
||||||
let result = Cli::command().try_get_matches_from(["managarr", "sonarr", "list", "series"]);
|
let result = Cli::command().try_get_matches_from(["managarr", "sonarr", "list", "series"]);
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_completions_requires_argument() {
|
fn test_completions_requires_argument() {
|
||||||
let result = Cli::command().try_get_matches_from(["managarr", "completions"]);
|
let result = Cli::command().try_get_matches_from(["managarr", "completions"]);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert_err!(&result);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
result.unwrap_err().kind(),
|
result.unwrap_err().kind(),
|
||||||
ErrorKind::DisplayHelpOnMissingArgumentOrSubcommand
|
ErrorKind::DisplayHelpOnMissingArgumentOrSubcommand
|
||||||
@@ -70,7 +70,7 @@ mod tests {
|
|||||||
fn test_completions_invalid_argument() {
|
fn test_completions_invalid_argument() {
|
||||||
let result = Cli::command().try_get_matches_from(["managarr", "completions", "test"]);
|
let result = Cli::command().try_get_matches_from(["managarr", "completions", "test"]);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert_err!(&result);
|
||||||
assert_eq!(result.unwrap_err().kind(), ErrorKind::InvalidValue);
|
assert_eq!(result.unwrap_err().kind(), ErrorKind::InvalidValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -78,7 +78,7 @@ mod tests {
|
|||||||
fn test_completions_satisfied_with_argument() {
|
fn test_completions_satisfied_with_argument() {
|
||||||
let result = Cli::command().try_get_matches_from(["managarr", "completions", "bash"]);
|
let result = Cli::command().try_get_matches_from(["managarr", "completions", "bash"]);
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rstest]
|
#[rstest]
|
||||||
@@ -136,12 +136,12 @@ mod tests {
|
|||||||
json!({"testResponse": "response"}),
|
json!({"testResponse": "response"}),
|
||||||
)))
|
)))
|
||||||
});
|
});
|
||||||
let app_arc = Arc::new(Mutex::new(App::default()));
|
let app_arc = Arc::new(Mutex::new(App::test_default()));
|
||||||
let clear_blocklist_command = RadarrCommand::ClearBlocklist.into();
|
let clear_blocklist_command = RadarrCommand::ClearBlocklist.into();
|
||||||
|
|
||||||
let result = handle_command(&app_arc, clear_blocklist_command, &mut mock_network).await;
|
let result = handle_command(&app_arc, clear_blocklist_command, &mut mock_network).await;
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@@ -167,11 +167,11 @@ mod tests {
|
|||||||
json!({"testResponse": "response"}),
|
json!({"testResponse": "response"}),
|
||||||
)))
|
)))
|
||||||
});
|
});
|
||||||
let app_arc = Arc::new(Mutex::new(App::default()));
|
let app_arc = Arc::new(Mutex::new(App::test_default()));
|
||||||
let clear_blocklist_command = SonarrCommand::ClearBlocklist.into();
|
let clear_blocklist_command = SonarrCommand::ClearBlocklist.into();
|
||||||
|
|
||||||
let result = handle_command(&app_arc, clear_blocklist_command, &mut mock_network).await;
|
let result = handle_command(&app_arc, clear_blocklist_command, &mut mock_network).await;
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use clap::{command, Subcommand};
|
use clap::{Subcommand, command};
|
||||||
use clap_complete::Shell;
|
use clap_complete::Shell;
|
||||||
use radarr::{RadarrCliHandler, RadarrCommand};
|
use radarr::{RadarrCliHandler, RadarrCommand};
|
||||||
use sonarr::{SonarrCliHandler, SonarrCommand};
|
use sonarr::{SonarrCliHandler, SonarrCommand};
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use clap::{arg, command, ArgAction, Subcommand};
|
use clap::{ArgAction, Subcommand, arg, command};
|
||||||
use tokio::sync::Mutex;
|
use tokio::sync::Mutex;
|
||||||
|
|
||||||
use super::RadarrCommand;
|
use super::RadarrCommand;
|
||||||
@@ -10,7 +10,7 @@ use crate::{
|
|||||||
app::App,
|
app::App,
|
||||||
cli::{CliCommandHandler, Command},
|
cli::{CliCommandHandler, Command},
|
||||||
models::radarr_models::{AddMovieBody, AddMovieOptions, MinimumAvailability, MovieMonitor},
|
models::radarr_models::{AddMovieBody, AddMovieOptions, MinimumAvailability, MovieMonitor},
|
||||||
network::{radarr_network::RadarrEvent, NetworkTrait},
|
network::{NetworkTrait, radarr_network::RadarrEvent},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use clap::{error::ErrorKind, CommandFactory, Parser};
|
use clap::{CommandFactory, Parser, error::ErrorKind};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
Cli,
|
||||||
cli::{
|
cli::{
|
||||||
radarr::{add_command_handler::RadarrAddCommand, RadarrCommand},
|
|
||||||
Command,
|
Command,
|
||||||
|
radarr::{RadarrCommand, add_command_handler::RadarrAddCommand},
|
||||||
},
|
},
|
||||||
models::radarr_models::{MinimumAvailability, MovieMonitor},
|
models::radarr_models::{MinimumAvailability, MovieMonitor},
|
||||||
Cli,
|
|
||||||
};
|
};
|
||||||
use pretty_assertions::assert_eq;
|
use pretty_assertions::assert_eq;
|
||||||
|
|
||||||
@@ -32,7 +32,7 @@ mod tests {
|
|||||||
fn test_add_movie_requires_arguments() {
|
fn test_add_movie_requires_arguments() {
|
||||||
let result = Cli::command().try_get_matches_from(["managarr", "radarr", "add", "movie"]);
|
let result = Cli::command().try_get_matches_from(["managarr", "radarr", "add", "movie"]);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert_err!(&result);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
result.unwrap_err().kind(),
|
result.unwrap_err().kind(),
|
||||||
ErrorKind::MissingRequiredArgument
|
ErrorKind::MissingRequiredArgument
|
||||||
@@ -52,7 +52,7 @@ mod tests {
|
|||||||
"1",
|
"1",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert_err!(&result);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
result.unwrap_err().kind(),
|
result.unwrap_err().kind(),
|
||||||
ErrorKind::MissingRequiredArgument
|
ErrorKind::MissingRequiredArgument
|
||||||
@@ -72,7 +72,7 @@ mod tests {
|
|||||||
"/test",
|
"/test",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert_err!(&result);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
result.unwrap_err().kind(),
|
result.unwrap_err().kind(),
|
||||||
ErrorKind::MissingRequiredArgument
|
ErrorKind::MissingRequiredArgument
|
||||||
@@ -92,7 +92,7 @@ mod tests {
|
|||||||
"1",
|
"1",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert_err!(&result);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
result.unwrap_err().kind(),
|
result.unwrap_err().kind(),
|
||||||
ErrorKind::MissingRequiredArgument
|
ErrorKind::MissingRequiredArgument
|
||||||
@@ -117,7 +117,7 @@ mod tests {
|
|||||||
flag,
|
flag,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert_err!(&result);
|
||||||
assert_eq!(result.unwrap_err().kind(), ErrorKind::InvalidValue);
|
assert_eq!(result.unwrap_err().kind(), ErrorKind::InvalidValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -136,7 +136,7 @@ mod tests {
|
|||||||
"1",
|
"1",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -156,7 +156,7 @@ mod tests {
|
|||||||
"test",
|
"test",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert_err!(&result);
|
||||||
assert_eq!(result.unwrap_err().kind(), ErrorKind::InvalidValue);
|
assert_eq!(result.unwrap_err().kind(), ErrorKind::InvalidValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -177,7 +177,7 @@ mod tests {
|
|||||||
"test",
|
"test",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert_err!(&result);
|
||||||
assert_eq!(result.unwrap_err().kind(), ErrorKind::InvalidValue);
|
assert_eq!(result.unwrap_err().kind(), ErrorKind::InvalidValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -207,10 +207,11 @@ mod tests {
|
|||||||
"1",
|
"1",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
if let Some(Command::Radarr(RadarrCommand::Add(add_command))) = result.unwrap().command {
|
let Some(Command::Radarr(RadarrCommand::Add(add_command))) = result.unwrap().command else {
|
||||||
assert_eq!(add_command, expected_args);
|
panic!("Unexpected command type")
|
||||||
}
|
};
|
||||||
|
assert_eq!(add_command, expected_args);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -243,10 +244,11 @@ mod tests {
|
|||||||
"2",
|
"2",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
if let Some(Command::Radarr(RadarrCommand::Add(add_command))) = result.unwrap().command {
|
let Some(Command::Radarr(RadarrCommand::Add(add_command))) = result.unwrap().command else {
|
||||||
assert_eq!(add_command, expected_args);
|
panic!("Unexpected command type")
|
||||||
}
|
};
|
||||||
|
assert_eq!(add_command, expected_args);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -285,10 +287,11 @@ mod tests {
|
|||||||
"--no-search-for-movie",
|
"--no-search-for-movie",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
if let Some(Command::Radarr(RadarrCommand::Add(add_command))) = result.unwrap().command {
|
let Some(Command::Radarr(RadarrCommand::Add(add_command))) = result.unwrap().command else {
|
||||||
assert_eq!(add_command, expected_args);
|
panic!("Unexpected command type")
|
||||||
}
|
};
|
||||||
|
assert_eq!(add_command, expected_args);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -296,7 +299,7 @@ mod tests {
|
|||||||
let result =
|
let result =
|
||||||
Cli::command().try_get_matches_from(["managarr", "radarr", "add", "root-folder"]);
|
Cli::command().try_get_matches_from(["managarr", "radarr", "add", "root-folder"]);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert_err!(&result);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
result.unwrap_err().kind(),
|
result.unwrap_err().kind(),
|
||||||
ErrorKind::MissingRequiredArgument
|
ErrorKind::MissingRequiredArgument
|
||||||
@@ -318,18 +321,19 @@ mod tests {
|
|||||||
"/nfs/test",
|
"/nfs/test",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
|
|
||||||
if let Some(Command::Radarr(RadarrCommand::Add(add_command))) = result.unwrap().command {
|
let Some(Command::Radarr(RadarrCommand::Add(add_command))) = result.unwrap().command else {
|
||||||
assert_eq!(add_command, expected_args);
|
panic!("Unexpected command type")
|
||||||
}
|
};
|
||||||
|
assert_eq!(add_command, expected_args);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_add_tag_requires_arguments() {
|
fn test_add_tag_requires_arguments() {
|
||||||
let result = Cli::command().try_get_matches_from(["managarr", "radarr", "add", "tag"]);
|
let result = Cli::command().try_get_matches_from(["managarr", "radarr", "add", "tag"]);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert_err!(&result);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
result.unwrap_err().kind(),
|
result.unwrap_err().kind(),
|
||||||
ErrorKind::MissingRequiredArgument
|
ErrorKind::MissingRequiredArgument
|
||||||
@@ -344,11 +348,12 @@ mod tests {
|
|||||||
|
|
||||||
let result = Cli::try_parse_from(["managarr", "radarr", "add", "tag", "--name", "test"]);
|
let result = Cli::try_parse_from(["managarr", "radarr", "add", "tag", "--name", "test"]);
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
|
|
||||||
if let Some(Command::Radarr(RadarrCommand::Add(add_command))) = result.unwrap().command {
|
let Some(Command::Radarr(RadarrCommand::Add(add_command))) = result.unwrap().command else {
|
||||||
assert_eq!(add_command, expected_args);
|
panic!("Unexpected command type")
|
||||||
}
|
};
|
||||||
|
assert_eq!(add_command, expected_args);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -357,12 +362,12 @@ mod tests {
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
app::App,
|
app::App,
|
||||||
cli::{radarr::add_command_handler::RadarrAddCommandHandler, CliCommandHandler},
|
cli::{CliCommandHandler, radarr::add_command_handler::RadarrAddCommandHandler},
|
||||||
models::{
|
models::{
|
||||||
radarr_models::{AddMovieBody, AddMovieOptions, RadarrSerdeable},
|
|
||||||
Serdeable,
|
Serdeable,
|
||||||
|
radarr_models::{AddMovieBody, AddMovieOptions, RadarrSerdeable},
|
||||||
},
|
},
|
||||||
network::{radarr_network::RadarrEvent, MockNetworkTrait, NetworkEvent},
|
network::{MockNetworkTrait, NetworkEvent, radarr_network::RadarrEvent},
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
@@ -400,7 +405,7 @@ mod tests {
|
|||||||
json!({"testResponse": "response"}),
|
json!({"testResponse": "response"}),
|
||||||
)))
|
)))
|
||||||
});
|
});
|
||||||
let app_arc = Arc::new(Mutex::new(App::default()));
|
let app_arc = Arc::new(Mutex::new(App::test_default()));
|
||||||
let add_movie_command = RadarrAddCommand::Movie {
|
let add_movie_command = RadarrAddCommand::Movie {
|
||||||
tmdb_id: 1,
|
tmdb_id: 1,
|
||||||
root_folder_path: "/test".to_owned(),
|
root_folder_path: "/test".to_owned(),
|
||||||
@@ -416,7 +421,7 @@ mod tests {
|
|||||||
.handle()
|
.handle()
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@@ -437,7 +442,7 @@ mod tests {
|
|||||||
json!({"testResponse": "response"}),
|
json!({"testResponse": "response"}),
|
||||||
)))
|
)))
|
||||||
});
|
});
|
||||||
let app_arc = Arc::new(Mutex::new(App::default()));
|
let app_arc = Arc::new(Mutex::new(App::test_default()));
|
||||||
let add_root_folder_command = RadarrAddCommand::RootFolder {
|
let add_root_folder_command = RadarrAddCommand::RootFolder {
|
||||||
root_folder_path: expected_root_folder_path,
|
root_folder_path: expected_root_folder_path,
|
||||||
};
|
};
|
||||||
@@ -447,7 +452,7 @@ mod tests {
|
|||||||
.handle()
|
.handle()
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@@ -465,7 +470,7 @@ mod tests {
|
|||||||
json!({"testResponse": "response"}),
|
json!({"testResponse": "response"}),
|
||||||
)))
|
)))
|
||||||
});
|
});
|
||||||
let app_arc = Arc::new(Mutex::new(App::default()));
|
let app_arc = Arc::new(Mutex::new(App::test_default()));
|
||||||
let add_tag_command = RadarrAddCommand::Tag {
|
let add_tag_command = RadarrAddCommand::Tag {
|
||||||
name: expected_tag_name,
|
name: expected_tag_name,
|
||||||
};
|
};
|
||||||
@@ -474,7 +479,7 @@ mod tests {
|
|||||||
.handle()
|
.handle()
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ use crate::{
|
|||||||
app::App,
|
app::App,
|
||||||
cli::{CliCommandHandler, Command},
|
cli::{CliCommandHandler, Command},
|
||||||
models::radarr_models::DeleteMovieParams,
|
models::radarr_models::DeleteMovieParams,
|
||||||
network::{radarr_network::RadarrEvent, NetworkTrait},
|
network::{NetworkTrait, radarr_network::RadarrEvent},
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::RadarrCommand;
|
use super::RadarrCommand;
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::{
|
use crate::{
|
||||||
cli::{
|
|
||||||
radarr::{delete_command_handler::RadarrDeleteCommand, RadarrCommand},
|
|
||||||
Command,
|
|
||||||
},
|
|
||||||
Cli,
|
Cli,
|
||||||
|
cli::{
|
||||||
|
Command,
|
||||||
|
radarr::{RadarrCommand, delete_command_handler::RadarrDeleteCommand},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
use clap::{error::ErrorKind, CommandFactory, Parser};
|
use clap::{CommandFactory, Parser, error::ErrorKind};
|
||||||
use pretty_assertions::assert_eq;
|
use pretty_assertions::assert_eq;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -30,7 +30,7 @@ mod tests {
|
|||||||
let result =
|
let result =
|
||||||
Cli::command().try_get_matches_from(["managarr", "radarr", "delete", "blocklist-item"]);
|
Cli::command().try_get_matches_from(["managarr", "radarr", "delete", "blocklist-item"]);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert_err!(&result);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
result.unwrap_err().kind(),
|
result.unwrap_err().kind(),
|
||||||
ErrorKind::MissingRequiredArgument
|
ErrorKind::MissingRequiredArgument
|
||||||
@@ -52,12 +52,13 @@ mod tests {
|
|||||||
"1",
|
"1",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
|
|
||||||
if let Some(Command::Radarr(RadarrCommand::Delete(delete_command))) = result.unwrap().command
|
let Some(Command::Radarr(RadarrCommand::Delete(delete_command))) = result.unwrap().command
|
||||||
{
|
else {
|
||||||
assert_eq!(delete_command, expected_args);
|
panic!("Unexpected command type");
|
||||||
}
|
};
|
||||||
|
assert_eq!(delete_command, expected_args);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -65,7 +66,7 @@ mod tests {
|
|||||||
let result =
|
let result =
|
||||||
Cli::command().try_get_matches_from(["managarr", "radarr", "delete", "download"]);
|
Cli::command().try_get_matches_from(["managarr", "radarr", "delete", "download"]);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert_err!(&result);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
result.unwrap_err().kind(),
|
result.unwrap_err().kind(),
|
||||||
ErrorKind::MissingRequiredArgument
|
ErrorKind::MissingRequiredArgument
|
||||||
@@ -85,19 +86,20 @@ mod tests {
|
|||||||
"1",
|
"1",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
|
|
||||||
if let Some(Command::Radarr(RadarrCommand::Delete(delete_command))) = result.unwrap().command
|
let Some(Command::Radarr(RadarrCommand::Delete(delete_command))) = result.unwrap().command
|
||||||
{
|
else {
|
||||||
assert_eq!(delete_command, expected_args);
|
panic!("Unexpected command type");
|
||||||
}
|
};
|
||||||
|
assert_eq!(delete_command, expected_args);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_delete_indexer_requires_arguments() {
|
fn test_delete_indexer_requires_arguments() {
|
||||||
let result = Cli::command().try_get_matches_from(["managarr", "radarr", "delete", "indexer"]);
|
let result = Cli::command().try_get_matches_from(["managarr", "radarr", "delete", "indexer"]);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert_err!(&result);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
result.unwrap_err().kind(),
|
result.unwrap_err().kind(),
|
||||||
ErrorKind::MissingRequiredArgument
|
ErrorKind::MissingRequiredArgument
|
||||||
@@ -117,19 +119,20 @@ mod tests {
|
|||||||
"1",
|
"1",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
|
|
||||||
if let Some(Command::Radarr(RadarrCommand::Delete(delete_command))) = result.unwrap().command
|
let Some(Command::Radarr(RadarrCommand::Delete(delete_command))) = result.unwrap().command
|
||||||
{
|
else {
|
||||||
assert_eq!(delete_command, expected_args);
|
panic!("Unexpected command type");
|
||||||
}
|
};
|
||||||
|
assert_eq!(delete_command, expected_args);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_delete_movie_requires_arguments() {
|
fn test_delete_movie_requires_arguments() {
|
||||||
let result = Cli::command().try_get_matches_from(["managarr", "radarr", "delete", "movie"]);
|
let result = Cli::command().try_get_matches_from(["managarr", "radarr", "delete", "movie"]);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert_err!(&result);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
result.unwrap_err().kind(),
|
result.unwrap_err().kind(),
|
||||||
ErrorKind::MissingRequiredArgument
|
ErrorKind::MissingRequiredArgument
|
||||||
@@ -147,12 +150,13 @@ mod tests {
|
|||||||
let result =
|
let result =
|
||||||
Cli::try_parse_from(["managarr", "radarr", "delete", "movie", "--movie-id", "1"]);
|
Cli::try_parse_from(["managarr", "radarr", "delete", "movie", "--movie-id", "1"]);
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
|
|
||||||
if let Some(Command::Radarr(RadarrCommand::Delete(delete_command))) = result.unwrap().command
|
let Some(Command::Radarr(RadarrCommand::Delete(delete_command))) = result.unwrap().command
|
||||||
{
|
else {
|
||||||
assert_eq!(delete_command, expected_args);
|
panic!("Unexpected command type");
|
||||||
}
|
};
|
||||||
|
assert_eq!(delete_command, expected_args);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -174,12 +178,13 @@ mod tests {
|
|||||||
"--add-list-exclusion",
|
"--add-list-exclusion",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
|
|
||||||
if let Some(Command::Radarr(RadarrCommand::Delete(delete_command))) = result.unwrap().command
|
let Some(Command::Radarr(RadarrCommand::Delete(delete_command))) = result.unwrap().command
|
||||||
{
|
else {
|
||||||
assert_eq!(delete_command, expected_args);
|
panic!("Unexpected command type");
|
||||||
}
|
};
|
||||||
|
assert_eq!(delete_command, expected_args);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -187,7 +192,7 @@ mod tests {
|
|||||||
let result =
|
let result =
|
||||||
Cli::command().try_get_matches_from(["managarr", "radarr", "delete", "root-folder"]);
|
Cli::command().try_get_matches_from(["managarr", "radarr", "delete", "root-folder"]);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert_err!(&result);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
result.unwrap_err().kind(),
|
result.unwrap_err().kind(),
|
||||||
ErrorKind::MissingRequiredArgument
|
ErrorKind::MissingRequiredArgument
|
||||||
@@ -207,19 +212,20 @@ mod tests {
|
|||||||
"1",
|
"1",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
|
|
||||||
if let Some(Command::Radarr(RadarrCommand::Delete(delete_command))) = result.unwrap().command
|
let Some(Command::Radarr(RadarrCommand::Delete(delete_command))) = result.unwrap().command
|
||||||
{
|
else {
|
||||||
assert_eq!(delete_command, expected_args);
|
panic!("Unexpected command type");
|
||||||
}
|
};
|
||||||
|
assert_eq!(delete_command, expected_args);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_delete_tag_requires_arguments() {
|
fn test_delete_tag_requires_arguments() {
|
||||||
let result = Cli::command().try_get_matches_from(["managarr", "radarr", "delete", "tag"]);
|
let result = Cli::command().try_get_matches_from(["managarr", "radarr", "delete", "tag"]);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert_err!(&result);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
result.unwrap_err().kind(),
|
result.unwrap_err().kind(),
|
||||||
ErrorKind::MissingRequiredArgument
|
ErrorKind::MissingRequiredArgument
|
||||||
@@ -232,12 +238,13 @@ mod tests {
|
|||||||
|
|
||||||
let result = Cli::try_parse_from(["managarr", "radarr", "delete", "tag", "--tag-id", "1"]);
|
let result = Cli::try_parse_from(["managarr", "radarr", "delete", "tag", "--tag-id", "1"]);
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
|
|
||||||
if let Some(Command::Radarr(RadarrCommand::Delete(delete_command))) = result.unwrap().command
|
let Some(Command::Radarr(RadarrCommand::Delete(delete_command))) = result.unwrap().command
|
||||||
{
|
else {
|
||||||
assert_eq!(delete_command, expected_args);
|
panic!("Unexpected command type");
|
||||||
}
|
};
|
||||||
|
assert_eq!(delete_command, expected_args);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -251,14 +258,14 @@ mod tests {
|
|||||||
use crate::{
|
use crate::{
|
||||||
app::App,
|
app::App,
|
||||||
cli::{
|
cli::{
|
||||||
radarr::delete_command_handler::{RadarrDeleteCommand, RadarrDeleteCommandHandler},
|
|
||||||
CliCommandHandler,
|
CliCommandHandler,
|
||||||
|
radarr::delete_command_handler::{RadarrDeleteCommand, RadarrDeleteCommandHandler},
|
||||||
},
|
},
|
||||||
models::{
|
models::{
|
||||||
radarr_models::{DeleteMovieParams, RadarrSerdeable},
|
|
||||||
Serdeable,
|
Serdeable,
|
||||||
|
radarr_models::{DeleteMovieParams, RadarrSerdeable},
|
||||||
},
|
},
|
||||||
network::{radarr_network::RadarrEvent, MockNetworkTrait, NetworkEvent},
|
network::{MockNetworkTrait, NetworkEvent, radarr_network::RadarrEvent},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@@ -276,7 +283,7 @@ mod tests {
|
|||||||
json!({"testResponse": "response"}),
|
json!({"testResponse": "response"}),
|
||||||
)))
|
)))
|
||||||
});
|
});
|
||||||
let app_arc = Arc::new(Mutex::new(App::default()));
|
let app_arc = Arc::new(Mutex::new(App::test_default()));
|
||||||
let delete_blocklist_item_command = RadarrDeleteCommand::BlocklistItem {
|
let delete_blocklist_item_command = RadarrDeleteCommand::BlocklistItem {
|
||||||
blocklist_item_id: 1,
|
blocklist_item_id: 1,
|
||||||
};
|
};
|
||||||
@@ -289,7 +296,7 @@ mod tests {
|
|||||||
.handle()
|
.handle()
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@@ -307,7 +314,7 @@ mod tests {
|
|||||||
json!({"testResponse": "response"}),
|
json!({"testResponse": "response"}),
|
||||||
)))
|
)))
|
||||||
});
|
});
|
||||||
let app_arc = Arc::new(Mutex::new(App::default()));
|
let app_arc = Arc::new(Mutex::new(App::test_default()));
|
||||||
let delete_download_command = RadarrDeleteCommand::Download { download_id: 1 };
|
let delete_download_command = RadarrDeleteCommand::Download { download_id: 1 };
|
||||||
|
|
||||||
let result =
|
let result =
|
||||||
@@ -315,7 +322,7 @@ mod tests {
|
|||||||
.handle()
|
.handle()
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@@ -333,7 +340,7 @@ mod tests {
|
|||||||
json!({"testResponse": "response"}),
|
json!({"testResponse": "response"}),
|
||||||
)))
|
)))
|
||||||
});
|
});
|
||||||
let app_arc = Arc::new(Mutex::new(App::default()));
|
let app_arc = Arc::new(Mutex::new(App::test_default()));
|
||||||
let delete_indexer_command = RadarrDeleteCommand::Indexer { indexer_id: 1 };
|
let delete_indexer_command = RadarrDeleteCommand::Indexer { indexer_id: 1 };
|
||||||
|
|
||||||
let result =
|
let result =
|
||||||
@@ -341,7 +348,7 @@ mod tests {
|
|||||||
.handle()
|
.handle()
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@@ -363,7 +370,7 @@ mod tests {
|
|||||||
json!({"testResponse": "response"}),
|
json!({"testResponse": "response"}),
|
||||||
)))
|
)))
|
||||||
});
|
});
|
||||||
let app_arc = Arc::new(Mutex::new(App::default()));
|
let app_arc = Arc::new(Mutex::new(App::test_default()));
|
||||||
let delete_movie_command = RadarrDeleteCommand::Movie {
|
let delete_movie_command = RadarrDeleteCommand::Movie {
|
||||||
movie_id: 1,
|
movie_id: 1,
|
||||||
delete_files_from_disk: true,
|
delete_files_from_disk: true,
|
||||||
@@ -375,7 +382,7 @@ mod tests {
|
|||||||
.handle()
|
.handle()
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@@ -393,7 +400,7 @@ mod tests {
|
|||||||
json!({"testResponse": "response"}),
|
json!({"testResponse": "response"}),
|
||||||
)))
|
)))
|
||||||
});
|
});
|
||||||
let app_arc = Arc::new(Mutex::new(App::default()));
|
let app_arc = Arc::new(Mutex::new(App::test_default()));
|
||||||
let delete_root_folder_command = RadarrDeleteCommand::RootFolder { root_folder_id: 1 };
|
let delete_root_folder_command = RadarrDeleteCommand::RootFolder { root_folder_id: 1 };
|
||||||
|
|
||||||
let result =
|
let result =
|
||||||
@@ -401,7 +408,7 @@ mod tests {
|
|||||||
.handle()
|
.handle()
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@@ -419,7 +426,7 @@ mod tests {
|
|||||||
json!({"testResponse": "response"}),
|
json!({"testResponse": "response"}),
|
||||||
)))
|
)))
|
||||||
});
|
});
|
||||||
let app_arc = Arc::new(Mutex::new(App::default()));
|
let app_arc = Arc::new(Mutex::new(App::test_default()));
|
||||||
let delete_tag_command = RadarrDeleteCommand::Tag { tag_id: 1 };
|
let delete_tag_command = RadarrDeleteCommand::Tag { tag_id: 1 };
|
||||||
|
|
||||||
let result =
|
let result =
|
||||||
@@ -427,7 +434,7 @@ mod tests {
|
|||||||
.handle()
|
.handle()
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,15 +6,15 @@ use tokio::sync::Mutex;
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
app::App,
|
app::App,
|
||||||
cli::{mutex_flags_or_default, mutex_flags_or_option, CliCommandHandler, Command},
|
cli::{CliCommandHandler, Command, mutex_flags_or_default, mutex_flags_or_option},
|
||||||
models::{
|
models::{
|
||||||
|
Serdeable,
|
||||||
radarr_models::{
|
radarr_models::{
|
||||||
EditCollectionParams, EditMovieParams, IndexerSettings, MinimumAvailability, RadarrSerdeable,
|
EditCollectionParams, EditMovieParams, IndexerSettings, MinimumAvailability, RadarrSerdeable,
|
||||||
},
|
},
|
||||||
servarr_models::EditIndexerParams,
|
servarr_models::EditIndexerParams,
|
||||||
Serdeable,
|
|
||||||
},
|
},
|
||||||
network::{radarr_network::RadarrEvent, NetworkTrait},
|
network::{NetworkTrait, radarr_network::RadarrEvent},
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::RadarrCommand;
|
use super::RadarrCommand;
|
||||||
@@ -379,13 +379,7 @@ impl<'a, 'b> CliCommandHandler<'a, 'b, RadarrEditCommand> for RadarrEditCommandH
|
|||||||
rss_sync_interval: rss_sync_interval
|
rss_sync_interval: rss_sync_interval
|
||||||
.unwrap_or(previous_indexer_settings.rss_sync_interval),
|
.unwrap_or(previous_indexer_settings.rss_sync_interval),
|
||||||
whitelisted_hardcoded_subs: whitelisted_subtitle_tags
|
whitelisted_hardcoded_subs: whitelisted_subtitle_tags
|
||||||
.clone()
|
.unwrap_or(previous_indexer_settings.whitelisted_hardcoded_subs.text)
|
||||||
.unwrap_or_else(|| {
|
|
||||||
previous_indexer_settings
|
|
||||||
.whitelisted_hardcoded_subs
|
|
||||||
.text
|
|
||||||
.clone()
|
|
||||||
})
|
|
||||||
.into(),
|
.into(),
|
||||||
};
|
};
|
||||||
self
|
self
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::{
|
use crate::{
|
||||||
cli::{
|
|
||||||
radarr::{edit_command_handler::RadarrEditCommand, RadarrCommand},
|
|
||||||
Command,
|
|
||||||
},
|
|
||||||
Cli,
|
Cli,
|
||||||
|
cli::{
|
||||||
|
Command,
|
||||||
|
radarr::{RadarrCommand, edit_command_handler::RadarrEditCommand},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
use clap::{error::ErrorKind, CommandFactory, Parser};
|
use clap::{CommandFactory, Parser, error::ErrorKind};
|
||||||
use pretty_assertions::assert_eq;
|
use pretty_assertions::assert_eq;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -42,7 +42,7 @@ mod tests {
|
|||||||
let result =
|
let result =
|
||||||
Cli::command().try_get_matches_from(["managarr", "radarr", "edit", "all-indexer-settings"]);
|
Cli::command().try_get_matches_from(["managarr", "radarr", "edit", "all-indexer-settings"]);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert_err!(&result);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
result.unwrap_err().kind(),
|
result.unwrap_err().kind(),
|
||||||
ErrorKind::MissingRequiredArgument
|
ErrorKind::MissingRequiredArgument
|
||||||
@@ -60,7 +60,7 @@ mod tests {
|
|||||||
"--disable-allow-hardcoded-subs",
|
"--disable-allow-hardcoded-subs",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert_err!(&result);
|
||||||
assert_eq!(result.unwrap_err().kind(), ErrorKind::ArgumentConflict);
|
assert_eq!(result.unwrap_err().kind(), ErrorKind::ArgumentConflict);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -75,7 +75,7 @@ mod tests {
|
|||||||
"--disable-prefer-indexer-flags",
|
"--disable-prefer-indexer-flags",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert_err!(&result);
|
||||||
assert_eq!(result.unwrap_err().kind(), ErrorKind::ArgumentConflict);
|
assert_eq!(result.unwrap_err().kind(), ErrorKind::ArgumentConflict);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -99,7 +99,7 @@ mod tests {
|
|||||||
flag,
|
flag,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert_err!(&result);
|
||||||
assert_eq!(result.unwrap_err().kind(), ErrorKind::InvalidValue);
|
assert_eq!(result.unwrap_err().kind(), ErrorKind::InvalidValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -126,11 +126,12 @@ mod tests {
|
|||||||
"1",
|
"1",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
|
|
||||||
if let Some(Command::Radarr(RadarrCommand::Edit(edit_command))) = result.unwrap().command {
|
let Some(Command::Radarr(RadarrCommand::Edit(edit_command))) = result.unwrap().command else {
|
||||||
assert_eq!(edit_command, expected_args);
|
panic!("Unexpected command type");
|
||||||
}
|
};
|
||||||
|
assert_eq!(edit_command, expected_args);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -168,11 +169,12 @@ mod tests {
|
|||||||
"test",
|
"test",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
|
|
||||||
if let Some(Command::Radarr(RadarrCommand::Edit(edit_command))) = result.unwrap().command {
|
let Some(Command::Radarr(RadarrCommand::Edit(edit_command))) = result.unwrap().command else {
|
||||||
assert_eq!(edit_command, expected_args);
|
panic!("Unexpected command type");
|
||||||
}
|
};
|
||||||
|
assert_eq!(edit_command, expected_args);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -180,7 +182,7 @@ mod tests {
|
|||||||
let result =
|
let result =
|
||||||
Cli::command().try_get_matches_from(["managarr", "radarr", "edit", "collection"]);
|
Cli::command().try_get_matches_from(["managarr", "radarr", "edit", "collection"]);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert_err!(&result);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
result.unwrap_err().kind(),
|
result.unwrap_err().kind(),
|
||||||
ErrorKind::MissingRequiredArgument
|
ErrorKind::MissingRequiredArgument
|
||||||
@@ -198,7 +200,7 @@ mod tests {
|
|||||||
"1",
|
"1",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert_err!(&result);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
result.unwrap_err().kind(),
|
result.unwrap_err().kind(),
|
||||||
ErrorKind::MissingRequiredArgument
|
ErrorKind::MissingRequiredArgument
|
||||||
@@ -218,7 +220,7 @@ mod tests {
|
|||||||
"--disable-monitoring",
|
"--disable-monitoring",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert_err!(&result);
|
||||||
assert_eq!(result.unwrap_err().kind(), ErrorKind::ArgumentConflict);
|
assert_eq!(result.unwrap_err().kind(), ErrorKind::ArgumentConflict);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -235,7 +237,7 @@ mod tests {
|
|||||||
"--disable-search-on-add",
|
"--disable-search-on-add",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert_err!(&result);
|
||||||
assert_eq!(result.unwrap_err().kind(), ErrorKind::ArgumentConflict);
|
assert_eq!(result.unwrap_err().kind(), ErrorKind::ArgumentConflict);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -252,7 +254,7 @@ mod tests {
|
|||||||
"test",
|
"test",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert_err!(&result);
|
||||||
assert_eq!(result.unwrap_err().kind(), ErrorKind::InvalidValue);
|
assert_eq!(result.unwrap_err().kind(), ErrorKind::InvalidValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -270,7 +272,7 @@ mod tests {
|
|||||||
flag,
|
flag,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert_err!(&result);
|
||||||
assert_eq!(result.unwrap_err().kind(), ErrorKind::InvalidValue);
|
assert_eq!(result.unwrap_err().kind(), ErrorKind::InvalidValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -298,11 +300,12 @@ mod tests {
|
|||||||
"/test",
|
"/test",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
|
|
||||||
if let Some(Command::Radarr(RadarrCommand::Edit(edit_command))) = result.unwrap().command {
|
let Some(Command::Radarr(RadarrCommand::Edit(edit_command))) = result.unwrap().command else {
|
||||||
assert_eq!(edit_command, expected_args);
|
panic!("Unexpected command type");
|
||||||
}
|
};
|
||||||
|
assert_eq!(edit_command, expected_args);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -334,18 +337,19 @@ mod tests {
|
|||||||
"--search-on-add",
|
"--search-on-add",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
|
|
||||||
if let Some(Command::Radarr(RadarrCommand::Edit(edit_command))) = result.unwrap().command {
|
let Some(Command::Radarr(RadarrCommand::Edit(edit_command))) = result.unwrap().command else {
|
||||||
assert_eq!(edit_command, expected_args);
|
panic!("Unexpected command type");
|
||||||
}
|
};
|
||||||
|
assert_eq!(edit_command, expected_args);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_edit_indexer_requires_arguments() {
|
fn test_edit_indexer_requires_arguments() {
|
||||||
let result = Cli::command().try_get_matches_from(["managarr", "radarr", "edit", "indexer"]);
|
let result = Cli::command().try_get_matches_from(["managarr", "radarr", "edit", "indexer"]);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert_err!(&result);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
result.unwrap_err().kind(),
|
result.unwrap_err().kind(),
|
||||||
ErrorKind::MissingRequiredArgument
|
ErrorKind::MissingRequiredArgument
|
||||||
@@ -363,7 +367,7 @@ mod tests {
|
|||||||
"1",
|
"1",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert_err!(&result);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
result.unwrap_err().kind(),
|
result.unwrap_err().kind(),
|
||||||
ErrorKind::MissingRequiredArgument
|
ErrorKind::MissingRequiredArgument
|
||||||
@@ -383,7 +387,7 @@ mod tests {
|
|||||||
"--disable-rss",
|
"--disable-rss",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert_err!(&result);
|
||||||
assert_eq!(result.unwrap_err().kind(), ErrorKind::ArgumentConflict);
|
assert_eq!(result.unwrap_err().kind(), ErrorKind::ArgumentConflict);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -400,7 +404,7 @@ mod tests {
|
|||||||
"--disable-automatic-search",
|
"--disable-automatic-search",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert_err!(&result);
|
||||||
assert_eq!(result.unwrap_err().kind(), ErrorKind::ArgumentConflict);
|
assert_eq!(result.unwrap_err().kind(), ErrorKind::ArgumentConflict);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -417,7 +421,7 @@ mod tests {
|
|||||||
"--disable-interactive-search",
|
"--disable-interactive-search",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert_err!(&result);
|
||||||
assert_eq!(result.unwrap_err().kind(), ErrorKind::ArgumentConflict);
|
assert_eq!(result.unwrap_err().kind(), ErrorKind::ArgumentConflict);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -435,7 +439,7 @@ mod tests {
|
|||||||
"--clear-tags",
|
"--clear-tags",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert_err!(&result);
|
||||||
assert_eq!(result.unwrap_err().kind(), ErrorKind::ArgumentConflict);
|
assert_eq!(result.unwrap_err().kind(), ErrorKind::ArgumentConflict);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -453,7 +457,7 @@ mod tests {
|
|||||||
flag,
|
flag,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert_err!(&result);
|
||||||
assert_eq!(result.unwrap_err().kind(), ErrorKind::InvalidValue);
|
assert_eq!(result.unwrap_err().kind(), ErrorKind::InvalidValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -487,11 +491,12 @@ mod tests {
|
|||||||
"Test",
|
"Test",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
|
|
||||||
if let Some(Command::Radarr(RadarrCommand::Edit(edit_command))) = result.unwrap().command {
|
let Some(Command::Radarr(RadarrCommand::Edit(edit_command))) = result.unwrap().command else {
|
||||||
assert_eq!(edit_command, expected_args);
|
panic!("Unexpected command type");
|
||||||
}
|
};
|
||||||
|
assert_eq!(edit_command, expected_args);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -526,11 +531,12 @@ mod tests {
|
|||||||
"2",
|
"2",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
|
|
||||||
if let Some(Command::Radarr(RadarrCommand::Edit(edit_command))) = result.unwrap().command {
|
let Some(Command::Radarr(RadarrCommand::Edit(edit_command))) = result.unwrap().command else {
|
||||||
assert_eq!(edit_command, expected_args);
|
panic!("Unexpected command type");
|
||||||
}
|
};
|
||||||
|
assert_eq!(edit_command, expected_args);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -578,18 +584,19 @@ mod tests {
|
|||||||
"25",
|
"25",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
|
|
||||||
if let Some(Command::Radarr(RadarrCommand::Edit(edit_command))) = result.unwrap().command {
|
let Some(Command::Radarr(RadarrCommand::Edit(edit_command))) = result.unwrap().command else {
|
||||||
assert_eq!(edit_command, expected_args);
|
panic!("Unexpected command type");
|
||||||
}
|
};
|
||||||
|
assert_eq!(edit_command, expected_args);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_edit_movie_requires_arguments() {
|
fn test_edit_movie_requires_arguments() {
|
||||||
let result = Cli::command().try_get_matches_from(["managarr", "radarr", "edit", "movie"]);
|
let result = Cli::command().try_get_matches_from(["managarr", "radarr", "edit", "movie"]);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert_err!(&result);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
result.unwrap_err().kind(),
|
result.unwrap_err().kind(),
|
||||||
ErrorKind::MissingRequiredArgument
|
ErrorKind::MissingRequiredArgument
|
||||||
@@ -607,7 +614,7 @@ mod tests {
|
|||||||
"1",
|
"1",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert_err!(&result);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
result.unwrap_err().kind(),
|
result.unwrap_err().kind(),
|
||||||
ErrorKind::MissingRequiredArgument
|
ErrorKind::MissingRequiredArgument
|
||||||
@@ -627,7 +634,7 @@ mod tests {
|
|||||||
"--disable-monitoring",
|
"--disable-monitoring",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert_err!(&result);
|
||||||
assert_eq!(result.unwrap_err().kind(), ErrorKind::ArgumentConflict);
|
assert_eq!(result.unwrap_err().kind(), ErrorKind::ArgumentConflict);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -645,7 +652,7 @@ mod tests {
|
|||||||
"--clear-tags",
|
"--clear-tags",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert_err!(&result);
|
||||||
assert_eq!(result.unwrap_err().kind(), ErrorKind::ArgumentConflict);
|
assert_eq!(result.unwrap_err().kind(), ErrorKind::ArgumentConflict);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -669,7 +676,7 @@ mod tests {
|
|||||||
flag,
|
flag,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert_err!(&result);
|
||||||
assert_eq!(result.unwrap_err().kind(), ErrorKind::InvalidValue);
|
assert_eq!(result.unwrap_err().kind(), ErrorKind::InvalidValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -686,7 +693,7 @@ mod tests {
|
|||||||
"test",
|
"test",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert_err!(&result);
|
||||||
assert_eq!(result.unwrap_err().kind(), ErrorKind::InvalidValue);
|
assert_eq!(result.unwrap_err().kind(), ErrorKind::InvalidValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -714,11 +721,12 @@ mod tests {
|
|||||||
"/nfs/test",
|
"/nfs/test",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
|
|
||||||
if let Some(Command::Radarr(RadarrCommand::Edit(edit_command))) = result.unwrap().command {
|
let Some(Command::Radarr(RadarrCommand::Edit(edit_command))) = result.unwrap().command else {
|
||||||
assert_eq!(edit_command, expected_args);
|
panic!("Unexpected command type");
|
||||||
}
|
};
|
||||||
|
assert_eq!(edit_command, expected_args);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -747,11 +755,12 @@ mod tests {
|
|||||||
"2",
|
"2",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
|
|
||||||
if let Some(Command::Radarr(RadarrCommand::Edit(edit_command))) = result.unwrap().command {
|
let Some(Command::Radarr(RadarrCommand::Edit(edit_command))) = result.unwrap().command else {
|
||||||
assert_eq!(edit_command, expected_args);
|
panic!("Unexpected command type");
|
||||||
}
|
};
|
||||||
|
assert_eq!(edit_command, expected_args);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -787,11 +796,12 @@ mod tests {
|
|||||||
"2",
|
"2",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
|
|
||||||
if let Some(Command::Radarr(RadarrCommand::Edit(edit_command))) = result.unwrap().command {
|
let Some(Command::Radarr(RadarrCommand::Edit(edit_command))) = result.unwrap().command else {
|
||||||
assert_eq!(edit_command, expected_args);
|
panic!("Unexpected command type");
|
||||||
}
|
};
|
||||||
|
assert_eq!(edit_command, expected_args);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -805,18 +815,18 @@ mod tests {
|
|||||||
use crate::{
|
use crate::{
|
||||||
app::App,
|
app::App,
|
||||||
cli::{
|
cli::{
|
||||||
radarr::edit_command_handler::{RadarrEditCommand, RadarrEditCommandHandler},
|
|
||||||
CliCommandHandler,
|
CliCommandHandler,
|
||||||
|
radarr::edit_command_handler::{RadarrEditCommand, RadarrEditCommandHandler},
|
||||||
},
|
},
|
||||||
models::{
|
models::{
|
||||||
|
Serdeable,
|
||||||
radarr_models::{
|
radarr_models::{
|
||||||
EditCollectionParams, EditMovieParams, IndexerSettings, MinimumAvailability,
|
EditCollectionParams, EditMovieParams, IndexerSettings, MinimumAvailability,
|
||||||
RadarrSerdeable,
|
RadarrSerdeable,
|
||||||
},
|
},
|
||||||
servarr_models::EditIndexerParams,
|
servarr_models::EditIndexerParams,
|
||||||
Serdeable,
|
|
||||||
},
|
},
|
||||||
network::{radarr_network::RadarrEvent, MockNetworkTrait, NetworkEvent},
|
network::{MockNetworkTrait, NetworkEvent, radarr_network::RadarrEvent},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@@ -865,7 +875,7 @@ mod tests {
|
|||||||
json!({"testResponse": "response"}),
|
json!({"testResponse": "response"}),
|
||||||
)))
|
)))
|
||||||
});
|
});
|
||||||
let app_arc = Arc::new(Mutex::new(App::default()));
|
let app_arc = Arc::new(Mutex::new(App::test_default()));
|
||||||
let edit_all_indexer_settings_command = RadarrEditCommand::AllIndexerSettings {
|
let edit_all_indexer_settings_command = RadarrEditCommand::AllIndexerSettings {
|
||||||
allow_hardcoded_subs: true,
|
allow_hardcoded_subs: true,
|
||||||
disable_allow_hardcoded_subs: false,
|
disable_allow_hardcoded_subs: false,
|
||||||
@@ -887,7 +897,7 @@ mod tests {
|
|||||||
.handle()
|
.handle()
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@@ -936,7 +946,7 @@ mod tests {
|
|||||||
json!({"testResponse": "response"}),
|
json!({"testResponse": "response"}),
|
||||||
)))
|
)))
|
||||||
});
|
});
|
||||||
let app_arc = Arc::new(Mutex::new(App::default()));
|
let app_arc = Arc::new(Mutex::new(App::test_default()));
|
||||||
let edit_all_indexer_settings_command = RadarrEditCommand::AllIndexerSettings {
|
let edit_all_indexer_settings_command = RadarrEditCommand::AllIndexerSettings {
|
||||||
allow_hardcoded_subs: false,
|
allow_hardcoded_subs: false,
|
||||||
disable_allow_hardcoded_subs: true,
|
disable_allow_hardcoded_subs: true,
|
||||||
@@ -958,12 +968,12 @@ mod tests {
|
|||||||
.handle()
|
.handle()
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_handle_edit_all_indexer_settings_command_unprovided_values_default_to_previous_values(
|
async fn test_handle_edit_all_indexer_settings_command_unprovided_values_default_to_previous_values()
|
||||||
) {
|
{
|
||||||
let expected_edit_all_indexer_settings = IndexerSettings {
|
let expected_edit_all_indexer_settings = IndexerSettings {
|
||||||
allow_hardcoded_subs: true,
|
allow_hardcoded_subs: true,
|
||||||
availability_delay: 2,
|
availability_delay: 2,
|
||||||
@@ -1008,7 +1018,7 @@ mod tests {
|
|||||||
json!({"testResponse": "response"}),
|
json!({"testResponse": "response"}),
|
||||||
)))
|
)))
|
||||||
});
|
});
|
||||||
let app_arc = Arc::new(Mutex::new(App::default()));
|
let app_arc = Arc::new(Mutex::new(App::test_default()));
|
||||||
let edit_all_indexer_settings_command = RadarrEditCommand::AllIndexerSettings {
|
let edit_all_indexer_settings_command = RadarrEditCommand::AllIndexerSettings {
|
||||||
allow_hardcoded_subs: false,
|
allow_hardcoded_subs: false,
|
||||||
disable_allow_hardcoded_subs: false,
|
disable_allow_hardcoded_subs: false,
|
||||||
@@ -1030,7 +1040,7 @@ mod tests {
|
|||||||
.handle()
|
.handle()
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@@ -1055,7 +1065,7 @@ mod tests {
|
|||||||
json!({"testResponse": "response"}),
|
json!({"testResponse": "response"}),
|
||||||
)))
|
)))
|
||||||
});
|
});
|
||||||
let app_arc = Arc::new(Mutex::new(App::default()));
|
let app_arc = Arc::new(Mutex::new(App::test_default()));
|
||||||
let edit_collection_command = RadarrEditCommand::Collection {
|
let edit_collection_command = RadarrEditCommand::Collection {
|
||||||
collection_id: 1,
|
collection_id: 1,
|
||||||
enable_monitoring: true,
|
enable_monitoring: true,
|
||||||
@@ -1072,7 +1082,7 @@ mod tests {
|
|||||||
.handle()
|
.handle()
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@@ -1097,7 +1107,7 @@ mod tests {
|
|||||||
json!({"testResponse": "response"}),
|
json!({"testResponse": "response"}),
|
||||||
)))
|
)))
|
||||||
});
|
});
|
||||||
let app_arc = Arc::new(Mutex::new(App::default()));
|
let app_arc = Arc::new(Mutex::new(App::test_default()));
|
||||||
let edit_collection_command = RadarrEditCommand::Collection {
|
let edit_collection_command = RadarrEditCommand::Collection {
|
||||||
collection_id: 1,
|
collection_id: 1,
|
||||||
enable_monitoring: false,
|
enable_monitoring: false,
|
||||||
@@ -1114,7 +1124,7 @@ mod tests {
|
|||||||
.handle()
|
.handle()
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@@ -1139,7 +1149,7 @@ mod tests {
|
|||||||
json!({"testResponse": "response"}),
|
json!({"testResponse": "response"}),
|
||||||
)))
|
)))
|
||||||
});
|
});
|
||||||
let app_arc = Arc::new(Mutex::new(App::default()));
|
let app_arc = Arc::new(Mutex::new(App::test_default()));
|
||||||
let edit_collection_command = RadarrEditCommand::Collection {
|
let edit_collection_command = RadarrEditCommand::Collection {
|
||||||
collection_id: 1,
|
collection_id: 1,
|
||||||
enable_monitoring: false,
|
enable_monitoring: false,
|
||||||
@@ -1156,7 +1166,7 @@ mod tests {
|
|||||||
.handle()
|
.handle()
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@@ -1187,7 +1197,7 @@ mod tests {
|
|||||||
json!({"testResponse": "response"}),
|
json!({"testResponse": "response"}),
|
||||||
)))
|
)))
|
||||||
});
|
});
|
||||||
let app_arc = Arc::new(Mutex::new(App::default()));
|
let app_arc = Arc::new(Mutex::new(App::test_default()));
|
||||||
let edit_indexer_command = RadarrEditCommand::Indexer {
|
let edit_indexer_command = RadarrEditCommand::Indexer {
|
||||||
indexer_id: 1,
|
indexer_id: 1,
|
||||||
name: Some("Test".to_owned()),
|
name: Some("Test".to_owned()),
|
||||||
@@ -1210,7 +1220,7 @@ mod tests {
|
|||||||
.handle()
|
.handle()
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@@ -1241,7 +1251,7 @@ mod tests {
|
|||||||
json!({"testResponse": "response"}),
|
json!({"testResponse": "response"}),
|
||||||
)))
|
)))
|
||||||
});
|
});
|
||||||
let app_arc = Arc::new(Mutex::new(App::default()));
|
let app_arc = Arc::new(Mutex::new(App::test_default()));
|
||||||
let edit_indexer_command = RadarrEditCommand::Indexer {
|
let edit_indexer_command = RadarrEditCommand::Indexer {
|
||||||
indexer_id: 1,
|
indexer_id: 1,
|
||||||
name: Some("Test".to_owned()),
|
name: Some("Test".to_owned()),
|
||||||
@@ -1264,7 +1274,7 @@ mod tests {
|
|||||||
.handle()
|
.handle()
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@@ -1295,7 +1305,7 @@ mod tests {
|
|||||||
json!({"testResponse": "response"}),
|
json!({"testResponse": "response"}),
|
||||||
)))
|
)))
|
||||||
});
|
});
|
||||||
let app_arc = Arc::new(Mutex::new(App::default()));
|
let app_arc = Arc::new(Mutex::new(App::test_default()));
|
||||||
let edit_indexer_command = RadarrEditCommand::Indexer {
|
let edit_indexer_command = RadarrEditCommand::Indexer {
|
||||||
indexer_id: 1,
|
indexer_id: 1,
|
||||||
name: Some("Test".to_owned()),
|
name: Some("Test".to_owned()),
|
||||||
@@ -1318,7 +1328,7 @@ mod tests {
|
|||||||
.handle()
|
.handle()
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@@ -1345,7 +1355,7 @@ mod tests {
|
|||||||
json!({"testResponse": "response"}),
|
json!({"testResponse": "response"}),
|
||||||
)))
|
)))
|
||||||
});
|
});
|
||||||
let app_arc = Arc::new(Mutex::new(App::default()));
|
let app_arc = Arc::new(Mutex::new(App::test_default()));
|
||||||
let edit_movie_command = RadarrEditCommand::Movie {
|
let edit_movie_command = RadarrEditCommand::Movie {
|
||||||
movie_id: 1,
|
movie_id: 1,
|
||||||
enable_monitoring: true,
|
enable_monitoring: true,
|
||||||
@@ -1361,7 +1371,7 @@ mod tests {
|
|||||||
.handle()
|
.handle()
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@@ -1388,7 +1398,7 @@ mod tests {
|
|||||||
json!({"testResponse": "response"}),
|
json!({"testResponse": "response"}),
|
||||||
)))
|
)))
|
||||||
});
|
});
|
||||||
let app_arc = Arc::new(Mutex::new(App::default()));
|
let app_arc = Arc::new(Mutex::new(App::test_default()));
|
||||||
let edit_movie_command = RadarrEditCommand::Movie {
|
let edit_movie_command = RadarrEditCommand::Movie {
|
||||||
movie_id: 1,
|
movie_id: 1,
|
||||||
enable_monitoring: false,
|
enable_monitoring: false,
|
||||||
@@ -1404,7 +1414,7 @@ mod tests {
|
|||||||
.handle()
|
.handle()
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@@ -1431,7 +1441,7 @@ mod tests {
|
|||||||
json!({"testResponse": "response"}),
|
json!({"testResponse": "response"}),
|
||||||
)))
|
)))
|
||||||
});
|
});
|
||||||
let app_arc = Arc::new(Mutex::new(App::default()));
|
let app_arc = Arc::new(Mutex::new(App::test_default()));
|
||||||
let edit_movie_command = RadarrEditCommand::Movie {
|
let edit_movie_command = RadarrEditCommand::Movie {
|
||||||
movie_id: 1,
|
movie_id: 1,
|
||||||
enable_monitoring: false,
|
enable_monitoring: false,
|
||||||
@@ -1447,7 +1457,7 @@ mod tests {
|
|||||||
.handle()
|
.handle()
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use clap::{command, Subcommand};
|
use clap::{Subcommand, command};
|
||||||
use tokio::sync::Mutex;
|
use tokio::sync::Mutex;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
app::App,
|
app::App,
|
||||||
cli::{CliCommandHandler, Command},
|
cli::{CliCommandHandler, Command},
|
||||||
network::{radarr_network::RadarrEvent, NetworkTrait},
|
network::{NetworkTrait, radarr_network::RadarrEvent},
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::RadarrCommand;
|
use super::RadarrCommand;
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use clap::error::ErrorKind;
|
|
||||||
use clap::CommandFactory;
|
use clap::CommandFactory;
|
||||||
|
use clap::error::ErrorKind;
|
||||||
|
|
||||||
use crate::cli::radarr::get_command_handler::RadarrGetCommand;
|
|
||||||
use crate::cli::radarr::RadarrCommand;
|
|
||||||
use crate::cli::Command;
|
|
||||||
use crate::Cli;
|
use crate::Cli;
|
||||||
|
use crate::cli::Command;
|
||||||
|
use crate::cli::radarr::RadarrCommand;
|
||||||
|
use crate::cli::radarr::get_command_handler::RadarrGetCommand;
|
||||||
use pretty_assertions::assert_eq;
|
use pretty_assertions::assert_eq;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -27,7 +27,7 @@ mod tests {
|
|||||||
let result =
|
let result =
|
||||||
Cli::command().try_get_matches_from(["managarr", "radarr", "get", "all-indexer-settings"]);
|
Cli::command().try_get_matches_from(["managarr", "radarr", "get", "all-indexer-settings"]);
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -35,7 +35,7 @@ mod tests {
|
|||||||
let result =
|
let result =
|
||||||
Cli::command().try_get_matches_from(["managarr", "radarr", "get", "host-config"]);
|
Cli::command().try_get_matches_from(["managarr", "radarr", "get", "host-config"]);
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -43,7 +43,7 @@ mod tests {
|
|||||||
let result =
|
let result =
|
||||||
Cli::command().try_get_matches_from(["managarr", "radarr", "get", "movie-details"]);
|
Cli::command().try_get_matches_from(["managarr", "radarr", "get", "movie-details"]);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert_err!(&result);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
result.unwrap_err().kind(),
|
result.unwrap_err().kind(),
|
||||||
ErrorKind::MissingRequiredArgument
|
ErrorKind::MissingRequiredArgument
|
||||||
@@ -61,7 +61,7 @@ mod tests {
|
|||||||
"1",
|
"1",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -69,7 +69,7 @@ mod tests {
|
|||||||
let result =
|
let result =
|
||||||
Cli::command().try_get_matches_from(["managarr", "radarr", "get", "movie-history"]);
|
Cli::command().try_get_matches_from(["managarr", "radarr", "get", "movie-history"]);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert_err!(&result);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
result.unwrap_err().kind(),
|
result.unwrap_err().kind(),
|
||||||
ErrorKind::MissingRequiredArgument
|
ErrorKind::MissingRequiredArgument
|
||||||
@@ -87,7 +87,7 @@ mod tests {
|
|||||||
"1",
|
"1",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -95,7 +95,7 @@ mod tests {
|
|||||||
let result =
|
let result =
|
||||||
Cli::command().try_get_matches_from(["managarr", "radarr", "get", "security-config"]);
|
Cli::command().try_get_matches_from(["managarr", "radarr", "get", "security-config"]);
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -103,7 +103,7 @@ mod tests {
|
|||||||
let result =
|
let result =
|
||||||
Cli::command().try_get_matches_from(["managarr", "radarr", "get", "system-status"]);
|
Cli::command().try_get_matches_from(["managarr", "radarr", "get", "system-status"]);
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -117,11 +117,11 @@ mod tests {
|
|||||||
use crate::{
|
use crate::{
|
||||||
app::App,
|
app::App,
|
||||||
cli::{
|
cli::{
|
||||||
radarr::get_command_handler::{RadarrGetCommand, RadarrGetCommandHandler},
|
|
||||||
CliCommandHandler,
|
CliCommandHandler,
|
||||||
|
radarr::get_command_handler::{RadarrGetCommand, RadarrGetCommandHandler},
|
||||||
},
|
},
|
||||||
models::{radarr_models::RadarrSerdeable, Serdeable},
|
models::{Serdeable, radarr_models::RadarrSerdeable},
|
||||||
network::{radarr_network::RadarrEvent, MockNetworkTrait, NetworkEvent},
|
network::{MockNetworkTrait, NetworkEvent, radarr_network::RadarrEvent},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@@ -138,7 +138,7 @@ mod tests {
|
|||||||
json!({"testResponse": "response"}),
|
json!({"testResponse": "response"}),
|
||||||
)))
|
)))
|
||||||
});
|
});
|
||||||
let app_arc = Arc::new(Mutex::new(App::default()));
|
let app_arc = Arc::new(Mutex::new(App::test_default()));
|
||||||
let get_all_indexer_settings_command = RadarrGetCommand::AllIndexerSettings;
|
let get_all_indexer_settings_command = RadarrGetCommand::AllIndexerSettings;
|
||||||
|
|
||||||
let result = RadarrGetCommandHandler::with(
|
let result = RadarrGetCommandHandler::with(
|
||||||
@@ -149,7 +149,7 @@ mod tests {
|
|||||||
.handle()
|
.handle()
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@@ -164,7 +164,7 @@ mod tests {
|
|||||||
json!({"testResponse": "response"}),
|
json!({"testResponse": "response"}),
|
||||||
)))
|
)))
|
||||||
});
|
});
|
||||||
let app_arc = Arc::new(Mutex::new(App::default()));
|
let app_arc = Arc::new(Mutex::new(App::test_default()));
|
||||||
let get_host_config_command = RadarrGetCommand::HostConfig;
|
let get_host_config_command = RadarrGetCommand::HostConfig;
|
||||||
|
|
||||||
let result =
|
let result =
|
||||||
@@ -172,7 +172,7 @@ mod tests {
|
|||||||
.handle()
|
.handle()
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@@ -190,7 +190,7 @@ mod tests {
|
|||||||
json!({"testResponse": "response"}),
|
json!({"testResponse": "response"}),
|
||||||
)))
|
)))
|
||||||
});
|
});
|
||||||
let app_arc = Arc::new(Mutex::new(App::default()));
|
let app_arc = Arc::new(Mutex::new(App::test_default()));
|
||||||
let get_movie_details_command = RadarrGetCommand::MovieDetails { movie_id: 1 };
|
let get_movie_details_command = RadarrGetCommand::MovieDetails { movie_id: 1 };
|
||||||
|
|
||||||
let result =
|
let result =
|
||||||
@@ -198,7 +198,7 @@ mod tests {
|
|||||||
.handle()
|
.handle()
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@@ -216,7 +216,7 @@ mod tests {
|
|||||||
json!({"testResponse": "response"}),
|
json!({"testResponse": "response"}),
|
||||||
)))
|
)))
|
||||||
});
|
});
|
||||||
let app_arc = Arc::new(Mutex::new(App::default()));
|
let app_arc = Arc::new(Mutex::new(App::test_default()));
|
||||||
let get_movie_history_command = RadarrGetCommand::MovieHistory { movie_id: 1 };
|
let get_movie_history_command = RadarrGetCommand::MovieHistory { movie_id: 1 };
|
||||||
|
|
||||||
let result =
|
let result =
|
||||||
@@ -224,7 +224,7 @@ mod tests {
|
|||||||
.handle()
|
.handle()
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@@ -239,7 +239,7 @@ mod tests {
|
|||||||
json!({"testResponse": "response"}),
|
json!({"testResponse": "response"}),
|
||||||
)))
|
)))
|
||||||
});
|
});
|
||||||
let app_arc = Arc::new(Mutex::new(App::default()));
|
let app_arc = Arc::new(Mutex::new(App::test_default()));
|
||||||
let get_security_config_command = RadarrGetCommand::SecurityConfig;
|
let get_security_config_command = RadarrGetCommand::SecurityConfig;
|
||||||
|
|
||||||
let result =
|
let result =
|
||||||
@@ -247,7 +247,7 @@ mod tests {
|
|||||||
.handle()
|
.handle()
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@@ -262,7 +262,7 @@ mod tests {
|
|||||||
json!({"testResponse": "response"}),
|
json!({"testResponse": "response"}),
|
||||||
)))
|
)))
|
||||||
});
|
});
|
||||||
let app_arc = Arc::new(Mutex::new(App::default()));
|
let app_arc = Arc::new(Mutex::new(App::test_default()));
|
||||||
let get_system_status_command = RadarrGetCommand::SystemStatus;
|
let get_system_status_command = RadarrGetCommand::SystemStatus;
|
||||||
|
|
||||||
let result =
|
let result =
|
||||||
@@ -270,7 +270,7 @@ mod tests {
|
|||||||
.handle()
|
.handle()
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use clap::{command, Subcommand};
|
use clap::{Subcommand, command};
|
||||||
use tokio::sync::Mutex;
|
use tokio::sync::Mutex;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
app::App,
|
app::App,
|
||||||
cli::{CliCommandHandler, Command},
|
cli::{CliCommandHandler, Command},
|
||||||
network::{radarr_network::RadarrEvent, NetworkTrait},
|
network::{NetworkTrait, radarr_network::RadarrEvent},
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::RadarrCommand;
|
use super::RadarrCommand;
|
||||||
@@ -23,7 +23,10 @@ pub enum RadarrListCommand {
|
|||||||
#[command(about = "List all Radarr collections")]
|
#[command(about = "List all Radarr collections")]
|
||||||
Collections,
|
Collections,
|
||||||
#[command(about = "List all active downloads in Radarr")]
|
#[command(about = "List all active downloads in Radarr")]
|
||||||
Downloads,
|
Downloads {
|
||||||
|
#[arg(long, help = "How many downloads to fetch", default_value_t = 500)]
|
||||||
|
count: u64,
|
||||||
|
},
|
||||||
#[command(about = "List disk space details for all provisioned root folders in Radarr")]
|
#[command(about = "List disk space details for all provisioned root folders in Radarr")]
|
||||||
DiskSpace,
|
DiskSpace,
|
||||||
#[command(about = "List all Radarr indexers")]
|
#[command(about = "List all Radarr indexers")]
|
||||||
@@ -104,10 +107,10 @@ impl<'a, 'b> CliCommandHandler<'a, 'b, RadarrListCommand> for RadarrListCommandH
|
|||||||
.await?;
|
.await?;
|
||||||
serde_json::to_string_pretty(&resp)?
|
serde_json::to_string_pretty(&resp)?
|
||||||
}
|
}
|
||||||
RadarrListCommand::Downloads => {
|
RadarrListCommand::Downloads { count } => {
|
||||||
let resp = self
|
let resp = self
|
||||||
.network
|
.network
|
||||||
.handle_network_event(RadarrEvent::GetDownloads.into())
|
.handle_network_event(RadarrEvent::GetDownloads(count).into())
|
||||||
.await?;
|
.await?;
|
||||||
serde_json::to_string_pretty(&resp)?
|
serde_json::to_string_pretty(&resp)?
|
||||||
}
|
}
|
||||||
@@ -135,9 +138,9 @@ impl<'a, 'b> CliCommandHandler<'a, 'b, RadarrListCommand> for RadarrListCommandH
|
|||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
if output_in_log_format {
|
if output_in_log_format {
|
||||||
let log_lines = self.app.lock().await.data.radarr_data.logs.items.clone();
|
let log_lines = &self.app.lock().await.data.radarr_data.logs.items;
|
||||||
|
|
||||||
serde_json::to_string_pretty(&log_lines)?
|
serde_json::to_string_pretty(log_lines)?
|
||||||
} else {
|
} else {
|
||||||
serde_json::to_string_pretty(&logs)?
|
serde_json::to_string_pretty(&logs)?
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use clap::error::ErrorKind;
|
|
||||||
use clap::CommandFactory;
|
use clap::CommandFactory;
|
||||||
|
use clap::error::ErrorKind;
|
||||||
|
|
||||||
use crate::cli::radarr::list_command_handler::RadarrListCommand;
|
|
||||||
use crate::cli::radarr::RadarrCommand;
|
|
||||||
use crate::cli::Command;
|
|
||||||
use crate::Cli;
|
use crate::Cli;
|
||||||
|
use crate::cli::Command;
|
||||||
|
use crate::cli::radarr::RadarrCommand;
|
||||||
|
use crate::cli::radarr::list_command_handler::RadarrListCommand;
|
||||||
use pretty_assertions::assert_eq;
|
use pretty_assertions::assert_eq;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -29,7 +29,6 @@ mod tests {
|
|||||||
#[values(
|
#[values(
|
||||||
"blocklist",
|
"blocklist",
|
||||||
"collections",
|
"collections",
|
||||||
"downloads",
|
|
||||||
"disk-space",
|
"disk-space",
|
||||||
"indexers",
|
"indexers",
|
||||||
"movies",
|
"movies",
|
||||||
@@ -44,7 +43,7 @@ mod tests {
|
|||||||
) {
|
) {
|
||||||
let result = Cli::command().try_get_matches_from(["managarr", "radarr", "list", subcommand]);
|
let result = Cli::command().try_get_matches_from(["managarr", "radarr", "list", subcommand]);
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -52,19 +51,28 @@ mod tests {
|
|||||||
let result =
|
let result =
|
||||||
Cli::command().try_get_matches_from(["managarr", "radarr", "list", "movie-credits"]);
|
Cli::command().try_get_matches_from(["managarr", "radarr", "list", "movie-credits"]);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert_err!(&result);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
result.unwrap_err().kind(),
|
result.unwrap_err().kind(),
|
||||||
ErrorKind::MissingRequiredArgument
|
ErrorKind::MissingRequiredArgument
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_list_downloads_count_flag_requires_arguments() {
|
||||||
|
let result =
|
||||||
|
Cli::command().try_get_matches_from(["managarr", "radarr", "list", "downloads", "--count"]);
|
||||||
|
|
||||||
|
assert_err!(&result);
|
||||||
|
assert_eq!(result.unwrap_err().kind(), ErrorKind::InvalidValue);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_list_logs_events_flag_requires_arguments() {
|
fn test_list_logs_events_flag_requires_arguments() {
|
||||||
let result =
|
let result =
|
||||||
Cli::command().try_get_matches_from(["managarr", "radarr", "list", "logs", "--events"]);
|
Cli::command().try_get_matches_from(["managarr", "radarr", "list", "logs", "--events"]);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert_err!(&result);
|
||||||
assert_eq!(result.unwrap_err().kind(), ErrorKind::InvalidValue);
|
assert_eq!(result.unwrap_err().kind(), ErrorKind::InvalidValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -80,11 +88,27 @@ mod tests {
|
|||||||
"1",
|
"1",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
|
|
||||||
if let Some(Command::Radarr(RadarrCommand::List(credits_command))) = result.unwrap().command {
|
let Some(Command::Radarr(RadarrCommand::List(credits_command))) = result.unwrap().command
|
||||||
assert_eq!(credits_command, expected_args);
|
else {
|
||||||
}
|
panic!("Unexpected command type");
|
||||||
|
};
|
||||||
|
assert_eq!(credits_command, expected_args);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_list_downloads_default_values() {
|
||||||
|
let expected_args = RadarrListCommand::Downloads { count: 500 };
|
||||||
|
let result = Cli::try_parse_from(["managarr", "radarr", "list", "downloads"]);
|
||||||
|
|
||||||
|
assert_ok!(&result);
|
||||||
|
|
||||||
|
let Some(Command::Radarr(RadarrCommand::List(refresh_command))) = result.unwrap().command
|
||||||
|
else {
|
||||||
|
panic!("Unexpected command type");
|
||||||
|
};
|
||||||
|
assert_eq!(refresh_command, expected_args);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -95,11 +119,13 @@ mod tests {
|
|||||||
};
|
};
|
||||||
let result = Cli::try_parse_from(["managarr", "radarr", "list", "logs"]);
|
let result = Cli::try_parse_from(["managarr", "radarr", "list", "logs"]);
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
|
|
||||||
if let Some(Command::Radarr(RadarrCommand::List(refresh_command))) = result.unwrap().command {
|
let Some(Command::Radarr(RadarrCommand::List(refresh_command))) = result.unwrap().command
|
||||||
assert_eq!(refresh_command, expected_args);
|
else {
|
||||||
}
|
panic!("Unexpected command type");
|
||||||
|
};
|
||||||
|
assert_eq!(refresh_command, expected_args);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -115,14 +141,13 @@ mod tests {
|
|||||||
use crate::{
|
use crate::{
|
||||||
app::App,
|
app::App,
|
||||||
cli::radarr::list_command_handler::{RadarrListCommand, RadarrListCommandHandler},
|
cli::radarr::list_command_handler::{RadarrListCommand, RadarrListCommandHandler},
|
||||||
models::{radarr_models::RadarrSerdeable, Serdeable},
|
models::{Serdeable, radarr_models::RadarrSerdeable},
|
||||||
network::{radarr_network::RadarrEvent, MockNetworkTrait, NetworkEvent},
|
network::{MockNetworkTrait, NetworkEvent, radarr_network::RadarrEvent},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[rstest]
|
#[rstest]
|
||||||
#[case(RadarrListCommand::Blocklist, RadarrEvent::GetBlocklist)]
|
#[case(RadarrListCommand::Blocklist, RadarrEvent::GetBlocklist)]
|
||||||
#[case(RadarrListCommand::Collections, RadarrEvent::GetCollections)]
|
#[case(RadarrListCommand::Collections, RadarrEvent::GetCollections)]
|
||||||
#[case(RadarrListCommand::Downloads, RadarrEvent::GetDownloads)]
|
|
||||||
#[case(RadarrListCommand::DiskSpace, RadarrEvent::GetDiskSpace)]
|
#[case(RadarrListCommand::DiskSpace, RadarrEvent::GetDiskSpace)]
|
||||||
#[case(RadarrListCommand::Indexers, RadarrEvent::GetIndexers)]
|
#[case(RadarrListCommand::Indexers, RadarrEvent::GetIndexers)]
|
||||||
#[case(RadarrListCommand::Movies, RadarrEvent::GetMovies)]
|
#[case(RadarrListCommand::Movies, RadarrEvent::GetMovies)]
|
||||||
@@ -147,13 +172,13 @@ mod tests {
|
|||||||
json!({"testResponse": "response"}),
|
json!({"testResponse": "response"}),
|
||||||
)))
|
)))
|
||||||
});
|
});
|
||||||
let app_arc = Arc::new(Mutex::new(App::default()));
|
let app_arc = Arc::new(Mutex::new(App::test_default()));
|
||||||
|
|
||||||
let result = RadarrListCommandHandler::with(&app_arc, list_command, &mut mock_network)
|
let result = RadarrListCommandHandler::with(&app_arc, list_command, &mut mock_network)
|
||||||
.handle()
|
.handle()
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@@ -171,7 +196,7 @@ mod tests {
|
|||||||
json!({"testResponse": "response"}),
|
json!({"testResponse": "response"}),
|
||||||
)))
|
)))
|
||||||
});
|
});
|
||||||
let app_arc = Arc::new(Mutex::new(App::default()));
|
let app_arc = Arc::new(Mutex::new(App::test_default()));
|
||||||
let list_movie_credits_command = RadarrListCommand::MovieCredits { movie_id: 1 };
|
let list_movie_credits_command = RadarrListCommand::MovieCredits { movie_id: 1 };
|
||||||
|
|
||||||
let result =
|
let result =
|
||||||
@@ -179,7 +204,33 @@ mod tests {
|
|||||||
.handle()
|
.handle()
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_handle_list_downloads_command() {
|
||||||
|
let expected_count = 1000;
|
||||||
|
let mut mock_network = MockNetworkTrait::new();
|
||||||
|
mock_network
|
||||||
|
.expect_handle_network_event()
|
||||||
|
.with(eq::<NetworkEvent>(
|
||||||
|
RadarrEvent::GetDownloads(expected_count).into(),
|
||||||
|
))
|
||||||
|
.times(1)
|
||||||
|
.returning(|_| {
|
||||||
|
Ok(Serdeable::Radarr(RadarrSerdeable::Value(
|
||||||
|
json!({"testResponse": "response"}),
|
||||||
|
)))
|
||||||
|
});
|
||||||
|
let app_arc = Arc::new(Mutex::new(App::test_default()));
|
||||||
|
let list_downloads_command = RadarrListCommand::Downloads { count: 1000 };
|
||||||
|
|
||||||
|
let result =
|
||||||
|
RadarrListCommandHandler::with(&app_arc, list_downloads_command, &mut mock_network)
|
||||||
|
.handle()
|
||||||
|
.await;
|
||||||
|
|
||||||
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@@ -197,7 +248,7 @@ mod tests {
|
|||||||
json!({"testResponse": "response"}),
|
json!({"testResponse": "response"}),
|
||||||
)))
|
)))
|
||||||
});
|
});
|
||||||
let app_arc = Arc::new(Mutex::new(App::default()));
|
let app_arc = Arc::new(Mutex::new(App::test_default()));
|
||||||
let list_logs_command = RadarrListCommand::Logs {
|
let list_logs_command = RadarrListCommand::Logs {
|
||||||
events: 1000,
|
events: 1000,
|
||||||
output_in_log_format: false,
|
output_in_log_format: false,
|
||||||
@@ -207,7 +258,7 @@ mod tests {
|
|||||||
.handle()
|
.handle()
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+19
-1
@@ -13,8 +13,8 @@ use crate::app::App;
|
|||||||
|
|
||||||
use crate::cli::CliCommandHandler;
|
use crate::cli::CliCommandHandler;
|
||||||
use crate::models::radarr_models::{RadarrReleaseDownloadBody, RadarrTaskName};
|
use crate::models::radarr_models::{RadarrReleaseDownloadBody, RadarrTaskName};
|
||||||
use crate::network::radarr_network::RadarrEvent;
|
|
||||||
use crate::network::NetworkTrait;
|
use crate::network::NetworkTrait;
|
||||||
|
use crate::network::radarr_network::RadarrEvent;
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
|
|
||||||
use super::Command;
|
use super::Command;
|
||||||
@@ -118,6 +118,17 @@ pub enum RadarrCommand {
|
|||||||
},
|
},
|
||||||
#[command(about = "Test all Radarr indexers")]
|
#[command(about = "Test all Radarr indexers")]
|
||||||
TestAllIndexers,
|
TestAllIndexers,
|
||||||
|
#[command(
|
||||||
|
about = "Toggle monitoring for the specified movie corresponding to the given movie ID"
|
||||||
|
)]
|
||||||
|
ToggleMovieMonitoring {
|
||||||
|
#[arg(
|
||||||
|
long,
|
||||||
|
help = "The Radarr ID of the movie to toggle monitoring on",
|
||||||
|
required = true
|
||||||
|
)]
|
||||||
|
movie_id: i64,
|
||||||
|
},
|
||||||
#[command(about = "Trigger an automatic search for the movie with the specified ID")]
|
#[command(about = "Trigger an automatic search for the movie with the specified ID")]
|
||||||
TriggerAutomaticSearch {
|
TriggerAutomaticSearch {
|
||||||
#[arg(
|
#[arg(
|
||||||
@@ -250,6 +261,13 @@ impl<'a, 'b> CliCommandHandler<'a, 'b, RadarrCommand> for RadarrCliHandler<'a, '
|
|||||||
.await?;
|
.await?;
|
||||||
serde_json::to_string_pretty(&resp)?
|
serde_json::to_string_pretty(&resp)?
|
||||||
}
|
}
|
||||||
|
RadarrCommand::ToggleMovieMonitoring { movie_id } => {
|
||||||
|
let resp = self
|
||||||
|
.network
|
||||||
|
.handle_network_event(RadarrEvent::ToggleMovieMonitoring(movie_id).into())
|
||||||
|
.await?;
|
||||||
|
serde_json::to_string_pretty(&resp)?
|
||||||
|
}
|
||||||
RadarrCommand::TriggerAutomaticSearch { movie_id } => {
|
RadarrCommand::TriggerAutomaticSearch { movie_id } => {
|
||||||
let resp = self
|
let resp = self
|
||||||
.network
|
.network
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use clap::error::ErrorKind;
|
|
||||||
use clap::CommandFactory;
|
use clap::CommandFactory;
|
||||||
|
use clap::error::ErrorKind;
|
||||||
|
|
||||||
use crate::cli::radarr::RadarrCommand;
|
|
||||||
use crate::cli::Command;
|
|
||||||
use crate::Cli;
|
use crate::Cli;
|
||||||
|
use crate::cli::Command;
|
||||||
|
use crate::cli::radarr::RadarrCommand;
|
||||||
use pretty_assertions::assert_eq;
|
use pretty_assertions::assert_eq;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -28,7 +28,7 @@ mod tests {
|
|||||||
) {
|
) {
|
||||||
let result = Cli::command().try_get_matches_from(["managarr", "radarr", subcommand]);
|
let result = Cli::command().try_get_matches_from(["managarr", "radarr", subcommand]);
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -43,7 +43,7 @@ mod tests {
|
|||||||
"1",
|
"1",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert_err!(&result);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
result.unwrap_err().kind(),
|
result.unwrap_err().kind(),
|
||||||
ErrorKind::MissingRequiredArgument
|
ErrorKind::MissingRequiredArgument
|
||||||
@@ -62,7 +62,7 @@ mod tests {
|
|||||||
"1",
|
"1",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert_err!(&result);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
result.unwrap_err().kind(),
|
result.unwrap_err().kind(),
|
||||||
ErrorKind::MissingRequiredArgument
|
ErrorKind::MissingRequiredArgument
|
||||||
@@ -81,7 +81,7 @@ mod tests {
|
|||||||
"1",
|
"1",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert_err!(&result);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
result.unwrap_err().kind(),
|
result.unwrap_err().kind(),
|
||||||
ErrorKind::MissingRequiredArgument
|
ErrorKind::MissingRequiredArgument
|
||||||
@@ -102,14 +102,14 @@ mod tests {
|
|||||||
"1",
|
"1",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_manual_search_requires_movie_id() {
|
fn test_manual_search_requires_movie_id() {
|
||||||
let result = Cli::command().try_get_matches_from(["managarr", "radarr", "manual-search"]);
|
let result = Cli::command().try_get_matches_from(["managarr", "radarr", "manual-search"]);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert_err!(&result);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
result.unwrap_err().kind(),
|
result.unwrap_err().kind(),
|
||||||
ErrorKind::MissingRequiredArgument
|
ErrorKind::MissingRequiredArgument
|
||||||
@@ -126,14 +126,14 @@ mod tests {
|
|||||||
"1",
|
"1",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_search_new_movie_requires_query() {
|
fn test_search_new_movie_requires_query() {
|
||||||
let result = Cli::command().try_get_matches_from(["managarr", "radarr", "search-new-movie"]);
|
let result = Cli::command().try_get_matches_from(["managarr", "radarr", "search-new-movie"]);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert_err!(&result);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
result.unwrap_err().kind(),
|
result.unwrap_err().kind(),
|
||||||
ErrorKind::MissingRequiredArgument
|
ErrorKind::MissingRequiredArgument
|
||||||
@@ -150,14 +150,14 @@ mod tests {
|
|||||||
"halo",
|
"halo",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_start_task_requires_task_name() {
|
fn test_start_task_requires_task_name() {
|
||||||
let result = Cli::command().try_get_matches_from(["managarr", "radarr", "start-task"]);
|
let result = Cli::command().try_get_matches_from(["managarr", "radarr", "start-task"]);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert_err!(&result);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
result.unwrap_err().kind(),
|
result.unwrap_err().kind(),
|
||||||
ErrorKind::MissingRequiredArgument
|
ErrorKind::MissingRequiredArgument
|
||||||
@@ -174,7 +174,7 @@ mod tests {
|
|||||||
"test",
|
"test",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert_err!(&result);
|
||||||
assert_eq!(result.unwrap_err().kind(), ErrorKind::InvalidValue);
|
assert_eq!(result.unwrap_err().kind(), ErrorKind::InvalidValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -188,14 +188,14 @@ mod tests {
|
|||||||
"application-check-update",
|
"application-check-update",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_test_indexer_requires_indexer_id() {
|
fn test_test_indexer_requires_indexer_id() {
|
||||||
let result = Cli::command().try_get_matches_from(["managarr", "radarr", "test-indexer"]);
|
let result = Cli::command().try_get_matches_from(["managarr", "radarr", "test-indexer"]);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert_err!(&result);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
result.unwrap_err().kind(),
|
result.unwrap_err().kind(),
|
||||||
ErrorKind::MissingRequiredArgument
|
ErrorKind::MissingRequiredArgument
|
||||||
@@ -212,7 +212,32 @@ mod tests {
|
|||||||
"1",
|
"1",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_toggle_movie_monitoring_requires_movie_id() {
|
||||||
|
let result =
|
||||||
|
Cli::command().try_get_matches_from(["managarr", "radarr", "toggle-movie-monitoring"]);
|
||||||
|
|
||||||
|
assert_err!(&result);
|
||||||
|
assert_eq!(
|
||||||
|
result.unwrap_err().kind(),
|
||||||
|
ErrorKind::MissingRequiredArgument
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_toggle_movie_monitoring_requirements_satisfied() {
|
||||||
|
let result = Cli::command().try_get_matches_from([
|
||||||
|
"managarr",
|
||||||
|
"radarr",
|
||||||
|
"toggle-movie-monitoring",
|
||||||
|
"--movie-id",
|
||||||
|
"1",
|
||||||
|
]);
|
||||||
|
|
||||||
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -220,7 +245,7 @@ mod tests {
|
|||||||
let result =
|
let result =
|
||||||
Cli::command().try_get_matches_from(["managarr", "radarr", "trigger-automatic-search"]);
|
Cli::command().try_get_matches_from(["managarr", "radarr", "trigger-automatic-search"]);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert_err!(&result);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
result.unwrap_err().kind(),
|
result.unwrap_err().kind(),
|
||||||
ErrorKind::MissingRequiredArgument
|
ErrorKind::MissingRequiredArgument
|
||||||
@@ -237,7 +262,7 @@ mod tests {
|
|||||||
"1",
|
"1",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -251,22 +276,22 @@ mod tests {
|
|||||||
use crate::{
|
use crate::{
|
||||||
app::App,
|
app::App,
|
||||||
cli::{
|
cli::{
|
||||||
radarr::{
|
|
||||||
add_command_handler::RadarrAddCommand, delete_command_handler::RadarrDeleteCommand,
|
|
||||||
edit_command_handler::RadarrEditCommand, get_command_handler::RadarrGetCommand,
|
|
||||||
list_command_handler::RadarrListCommand, refresh_command_handler::RadarrRefreshCommand,
|
|
||||||
RadarrCliHandler, RadarrCommand,
|
|
||||||
},
|
|
||||||
CliCommandHandler,
|
CliCommandHandler,
|
||||||
|
radarr::{
|
||||||
|
RadarrCliHandler, RadarrCommand, add_command_handler::RadarrAddCommand,
|
||||||
|
delete_command_handler::RadarrDeleteCommand, edit_command_handler::RadarrEditCommand,
|
||||||
|
get_command_handler::RadarrGetCommand, list_command_handler::RadarrListCommand,
|
||||||
|
refresh_command_handler::RadarrRefreshCommand,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
models::{
|
models::{
|
||||||
|
Serdeable,
|
||||||
radarr_models::{
|
radarr_models::{
|
||||||
BlocklistItem, BlocklistResponse, IndexerSettings, RadarrReleaseDownloadBody,
|
BlocklistItem, BlocklistResponse, IndexerSettings, RadarrReleaseDownloadBody,
|
||||||
RadarrSerdeable, RadarrTaskName,
|
RadarrSerdeable, RadarrTaskName,
|
||||||
},
|
},
|
||||||
Serdeable,
|
|
||||||
},
|
},
|
||||||
network::{radarr_network::RadarrEvent, MockNetworkTrait, NetworkEvent},
|
network::{MockNetworkTrait, NetworkEvent, radarr_network::RadarrEvent},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@@ -292,14 +317,14 @@ mod tests {
|
|||||||
json!({"testResponse": "response"}),
|
json!({"testResponse": "response"}),
|
||||||
)))
|
)))
|
||||||
});
|
});
|
||||||
let app_arc = Arc::new(Mutex::new(App::default()));
|
let app_arc = Arc::new(Mutex::new(App::test_default()));
|
||||||
let clear_blocklist_command = RadarrCommand::ClearBlocklist;
|
let clear_blocklist_command = RadarrCommand::ClearBlocklist;
|
||||||
|
|
||||||
let result = RadarrCliHandler::with(&app_arc, clear_blocklist_command, &mut mock_network)
|
let result = RadarrCliHandler::with(&app_arc, clear_blocklist_command, &mut mock_network)
|
||||||
.handle()
|
.handle()
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@@ -321,7 +346,7 @@ mod tests {
|
|||||||
json!({"testResponse": "response"}),
|
json!({"testResponse": "response"}),
|
||||||
)))
|
)))
|
||||||
});
|
});
|
||||||
let app_arc = Arc::new(Mutex::new(App::default()));
|
let app_arc = Arc::new(Mutex::new(App::test_default()));
|
||||||
let download_release_command = RadarrCommand::DownloadRelease {
|
let download_release_command = RadarrCommand::DownloadRelease {
|
||||||
guid: "guid".to_owned(),
|
guid: "guid".to_owned(),
|
||||||
indexer_id: 1,
|
indexer_id: 1,
|
||||||
@@ -332,7 +357,7 @@ mod tests {
|
|||||||
.handle()
|
.handle()
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@@ -350,14 +375,14 @@ mod tests {
|
|||||||
json!({"testResponse": "response"}),
|
json!({"testResponse": "response"}),
|
||||||
)))
|
)))
|
||||||
});
|
});
|
||||||
let app_arc = Arc::new(Mutex::new(App::default()));
|
let app_arc = Arc::new(Mutex::new(App::test_default()));
|
||||||
let manual_search_command = RadarrCommand::ManualSearch { movie_id: 1 };
|
let manual_search_command = RadarrCommand::ManualSearch { movie_id: 1 };
|
||||||
|
|
||||||
let result = RadarrCliHandler::with(&app_arc, manual_search_command, &mut mock_network)
|
let result = RadarrCliHandler::with(&app_arc, manual_search_command, &mut mock_network)
|
||||||
.handle()
|
.handle()
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@@ -375,7 +400,7 @@ mod tests {
|
|||||||
json!({"testResponse": "response"}),
|
json!({"testResponse": "response"}),
|
||||||
)))
|
)))
|
||||||
});
|
});
|
||||||
let app_arc = Arc::new(Mutex::new(App::default()));
|
let app_arc = Arc::new(Mutex::new(App::test_default()));
|
||||||
let search_new_movie_command = RadarrCommand::SearchNewMovie {
|
let search_new_movie_command = RadarrCommand::SearchNewMovie {
|
||||||
query: "halo".to_owned(),
|
query: "halo".to_owned(),
|
||||||
};
|
};
|
||||||
@@ -384,7 +409,7 @@ mod tests {
|
|||||||
.handle()
|
.handle()
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@@ -402,7 +427,7 @@ mod tests {
|
|||||||
json!({"testResponse": "response"}),
|
json!({"testResponse": "response"}),
|
||||||
)))
|
)))
|
||||||
});
|
});
|
||||||
let app_arc = Arc::new(Mutex::new(App::default()));
|
let app_arc = Arc::new(Mutex::new(App::test_default()));
|
||||||
let start_task_command = RadarrCommand::StartTask {
|
let start_task_command = RadarrCommand::StartTask {
|
||||||
task_name: RadarrTaskName::ApplicationCheckUpdate,
|
task_name: RadarrTaskName::ApplicationCheckUpdate,
|
||||||
};
|
};
|
||||||
@@ -411,7 +436,7 @@ mod tests {
|
|||||||
.handle()
|
.handle()
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@@ -429,14 +454,14 @@ mod tests {
|
|||||||
json!({"testResponse": "response"}),
|
json!({"testResponse": "response"}),
|
||||||
)))
|
)))
|
||||||
});
|
});
|
||||||
let app_arc = Arc::new(Mutex::new(App::default()));
|
let app_arc = Arc::new(Mutex::new(App::test_default()));
|
||||||
let test_indexer_command = RadarrCommand::TestIndexer { indexer_id: 1 };
|
let test_indexer_command = RadarrCommand::TestIndexer { indexer_id: 1 };
|
||||||
|
|
||||||
let result = RadarrCliHandler::with(&app_arc, test_indexer_command, &mut mock_network)
|
let result = RadarrCliHandler::with(&app_arc, test_indexer_command, &mut mock_network)
|
||||||
.handle()
|
.handle()
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@@ -451,14 +476,40 @@ mod tests {
|
|||||||
json!({"testResponse": "response"}),
|
json!({"testResponse": "response"}),
|
||||||
)))
|
)))
|
||||||
});
|
});
|
||||||
let app_arc = Arc::new(Mutex::new(App::default()));
|
let app_arc = Arc::new(Mutex::new(App::test_default()));
|
||||||
let test_all_indexers_command = RadarrCommand::TestAllIndexers;
|
let test_all_indexers_command = RadarrCommand::TestAllIndexers;
|
||||||
|
|
||||||
let result = RadarrCliHandler::with(&app_arc, test_all_indexers_command, &mut mock_network)
|
let result = RadarrCliHandler::with(&app_arc, test_all_indexers_command, &mut mock_network)
|
||||||
.handle()
|
.handle()
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_toggle_movie_monitoring_command() {
|
||||||
|
let expected_movie_id = 1;
|
||||||
|
let mut mock_network = MockNetworkTrait::new();
|
||||||
|
mock_network
|
||||||
|
.expect_handle_network_event()
|
||||||
|
.with(eq::<NetworkEvent>(
|
||||||
|
RadarrEvent::ToggleMovieMonitoring(expected_movie_id).into(),
|
||||||
|
))
|
||||||
|
.times(1)
|
||||||
|
.returning(|_| {
|
||||||
|
Ok(Serdeable::Radarr(RadarrSerdeable::Value(
|
||||||
|
json!({"testResponse": "response"}),
|
||||||
|
)))
|
||||||
|
});
|
||||||
|
let app_arc = Arc::new(Mutex::new(App::test_default()));
|
||||||
|
let toggle_movie_monitoring_command = RadarrCommand::ToggleMovieMonitoring { movie_id: 1 };
|
||||||
|
|
||||||
|
let result =
|
||||||
|
RadarrCliHandler::with(&app_arc, toggle_movie_monitoring_command, &mut mock_network)
|
||||||
|
.handle()
|
||||||
|
.await;
|
||||||
|
|
||||||
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@@ -476,7 +527,7 @@ mod tests {
|
|||||||
json!({"testResponse": "response"}),
|
json!({"testResponse": "response"}),
|
||||||
)))
|
)))
|
||||||
});
|
});
|
||||||
let app_arc = Arc::new(Mutex::new(App::default()));
|
let app_arc = Arc::new(Mutex::new(App::test_default()));
|
||||||
let trigger_automatic_search_command = RadarrCommand::TriggerAutomaticSearch { movie_id: 1 };
|
let trigger_automatic_search_command = RadarrCommand::TriggerAutomaticSearch { movie_id: 1 };
|
||||||
|
|
||||||
let result = RadarrCliHandler::with(
|
let result = RadarrCliHandler::with(
|
||||||
@@ -487,7 +538,7 @@ mod tests {
|
|||||||
.handle()
|
.handle()
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@@ -505,7 +556,7 @@ mod tests {
|
|||||||
json!({"testResponse": "response"}),
|
json!({"testResponse": "response"}),
|
||||||
)))
|
)))
|
||||||
});
|
});
|
||||||
let app_arc = Arc::new(Mutex::new(App::default()));
|
let app_arc = Arc::new(Mutex::new(App::test_default()));
|
||||||
let add_tag_command = RadarrCommand::Add(RadarrAddCommand::Tag {
|
let add_tag_command = RadarrCommand::Add(RadarrAddCommand::Tag {
|
||||||
name: expected_tag_name,
|
name: expected_tag_name,
|
||||||
});
|
});
|
||||||
@@ -514,7 +565,7 @@ mod tests {
|
|||||||
.handle()
|
.handle()
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@@ -532,7 +583,7 @@ mod tests {
|
|||||||
json!({"testResponse": "response"}),
|
json!({"testResponse": "response"}),
|
||||||
)))
|
)))
|
||||||
});
|
});
|
||||||
let app_arc = Arc::new(Mutex::new(App::default()));
|
let app_arc = Arc::new(Mutex::new(App::test_default()));
|
||||||
let delete_blocklist_item_command =
|
let delete_blocklist_item_command =
|
||||||
RadarrCommand::Delete(RadarrDeleteCommand::BlocklistItem {
|
RadarrCommand::Delete(RadarrDeleteCommand::BlocklistItem {
|
||||||
blocklist_item_id: 1,
|
blocklist_item_id: 1,
|
||||||
@@ -543,7 +594,7 @@ mod tests {
|
|||||||
.handle()
|
.handle()
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@@ -592,7 +643,7 @@ mod tests {
|
|||||||
json!({"testResponse": "response"}),
|
json!({"testResponse": "response"}),
|
||||||
)))
|
)))
|
||||||
});
|
});
|
||||||
let app_arc = Arc::new(Mutex::new(App::default()));
|
let app_arc = Arc::new(Mutex::new(App::test_default()));
|
||||||
let edit_all_indexer_settings_command =
|
let edit_all_indexer_settings_command =
|
||||||
RadarrCommand::Edit(RadarrEditCommand::AllIndexerSettings {
|
RadarrCommand::Edit(RadarrEditCommand::AllIndexerSettings {
|
||||||
allow_hardcoded_subs: true,
|
allow_hardcoded_subs: true,
|
||||||
@@ -615,7 +666,7 @@ mod tests {
|
|||||||
.handle()
|
.handle()
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@@ -632,7 +683,7 @@ mod tests {
|
|||||||
json!({"testResponse": "response"}),
|
json!({"testResponse": "response"}),
|
||||||
)))
|
)))
|
||||||
});
|
});
|
||||||
let app_arc = Arc::new(Mutex::new(App::default()));
|
let app_arc = Arc::new(Mutex::new(App::test_default()));
|
||||||
let get_all_indexer_settings_command =
|
let get_all_indexer_settings_command =
|
||||||
RadarrCommand::Get(RadarrGetCommand::AllIndexerSettings);
|
RadarrCommand::Get(RadarrGetCommand::AllIndexerSettings);
|
||||||
|
|
||||||
@@ -644,7 +695,7 @@ mod tests {
|
|||||||
.handle()
|
.handle()
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@@ -662,7 +713,7 @@ mod tests {
|
|||||||
json!({"testResponse": "response"}),
|
json!({"testResponse": "response"}),
|
||||||
)))
|
)))
|
||||||
});
|
});
|
||||||
let app_arc = Arc::new(Mutex::new(App::default()));
|
let app_arc = Arc::new(Mutex::new(App::test_default()));
|
||||||
let list_movie_credits_command =
|
let list_movie_credits_command =
|
||||||
RadarrCommand::List(RadarrListCommand::MovieCredits { movie_id: 1 });
|
RadarrCommand::List(RadarrListCommand::MovieCredits { movie_id: 1 });
|
||||||
|
|
||||||
@@ -670,7 +721,7 @@ mod tests {
|
|||||||
.handle()
|
.handle()
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@@ -688,7 +739,7 @@ mod tests {
|
|||||||
json!({"testResponse": "response"}),
|
json!({"testResponse": "response"}),
|
||||||
)))
|
)))
|
||||||
});
|
});
|
||||||
let app_arc = Arc::new(Mutex::new(App::default()));
|
let app_arc = Arc::new(Mutex::new(App::test_default()));
|
||||||
let refresh_movie_command =
|
let refresh_movie_command =
|
||||||
RadarrCommand::Refresh(RadarrRefreshCommand::Movie { movie_id: 1 });
|
RadarrCommand::Refresh(RadarrRefreshCommand::Movie { movie_id: 1 });
|
||||||
|
|
||||||
@@ -696,7 +747,7 @@ mod tests {
|
|||||||
.handle()
|
.handle()
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ use tokio::sync::Mutex;
|
|||||||
use crate::{
|
use crate::{
|
||||||
app::App,
|
app::App,
|
||||||
cli::{CliCommandHandler, Command},
|
cli::{CliCommandHandler, Command},
|
||||||
network::{radarr_network::RadarrEvent, NetworkTrait},
|
network::{NetworkTrait, radarr_network::RadarrEvent},
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::RadarrCommand;
|
use super::RadarrCommand;
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use clap::error::ErrorKind;
|
|
||||||
use clap::CommandFactory;
|
use clap::CommandFactory;
|
||||||
|
use clap::error::ErrorKind;
|
||||||
|
|
||||||
use crate::cli::radarr::refresh_command_handler::RadarrRefreshCommand;
|
|
||||||
use crate::cli::radarr::RadarrCommand;
|
|
||||||
use crate::cli::Command;
|
|
||||||
use crate::Cli;
|
use crate::Cli;
|
||||||
|
use crate::cli::Command;
|
||||||
|
use crate::cli::radarr::RadarrCommand;
|
||||||
|
use crate::cli::radarr::refresh_command_handler::RadarrRefreshCommand;
|
||||||
use pretty_assertions::assert_eq;
|
use pretty_assertions::assert_eq;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -31,14 +31,14 @@ mod tests {
|
|||||||
let result =
|
let result =
|
||||||
Cli::command().try_get_matches_from(["managarr", "radarr", "refresh", subcommand]);
|
Cli::command().try_get_matches_from(["managarr", "radarr", "refresh", subcommand]);
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_refresh_movie_requires_movie_id() {
|
fn test_refresh_movie_requires_movie_id() {
|
||||||
let result = Cli::command().try_get_matches_from(["managarr", "radarr", "refresh", "movie"]);
|
let result = Cli::command().try_get_matches_from(["managarr", "radarr", "refresh", "movie"]);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert_err!(&result);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
result.unwrap_err().kind(),
|
result.unwrap_err().kind(),
|
||||||
ErrorKind::MissingRequiredArgument
|
ErrorKind::MissingRequiredArgument
|
||||||
@@ -51,13 +51,13 @@ mod tests {
|
|||||||
let result =
|
let result =
|
||||||
Cli::try_parse_from(["managarr", "radarr", "refresh", "movie", "--movie-id", "1"]);
|
Cli::try_parse_from(["managarr", "radarr", "refresh", "movie", "--movie-id", "1"]);
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
|
|
||||||
if let Some(Command::Radarr(RadarrCommand::Refresh(refresh_command))) =
|
let Some(Command::Radarr(RadarrCommand::Refresh(refresh_command))) = result.unwrap().command
|
||||||
result.unwrap().command
|
else {
|
||||||
{
|
panic!("Unexpected command type");
|
||||||
assert_eq!(refresh_command, expected_args);
|
};
|
||||||
}
|
assert_eq!(refresh_command, expected_args);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -73,8 +73,8 @@ mod tests {
|
|||||||
use crate::{
|
use crate::{
|
||||||
app::App,
|
app::App,
|
||||||
cli::radarr::refresh_command_handler::{RadarrRefreshCommand, RadarrRefreshCommandHandler},
|
cli::radarr::refresh_command_handler::{RadarrRefreshCommand, RadarrRefreshCommandHandler},
|
||||||
models::{radarr_models::RadarrSerdeable, Serdeable},
|
models::{Serdeable, radarr_models::RadarrSerdeable},
|
||||||
network::{radarr_network::RadarrEvent, MockNetworkTrait, NetworkEvent},
|
network::{MockNetworkTrait, NetworkEvent, radarr_network::RadarrEvent},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[rstest]
|
#[rstest]
|
||||||
@@ -96,13 +96,13 @@ mod tests {
|
|||||||
json!({"testResponse": "response"}),
|
json!({"testResponse": "response"}),
|
||||||
)))
|
)))
|
||||||
});
|
});
|
||||||
let app_arc = Arc::new(Mutex::new(App::default()));
|
let app_arc = Arc::new(Mutex::new(App::test_default()));
|
||||||
|
|
||||||
let result = RadarrRefreshCommandHandler::with(&app_arc, refresh_command, &mut mock_network)
|
let result = RadarrRefreshCommandHandler::with(&app_arc, refresh_command, &mut mock_network)
|
||||||
.handle()
|
.handle()
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@@ -120,7 +120,7 @@ mod tests {
|
|||||||
json!({"testResponse": "response"}),
|
json!({"testResponse": "response"}),
|
||||||
)))
|
)))
|
||||||
});
|
});
|
||||||
let app_arc = Arc::new(Mutex::new(App::default()));
|
let app_arc = Arc::new(Mutex::new(App::test_default()));
|
||||||
let refresh_movie_command = RadarrRefreshCommand::Movie { movie_id: 1 };
|
let refresh_movie_command = RadarrRefreshCommand::Movie { movie_id: 1 };
|
||||||
|
|
||||||
let result =
|
let result =
|
||||||
@@ -128,7 +128,7 @@ mod tests {
|
|||||||
.handle()
|
.handle()
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ use crate::{
|
|||||||
app::App,
|
app::App,
|
||||||
cli::{CliCommandHandler, Command},
|
cli::{CliCommandHandler, Command},
|
||||||
models::sonarr_models::{AddSeriesBody, AddSeriesOptions, SeriesMonitor, SeriesType},
|
models::sonarr_models::{AddSeriesBody, AddSeriesOptions, SeriesMonitor, SeriesType},
|
||||||
network::{sonarr_network::SonarrEvent, NetworkTrait},
|
network::{NetworkTrait, sonarr_network::SonarrEvent},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use clap::{error::ErrorKind, CommandFactory, Parser};
|
use clap::{CommandFactory, Parser, error::ErrorKind};
|
||||||
use pretty_assertions::assert_eq;
|
use pretty_assertions::assert_eq;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
cli::{
|
|
||||||
sonarr::{add_command_handler::SonarrAddCommand, SonarrCommand},
|
|
||||||
Command,
|
|
||||||
},
|
|
||||||
Cli,
|
Cli,
|
||||||
|
cli::{
|
||||||
|
Command,
|
||||||
|
sonarr::{SonarrCommand, add_command_handler::SonarrAddCommand},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -34,7 +34,7 @@ mod tests {
|
|||||||
let result =
|
let result =
|
||||||
Cli::command().try_get_matches_from(["managarr", "sonarr", "add", "root-folder"]);
|
Cli::command().try_get_matches_from(["managarr", "sonarr", "add", "root-folder"]);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert_err!(&result);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
result.unwrap_err().kind(),
|
result.unwrap_err().kind(),
|
||||||
ErrorKind::MissingRequiredArgument
|
ErrorKind::MissingRequiredArgument
|
||||||
@@ -56,18 +56,19 @@ mod tests {
|
|||||||
"/nfs/test",
|
"/nfs/test",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
|
|
||||||
if let Some(Command::Sonarr(SonarrCommand::Add(add_command))) = result.unwrap().command {
|
let Some(Command::Sonarr(SonarrCommand::Add(add_command))) = result.unwrap().command else {
|
||||||
assert_eq!(add_command, expected_args);
|
panic!("Unexpected command type");
|
||||||
}
|
};
|
||||||
|
assert_eq!(add_command, expected_args);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_add_series_requires_arguments() {
|
fn test_add_series_requires_arguments() {
|
||||||
let result = Cli::command().try_get_matches_from(["managarr", "sonarr", "add", "series"]);
|
let result = Cli::command().try_get_matches_from(["managarr", "sonarr", "add", "series"]);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert_err!(&result);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
result.unwrap_err().kind(),
|
result.unwrap_err().kind(),
|
||||||
ErrorKind::MissingRequiredArgument
|
ErrorKind::MissingRequiredArgument
|
||||||
@@ -91,7 +92,7 @@ mod tests {
|
|||||||
"test",
|
"test",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert_err!(&result);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
result.unwrap_err().kind(),
|
result.unwrap_err().kind(),
|
||||||
ErrorKind::MissingRequiredArgument
|
ErrorKind::MissingRequiredArgument
|
||||||
@@ -115,7 +116,7 @@ mod tests {
|
|||||||
"1",
|
"1",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert_err!(&result);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
result.unwrap_err().kind(),
|
result.unwrap_err().kind(),
|
||||||
ErrorKind::MissingRequiredArgument
|
ErrorKind::MissingRequiredArgument
|
||||||
@@ -139,7 +140,7 @@ mod tests {
|
|||||||
"test",
|
"test",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert_err!(&result);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
result.unwrap_err().kind(),
|
result.unwrap_err().kind(),
|
||||||
ErrorKind::MissingRequiredArgument
|
ErrorKind::MissingRequiredArgument
|
||||||
@@ -163,7 +164,7 @@ mod tests {
|
|||||||
"test",
|
"test",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert_err!(&result);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
result.unwrap_err().kind(),
|
result.unwrap_err().kind(),
|
||||||
ErrorKind::MissingRequiredArgument
|
ErrorKind::MissingRequiredArgument
|
||||||
@@ -187,7 +188,7 @@ mod tests {
|
|||||||
"test",
|
"test",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert_err!(&result);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
result.unwrap_err().kind(),
|
result.unwrap_err().kind(),
|
||||||
ErrorKind::MissingRequiredArgument
|
ErrorKind::MissingRequiredArgument
|
||||||
@@ -216,7 +217,7 @@ mod tests {
|
|||||||
flag,
|
flag,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert_err!(&result);
|
||||||
assert_eq!(result.unwrap_err().kind(), ErrorKind::InvalidValue);
|
assert_eq!(result.unwrap_err().kind(), ErrorKind::InvalidValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -239,7 +240,7 @@ mod tests {
|
|||||||
"1",
|
"1",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -263,7 +264,7 @@ mod tests {
|
|||||||
"test",
|
"test",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert_err!(&result);
|
||||||
assert_eq!(result.unwrap_err().kind(), ErrorKind::InvalidValue);
|
assert_eq!(result.unwrap_err().kind(), ErrorKind::InvalidValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -288,7 +289,7 @@ mod tests {
|
|||||||
"test",
|
"test",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert_err!(&result);
|
||||||
assert_eq!(result.unwrap_err().kind(), ErrorKind::InvalidValue);
|
assert_eq!(result.unwrap_err().kind(), ErrorKind::InvalidValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -325,10 +326,11 @@ mod tests {
|
|||||||
"1",
|
"1",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
if let Some(Command::Sonarr(SonarrCommand::Add(add_command))) = result.unwrap().command {
|
let Some(Command::Sonarr(SonarrCommand::Add(add_command))) = result.unwrap().command else {
|
||||||
assert_eq!(add_command, expected_args);
|
panic!("Unexpected command type");
|
||||||
}
|
};
|
||||||
|
assert_eq!(add_command, expected_args);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -368,10 +370,11 @@ mod tests {
|
|||||||
"2",
|
"2",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
if let Some(Command::Sonarr(SonarrCommand::Add(add_command))) = result.unwrap().command {
|
let Some(Command::Sonarr(SonarrCommand::Add(add_command))) = result.unwrap().command else {
|
||||||
assert_eq!(add_command, expected_args);
|
panic!("Unexpected command type");
|
||||||
}
|
};
|
||||||
|
assert_eq!(add_command, expected_args);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -418,17 +421,18 @@ mod tests {
|
|||||||
"--no-search-for-series",
|
"--no-search-for-series",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
if let Some(Command::Sonarr(SonarrCommand::Add(add_command))) = result.unwrap().command {
|
let Some(Command::Sonarr(SonarrCommand::Add(add_command))) = result.unwrap().command else {
|
||||||
assert_eq!(add_command, expected_args);
|
panic!("Unexpected command type");
|
||||||
}
|
};
|
||||||
|
assert_eq!(add_command, expected_args);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_add_tag_requires_arguments() {
|
fn test_add_tag_requires_arguments() {
|
||||||
let result = Cli::command().try_get_matches_from(["managarr", "sonarr", "add", "tag"]);
|
let result = Cli::command().try_get_matches_from(["managarr", "sonarr", "add", "tag"]);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert_err!(&result);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
result.unwrap_err().kind(),
|
result.unwrap_err().kind(),
|
||||||
ErrorKind::MissingRequiredArgument
|
ErrorKind::MissingRequiredArgument
|
||||||
@@ -443,11 +447,12 @@ mod tests {
|
|||||||
|
|
||||||
let result = Cli::try_parse_from(["managarr", "sonarr", "add", "tag", "--name", "test"]);
|
let result = Cli::try_parse_from(["managarr", "sonarr", "add", "tag", "--name", "test"]);
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
|
|
||||||
if let Some(Command::Sonarr(SonarrCommand::Add(add_command))) = result.unwrap().command {
|
let Some(Command::Sonarr(SonarrCommand::Add(add_command))) = result.unwrap().command else {
|
||||||
assert_eq!(add_command, expected_args);
|
panic!("Unexpected command type");
|
||||||
}
|
};
|
||||||
|
assert_eq!(add_command, expected_args);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -456,14 +461,14 @@ mod tests {
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
app::App,
|
app::App,
|
||||||
cli::{sonarr::add_command_handler::SonarrAddCommandHandler, CliCommandHandler},
|
cli::{CliCommandHandler, sonarr::add_command_handler::SonarrAddCommandHandler},
|
||||||
models::{
|
models::{
|
||||||
|
Serdeable,
|
||||||
sonarr_models::{
|
sonarr_models::{
|
||||||
AddSeriesBody, AddSeriesOptions, SeriesMonitor, SeriesType, SonarrSerdeable,
|
AddSeriesBody, AddSeriesOptions, SeriesMonitor, SeriesType, SonarrSerdeable,
|
||||||
},
|
},
|
||||||
Serdeable,
|
|
||||||
},
|
},
|
||||||
network::{sonarr_network::SonarrEvent, MockNetworkTrait, NetworkEvent},
|
network::{MockNetworkTrait, NetworkEvent, sonarr_network::SonarrEvent},
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
@@ -491,7 +496,7 @@ mod tests {
|
|||||||
json!({"testResponse": "response"}),
|
json!({"testResponse": "response"}),
|
||||||
)))
|
)))
|
||||||
});
|
});
|
||||||
let app_arc = Arc::new(Mutex::new(App::default()));
|
let app_arc = Arc::new(Mutex::new(App::test_default()));
|
||||||
let add_root_folder_command = SonarrAddCommand::RootFolder {
|
let add_root_folder_command = SonarrAddCommand::RootFolder {
|
||||||
root_folder_path: expected_root_folder_path,
|
root_folder_path: expected_root_folder_path,
|
||||||
};
|
};
|
||||||
@@ -501,7 +506,7 @@ mod tests {
|
|||||||
.handle()
|
.handle()
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@@ -535,7 +540,7 @@ mod tests {
|
|||||||
json!({"testResponse": "response"}),
|
json!({"testResponse": "response"}),
|
||||||
)))
|
)))
|
||||||
});
|
});
|
||||||
let app_arc = Arc::new(Mutex::new(App::default()));
|
let app_arc = Arc::new(Mutex::new(App::test_default()));
|
||||||
let add_series_command = SonarrAddCommand::Series {
|
let add_series_command = SonarrAddCommand::Series {
|
||||||
tvdb_id: 1,
|
tvdb_id: 1,
|
||||||
title: "test".to_owned(),
|
title: "test".to_owned(),
|
||||||
@@ -554,7 +559,7 @@ mod tests {
|
|||||||
.handle()
|
.handle()
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@@ -572,7 +577,7 @@ mod tests {
|
|||||||
json!({"testResponse": "response"}),
|
json!({"testResponse": "response"}),
|
||||||
)))
|
)))
|
||||||
});
|
});
|
||||||
let app_arc = Arc::new(Mutex::new(App::default()));
|
let app_arc = Arc::new(Mutex::new(App::test_default()));
|
||||||
let add_tag_command = SonarrAddCommand::Tag {
|
let add_tag_command = SonarrAddCommand::Tag {
|
||||||
name: expected_tag_name,
|
name: expected_tag_name,
|
||||||
};
|
};
|
||||||
@@ -581,7 +586,7 @@ mod tests {
|
|||||||
.handle()
|
.handle()
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ use crate::{
|
|||||||
app::App,
|
app::App,
|
||||||
cli::{CliCommandHandler, Command},
|
cli::{CliCommandHandler, Command},
|
||||||
models::sonarr_models::DeleteSeriesParams,
|
models::sonarr_models::DeleteSeriesParams,
|
||||||
network::{sonarr_network::SonarrEvent, NetworkTrait},
|
network::{NetworkTrait, sonarr_network::SonarrEvent},
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::SonarrCommand;
|
use super::SonarrCommand;
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::{
|
use crate::{
|
||||||
cli::{
|
|
||||||
sonarr::{delete_command_handler::SonarrDeleteCommand, SonarrCommand},
|
|
||||||
Command,
|
|
||||||
},
|
|
||||||
Cli,
|
Cli,
|
||||||
|
cli::{
|
||||||
|
Command,
|
||||||
|
sonarr::{SonarrCommand, delete_command_handler::SonarrDeleteCommand},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
use clap::{error::ErrorKind, CommandFactory, Parser};
|
use clap::{CommandFactory, Parser, error::ErrorKind};
|
||||||
use pretty_assertions::assert_eq;
|
use pretty_assertions::assert_eq;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -30,7 +30,7 @@ mod tests {
|
|||||||
let result =
|
let result =
|
||||||
Cli::command().try_get_matches_from(["managarr", "sonarr", "delete", "blocklist-item"]);
|
Cli::command().try_get_matches_from(["managarr", "sonarr", "delete", "blocklist-item"]);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert_err!(&result);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
result.unwrap_err().kind(),
|
result.unwrap_err().kind(),
|
||||||
ErrorKind::MissingRequiredArgument
|
ErrorKind::MissingRequiredArgument
|
||||||
@@ -52,12 +52,13 @@ mod tests {
|
|||||||
"1",
|
"1",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
|
|
||||||
if let Some(Command::Sonarr(SonarrCommand::Delete(delete_command))) = result.unwrap().command
|
let Some(Command::Sonarr(SonarrCommand::Delete(delete_command))) = result.unwrap().command
|
||||||
{
|
else {
|
||||||
assert_eq!(delete_command, expected_args);
|
panic!("Unexpected command type");
|
||||||
}
|
};
|
||||||
|
assert_eq!(delete_command, expected_args);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -65,7 +66,7 @@ mod tests {
|
|||||||
let result =
|
let result =
|
||||||
Cli::command().try_get_matches_from(["managarr", "sonarr", "delete", "download"]);
|
Cli::command().try_get_matches_from(["managarr", "sonarr", "delete", "download"]);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert_err!(&result);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
result.unwrap_err().kind(),
|
result.unwrap_err().kind(),
|
||||||
ErrorKind::MissingRequiredArgument
|
ErrorKind::MissingRequiredArgument
|
||||||
@@ -85,12 +86,13 @@ mod tests {
|
|||||||
"1",
|
"1",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
|
|
||||||
if let Some(Command::Sonarr(SonarrCommand::Delete(delete_command))) = result.unwrap().command
|
let Some(Command::Sonarr(SonarrCommand::Delete(delete_command))) = result.unwrap().command
|
||||||
{
|
else {
|
||||||
assert_eq!(delete_command, expected_args);
|
panic!("Unexpected command type");
|
||||||
}
|
};
|
||||||
|
assert_eq!(delete_command, expected_args);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -98,7 +100,7 @@ mod tests {
|
|||||||
let result =
|
let result =
|
||||||
Cli::command().try_get_matches_from(["managarr", "sonarr", "delete", "episode-file"]);
|
Cli::command().try_get_matches_from(["managarr", "sonarr", "delete", "episode-file"]);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert_err!(&result);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
result.unwrap_err().kind(),
|
result.unwrap_err().kind(),
|
||||||
ErrorKind::MissingRequiredArgument
|
ErrorKind::MissingRequiredArgument
|
||||||
@@ -118,19 +120,20 @@ mod tests {
|
|||||||
"1",
|
"1",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
|
|
||||||
if let Some(Command::Sonarr(SonarrCommand::Delete(delete_command))) = result.unwrap().command
|
let Some(Command::Sonarr(SonarrCommand::Delete(delete_command))) = result.unwrap().command
|
||||||
{
|
else {
|
||||||
assert_eq!(delete_command, expected_args);
|
panic!("Unexpected command type");
|
||||||
}
|
};
|
||||||
|
assert_eq!(delete_command, expected_args);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_delete_indexer_requires_arguments() {
|
fn test_delete_indexer_requires_arguments() {
|
||||||
let result = Cli::command().try_get_matches_from(["managarr", "sonarr", "delete", "indexer"]);
|
let result = Cli::command().try_get_matches_from(["managarr", "sonarr", "delete", "indexer"]);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert_err!(&result);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
result.unwrap_err().kind(),
|
result.unwrap_err().kind(),
|
||||||
ErrorKind::MissingRequiredArgument
|
ErrorKind::MissingRequiredArgument
|
||||||
@@ -150,12 +153,13 @@ mod tests {
|
|||||||
"1",
|
"1",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
|
|
||||||
if let Some(Command::Sonarr(SonarrCommand::Delete(delete_command))) = result.unwrap().command
|
let Some(Command::Sonarr(SonarrCommand::Delete(delete_command))) = result.unwrap().command
|
||||||
{
|
else {
|
||||||
assert_eq!(delete_command, expected_args);
|
panic!("Unexpected command type");
|
||||||
}
|
};
|
||||||
|
assert_eq!(delete_command, expected_args);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -163,7 +167,7 @@ mod tests {
|
|||||||
let result =
|
let result =
|
||||||
Cli::command().try_get_matches_from(["managarr", "sonarr", "delete", "root-folder"]);
|
Cli::command().try_get_matches_from(["managarr", "sonarr", "delete", "root-folder"]);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert_err!(&result);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
result.unwrap_err().kind(),
|
result.unwrap_err().kind(),
|
||||||
ErrorKind::MissingRequiredArgument
|
ErrorKind::MissingRequiredArgument
|
||||||
@@ -183,19 +187,20 @@ mod tests {
|
|||||||
"1",
|
"1",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
|
|
||||||
if let Some(Command::Sonarr(SonarrCommand::Delete(delete_command))) = result.unwrap().command
|
let Some(Command::Sonarr(SonarrCommand::Delete(delete_command))) = result.unwrap().command
|
||||||
{
|
else {
|
||||||
assert_eq!(delete_command, expected_args);
|
panic!("Unexpected command type");
|
||||||
}
|
};
|
||||||
|
assert_eq!(delete_command, expected_args);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_delete_series_requires_arguments() {
|
fn test_delete_series_requires_arguments() {
|
||||||
let result = Cli::command().try_get_matches_from(["managarr", "sonarr", "delete", "series"]);
|
let result = Cli::command().try_get_matches_from(["managarr", "sonarr", "delete", "series"]);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert_err!(&result);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
result.unwrap_err().kind(),
|
result.unwrap_err().kind(),
|
||||||
ErrorKind::MissingRequiredArgument
|
ErrorKind::MissingRequiredArgument
|
||||||
@@ -213,12 +218,13 @@ mod tests {
|
|||||||
let result =
|
let result =
|
||||||
Cli::try_parse_from(["managarr", "sonarr", "delete", "series", "--series-id", "1"]);
|
Cli::try_parse_from(["managarr", "sonarr", "delete", "series", "--series-id", "1"]);
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
|
|
||||||
if let Some(Command::Sonarr(SonarrCommand::Delete(delete_command))) = result.unwrap().command
|
let Some(Command::Sonarr(SonarrCommand::Delete(delete_command))) = result.unwrap().command
|
||||||
{
|
else {
|
||||||
assert_eq!(delete_command, expected_args);
|
panic!("Unexpected command type");
|
||||||
}
|
};
|
||||||
|
assert_eq!(delete_command, expected_args);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -240,19 +246,20 @@ mod tests {
|
|||||||
"--add-list-exclusion",
|
"--add-list-exclusion",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
|
|
||||||
if let Some(Command::Sonarr(SonarrCommand::Delete(delete_command))) = result.unwrap().command
|
let Some(Command::Sonarr(SonarrCommand::Delete(delete_command))) = result.unwrap().command
|
||||||
{
|
else {
|
||||||
assert_eq!(delete_command, expected_args);
|
panic!("Unexpected command type");
|
||||||
}
|
};
|
||||||
|
assert_eq!(delete_command, expected_args);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_delete_tag_requires_arguments() {
|
fn test_delete_tag_requires_arguments() {
|
||||||
let result = Cli::command().try_get_matches_from(["managarr", "sonarr", "delete", "tag"]);
|
let result = Cli::command().try_get_matches_from(["managarr", "sonarr", "delete", "tag"]);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert_err!(&result);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
result.unwrap_err().kind(),
|
result.unwrap_err().kind(),
|
||||||
ErrorKind::MissingRequiredArgument
|
ErrorKind::MissingRequiredArgument
|
||||||
@@ -265,12 +272,13 @@ mod tests {
|
|||||||
|
|
||||||
let result = Cli::try_parse_from(["managarr", "sonarr", "delete", "tag", "--tag-id", "1"]);
|
let result = Cli::try_parse_from(["managarr", "sonarr", "delete", "tag", "--tag-id", "1"]);
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
|
|
||||||
if let Some(Command::Sonarr(SonarrCommand::Delete(delete_command))) = result.unwrap().command
|
let Some(Command::Sonarr(SonarrCommand::Delete(delete_command))) = result.unwrap().command
|
||||||
{
|
else {
|
||||||
assert_eq!(delete_command, expected_args);
|
panic!("Unexpected command type");
|
||||||
}
|
};
|
||||||
|
assert_eq!(delete_command, expected_args);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -284,14 +292,14 @@ mod tests {
|
|||||||
use crate::{
|
use crate::{
|
||||||
app::App,
|
app::App,
|
||||||
cli::{
|
cli::{
|
||||||
sonarr::delete_command_handler::{SonarrDeleteCommand, SonarrDeleteCommandHandler},
|
|
||||||
CliCommandHandler,
|
CliCommandHandler,
|
||||||
|
sonarr::delete_command_handler::{SonarrDeleteCommand, SonarrDeleteCommandHandler},
|
||||||
},
|
},
|
||||||
models::{
|
models::{
|
||||||
sonarr_models::{DeleteSeriesParams, SonarrSerdeable},
|
|
||||||
Serdeable,
|
Serdeable,
|
||||||
|
sonarr_models::{DeleteSeriesParams, SonarrSerdeable},
|
||||||
},
|
},
|
||||||
network::{sonarr_network::SonarrEvent, MockNetworkTrait, NetworkEvent},
|
network::{MockNetworkTrait, NetworkEvent, sonarr_network::SonarrEvent},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@@ -309,7 +317,7 @@ mod tests {
|
|||||||
json!({"testResponse": "response"}),
|
json!({"testResponse": "response"}),
|
||||||
)))
|
)))
|
||||||
});
|
});
|
||||||
let app_arc = Arc::new(Mutex::new(App::default()));
|
let app_arc = Arc::new(Mutex::new(App::test_default()));
|
||||||
let delete_blocklist_item_command = SonarrDeleteCommand::BlocklistItem {
|
let delete_blocklist_item_command = SonarrDeleteCommand::BlocklistItem {
|
||||||
blocklist_item_id: 1,
|
blocklist_item_id: 1,
|
||||||
};
|
};
|
||||||
@@ -322,7 +330,7 @@ mod tests {
|
|||||||
.handle()
|
.handle()
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@@ -340,7 +348,7 @@ mod tests {
|
|||||||
json!({"testResponse": "response"}),
|
json!({"testResponse": "response"}),
|
||||||
)))
|
)))
|
||||||
});
|
});
|
||||||
let app_arc = Arc::new(Mutex::new(App::default()));
|
let app_arc = Arc::new(Mutex::new(App::test_default()));
|
||||||
let delete_download_command = SonarrDeleteCommand::Download { download_id: 1 };
|
let delete_download_command = SonarrDeleteCommand::Download { download_id: 1 };
|
||||||
|
|
||||||
let result =
|
let result =
|
||||||
@@ -348,7 +356,7 @@ mod tests {
|
|||||||
.handle()
|
.handle()
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@@ -366,7 +374,7 @@ mod tests {
|
|||||||
json!({"testResponse": "response"}),
|
json!({"testResponse": "response"}),
|
||||||
)))
|
)))
|
||||||
});
|
});
|
||||||
let app_arc = Arc::new(Mutex::new(App::default()));
|
let app_arc = Arc::new(Mutex::new(App::test_default()));
|
||||||
let delete_episode_file_command = SonarrDeleteCommand::EpisodeFile { episode_file_id: 1 };
|
let delete_episode_file_command = SonarrDeleteCommand::EpisodeFile { episode_file_id: 1 };
|
||||||
|
|
||||||
let result =
|
let result =
|
||||||
@@ -374,7 +382,7 @@ mod tests {
|
|||||||
.handle()
|
.handle()
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@@ -392,7 +400,7 @@ mod tests {
|
|||||||
json!({"testResponse": "response"}),
|
json!({"testResponse": "response"}),
|
||||||
)))
|
)))
|
||||||
});
|
});
|
||||||
let app_arc = Arc::new(Mutex::new(App::default()));
|
let app_arc = Arc::new(Mutex::new(App::test_default()));
|
||||||
let delete_indexer_command = SonarrDeleteCommand::Indexer { indexer_id: 1 };
|
let delete_indexer_command = SonarrDeleteCommand::Indexer { indexer_id: 1 };
|
||||||
|
|
||||||
let result =
|
let result =
|
||||||
@@ -400,7 +408,7 @@ mod tests {
|
|||||||
.handle()
|
.handle()
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@@ -418,7 +426,7 @@ mod tests {
|
|||||||
json!({"testResponse": "response"}),
|
json!({"testResponse": "response"}),
|
||||||
)))
|
)))
|
||||||
});
|
});
|
||||||
let app_arc = Arc::new(Mutex::new(App::default()));
|
let app_arc = Arc::new(Mutex::new(App::test_default()));
|
||||||
let delete_root_folder_command = SonarrDeleteCommand::RootFolder { root_folder_id: 1 };
|
let delete_root_folder_command = SonarrDeleteCommand::RootFolder { root_folder_id: 1 };
|
||||||
|
|
||||||
let result =
|
let result =
|
||||||
@@ -426,7 +434,7 @@ mod tests {
|
|||||||
.handle()
|
.handle()
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@@ -448,7 +456,7 @@ mod tests {
|
|||||||
json!({"testResponse": "response"}),
|
json!({"testResponse": "response"}),
|
||||||
)))
|
)))
|
||||||
});
|
});
|
||||||
let app_arc = Arc::new(Mutex::new(App::default()));
|
let app_arc = Arc::new(Mutex::new(App::test_default()));
|
||||||
let delete_series_command = SonarrDeleteCommand::Series {
|
let delete_series_command = SonarrDeleteCommand::Series {
|
||||||
series_id: 1,
|
series_id: 1,
|
||||||
delete_files_from_disk: true,
|
delete_files_from_disk: true,
|
||||||
@@ -460,7 +468,7 @@ mod tests {
|
|||||||
.handle()
|
.handle()
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@@ -478,7 +486,7 @@ mod tests {
|
|||||||
json!({"testResponse": "response"}),
|
json!({"testResponse": "response"}),
|
||||||
)))
|
)))
|
||||||
});
|
});
|
||||||
let app_arc = Arc::new(Mutex::new(App::default()));
|
let app_arc = Arc::new(Mutex::new(App::test_default()));
|
||||||
let delete_tag_command = SonarrDeleteCommand::Tag { tag_id: 1 };
|
let delete_tag_command = SonarrDeleteCommand::Tag { tag_id: 1 };
|
||||||
|
|
||||||
let result =
|
let result =
|
||||||
@@ -486,7 +494,7 @@ mod tests {
|
|||||||
.handle()
|
.handle()
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ use crate::{
|
|||||||
app::App,
|
app::App,
|
||||||
cli::{CliCommandHandler, Command},
|
cli::{CliCommandHandler, Command},
|
||||||
models::sonarr_models::SonarrReleaseDownloadBody,
|
models::sonarr_models::SonarrReleaseDownloadBody,
|
||||||
network::{sonarr_network::SonarrEvent, NetworkTrait},
|
network::{NetworkTrait, sonarr_network::SonarrEvent},
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::SonarrCommand;
|
use super::SonarrCommand;
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::{
|
use crate::{
|
||||||
cli::{
|
|
||||||
sonarr::{download_command_handler::SonarrDownloadCommand, SonarrCommand},
|
|
||||||
Command,
|
|
||||||
},
|
|
||||||
Cli,
|
Cli,
|
||||||
|
cli::{
|
||||||
|
Command,
|
||||||
|
sonarr::{SonarrCommand, download_command_handler::SonarrDownloadCommand},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
use clap::CommandFactory;
|
use clap::CommandFactory;
|
||||||
use pretty_assertions::assert_eq;
|
use pretty_assertions::assert_eq;
|
||||||
@@ -41,7 +41,7 @@ mod tests {
|
|||||||
"1",
|
"1",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert_err!(&result);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
result.unwrap_err().kind(),
|
result.unwrap_err().kind(),
|
||||||
ErrorKind::MissingRequiredArgument
|
ErrorKind::MissingRequiredArgument
|
||||||
@@ -61,7 +61,7 @@ mod tests {
|
|||||||
"1",
|
"1",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert_err!(&result);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
result.unwrap_err().kind(),
|
result.unwrap_err().kind(),
|
||||||
ErrorKind::MissingRequiredArgument
|
ErrorKind::MissingRequiredArgument
|
||||||
@@ -81,7 +81,7 @@ mod tests {
|
|||||||
"1",
|
"1",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert_err!(&result);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
result.unwrap_err().kind(),
|
result.unwrap_err().kind(),
|
||||||
ErrorKind::MissingRequiredArgument
|
ErrorKind::MissingRequiredArgument
|
||||||
@@ -103,7 +103,7 @@ mod tests {
|
|||||||
"1",
|
"1",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -121,7 +121,7 @@ mod tests {
|
|||||||
"1",
|
"1",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert_err!(&result);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
result.unwrap_err().kind(),
|
result.unwrap_err().kind(),
|
||||||
ErrorKind::MissingRequiredArgument
|
ErrorKind::MissingRequiredArgument
|
||||||
@@ -143,7 +143,7 @@ mod tests {
|
|||||||
"1",
|
"1",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert_err!(&result);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
result.unwrap_err().kind(),
|
result.unwrap_err().kind(),
|
||||||
ErrorKind::MissingRequiredArgument
|
ErrorKind::MissingRequiredArgument
|
||||||
@@ -165,7 +165,7 @@ mod tests {
|
|||||||
"1",
|
"1",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert_err!(&result);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
result.unwrap_err().kind(),
|
result.unwrap_err().kind(),
|
||||||
ErrorKind::MissingRequiredArgument
|
ErrorKind::MissingRequiredArgument
|
||||||
@@ -187,7 +187,7 @@ mod tests {
|
|||||||
"1",
|
"1",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert_err!(&result);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
result.unwrap_err().kind(),
|
result.unwrap_err().kind(),
|
||||||
ErrorKind::MissingRequiredArgument
|
ErrorKind::MissingRequiredArgument
|
||||||
@@ -211,7 +211,7 @@ mod tests {
|
|||||||
"1",
|
"1",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -227,7 +227,7 @@ mod tests {
|
|||||||
"1",
|
"1",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert_err!(&result);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
result.unwrap_err().kind(),
|
result.unwrap_err().kind(),
|
||||||
ErrorKind::MissingRequiredArgument
|
ErrorKind::MissingRequiredArgument
|
||||||
@@ -247,7 +247,7 @@ mod tests {
|
|||||||
"1",
|
"1",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert_err!(&result);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
result.unwrap_err().kind(),
|
result.unwrap_err().kind(),
|
||||||
ErrorKind::MissingRequiredArgument
|
ErrorKind::MissingRequiredArgument
|
||||||
@@ -267,7 +267,7 @@ mod tests {
|
|||||||
"1",
|
"1",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert_err!(&result);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
result.unwrap_err().kind(),
|
result.unwrap_err().kind(),
|
||||||
ErrorKind::MissingRequiredArgument
|
ErrorKind::MissingRequiredArgument
|
||||||
@@ -289,7 +289,7 @@ mod tests {
|
|||||||
"1",
|
"1",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -303,14 +303,14 @@ mod tests {
|
|||||||
use crate::{
|
use crate::{
|
||||||
app::App,
|
app::App,
|
||||||
cli::{
|
cli::{
|
||||||
sonarr::download_command_handler::{SonarrDownloadCommand, SonarrDownloadCommandHandler},
|
|
||||||
CliCommandHandler,
|
CliCommandHandler,
|
||||||
|
sonarr::download_command_handler::{SonarrDownloadCommand, SonarrDownloadCommandHandler},
|
||||||
},
|
},
|
||||||
models::{
|
models::{
|
||||||
sonarr_models::{SonarrReleaseDownloadBody, SonarrSerdeable},
|
|
||||||
Serdeable,
|
Serdeable,
|
||||||
|
sonarr_models::{SonarrReleaseDownloadBody, SonarrSerdeable},
|
||||||
},
|
},
|
||||||
network::{sonarr_network::SonarrEvent, MockNetworkTrait, NetworkEvent},
|
network::{MockNetworkTrait, NetworkEvent, sonarr_network::SonarrEvent},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@@ -333,7 +333,7 @@ mod tests {
|
|||||||
json!({"testResponse": "response"}),
|
json!({"testResponse": "response"}),
|
||||||
)))
|
)))
|
||||||
});
|
});
|
||||||
let app_arc = Arc::new(Mutex::new(App::default()));
|
let app_arc = Arc::new(Mutex::new(App::test_default()));
|
||||||
let download_release_command = SonarrDownloadCommand::Series {
|
let download_release_command = SonarrDownloadCommand::Series {
|
||||||
guid: "guid".to_owned(),
|
guid: "guid".to_owned(),
|
||||||
indexer_id: 1,
|
indexer_id: 1,
|
||||||
@@ -345,7 +345,7 @@ mod tests {
|
|||||||
.handle()
|
.handle()
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@@ -369,7 +369,7 @@ mod tests {
|
|||||||
json!({"testResponse": "response"}),
|
json!({"testResponse": "response"}),
|
||||||
)))
|
)))
|
||||||
});
|
});
|
||||||
let app_arc = Arc::new(Mutex::new(App::default()));
|
let app_arc = Arc::new(Mutex::new(App::test_default()));
|
||||||
let download_release_command = SonarrDownloadCommand::Season {
|
let download_release_command = SonarrDownloadCommand::Season {
|
||||||
guid: "guid".to_owned(),
|
guid: "guid".to_owned(),
|
||||||
indexer_id: 1,
|
indexer_id: 1,
|
||||||
@@ -382,7 +382,7 @@ mod tests {
|
|||||||
.handle()
|
.handle()
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@@ -405,7 +405,7 @@ mod tests {
|
|||||||
json!({"testResponse": "response"}),
|
json!({"testResponse": "response"}),
|
||||||
)))
|
)))
|
||||||
});
|
});
|
||||||
let app_arc = Arc::new(Mutex::new(App::default()));
|
let app_arc = Arc::new(Mutex::new(App::test_default()));
|
||||||
let download_release_command = SonarrDownloadCommand::Episode {
|
let download_release_command = SonarrDownloadCommand::Episode {
|
||||||
guid: "guid".to_owned(),
|
guid: "guid".to_owned(),
|
||||||
indexer_id: 1,
|
indexer_id: 1,
|
||||||
@@ -417,7 +417,7 @@ mod tests {
|
|||||||
.handle()
|
.handle()
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,13 +6,13 @@ use tokio::sync::Mutex;
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
app::App,
|
app::App,
|
||||||
cli::{mutex_flags_or_option, CliCommandHandler, Command},
|
cli::{CliCommandHandler, Command, mutex_flags_or_option},
|
||||||
models::{
|
models::{
|
||||||
|
Serdeable,
|
||||||
servarr_models::EditIndexerParams,
|
servarr_models::EditIndexerParams,
|
||||||
sonarr_models::{EditSeriesParams, IndexerSettings, SeriesType, SonarrSerdeable},
|
sonarr_models::{EditSeriesParams, IndexerSettings, SeriesType, SonarrSerdeable},
|
||||||
Serdeable,
|
|
||||||
},
|
},
|
||||||
network::{sonarr_network::SonarrEvent, NetworkTrait},
|
network::{NetworkTrait, sonarr_network::SonarrEvent},
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::SonarrCommand;
|
use super::SonarrCommand;
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::cli::{
|
use crate::cli::{
|
||||||
sonarr::{edit_command_handler::SonarrEditCommand, SonarrCommand},
|
|
||||||
Command,
|
Command,
|
||||||
|
sonarr::{SonarrCommand, edit_command_handler::SonarrEditCommand},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -20,10 +20,10 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
mod cli {
|
mod cli {
|
||||||
use crate::{models::sonarr_models::SeriesType, Cli};
|
use crate::{Cli, models::sonarr_models::SeriesType};
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use clap::{error::ErrorKind, CommandFactory, Parser};
|
use clap::{CommandFactory, Parser, error::ErrorKind};
|
||||||
use pretty_assertions::assert_eq;
|
use pretty_assertions::assert_eq;
|
||||||
use rstest::rstest;
|
use rstest::rstest;
|
||||||
|
|
||||||
@@ -32,7 +32,7 @@ mod tests {
|
|||||||
let result =
|
let result =
|
||||||
Cli::command().try_get_matches_from(["managarr", "sonarr", "edit", "all-indexer-settings"]);
|
Cli::command().try_get_matches_from(["managarr", "sonarr", "edit", "all-indexer-settings"]);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert_err!(&result);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
result.unwrap_err().kind(),
|
result.unwrap_err().kind(),
|
||||||
ErrorKind::MissingRequiredArgument
|
ErrorKind::MissingRequiredArgument
|
||||||
@@ -57,7 +57,7 @@ mod tests {
|
|||||||
flag,
|
flag,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert_err!(&result);
|
||||||
assert_eq!(result.unwrap_err().kind(), ErrorKind::InvalidValue);
|
assert_eq!(result.unwrap_err().kind(), ErrorKind::InvalidValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -78,11 +78,12 @@ mod tests {
|
|||||||
"1",
|
"1",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
|
|
||||||
if let Some(Command::Sonarr(SonarrCommand::Edit(edit_command))) = result.unwrap().command {
|
let Some(Command::Sonarr(SonarrCommand::Edit(edit_command))) = result.unwrap().command else {
|
||||||
assert_eq!(edit_command, expected_args);
|
panic!("Unexpected command type");
|
||||||
}
|
};
|
||||||
|
assert_eq!(edit_command, expected_args);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -108,18 +109,19 @@ mod tests {
|
|||||||
"1",
|
"1",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
|
|
||||||
if let Some(Command::Sonarr(SonarrCommand::Edit(edit_command))) = result.unwrap().command {
|
let Some(Command::Sonarr(SonarrCommand::Edit(edit_command))) = result.unwrap().command else {
|
||||||
assert_eq!(edit_command, expected_args);
|
panic!("Unexpected command type");
|
||||||
}
|
};
|
||||||
|
assert_eq!(edit_command, expected_args);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_edit_indexer_requires_arguments() {
|
fn test_edit_indexer_requires_arguments() {
|
||||||
let result = Cli::command().try_get_matches_from(["managarr", "sonarr", "edit", "indexer"]);
|
let result = Cli::command().try_get_matches_from(["managarr", "sonarr", "edit", "indexer"]);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert_err!(&result);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
result.unwrap_err().kind(),
|
result.unwrap_err().kind(),
|
||||||
ErrorKind::MissingRequiredArgument
|
ErrorKind::MissingRequiredArgument
|
||||||
@@ -137,7 +139,7 @@ mod tests {
|
|||||||
"1",
|
"1",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert_err!(&result);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
result.unwrap_err().kind(),
|
result.unwrap_err().kind(),
|
||||||
ErrorKind::MissingRequiredArgument
|
ErrorKind::MissingRequiredArgument
|
||||||
@@ -157,7 +159,7 @@ mod tests {
|
|||||||
"--disable-rss",
|
"--disable-rss",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert_err!(&result);
|
||||||
assert_eq!(result.unwrap_err().kind(), ErrorKind::ArgumentConflict);
|
assert_eq!(result.unwrap_err().kind(), ErrorKind::ArgumentConflict);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -174,7 +176,7 @@ mod tests {
|
|||||||
"--disable-automatic-search",
|
"--disable-automatic-search",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert_err!(&result);
|
||||||
assert_eq!(result.unwrap_err().kind(), ErrorKind::ArgumentConflict);
|
assert_eq!(result.unwrap_err().kind(), ErrorKind::ArgumentConflict);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -191,7 +193,7 @@ mod tests {
|
|||||||
"--disable-interactive-search",
|
"--disable-interactive-search",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert_err!(&result);
|
||||||
assert_eq!(result.unwrap_err().kind(), ErrorKind::ArgumentConflict);
|
assert_eq!(result.unwrap_err().kind(), ErrorKind::ArgumentConflict);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -209,7 +211,7 @@ mod tests {
|
|||||||
"--clear-tags",
|
"--clear-tags",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert_err!(&result);
|
||||||
assert_eq!(result.unwrap_err().kind(), ErrorKind::ArgumentConflict);
|
assert_eq!(result.unwrap_err().kind(), ErrorKind::ArgumentConflict);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -227,7 +229,7 @@ mod tests {
|
|||||||
flag,
|
flag,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert_err!(&result);
|
||||||
assert_eq!(result.unwrap_err().kind(), ErrorKind::InvalidValue);
|
assert_eq!(result.unwrap_err().kind(), ErrorKind::InvalidValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -261,11 +263,12 @@ mod tests {
|
|||||||
"Test",
|
"Test",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
|
|
||||||
if let Some(Command::Sonarr(SonarrCommand::Edit(edit_command))) = result.unwrap().command {
|
let Some(Command::Sonarr(SonarrCommand::Edit(edit_command))) = result.unwrap().command else {
|
||||||
assert_eq!(edit_command, expected_args);
|
panic!("Unexpected command type");
|
||||||
}
|
};
|
||||||
|
assert_eq!(edit_command, expected_args);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -300,11 +303,12 @@ mod tests {
|
|||||||
"2",
|
"2",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
|
|
||||||
if let Some(Command::Sonarr(SonarrCommand::Edit(edit_command))) = result.unwrap().command {
|
let Some(Command::Sonarr(SonarrCommand::Edit(edit_command))) = result.unwrap().command else {
|
||||||
assert_eq!(edit_command, expected_args);
|
panic!("Unexpected command type");
|
||||||
}
|
};
|
||||||
|
assert_eq!(edit_command, expected_args);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -352,18 +356,19 @@ mod tests {
|
|||||||
"25",
|
"25",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
|
|
||||||
if let Some(Command::Sonarr(SonarrCommand::Edit(edit_command))) = result.unwrap().command {
|
let Some(Command::Sonarr(SonarrCommand::Edit(edit_command))) = result.unwrap().command else {
|
||||||
assert_eq!(edit_command, expected_args);
|
panic!("Unexpected command type");
|
||||||
}
|
};
|
||||||
|
assert_eq!(edit_command, expected_args);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_edit_series_requires_arguments() {
|
fn test_edit_series_requires_arguments() {
|
||||||
let result = Cli::command().try_get_matches_from(["managarr", "sonarr", "edit", "series"]);
|
let result = Cli::command().try_get_matches_from(["managarr", "sonarr", "edit", "series"]);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert_err!(&result);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
result.unwrap_err().kind(),
|
result.unwrap_err().kind(),
|
||||||
ErrorKind::MissingRequiredArgument
|
ErrorKind::MissingRequiredArgument
|
||||||
@@ -381,7 +386,7 @@ mod tests {
|
|||||||
"1",
|
"1",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert_err!(&result);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
result.unwrap_err().kind(),
|
result.unwrap_err().kind(),
|
||||||
ErrorKind::MissingRequiredArgument
|
ErrorKind::MissingRequiredArgument
|
||||||
@@ -401,7 +406,7 @@ mod tests {
|
|||||||
"--disable-monitoring",
|
"--disable-monitoring",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert_err!(&result);
|
||||||
assert_eq!(result.unwrap_err().kind(), ErrorKind::ArgumentConflict);
|
assert_eq!(result.unwrap_err().kind(), ErrorKind::ArgumentConflict);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -418,7 +423,7 @@ mod tests {
|
|||||||
"--disable-season-folders",
|
"--disable-season-folders",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert_err!(&result);
|
||||||
assert_eq!(result.unwrap_err().kind(), ErrorKind::ArgumentConflict);
|
assert_eq!(result.unwrap_err().kind(), ErrorKind::ArgumentConflict);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -436,7 +441,7 @@ mod tests {
|
|||||||
"--clear-tags",
|
"--clear-tags",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert_err!(&result);
|
||||||
assert_eq!(result.unwrap_err().kind(), ErrorKind::ArgumentConflict);
|
assert_eq!(result.unwrap_err().kind(), ErrorKind::ArgumentConflict);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -461,7 +466,7 @@ mod tests {
|
|||||||
flag,
|
flag,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert_err!(&result);
|
||||||
assert_eq!(result.unwrap_err().kind(), ErrorKind::InvalidValue);
|
assert_eq!(result.unwrap_err().kind(), ErrorKind::InvalidValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -478,7 +483,7 @@ mod tests {
|
|||||||
"test",
|
"test",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert_err!(&result);
|
||||||
assert_eq!(result.unwrap_err().kind(), ErrorKind::InvalidValue);
|
assert_eq!(result.unwrap_err().kind(), ErrorKind::InvalidValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -509,11 +514,12 @@ mod tests {
|
|||||||
"/nfs/test",
|
"/nfs/test",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
|
|
||||||
if let Some(Command::Sonarr(SonarrCommand::Edit(edit_command))) = result.unwrap().command {
|
let Some(Command::Sonarr(SonarrCommand::Edit(edit_command))) = result.unwrap().command else {
|
||||||
assert_eq!(edit_command, expected_args);
|
panic!("Unexpected command type");
|
||||||
}
|
};
|
||||||
|
assert_eq!(edit_command, expected_args);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -545,11 +551,12 @@ mod tests {
|
|||||||
"2",
|
"2",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
|
|
||||||
if let Some(Command::Sonarr(SonarrCommand::Edit(edit_command))) = result.unwrap().command {
|
let Some(Command::Sonarr(SonarrCommand::Edit(edit_command))) = result.unwrap().command else {
|
||||||
assert_eq!(edit_command, expected_args);
|
panic!("Unexpected command type");
|
||||||
}
|
};
|
||||||
|
assert_eq!(edit_command, expected_args);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -591,11 +598,12 @@ mod tests {
|
|||||||
"2",
|
"2",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
|
|
||||||
if let Some(Command::Sonarr(SonarrCommand::Edit(edit_command))) = result.unwrap().command {
|
let Some(Command::Sonarr(SonarrCommand::Edit(edit_command))) = result.unwrap().command else {
|
||||||
assert_eq!(edit_command, expected_args);
|
panic!("Unexpected command type");
|
||||||
}
|
};
|
||||||
|
assert_eq!(edit_command, expected_args);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -609,15 +617,15 @@ mod tests {
|
|||||||
use crate::{
|
use crate::{
|
||||||
app::App,
|
app::App,
|
||||||
cli::{
|
cli::{
|
||||||
sonarr::edit_command_handler::{SonarrEditCommand, SonarrEditCommandHandler},
|
|
||||||
CliCommandHandler,
|
CliCommandHandler,
|
||||||
|
sonarr::edit_command_handler::{SonarrEditCommand, SonarrEditCommandHandler},
|
||||||
},
|
},
|
||||||
models::{
|
models::{
|
||||||
|
Serdeable,
|
||||||
servarr_models::EditIndexerParams,
|
servarr_models::EditIndexerParams,
|
||||||
sonarr_models::{EditSeriesParams, IndexerSettings, SeriesType, SonarrSerdeable},
|
sonarr_models::{EditSeriesParams, IndexerSettings, SeriesType, SonarrSerdeable},
|
||||||
Serdeable,
|
|
||||||
},
|
},
|
||||||
network::{sonarr_network::SonarrEvent, MockNetworkTrait, NetworkEvent},
|
network::{MockNetworkTrait, NetworkEvent, sonarr_network::SonarrEvent},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@@ -658,7 +666,7 @@ mod tests {
|
|||||||
json!({"testResponse": "response"}),
|
json!({"testResponse": "response"}),
|
||||||
)))
|
)))
|
||||||
});
|
});
|
||||||
let app_arc = Arc::new(Mutex::new(App::default()));
|
let app_arc = Arc::new(Mutex::new(App::test_default()));
|
||||||
let edit_all_indexer_settings_command = SonarrEditCommand::AllIndexerSettings {
|
let edit_all_indexer_settings_command = SonarrEditCommand::AllIndexerSettings {
|
||||||
maximum_size: Some(1),
|
maximum_size: Some(1),
|
||||||
minimum_age: Some(1),
|
minimum_age: Some(1),
|
||||||
@@ -674,7 +682,7 @@ mod tests {
|
|||||||
.handle()
|
.handle()
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@@ -705,7 +713,7 @@ mod tests {
|
|||||||
json!({"testResponse": "response"}),
|
json!({"testResponse": "response"}),
|
||||||
)))
|
)))
|
||||||
});
|
});
|
||||||
let app_arc = Arc::new(Mutex::new(App::default()));
|
let app_arc = Arc::new(Mutex::new(App::test_default()));
|
||||||
let edit_indexer_command = SonarrEditCommand::Indexer {
|
let edit_indexer_command = SonarrEditCommand::Indexer {
|
||||||
indexer_id: 1,
|
indexer_id: 1,
|
||||||
name: Some("Test".to_owned()),
|
name: Some("Test".to_owned()),
|
||||||
@@ -728,7 +736,7 @@ mod tests {
|
|||||||
.handle()
|
.handle()
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@@ -757,7 +765,7 @@ mod tests {
|
|||||||
json!({"testResponse": "response"}),
|
json!({"testResponse": "response"}),
|
||||||
)))
|
)))
|
||||||
});
|
});
|
||||||
let app_arc = Arc::new(Mutex::new(App::default()));
|
let app_arc = Arc::new(Mutex::new(App::test_default()));
|
||||||
let edit_series_command = SonarrEditCommand::Series {
|
let edit_series_command = SonarrEditCommand::Series {
|
||||||
series_id: 1,
|
series_id: 1,
|
||||||
enable_monitoring: true,
|
enable_monitoring: true,
|
||||||
@@ -776,7 +784,7 @@ mod tests {
|
|||||||
.handle()
|
.handle()
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@@ -805,7 +813,7 @@ mod tests {
|
|||||||
json!({"testResponse": "response"}),
|
json!({"testResponse": "response"}),
|
||||||
)))
|
)))
|
||||||
});
|
});
|
||||||
let app_arc = Arc::new(Mutex::new(App::default()));
|
let app_arc = Arc::new(Mutex::new(App::test_default()));
|
||||||
let edit_series_command = SonarrEditCommand::Series {
|
let edit_series_command = SonarrEditCommand::Series {
|
||||||
series_id: 1,
|
series_id: 1,
|
||||||
enable_monitoring: false,
|
enable_monitoring: false,
|
||||||
@@ -824,7 +832,7 @@ mod tests {
|
|||||||
.handle()
|
.handle()
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@@ -853,7 +861,7 @@ mod tests {
|
|||||||
json!({"testResponse": "response"}),
|
json!({"testResponse": "response"}),
|
||||||
)))
|
)))
|
||||||
});
|
});
|
||||||
let app_arc = Arc::new(Mutex::new(App::default()));
|
let app_arc = Arc::new(Mutex::new(App::test_default()));
|
||||||
let edit_series_command = SonarrEditCommand::Series {
|
let edit_series_command = SonarrEditCommand::Series {
|
||||||
series_id: 1,
|
series_id: 1,
|
||||||
enable_monitoring: false,
|
enable_monitoring: false,
|
||||||
@@ -872,7 +880,7 @@ mod tests {
|
|||||||
.handle()
|
.handle()
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ use tokio::sync::Mutex;
|
|||||||
use crate::{
|
use crate::{
|
||||||
app::App,
|
app::App,
|
||||||
cli::{CliCommandHandler, Command},
|
cli::{CliCommandHandler, Command},
|
||||||
network::{sonarr_network::SonarrEvent, NetworkTrait},
|
network::{NetworkTrait, sonarr_network::SonarrEvent},
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::SonarrCommand;
|
use super::SonarrCommand;
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::cli::{
|
|
||||||
sonarr::{get_command_handler::SonarrGetCommand, SonarrCommand},
|
|
||||||
Command,
|
|
||||||
};
|
|
||||||
use crate::Cli;
|
use crate::Cli;
|
||||||
|
use crate::cli::{
|
||||||
|
Command,
|
||||||
|
sonarr::{SonarrCommand, get_command_handler::SonarrGetCommand},
|
||||||
|
};
|
||||||
use clap::CommandFactory;
|
use clap::CommandFactory;
|
||||||
use pretty_assertions::assert_eq;
|
use pretty_assertions::assert_eq;
|
||||||
|
|
||||||
@@ -28,7 +28,7 @@ mod tests {
|
|||||||
let result =
|
let result =
|
||||||
Cli::command().try_get_matches_from(["managarr", "sonarr", "get", "all-indexer-settings"]);
|
Cli::command().try_get_matches_from(["managarr", "sonarr", "get", "all-indexer-settings"]);
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -36,7 +36,7 @@ mod tests {
|
|||||||
let result =
|
let result =
|
||||||
Cli::command().try_get_matches_from(["managarr", "sonarr", "get", "system-status"]);
|
Cli::command().try_get_matches_from(["managarr", "sonarr", "get", "system-status"]);
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -44,7 +44,7 @@ mod tests {
|
|||||||
let result =
|
let result =
|
||||||
Cli::command().try_get_matches_from(["managarr", "sonarr", "get", "episode-details"]);
|
Cli::command().try_get_matches_from(["managarr", "sonarr", "get", "episode-details"]);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert_err!(&result);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
result.unwrap_err().kind(),
|
result.unwrap_err().kind(),
|
||||||
ErrorKind::MissingRequiredArgument
|
ErrorKind::MissingRequiredArgument
|
||||||
@@ -62,7 +62,7 @@ mod tests {
|
|||||||
"1",
|
"1",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -70,7 +70,7 @@ mod tests {
|
|||||||
let result =
|
let result =
|
||||||
Cli::command().try_get_matches_from(["managarr", "sonarr", "get", "host-config"]);
|
Cli::command().try_get_matches_from(["managarr", "sonarr", "get", "host-config"]);
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -78,7 +78,7 @@ mod tests {
|
|||||||
let result =
|
let result =
|
||||||
Cli::command().try_get_matches_from(["managarr", "sonarr", "get", "security-config"]);
|
Cli::command().try_get_matches_from(["managarr", "sonarr", "get", "security-config"]);
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -86,7 +86,7 @@ mod tests {
|
|||||||
let result =
|
let result =
|
||||||
Cli::command().try_get_matches_from(["managarr", "sonarr", "get", "series-details"]);
|
Cli::command().try_get_matches_from(["managarr", "sonarr", "get", "series-details"]);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert_err!(&result);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
result.unwrap_err().kind(),
|
result.unwrap_err().kind(),
|
||||||
ErrorKind::MissingRequiredArgument
|
ErrorKind::MissingRequiredArgument
|
||||||
@@ -104,7 +104,7 @@ mod tests {
|
|||||||
"1",
|
"1",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -118,11 +118,11 @@ mod tests {
|
|||||||
use crate::{
|
use crate::{
|
||||||
app::App,
|
app::App,
|
||||||
cli::{
|
cli::{
|
||||||
sonarr::get_command_handler::{SonarrGetCommand, SonarrGetCommandHandler},
|
|
||||||
CliCommandHandler,
|
CliCommandHandler,
|
||||||
|
sonarr::get_command_handler::{SonarrGetCommand, SonarrGetCommandHandler},
|
||||||
},
|
},
|
||||||
models::{sonarr_models::SonarrSerdeable, Serdeable},
|
models::{Serdeable, sonarr_models::SonarrSerdeable},
|
||||||
network::{sonarr_network::SonarrEvent, MockNetworkTrait, NetworkEvent},
|
network::{MockNetworkTrait, NetworkEvent, sonarr_network::SonarrEvent},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@@ -139,7 +139,7 @@ mod tests {
|
|||||||
json!({"testResponse": "response"}),
|
json!({"testResponse": "response"}),
|
||||||
)))
|
)))
|
||||||
});
|
});
|
||||||
let app_arc = Arc::new(Mutex::new(App::default()));
|
let app_arc = Arc::new(Mutex::new(App::test_default()));
|
||||||
let get_all_indexer_settings_command = SonarrGetCommand::AllIndexerSettings;
|
let get_all_indexer_settings_command = SonarrGetCommand::AllIndexerSettings;
|
||||||
|
|
||||||
let result = SonarrGetCommandHandler::with(
|
let result = SonarrGetCommandHandler::with(
|
||||||
@@ -150,7 +150,7 @@ mod tests {
|
|||||||
.handle()
|
.handle()
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@@ -168,7 +168,7 @@ mod tests {
|
|||||||
json!({"testResponse": "response"}),
|
json!({"testResponse": "response"}),
|
||||||
)))
|
)))
|
||||||
});
|
});
|
||||||
let app_arc = Arc::new(Mutex::new(App::default()));
|
let app_arc = Arc::new(Mutex::new(App::test_default()));
|
||||||
let get_episode_details_command = SonarrGetCommand::EpisodeDetails { episode_id: 1 };
|
let get_episode_details_command = SonarrGetCommand::EpisodeDetails { episode_id: 1 };
|
||||||
|
|
||||||
let result =
|
let result =
|
||||||
@@ -176,7 +176,7 @@ mod tests {
|
|||||||
.handle()
|
.handle()
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@@ -191,7 +191,7 @@ mod tests {
|
|||||||
json!({"testResponse": "response"}),
|
json!({"testResponse": "response"}),
|
||||||
)))
|
)))
|
||||||
});
|
});
|
||||||
let app_arc = Arc::new(Mutex::new(App::default()));
|
let app_arc = Arc::new(Mutex::new(App::test_default()));
|
||||||
let get_host_config_command = SonarrGetCommand::HostConfig;
|
let get_host_config_command = SonarrGetCommand::HostConfig;
|
||||||
|
|
||||||
let result =
|
let result =
|
||||||
@@ -199,7 +199,7 @@ mod tests {
|
|||||||
.handle()
|
.handle()
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@@ -214,7 +214,7 @@ mod tests {
|
|||||||
json!({"testResponse": "response"}),
|
json!({"testResponse": "response"}),
|
||||||
)))
|
)))
|
||||||
});
|
});
|
||||||
let app_arc = Arc::new(Mutex::new(App::default()));
|
let app_arc = Arc::new(Mutex::new(App::test_default()));
|
||||||
let get_security_config_command = SonarrGetCommand::SecurityConfig;
|
let get_security_config_command = SonarrGetCommand::SecurityConfig;
|
||||||
|
|
||||||
let result =
|
let result =
|
||||||
@@ -222,7 +222,7 @@ mod tests {
|
|||||||
.handle()
|
.handle()
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@@ -240,7 +240,7 @@ mod tests {
|
|||||||
json!({"testResponse": "response"}),
|
json!({"testResponse": "response"}),
|
||||||
)))
|
)))
|
||||||
});
|
});
|
||||||
let app_arc = Arc::new(Mutex::new(App::default()));
|
let app_arc = Arc::new(Mutex::new(App::test_default()));
|
||||||
let get_series_details_command = SonarrGetCommand::SeriesDetails { series_id: 1 };
|
let get_series_details_command = SonarrGetCommand::SeriesDetails { series_id: 1 };
|
||||||
|
|
||||||
let result =
|
let result =
|
||||||
@@ -248,7 +248,7 @@ mod tests {
|
|||||||
.handle()
|
.handle()
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@@ -263,7 +263,7 @@ mod tests {
|
|||||||
json!({"testResponse": "response"}),
|
json!({"testResponse": "response"}),
|
||||||
)))
|
)))
|
||||||
});
|
});
|
||||||
let app_arc = Arc::new(Mutex::new(App::default()));
|
let app_arc = Arc::new(Mutex::new(App::test_default()));
|
||||||
let get_system_status_command = SonarrGetCommand::SystemStatus;
|
let get_system_status_command = SonarrGetCommand::SystemStatus;
|
||||||
|
|
||||||
let result =
|
let result =
|
||||||
@@ -271,7 +271,7 @@ mod tests {
|
|||||||
.handle()
|
.handle()
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ use tokio::sync::Mutex;
|
|||||||
use crate::{
|
use crate::{
|
||||||
app::App,
|
app::App,
|
||||||
cli::{CliCommandHandler, Command},
|
cli::{CliCommandHandler, Command},
|
||||||
network::{sonarr_network::SonarrEvent, NetworkTrait},
|
network::{NetworkTrait, sonarr_network::SonarrEvent},
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::SonarrCommand;
|
use super::SonarrCommand;
|
||||||
@@ -21,7 +21,10 @@ pub enum SonarrListCommand {
|
|||||||
#[command(about = "List all items in the Sonarr blocklist")]
|
#[command(about = "List all items in the Sonarr blocklist")]
|
||||||
Blocklist,
|
Blocklist,
|
||||||
#[command(about = "List all active downloads in Sonarr")]
|
#[command(about = "List all active downloads in Sonarr")]
|
||||||
Downloads,
|
Downloads {
|
||||||
|
#[arg(long, help = "How many downloads to fetch", default_value_t = 500)]
|
||||||
|
count: u64,
|
||||||
|
},
|
||||||
#[command(about = "List disk space details for all provisioned root folders in Sonarr")]
|
#[command(about = "List disk space details for all provisioned root folders in Sonarr")]
|
||||||
DiskSpace,
|
DiskSpace,
|
||||||
#[command(about = "List the episodes for the series with the given ID")]
|
#[command(about = "List the episodes for the series with the given ID")]
|
||||||
@@ -146,10 +149,10 @@ impl<'a, 'b> CliCommandHandler<'a, 'b, SonarrListCommand> for SonarrListCommandH
|
|||||||
.await?;
|
.await?;
|
||||||
serde_json::to_string_pretty(&resp)?
|
serde_json::to_string_pretty(&resp)?
|
||||||
}
|
}
|
||||||
SonarrListCommand::Downloads => {
|
SonarrListCommand::Downloads { count } => {
|
||||||
let resp = self
|
let resp = self
|
||||||
.network
|
.network
|
||||||
.handle_network_event(SonarrEvent::GetDownloads.into())
|
.handle_network_event(SonarrEvent::GetDownloads(count).into())
|
||||||
.await?;
|
.await?;
|
||||||
serde_json::to_string_pretty(&resp)?
|
serde_json::to_string_pretty(&resp)?
|
||||||
}
|
}
|
||||||
@@ -212,9 +215,9 @@ impl<'a, 'b> CliCommandHandler<'a, 'b, SonarrListCommand> for SonarrListCommandH
|
|||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
if output_in_log_format {
|
if output_in_log_format {
|
||||||
let log_lines = self.app.lock().await.data.sonarr_data.logs.items.clone();
|
let log_lines = &self.app.lock().await.data.sonarr_data.logs.items;
|
||||||
|
|
||||||
serde_json::to_string_pretty(&log_lines)?
|
serde_json::to_string_pretty(log_lines)?
|
||||||
} else {
|
} else {
|
||||||
serde_json::to_string_pretty(&logs)?
|
serde_json::to_string_pretty(&logs)?
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::cli::{
|
|
||||||
sonarr::{list_command_handler::SonarrListCommand, SonarrCommand},
|
|
||||||
Command,
|
|
||||||
};
|
|
||||||
use crate::Cli;
|
use crate::Cli;
|
||||||
|
use crate::cli::{
|
||||||
|
Command,
|
||||||
|
sonarr::{SonarrCommand, list_command_handler::SonarrListCommand},
|
||||||
|
};
|
||||||
use clap::CommandFactory;
|
use clap::CommandFactory;
|
||||||
use pretty_assertions::assert_eq;
|
use pretty_assertions::assert_eq;
|
||||||
|
|
||||||
@@ -19,7 +19,7 @@ mod tests {
|
|||||||
|
|
||||||
mod cli {
|
mod cli {
|
||||||
use super::*;
|
use super::*;
|
||||||
use clap::{error::ErrorKind, Parser};
|
use clap::{Parser, error::ErrorKind};
|
||||||
use pretty_assertions::assert_eq;
|
use pretty_assertions::assert_eq;
|
||||||
use rstest::rstest;
|
use rstest::rstest;
|
||||||
|
|
||||||
@@ -28,7 +28,6 @@ mod tests {
|
|||||||
#[values(
|
#[values(
|
||||||
"blocklist",
|
"blocklist",
|
||||||
"series",
|
"series",
|
||||||
"downloads",
|
|
||||||
"disk-space",
|
"disk-space",
|
||||||
"quality-profiles",
|
"quality-profiles",
|
||||||
"indexers",
|
"indexers",
|
||||||
@@ -43,14 +42,14 @@ mod tests {
|
|||||||
) {
|
) {
|
||||||
let result = Cli::command().try_get_matches_from(["managarr", "sonarr", "list", subcommand]);
|
let result = Cli::command().try_get_matches_from(["managarr", "sonarr", "list", subcommand]);
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_list_episodes_requires_series_id() {
|
fn test_list_episodes_requires_series_id() {
|
||||||
let result = Cli::command().try_get_matches_from(["managarr", "sonarr", "list", "episodes"]);
|
let result = Cli::command().try_get_matches_from(["managarr", "sonarr", "list", "episodes"]);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert_err!(&result);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
result.unwrap_err().kind(),
|
result.unwrap_err().kind(),
|
||||||
ErrorKind::MissingRequiredArgument
|
ErrorKind::MissingRequiredArgument
|
||||||
@@ -62,7 +61,7 @@ mod tests {
|
|||||||
let result =
|
let result =
|
||||||
Cli::command().try_get_matches_from(["managarr", "sonarr", "list", "episode-files"]);
|
Cli::command().try_get_matches_from(["managarr", "sonarr", "list", "episode-files"]);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert_err!(&result);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
result.unwrap_err().kind(),
|
result.unwrap_err().kind(),
|
||||||
ErrorKind::MissingRequiredArgument
|
ErrorKind::MissingRequiredArgument
|
||||||
@@ -74,7 +73,7 @@ mod tests {
|
|||||||
let result =
|
let result =
|
||||||
Cli::command().try_get_matches_from(["managarr", "sonarr", "list", "episode-history"]);
|
Cli::command().try_get_matches_from(["managarr", "sonarr", "list", "episode-history"]);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert_err!(&result);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
result.unwrap_err().kind(),
|
result.unwrap_err().kind(),
|
||||||
ErrorKind::MissingRequiredArgument
|
ErrorKind::MissingRequiredArgument
|
||||||
@@ -93,13 +92,37 @@ mod tests {
|
|||||||
"1",
|
"1",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
|
|
||||||
if let Some(Command::Sonarr(SonarrCommand::List(episode_history_command))) =
|
let Some(Command::Sonarr(SonarrCommand::List(episode_history_command))) =
|
||||||
result.unwrap().command
|
result.unwrap().command
|
||||||
{
|
else {
|
||||||
assert_eq!(episode_history_command, expected_args);
|
panic!("Unexpected command type");
|
||||||
}
|
};
|
||||||
|
assert_eq!(episode_history_command, expected_args);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_list_downloads_count_flag_requires_arguments() {
|
||||||
|
let result =
|
||||||
|
Cli::command().try_get_matches_from(["managarr", "sonarr", "list", "downloads", "--count"]);
|
||||||
|
|
||||||
|
assert_err!(&result);
|
||||||
|
assert_eq!(result.unwrap_err().kind(), ErrorKind::InvalidValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_list_downloads_default_values() {
|
||||||
|
let expected_args = SonarrListCommand::Downloads { count: 500 };
|
||||||
|
let result = Cli::try_parse_from(["managarr", "sonarr", "list", "downloads"]);
|
||||||
|
|
||||||
|
assert_ok!(&result);
|
||||||
|
|
||||||
|
let Some(Command::Sonarr(SonarrCommand::List(downloads_command))) = result.unwrap().command
|
||||||
|
else {
|
||||||
|
panic!("Unexpected command type");
|
||||||
|
};
|
||||||
|
assert_eq!(downloads_command, expected_args);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -107,7 +130,7 @@ mod tests {
|
|||||||
let result =
|
let result =
|
||||||
Cli::command().try_get_matches_from(["managarr", "sonarr", "list", "history", "--events"]);
|
Cli::command().try_get_matches_from(["managarr", "sonarr", "list", "history", "--events"]);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert_err!(&result);
|
||||||
assert_eq!(result.unwrap_err().kind(), ErrorKind::InvalidValue);
|
assert_eq!(result.unwrap_err().kind(), ErrorKind::InvalidValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -116,11 +139,13 @@ mod tests {
|
|||||||
let expected_args = SonarrListCommand::History { events: 500 };
|
let expected_args = SonarrListCommand::History { events: 500 };
|
||||||
let result = Cli::try_parse_from(["managarr", "sonarr", "list", "history"]);
|
let result = Cli::try_parse_from(["managarr", "sonarr", "list", "history"]);
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
|
|
||||||
if let Some(Command::Sonarr(SonarrCommand::List(history_command))) = result.unwrap().command {
|
let Some(Command::Sonarr(SonarrCommand::List(history_command))) = result.unwrap().command
|
||||||
assert_eq!(history_command, expected_args);
|
else {
|
||||||
}
|
panic!("Unexpected command type");
|
||||||
|
};
|
||||||
|
assert_eq!(history_command, expected_args);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -128,7 +153,7 @@ mod tests {
|
|||||||
let result =
|
let result =
|
||||||
Cli::command().try_get_matches_from(["managarr", "sonarr", "list", "logs", "--events"]);
|
Cli::command().try_get_matches_from(["managarr", "sonarr", "list", "logs", "--events"]);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert_err!(&result);
|
||||||
assert_eq!(result.unwrap_err().kind(), ErrorKind::InvalidValue);
|
assert_eq!(result.unwrap_err().kind(), ErrorKind::InvalidValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -140,11 +165,12 @@ mod tests {
|
|||||||
};
|
};
|
||||||
let result = Cli::try_parse_from(["managarr", "sonarr", "list", "logs"]);
|
let result = Cli::try_parse_from(["managarr", "sonarr", "list", "logs"]);
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
|
|
||||||
if let Some(Command::Sonarr(SonarrCommand::List(logs_command))) = result.unwrap().command {
|
let Some(Command::Sonarr(SonarrCommand::List(logs_command))) = result.unwrap().command else {
|
||||||
assert_eq!(logs_command, expected_args);
|
panic!("Unexpected command type");
|
||||||
}
|
};
|
||||||
|
assert_eq!(logs_command, expected_args);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -153,12 +179,13 @@ mod tests {
|
|||||||
let result =
|
let result =
|
||||||
Cli::try_parse_from(["managarr", "sonarr", "list", "episodes", "--series-id", "1"]);
|
Cli::try_parse_from(["managarr", "sonarr", "list", "episodes", "--series-id", "1"]);
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
|
|
||||||
if let Some(Command::Sonarr(SonarrCommand::List(episodes_command))) = result.unwrap().command
|
let Some(Command::Sonarr(SonarrCommand::List(episodes_command))) = result.unwrap().command
|
||||||
{
|
else {
|
||||||
assert_eq!(episodes_command, expected_args);
|
panic!("Unexpected command type");
|
||||||
}
|
};
|
||||||
|
assert_eq!(episodes_command, expected_args);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -173,13 +200,14 @@ mod tests {
|
|||||||
"1",
|
"1",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
|
|
||||||
if let Some(Command::Sonarr(SonarrCommand::List(episode_files_command))) =
|
let Some(Command::Sonarr(SonarrCommand::List(episode_files_command))) =
|
||||||
result.unwrap().command
|
result.unwrap().command
|
||||||
{
|
else {
|
||||||
assert_eq!(episode_files_command, expected_args);
|
panic!("Unexpected command type");
|
||||||
}
|
};
|
||||||
|
assert_eq!(episode_files_command, expected_args);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -193,7 +221,7 @@ mod tests {
|
|||||||
"1",
|
"1",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert_err!(&result);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
result.unwrap_err().kind(),
|
result.unwrap_err().kind(),
|
||||||
ErrorKind::MissingRequiredArgument
|
ErrorKind::MissingRequiredArgument
|
||||||
@@ -211,7 +239,7 @@ mod tests {
|
|||||||
"1",
|
"1",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert_err!(&result);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
result.unwrap_err().kind(),
|
result.unwrap_err().kind(),
|
||||||
ErrorKind::MissingRequiredArgument
|
ErrorKind::MissingRequiredArgument
|
||||||
@@ -231,7 +259,7 @@ mod tests {
|
|||||||
"1",
|
"1",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -239,7 +267,7 @@ mod tests {
|
|||||||
let result =
|
let result =
|
||||||
Cli::command().try_get_matches_from(["managarr", "sonarr", "list", "series-history"]);
|
Cli::command().try_get_matches_from(["managarr", "sonarr", "list", "series-history"]);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert_err!(&result);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
result.unwrap_err().kind(),
|
result.unwrap_err().kind(),
|
||||||
ErrorKind::MissingRequiredArgument
|
ErrorKind::MissingRequiredArgument
|
||||||
@@ -258,11 +286,13 @@ mod tests {
|
|||||||
"1",
|
"1",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
|
|
||||||
if let Some(Command::Sonarr(SonarrCommand::List(series_command))) = result.unwrap().command {
|
let Some(Command::Sonarr(SonarrCommand::List(series_command))) = result.unwrap().command
|
||||||
assert_eq!(series_command, expected_args);
|
else {
|
||||||
}
|
panic!("Unexpected command type");
|
||||||
|
};
|
||||||
|
assert_eq!(series_command, expected_args);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -275,10 +305,10 @@ mod tests {
|
|||||||
use serde_json::json;
|
use serde_json::json;
|
||||||
use tokio::sync::Mutex;
|
use tokio::sync::Mutex;
|
||||||
|
|
||||||
use crate::cli::sonarr::list_command_handler::{SonarrListCommand, SonarrListCommandHandler};
|
|
||||||
use crate::cli::CliCommandHandler;
|
use crate::cli::CliCommandHandler;
|
||||||
use crate::models::sonarr_models::SonarrSerdeable;
|
use crate::cli::sonarr::list_command_handler::{SonarrListCommand, SonarrListCommandHandler};
|
||||||
use crate::models::Serdeable;
|
use crate::models::Serdeable;
|
||||||
|
use crate::models::sonarr_models::SonarrSerdeable;
|
||||||
use crate::network::sonarr_network::SonarrEvent;
|
use crate::network::sonarr_network::SonarrEvent;
|
||||||
use crate::{
|
use crate::{
|
||||||
app::App,
|
app::App,
|
||||||
@@ -287,7 +317,6 @@ mod tests {
|
|||||||
|
|
||||||
#[rstest]
|
#[rstest]
|
||||||
#[case(SonarrListCommand::Blocklist, SonarrEvent::GetBlocklist)]
|
#[case(SonarrListCommand::Blocklist, SonarrEvent::GetBlocklist)]
|
||||||
#[case(SonarrListCommand::Downloads, SonarrEvent::GetDownloads)]
|
|
||||||
#[case(SonarrListCommand::DiskSpace, SonarrEvent::GetDiskSpace)]
|
#[case(SonarrListCommand::DiskSpace, SonarrEvent::GetDiskSpace)]
|
||||||
#[case(SonarrListCommand::Indexers, SonarrEvent::GetIndexers)]
|
#[case(SonarrListCommand::Indexers, SonarrEvent::GetIndexers)]
|
||||||
#[case(SonarrListCommand::QualityProfiles, SonarrEvent::GetQualityProfiles)]
|
#[case(SonarrListCommand::QualityProfiles, SonarrEvent::GetQualityProfiles)]
|
||||||
@@ -313,13 +342,13 @@ mod tests {
|
|||||||
json!({"testResponse": "response"}),
|
json!({"testResponse": "response"}),
|
||||||
)))
|
)))
|
||||||
});
|
});
|
||||||
let app_arc = Arc::new(Mutex::new(App::default()));
|
let app_arc = Arc::new(Mutex::new(App::test_default()));
|
||||||
|
|
||||||
let result = SonarrListCommandHandler::with(&app_arc, list_command, &mut mock_network)
|
let result = SonarrListCommandHandler::with(&app_arc, list_command, &mut mock_network)
|
||||||
.handle()
|
.handle()
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@@ -337,7 +366,7 @@ mod tests {
|
|||||||
json!({"testResponse": "response"}),
|
json!({"testResponse": "response"}),
|
||||||
)))
|
)))
|
||||||
});
|
});
|
||||||
let app_arc = Arc::new(Mutex::new(App::default()));
|
let app_arc = Arc::new(Mutex::new(App::test_default()));
|
||||||
let list_episodes_command = SonarrListCommand::Episodes { series_id: 1 };
|
let list_episodes_command = SonarrListCommand::Episodes { series_id: 1 };
|
||||||
|
|
||||||
let result =
|
let result =
|
||||||
@@ -345,7 +374,7 @@ mod tests {
|
|||||||
.handle()
|
.handle()
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@@ -363,7 +392,7 @@ mod tests {
|
|||||||
json!({"testResponse": "response"}),
|
json!({"testResponse": "response"}),
|
||||||
)))
|
)))
|
||||||
});
|
});
|
||||||
let app_arc = Arc::new(Mutex::new(App::default()));
|
let app_arc = Arc::new(Mutex::new(App::test_default()));
|
||||||
let list_episode_files_command = SonarrListCommand::EpisodeFiles { series_id: 1 };
|
let list_episode_files_command = SonarrListCommand::EpisodeFiles { series_id: 1 };
|
||||||
|
|
||||||
let result =
|
let result =
|
||||||
@@ -371,7 +400,33 @@ mod tests {
|
|||||||
.handle()
|
.handle()
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_handle_list_downloads_command() {
|
||||||
|
let expected_count = 1000;
|
||||||
|
let mut mock_network = MockNetworkTrait::new();
|
||||||
|
mock_network
|
||||||
|
.expect_handle_network_event()
|
||||||
|
.with(eq::<NetworkEvent>(
|
||||||
|
SonarrEvent::GetDownloads(expected_count).into(),
|
||||||
|
))
|
||||||
|
.times(1)
|
||||||
|
.returning(|_| {
|
||||||
|
Ok(Serdeable::Sonarr(SonarrSerdeable::Value(
|
||||||
|
json!({"testResponse": "response"}),
|
||||||
|
)))
|
||||||
|
});
|
||||||
|
let app_arc = Arc::new(Mutex::new(App::test_default()));
|
||||||
|
let list_downloads_command = SonarrListCommand::Downloads { count: 1000 };
|
||||||
|
|
||||||
|
let result =
|
||||||
|
SonarrListCommandHandler::with(&app_arc, list_downloads_command, &mut mock_network)
|
||||||
|
.handle()
|
||||||
|
.await;
|
||||||
|
|
||||||
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@@ -389,7 +444,7 @@ mod tests {
|
|||||||
json!({"testResponse": "response"}),
|
json!({"testResponse": "response"}),
|
||||||
)))
|
)))
|
||||||
});
|
});
|
||||||
let app_arc = Arc::new(Mutex::new(App::default()));
|
let app_arc = Arc::new(Mutex::new(App::test_default()));
|
||||||
let list_history_command = SonarrListCommand::History { events: 1000 };
|
let list_history_command = SonarrListCommand::History { events: 1000 };
|
||||||
|
|
||||||
let result =
|
let result =
|
||||||
@@ -397,7 +452,7 @@ mod tests {
|
|||||||
.handle()
|
.handle()
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@@ -415,7 +470,7 @@ mod tests {
|
|||||||
json!({"testResponse": "response"}),
|
json!({"testResponse": "response"}),
|
||||||
)))
|
)))
|
||||||
});
|
});
|
||||||
let app_arc = Arc::new(Mutex::new(App::default()));
|
let app_arc = Arc::new(Mutex::new(App::test_default()));
|
||||||
let list_logs_command = SonarrListCommand::Logs {
|
let list_logs_command = SonarrListCommand::Logs {
|
||||||
events: 1000,
|
events: 1000,
|
||||||
output_in_log_format: false,
|
output_in_log_format: false,
|
||||||
@@ -425,7 +480,7 @@ mod tests {
|
|||||||
.handle()
|
.handle()
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@@ -443,7 +498,7 @@ mod tests {
|
|||||||
json!({"testResponse": "response"}),
|
json!({"testResponse": "response"}),
|
||||||
)))
|
)))
|
||||||
});
|
});
|
||||||
let app_arc = Arc::new(Mutex::new(App::default()));
|
let app_arc = Arc::new(Mutex::new(App::test_default()));
|
||||||
let list_series_history_command = SonarrListCommand::SeriesHistory { series_id: 1 };
|
let list_series_history_command = SonarrListCommand::SeriesHistory { series_id: 1 };
|
||||||
|
|
||||||
let result =
|
let result =
|
||||||
@@ -451,7 +506,7 @@ mod tests {
|
|||||||
.handle()
|
.handle()
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@@ -469,7 +524,7 @@ mod tests {
|
|||||||
json!({"testResponse": "response"}),
|
json!({"testResponse": "response"}),
|
||||||
)))
|
)))
|
||||||
});
|
});
|
||||||
let app_arc = Arc::new(Mutex::new(App::default()));
|
let app_arc = Arc::new(Mutex::new(App::test_default()));
|
||||||
let list_episode_history_command = SonarrListCommand::EpisodeHistory { episode_id: 1 };
|
let list_episode_history_command = SonarrListCommand::EpisodeHistory { episode_id: 1 };
|
||||||
|
|
||||||
let result =
|
let result =
|
||||||
@@ -477,7 +532,7 @@ mod tests {
|
|||||||
.handle()
|
.handle()
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@@ -496,7 +551,7 @@ mod tests {
|
|||||||
json!({"testResponse": "response"}),
|
json!({"testResponse": "response"}),
|
||||||
)))
|
)))
|
||||||
});
|
});
|
||||||
let app_arc = Arc::new(Mutex::new(App::default()));
|
let app_arc = Arc::new(Mutex::new(App::test_default()));
|
||||||
let list_season_history_command = SonarrListCommand::SeasonHistory {
|
let list_season_history_command = SonarrListCommand::SeasonHistory {
|
||||||
series_id: 1,
|
series_id: 1,
|
||||||
season_number: 1,
|
season_number: 1,
|
||||||
@@ -507,7 +562,7 @@ mod tests {
|
|||||||
.handle()
|
.handle()
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ use tokio::sync::Mutex;
|
|||||||
use crate::{
|
use crate::{
|
||||||
app::App,
|
app::App,
|
||||||
cli::{CliCommandHandler, Command},
|
cli::{CliCommandHandler, Command},
|
||||||
network::{sonarr_network::SonarrEvent, NetworkTrait},
|
network::{NetworkTrait, sonarr_network::SonarrEvent},
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::SonarrCommand;
|
use super::SonarrCommand;
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::cli::{
|
|
||||||
sonarr::{manual_search_command_handler::SonarrManualSearchCommand, SonarrCommand},
|
|
||||||
Command,
|
|
||||||
};
|
|
||||||
use crate::Cli;
|
use crate::Cli;
|
||||||
|
use crate::cli::{
|
||||||
|
Command,
|
||||||
|
sonarr::{SonarrCommand, manual_search_command_handler::SonarrManualSearchCommand},
|
||||||
|
};
|
||||||
use clap::CommandFactory;
|
use clap::CommandFactory;
|
||||||
use pretty_assertions::assert_eq;
|
use pretty_assertions::assert_eq;
|
||||||
|
|
||||||
@@ -36,7 +36,7 @@ mod tests {
|
|||||||
"1",
|
"1",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert_err!(&result);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
result.unwrap_err().kind(),
|
result.unwrap_err().kind(),
|
||||||
ErrorKind::MissingRequiredArgument
|
ErrorKind::MissingRequiredArgument
|
||||||
@@ -54,7 +54,7 @@ mod tests {
|
|||||||
"1",
|
"1",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert_err!(&result);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
result.unwrap_err().kind(),
|
result.unwrap_err().kind(),
|
||||||
ErrorKind::MissingRequiredArgument
|
ErrorKind::MissingRequiredArgument
|
||||||
@@ -74,7 +74,7 @@ mod tests {
|
|||||||
"1",
|
"1",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -82,7 +82,7 @@ mod tests {
|
|||||||
let result =
|
let result =
|
||||||
Cli::command().try_get_matches_from(["managarr", "sonarr", "manual-search", "episode"]);
|
Cli::command().try_get_matches_from(["managarr", "sonarr", "manual-search", "episode"]);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert_err!(&result);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
result.unwrap_err().kind(),
|
result.unwrap_err().kind(),
|
||||||
ErrorKind::MissingRequiredArgument
|
ErrorKind::MissingRequiredArgument
|
||||||
@@ -100,7 +100,7 @@ mod tests {
|
|||||||
"1",
|
"1",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -114,13 +114,13 @@ mod tests {
|
|||||||
use crate::{
|
use crate::{
|
||||||
app::App,
|
app::App,
|
||||||
cli::{
|
cli::{
|
||||||
|
CliCommandHandler,
|
||||||
sonarr::manual_search_command_handler::{
|
sonarr::manual_search_command_handler::{
|
||||||
SonarrManualSearchCommand, SonarrManualSearchCommandHandler,
|
SonarrManualSearchCommand, SonarrManualSearchCommandHandler,
|
||||||
},
|
},
|
||||||
CliCommandHandler,
|
|
||||||
},
|
},
|
||||||
models::{sonarr_models::SonarrSerdeable, Serdeable},
|
models::{Serdeable, sonarr_models::SonarrSerdeable},
|
||||||
network::{sonarr_network::SonarrEvent, MockNetworkTrait, NetworkEvent},
|
network::{MockNetworkTrait, NetworkEvent, sonarr_network::SonarrEvent},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@@ -138,7 +138,7 @@ mod tests {
|
|||||||
json!({"testResponse": "response"}),
|
json!({"testResponse": "response"}),
|
||||||
)))
|
)))
|
||||||
});
|
});
|
||||||
let app_arc = Arc::new(Mutex::new(App::default()));
|
let app_arc = Arc::new(Mutex::new(App::test_default()));
|
||||||
let manual_episode_search_command = SonarrManualSearchCommand::Episode { episode_id: 1 };
|
let manual_episode_search_command = SonarrManualSearchCommand::Episode { episode_id: 1 };
|
||||||
|
|
||||||
let result = SonarrManualSearchCommandHandler::with(
|
let result = SonarrManualSearchCommandHandler::with(
|
||||||
@@ -149,7 +149,7 @@ mod tests {
|
|||||||
.handle()
|
.handle()
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@@ -168,7 +168,7 @@ mod tests {
|
|||||||
json!({"testResponse": "response"}),
|
json!({"testResponse": "response"}),
|
||||||
)))
|
)))
|
||||||
});
|
});
|
||||||
let app_arc = Arc::new(Mutex::new(App::default()));
|
let app_arc = Arc::new(Mutex::new(App::test_default()));
|
||||||
let manual_season_search_command = SonarrManualSearchCommand::Season {
|
let manual_season_search_command = SonarrManualSearchCommand::Season {
|
||||||
series_id: 1,
|
series_id: 1,
|
||||||
season_number: 1,
|
season_number: 1,
|
||||||
@@ -182,7 +182,7 @@ mod tests {
|
|||||||
.handle()
|
.handle()
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+19
-1
@@ -18,7 +18,7 @@ use trigger_automatic_search_command_handler::{
|
|||||||
use crate::{
|
use crate::{
|
||||||
app::App,
|
app::App,
|
||||||
models::sonarr_models::SonarrTaskName,
|
models::sonarr_models::SonarrTaskName,
|
||||||
network::{sonarr_network::SonarrEvent, NetworkTrait},
|
network::{NetworkTrait, sonarr_network::SonarrEvent},
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{CliCommandHandler, Command};
|
use super::{CliCommandHandler, Command};
|
||||||
@@ -146,6 +146,17 @@ pub enum SonarrCommand {
|
|||||||
)]
|
)]
|
||||||
season_number: i64,
|
season_number: i64,
|
||||||
},
|
},
|
||||||
|
#[command(
|
||||||
|
about = "Toggle monitoring for the specified series corresponding to the given series ID"
|
||||||
|
)]
|
||||||
|
ToggleSeriesMonitoring {
|
||||||
|
#[arg(
|
||||||
|
long,
|
||||||
|
help = "The Sonarr ID of the series to toggle monitoring on",
|
||||||
|
required = true
|
||||||
|
)]
|
||||||
|
series_id: i64,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<SonarrCommand> for Command {
|
impl From<SonarrCommand> for Command {
|
||||||
@@ -290,6 +301,13 @@ impl<'a, 'b> CliCommandHandler<'a, 'b, SonarrCommand> for SonarrCliHandler<'a, '
|
|||||||
.await?;
|
.await?;
|
||||||
serde_json::to_string_pretty(&resp)?
|
serde_json::to_string_pretty(&resp)?
|
||||||
}
|
}
|
||||||
|
SonarrCommand::ToggleSeriesMonitoring { series_id } => {
|
||||||
|
let resp = self
|
||||||
|
.network
|
||||||
|
.handle_network_event(SonarrEvent::ToggleSeriesMonitoring(series_id).into())
|
||||||
|
.await?;
|
||||||
|
serde_json::to_string_pretty(&resp)?
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(result)
|
Ok(result)
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ use tokio::sync::Mutex;
|
|||||||
use crate::{
|
use crate::{
|
||||||
app::App,
|
app::App,
|
||||||
cli::{CliCommandHandler, Command},
|
cli::{CliCommandHandler, Command},
|
||||||
network::{sonarr_network::SonarrEvent, NetworkTrait},
|
network::{NetworkTrait, sonarr_network::SonarrEvent},
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::SonarrCommand;
|
use super::SonarrCommand;
|
||||||
|
|||||||
@@ -2,11 +2,11 @@
|
|||||||
mod tests {
|
mod tests {
|
||||||
use pretty_assertions::assert_eq;
|
use pretty_assertions::assert_eq;
|
||||||
|
|
||||||
use crate::cli::{
|
|
||||||
sonarr::{refresh_command_handler::SonarrRefreshCommand, SonarrCommand},
|
|
||||||
Command,
|
|
||||||
};
|
|
||||||
use crate::Cli;
|
use crate::Cli;
|
||||||
|
use crate::cli::{
|
||||||
|
Command,
|
||||||
|
sonarr::{SonarrCommand, refresh_command_handler::SonarrRefreshCommand},
|
||||||
|
};
|
||||||
use clap::CommandFactory;
|
use clap::CommandFactory;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -20,7 +20,7 @@ mod tests {
|
|||||||
|
|
||||||
mod cli {
|
mod cli {
|
||||||
use super::*;
|
use super::*;
|
||||||
use clap::{error::ErrorKind, Parser};
|
use clap::{Parser, error::ErrorKind};
|
||||||
use pretty_assertions::assert_eq;
|
use pretty_assertions::assert_eq;
|
||||||
use rstest::rstest;
|
use rstest::rstest;
|
||||||
|
|
||||||
@@ -31,14 +31,14 @@ mod tests {
|
|||||||
let result =
|
let result =
|
||||||
Cli::command().try_get_matches_from(["managarr", "sonarr", "refresh", subcommand]);
|
Cli::command().try_get_matches_from(["managarr", "sonarr", "refresh", subcommand]);
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_refresh_series_requires_series_id() {
|
fn test_refresh_series_requires_series_id() {
|
||||||
let result = Cli::command().try_get_matches_from(["managarr", "sonarr", "refresh", "series"]);
|
let result = Cli::command().try_get_matches_from(["managarr", "sonarr", "refresh", "series"]);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert_err!(&result);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
result.unwrap_err().kind(),
|
result.unwrap_err().kind(),
|
||||||
ErrorKind::MissingRequiredArgument
|
ErrorKind::MissingRequiredArgument
|
||||||
@@ -57,13 +57,13 @@ mod tests {
|
|||||||
"1",
|
"1",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
|
|
||||||
if let Some(Command::Sonarr(SonarrCommand::Refresh(refresh_command))) =
|
let Some(Command::Sonarr(SonarrCommand::Refresh(refresh_command))) = result.unwrap().command
|
||||||
result.unwrap().command
|
else {
|
||||||
{
|
panic!("Unexpected command type");
|
||||||
assert_eq!(refresh_command, expected_args);
|
};
|
||||||
}
|
assert_eq!(refresh_command, expected_args);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -77,11 +77,11 @@ mod tests {
|
|||||||
|
|
||||||
use crate::{app::App, cli::sonarr::refresh_command_handler::SonarrRefreshCommandHandler};
|
use crate::{app::App, cli::sonarr::refresh_command_handler::SonarrRefreshCommandHandler};
|
||||||
use crate::{
|
use crate::{
|
||||||
cli::{sonarr::refresh_command_handler::SonarrRefreshCommand, CliCommandHandler},
|
cli::{CliCommandHandler, sonarr::refresh_command_handler::SonarrRefreshCommand},
|
||||||
network::sonarr_network::SonarrEvent,
|
network::sonarr_network::SonarrEvent,
|
||||||
};
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
models::{sonarr_models::SonarrSerdeable, Serdeable},
|
models::{Serdeable, sonarr_models::SonarrSerdeable},
|
||||||
network::{MockNetworkTrait, NetworkEvent},
|
network::{MockNetworkTrait, NetworkEvent},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -103,13 +103,13 @@ mod tests {
|
|||||||
json!({"testResponse": "response"}),
|
json!({"testResponse": "response"}),
|
||||||
)))
|
)))
|
||||||
});
|
});
|
||||||
let app_arc = Arc::new(Mutex::new(App::default()));
|
let app_arc = Arc::new(Mutex::new(App::test_default()));
|
||||||
|
|
||||||
let result = SonarrRefreshCommandHandler::with(&app_arc, refresh_command, &mut mock_network)
|
let result = SonarrRefreshCommandHandler::with(&app_arc, refresh_command, &mut mock_network)
|
||||||
.handle()
|
.handle()
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@@ -127,7 +127,7 @@ mod tests {
|
|||||||
json!({"testResponse": "response"}),
|
json!({"testResponse": "response"}),
|
||||||
)))
|
)))
|
||||||
});
|
});
|
||||||
let app_arc = Arc::new(Mutex::new(App::default()));
|
let app_arc = Arc::new(Mutex::new(App::test_default()));
|
||||||
let refresh_series_command = SonarrRefreshCommand::Series { series_id: 1 };
|
let refresh_series_command = SonarrRefreshCommand::Series { series_id: 1 };
|
||||||
|
|
||||||
let result =
|
let result =
|
||||||
@@ -135,7 +135,7 @@ mod tests {
|
|||||||
.handle()
|
.handle()
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::cli::{
|
|
||||||
sonarr::{list_command_handler::SonarrListCommand, SonarrCommand},
|
|
||||||
Command,
|
|
||||||
};
|
|
||||||
use crate::Cli;
|
use crate::Cli;
|
||||||
|
use crate::cli::{
|
||||||
|
Command,
|
||||||
|
sonarr::{SonarrCommand, list_command_handler::SonarrListCommand},
|
||||||
|
};
|
||||||
use clap::CommandFactory;
|
use clap::CommandFactory;
|
||||||
use pretty_assertions::assert_eq;
|
use pretty_assertions::assert_eq;
|
||||||
|
|
||||||
@@ -29,7 +29,7 @@ mod tests {
|
|||||||
) {
|
) {
|
||||||
let result = Cli::command().try_get_matches_from(["managarr", "sonarr", subcommand]);
|
let result = Cli::command().try_get_matches_from(["managarr", "sonarr", subcommand]);
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -37,7 +37,7 @@ mod tests {
|
|||||||
let result =
|
let result =
|
||||||
Cli::command().try_get_matches_from(["managarr", "sonarr", "mark-history-item-as-failed"]);
|
Cli::command().try_get_matches_from(["managarr", "sonarr", "mark-history-item-as-failed"]);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert_err!(&result);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
result.unwrap_err().kind(),
|
result.unwrap_err().kind(),
|
||||||
ErrorKind::MissingRequiredArgument
|
ErrorKind::MissingRequiredArgument
|
||||||
@@ -54,14 +54,14 @@ mod tests {
|
|||||||
"1",
|
"1",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_search_new_series_requires_query() {
|
fn test_search_new_series_requires_query() {
|
||||||
let result = Cli::command().try_get_matches_from(["managarr", "sonarr", "search-new-series"]);
|
let result = Cli::command().try_get_matches_from(["managarr", "sonarr", "search-new-series"]);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert_err!(&result);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
result.unwrap_err().kind(),
|
result.unwrap_err().kind(),
|
||||||
ErrorKind::MissingRequiredArgument
|
ErrorKind::MissingRequiredArgument
|
||||||
@@ -78,14 +78,14 @@ mod tests {
|
|||||||
"halo",
|
"halo",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_start_task_requires_task_name() {
|
fn test_start_task_requires_task_name() {
|
||||||
let result = Cli::command().try_get_matches_from(["managarr", "sonarr", "start-task"]);
|
let result = Cli::command().try_get_matches_from(["managarr", "sonarr", "start-task"]);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert_err!(&result);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
result.unwrap_err().kind(),
|
result.unwrap_err().kind(),
|
||||||
ErrorKind::MissingRequiredArgument
|
ErrorKind::MissingRequiredArgument
|
||||||
@@ -102,7 +102,7 @@ mod tests {
|
|||||||
"test",
|
"test",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert_err!(&result);
|
||||||
assert_eq!(result.unwrap_err().kind(), ErrorKind::InvalidValue);
|
assert_eq!(result.unwrap_err().kind(), ErrorKind::InvalidValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -116,14 +116,14 @@ mod tests {
|
|||||||
"application-update-check",
|
"application-update-check",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_test_indexer_requires_indexer_id() {
|
fn test_test_indexer_requires_indexer_id() {
|
||||||
let result = Cli::command().try_get_matches_from(["managarr", "sonarr", "test-indexer"]);
|
let result = Cli::command().try_get_matches_from(["managarr", "sonarr", "test-indexer"]);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert_err!(&result);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
result.unwrap_err().kind(),
|
result.unwrap_err().kind(),
|
||||||
ErrorKind::MissingRequiredArgument
|
ErrorKind::MissingRequiredArgument
|
||||||
@@ -140,7 +140,7 @@ mod tests {
|
|||||||
"1",
|
"1",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -148,7 +148,7 @@ mod tests {
|
|||||||
let result =
|
let result =
|
||||||
Cli::command().try_get_matches_from(["managarr", "sonarr", "toggle-episode-monitoring"]);
|
Cli::command().try_get_matches_from(["managarr", "sonarr", "toggle-episode-monitoring"]);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert_err!(&result);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
result.unwrap_err().kind(),
|
result.unwrap_err().kind(),
|
||||||
ErrorKind::MissingRequiredArgument
|
ErrorKind::MissingRequiredArgument
|
||||||
@@ -165,7 +165,7 @@ mod tests {
|
|||||||
"1",
|
"1",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -178,7 +178,7 @@ mod tests {
|
|||||||
"1",
|
"1",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert_err!(&result);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
result.unwrap_err().kind(),
|
result.unwrap_err().kind(),
|
||||||
ErrorKind::MissingRequiredArgument
|
ErrorKind::MissingRequiredArgument
|
||||||
@@ -195,7 +195,7 @@ mod tests {
|
|||||||
"1",
|
"1",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert_err!(&result);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
result.unwrap_err().kind(),
|
result.unwrap_err().kind(),
|
||||||
ErrorKind::MissingRequiredArgument
|
ErrorKind::MissingRequiredArgument
|
||||||
@@ -214,7 +214,32 @@ mod tests {
|
|||||||
"1",
|
"1",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_toggle_series_monitoring_requires_series_id() {
|
||||||
|
let result =
|
||||||
|
Cli::command().try_get_matches_from(["managarr", "sonarr", "toggle-series-monitoring"]);
|
||||||
|
|
||||||
|
assert_err!(&result);
|
||||||
|
assert_eq!(
|
||||||
|
result.unwrap_err().kind(),
|
||||||
|
ErrorKind::MissingRequiredArgument
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_toggle_series_monitoring_requirements_satisfied() {
|
||||||
|
let result = Cli::command().try_get_matches_from([
|
||||||
|
"managarr",
|
||||||
|
"sonarr",
|
||||||
|
"toggle-series-monitoring",
|
||||||
|
"--series-id",
|
||||||
|
"1",
|
||||||
|
]);
|
||||||
|
|
||||||
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -228,25 +253,25 @@ mod tests {
|
|||||||
use crate::{
|
use crate::{
|
||||||
app::App,
|
app::App,
|
||||||
cli::{
|
cli::{
|
||||||
|
CliCommandHandler,
|
||||||
sonarr::{
|
sonarr::{
|
||||||
add_command_handler::SonarrAddCommand, delete_command_handler::SonarrDeleteCommand,
|
SonarrCliHandler, SonarrCommand, add_command_handler::SonarrAddCommand,
|
||||||
|
delete_command_handler::SonarrDeleteCommand,
|
||||||
download_command_handler::SonarrDownloadCommand, edit_command_handler::SonarrEditCommand,
|
download_command_handler::SonarrDownloadCommand, edit_command_handler::SonarrEditCommand,
|
||||||
get_command_handler::SonarrGetCommand, list_command_handler::SonarrListCommand,
|
get_command_handler::SonarrGetCommand, list_command_handler::SonarrListCommand,
|
||||||
manual_search_command_handler::SonarrManualSearchCommand,
|
manual_search_command_handler::SonarrManualSearchCommand,
|
||||||
refresh_command_handler::SonarrRefreshCommand,
|
refresh_command_handler::SonarrRefreshCommand,
|
||||||
trigger_automatic_search_command_handler::SonarrTriggerAutomaticSearchCommand,
|
trigger_automatic_search_command_handler::SonarrTriggerAutomaticSearchCommand,
|
||||||
SonarrCliHandler, SonarrCommand,
|
|
||||||
},
|
},
|
||||||
CliCommandHandler,
|
|
||||||
},
|
},
|
||||||
models::{
|
models::{
|
||||||
|
Serdeable,
|
||||||
sonarr_models::{
|
sonarr_models::{
|
||||||
BlocklistItem, BlocklistResponse, IndexerSettings, Series, SonarrReleaseDownloadBody,
|
BlocklistItem, BlocklistResponse, IndexerSettings, Series, SonarrReleaseDownloadBody,
|
||||||
SonarrSerdeable, SonarrTaskName,
|
SonarrSerdeable, SonarrTaskName,
|
||||||
},
|
},
|
||||||
Serdeable,
|
|
||||||
},
|
},
|
||||||
network::{sonarr_network::SonarrEvent, MockNetworkTrait, NetworkEvent},
|
network::{MockNetworkTrait, NetworkEvent, sonarr_network::SonarrEvent},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@@ -272,14 +297,14 @@ mod tests {
|
|||||||
json!({"testResponse": "response"}),
|
json!({"testResponse": "response"}),
|
||||||
)))
|
)))
|
||||||
});
|
});
|
||||||
let app_arc = Arc::new(Mutex::new(App::default()));
|
let app_arc = Arc::new(Mutex::new(App::test_default()));
|
||||||
let claer_blocklist_command = SonarrCommand::ClearBlocklist;
|
let claer_blocklist_command = SonarrCommand::ClearBlocklist;
|
||||||
|
|
||||||
let result = SonarrCliHandler::with(&app_arc, claer_blocklist_command, &mut mock_network)
|
let result = SonarrCliHandler::with(&app_arc, claer_blocklist_command, &mut mock_network)
|
||||||
.handle()
|
.handle()
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@@ -297,7 +322,7 @@ mod tests {
|
|||||||
json!({"testResponse": "response"}),
|
json!({"testResponse": "response"}),
|
||||||
)))
|
)))
|
||||||
});
|
});
|
||||||
let app_arc = Arc::new(Mutex::new(App::default()));
|
let app_arc = Arc::new(Mutex::new(App::test_default()));
|
||||||
let mark_history_item_as_failed_command =
|
let mark_history_item_as_failed_command =
|
||||||
SonarrCommand::MarkHistoryItemAsFailed { history_item_id: 1 };
|
SonarrCommand::MarkHistoryItemAsFailed { history_item_id: 1 };
|
||||||
|
|
||||||
@@ -309,7 +334,7 @@ mod tests {
|
|||||||
.handle()
|
.handle()
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@@ -327,7 +352,7 @@ mod tests {
|
|||||||
json!({"testResponse": "response"}),
|
json!({"testResponse": "response"}),
|
||||||
)))
|
)))
|
||||||
});
|
});
|
||||||
let app_arc = Arc::new(Mutex::new(App::default()));
|
let app_arc = Arc::new(Mutex::new(App::test_default()));
|
||||||
let add_tag_command = SonarrCommand::Add(SonarrAddCommand::Tag {
|
let add_tag_command = SonarrCommand::Add(SonarrAddCommand::Tag {
|
||||||
name: expected_tag_name,
|
name: expected_tag_name,
|
||||||
});
|
});
|
||||||
@@ -336,7 +361,7 @@ mod tests {
|
|||||||
.handle()
|
.handle()
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@@ -354,7 +379,7 @@ mod tests {
|
|||||||
json!({"testResponse": "response"}),
|
json!({"testResponse": "response"}),
|
||||||
)))
|
)))
|
||||||
});
|
});
|
||||||
let app_arc = Arc::new(Mutex::new(App::default()));
|
let app_arc = Arc::new(Mutex::new(App::test_default()));
|
||||||
let delete_blocklist_item_command =
|
let delete_blocklist_item_command =
|
||||||
SonarrCommand::Delete(SonarrDeleteCommand::BlocklistItem {
|
SonarrCommand::Delete(SonarrDeleteCommand::BlocklistItem {
|
||||||
blocklist_item_id: 1,
|
blocklist_item_id: 1,
|
||||||
@@ -365,7 +390,7 @@ mod tests {
|
|||||||
.handle()
|
.handle()
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@@ -388,7 +413,7 @@ mod tests {
|
|||||||
json!({"testResponse": "response"}),
|
json!({"testResponse": "response"}),
|
||||||
)))
|
)))
|
||||||
});
|
});
|
||||||
let app_arc = Arc::new(Mutex::new(App::default()));
|
let app_arc = Arc::new(Mutex::new(App::test_default()));
|
||||||
let download_series_release_command =
|
let download_series_release_command =
|
||||||
SonarrCommand::Download(SonarrDownloadCommand::Series {
|
SonarrCommand::Download(SonarrDownloadCommand::Series {
|
||||||
guid: "1234".to_owned(),
|
guid: "1234".to_owned(),
|
||||||
@@ -401,7 +426,7 @@ mod tests {
|
|||||||
.handle()
|
.handle()
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@@ -442,7 +467,7 @@ mod tests {
|
|||||||
json!({"testResponse": "response"}),
|
json!({"testResponse": "response"}),
|
||||||
)))
|
)))
|
||||||
});
|
});
|
||||||
let app_arc = Arc::new(Mutex::new(App::default()));
|
let app_arc = Arc::new(Mutex::new(App::test_default()));
|
||||||
let edit_all_indexer_settings_command =
|
let edit_all_indexer_settings_command =
|
||||||
SonarrCommand::Edit(SonarrEditCommand::AllIndexerSettings {
|
SonarrCommand::Edit(SonarrEditCommand::AllIndexerSettings {
|
||||||
maximum_size: Some(1),
|
maximum_size: Some(1),
|
||||||
@@ -459,12 +484,12 @@ mod tests {
|
|||||||
.handle()
|
.handle()
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_sonarr_cli_handler_delegates_manual_search_commands_to_the_manual_search_command_handler(
|
async fn test_sonarr_cli_handler_delegates_manual_search_commands_to_the_manual_search_command_handler()
|
||||||
) {
|
{
|
||||||
let expected_episode_id = 1;
|
let expected_episode_id = 1;
|
||||||
let mut mock_network = MockNetworkTrait::new();
|
let mut mock_network = MockNetworkTrait::new();
|
||||||
mock_network
|
mock_network
|
||||||
@@ -478,7 +503,7 @@ mod tests {
|
|||||||
json!({"testResponse": "response"}),
|
json!({"testResponse": "response"}),
|
||||||
)))
|
)))
|
||||||
});
|
});
|
||||||
let app_arc = Arc::new(Mutex::new(App::default()));
|
let app_arc = Arc::new(Mutex::new(App::test_default()));
|
||||||
let manual_episode_search_command =
|
let manual_episode_search_command =
|
||||||
SonarrCommand::ManualSearch(SonarrManualSearchCommand::Episode { episode_id: 1 });
|
SonarrCommand::ManualSearch(SonarrManualSearchCommand::Episode { episode_id: 1 });
|
||||||
|
|
||||||
@@ -487,12 +512,12 @@ mod tests {
|
|||||||
.handle()
|
.handle()
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_sonarr_cli_handler_delegates_trigger_automatic_search_commands_to_the_trigger_automatic_search_command_handler(
|
async fn test_sonarr_cli_handler_delegates_trigger_automatic_search_commands_to_the_trigger_automatic_search_command_handler()
|
||||||
) {
|
{
|
||||||
let expected_episode_id = 1;
|
let expected_episode_id = 1;
|
||||||
let mut mock_network = MockNetworkTrait::new();
|
let mut mock_network = MockNetworkTrait::new();
|
||||||
mock_network
|
mock_network
|
||||||
@@ -506,7 +531,7 @@ mod tests {
|
|||||||
json!({"testResponse": "response"}),
|
json!({"testResponse": "response"}),
|
||||||
)))
|
)))
|
||||||
});
|
});
|
||||||
let app_arc = Arc::new(Mutex::new(App::default()));
|
let app_arc = Arc::new(Mutex::new(App::test_default()));
|
||||||
let manual_episode_search_command =
|
let manual_episode_search_command =
|
||||||
SonarrCommand::TriggerAutomaticSearch(SonarrTriggerAutomaticSearchCommand::Episode {
|
SonarrCommand::TriggerAutomaticSearch(SonarrTriggerAutomaticSearchCommand::Episode {
|
||||||
episode_id: 1,
|
episode_id: 1,
|
||||||
@@ -517,7 +542,7 @@ mod tests {
|
|||||||
.handle()
|
.handle()
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@@ -532,14 +557,14 @@ mod tests {
|
|||||||
json!({"testResponse": "response"}),
|
json!({"testResponse": "response"}),
|
||||||
)))
|
)))
|
||||||
});
|
});
|
||||||
let app_arc = Arc::new(Mutex::new(App::default()));
|
let app_arc = Arc::new(Mutex::new(App::test_default()));
|
||||||
let get_system_status_command = SonarrCommand::Get(SonarrGetCommand::SystemStatus);
|
let get_system_status_command = SonarrCommand::Get(SonarrGetCommand::SystemStatus);
|
||||||
|
|
||||||
let result = SonarrCliHandler::with(&app_arc, get_system_status_command, &mut mock_network)
|
let result = SonarrCliHandler::with(&app_arc, get_system_status_command, &mut mock_network)
|
||||||
.handle()
|
.handle()
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@@ -554,14 +579,14 @@ mod tests {
|
|||||||
Series::default(),
|
Series::default(),
|
||||||
])))
|
])))
|
||||||
});
|
});
|
||||||
let app_arc = Arc::new(Mutex::new(App::default()));
|
let app_arc = Arc::new(Mutex::new(App::test_default()));
|
||||||
let list_series_command = SonarrCommand::List(SonarrListCommand::Series);
|
let list_series_command = SonarrCommand::List(SonarrListCommand::Series);
|
||||||
|
|
||||||
let result = SonarrCliHandler::with(&app_arc, list_series_command, &mut mock_network)
|
let result = SonarrCliHandler::with(&app_arc, list_series_command, &mut mock_network)
|
||||||
.handle()
|
.handle()
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@@ -579,7 +604,7 @@ mod tests {
|
|||||||
json!({"testResponse": "response"}),
|
json!({"testResponse": "response"}),
|
||||||
)))
|
)))
|
||||||
});
|
});
|
||||||
let app_arc = Arc::new(Mutex::new(App::default()));
|
let app_arc = Arc::new(Mutex::new(App::test_default()));
|
||||||
let refresh_series_command =
|
let refresh_series_command =
|
||||||
SonarrCommand::Refresh(SonarrRefreshCommand::Series { series_id: 1 });
|
SonarrCommand::Refresh(SonarrRefreshCommand::Series { series_id: 1 });
|
||||||
|
|
||||||
@@ -587,7 +612,7 @@ mod tests {
|
|||||||
.handle()
|
.handle()
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@@ -605,7 +630,7 @@ mod tests {
|
|||||||
json!({"testResponse": "response"}),
|
json!({"testResponse": "response"}),
|
||||||
)))
|
)))
|
||||||
});
|
});
|
||||||
let app_arc = Arc::new(Mutex::new(App::default()));
|
let app_arc = Arc::new(Mutex::new(App::test_default()));
|
||||||
let search_new_series_command = SonarrCommand::SearchNewSeries {
|
let search_new_series_command = SonarrCommand::SearchNewSeries {
|
||||||
query: "halo".to_owned(),
|
query: "halo".to_owned(),
|
||||||
};
|
};
|
||||||
@@ -614,7 +639,7 @@ mod tests {
|
|||||||
.handle()
|
.handle()
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@@ -632,7 +657,7 @@ mod tests {
|
|||||||
json!({"testResponse": "response"}),
|
json!({"testResponse": "response"}),
|
||||||
)))
|
)))
|
||||||
});
|
});
|
||||||
let app_arc = Arc::new(Mutex::new(App::default()));
|
let app_arc = Arc::new(Mutex::new(App::test_default()));
|
||||||
let start_task_command = SonarrCommand::StartTask {
|
let start_task_command = SonarrCommand::StartTask {
|
||||||
task_name: SonarrTaskName::ApplicationUpdateCheck,
|
task_name: SonarrTaskName::ApplicationUpdateCheck,
|
||||||
};
|
};
|
||||||
@@ -641,7 +666,7 @@ mod tests {
|
|||||||
.handle()
|
.handle()
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@@ -659,14 +684,14 @@ mod tests {
|
|||||||
json!({"testResponse": "response"}),
|
json!({"testResponse": "response"}),
|
||||||
)))
|
)))
|
||||||
});
|
});
|
||||||
let app_arc = Arc::new(Mutex::new(App::default()));
|
let app_arc = Arc::new(Mutex::new(App::test_default()));
|
||||||
let test_indexer_command = SonarrCommand::TestIndexer { indexer_id: 1 };
|
let test_indexer_command = SonarrCommand::TestIndexer { indexer_id: 1 };
|
||||||
|
|
||||||
let result = SonarrCliHandler::with(&app_arc, test_indexer_command, &mut mock_network)
|
let result = SonarrCliHandler::with(&app_arc, test_indexer_command, &mut mock_network)
|
||||||
.handle()
|
.handle()
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@@ -681,18 +706,18 @@ mod tests {
|
|||||||
json!({"testResponse": "response"}),
|
json!({"testResponse": "response"}),
|
||||||
)))
|
)))
|
||||||
});
|
});
|
||||||
let app_arc = Arc::new(Mutex::new(App::default()));
|
let app_arc = Arc::new(Mutex::new(App::test_default()));
|
||||||
let test_all_indexers_command = SonarrCommand::TestAllIndexers;
|
let test_all_indexers_command = SonarrCommand::TestAllIndexers;
|
||||||
|
|
||||||
let result = SonarrCliHandler::with(&app_arc, test_all_indexers_command, &mut mock_network)
|
let result = SonarrCliHandler::with(&app_arc, test_all_indexers_command, &mut mock_network)
|
||||||
.handle()
|
.handle()
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_list_toggle_episode_monitoring_command() {
|
async fn test_toggle_episode_monitoring_command() {
|
||||||
let expected_episode_id = 1;
|
let expected_episode_id = 1;
|
||||||
let mut mock_network = MockNetworkTrait::new();
|
let mut mock_network = MockNetworkTrait::new();
|
||||||
mock_network
|
mock_network
|
||||||
@@ -706,7 +731,7 @@ mod tests {
|
|||||||
json!({"testResponse": "response"}),
|
json!({"testResponse": "response"}),
|
||||||
)))
|
)))
|
||||||
});
|
});
|
||||||
let app_arc = Arc::new(Mutex::new(App::default()));
|
let app_arc = Arc::new(Mutex::new(App::test_default()));
|
||||||
let toggle_episode_monitoring_command =
|
let toggle_episode_monitoring_command =
|
||||||
SonarrCommand::ToggleEpisodeMonitoring { episode_id: 1 };
|
SonarrCommand::ToggleEpisodeMonitoring { episode_id: 1 };
|
||||||
|
|
||||||
@@ -718,11 +743,11 @@ mod tests {
|
|||||||
.handle()
|
.handle()
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_list_toggle_season_monitoring_command() {
|
async fn test_toggle_season_monitoring_command() {
|
||||||
let expected_series_id = 1;
|
let expected_series_id = 1;
|
||||||
let expected_season_number = 1;
|
let expected_season_number = 1;
|
||||||
let mut mock_network = MockNetworkTrait::new();
|
let mut mock_network = MockNetworkTrait::new();
|
||||||
@@ -737,7 +762,7 @@ mod tests {
|
|||||||
json!({"testResponse": "response"}),
|
json!({"testResponse": "response"}),
|
||||||
)))
|
)))
|
||||||
});
|
});
|
||||||
let app_arc = Arc::new(Mutex::new(App::default()));
|
let app_arc = Arc::new(Mutex::new(App::test_default()));
|
||||||
let toggle_season_monitoring_command = SonarrCommand::ToggleSeasonMonitoring {
|
let toggle_season_monitoring_command = SonarrCommand::ToggleSeasonMonitoring {
|
||||||
series_id: 1,
|
series_id: 1,
|
||||||
season_number: 1,
|
season_number: 1,
|
||||||
@@ -751,7 +776,36 @@ mod tests {
|
|||||||
.handle()
|
.handle()
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_toggle_series_monitoring_command() {
|
||||||
|
let expected_series_id = 1;
|
||||||
|
let mut mock_network = MockNetworkTrait::new();
|
||||||
|
mock_network
|
||||||
|
.expect_handle_network_event()
|
||||||
|
.with(eq::<NetworkEvent>(
|
||||||
|
SonarrEvent::ToggleSeriesMonitoring(expected_series_id).into(),
|
||||||
|
))
|
||||||
|
.times(1)
|
||||||
|
.returning(|_| {
|
||||||
|
Ok(Serdeable::Sonarr(SonarrSerdeable::Value(
|
||||||
|
json!({"testResponse": "response"}),
|
||||||
|
)))
|
||||||
|
});
|
||||||
|
let app_arc = Arc::new(Mutex::new(App::test_default()));
|
||||||
|
let toggle_series_monitoring_command = SonarrCommand::ToggleSeriesMonitoring { series_id: 1 };
|
||||||
|
|
||||||
|
let result = SonarrCliHandler::with(
|
||||||
|
&app_arc,
|
||||||
|
toggle_series_monitoring_command,
|
||||||
|
&mut mock_network,
|
||||||
|
)
|
||||||
|
.handle()
|
||||||
|
.await;
|
||||||
|
|
||||||
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ use tokio::sync::Mutex;
|
|||||||
use crate::{
|
use crate::{
|
||||||
app::App,
|
app::App,
|
||||||
cli::{CliCommandHandler, Command},
|
cli::{CliCommandHandler, Command},
|
||||||
network::{sonarr_network::SonarrEvent, NetworkTrait},
|
network::{NetworkTrait, sonarr_network::SonarrEvent},
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::SonarrCommand;
|
use super::SonarrCommand;
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::cli::{
|
|
||||||
sonarr::{
|
|
||||||
trigger_automatic_search_command_handler::SonarrTriggerAutomaticSearchCommand, SonarrCommand,
|
|
||||||
},
|
|
||||||
Command,
|
|
||||||
};
|
|
||||||
use crate::Cli;
|
use crate::Cli;
|
||||||
|
use crate::cli::{
|
||||||
|
Command,
|
||||||
|
sonarr::{
|
||||||
|
SonarrCommand, trigger_automatic_search_command_handler::SonarrTriggerAutomaticSearchCommand,
|
||||||
|
},
|
||||||
|
};
|
||||||
use clap::CommandFactory;
|
use clap::CommandFactory;
|
||||||
use pretty_assertions::assert_eq;
|
use pretty_assertions::assert_eq;
|
||||||
|
|
||||||
@@ -36,7 +36,7 @@ mod tests {
|
|||||||
"series",
|
"series",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert_err!(&result);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
result.unwrap_err().kind(),
|
result.unwrap_err().kind(),
|
||||||
ErrorKind::MissingRequiredArgument
|
ErrorKind::MissingRequiredArgument
|
||||||
@@ -54,7 +54,7 @@ mod tests {
|
|||||||
"1",
|
"1",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -68,7 +68,7 @@ mod tests {
|
|||||||
"1",
|
"1",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert_err!(&result);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
result.unwrap_err().kind(),
|
result.unwrap_err().kind(),
|
||||||
ErrorKind::MissingRequiredArgument
|
ErrorKind::MissingRequiredArgument
|
||||||
@@ -86,7 +86,7 @@ mod tests {
|
|||||||
"1",
|
"1",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert_err!(&result);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
result.unwrap_err().kind(),
|
result.unwrap_err().kind(),
|
||||||
ErrorKind::MissingRequiredArgument
|
ErrorKind::MissingRequiredArgument
|
||||||
@@ -106,7 +106,7 @@ mod tests {
|
|||||||
"1",
|
"1",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -118,7 +118,7 @@ mod tests {
|
|||||||
"episode",
|
"episode",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert_err!(&result);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
result.unwrap_err().kind(),
|
result.unwrap_err().kind(),
|
||||||
ErrorKind::MissingRequiredArgument
|
ErrorKind::MissingRequiredArgument
|
||||||
@@ -136,7 +136,7 @@ mod tests {
|
|||||||
"1",
|
"1",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -150,13 +150,13 @@ mod tests {
|
|||||||
use crate::{
|
use crate::{
|
||||||
app::App,
|
app::App,
|
||||||
cli::{
|
cli::{
|
||||||
|
CliCommandHandler,
|
||||||
sonarr::trigger_automatic_search_command_handler::{
|
sonarr::trigger_automatic_search_command_handler::{
|
||||||
SonarrTriggerAutomaticSearchCommand, SonarrTriggerAutomaticSearchCommandHandler,
|
SonarrTriggerAutomaticSearchCommand, SonarrTriggerAutomaticSearchCommandHandler,
|
||||||
},
|
},
|
||||||
CliCommandHandler,
|
|
||||||
},
|
},
|
||||||
models::{sonarr_models::SonarrSerdeable, Serdeable},
|
models::{Serdeable, sonarr_models::SonarrSerdeable},
|
||||||
network::{sonarr_network::SonarrEvent, MockNetworkTrait, NetworkEvent},
|
network::{MockNetworkTrait, NetworkEvent, sonarr_network::SonarrEvent},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@@ -174,7 +174,7 @@ mod tests {
|
|||||||
json!({"testResponse": "response"}),
|
json!({"testResponse": "response"}),
|
||||||
)))
|
)))
|
||||||
});
|
});
|
||||||
let app_arc = Arc::new(Mutex::new(App::default()));
|
let app_arc = Arc::new(Mutex::new(App::test_default()));
|
||||||
let trigger_automatic_series_search_command =
|
let trigger_automatic_series_search_command =
|
||||||
SonarrTriggerAutomaticSearchCommand::Series { series_id: 1 };
|
SonarrTriggerAutomaticSearchCommand::Series { series_id: 1 };
|
||||||
|
|
||||||
@@ -186,7 +186,7 @@ mod tests {
|
|||||||
.handle()
|
.handle()
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@@ -206,7 +206,7 @@ mod tests {
|
|||||||
json!({"testResponse": "response"}),
|
json!({"testResponse": "response"}),
|
||||||
)))
|
)))
|
||||||
});
|
});
|
||||||
let app_arc = Arc::new(Mutex::new(App::default()));
|
let app_arc = Arc::new(Mutex::new(App::test_default()));
|
||||||
let trigger_automatic_season_search_command = SonarrTriggerAutomaticSearchCommand::Season {
|
let trigger_automatic_season_search_command = SonarrTriggerAutomaticSearchCommand::Season {
|
||||||
series_id: 1,
|
series_id: 1,
|
||||||
season_number: 1,
|
season_number: 1,
|
||||||
@@ -220,7 +220,7 @@ mod tests {
|
|||||||
.handle()
|
.handle()
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@@ -238,7 +238,7 @@ mod tests {
|
|||||||
json!({"testResponse": "response"}),
|
json!({"testResponse": "response"}),
|
||||||
)))
|
)))
|
||||||
});
|
});
|
||||||
let app_arc = Arc::new(Mutex::new(App::default()));
|
let app_arc = Arc::new(Mutex::new(App::test_default()));
|
||||||
let trigger_automatic_episode_search_command =
|
let trigger_automatic_episode_search_command =
|
||||||
SonarrTriggerAutomaticSearchCommand::Episode { episode_id: 1 };
|
SonarrTriggerAutomaticSearchCommand::Episode { episode_id: 1 };
|
||||||
|
|
||||||
@@ -250,7 +250,7 @@ mod tests {
|
|||||||
.handle()
|
.handle()
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ use std::thread;
|
|||||||
use std::time::{Duration, Instant};
|
use std::time::{Duration, Instant};
|
||||||
|
|
||||||
use crossterm::event;
|
use crossterm::event;
|
||||||
use crossterm::event::Event as CrosstermEvent;
|
use crossterm::event::{Event as CrosstermEvent, KeyEventKind};
|
||||||
|
|
||||||
use crate::event::Key;
|
use crate::event::Key;
|
||||||
|
|
||||||
@@ -28,8 +28,12 @@ impl Events {
|
|||||||
let timeout = tick_rate
|
let timeout = tick_rate
|
||||||
.checked_sub(last_tick.elapsed())
|
.checked_sub(last_tick.elapsed())
|
||||||
.unwrap_or_else(|| Duration::from_secs(0));
|
.unwrap_or_else(|| Duration::from_secs(0));
|
||||||
if event::poll(timeout).unwrap() {
|
if event::poll(timeout).unwrap()
|
||||||
if let CrosstermEvent::Key(key_event) = event::read().unwrap() {
|
&& let CrosstermEvent::Key(key_event) = event::read().unwrap()
|
||||||
|
{
|
||||||
|
// Only process the key event if it's a press event
|
||||||
|
// Source: https://ratatui.rs/faq/ Why am I getting duplicate key events on Windows?
|
||||||
|
if key_event.kind == KeyEventKind::Press {
|
||||||
let key = Key::from(key_event);
|
let key = Key::from(key_event);
|
||||||
tx.send(InputEvent::KeyEvent(key)).unwrap();
|
tx.send(InputEvent::KeyEvent(key)).unwrap();
|
||||||
}
|
}
|
||||||
|
|||||||
+27
-15
@@ -13,6 +13,8 @@ pub enum Key {
|
|||||||
Down,
|
Down,
|
||||||
Left,
|
Left,
|
||||||
Right,
|
Right,
|
||||||
|
PgDown,
|
||||||
|
PgUp,
|
||||||
Enter,
|
Enter,
|
||||||
Esc,
|
Esc,
|
||||||
Backspace,
|
Backspace,
|
||||||
@@ -29,21 +31,23 @@ pub enum Key {
|
|||||||
impl Display for Key {
|
impl Display for Key {
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||||
match *self {
|
match *self {
|
||||||
Key::Char(c) => write!(f, "<{c}>"),
|
Key::Char(c) => write!(f, "{c}"),
|
||||||
Key::Ctrl(c) => write!(f, "<ctrl-{c}>"),
|
Key::Ctrl(c) => write!(f, "ctrl-{c}"),
|
||||||
Key::Up => write!(f, "<↑>"),
|
Key::Up => write!(f, "↑"),
|
||||||
Key::Down => write!(f, "<↓>"),
|
Key::Down => write!(f, "↓"),
|
||||||
Key::Left => write!(f, "<←>"),
|
Key::Left => write!(f, "←"),
|
||||||
Key::Right => write!(f, "<→>"),
|
Key::Right => write!(f, "→"),
|
||||||
Key::Enter => write!(f, "<enter>"),
|
Key::PgDown => write!(f, "pgDown"),
|
||||||
Key::Esc => write!(f, "<esc>"),
|
Key::PgUp => write!(f, "pgUp"),
|
||||||
Key::Backspace => write!(f, "<backspace>"),
|
Key::Enter => write!(f, "enter"),
|
||||||
Key::Home => write!(f, "<home>"),
|
Key::Esc => write!(f, "esc"),
|
||||||
Key::End => write!(f, "<end>"),
|
Key::Backspace => write!(f, "backspace"),
|
||||||
Key::Tab => write!(f, "<tab>"),
|
Key::Home => write!(f, "home"),
|
||||||
Key::BackTab => write!(f, "<shift-tab>"),
|
Key::End => write!(f, "end"),
|
||||||
Key::Delete => write!(f, "<del>"),
|
Key::Tab => write!(f, "tab"),
|
||||||
_ => write!(f, "<{self:?}>"),
|
Key::BackTab => write!(f, "shift-tab"),
|
||||||
|
Key::Delete => write!(f, "del"),
|
||||||
|
_ => write!(f, "{self:?}"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -66,6 +70,14 @@ impl From<KeyEvent> for Key {
|
|||||||
code: KeyCode::Right,
|
code: KeyCode::Right,
|
||||||
..
|
..
|
||||||
} => Key::Right,
|
} => Key::Right,
|
||||||
|
KeyEvent {
|
||||||
|
code: KeyCode::PageDown,
|
||||||
|
..
|
||||||
|
} => Key::PgDown,
|
||||||
|
KeyEvent {
|
||||||
|
code: KeyCode::PageUp,
|
||||||
|
..
|
||||||
|
} => Key::PgUp,
|
||||||
KeyEvent {
|
KeyEvent {
|
||||||
code: KeyCode::Backspace,
|
code: KeyCode::Backspace,
|
||||||
..
|
..
|
||||||
|
|||||||
+13
-1
@@ -11,6 +11,8 @@ mod tests {
|
|||||||
#[case(Key::Down, "↓")]
|
#[case(Key::Down, "↓")]
|
||||||
#[case(Key::Left, "←")]
|
#[case(Key::Left, "←")]
|
||||||
#[case(Key::Right, "→")]
|
#[case(Key::Right, "→")]
|
||||||
|
#[case(Key::PgDown, "pgDown")]
|
||||||
|
#[case(Key::PgUp, "pgUp")]
|
||||||
#[case(Key::Enter, "enter")]
|
#[case(Key::Enter, "enter")]
|
||||||
#[case(Key::Esc, "esc")]
|
#[case(Key::Esc, "esc")]
|
||||||
#[case(Key::Backspace, "backspace")]
|
#[case(Key::Backspace, "backspace")]
|
||||||
@@ -22,7 +24,7 @@ mod tests {
|
|||||||
#[case(Key::Char('q'), "q")]
|
#[case(Key::Char('q'), "q")]
|
||||||
#[case(Key::Ctrl('q'), "ctrl-q")]
|
#[case(Key::Ctrl('q'), "ctrl-q")]
|
||||||
fn test_key_formatter(#[case] key: Key, #[case] expected_str: &str) {
|
fn test_key_formatter(#[case] key: Key, #[case] expected_str: &str) {
|
||||||
assert_str_eq!(format!("{key}"), format!("<{expected_str}>"));
|
assert_str_eq!(format!("{key}"), format!("{expected_str}"));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -45,6 +47,16 @@ mod tests {
|
|||||||
assert_eq!(Key::from(KeyEvent::from(KeyCode::Right)), Key::Right);
|
assert_eq!(Key::from(KeyEvent::from(KeyCode::Right)), Key::Right);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_key_from_page_down() {
|
||||||
|
assert_eq!(Key::from(KeyEvent::from(KeyCode::PageDown)), Key::PgDown);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_key_from_page_up() {
|
||||||
|
assert_eq!(Key::from(KeyEvent::from(KeyCode::PageUp)), Key::PgUp);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_key_from_backspace() {
|
fn test_key_from_backspace() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
|||||||
@@ -0,0 +1,221 @@
|
|||||||
|
#[cfg(test)]
|
||||||
|
mod property_tests {
|
||||||
|
use proptest::prelude::*;
|
||||||
|
|
||||||
|
use crate::app::App;
|
||||||
|
use crate::handlers::handler_test_utils::test_utils::proptest_helpers::*;
|
||||||
|
use crate::models::servarr_data::radarr::radarr_data::ActiveRadarrBlock;
|
||||||
|
use crate::models::stateful_table::StatefulTable;
|
||||||
|
use crate::models::radarr_models::Movie;
|
||||||
|
use crate::models::{Scrollable, Paginated};
|
||||||
|
|
||||||
|
proptest! {
|
||||||
|
/// Property test: Table never panics on index selection
|
||||||
|
#[test]
|
||||||
|
fn test_table_index_selection_safety(
|
||||||
|
list_size in list_size(),
|
||||||
|
index in 0usize..1000
|
||||||
|
) {
|
||||||
|
let mut table = StatefulTable::<Movie>::default();
|
||||||
|
let movies: Vec<Movie> = (0..list_size).map(|i| {
|
||||||
|
let mut movie = Movie::default();
|
||||||
|
movie.id = i as i64;
|
||||||
|
movie
|
||||||
|
}).collect();
|
||||||
|
|
||||||
|
table.set_items(movies);
|
||||||
|
|
||||||
|
// Try to select an arbitrary index
|
||||||
|
if index < list_size {
|
||||||
|
table.select_index(Some(index));
|
||||||
|
let selected = table.current_selection();
|
||||||
|
prop_assert_eq!(selected.id, index as i64);
|
||||||
|
} else {
|
||||||
|
// Out of bounds selection should be safe
|
||||||
|
table.select_index(Some(index));
|
||||||
|
// Should not panic, selection stays valid
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Property test: Table state remains consistent after scroll operations
|
||||||
|
#[test]
|
||||||
|
fn test_table_scroll_consistency(
|
||||||
|
list_size in list_size(),
|
||||||
|
scroll_amount in 0usize..20
|
||||||
|
) {
|
||||||
|
let mut table = StatefulTable::<Movie>::default();
|
||||||
|
let movies: Vec<Movie> = (0..list_size).map(|i| {
|
||||||
|
let mut movie = Movie::default();
|
||||||
|
movie.id = i as i64;
|
||||||
|
movie
|
||||||
|
}).collect();
|
||||||
|
|
||||||
|
table.set_items(movies);
|
||||||
|
let initial_id = table.current_selection().id;
|
||||||
|
|
||||||
|
// Scroll down multiple times
|
||||||
|
for _ in 0..scroll_amount {
|
||||||
|
table.scroll_down();
|
||||||
|
}
|
||||||
|
let after_down_id = table.current_selection().id;
|
||||||
|
|
||||||
|
// Position should increase (up to max)
|
||||||
|
prop_assert!(after_down_id >= initial_id);
|
||||||
|
prop_assert!(after_down_id < list_size as i64);
|
||||||
|
|
||||||
|
// Scroll back up
|
||||||
|
for _ in 0..scroll_amount {
|
||||||
|
table.scroll_up();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Should return to initial position (or 0 if we hit the top)
|
||||||
|
prop_assert!(table.current_selection().id <= initial_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Property test: Empty tables handle operations gracefully
|
||||||
|
#[test]
|
||||||
|
fn test_empty_table_safety(_scroll_ops in 0usize..50) {
|
||||||
|
let table = StatefulTable::<Movie>::default();
|
||||||
|
|
||||||
|
// Empty table operations should be safe
|
||||||
|
prop_assert!(table.is_empty());
|
||||||
|
prop_assert!(table.items.is_empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Property test: Navigation operations maintain consistency
|
||||||
|
#[test]
|
||||||
|
fn test_navigation_consistency(pushes in 1usize..20) {
|
||||||
|
let mut app = App::test_default();
|
||||||
|
let initial_route = app.get_current_route();
|
||||||
|
|
||||||
|
// Push multiple routes
|
||||||
|
let routes = vec![
|
||||||
|
ActiveRadarrBlock::Movies,
|
||||||
|
ActiveRadarrBlock::Collections,
|
||||||
|
ActiveRadarrBlock::Downloads,
|
||||||
|
ActiveRadarrBlock::Blocklist,
|
||||||
|
];
|
||||||
|
|
||||||
|
for i in 0..pushes {
|
||||||
|
let route = routes[i % routes.len()];
|
||||||
|
app.push_navigation_stack(route.into());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Current route should be the last pushed
|
||||||
|
let last_pushed = routes[(pushes - 1) % routes.len()];
|
||||||
|
prop_assert_eq!(app.get_current_route(), last_pushed.into());
|
||||||
|
|
||||||
|
// Pop all routes
|
||||||
|
for _ in 0..pushes {
|
||||||
|
app.pop_navigation_stack();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Should return to initial route
|
||||||
|
prop_assert_eq!(app.get_current_route(), initial_route);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Property test: String input handling is safe
|
||||||
|
#[test]
|
||||||
|
fn test_string_input_safety(input in text_input_string()) {
|
||||||
|
// String operations should never panic
|
||||||
|
let _lowercase = input.to_lowercase();
|
||||||
|
let _uppercase = input.to_uppercase();
|
||||||
|
let _trimmed = input.trim();
|
||||||
|
let _len = input.len();
|
||||||
|
let _chars: Vec<char> = input.chars().collect();
|
||||||
|
|
||||||
|
// All operations completed without panic
|
||||||
|
prop_assert!(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Property test: Table maintains data integrity after operations
|
||||||
|
#[test]
|
||||||
|
fn test_table_data_integrity(
|
||||||
|
list_size in 1usize..100
|
||||||
|
) {
|
||||||
|
let mut table = StatefulTable::<Movie>::default();
|
||||||
|
let movies: Vec<Movie> = (0..list_size).map(|i| {
|
||||||
|
let mut movie = Movie::default();
|
||||||
|
movie.id = i as i64;
|
||||||
|
movie.title = format!("Movie {}", i).into();
|
||||||
|
movie
|
||||||
|
}).collect();
|
||||||
|
|
||||||
|
table.set_items(movies.clone());
|
||||||
|
let original_count = table.items.len();
|
||||||
|
|
||||||
|
// Count should remain the same after various operations
|
||||||
|
prop_assert_eq!(table.items.len(), original_count);
|
||||||
|
|
||||||
|
// All original items should still be present
|
||||||
|
for movie in &movies {
|
||||||
|
prop_assert!(table.items.iter().any(|m| m.id == movie.id));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Property test: Page up/down maintains bounds
|
||||||
|
#[test]
|
||||||
|
fn test_page_navigation_bounds(
|
||||||
|
list_size in list_size(),
|
||||||
|
page_ops in 0usize..10
|
||||||
|
) {
|
||||||
|
let mut table = StatefulTable::<Movie>::default();
|
||||||
|
let movies: Vec<Movie> = (0..list_size).map(|i| {
|
||||||
|
let mut movie = Movie::default();
|
||||||
|
movie.id = i as i64;
|
||||||
|
movie
|
||||||
|
}).collect();
|
||||||
|
|
||||||
|
table.set_items(movies);
|
||||||
|
|
||||||
|
// Perform page operations
|
||||||
|
for i in 0..page_ops {
|
||||||
|
if i % 2 == 0 {
|
||||||
|
table.page_down();
|
||||||
|
} else {
|
||||||
|
table.page_up();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Should never exceed bounds
|
||||||
|
let current = table.current_selection();
|
||||||
|
prop_assert!(current.id >= 0);
|
||||||
|
prop_assert!(current.id < list_size as i64);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Property test: Table filtering reduces or maintains size
|
||||||
|
#[test]
|
||||||
|
fn test_table_filter_size_invariant(
|
||||||
|
list_size in list_size(),
|
||||||
|
filter_term in text_input_string()
|
||||||
|
) {
|
||||||
|
let mut table = StatefulTable::<Movie>::default();
|
||||||
|
let movies: Vec<Movie> = (0..list_size).map(|i| {
|
||||||
|
let mut movie = Movie::default();
|
||||||
|
movie.id = i as i64;
|
||||||
|
movie.title = format!("Test Movie {}", i % 10).into();
|
||||||
|
movie
|
||||||
|
}).collect();
|
||||||
|
|
||||||
|
table.set_items(movies.clone());
|
||||||
|
let original_size = table.items.len();
|
||||||
|
|
||||||
|
// Apply filter
|
||||||
|
if !filter_term.is_empty() {
|
||||||
|
let filtered: Vec<Movie> = movies.into_iter()
|
||||||
|
.filter(|m| m.title.text.to_lowercase().contains(&filter_term.to_lowercase()))
|
||||||
|
.collect();
|
||||||
|
table.set_items(filtered);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Filtered size should be <= original
|
||||||
|
prop_assert!(table.items.len() <= original_size);
|
||||||
|
|
||||||
|
// Selection should still be valid if table not empty
|
||||||
|
if !table.items.is_empty() {
|
||||||
|
let current = table.current_selection();
|
||||||
|
prop_assert!(current.id >= 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -102,7 +102,7 @@ mod test_utils {
|
|||||||
($func:ident, $handler:ident, $servarr_data:ident, $data_ref:ident, $block:expr, $context:expr) => {
|
($func:ident, $handler:ident, $servarr_data:ident, $data_ref:ident, $block:expr, $context:expr) => {
|
||||||
#[rstest]
|
#[rstest]
|
||||||
fn $func(#[values(DEFAULT_KEYBINDINGS.up.key, DEFAULT_KEYBINDINGS.down.key)] key: Key) {
|
fn $func(#[values(DEFAULT_KEYBINDINGS.up.key, DEFAULT_KEYBINDINGS.down.key)] key: Key) {
|
||||||
let mut app = App::default();
|
let mut app = App::test_default();
|
||||||
app.push_navigation_stack($block.into());
|
app.push_navigation_stack($block.into());
|
||||||
app
|
app
|
||||||
.data
|
.data
|
||||||
@@ -110,14 +110,14 @@ mod test_utils {
|
|||||||
.$data_ref
|
.$data_ref
|
||||||
.set_items(vec!["Test 1".to_owned(), "Test 2".to_owned()]);
|
.set_items(vec!["Test 1".to_owned(), "Test 2".to_owned()]);
|
||||||
|
|
||||||
$handler::with(&key, &mut app, &$block, &$context).handle();
|
$handler::new(&key, &mut app, &$block, &$context).handle();
|
||||||
|
|
||||||
pretty_assertions::assert_str_eq!(
|
pretty_assertions::assert_str_eq!(
|
||||||
app.data.$servarr_data.$data_ref.current_selection(),
|
app.data.$servarr_data.$data_ref.current_selection(),
|
||||||
"Test 2"
|
"Test 2"
|
||||||
);
|
);
|
||||||
|
|
||||||
$handler::with(&key, &mut app, &$block, &$context).handle();
|
$handler::new(&key, &mut app, &$block, &$context).handle();
|
||||||
|
|
||||||
pretty_assertions::assert_str_eq!(
|
pretty_assertions::assert_str_eq!(
|
||||||
app.data.$servarr_data.$data_ref.current_selection(),
|
app.data.$servarr_data.$data_ref.current_selection(),
|
||||||
@@ -129,7 +129,7 @@ mod test_utils {
|
|||||||
($func:ident, $handler:ident, $servarr_data:ident, $data_ref:ident, $items:ident, $block:expr, $context:expr, $field:ident) => {
|
($func:ident, $handler:ident, $servarr_data:ident, $data_ref:ident, $items:ident, $block:expr, $context:expr, $field:ident) => {
|
||||||
#[rstest]
|
#[rstest]
|
||||||
fn $func(#[values(DEFAULT_KEYBINDINGS.up.key, DEFAULT_KEYBINDINGS.down.key)] key: Key) {
|
fn $func(#[values(DEFAULT_KEYBINDINGS.up.key, DEFAULT_KEYBINDINGS.down.key)] key: Key) {
|
||||||
let mut app = App::default();
|
let mut app = App::test_default();
|
||||||
app.push_navigation_stack($block.into());
|
app.push_navigation_stack($block.into());
|
||||||
app
|
app
|
||||||
.data
|
.data
|
||||||
@@ -137,14 +137,14 @@ mod test_utils {
|
|||||||
.$data_ref
|
.$data_ref
|
||||||
.set_items(simple_stateful_iterable_vec!($items));
|
.set_items(simple_stateful_iterable_vec!($items));
|
||||||
|
|
||||||
$handler::with(key, &mut app, $block, $context).handle();
|
$handler::new(key, &mut app, $block, $context).handle();
|
||||||
|
|
||||||
pretty_assertions::assert_str_eq!(
|
pretty_assertions::assert_str_eq!(
|
||||||
app.data.$servarr_data.$data_ref.current_selection().$field,
|
app.data.$servarr_data.$data_ref.current_selection().$field,
|
||||||
"Test 2"
|
"Test 2"
|
||||||
);
|
);
|
||||||
|
|
||||||
$handler::with(key, &mut app, $block, $context).handle();
|
$handler::new(key, &mut app, $block, $context).handle();
|
||||||
|
|
||||||
pretty_assertions::assert_str_eq!(
|
pretty_assertions::assert_str_eq!(
|
||||||
app.data.$servarr_data.$data_ref.current_selection().$field,
|
app.data.$servarr_data.$data_ref.current_selection().$field,
|
||||||
@@ -156,18 +156,18 @@ mod test_utils {
|
|||||||
($func:ident, $handler:ident, $servarr_data:ident, $data_ref:ident, $items:expr, $block:expr, $context:expr, $field:ident) => {
|
($func:ident, $handler:ident, $servarr_data:ident, $data_ref:ident, $items:expr, $block:expr, $context:expr, $field:ident) => {
|
||||||
#[rstest]
|
#[rstest]
|
||||||
fn $func(#[values(DEFAULT_KEYBINDINGS.up.key, DEFAULT_KEYBINDINGS.down.key)] key: Key) {
|
fn $func(#[values(DEFAULT_KEYBINDINGS.up.key, DEFAULT_KEYBINDINGS.down.key)] key: Key) {
|
||||||
let mut app = App::default();
|
let mut app = App::test_default();
|
||||||
app.push_navigation_stack($block.into());
|
app.push_navigation_stack($block.into());
|
||||||
app.data.$servarr_data.$data_ref.set_items($items);
|
app.data.$servarr_data.$data_ref.set_items($items);
|
||||||
|
|
||||||
$handler::with(key, &mut app, $block, $context).handle();
|
$handler::new(key, &mut app, $block, $context).handle();
|
||||||
|
|
||||||
pretty_assertions::assert_str_eq!(
|
pretty_assertions::assert_str_eq!(
|
||||||
app.data.$servarr_data.$data_ref.current_selection().$field,
|
app.data.$servarr_data.$data_ref.current_selection().$field,
|
||||||
"Test 2"
|
"Test 2"
|
||||||
);
|
);
|
||||||
|
|
||||||
$handler::with(key, &mut app, $block, $context).handle();
|
$handler::new(key, &mut app, $block, $context).handle();
|
||||||
|
|
||||||
pretty_assertions::assert_str_eq!(
|
pretty_assertions::assert_str_eq!(
|
||||||
app.data.$servarr_data.$data_ref.current_selection().$field,
|
app.data.$servarr_data.$data_ref.current_selection().$field,
|
||||||
@@ -179,11 +179,11 @@ mod test_utils {
|
|||||||
($func:ident, $handler:ident, $servarr_data:ident, $data_ref:ident, $items:expr, $block:expr, $context:expr, $field:ident, $conversion_fn:ident) => {
|
($func:ident, $handler:ident, $servarr_data:ident, $data_ref:ident, $items:expr, $block:expr, $context:expr, $field:ident, $conversion_fn:ident) => {
|
||||||
#[rstest]
|
#[rstest]
|
||||||
fn $func(#[values(DEFAULT_KEYBINDINGS.up.key, DEFAULT_KEYBINDINGS.down.key)] key: Key) {
|
fn $func(#[values(DEFAULT_KEYBINDINGS.up.key, DEFAULT_KEYBINDINGS.down.key)] key: Key) {
|
||||||
let mut app = App::default();
|
let mut app = App::test_default();
|
||||||
app.push_navigation_stack($block.into());
|
app.push_navigation_stack($block.into());
|
||||||
app.data.$servarr_data.$data_ref.set_items($items);
|
app.data.$servarr_data.$data_ref.set_items($items);
|
||||||
|
|
||||||
$handler::with(key, &mut app, $block, $context).handle();
|
$handler::new(key, &mut app, $block, $context).handle();
|
||||||
|
|
||||||
pretty_assertions::assert_str_eq!(
|
pretty_assertions::assert_str_eq!(
|
||||||
app
|
app
|
||||||
@@ -196,7 +196,7 @@ mod test_utils {
|
|||||||
"Test 2"
|
"Test 2"
|
||||||
);
|
);
|
||||||
|
|
||||||
$handler::with(key, &mut app, $block, $context).handle();
|
$handler::new(key, &mut app, $block, $context).handle();
|
||||||
|
|
||||||
pretty_assertions::assert_str_eq!(
|
pretty_assertions::assert_str_eq!(
|
||||||
app
|
app
|
||||||
@@ -217,7 +217,7 @@ mod test_utils {
|
|||||||
($func:ident, $handler:ident, $servarr_data:ident, $data_ref:ident, $block:expr, $context:expr) => {
|
($func:ident, $handler:ident, $servarr_data:ident, $data_ref:ident, $block:expr, $context:expr) => {
|
||||||
#[test]
|
#[test]
|
||||||
fn $func() {
|
fn $func() {
|
||||||
let mut app = App::default();
|
let mut app = App::test_default();
|
||||||
app.push_navigation_stack($block.into());
|
app.push_navigation_stack($block.into());
|
||||||
app.data.$servarr_data.$data_ref.set_items(vec![
|
app.data.$servarr_data.$data_ref.set_items(vec![
|
||||||
"Test 1".to_owned(),
|
"Test 1".to_owned(),
|
||||||
@@ -225,14 +225,14 @@ mod test_utils {
|
|||||||
"Test 3".to_owned(),
|
"Test 3".to_owned(),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$handler::with(DEFAULT_KEYBINDINGS.end.key, &mut app, $block, $context).handle();
|
$handler::new(DEFAULT_KEYBINDINGS.end.key, &mut app, $block, $context).handle();
|
||||||
|
|
||||||
pretty_assertions::assert_str_eq!(
|
pretty_assertions::assert_str_eq!(
|
||||||
app.data.$servarr_data.$data_ref.current_selection(),
|
app.data.$servarr_data.$data_ref.current_selection(),
|
||||||
"Test 3"
|
"Test 3"
|
||||||
);
|
);
|
||||||
|
|
||||||
$handler::with(DEFAULT_KEYBINDINGS.home.key, &mut app, $block, $context).handle();
|
$handler::new(DEFAULT_KEYBINDINGS.home.key, &mut app, $block, $context).handle();
|
||||||
|
|
||||||
pretty_assertions::assert_str_eq!(
|
pretty_assertions::assert_str_eq!(
|
||||||
app.data.$servarr_data.$data_ref.current_selection(),
|
app.data.$servarr_data.$data_ref.current_selection(),
|
||||||
@@ -244,7 +244,7 @@ mod test_utils {
|
|||||||
($func:ident, $handler:ident, $servarr_data:ident, $data_ref:ident, $items:ident, $block:expr, $context:expr, $field:ident) => {
|
($func:ident, $handler:ident, $servarr_data:ident, $data_ref:ident, $items:ident, $block:expr, $context:expr, $field:ident) => {
|
||||||
#[test]
|
#[test]
|
||||||
fn $func() {
|
fn $func() {
|
||||||
let mut app = App::default();
|
let mut app = App::test_default();
|
||||||
app.push_navigation_stack($block.into());
|
app.push_navigation_stack($block.into());
|
||||||
app
|
app
|
||||||
.data
|
.data
|
||||||
@@ -252,14 +252,14 @@ mod test_utils {
|
|||||||
.$data_ref
|
.$data_ref
|
||||||
.set_items(extended_stateful_iterable_vec!($items));
|
.set_items(extended_stateful_iterable_vec!($items));
|
||||||
|
|
||||||
$handler::with(DEFAULT_KEYBINDINGS.end.key, &mut app, $block, $context).handle();
|
$handler::new(DEFAULT_KEYBINDINGS.end.key, &mut app, $block, $context).handle();
|
||||||
|
|
||||||
pretty_assertions::assert_str_eq!(
|
pretty_assertions::assert_str_eq!(
|
||||||
app.data.$servarr_data.$data_ref.current_selection().$field,
|
app.data.$servarr_data.$data_ref.current_selection().$field,
|
||||||
"Test 3"
|
"Test 3"
|
||||||
);
|
);
|
||||||
|
|
||||||
$handler::with(DEFAULT_KEYBINDINGS.home.key, &mut app, $block, $context).handle();
|
$handler::new(DEFAULT_KEYBINDINGS.home.key, &mut app, $block, $context).handle();
|
||||||
|
|
||||||
pretty_assertions::assert_str_eq!(
|
pretty_assertions::assert_str_eq!(
|
||||||
app.data.$servarr_data.$data_ref.current_selection().$field,
|
app.data.$servarr_data.$data_ref.current_selection().$field,
|
||||||
@@ -271,18 +271,18 @@ mod test_utils {
|
|||||||
($func:ident, $handler:ident, $servarr_data:ident, $data_ref:ident, $items:expr, $block:expr, $context:expr, $field:ident) => {
|
($func:ident, $handler:ident, $servarr_data:ident, $data_ref:ident, $items:expr, $block:expr, $context:expr, $field:ident) => {
|
||||||
#[test]
|
#[test]
|
||||||
fn $func() {
|
fn $func() {
|
||||||
let mut app = App::default();
|
let mut app = App::test_default();
|
||||||
app.push_navigation_stack($block.into());
|
app.push_navigation_stack($block.into());
|
||||||
app.data.$servarr_data.$data_ref.set_items($items);
|
app.data.$servarr_data.$data_ref.set_items($items);
|
||||||
|
|
||||||
$handler::with(DEFAULT_KEYBINDINGS.end.key, &mut app, $block, $context).handle();
|
$handler::new(DEFAULT_KEYBINDINGS.end.key, &mut app, $block, $context).handle();
|
||||||
|
|
||||||
pretty_assertions::assert_str_eq!(
|
pretty_assertions::assert_str_eq!(
|
||||||
app.data.$servarr_data.$data_ref.current_selection().$field,
|
app.data.$servarr_data.$data_ref.current_selection().$field,
|
||||||
"Test 3"
|
"Test 3"
|
||||||
);
|
);
|
||||||
|
|
||||||
$handler::with(DEFAULT_KEYBINDINGS.home.key, &mut app, $block, $context).handle();
|
$handler::new(DEFAULT_KEYBINDINGS.home.key, &mut app, $block, $context).handle();
|
||||||
|
|
||||||
pretty_assertions::assert_str_eq!(
|
pretty_assertions::assert_str_eq!(
|
||||||
app.data.$servarr_data.$data_ref.current_selection().$field,
|
app.data.$servarr_data.$data_ref.current_selection().$field,
|
||||||
@@ -294,11 +294,11 @@ mod test_utils {
|
|||||||
($func:ident, $handler:ident, $servarr_data:ident, $data_ref:ident, $items:expr, $block:expr, $context:expr, $field:ident, $conversion_fn:ident) => {
|
($func:ident, $handler:ident, $servarr_data:ident, $data_ref:ident, $items:expr, $block:expr, $context:expr, $field:ident, $conversion_fn:ident) => {
|
||||||
#[test]
|
#[test]
|
||||||
fn $func() {
|
fn $func() {
|
||||||
let mut app = App::default();
|
let mut app = App::test_default();
|
||||||
app.push_navigation_stack($block.into());
|
app.push_navigation_stack($block.into());
|
||||||
app.data.$servarr_data.$data_ref.set_items($items);
|
app.data.$servarr_data.$data_ref.set_items($items);
|
||||||
|
|
||||||
$handler::with(DEFAULT_KEYBINDINGS.end.key, &mut app, $block, $context).handle();
|
$handler::new(DEFAULT_KEYBINDINGS.end.key, &mut app, $block, $context).handle();
|
||||||
|
|
||||||
pretty_assertions::assert_str_eq!(
|
pretty_assertions::assert_str_eq!(
|
||||||
app
|
app
|
||||||
@@ -311,7 +311,7 @@ mod test_utils {
|
|||||||
"Test 3"
|
"Test 3"
|
||||||
);
|
);
|
||||||
|
|
||||||
$handler::with(DEFAULT_KEYBINDINGS.home.key, &mut app, $block, $context).handle();
|
$handler::new(DEFAULT_KEYBINDINGS.home.key, &mut app, $block, $context).handle();
|
||||||
|
|
||||||
pretty_assertions::assert_str_eq!(
|
pretty_assertions::assert_str_eq!(
|
||||||
app
|
app
|
||||||
@@ -330,7 +330,7 @@ mod test_utils {
|
|||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! test_handler_delegation {
|
macro_rules! test_handler_delegation {
|
||||||
($handler:ident, $base:expr, $active_block:expr) => {
|
($handler:ident, $base:expr, $active_block:expr) => {
|
||||||
let mut app = App::default();
|
let mut app = App::test_default();
|
||||||
app.data.sonarr_data.history.set_items(vec![
|
app.data.sonarr_data.history.set_items(vec![
|
||||||
$crate::models::sonarr_models::SonarrHistoryItem::default(),
|
$crate::models::sonarr_models::SonarrHistoryItem::default(),
|
||||||
]);
|
]);
|
||||||
@@ -417,7 +417,7 @@ mod test_utils {
|
|||||||
app.push_navigation_stack($base.into());
|
app.push_navigation_stack($base.into());
|
||||||
app.push_navigation_stack($active_block.into());
|
app.push_navigation_stack($active_block.into());
|
||||||
|
|
||||||
$handler::with(DEFAULT_KEYBINDINGS.esc.key, &mut app, $active_block, None).handle();
|
$handler::new(DEFAULT_KEYBINDINGS.esc.key, &mut app, $active_block, None).handle();
|
||||||
|
|
||||||
pretty_assertions::assert_eq!(app.get_current_route(), $base.into());
|
pretty_assertions::assert_eq!(app.get_current_route(), $base.into());
|
||||||
};
|
};
|
||||||
@@ -426,15 +426,15 @@ mod test_utils {
|
|||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! assert_delete_prompt {
|
macro_rules! assert_delete_prompt {
|
||||||
($handler:ident, $block:expr, $expected_block:expr) => {
|
($handler:ident, $block:expr, $expected_block:expr) => {
|
||||||
let mut app = App::default();
|
let mut app = App::test_default();
|
||||||
|
|
||||||
$handler::with(DELETE_KEY, &mut app, $block, None).handle();
|
$handler::new(DELETE_KEY, &mut app, $block, None).handle();
|
||||||
|
|
||||||
pretty_assertions::assert_eq!(app.get_current_route(), $expected_block.into());
|
pretty_assertions::assert_eq!(app.get_current_route(), $expected_block.into());
|
||||||
};
|
};
|
||||||
|
|
||||||
($handler:ident, $app:expr, $block:expr, $expected_block:expr) => {
|
($handler:ident, $app:expr, $block:expr, $expected_block:expr) => {
|
||||||
$handler::with(DELETE_KEY, &mut $app, $block, None).handle();
|
$handler::new(DELETE_KEY, &mut $app, $block, None).handle();
|
||||||
|
|
||||||
pretty_assertions::assert_eq!($app.get_current_route(), $expected_block.into());
|
pretty_assertions::assert_eq!($app.get_current_route(), $expected_block.into());
|
||||||
};
|
};
|
||||||
@@ -443,13 +443,49 @@ mod test_utils {
|
|||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! assert_refresh_key {
|
macro_rules! assert_refresh_key {
|
||||||
($handler:ident, $block:expr) => {
|
($handler:ident, $block:expr) => {
|
||||||
let mut app = App::default();
|
let mut app = App::test_default();
|
||||||
app.push_navigation_stack($block.into());
|
app.push_navigation_stack($block.into());
|
||||||
|
|
||||||
$handler::with(DEFAULT_KEYBINDINGS.refresh.key, &mut app, $block, None).handle();
|
$handler::new(DEFAULT_KEYBINDINGS.refresh.key, &mut app, $block, None).handle();
|
||||||
|
|
||||||
pretty_assertions::assert_eq!(app.get_current_route(), $block.into());
|
pretty_assertions::assert_eq!(app.get_current_route(), $block.into());
|
||||||
assert!(app.should_refresh);
|
assert!(app.should_refresh);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! assert_modal_present {
|
||||||
|
($modal:expr) => {
|
||||||
|
assert!($modal.is_some(), "Expected modal to be present");
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! assert_modal_absent {
|
||||||
|
($modal:expr) => {
|
||||||
|
assert!($modal.is_none(), "Expected modal to be absent");
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! assert_navigation_pushed {
|
||||||
|
($app:expr, $expected_route:expr) => {
|
||||||
|
pretty_assertions::assert_eq!(
|
||||||
|
$app.get_current_route(),
|
||||||
|
$expected_route,
|
||||||
|
"Expected route to be pushed onto navigation stack"
|
||||||
|
);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! assert_navigation_popped {
|
||||||
|
($app:expr, $expected_route:expr) => {
|
||||||
|
pretty_assertions::assert_eq!(
|
||||||
|
$app.get_current_route(),
|
||||||
|
$expected_route,
|
||||||
|
"Expected route after popping navigation stack"
|
||||||
|
);
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+190
-13
@@ -1,36 +1,46 @@
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
use crate::assert_modal_absent;
|
||||||
|
use crate::assert_navigation_pushed;
|
||||||
use crate::models::radarr_models::Movie;
|
use crate::models::radarr_models::Movie;
|
||||||
use crate::models::sonarr_models::Series;
|
use crate::models::sonarr_models::Series;
|
||||||
|
use crate::{assert_modal_present, assert_navigation_popped};
|
||||||
use pretty_assertions::assert_eq;
|
use pretty_assertions::assert_eq;
|
||||||
use rstest::rstest;
|
use rstest::rstest;
|
||||||
use tokio_util::sync::CancellationToken;
|
use tokio_util::sync::CancellationToken;
|
||||||
|
|
||||||
use crate::app::key_binding::DEFAULT_KEYBINDINGS;
|
|
||||||
use crate::app::App;
|
use crate::app::App;
|
||||||
|
use crate::app::context_clues::SERVARR_CONTEXT_CLUES;
|
||||||
|
use crate::app::key_binding::{DEFAULT_KEYBINDINGS, KeyBinding};
|
||||||
|
use crate::app::radarr::radarr_context_clues::{
|
||||||
|
LIBRARY_CONTEXT_CLUES, MOVIE_DETAILS_CONTEXT_CLUES,
|
||||||
|
};
|
||||||
use crate::event::Key;
|
use crate::event::Key;
|
||||||
use crate::handlers::handle_events;
|
|
||||||
use crate::handlers::{handle_clear_errors, handle_prompt_toggle};
|
use crate::handlers::{handle_clear_errors, handle_prompt_toggle};
|
||||||
use crate::models::servarr_data::radarr::radarr_data::ActiveRadarrBlock;
|
use crate::handlers::{handle_events, populate_keymapping_table};
|
||||||
use crate::models::servarr_data::sonarr::sonarr_data::ActiveSonarrBlock;
|
|
||||||
use crate::models::HorizontallyScrollableText;
|
use crate::models::HorizontallyScrollableText;
|
||||||
use crate::models::Route;
|
use crate::models::Route;
|
||||||
|
use crate::models::servarr_data::ActiveKeybindingBlock;
|
||||||
|
use crate::models::servarr_data::radarr::radarr_data::{ActiveRadarrBlock, RadarrData};
|
||||||
|
use crate::models::servarr_data::sonarr::sonarr_data::ActiveSonarrBlock;
|
||||||
|
use crate::models::servarr_models::KeybindingItem;
|
||||||
|
use crate::models::stateful_table::StatefulTable;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_handle_clear_errors() {
|
fn test_handle_clear_errors() {
|
||||||
let mut app = App::default();
|
let mut app = App::test_default();
|
||||||
app.error = "test error".to_owned().into();
|
app.error = "test error".to_owned().into();
|
||||||
|
|
||||||
handle_clear_errors(&mut app);
|
handle_clear_errors(&mut app);
|
||||||
|
|
||||||
assert!(app.error.text.is_empty());
|
assert_is_empty!(app.error.text);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rstest]
|
#[rstest]
|
||||||
#[case(ActiveRadarrBlock::Movies.into(), ActiveRadarrBlock::SearchMovie.into())]
|
#[case(ActiveRadarrBlock::Movies.into(), ActiveRadarrBlock::SearchMovie.into())]
|
||||||
#[case(ActiveSonarrBlock::Series.into(), ActiveSonarrBlock::SearchSeries.into())]
|
#[case(ActiveSonarrBlock::Series.into(), ActiveSonarrBlock::SearchSeries.into())]
|
||||||
fn test_handle_events(#[case] base_block: Route, #[case] top_block: Route) {
|
fn test_handle_events(#[case] base_block: Route, #[case] top_block: Route) {
|
||||||
let mut app = App::default();
|
let mut app = App::test_default();
|
||||||
app.push_navigation_stack(base_block);
|
app.push_navigation_stack(base_block);
|
||||||
app.push_navigation_stack(top_block);
|
app.push_navigation_stack(top_block);
|
||||||
app
|
app
|
||||||
@@ -46,7 +56,7 @@ mod tests {
|
|||||||
|
|
||||||
handle_events(DEFAULT_KEYBINDINGS.esc.key, &mut app);
|
handle_events(DEFAULT_KEYBINDINGS.esc.key, &mut app);
|
||||||
|
|
||||||
assert_eq!(app.get_current_route(), base_block);
|
assert_navigation_popped!(app, base_block);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rstest]
|
#[rstest]
|
||||||
@@ -56,14 +66,14 @@ mod tests {
|
|||||||
where
|
where
|
||||||
T: Into<Route> + Copy,
|
T: Into<Route> + Copy,
|
||||||
{
|
{
|
||||||
let mut app = App::default();
|
let mut app = App::test_default();
|
||||||
app.error = "Test".into();
|
app.error = "Test".into();
|
||||||
app.server_tabs.set_index(index);
|
app.server_tabs.set_index(index);
|
||||||
|
|
||||||
handle_events(DEFAULT_KEYBINDINGS.previous_servarr.key, &mut app);
|
handle_events(DEFAULT_KEYBINDINGS.previous_servarr.key, &mut app);
|
||||||
|
|
||||||
assert_eq!(app.server_tabs.get_active_route(), left_block.into());
|
assert_eq!(app.server_tabs.get_active_route(), left_block.into());
|
||||||
assert_eq!(app.get_current_route(), left_block.into());
|
assert_navigation_pushed!(app, left_block.into());
|
||||||
assert!(app.is_first_render);
|
assert!(app.is_first_render);
|
||||||
assert_eq!(app.error, HorizontallyScrollableText::default());
|
assert_eq!(app.error, HorizontallyScrollableText::default());
|
||||||
assert!(app.cancellation_token.is_cancelled());
|
assert!(app.cancellation_token.is_cancelled());
|
||||||
@@ -76,15 +86,91 @@ mod tests {
|
|||||||
handle_events(DEFAULT_KEYBINDINGS.next_servarr.key, &mut app);
|
handle_events(DEFAULT_KEYBINDINGS.next_servarr.key, &mut app);
|
||||||
|
|
||||||
assert_eq!(app.server_tabs.get_active_route(), right_block.into());
|
assert_eq!(app.server_tabs.get_active_route(), right_block.into());
|
||||||
assert_eq!(app.get_current_route(), right_block.into());
|
assert_navigation_pushed!(app, right_block.into());
|
||||||
assert!(app.is_first_render);
|
assert!(app.is_first_render);
|
||||||
assert_eq!(app.error, HorizontallyScrollableText::default());
|
assert_eq!(app.error, HorizontallyScrollableText::default());
|
||||||
assert!(app.cancellation_token.is_cancelled());
|
assert!(app.cancellation_token.is_cancelled());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_handle_populate_keybindings_table_on_help_button_press() {
|
||||||
|
let mut app = App::test_default();
|
||||||
|
let expected_keybinding_items = Vec::from(SERVARR_CONTEXT_CLUES)
|
||||||
|
.iter()
|
||||||
|
.map(|(key, desc)| context_clue_to_keybinding_item(key, desc))
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
app.push_navigation_stack(ActiveKeybindingBlock::Help.into());
|
||||||
|
|
||||||
|
handle_events(DEFAULT_KEYBINDINGS.help.key, &mut app);
|
||||||
|
|
||||||
|
assert_modal_present!(app.keymapping_table);
|
||||||
|
assert_eq!(
|
||||||
|
expected_keybinding_items,
|
||||||
|
app.keymapping_table.unwrap().items
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_handle_ignore_help_button_when_ignore_special_keys_for_textbox_input_is_true() {
|
||||||
|
let mut app = App::test_default();
|
||||||
|
app.ignore_special_keys_for_textbox_input = true;
|
||||||
|
app.push_navigation_stack(ActiveRadarrBlock::default().into());
|
||||||
|
|
||||||
|
handle_events(DEFAULT_KEYBINDINGS.help.key, &mut app);
|
||||||
|
|
||||||
|
assert_modal_absent!(app.keymapping_table);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_handle_empties_keybindings_table_on_help_button_press_when_keybindings_table_is_already_populated()
|
||||||
|
{
|
||||||
|
let mut app = App::test_default();
|
||||||
|
let keybinding_items = Vec::from(SERVARR_CONTEXT_CLUES)
|
||||||
|
.iter()
|
||||||
|
.map(|(key, desc)| context_clue_to_keybinding_item(key, desc))
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
let mut stateful_table = StatefulTable::default();
|
||||||
|
stateful_table.set_items(keybinding_items);
|
||||||
|
app.keymapping_table = Some(stateful_table);
|
||||||
|
app.push_navigation_stack(ActiveRadarrBlock::default().into());
|
||||||
|
|
||||||
|
handle_events(DEFAULT_KEYBINDINGS.help.key, &mut app);
|
||||||
|
|
||||||
|
assert_modal_absent!(app.keymapping_table);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_handle_shows_keymapping_popup_when_keymapping_table_is_populated() {
|
||||||
|
let mut app = App::test_default();
|
||||||
|
let keybinding_items = Vec::from(SERVARR_CONTEXT_CLUES)
|
||||||
|
.iter()
|
||||||
|
.map(|(key, desc)| context_clue_to_keybinding_item(key, desc))
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
let mut stateful_table = StatefulTable::default();
|
||||||
|
stateful_table.set_items(keybinding_items);
|
||||||
|
app.keymapping_table = Some(stateful_table);
|
||||||
|
app.push_navigation_stack(ActiveRadarrBlock::default().into());
|
||||||
|
let expected_selection = KeybindingItem {
|
||||||
|
key: SERVARR_CONTEXT_CLUES[1].0.key.to_string(),
|
||||||
|
alt_key: SERVARR_CONTEXT_CLUES[1]
|
||||||
|
.0
|
||||||
|
.alt
|
||||||
|
.map_or(String::new(), |k| k.to_string()),
|
||||||
|
desc: SERVARR_CONTEXT_CLUES[1].1.to_string(),
|
||||||
|
};
|
||||||
|
|
||||||
|
handle_events(DEFAULT_KEYBINDINGS.down.key, &mut app);
|
||||||
|
|
||||||
|
assert_modal_present!(app.keymapping_table);
|
||||||
|
assert_eq!(
|
||||||
|
&expected_selection,
|
||||||
|
app.keymapping_table.unwrap().current_selection()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[rstest]
|
#[rstest]
|
||||||
fn test_handle_prompt_toggle_left_right_radarr(#[values(Key::Left, Key::Right)] key: Key) {
|
fn test_handle_prompt_toggle_left_right_radarr(#[values(Key::Left, Key::Right)] key: Key) {
|
||||||
let mut app = App::default();
|
let mut app = App::test_default();
|
||||||
app.push_navigation_stack(ActiveRadarrBlock::Movies.into());
|
app.push_navigation_stack(ActiveRadarrBlock::Movies.into());
|
||||||
|
|
||||||
assert!(!app.data.radarr_data.prompt_confirm);
|
assert!(!app.data.radarr_data.prompt_confirm);
|
||||||
@@ -100,7 +186,7 @@ mod tests {
|
|||||||
|
|
||||||
#[rstest]
|
#[rstest]
|
||||||
fn test_handle_prompt_toggle_left_right_sonarr(#[values(Key::Left, Key::Right)] key: Key) {
|
fn test_handle_prompt_toggle_left_right_sonarr(#[values(Key::Left, Key::Right)] key: Key) {
|
||||||
let mut app = App::default();
|
let mut app = App::test_default();
|
||||||
app.push_navigation_stack(ActiveSonarrBlock::Series.into());
|
app.push_navigation_stack(ActiveSonarrBlock::Series.into());
|
||||||
|
|
||||||
assert!(!app.data.sonarr_data.prompt_confirm);
|
assert!(!app.data.sonarr_data.prompt_confirm);
|
||||||
@@ -113,4 +199,95 @@ mod tests {
|
|||||||
|
|
||||||
assert!(!app.data.sonarr_data.prompt_confirm);
|
assert!(!app.data.sonarr_data.prompt_confirm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_populate_keymapping_table_global_options() {
|
||||||
|
let expected_keybinding_items = Vec::from(SERVARR_CONTEXT_CLUES)
|
||||||
|
.iter()
|
||||||
|
.map(|(key, desc)| {
|
||||||
|
let (key, alt_key) = if key.alt.is_some() {
|
||||||
|
(key.key.to_string(), key.alt.as_ref().unwrap().to_string())
|
||||||
|
} else {
|
||||||
|
(key.key.to_string(), String::new())
|
||||||
|
};
|
||||||
|
KeybindingItem {
|
||||||
|
key,
|
||||||
|
alt_key,
|
||||||
|
desc: desc.to_string(),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
let mut app = App::test_default();
|
||||||
|
app.push_navigation_stack(ActiveKeybindingBlock::Help.into());
|
||||||
|
|
||||||
|
populate_keymapping_table(&mut app);
|
||||||
|
|
||||||
|
assert_modal_present!(app.keymapping_table);
|
||||||
|
assert_eq!(
|
||||||
|
expected_keybinding_items,
|
||||||
|
app.keymapping_table.unwrap().items
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_populate_keymapping_table_populates_servarr_specific_tab_info_before_global_options() {
|
||||||
|
let mut expected_keybinding_items = LIBRARY_CONTEXT_CLUES
|
||||||
|
.iter()
|
||||||
|
.map(|(key, desc)| context_clue_to_keybinding_item(key, desc))
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
expected_keybinding_items.extend(
|
||||||
|
SERVARR_CONTEXT_CLUES
|
||||||
|
.iter()
|
||||||
|
.map(|(key, desc)| context_clue_to_keybinding_item(key, desc)),
|
||||||
|
);
|
||||||
|
let mut app = App::test_default();
|
||||||
|
app.data.radarr_data = RadarrData::default();
|
||||||
|
app.push_navigation_stack(ActiveRadarrBlock::default().into());
|
||||||
|
|
||||||
|
populate_keymapping_table(&mut app);
|
||||||
|
|
||||||
|
assert_modal_present!(app.keymapping_table);
|
||||||
|
assert_eq!(
|
||||||
|
expected_keybinding_items,
|
||||||
|
app.keymapping_table.unwrap().items
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_populate_keymapping_table_populates_delegated_servarr_context_provider_options_before_global_options()
|
||||||
|
{
|
||||||
|
let mut expected_keybinding_items = MOVIE_DETAILS_CONTEXT_CLUES
|
||||||
|
.iter()
|
||||||
|
.map(|(key, desc)| context_clue_to_keybinding_item(key, desc))
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
expected_keybinding_items.extend(
|
||||||
|
SERVARR_CONTEXT_CLUES
|
||||||
|
.iter()
|
||||||
|
.map(|(key, desc)| context_clue_to_keybinding_item(key, desc)),
|
||||||
|
);
|
||||||
|
let mut app = App::test_default();
|
||||||
|
app.data.radarr_data = RadarrData::default();
|
||||||
|
app.push_navigation_stack(ActiveRadarrBlock::MovieDetails.into());
|
||||||
|
|
||||||
|
populate_keymapping_table(&mut app);
|
||||||
|
|
||||||
|
assert_modal_present!(app.keymapping_table);
|
||||||
|
assert_eq!(
|
||||||
|
expected_keybinding_items,
|
||||||
|
app.keymapping_table.unwrap().items
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn context_clue_to_keybinding_item(key: &KeyBinding, desc: &&str) -> KeybindingItem {
|
||||||
|
let (key, alt_key) = if key.alt.is_some() {
|
||||||
|
(key.key.to_string(), key.alt.as_ref().unwrap().to_string())
|
||||||
|
} else {
|
||||||
|
(key.key.to_string(), String::new())
|
||||||
|
};
|
||||||
|
KeybindingItem {
|
||||||
|
key,
|
||||||
|
alt_key,
|
||||||
|
desc: desc.to_string(),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,81 @@
|
|||||||
|
use crate::app::App;
|
||||||
|
use crate::event::Key;
|
||||||
|
use crate::handlers::KeyEventHandler;
|
||||||
|
use crate::handlers::table_handler::{TableHandlingConfig, handle_table};
|
||||||
|
use crate::models::servarr_data::ActiveKeybindingBlock;
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
#[path = "keybinding_handler_tests.rs"]
|
||||||
|
mod keybinding_handler_tests;
|
||||||
|
|
||||||
|
pub(super) struct KeybindingHandler<'a, 'b> {
|
||||||
|
key: Key,
|
||||||
|
app: &'a mut App<'b>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveKeybindingBlock> for KeybindingHandler<'a, 'b> {
|
||||||
|
fn handle(&mut self) {
|
||||||
|
let keybinding_table_handling_config = TableHandlingConfig::new(self.app.get_current_route());
|
||||||
|
|
||||||
|
if !handle_table(
|
||||||
|
self,
|
||||||
|
|app| app.keymapping_table.as_mut().unwrap(),
|
||||||
|
keybinding_table_handling_config,
|
||||||
|
) {
|
||||||
|
self.handle_key_event();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn accepts(_active_block: ActiveKeybindingBlock) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new(
|
||||||
|
key: Key,
|
||||||
|
app: &'a mut App<'b>,
|
||||||
|
_active_block: ActiveKeybindingBlock,
|
||||||
|
_context: Option<ActiveKeybindingBlock>,
|
||||||
|
) -> KeybindingHandler<'a, 'b> {
|
||||||
|
KeybindingHandler { key, app }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_key(&self) -> Key {
|
||||||
|
self.key
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ignore_special_keys(&self) -> bool {
|
||||||
|
self.app.ignore_special_keys_for_textbox_input
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_ready(&self) -> bool {
|
||||||
|
self.app.keymapping_table.is_some()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_scroll_up(&mut self) {}
|
||||||
|
|
||||||
|
fn handle_scroll_down(&mut self) {}
|
||||||
|
|
||||||
|
fn handle_home(&mut self) {}
|
||||||
|
|
||||||
|
fn handle_end(&mut self) {}
|
||||||
|
|
||||||
|
fn handle_delete(&mut self) {}
|
||||||
|
|
||||||
|
fn handle_left_right_action(&mut self) {}
|
||||||
|
|
||||||
|
fn handle_submit(&mut self) {}
|
||||||
|
|
||||||
|
fn handle_esc(&mut self) {
|
||||||
|
self.app.keymapping_table = None;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_char_key_event(&mut self) {}
|
||||||
|
|
||||||
|
fn app_mut(&mut self) -> &mut App<'b> {
|
||||||
|
self.app
|
||||||
|
}
|
||||||
|
|
||||||
|
fn current_route(&self) -> crate::models::Route {
|
||||||
|
self.app.get_current_route()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use crate::app::App;
|
||||||
|
use crate::app::key_binding::DEFAULT_KEYBINDINGS;
|
||||||
|
use crate::event::Key;
|
||||||
|
use crate::handlers::KeyEventHandler;
|
||||||
|
use crate::handlers::KeybindingHandler;
|
||||||
|
use crate::models::servarr_data::ActiveKeybindingBlock;
|
||||||
|
use crate::models::stateful_table::StatefulTable;
|
||||||
|
use rstest::rstest;
|
||||||
|
|
||||||
|
mod test_handle_esc {
|
||||||
|
use super::*;
|
||||||
|
use crate::assert_modal_absent;
|
||||||
|
use crate::models::servarr_data::radarr::radarr_data::ActiveRadarrBlock;
|
||||||
|
use pretty_assertions::assert_eq;
|
||||||
|
|
||||||
|
const ESC_KEY: Key = DEFAULT_KEYBINDINGS.esc.key;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_esc_empties_keymapping_table() {
|
||||||
|
let mut app = App::test_default();
|
||||||
|
app.is_loading = true;
|
||||||
|
app.push_navigation_stack(ActiveRadarrBlock::Movies.into());
|
||||||
|
|
||||||
|
KeybindingHandler::new(ESC_KEY, &mut app, ActiveKeybindingBlock::Help, None).handle();
|
||||||
|
|
||||||
|
assert_eq!(app.get_current_route(), ActiveRadarrBlock::Movies.into());
|
||||||
|
assert_modal_absent!(app.keymapping_table);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_keybinding_handler_accepts() {
|
||||||
|
assert!(KeybindingHandler::accepts(ActiveKeybindingBlock::Help));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_keybinding_handler_not_ready_when_keybinding_is_empty() {
|
||||||
|
let mut app = App::test_default();
|
||||||
|
app.is_loading = false;
|
||||||
|
|
||||||
|
let handler = KeybindingHandler::new(
|
||||||
|
DEFAULT_KEYBINDINGS.esc.key,
|
||||||
|
&mut app,
|
||||||
|
ActiveKeybindingBlock::Help,
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert!(!handler.is_ready());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
fn test_keybinding_handler_ready_when_keymapping_table_is_not_empty(
|
||||||
|
#[values(true, false)] is_loading: bool,
|
||||||
|
) {
|
||||||
|
let mut app = App::test_default();
|
||||||
|
app.keymapping_table = Some(StatefulTable::default());
|
||||||
|
app.is_loading = is_loading;
|
||||||
|
|
||||||
|
let handler = KeybindingHandler::new(
|
||||||
|
DEFAULT_KEYBINDINGS.esc.key,
|
||||||
|
&mut app,
|
||||||
|
ActiveKeybindingBlock::Help,
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert!(handler.is_ready());
|
||||||
|
}
|
||||||
|
}
|
||||||
+89
-26
@@ -1,11 +1,20 @@
|
|||||||
use radarr_handlers::RadarrHandler;
|
use radarr_handlers::RadarrHandler;
|
||||||
use sonarr_handlers::SonarrHandler;
|
use sonarr_handlers::SonarrHandler;
|
||||||
|
|
||||||
use crate::app::key_binding::DEFAULT_KEYBINDINGS;
|
|
||||||
use crate::app::App;
|
use crate::app::App;
|
||||||
|
use crate::app::context_clues::{
|
||||||
|
ContextClueProvider, SERVARR_CONTEXT_CLUES, ServarrContextClueProvider,
|
||||||
|
};
|
||||||
|
use crate::app::key_binding::KeyBinding;
|
||||||
use crate::event::Key;
|
use crate::event::Key;
|
||||||
|
use crate::handlers::keybinding_handler::KeybindingHandler;
|
||||||
|
use crate::matches_key;
|
||||||
|
use crate::models::servarr_data::ActiveKeybindingBlock;
|
||||||
|
use crate::models::servarr_models::KeybindingItem;
|
||||||
|
use crate::models::stateful_table::StatefulTable;
|
||||||
use crate::models::{HorizontallyScrollableText, Route};
|
use crate::models::{HorizontallyScrollableText, Route};
|
||||||
|
|
||||||
|
mod keybinding_handler;
|
||||||
mod radarr_handlers;
|
mod radarr_handlers;
|
||||||
mod sonarr_handlers;
|
mod sonarr_handlers;
|
||||||
|
|
||||||
@@ -22,40 +31,42 @@ pub trait KeyEventHandler<'a, 'b, T: Into<Route> + Copy> {
|
|||||||
fn handle_key_event(&mut self) {
|
fn handle_key_event(&mut self) {
|
||||||
let key = self.get_key();
|
let key = self.get_key();
|
||||||
match key {
|
match key {
|
||||||
_ if key == DEFAULT_KEYBINDINGS.up.key => {
|
_ if matches_key!(up, key, self.ignore_special_keys()) => {
|
||||||
if self.is_ready() {
|
if self.is_ready() {
|
||||||
self.handle_scroll_up();
|
self.handle_scroll_up();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ if key == DEFAULT_KEYBINDINGS.down.key => {
|
_ if matches_key!(down, key, self.ignore_special_keys()) => {
|
||||||
if self.is_ready() {
|
if self.is_ready() {
|
||||||
self.handle_scroll_down();
|
self.handle_scroll_down();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ if key == DEFAULT_KEYBINDINGS.home.key => {
|
_ if matches_key!(home, key) => {
|
||||||
if self.is_ready() {
|
if self.is_ready() {
|
||||||
self.handle_home();
|
self.handle_home();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ if key == DEFAULT_KEYBINDINGS.end.key => {
|
_ if matches_key!(end, key) => {
|
||||||
if self.is_ready() {
|
if self.is_ready() {
|
||||||
self.handle_end();
|
self.handle_end();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ if key == DEFAULT_KEYBINDINGS.delete.key => {
|
_ if matches_key!(delete, key) => {
|
||||||
if self.is_ready() {
|
if self.is_ready() {
|
||||||
self.handle_delete();
|
self.handle_delete();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ if key == DEFAULT_KEYBINDINGS.left.key || key == DEFAULT_KEYBINDINGS.right.key => {
|
_ if matches_key!(left, key, self.ignore_special_keys())
|
||||||
|
|| matches_key!(right, key, self.ignore_special_keys()) =>
|
||||||
|
{
|
||||||
self.handle_left_right_action()
|
self.handle_left_right_action()
|
||||||
}
|
}
|
||||||
_ if key == DEFAULT_KEYBINDINGS.submit.key => {
|
_ if matches_key!(submit, key) => {
|
||||||
if self.is_ready() {
|
if self.is_ready() {
|
||||||
self.handle_submit();
|
self.handle_submit();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ if key == DEFAULT_KEYBINDINGS.esc.key => self.handle_esc(),
|
_ if matches_key!(esc, key) => self.handle_esc(),
|
||||||
_ => {
|
_ => {
|
||||||
if self.is_ready() {
|
if self.is_ready() {
|
||||||
self.handle_char_key_event();
|
self.handle_char_key_event();
|
||||||
@@ -69,8 +80,9 @@ pub trait KeyEventHandler<'a, 'b, T: Into<Route> + Copy> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn accepts(active_block: T) -> bool;
|
fn accepts(active_block: T) -> bool;
|
||||||
fn with(key: Key, app: &'a mut App<'b>, active_block: T, context: Option<T>) -> Self;
|
fn new(key: Key, app: &'a mut App<'b>, active_block: T, context: Option<T>) -> Self;
|
||||||
fn get_key(&self) -> Key;
|
fn get_key(&self) -> Key;
|
||||||
|
fn ignore_special_keys(&self) -> bool;
|
||||||
fn is_ready(&self) -> bool;
|
fn is_ready(&self) -> bool;
|
||||||
fn handle_scroll_up(&mut self);
|
fn handle_scroll_up(&mut self);
|
||||||
fn handle_scroll_down(&mut self);
|
fn handle_scroll_down(&mut self);
|
||||||
@@ -81,32 +93,85 @@ pub trait KeyEventHandler<'a, 'b, T: Into<Route> + Copy> {
|
|||||||
fn handle_submit(&mut self);
|
fn handle_submit(&mut self);
|
||||||
fn handle_esc(&mut self);
|
fn handle_esc(&mut self);
|
||||||
fn handle_char_key_event(&mut self);
|
fn handle_char_key_event(&mut self);
|
||||||
|
fn app_mut(&mut self) -> &mut App<'b>;
|
||||||
|
fn current_route(&self) -> Route;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn handle_events(key: Key, app: &mut App<'_>) {
|
pub fn handle_events(key: Key, app: &mut App<'_>) {
|
||||||
if key == DEFAULT_KEYBINDINGS.next_servarr.key {
|
if matches_key!(next_servarr, key) {
|
||||||
app.reset();
|
app.reset();
|
||||||
app.server_tabs.next();
|
app.server_tabs.next();
|
||||||
app.pop_and_push_navigation_stack(app.server_tabs.get_active_route());
|
app.pop_and_push_navigation_stack(app.server_tabs.get_active_route());
|
||||||
app.cancellation_token.cancel();
|
app.cancellation_token.cancel();
|
||||||
} else if key == DEFAULT_KEYBINDINGS.previous_servarr.key {
|
} else if matches_key!(previous_servarr, key) {
|
||||||
app.reset();
|
app.reset();
|
||||||
app.server_tabs.previous();
|
app.server_tabs.previous();
|
||||||
app.pop_and_push_navigation_stack(app.server_tabs.get_active_route());
|
app.pop_and_push_navigation_stack(app.server_tabs.get_active_route());
|
||||||
app.cancellation_token.cancel();
|
app.cancellation_token.cancel();
|
||||||
|
} else if matches_key!(help, key) && !app.ignore_special_keys_for_textbox_input {
|
||||||
|
if app.keymapping_table.is_none() {
|
||||||
|
populate_keymapping_table(app);
|
||||||
|
} else {
|
||||||
|
app.keymapping_table = None;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
match app.get_current_route() {
|
match app.get_current_route() {
|
||||||
|
_ if app.keymapping_table.is_some() => {
|
||||||
|
KeybindingHandler::new(key, app, ActiveKeybindingBlock::Help, None).handle();
|
||||||
|
}
|
||||||
Route::Radarr(active_radarr_block, context) => {
|
Route::Radarr(active_radarr_block, context) => {
|
||||||
RadarrHandler::with(key, app, active_radarr_block, context).handle()
|
RadarrHandler::new(key, app, active_radarr_block, context).handle()
|
||||||
}
|
}
|
||||||
Route::Sonarr(active_sonarr_block, context) => {
|
Route::Sonarr(active_sonarr_block, context) => {
|
||||||
SonarrHandler::with(key, app, active_sonarr_block, context).handle()
|
SonarrHandler::new(key, app, active_sonarr_block, context).handle()
|
||||||
}
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn populate_keymapping_table(app: &mut App<'_>) {
|
||||||
|
let context_clue_to_keybinding_item = |key: &KeyBinding, desc: &&str| {
|
||||||
|
let (key, alt_key) = if key.alt.is_some() {
|
||||||
|
(key.key.to_string(), key.alt.as_ref().unwrap().to_string())
|
||||||
|
} else {
|
||||||
|
(key.key.to_string(), String::new())
|
||||||
|
};
|
||||||
|
KeybindingItem {
|
||||||
|
key,
|
||||||
|
alt_key,
|
||||||
|
desc: desc.to_string(),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let mut keybindings = Vec::new();
|
||||||
|
let global_keybindings = Vec::from(SERVARR_CONTEXT_CLUES)
|
||||||
|
.iter()
|
||||||
|
.map(|(key, desc)| context_clue_to_keybinding_item(key, desc))
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
if let Some(contextual_help) = app.server_tabs.get_active_route_contextual_help() {
|
||||||
|
keybindings.extend(
|
||||||
|
contextual_help
|
||||||
|
.iter()
|
||||||
|
.map(|(key, desc)| context_clue_to_keybinding_item(key, desc)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(contextual_help) = ServarrContextClueProvider::get_context_clues(app) {
|
||||||
|
keybindings.extend(
|
||||||
|
contextual_help
|
||||||
|
.iter()
|
||||||
|
.map(|(key, desc)| context_clue_to_keybinding_item(key, desc)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
keybindings.extend(global_keybindings);
|
||||||
|
|
||||||
|
let mut table = StatefulTable::default();
|
||||||
|
table.set_items(keybindings);
|
||||||
|
app.keymapping_table = Some(table);
|
||||||
|
}
|
||||||
|
|
||||||
fn handle_clear_errors(app: &mut App<'_>) {
|
fn handle_clear_errors(app: &mut App<'_>) {
|
||||||
if !app.error.text.is_empty() {
|
if !app.error.text.is_empty() {
|
||||||
app.error = HorizontallyScrollableText::default();
|
app.error = HorizontallyScrollableText::default();
|
||||||
@@ -115,17 +180,15 @@ fn handle_clear_errors(app: &mut App<'_>) {
|
|||||||
|
|
||||||
fn handle_prompt_toggle(app: &mut App<'_>, key: Key) {
|
fn handle_prompt_toggle(app: &mut App<'_>, key: Key) {
|
||||||
match key {
|
match key {
|
||||||
_ if key == DEFAULT_KEYBINDINGS.left.key || key == DEFAULT_KEYBINDINGS.right.key => {
|
_ if matches_key!(left, key) || matches_key!(right, key) => match app.get_current_route() {
|
||||||
match app.get_current_route() {
|
Route::Radarr(_, _) => {
|
||||||
Route::Radarr(_, _) => {
|
app.data.radarr_data.prompt_confirm = !app.data.radarr_data.prompt_confirm
|
||||||
app.data.radarr_data.prompt_confirm = !app.data.radarr_data.prompt_confirm
|
|
||||||
}
|
|
||||||
Route::Sonarr(_, _) => {
|
|
||||||
app.data.sonarr_data.prompt_confirm = !app.data.sonarr_data.prompt_confirm
|
|
||||||
}
|
|
||||||
_ => (),
|
|
||||||
}
|
}
|
||||||
}
|
Route::Sonarr(_, _) => {
|
||||||
|
app.data.sonarr_data.prompt_confirm = !app.data.sonarr_data.prompt_confirm
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
},
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -149,7 +212,7 @@ macro_rules! handle_text_box_left_right_keys {
|
|||||||
macro_rules! handle_text_box_keys {
|
macro_rules! handle_text_box_keys {
|
||||||
($self:expr, $key:expr, $input:expr) => {
|
($self:expr, $key:expr, $input:expr) => {
|
||||||
match $self.key {
|
match $self.key {
|
||||||
_ if $key == $crate::app::key_binding::DEFAULT_KEYBINDINGS.backspace.key => {
|
_ if $crate::matches_key!(backspace, $key) => {
|
||||||
$input.pop();
|
$input.pop();
|
||||||
}
|
}
|
||||||
Key::Char(character) => {
|
Key::Char(character) => {
|
||||||
@@ -165,7 +228,7 @@ macro_rules! handle_prompt_left_right_keys {
|
|||||||
($self:expr, $confirm_prompt:expr, $data:ident) => {
|
($self:expr, $confirm_prompt:expr, $data:ident) => {
|
||||||
if $self.app.data.$data.selected_block.get_active_block() == $confirm_prompt {
|
if $self.app.data.$data.selected_block.get_active_block() == $confirm_prompt {
|
||||||
handle_prompt_toggle($self.app, $self.key);
|
handle_prompt_toggle($self.app, $self.key);
|
||||||
} else if $self.key == $crate::app::key_binding::DEFAULT_KEYBINDINGS.left.key {
|
} else if $crate::matches_key!(left, $self.key) {
|
||||||
$self.app.data.$data.selected_block.left();
|
$self.app.data.$data.selected_block.left();
|
||||||
} else {
|
} else {
|
||||||
$self.app.data.$data.selected_block.right();
|
$self.app.data.$data.selected_block.right();
|
||||||
|
|||||||
@@ -4,13 +4,15 @@ mod tests {
|
|||||||
|
|
||||||
use chrono::DateTime;
|
use chrono::DateTime;
|
||||||
use pretty_assertions::{assert_eq, assert_str_eq};
|
use pretty_assertions::{assert_eq, assert_str_eq};
|
||||||
|
use rstest::rstest;
|
||||||
use strum::IntoEnumIterator;
|
use strum::IntoEnumIterator;
|
||||||
|
|
||||||
use crate::app::key_binding::DEFAULT_KEYBINDINGS;
|
|
||||||
use crate::app::App;
|
use crate::app::App;
|
||||||
|
use crate::app::key_binding::DEFAULT_KEYBINDINGS;
|
||||||
|
use crate::assert_navigation_pushed;
|
||||||
use crate::event::Key;
|
use crate::event::Key;
|
||||||
use crate::handlers::radarr_handlers::blocklist::{blocklist_sorting_options, BlocklistHandler};
|
|
||||||
use crate::handlers::KeyEventHandler;
|
use crate::handlers::KeyEventHandler;
|
||||||
|
use crate::handlers::radarr_handlers::blocklist::{BlocklistHandler, blocklist_sorting_options};
|
||||||
use crate::models::radarr_models::{BlocklistItem, BlocklistItemMovie};
|
use crate::models::radarr_models::{BlocklistItem, BlocklistItemMovie};
|
||||||
use crate::models::servarr_data::radarr::radarr_data::{ActiveRadarrBlock, BLOCKLIST_BLOCKS};
|
use crate::models::servarr_data::radarr::radarr_data::{ActiveRadarrBlock, BLOCKLIST_BLOCKS};
|
||||||
use crate::models::servarr_models::{Language, Quality, QualityWrapper};
|
use crate::models::servarr_models::{Language, Quality, QualityWrapper};
|
||||||
@@ -24,25 +26,22 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_delete_blocklist_item_prompt() {
|
fn test_delete_blocklist_item_prompt() {
|
||||||
let mut app = App::default();
|
let mut app = App::test_default();
|
||||||
app.data.radarr_data.blocklist.set_items(blocklist_vec());
|
app.data.radarr_data.blocklist.set_items(blocklist_vec());
|
||||||
|
|
||||||
BlocklistHandler::with(DELETE_KEY, &mut app, ActiveRadarrBlock::Blocklist, None).handle();
|
BlocklistHandler::new(DELETE_KEY, &mut app, ActiveRadarrBlock::Blocklist, None).handle();
|
||||||
|
|
||||||
assert_eq!(
|
assert_navigation_pushed!(app, ActiveRadarrBlock::DeleteBlocklistItemPrompt.into());
|
||||||
app.get_current_route(),
|
|
||||||
ActiveRadarrBlock::DeleteBlocklistItemPrompt.into()
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_delete_blocklist_item_no_op_when_not_ready() {
|
fn test_delete_blocklist_item_no_op_when_not_ready() {
|
||||||
let mut app = App::default();
|
let mut app = App::test_default();
|
||||||
app.is_loading = true;
|
app.is_loading = true;
|
||||||
app.push_navigation_stack(ActiveRadarrBlock::Blocklist.into());
|
app.push_navigation_stack(ActiveRadarrBlock::Blocklist.into());
|
||||||
app.data.radarr_data.blocklist.set_items(blocklist_vec());
|
app.data.radarr_data.blocklist.set_items(blocklist_vec());
|
||||||
|
|
||||||
BlocklistHandler::with(DELETE_KEY, &mut app, ActiveRadarrBlock::Blocklist, None).handle();
|
BlocklistHandler::new(DELETE_KEY, &mut app, ActiveRadarrBlock::Blocklist, None).handle();
|
||||||
|
|
||||||
assert_eq!(app.get_current_route(), ActiveRadarrBlock::Blocklist.into());
|
assert_eq!(app.get_current_route(), ActiveRadarrBlock::Blocklist.into());
|
||||||
}
|
}
|
||||||
@@ -53,14 +52,15 @@ mod tests {
|
|||||||
use rstest::rstest;
|
use rstest::rstest;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use crate::assert_navigation_pushed;
|
||||||
|
|
||||||
#[rstest]
|
#[rstest]
|
||||||
fn test_blocklist_tab_left(#[values(true, false)] is_ready: bool) {
|
fn test_blocklist_tab_left(#[values(true, false)] is_ready: bool) {
|
||||||
let mut app = App::default();
|
let mut app = App::test_default();
|
||||||
app.is_loading = is_ready;
|
app.is_loading = is_ready;
|
||||||
app.data.radarr_data.main_tabs.set_index(3);
|
app.data.radarr_data.main_tabs.set_index(3);
|
||||||
|
|
||||||
BlocklistHandler::with(
|
BlocklistHandler::new(
|
||||||
DEFAULT_KEYBINDINGS.left.key,
|
DEFAULT_KEYBINDINGS.left.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
ActiveRadarrBlock::Blocklist,
|
ActiveRadarrBlock::Blocklist,
|
||||||
@@ -72,16 +72,16 @@ mod tests {
|
|||||||
app.data.radarr_data.main_tabs.get_active_route(),
|
app.data.radarr_data.main_tabs.get_active_route(),
|
||||||
ActiveRadarrBlock::Downloads.into()
|
ActiveRadarrBlock::Downloads.into()
|
||||||
);
|
);
|
||||||
assert_eq!(app.get_current_route(), ActiveRadarrBlock::Downloads.into());
|
assert_navigation_pushed!(app, ActiveRadarrBlock::Downloads.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rstest]
|
#[rstest]
|
||||||
fn test_blocklist_tab_right(#[values(true, false)] is_ready: bool) {
|
fn test_blocklist_tab_right(#[values(true, false)] is_ready: bool) {
|
||||||
let mut app = App::default();
|
let mut app = App::test_default();
|
||||||
app.is_loading = is_ready;
|
app.is_loading = is_ready;
|
||||||
app.data.radarr_data.main_tabs.set_index(3);
|
app.data.radarr_data.main_tabs.set_index(3);
|
||||||
|
|
||||||
BlocklistHandler::with(
|
BlocklistHandler::new(
|
||||||
DEFAULT_KEYBINDINGS.right.key,
|
DEFAULT_KEYBINDINGS.right.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
ActiveRadarrBlock::Blocklist,
|
ActiveRadarrBlock::Blocklist,
|
||||||
@@ -93,10 +93,7 @@ mod tests {
|
|||||||
app.data.radarr_data.main_tabs.get_active_route(),
|
app.data.radarr_data.main_tabs.get_active_route(),
|
||||||
ActiveRadarrBlock::RootFolders.into()
|
ActiveRadarrBlock::RootFolders.into()
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_navigation_pushed!(app, ActiveRadarrBlock::RootFolders.into());
|
||||||
app.get_current_route(),
|
|
||||||
ActiveRadarrBlock::RootFolders.into()
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rstest]
|
#[rstest]
|
||||||
@@ -108,50 +105,47 @@ mod tests {
|
|||||||
active_radarr_block: ActiveRadarrBlock,
|
active_radarr_block: ActiveRadarrBlock,
|
||||||
#[values(DEFAULT_KEYBINDINGS.left.key, DEFAULT_KEYBINDINGS.right.key)] key: Key,
|
#[values(DEFAULT_KEYBINDINGS.left.key, DEFAULT_KEYBINDINGS.right.key)] key: Key,
|
||||||
) {
|
) {
|
||||||
let mut app = App::default();
|
let mut app = App::test_default();
|
||||||
|
|
||||||
BlocklistHandler::with(key, &mut app, active_radarr_block, None).handle();
|
BlocklistHandler::new(key, &mut app, active_radarr_block, None).handle();
|
||||||
|
|
||||||
assert!(app.data.radarr_data.prompt_confirm);
|
assert!(app.data.radarr_data.prompt_confirm);
|
||||||
|
|
||||||
BlocklistHandler::with(key, &mut app, active_radarr_block, None).handle();
|
BlocklistHandler::new(key, &mut app, active_radarr_block, None).handle();
|
||||||
|
|
||||||
assert!(!app.data.radarr_data.prompt_confirm);
|
assert!(!app.data.radarr_data.prompt_confirm);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mod test_handle_submit {
|
mod test_handle_submit {
|
||||||
|
use crate::assert_navigation_popped;
|
||||||
|
use crate::network::radarr_network::RadarrEvent;
|
||||||
use pretty_assertions::assert_eq;
|
use pretty_assertions::assert_eq;
|
||||||
use rstest::rstest;
|
use rstest::rstest;
|
||||||
|
|
||||||
use crate::network::radarr_network::RadarrEvent;
|
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
const SUBMIT_KEY: Key = DEFAULT_KEYBINDINGS.submit.key;
|
const SUBMIT_KEY: Key = DEFAULT_KEYBINDINGS.submit.key;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_blocklist_submit() {
|
fn test_blocklist_submit() {
|
||||||
let mut app = App::default();
|
let mut app = App::test_default();
|
||||||
app.data.radarr_data.blocklist.set_items(blocklist_vec());
|
app.data.radarr_data.blocklist.set_items(blocklist_vec());
|
||||||
app.push_navigation_stack(ActiveRadarrBlock::Blocklist.into());
|
app.push_navigation_stack(ActiveRadarrBlock::Blocklist.into());
|
||||||
|
|
||||||
BlocklistHandler::with(SUBMIT_KEY, &mut app, ActiveRadarrBlock::Blocklist, None).handle();
|
BlocklistHandler::new(SUBMIT_KEY, &mut app, ActiveRadarrBlock::Blocklist, None).handle();
|
||||||
|
|
||||||
assert_eq!(
|
assert_navigation_pushed!(app, ActiveRadarrBlock::BlocklistItemDetails.into());
|
||||||
app.get_current_route(),
|
|
||||||
ActiveRadarrBlock::BlocklistItemDetails.into()
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_blocklist_submit_no_op_when_not_ready() {
|
fn test_blocklist_submit_no_op_when_not_ready() {
|
||||||
let mut app = App::default();
|
let mut app = App::test_default();
|
||||||
app.is_loading = true;
|
app.is_loading = true;
|
||||||
app.data.radarr_data.blocklist.set_items(blocklist_vec());
|
app.data.radarr_data.blocklist.set_items(blocklist_vec());
|
||||||
app.push_navigation_stack(ActiveRadarrBlock::Blocklist.into());
|
app.push_navigation_stack(ActiveRadarrBlock::Blocklist.into());
|
||||||
|
|
||||||
BlocklistHandler::with(SUBMIT_KEY, &mut app, ActiveRadarrBlock::Blocklist, None).handle();
|
BlocklistHandler::new(SUBMIT_KEY, &mut app, ActiveRadarrBlock::Blocklist, None).handle();
|
||||||
|
|
||||||
assert_eq!(app.get_current_route(), ActiveRadarrBlock::Blocklist.into());
|
assert_eq!(app.get_current_route(), ActiveRadarrBlock::Blocklist.into());
|
||||||
}
|
}
|
||||||
@@ -172,20 +166,20 @@ mod tests {
|
|||||||
#[case] prompt_block: ActiveRadarrBlock,
|
#[case] prompt_block: ActiveRadarrBlock,
|
||||||
#[case] expected_action: RadarrEvent,
|
#[case] expected_action: RadarrEvent,
|
||||||
) {
|
) {
|
||||||
let mut app = App::default();
|
let mut app = App::test_default();
|
||||||
app.data.radarr_data.blocklist.set_items(blocklist_vec());
|
app.data.radarr_data.blocklist.set_items(blocklist_vec());
|
||||||
app.data.radarr_data.prompt_confirm = true;
|
app.data.radarr_data.prompt_confirm = true;
|
||||||
app.push_navigation_stack(base_route.into());
|
app.push_navigation_stack(base_route.into());
|
||||||
app.push_navigation_stack(prompt_block.into());
|
app.push_navigation_stack(prompt_block.into());
|
||||||
|
|
||||||
BlocklistHandler::with(SUBMIT_KEY, &mut app, prompt_block, None).handle();
|
BlocklistHandler::new(SUBMIT_KEY, &mut app, prompt_block, None).handle();
|
||||||
|
|
||||||
assert!(app.data.radarr_data.prompt_confirm);
|
assert!(app.data.radarr_data.prompt_confirm);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.data.radarr_data.prompt_confirm_action,
|
app.data.radarr_data.prompt_confirm_action,
|
||||||
Some(expected_action)
|
Some(expected_action)
|
||||||
);
|
);
|
||||||
assert_eq!(app.get_current_route(), base_route.into());
|
assert_navigation_popped!(app, base_route.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rstest]
|
#[rstest]
|
||||||
@@ -196,26 +190,26 @@ mod tests {
|
|||||||
)]
|
)]
|
||||||
prompt_block: ActiveRadarrBlock,
|
prompt_block: ActiveRadarrBlock,
|
||||||
) {
|
) {
|
||||||
let mut app = App::default();
|
let mut app = App::test_default();
|
||||||
app.data.radarr_data.blocklist.set_items(blocklist_vec());
|
app.data.radarr_data.blocklist.set_items(blocklist_vec());
|
||||||
app.push_navigation_stack(ActiveRadarrBlock::Blocklist.into());
|
app.push_navigation_stack(ActiveRadarrBlock::Blocklist.into());
|
||||||
app.push_navigation_stack(prompt_block.into());
|
app.push_navigation_stack(prompt_block.into());
|
||||||
|
|
||||||
BlocklistHandler::with(SUBMIT_KEY, &mut app, prompt_block, None).handle();
|
BlocklistHandler::new(SUBMIT_KEY, &mut app, prompt_block, None).handle();
|
||||||
|
|
||||||
assert!(!app.data.radarr_data.prompt_confirm);
|
assert!(!app.data.radarr_data.prompt_confirm);
|
||||||
assert_eq!(app.data.radarr_data.prompt_confirm_action, None);
|
assert_none!(app.data.radarr_data.prompt_confirm_action);
|
||||||
assert_eq!(app.get_current_route(), ActiveRadarrBlock::Blocklist.into());
|
assert_navigation_popped!(app, ActiveRadarrBlock::Blocklist.into());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mod test_handle_esc {
|
mod test_handle_esc {
|
||||||
use pretty_assertions::assert_eq;
|
|
||||||
use rstest::rstest;
|
use rstest::rstest;
|
||||||
|
|
||||||
use crate::handlers::radarr_handlers::downloads::DownloadsHandler;
|
use crate::handlers::radarr_handlers::downloads::DownloadsHandler;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use crate::assert_navigation_popped;
|
||||||
|
|
||||||
const ESC_KEY: Key = DEFAULT_KEYBINDINGS.esc.key;
|
const ESC_KEY: Key = DEFAULT_KEYBINDINGS.esc.key;
|
||||||
|
|
||||||
@@ -232,24 +226,24 @@ mod tests {
|
|||||||
#[case] base_block: ActiveRadarrBlock,
|
#[case] base_block: ActiveRadarrBlock,
|
||||||
#[case] prompt_block: ActiveRadarrBlock,
|
#[case] prompt_block: ActiveRadarrBlock,
|
||||||
) {
|
) {
|
||||||
let mut app = App::default();
|
let mut app = App::test_default();
|
||||||
app.push_navigation_stack(base_block.into());
|
app.push_navigation_stack(base_block.into());
|
||||||
app.push_navigation_stack(prompt_block.into());
|
app.push_navigation_stack(prompt_block.into());
|
||||||
app.data.radarr_data.prompt_confirm = true;
|
app.data.radarr_data.prompt_confirm = true;
|
||||||
|
|
||||||
BlocklistHandler::with(ESC_KEY, &mut app, prompt_block, None).handle();
|
BlocklistHandler::new(ESC_KEY, &mut app, prompt_block, None).handle();
|
||||||
|
|
||||||
assert_eq!(app.get_current_route(), base_block.into());
|
assert_navigation_popped!(app, base_block.into());
|
||||||
assert!(!app.data.radarr_data.prompt_confirm);
|
assert!(!app.data.radarr_data.prompt_confirm);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_esc_blocklist_item_details() {
|
fn test_esc_blocklist_item_details() {
|
||||||
let mut app = App::default();
|
let mut app = App::test_default();
|
||||||
app.push_navigation_stack(ActiveRadarrBlock::Blocklist.into());
|
app.push_navigation_stack(ActiveRadarrBlock::Blocklist.into());
|
||||||
app.push_navigation_stack(ActiveRadarrBlock::BlocklistItemDetails.into());
|
app.push_navigation_stack(ActiveRadarrBlock::BlocklistItemDetails.into());
|
||||||
|
|
||||||
BlocklistHandler::with(
|
BlocklistHandler::new(
|
||||||
ESC_KEY,
|
ESC_KEY,
|
||||||
&mut app,
|
&mut app,
|
||||||
ActiveRadarrBlock::BlocklistItemDetails,
|
ActiveRadarrBlock::BlocklistItemDetails,
|
||||||
@@ -257,20 +251,20 @@ mod tests {
|
|||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert_eq!(app.get_current_route(), ActiveRadarrBlock::Blocklist.into());
|
assert_navigation_popped!(app, ActiveRadarrBlock::Blocklist.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rstest]
|
#[rstest]
|
||||||
fn test_default_esc(#[values(true, false)] is_ready: bool) {
|
fn test_default_esc(#[values(true, false)] is_ready: bool) {
|
||||||
let mut app = App::default();
|
let mut app = App::test_default();
|
||||||
app.is_loading = is_ready;
|
app.is_loading = is_ready;
|
||||||
app.error = "test error".to_owned().into();
|
app.error = "test error".to_owned().into();
|
||||||
app.push_navigation_stack(ActiveRadarrBlock::Blocklist.into());
|
app.push_navigation_stack(ActiveRadarrBlock::Blocklist.into());
|
||||||
app.push_navigation_stack(ActiveRadarrBlock::Blocklist.into());
|
app.push_navigation_stack(ActiveRadarrBlock::Blocklist.into());
|
||||||
|
|
||||||
DownloadsHandler::with(ESC_KEY, &mut app, ActiveRadarrBlock::Blocklist, None).handle();
|
DownloadsHandler::new(ESC_KEY, &mut app, ActiveRadarrBlock::Blocklist, None).handle();
|
||||||
|
|
||||||
assert_eq!(app.get_current_route(), ActiveRadarrBlock::Blocklist.into());
|
assert_navigation_popped!(app, ActiveRadarrBlock::Blocklist.into());
|
||||||
assert!(app.error.text.is_empty());
|
assert!(app.error.text.is_empty());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -282,14 +276,15 @@ mod tests {
|
|||||||
use crate::network::radarr_network::RadarrEvent;
|
use crate::network::radarr_network::RadarrEvent;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use crate::{assert_navigation_popped, assert_navigation_pushed};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_refresh_blocklist_key() {
|
fn test_refresh_blocklist_key() {
|
||||||
let mut app = App::default();
|
let mut app = App::test_default();
|
||||||
app.data.radarr_data.blocklist.set_items(blocklist_vec());
|
app.data.radarr_data.blocklist.set_items(blocklist_vec());
|
||||||
app.push_navigation_stack(ActiveRadarrBlock::Blocklist.into());
|
app.push_navigation_stack(ActiveRadarrBlock::Blocklist.into());
|
||||||
|
|
||||||
BlocklistHandler::with(
|
BlocklistHandler::new(
|
||||||
DEFAULT_KEYBINDINGS.refresh.key,
|
DEFAULT_KEYBINDINGS.refresh.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
ActiveRadarrBlock::Blocklist,
|
ActiveRadarrBlock::Blocklist,
|
||||||
@@ -297,18 +292,18 @@ mod tests {
|
|||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert_eq!(app.get_current_route(), ActiveRadarrBlock::Blocklist.into());
|
assert_navigation_pushed!(app, ActiveRadarrBlock::Blocklist.into());
|
||||||
assert!(app.should_refresh);
|
assert!(app.should_refresh);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_refresh_blocklist_key_no_op_when_not_ready() {
|
fn test_refresh_blocklist_key_no_op_when_not_ready() {
|
||||||
let mut app = App::default();
|
let mut app = App::test_default();
|
||||||
app.is_loading = true;
|
app.is_loading = true;
|
||||||
app.data.radarr_data.blocklist.set_items(blocklist_vec());
|
app.data.radarr_data.blocklist.set_items(blocklist_vec());
|
||||||
app.push_navigation_stack(ActiveRadarrBlock::Blocklist.into());
|
app.push_navigation_stack(ActiveRadarrBlock::Blocklist.into());
|
||||||
|
|
||||||
BlocklistHandler::with(
|
BlocklistHandler::new(
|
||||||
DEFAULT_KEYBINDINGS.refresh.key,
|
DEFAULT_KEYBINDINGS.refresh.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
ActiveRadarrBlock::Blocklist,
|
ActiveRadarrBlock::Blocklist,
|
||||||
@@ -322,10 +317,10 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_clear_blocklist_key() {
|
fn test_clear_blocklist_key() {
|
||||||
let mut app = App::default();
|
let mut app = App::test_default();
|
||||||
app.data.radarr_data.blocklist.set_items(blocklist_vec());
|
app.data.radarr_data.blocklist.set_items(blocklist_vec());
|
||||||
|
|
||||||
BlocklistHandler::with(
|
BlocklistHandler::new(
|
||||||
DEFAULT_KEYBINDINGS.clear.key,
|
DEFAULT_KEYBINDINGS.clear.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
ActiveRadarrBlock::Blocklist,
|
ActiveRadarrBlock::Blocklist,
|
||||||
@@ -333,20 +328,17 @@ mod tests {
|
|||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert_eq!(
|
assert_navigation_pushed!(app, ActiveRadarrBlock::BlocklistClearAllItemsPrompt.into());
|
||||||
app.get_current_route(),
|
|
||||||
ActiveRadarrBlock::BlocklistClearAllItemsPrompt.into()
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_clear_blocklist_key_no_op_when_not_ready() {
|
fn test_clear_blocklist_key_no_op_when_not_ready() {
|
||||||
let mut app = App::default();
|
let mut app = App::test_default();
|
||||||
app.is_loading = true;
|
app.is_loading = true;
|
||||||
app.push_navigation_stack(ActiveRadarrBlock::Blocklist.into());
|
app.push_navigation_stack(ActiveRadarrBlock::Blocklist.into());
|
||||||
app.data.radarr_data.blocklist.set_items(blocklist_vec());
|
app.data.radarr_data.blocklist.set_items(blocklist_vec());
|
||||||
|
|
||||||
BlocklistHandler::with(
|
BlocklistHandler::new(
|
||||||
DEFAULT_KEYBINDINGS.clear.key,
|
DEFAULT_KEYBINDINGS.clear.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
ActiveRadarrBlock::Blocklist,
|
ActiveRadarrBlock::Blocklist,
|
||||||
@@ -373,12 +365,12 @@ mod tests {
|
|||||||
#[case] prompt_block: ActiveRadarrBlock,
|
#[case] prompt_block: ActiveRadarrBlock,
|
||||||
#[case] expected_action: RadarrEvent,
|
#[case] expected_action: RadarrEvent,
|
||||||
) {
|
) {
|
||||||
let mut app = App::default();
|
let mut app = App::test_default();
|
||||||
app.data.radarr_data.blocklist.set_items(blocklist_vec());
|
app.data.radarr_data.blocklist.set_items(blocklist_vec());
|
||||||
app.push_navigation_stack(base_route.into());
|
app.push_navigation_stack(base_route.into());
|
||||||
app.push_navigation_stack(prompt_block.into());
|
app.push_navigation_stack(prompt_block.into());
|
||||||
|
|
||||||
BlocklistHandler::with(
|
BlocklistHandler::new(
|
||||||
DEFAULT_KEYBINDINGS.confirm.key,
|
DEFAULT_KEYBINDINGS.confirm.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
prompt_block,
|
prompt_block,
|
||||||
@@ -391,7 +383,7 @@ mod tests {
|
|||||||
app.data.radarr_data.prompt_confirm_action,
|
app.data.radarr_data.prompt_confirm_action,
|
||||||
Some(expected_action)
|
Some(expected_action)
|
||||||
);
|
);
|
||||||
assert_eq!(app.get_current_route(), base_route.into());
|
assert_navigation_popped!(app, base_route.into());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -541,12 +533,31 @@ mod tests {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
fn test_blocklist_handler_ignore_special_keys(
|
||||||
|
#[values(true, false)] ignore_special_keys_for_textbox_input: bool,
|
||||||
|
) {
|
||||||
|
let mut app = App::test_default();
|
||||||
|
app.ignore_special_keys_for_textbox_input = ignore_special_keys_for_textbox_input;
|
||||||
|
let handler = BlocklistHandler::new(
|
||||||
|
DEFAULT_KEYBINDINGS.esc.key,
|
||||||
|
&mut app,
|
||||||
|
ActiveRadarrBlock::default(),
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
handler.ignore_special_keys(),
|
||||||
|
ignore_special_keys_for_textbox_input
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_extract_blocklist_item_id() {
|
fn test_extract_blocklist_item_id() {
|
||||||
let mut app = App::default();
|
let mut app = App::test_default();
|
||||||
app.data.radarr_data.blocklist.set_items(blocklist_vec());
|
app.data.radarr_data.blocklist.set_items(blocklist_vec());
|
||||||
|
|
||||||
let blocklist_item_id = BlocklistHandler::with(
|
let blocklist_item_id = BlocklistHandler::new(
|
||||||
DEFAULT_KEYBINDINGS.esc.key,
|
DEFAULT_KEYBINDINGS.esc.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
ActiveRadarrBlock::Blocklist,
|
ActiveRadarrBlock::Blocklist,
|
||||||
@@ -559,10 +570,10 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_blocklist_handler_not_ready_when_loading() {
|
fn test_blocklist_handler_not_ready_when_loading() {
|
||||||
let mut app = App::default();
|
let mut app = App::test_default();
|
||||||
app.is_loading = true;
|
app.is_loading = true;
|
||||||
|
|
||||||
let handler = BlocklistHandler::with(
|
let handler = BlocklistHandler::new(
|
||||||
DEFAULT_KEYBINDINGS.esc.key,
|
DEFAULT_KEYBINDINGS.esc.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
ActiveRadarrBlock::Blocklist,
|
ActiveRadarrBlock::Blocklist,
|
||||||
@@ -574,10 +585,10 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_blocklist_handler_not_ready_when_blocklist_is_empty() {
|
fn test_blocklist_handler_not_ready_when_blocklist_is_empty() {
|
||||||
let mut app = App::default();
|
let mut app = App::test_default();
|
||||||
app.is_loading = false;
|
app.is_loading = false;
|
||||||
|
|
||||||
let handler = BlocklistHandler::with(
|
let handler = BlocklistHandler::new(
|
||||||
DEFAULT_KEYBINDINGS.esc.key,
|
DEFAULT_KEYBINDINGS.esc.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
ActiveRadarrBlock::Blocklist,
|
ActiveRadarrBlock::Blocklist,
|
||||||
@@ -589,7 +600,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_blocklist_handler_ready_when_not_loading_and_blocklist_is_not_empty() {
|
fn test_blocklist_handler_ready_when_not_loading_and_blocklist_is_not_empty() {
|
||||||
let mut app = App::default();
|
let mut app = App::test_default();
|
||||||
app.is_loading = false;
|
app.is_loading = false;
|
||||||
app
|
app
|
||||||
.data
|
.data
|
||||||
@@ -597,7 +608,7 @@ mod tests {
|
|||||||
.blocklist
|
.blocklist
|
||||||
.set_items(vec![BlocklistItem::default()]);
|
.set_items(vec![BlocklistItem::default()]);
|
||||||
|
|
||||||
let handler = BlocklistHandler::with(
|
let handler = BlocklistHandler::new(
|
||||||
DEFAULT_KEYBINDINGS.esc.key,
|
DEFAULT_KEYBINDINGS.esc.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
ActiveRadarrBlock::Blocklist,
|
ActiveRadarrBlock::Blocklist,
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
use crate::app::key_binding::DEFAULT_KEYBINDINGS;
|
|
||||||
use crate::app::App;
|
use crate::app::App;
|
||||||
use crate::event::Key;
|
use crate::event::Key;
|
||||||
use crate::handle_table_events;
|
|
||||||
use crate::handlers::radarr_handlers::handle_change_tab_left_right_keys;
|
use crate::handlers::radarr_handlers::handle_change_tab_left_right_keys;
|
||||||
use crate::handlers::table_handler::TableHandlingConfig;
|
use crate::handlers::table_handler::{TableHandlingConfig, handle_table};
|
||||||
use crate::handlers::{handle_clear_errors, handle_prompt_toggle, KeyEventHandler};
|
use crate::handlers::{KeyEventHandler, handle_clear_errors, handle_prompt_toggle};
|
||||||
|
use crate::matches_key;
|
||||||
use crate::models::radarr_models::BlocklistItem;
|
use crate::models::radarr_models::BlocklistItem;
|
||||||
use crate::models::servarr_data::radarr::radarr_data::{ActiveRadarrBlock, BLOCKLIST_BLOCKS};
|
use crate::models::servarr_data::radarr::radarr_data::{ActiveRadarrBlock, BLOCKLIST_BLOCKS};
|
||||||
use crate::models::stateful_table::SortOption;
|
use crate::models::stateful_table::SortOption;
|
||||||
@@ -21,14 +20,7 @@ pub(super) struct BlocklistHandler<'a, 'b> {
|
|||||||
_context: Option<ActiveRadarrBlock>,
|
_context: Option<ActiveRadarrBlock>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'b> BlocklistHandler<'a, 'b> {
|
impl BlocklistHandler<'_, '_> {
|
||||||
handle_table_events!(
|
|
||||||
self,
|
|
||||||
blocklist,
|
|
||||||
self.app.data.radarr_data.blocklist,
|
|
||||||
BlocklistItem
|
|
||||||
);
|
|
||||||
|
|
||||||
fn extract_blocklist_item_id(&self) -> i64 {
|
fn extract_blocklist_item_id(&self) -> i64 {
|
||||||
self.app.data.radarr_data.blocklist.current_selection().id
|
self.app.data.radarr_data.blocklist.current_selection().id
|
||||||
}
|
}
|
||||||
@@ -39,10 +31,13 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for BlocklistHandler<'a,
|
|||||||
let blocklist_table_handling_config =
|
let blocklist_table_handling_config =
|
||||||
TableHandlingConfig::new(ActiveRadarrBlock::Blocklist.into())
|
TableHandlingConfig::new(ActiveRadarrBlock::Blocklist.into())
|
||||||
.sorting_block(ActiveRadarrBlock::BlocklistSortPrompt.into())
|
.sorting_block(ActiveRadarrBlock::BlocklistSortPrompt.into())
|
||||||
.sort_by_fn(|a: &BlocklistItem, b: &BlocklistItem| a.id.cmp(&b.id))
|
|
||||||
.sort_options(blocklist_sorting_options());
|
.sort_options(blocklist_sorting_options());
|
||||||
|
|
||||||
if !self.handle_blocklist_table_events(blocklist_table_handling_config) {
|
if !handle_table(
|
||||||
|
self,
|
||||||
|
|app| &mut app.data.radarr_data.blocklist,
|
||||||
|
blocklist_table_handling_config,
|
||||||
|
) {
|
||||||
self.handle_key_event();
|
self.handle_key_event();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -51,7 +46,11 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for BlocklistHandler<'a,
|
|||||||
BLOCKLIST_BLOCKS.contains(&active_block)
|
BLOCKLIST_BLOCKS.contains(&active_block)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn with(
|
fn ignore_special_keys(&self) -> bool {
|
||||||
|
self.app.ignore_special_keys_for_textbox_input
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new(
|
||||||
key: Key,
|
key: Key,
|
||||||
app: &'a mut App<'b>,
|
app: &'a mut App<'b>,
|
||||||
active_block: ActiveRadarrBlock,
|
active_block: ActiveRadarrBlock,
|
||||||
@@ -143,10 +142,10 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for BlocklistHandler<'a,
|
|||||||
let key = self.key;
|
let key = self.key;
|
||||||
match self.active_radarr_block {
|
match self.active_radarr_block {
|
||||||
ActiveRadarrBlock::Blocklist => match self.key {
|
ActiveRadarrBlock::Blocklist => match self.key {
|
||||||
_ if key == DEFAULT_KEYBINDINGS.refresh.key => {
|
_ if matches_key!(refresh, key) => {
|
||||||
self.app.should_refresh = true;
|
self.app.should_refresh = true;
|
||||||
}
|
}
|
||||||
_ if key == DEFAULT_KEYBINDINGS.clear.key => {
|
_ if matches_key!(clear, key) => {
|
||||||
self
|
self
|
||||||
.app
|
.app
|
||||||
.push_navigation_stack(ActiveRadarrBlock::BlocklistClearAllItemsPrompt.into());
|
.push_navigation_stack(ActiveRadarrBlock::BlocklistClearAllItemsPrompt.into());
|
||||||
@@ -154,7 +153,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for BlocklistHandler<'a,
|
|||||||
_ => (),
|
_ => (),
|
||||||
},
|
},
|
||||||
ActiveRadarrBlock::DeleteBlocklistItemPrompt => {
|
ActiveRadarrBlock::DeleteBlocklistItemPrompt => {
|
||||||
if key == DEFAULT_KEYBINDINGS.confirm.key {
|
if matches_key!(confirm, key) {
|
||||||
self.app.data.radarr_data.prompt_confirm = true;
|
self.app.data.radarr_data.prompt_confirm = true;
|
||||||
self.app.data.radarr_data.prompt_confirm_action = Some(RadarrEvent::DeleteBlocklistItem(
|
self.app.data.radarr_data.prompt_confirm_action = Some(RadarrEvent::DeleteBlocklistItem(
|
||||||
self.extract_blocklist_item_id(),
|
self.extract_blocklist_item_id(),
|
||||||
@@ -164,7 +163,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for BlocklistHandler<'a,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
ActiveRadarrBlock::BlocklistClearAllItemsPrompt => {
|
ActiveRadarrBlock::BlocklistClearAllItemsPrompt => {
|
||||||
if key == DEFAULT_KEYBINDINGS.confirm.key {
|
if matches_key!(confirm, key) {
|
||||||
self.app.data.radarr_data.prompt_confirm = true;
|
self.app.data.radarr_data.prompt_confirm = true;
|
||||||
self.app.data.radarr_data.prompt_confirm_action = Some(RadarrEvent::ClearBlocklist);
|
self.app.data.radarr_data.prompt_confirm_action = Some(RadarrEvent::ClearBlocklist);
|
||||||
|
|
||||||
@@ -174,6 +173,14 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for BlocklistHandler<'a,
|
|||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn app_mut(&mut self) -> &mut App<'b> {
|
||||||
|
self.app
|
||||||
|
}
|
||||||
|
|
||||||
|
fn current_route(&self) -> crate::models::Route {
|
||||||
|
self.app.get_current_route()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn blocklist_sorting_options() -> Vec<SortOption<BlocklistItem>> {
|
fn blocklist_sorting_options() -> Vec<SortOption<BlocklistItem>> {
|
||||||
|
|||||||
@@ -1,16 +1,14 @@
|
|||||||
use crate::app::key_binding::DEFAULT_KEYBINDINGS;
|
|
||||||
use crate::app::App;
|
use crate::app::App;
|
||||||
use crate::event::Key;
|
use crate::event::Key;
|
||||||
use crate::handle_table_events;
|
|
||||||
use crate::handlers::table_handler::TableHandlingConfig;
|
|
||||||
use crate::handlers::KeyEventHandler;
|
use crate::handlers::KeyEventHandler;
|
||||||
use crate::models::radarr_models::CollectionMovie;
|
use crate::handlers::table_handler::{TableHandlingConfig, handle_table};
|
||||||
|
use crate::matches_key;
|
||||||
|
use crate::models::BlockSelectionState;
|
||||||
use crate::models::servarr_data::radarr::radarr_data::{
|
use crate::models::servarr_data::radarr::radarr_data::{
|
||||||
ActiveRadarrBlock, ADD_MOVIE_SELECTION_BLOCKS, COLLECTION_DETAILS_BLOCKS,
|
ADD_MOVIE_SELECTION_BLOCKS, ActiveRadarrBlock, COLLECTION_DETAILS_BLOCKS,
|
||||||
EDIT_COLLECTION_SELECTION_BLOCKS,
|
EDIT_COLLECTION_SELECTION_BLOCKS,
|
||||||
};
|
};
|
||||||
use crate::models::stateful_table::StatefulTable;
|
use crate::models::stateful_table::StatefulTable;
|
||||||
use crate::models::BlockSelectionState;
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
#[path = "collection_details_handler_tests.rs"]
|
#[path = "collection_details_handler_tests.rs"]
|
||||||
@@ -23,21 +21,18 @@ pub(super) struct CollectionDetailsHandler<'a, 'b> {
|
|||||||
_context: Option<ActiveRadarrBlock>,
|
_context: Option<ActiveRadarrBlock>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'b> CollectionDetailsHandler<'a, 'b> {
|
impl CollectionDetailsHandler<'_, '_> {}
|
||||||
handle_table_events!(
|
|
||||||
self,
|
|
||||||
collection_movies,
|
|
||||||
self.app.data.radarr_data.collection_movies,
|
|
||||||
CollectionMovie
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for CollectionDetailsHandler<'a, 'b> {
|
impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for CollectionDetailsHandler<'a, 'b> {
|
||||||
fn handle(&mut self) {
|
fn handle(&mut self) {
|
||||||
let collection_movies_table_handling_config =
|
let collection_movies_table_handling_config =
|
||||||
TableHandlingConfig::new(ActiveRadarrBlock::CollectionDetails.into());
|
TableHandlingConfig::new(ActiveRadarrBlock::CollectionDetails.into());
|
||||||
|
|
||||||
if !self.handle_collection_movies_table_events(collection_movies_table_handling_config) {
|
if !handle_table(
|
||||||
|
self,
|
||||||
|
|app| &mut app.data.radarr_data.collection_movies,
|
||||||
|
collection_movies_table_handling_config,
|
||||||
|
) {
|
||||||
self.handle_key_event();
|
self.handle_key_event();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -46,7 +41,11 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for CollectionDetailsHan
|
|||||||
COLLECTION_DETAILS_BLOCKS.contains(&active_block)
|
COLLECTION_DETAILS_BLOCKS.contains(&active_block)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn with(
|
fn ignore_special_keys(&self) -> bool {
|
||||||
|
self.app.ignore_special_keys_for_textbox_input
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new(
|
||||||
key: Key,
|
key: Key,
|
||||||
app: &'a mut App<'b>,
|
app: &'a mut App<'b>,
|
||||||
active_block: ActiveRadarrBlock,
|
active_block: ActiveRadarrBlock,
|
||||||
@@ -130,7 +129,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for CollectionDetailsHan
|
|||||||
|
|
||||||
fn handle_char_key_event(&mut self) {
|
fn handle_char_key_event(&mut self) {
|
||||||
if self.active_radarr_block == ActiveRadarrBlock::CollectionDetails
|
if self.active_radarr_block == ActiveRadarrBlock::CollectionDetails
|
||||||
&& self.key == DEFAULT_KEYBINDINGS.edit.key
|
&& matches_key!(edit, self.key)
|
||||||
{
|
{
|
||||||
self.app.push_navigation_stack(
|
self.app.push_navigation_stack(
|
||||||
(
|
(
|
||||||
@@ -144,4 +143,12 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for CollectionDetailsHan
|
|||||||
BlockSelectionState::new(EDIT_COLLECTION_SELECTION_BLOCKS);
|
BlockSelectionState::new(EDIT_COLLECTION_SELECTION_BLOCKS);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn app_mut(&mut self) -> &mut App<'b> {
|
||||||
|
self.app
|
||||||
|
}
|
||||||
|
|
||||||
|
fn current_route(&self) -> crate::models::Route {
|
||||||
|
self.app.get_current_route()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,25 +1,27 @@
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use pretty_assertions::assert_str_eq;
|
use pretty_assertions::assert_str_eq;
|
||||||
|
use rstest::rstest;
|
||||||
use strum::IntoEnumIterator;
|
use strum::IntoEnumIterator;
|
||||||
|
|
||||||
use crate::app::key_binding::DEFAULT_KEYBINDINGS;
|
|
||||||
use crate::app::App;
|
use crate::app::App;
|
||||||
|
use crate::app::key_binding::DEFAULT_KEYBINDINGS;
|
||||||
|
use crate::assert_modal_absent;
|
||||||
use crate::event::Key;
|
use crate::event::Key;
|
||||||
use crate::handlers::radarr_handlers::collections::collection_details_handler::CollectionDetailsHandler;
|
|
||||||
use crate::handlers::KeyEventHandler;
|
use crate::handlers::KeyEventHandler;
|
||||||
|
use crate::handlers::radarr_handlers::collections::collection_details_handler::CollectionDetailsHandler;
|
||||||
use crate::models::radarr_models::CollectionMovie;
|
use crate::models::radarr_models::CollectionMovie;
|
||||||
use crate::models::servarr_data::radarr::radarr_data::{
|
use crate::models::servarr_data::radarr::radarr_data::{
|
||||||
ActiveRadarrBlock, COLLECTION_DETAILS_BLOCKS,
|
ActiveRadarrBlock, COLLECTION_DETAILS_BLOCKS,
|
||||||
};
|
};
|
||||||
|
|
||||||
mod test_handle_submit {
|
mod test_handle_submit {
|
||||||
use bimap::BiMap;
|
use crate::assert_navigation_pushed;
|
||||||
use pretty_assertions::assert_eq;
|
use crate::models::BlockSelectionState;
|
||||||
|
|
||||||
use crate::models::radarr_models::Movie;
|
use crate::models::radarr_models::Movie;
|
||||||
use crate::models::servarr_data::radarr::radarr_data::ADD_MOVIE_SELECTION_BLOCKS;
|
use crate::models::servarr_data::radarr::radarr_data::ADD_MOVIE_SELECTION_BLOCKS;
|
||||||
use crate::models::BlockSelectionState;
|
use bimap::BiMap;
|
||||||
|
use pretty_assertions::assert_eq;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
@@ -27,7 +29,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_collection_details_submit() {
|
fn test_collection_details_submit() {
|
||||||
let mut app = App::default();
|
let mut app = App::test_default();
|
||||||
app
|
app
|
||||||
.data
|
.data
|
||||||
.radarr_data
|
.radarr_data
|
||||||
@@ -42,7 +44,7 @@ mod tests {
|
|||||||
.selected_block
|
.selected_block
|
||||||
.set_index(0, ADD_MOVIE_SELECTION_BLOCKS.len() - 1);
|
.set_index(0, ADD_MOVIE_SELECTION_BLOCKS.len() - 1);
|
||||||
|
|
||||||
CollectionDetailsHandler::with(
|
CollectionDetailsHandler::new(
|
||||||
SUBMIT_KEY,
|
SUBMIT_KEY,
|
||||||
&mut app,
|
&mut app,
|
||||||
ActiveRadarrBlock::CollectionDetails,
|
ActiveRadarrBlock::CollectionDetails,
|
||||||
@@ -50,45 +52,51 @@ mod tests {
|
|||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert_eq!(
|
assert_navigation_pushed!(
|
||||||
app.get_current_route(),
|
app,
|
||||||
(
|
(
|
||||||
ActiveRadarrBlock::AddMoviePrompt,
|
ActiveRadarrBlock::AddMoviePrompt,
|
||||||
Some(ActiveRadarrBlock::CollectionDetails)
|
Some(ActiveRadarrBlock::CollectionDetails)
|
||||||
)
|
)
|
||||||
.into()
|
.into()
|
||||||
);
|
);
|
||||||
assert!(!app
|
assert!(
|
||||||
.data
|
!app
|
||||||
.radarr_data
|
.data
|
||||||
.add_movie_modal
|
.radarr_data
|
||||||
.as_ref()
|
.add_movie_modal
|
||||||
.unwrap()
|
.as_ref()
|
||||||
.monitor_list
|
.unwrap()
|
||||||
.items
|
.monitor_list
|
||||||
.is_empty());
|
.items
|
||||||
|
.is_empty()
|
||||||
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.data.radarr_data.selected_block.get_active_block(),
|
app.data.radarr_data.selected_block.get_active_block(),
|
||||||
ActiveRadarrBlock::AddMovieSelectRootFolder
|
ActiveRadarrBlock::AddMovieSelectRootFolder
|
||||||
);
|
);
|
||||||
assert!(!app
|
assert!(
|
||||||
.data
|
!app
|
||||||
.radarr_data
|
.data
|
||||||
.add_movie_modal
|
.radarr_data
|
||||||
.as_ref()
|
.add_movie_modal
|
||||||
.unwrap()
|
.as_ref()
|
||||||
.minimum_availability_list
|
.unwrap()
|
||||||
.items
|
.minimum_availability_list
|
||||||
.is_empty());
|
.items
|
||||||
assert!(!app
|
.is_empty()
|
||||||
.data
|
);
|
||||||
.radarr_data
|
assert!(
|
||||||
.add_movie_modal
|
!app
|
||||||
.as_ref()
|
.data
|
||||||
.unwrap()
|
.radarr_data
|
||||||
.quality_profile_list
|
.add_movie_modal
|
||||||
.items
|
.as_ref()
|
||||||
.is_empty());
|
.unwrap()
|
||||||
|
.quality_profile_list
|
||||||
|
.items
|
||||||
|
.is_empty()
|
||||||
|
);
|
||||||
assert_str_eq!(
|
assert_str_eq!(
|
||||||
app
|
app
|
||||||
.data
|
.data
|
||||||
@@ -104,7 +112,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_collection_details_submit_no_op_when_not_ready() {
|
fn test_collection_details_submit_no_op_when_not_ready() {
|
||||||
let mut app = App::default();
|
let mut app = App::test_default();
|
||||||
app.is_loading = true;
|
app.is_loading = true;
|
||||||
app.push_navigation_stack(ActiveRadarrBlock::CollectionDetails.into());
|
app.push_navigation_stack(ActiveRadarrBlock::CollectionDetails.into());
|
||||||
app
|
app
|
||||||
@@ -113,7 +121,7 @@ mod tests {
|
|||||||
.collection_movies
|
.collection_movies
|
||||||
.set_items(vec![CollectionMovie::default()]);
|
.set_items(vec![CollectionMovie::default()]);
|
||||||
|
|
||||||
CollectionDetailsHandler::with(
|
CollectionDetailsHandler::new(
|
||||||
SUBMIT_KEY,
|
SUBMIT_KEY,
|
||||||
&mut app,
|
&mut app,
|
||||||
ActiveRadarrBlock::CollectionDetails,
|
ActiveRadarrBlock::CollectionDetails,
|
||||||
@@ -125,12 +133,12 @@ mod tests {
|
|||||||
app.get_current_route(),
|
app.get_current_route(),
|
||||||
ActiveRadarrBlock::CollectionDetails.into()
|
ActiveRadarrBlock::CollectionDetails.into()
|
||||||
);
|
);
|
||||||
assert!(app.data.radarr_data.add_movie_modal.is_none());
|
assert_modal_absent!(app.data.radarr_data.add_movie_modal);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_collection_details_submit_movie_already_in_library() {
|
fn test_collection_details_submit_movie_already_in_library() {
|
||||||
let mut app = App::default();
|
let mut app = App::test_default();
|
||||||
app
|
app
|
||||||
.data
|
.data
|
||||||
.radarr_data
|
.radarr_data
|
||||||
@@ -142,7 +150,7 @@ mod tests {
|
|||||||
.movies
|
.movies
|
||||||
.set_items(vec![Movie::default()]);
|
.set_items(vec![Movie::default()]);
|
||||||
|
|
||||||
CollectionDetailsHandler::with(
|
CollectionDetailsHandler::new(
|
||||||
SUBMIT_KEY,
|
SUBMIT_KEY,
|
||||||
&mut app,
|
&mut app,
|
||||||
ActiveRadarrBlock::CollectionDetails,
|
ActiveRadarrBlock::CollectionDetails,
|
||||||
@@ -150,23 +158,20 @@ mod tests {
|
|||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert_eq!(
|
assert_navigation_pushed!(app, ActiveRadarrBlock::ViewMovieOverview.into());
|
||||||
app.get_current_route(),
|
|
||||||
ActiveRadarrBlock::ViewMovieOverview.into()
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mod test_handle_esc {
|
mod test_handle_esc {
|
||||||
use super::*;
|
use super::*;
|
||||||
use pretty_assertions::assert_eq;
|
use crate::assert_navigation_popped;
|
||||||
use rstest::rstest;
|
use rstest::rstest;
|
||||||
|
|
||||||
const ESC_KEY: Key = DEFAULT_KEYBINDINGS.esc.key;
|
const ESC_KEY: Key = DEFAULT_KEYBINDINGS.esc.key;
|
||||||
|
|
||||||
#[rstest]
|
#[rstest]
|
||||||
fn test_esc_collection_details(#[values(true, false)] is_ready: bool) {
|
fn test_esc_collection_details(#[values(true, false)] is_ready: bool) {
|
||||||
let mut app = App::default();
|
let mut app = App::test_default();
|
||||||
app.is_loading = is_ready;
|
app.is_loading = is_ready;
|
||||||
app.push_navigation_stack(ActiveRadarrBlock::Collections.into());
|
app.push_navigation_stack(ActiveRadarrBlock::Collections.into());
|
||||||
app.push_navigation_stack(ActiveRadarrBlock::CollectionDetails.into());
|
app.push_navigation_stack(ActiveRadarrBlock::CollectionDetails.into());
|
||||||
@@ -176,7 +181,7 @@ mod tests {
|
|||||||
.collection_movies
|
.collection_movies
|
||||||
.set_items(vec![CollectionMovie::default()]);
|
.set_items(vec![CollectionMovie::default()]);
|
||||||
|
|
||||||
CollectionDetailsHandler::with(
|
CollectionDetailsHandler::new(
|
||||||
ESC_KEY,
|
ESC_KEY,
|
||||||
&mut app,
|
&mut app,
|
||||||
ActiveRadarrBlock::CollectionDetails,
|
ActiveRadarrBlock::CollectionDetails,
|
||||||
@@ -184,20 +189,17 @@ mod tests {
|
|||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert_eq!(
|
assert_navigation_popped!(app, ActiveRadarrBlock::Collections.into());
|
||||||
app.get_current_route(),
|
assert_is_empty!(app.data.radarr_data.collection_movies.items);
|
||||||
ActiveRadarrBlock::Collections.into()
|
|
||||||
);
|
|
||||||
assert!(app.data.radarr_data.collection_movies.items.is_empty());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_esc_view_movie_overview() {
|
fn test_esc_view_movie_overview() {
|
||||||
let mut app = App::default();
|
let mut app = App::test_default();
|
||||||
app.push_navigation_stack(ActiveRadarrBlock::CollectionDetails.into());
|
app.push_navigation_stack(ActiveRadarrBlock::CollectionDetails.into());
|
||||||
app.push_navigation_stack(ActiveRadarrBlock::ViewMovieOverview.into());
|
app.push_navigation_stack(ActiveRadarrBlock::ViewMovieOverview.into());
|
||||||
|
|
||||||
CollectionDetailsHandler::with(
|
CollectionDetailsHandler::new(
|
||||||
ESC_KEY,
|
ESC_KEY,
|
||||||
&mut app,
|
&mut app,
|
||||||
ActiveRadarrBlock::ViewMovieOverview,
|
ActiveRadarrBlock::ViewMovieOverview,
|
||||||
@@ -205,10 +207,7 @@ mod tests {
|
|||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert_eq!(
|
assert_navigation_popped!(app, ActiveRadarrBlock::CollectionDetails.into());
|
||||||
app.get_current_route(),
|
|
||||||
ActiveRadarrBlock::CollectionDetails.into()
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -220,7 +219,7 @@ mod tests {
|
|||||||
use crate::models::radarr_models::{Collection, MinimumAvailability};
|
use crate::models::radarr_models::{Collection, MinimumAvailability};
|
||||||
use crate::models::servarr_data::radarr::radarr_data::radarr_test_utils::utils::create_test_radarr_data;
|
use crate::models::servarr_data::radarr::radarr_data::radarr_test_utils::utils::create_test_radarr_data;
|
||||||
use crate::models::servarr_data::radarr::radarr_data::{
|
use crate::models::servarr_data::radarr::radarr_data::{
|
||||||
RadarrData, EDIT_COLLECTION_SELECTION_BLOCKS,
|
EDIT_COLLECTION_SELECTION_BLOCKS, RadarrData,
|
||||||
};
|
};
|
||||||
use crate::test_edit_collection_key;
|
use crate::test_edit_collection_key;
|
||||||
|
|
||||||
@@ -237,7 +236,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_edit_key_no_op_when_not_ready() {
|
fn test_edit_key_no_op_when_not_ready() {
|
||||||
let mut app = App::default();
|
let mut app = App::test_default();
|
||||||
app.is_loading = true;
|
app.is_loading = true;
|
||||||
app.push_navigation_stack(ActiveRadarrBlock::CollectionDetails.into());
|
app.push_navigation_stack(ActiveRadarrBlock::CollectionDetails.into());
|
||||||
let mut radarr_data = create_test_radarr_data();
|
let mut radarr_data = create_test_radarr_data();
|
||||||
@@ -251,7 +250,7 @@ mod tests {
|
|||||||
}]);
|
}]);
|
||||||
app.data.radarr_data = radarr_data;
|
app.data.radarr_data = radarr_data;
|
||||||
|
|
||||||
CollectionDetailsHandler::with(
|
CollectionDetailsHandler::new(
|
||||||
DEFAULT_KEYBINDINGS.edit.key,
|
DEFAULT_KEYBINDINGS.edit.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
ActiveRadarrBlock::CollectionDetails,
|
ActiveRadarrBlock::CollectionDetails,
|
||||||
@@ -263,7 +262,7 @@ mod tests {
|
|||||||
app.get_current_route(),
|
app.get_current_route(),
|
||||||
ActiveRadarrBlock::CollectionDetails.into()
|
ActiveRadarrBlock::CollectionDetails.into()
|
||||||
);
|
);
|
||||||
assert!(app.data.radarr_data.edit_collection_modal.is_none());
|
assert_modal_absent!(app.data.radarr_data.edit_collection_modal);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -278,12 +277,31 @@ mod tests {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
fn test_collection_details_handler_ignore_special_keys(
|
||||||
|
#[values(true, false)] ignore_special_keys_for_textbox_input: bool,
|
||||||
|
) {
|
||||||
|
let mut app = App::test_default();
|
||||||
|
app.ignore_special_keys_for_textbox_input = ignore_special_keys_for_textbox_input;
|
||||||
|
let handler = CollectionDetailsHandler::new(
|
||||||
|
DEFAULT_KEYBINDINGS.esc.key,
|
||||||
|
&mut app,
|
||||||
|
ActiveRadarrBlock::default(),
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
handler.ignore_special_keys(),
|
||||||
|
ignore_special_keys_for_textbox_input
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_collection_details_handler_not_ready_when_loading() {
|
fn test_collection_details_handler_not_ready_when_loading() {
|
||||||
let mut app = App::default();
|
let mut app = App::test_default();
|
||||||
app.is_loading = true;
|
app.is_loading = true;
|
||||||
|
|
||||||
let handler = CollectionDetailsHandler::with(
|
let handler = CollectionDetailsHandler::new(
|
||||||
DEFAULT_KEYBINDINGS.esc.key,
|
DEFAULT_KEYBINDINGS.esc.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
ActiveRadarrBlock::CollectionDetails,
|
ActiveRadarrBlock::CollectionDetails,
|
||||||
@@ -295,10 +313,10 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_collection_details_handler_not_ready_when_collection_movies_is_empty() {
|
fn test_collection_details_handler_not_ready_when_collection_movies_is_empty() {
|
||||||
let mut app = App::default();
|
let mut app = App::test_default();
|
||||||
app.is_loading = false;
|
app.is_loading = false;
|
||||||
|
|
||||||
let handler = CollectionDetailsHandler::with(
|
let handler = CollectionDetailsHandler::new(
|
||||||
DEFAULT_KEYBINDINGS.esc.key,
|
DEFAULT_KEYBINDINGS.esc.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
ActiveRadarrBlock::CollectionDetails,
|
ActiveRadarrBlock::CollectionDetails,
|
||||||
@@ -310,7 +328,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_collection_details_handler_ready_when_not_loading_and_collection_movies_is_not_empty() {
|
fn test_collection_details_handler_ready_when_not_loading_and_collection_movies_is_not_empty() {
|
||||||
let mut app = App::default();
|
let mut app = App::test_default();
|
||||||
app.is_loading = false;
|
app.is_loading = false;
|
||||||
app
|
app
|
||||||
.data
|
.data
|
||||||
@@ -318,7 +336,7 @@ mod tests {
|
|||||||
.collection_movies
|
.collection_movies
|
||||||
.set_items(vec![CollectionMovie::default()]);
|
.set_items(vec![CollectionMovie::default()]);
|
||||||
|
|
||||||
let handler = CollectionDetailsHandler::with(
|
let handler = CollectionDetailsHandler::new(
|
||||||
DEFAULT_KEYBINDINGS.esc.key,
|
DEFAULT_KEYBINDINGS.esc.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
ActiveRadarrBlock::CollectionDetails,
|
ActiveRadarrBlock::CollectionDetails,
|
||||||
|
|||||||
@@ -7,16 +7,18 @@ mod tests {
|
|||||||
use rstest::rstest;
|
use rstest::rstest;
|
||||||
use strum::IntoEnumIterator;
|
use strum::IntoEnumIterator;
|
||||||
|
|
||||||
use crate::app::key_binding::DEFAULT_KEYBINDINGS;
|
|
||||||
use crate::app::App;
|
use crate::app::App;
|
||||||
|
use crate::app::key_binding::DEFAULT_KEYBINDINGS;
|
||||||
|
use crate::assert_modal_absent;
|
||||||
|
use crate::assert_navigation_pushed;
|
||||||
use crate::event::Key;
|
use crate::event::Key;
|
||||||
use crate::handlers::radarr_handlers::collections::{
|
|
||||||
collections_sorting_options, CollectionsHandler,
|
|
||||||
};
|
|
||||||
use crate::handlers::KeyEventHandler;
|
use crate::handlers::KeyEventHandler;
|
||||||
|
use crate::handlers::radarr_handlers::collections::{
|
||||||
|
CollectionsHandler, collections_sorting_options,
|
||||||
|
};
|
||||||
use crate::models::radarr_models::{Collection, CollectionMovie};
|
use crate::models::radarr_models::{Collection, CollectionMovie};
|
||||||
use crate::models::servarr_data::radarr::radarr_data::{
|
use crate::models::servarr_data::radarr::radarr_data::{
|
||||||
ActiveRadarrBlock, COLLECTIONS_BLOCKS, COLLECTION_DETAILS_BLOCKS, EDIT_COLLECTION_BLOCKS,
|
ActiveRadarrBlock, COLLECTION_DETAILS_BLOCKS, COLLECTIONS_BLOCKS, EDIT_COLLECTION_BLOCKS,
|
||||||
};
|
};
|
||||||
use crate::test_handler_delegation;
|
use crate::test_handler_delegation;
|
||||||
|
|
||||||
@@ -25,14 +27,15 @@ mod tests {
|
|||||||
use rstest::rstest;
|
use rstest::rstest;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use crate::assert_navigation_pushed;
|
||||||
|
|
||||||
#[rstest]
|
#[rstest]
|
||||||
fn test_collections_tab_left(#[values(true, false)] is_ready: bool) {
|
fn test_collections_tab_left(#[values(true, false)] is_ready: bool) {
|
||||||
let mut app = App::default();
|
let mut app = App::test_default();
|
||||||
app.is_loading = is_ready;
|
app.is_loading = is_ready;
|
||||||
app.data.radarr_data.main_tabs.set_index(1);
|
app.data.radarr_data.main_tabs.set_index(1);
|
||||||
|
|
||||||
CollectionsHandler::with(
|
CollectionsHandler::new(
|
||||||
DEFAULT_KEYBINDINGS.left.key,
|
DEFAULT_KEYBINDINGS.left.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
ActiveRadarrBlock::Collections,
|
ActiveRadarrBlock::Collections,
|
||||||
@@ -44,16 +47,16 @@ mod tests {
|
|||||||
app.data.radarr_data.main_tabs.get_active_route(),
|
app.data.radarr_data.main_tabs.get_active_route(),
|
||||||
ActiveRadarrBlock::Movies.into()
|
ActiveRadarrBlock::Movies.into()
|
||||||
);
|
);
|
||||||
assert_eq!(app.get_current_route(), ActiveRadarrBlock::Movies.into());
|
assert_navigation_pushed!(app, ActiveRadarrBlock::Movies.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rstest]
|
#[rstest]
|
||||||
fn test_collections_tab_right(#[values(true, false)] is_ready: bool) {
|
fn test_collections_tab_right(#[values(true, false)] is_ready: bool) {
|
||||||
let mut app = App::default();
|
let mut app = App::test_default();
|
||||||
app.is_loading = is_ready;
|
app.is_loading = is_ready;
|
||||||
app.data.radarr_data.main_tabs.set_index(1);
|
app.data.radarr_data.main_tabs.set_index(1);
|
||||||
|
|
||||||
CollectionsHandler::with(
|
CollectionsHandler::new(
|
||||||
DEFAULT_KEYBINDINGS.right.key,
|
DEFAULT_KEYBINDINGS.right.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
ActiveRadarrBlock::Collections,
|
ActiveRadarrBlock::Collections,
|
||||||
@@ -65,16 +68,16 @@ mod tests {
|
|||||||
app.data.radarr_data.main_tabs.get_active_route(),
|
app.data.radarr_data.main_tabs.get_active_route(),
|
||||||
ActiveRadarrBlock::Downloads.into()
|
ActiveRadarrBlock::Downloads.into()
|
||||||
);
|
);
|
||||||
assert_eq!(app.get_current_route(), ActiveRadarrBlock::Downloads.into());
|
assert_navigation_pushed!(app, ActiveRadarrBlock::Downloads.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rstest]
|
#[rstest]
|
||||||
fn test_left_right_update_all_collections_prompt_toggle(
|
fn test_left_right_update_all_collections_prompt_toggle(
|
||||||
#[values(DEFAULT_KEYBINDINGS.left.key, DEFAULT_KEYBINDINGS.right.key)] key: Key,
|
#[values(DEFAULT_KEYBINDINGS.left.key, DEFAULT_KEYBINDINGS.right.key)] key: Key,
|
||||||
) {
|
) {
|
||||||
let mut app = App::default();
|
let mut app = App::test_default();
|
||||||
|
|
||||||
CollectionsHandler::with(
|
CollectionsHandler::new(
|
||||||
key,
|
key,
|
||||||
&mut app,
|
&mut app,
|
||||||
ActiveRadarrBlock::UpdateAllCollectionsPrompt,
|
ActiveRadarrBlock::UpdateAllCollectionsPrompt,
|
||||||
@@ -84,7 +87,7 @@ mod tests {
|
|||||||
|
|
||||||
assert!(app.data.radarr_data.prompt_confirm);
|
assert!(app.data.radarr_data.prompt_confirm);
|
||||||
|
|
||||||
CollectionsHandler::with(
|
CollectionsHandler::new(
|
||||||
key,
|
key,
|
||||||
&mut app,
|
&mut app,
|
||||||
ActiveRadarrBlock::UpdateAllCollectionsPrompt,
|
ActiveRadarrBlock::UpdateAllCollectionsPrompt,
|
||||||
@@ -97,9 +100,9 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
mod test_handle_submit {
|
mod test_handle_submit {
|
||||||
use pretty_assertions::assert_eq;
|
use crate::assert_navigation_popped;
|
||||||
|
|
||||||
use crate::network::radarr_network::RadarrEvent;
|
use crate::network::radarr_network::RadarrEvent;
|
||||||
|
use pretty_assertions::assert_eq;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
@@ -107,24 +110,21 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_collections_submit() {
|
fn test_collections_submit() {
|
||||||
let mut app = App::default();
|
let mut app = App::test_default();
|
||||||
app
|
app
|
||||||
.data
|
.data
|
||||||
.radarr_data
|
.radarr_data
|
||||||
.collections
|
.collections
|
||||||
.set_items(vec![Collection::default()]);
|
.set_items(vec![Collection::default()]);
|
||||||
|
|
||||||
CollectionsHandler::with(SUBMIT_KEY, &mut app, ActiveRadarrBlock::Collections, None).handle();
|
CollectionsHandler::new(SUBMIT_KEY, &mut app, ActiveRadarrBlock::Collections, None).handle();
|
||||||
|
|
||||||
assert_eq!(
|
assert_navigation_pushed!(app, ActiveRadarrBlock::CollectionDetails.into());
|
||||||
app.get_current_route(),
|
|
||||||
ActiveRadarrBlock::CollectionDetails.into()
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_collections_submit_no_op_when_not_ready() {
|
fn test_collections_submit_no_op_when_not_ready() {
|
||||||
let mut app = App::default();
|
let mut app = App::test_default();
|
||||||
app.is_loading = true;
|
app.is_loading = true;
|
||||||
app.push_navigation_stack(ActiveRadarrBlock::Collections.into());
|
app.push_navigation_stack(ActiveRadarrBlock::Collections.into());
|
||||||
app
|
app
|
||||||
@@ -133,7 +133,7 @@ mod tests {
|
|||||||
.collections
|
.collections
|
||||||
.set_items(vec![Collection::default()]);
|
.set_items(vec![Collection::default()]);
|
||||||
|
|
||||||
CollectionsHandler::with(SUBMIT_KEY, &mut app, ActiveRadarrBlock::Collections, None).handle();
|
CollectionsHandler::new(SUBMIT_KEY, &mut app, ActiveRadarrBlock::Collections, None).handle();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.get_current_route(),
|
app.get_current_route(),
|
||||||
@@ -143,7 +143,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_update_all_collections_prompt_confirm_submit() {
|
fn test_update_all_collections_prompt_confirm_submit() {
|
||||||
let mut app = App::default();
|
let mut app = App::test_default();
|
||||||
app
|
app
|
||||||
.data
|
.data
|
||||||
.radarr_data
|
.radarr_data
|
||||||
@@ -153,7 +153,7 @@ mod tests {
|
|||||||
app.push_navigation_stack(ActiveRadarrBlock::Collections.into());
|
app.push_navigation_stack(ActiveRadarrBlock::Collections.into());
|
||||||
app.push_navigation_stack(ActiveRadarrBlock::UpdateAllCollectionsPrompt.into());
|
app.push_navigation_stack(ActiveRadarrBlock::UpdateAllCollectionsPrompt.into());
|
||||||
|
|
||||||
CollectionsHandler::with(
|
CollectionsHandler::new(
|
||||||
SUBMIT_KEY,
|
SUBMIT_KEY,
|
||||||
&mut app,
|
&mut app,
|
||||||
ActiveRadarrBlock::UpdateAllCollectionsPrompt,
|
ActiveRadarrBlock::UpdateAllCollectionsPrompt,
|
||||||
@@ -166,15 +166,12 @@ mod tests {
|
|||||||
app.data.radarr_data.prompt_confirm_action,
|
app.data.radarr_data.prompt_confirm_action,
|
||||||
Some(RadarrEvent::UpdateCollections)
|
Some(RadarrEvent::UpdateCollections)
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_navigation_popped!(app, ActiveRadarrBlock::Collections.into());
|
||||||
app.get_current_route(),
|
|
||||||
ActiveRadarrBlock::Collections.into()
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_update_all_collections_prompt_decline_submit() {
|
fn test_update_all_collections_prompt_decline_submit() {
|
||||||
let mut app = App::default();
|
let mut app = App::test_default();
|
||||||
app
|
app
|
||||||
.data
|
.data
|
||||||
.radarr_data
|
.radarr_data
|
||||||
@@ -183,7 +180,7 @@ mod tests {
|
|||||||
app.push_navigation_stack(ActiveRadarrBlock::Collections.into());
|
app.push_navigation_stack(ActiveRadarrBlock::Collections.into());
|
||||||
app.push_navigation_stack(ActiveRadarrBlock::UpdateAllCollectionsPrompt.into());
|
app.push_navigation_stack(ActiveRadarrBlock::UpdateAllCollectionsPrompt.into());
|
||||||
|
|
||||||
CollectionsHandler::with(
|
CollectionsHandler::new(
|
||||||
SUBMIT_KEY,
|
SUBMIT_KEY,
|
||||||
&mut app,
|
&mut app,
|
||||||
ActiveRadarrBlock::UpdateAllCollectionsPrompt,
|
ActiveRadarrBlock::UpdateAllCollectionsPrompt,
|
||||||
@@ -192,17 +189,13 @@ mod tests {
|
|||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert!(!app.data.radarr_data.prompt_confirm);
|
assert!(!app.data.radarr_data.prompt_confirm);
|
||||||
assert_eq!(app.data.radarr_data.prompt_confirm_action, None);
|
assert_none!(app.data.radarr_data.prompt_confirm_action);
|
||||||
assert_eq!(
|
assert_navigation_popped!(app, ActiveRadarrBlock::Collections.into());
|
||||||
app.get_current_route(),
|
|
||||||
ActiveRadarrBlock::Collections.into()
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mod test_handle_esc {
|
mod test_handle_esc {
|
||||||
use pretty_assertions::assert_eq;
|
use crate::assert_navigation_popped;
|
||||||
|
|
||||||
use crate::models::servarr_data::radarr::radarr_data::radarr_test_utils::utils::create_test_radarr_data;
|
use crate::models::servarr_data::radarr::radarr_data::radarr_test_utils::utils::create_test_radarr_data;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
@@ -211,12 +204,12 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_update_all_collections_prompt_block_esc() {
|
fn test_update_all_collections_prompt_block_esc() {
|
||||||
let mut app = App::default();
|
let mut app = App::test_default();
|
||||||
app.push_navigation_stack(ActiveRadarrBlock::Collections.into());
|
app.push_navigation_stack(ActiveRadarrBlock::Collections.into());
|
||||||
app.push_navigation_stack(ActiveRadarrBlock::UpdateAllCollectionsPrompt.into());
|
app.push_navigation_stack(ActiveRadarrBlock::UpdateAllCollectionsPrompt.into());
|
||||||
app.data.radarr_data.prompt_confirm = true;
|
app.data.radarr_data.prompt_confirm = true;
|
||||||
|
|
||||||
CollectionsHandler::with(
|
CollectionsHandler::new(
|
||||||
ESC_KEY,
|
ESC_KEY,
|
||||||
&mut app,
|
&mut app,
|
||||||
ActiveRadarrBlock::UpdateAllCollectionsPrompt,
|
ActiveRadarrBlock::UpdateAllCollectionsPrompt,
|
||||||
@@ -224,29 +217,23 @@ mod tests {
|
|||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert_eq!(
|
assert_navigation_popped!(app, ActiveRadarrBlock::Collections.into());
|
||||||
app.get_current_route(),
|
|
||||||
ActiveRadarrBlock::Collections.into()
|
|
||||||
);
|
|
||||||
assert!(!app.data.radarr_data.prompt_confirm);
|
assert!(!app.data.radarr_data.prompt_confirm);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rstest]
|
#[rstest]
|
||||||
fn test_default_esc(#[values(true, false)] is_ready: bool) {
|
fn test_default_esc(#[values(true, false)] is_ready: bool) {
|
||||||
let mut app = App::default();
|
let mut app = App::test_default();
|
||||||
app.is_loading = is_ready;
|
app.is_loading = is_ready;
|
||||||
app.error = "test error".to_owned().into();
|
app.error = "test error".to_owned().into();
|
||||||
app.push_navigation_stack(ActiveRadarrBlock::Collections.into());
|
app.push_navigation_stack(ActiveRadarrBlock::Collections.into());
|
||||||
app.push_navigation_stack(ActiveRadarrBlock::Collections.into());
|
app.push_navigation_stack(ActiveRadarrBlock::Collections.into());
|
||||||
app.data.radarr_data = create_test_radarr_data();
|
app.data.radarr_data = create_test_radarr_data();
|
||||||
|
|
||||||
CollectionsHandler::with(ESC_KEY, &mut app, ActiveRadarrBlock::Collections, None).handle();
|
CollectionsHandler::new(ESC_KEY, &mut app, ActiveRadarrBlock::Collections, None).handle();
|
||||||
|
|
||||||
assert_eq!(
|
assert_navigation_popped!(app, ActiveRadarrBlock::Collections.into());
|
||||||
app.get_current_route(),
|
assert_is_empty!(app.error.text);
|
||||||
ActiveRadarrBlock::Collections.into()
|
|
||||||
);
|
|
||||||
assert!(app.error.text.is_empty());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -258,10 +245,10 @@ mod tests {
|
|||||||
use crate::models::radarr_models::MinimumAvailability;
|
use crate::models::radarr_models::MinimumAvailability;
|
||||||
use crate::models::servarr_data::radarr::radarr_data::radarr_test_utils::utils::create_test_radarr_data;
|
use crate::models::servarr_data::radarr::radarr_data::radarr_test_utils::utils::create_test_radarr_data;
|
||||||
use crate::models::servarr_data::radarr::radarr_data::{
|
use crate::models::servarr_data::radarr::radarr_data::{
|
||||||
RadarrData, EDIT_COLLECTION_SELECTION_BLOCKS,
|
EDIT_COLLECTION_SELECTION_BLOCKS, RadarrData,
|
||||||
};
|
};
|
||||||
use crate::network::radarr_network::RadarrEvent;
|
use crate::network::radarr_network::RadarrEvent;
|
||||||
use crate::test_edit_collection_key;
|
use crate::{assert_navigation_popped, test_edit_collection_key};
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
@@ -272,7 +259,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_collection_edit_key_no_op_when_not_ready() {
|
fn test_collection_edit_key_no_op_when_not_ready() {
|
||||||
let mut app = App::default();
|
let mut app = App::test_default();
|
||||||
app.is_loading = true;
|
app.is_loading = true;
|
||||||
app.push_navigation_stack(ActiveRadarrBlock::Collections.into());
|
app.push_navigation_stack(ActiveRadarrBlock::Collections.into());
|
||||||
let mut radarr_data = create_test_radarr_data();
|
let mut radarr_data = create_test_radarr_data();
|
||||||
@@ -286,7 +273,7 @@ mod tests {
|
|||||||
}]);
|
}]);
|
||||||
app.data.radarr_data = radarr_data;
|
app.data.radarr_data = radarr_data;
|
||||||
|
|
||||||
CollectionsHandler::with(
|
CollectionsHandler::new(
|
||||||
DEFAULT_KEYBINDINGS.edit.key,
|
DEFAULT_KEYBINDINGS.edit.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
ActiveRadarrBlock::Collections,
|
ActiveRadarrBlock::Collections,
|
||||||
@@ -298,19 +285,19 @@ mod tests {
|
|||||||
app.get_current_route(),
|
app.get_current_route(),
|
||||||
ActiveRadarrBlock::Collections.into()
|
ActiveRadarrBlock::Collections.into()
|
||||||
);
|
);
|
||||||
assert!(app.data.radarr_data.edit_collection_modal.is_none());
|
assert_modal_absent!(app.data.radarr_data.edit_collection_modal);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_update_key() {
|
fn test_update_key() {
|
||||||
let mut app = App::default();
|
let mut app = App::test_default();
|
||||||
app
|
app
|
||||||
.data
|
.data
|
||||||
.radarr_data
|
.radarr_data
|
||||||
.collections
|
.collections
|
||||||
.set_items(vec![Collection::default()]);
|
.set_items(vec![Collection::default()]);
|
||||||
|
|
||||||
CollectionsHandler::with(
|
CollectionsHandler::new(
|
||||||
DEFAULT_KEYBINDINGS.update.key,
|
DEFAULT_KEYBINDINGS.update.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
ActiveRadarrBlock::Collections,
|
ActiveRadarrBlock::Collections,
|
||||||
@@ -318,15 +305,12 @@ mod tests {
|
|||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert_eq!(
|
assert_navigation_pushed!(app, ActiveRadarrBlock::UpdateAllCollectionsPrompt.into());
|
||||||
app.get_current_route(),
|
|
||||||
ActiveRadarrBlock::UpdateAllCollectionsPrompt.into()
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_update_key_no_op_when_not_ready() {
|
fn test_update_key_no_op_when_not_ready() {
|
||||||
let mut app = App::default();
|
let mut app = App::test_default();
|
||||||
app.is_loading = true;
|
app.is_loading = true;
|
||||||
app.push_navigation_stack(ActiveRadarrBlock::Collections.into());
|
app.push_navigation_stack(ActiveRadarrBlock::Collections.into());
|
||||||
app
|
app
|
||||||
@@ -335,7 +319,7 @@ mod tests {
|
|||||||
.collections
|
.collections
|
||||||
.set_items(vec![Collection::default()]);
|
.set_items(vec![Collection::default()]);
|
||||||
|
|
||||||
CollectionsHandler::with(
|
CollectionsHandler::new(
|
||||||
DEFAULT_KEYBINDINGS.update.key,
|
DEFAULT_KEYBINDINGS.update.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
ActiveRadarrBlock::Collections,
|
ActiveRadarrBlock::Collections,
|
||||||
@@ -351,7 +335,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_refresh_collections_key() {
|
fn test_refresh_collections_key() {
|
||||||
let mut app = App::default();
|
let mut app = App::test_default();
|
||||||
app.push_navigation_stack(ActiveRadarrBlock::Collections.into());
|
app.push_navigation_stack(ActiveRadarrBlock::Collections.into());
|
||||||
app
|
app
|
||||||
.data
|
.data
|
||||||
@@ -359,7 +343,7 @@ mod tests {
|
|||||||
.collections
|
.collections
|
||||||
.set_items(vec![Collection::default()]);
|
.set_items(vec![Collection::default()]);
|
||||||
|
|
||||||
CollectionsHandler::with(
|
CollectionsHandler::new(
|
||||||
DEFAULT_KEYBINDINGS.refresh.key,
|
DEFAULT_KEYBINDINGS.refresh.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
ActiveRadarrBlock::Collections,
|
ActiveRadarrBlock::Collections,
|
||||||
@@ -367,16 +351,13 @@ mod tests {
|
|||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert_eq!(
|
assert_navigation_pushed!(app, ActiveRadarrBlock::Collections.into());
|
||||||
app.get_current_route(),
|
|
||||||
ActiveRadarrBlock::Collections.into()
|
|
||||||
);
|
|
||||||
assert!(app.should_refresh);
|
assert!(app.should_refresh);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_refresh_collections_key_no_op_when_not_ready() {
|
fn test_refresh_collections_key_no_op_when_not_ready() {
|
||||||
let mut app = App::default();
|
let mut app = App::test_default();
|
||||||
app.is_loading = true;
|
app.is_loading = true;
|
||||||
app.push_navigation_stack(ActiveRadarrBlock::Collections.into());
|
app.push_navigation_stack(ActiveRadarrBlock::Collections.into());
|
||||||
app
|
app
|
||||||
@@ -385,7 +366,7 @@ mod tests {
|
|||||||
.collections
|
.collections
|
||||||
.set_items(vec![Collection::default()]);
|
.set_items(vec![Collection::default()]);
|
||||||
|
|
||||||
CollectionsHandler::with(
|
CollectionsHandler::new(
|
||||||
DEFAULT_KEYBINDINGS.refresh.key,
|
DEFAULT_KEYBINDINGS.refresh.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
ActiveRadarrBlock::Collections,
|
ActiveRadarrBlock::Collections,
|
||||||
@@ -402,7 +383,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_update_all_collections_prompt_confirm_confirm() {
|
fn test_update_all_collections_prompt_confirm_confirm() {
|
||||||
let mut app = App::default();
|
let mut app = App::test_default();
|
||||||
app
|
app
|
||||||
.data
|
.data
|
||||||
.radarr_data
|
.radarr_data
|
||||||
@@ -411,7 +392,7 @@ mod tests {
|
|||||||
app.push_navigation_stack(ActiveRadarrBlock::Collections.into());
|
app.push_navigation_stack(ActiveRadarrBlock::Collections.into());
|
||||||
app.push_navigation_stack(ActiveRadarrBlock::UpdateAllCollectionsPrompt.into());
|
app.push_navigation_stack(ActiveRadarrBlock::UpdateAllCollectionsPrompt.into());
|
||||||
|
|
||||||
CollectionsHandler::with(
|
CollectionsHandler::new(
|
||||||
DEFAULT_KEYBINDINGS.confirm.key,
|
DEFAULT_KEYBINDINGS.confirm.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
ActiveRadarrBlock::UpdateAllCollectionsPrompt,
|
ActiveRadarrBlock::UpdateAllCollectionsPrompt,
|
||||||
@@ -424,10 +405,7 @@ mod tests {
|
|||||||
app.data.radarr_data.prompt_confirm_action,
|
app.data.radarr_data.prompt_confirm_action,
|
||||||
Some(RadarrEvent::UpdateCollections)
|
Some(RadarrEvent::UpdateCollections)
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_navigation_popped!(app, ActiveRadarrBlock::Collections.into());
|
||||||
app.get_current_route(),
|
|
||||||
ActiveRadarrBlock::Collections.into()
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -589,12 +567,31 @@ mod tests {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
fn test_collections_handler_ignore_special_keys(
|
||||||
|
#[values(true, false)] ignore_special_keys_for_textbox_input: bool,
|
||||||
|
) {
|
||||||
|
let mut app = App::test_default();
|
||||||
|
app.ignore_special_keys_for_textbox_input = ignore_special_keys_for_textbox_input;
|
||||||
|
let handler = CollectionsHandler::new(
|
||||||
|
DEFAULT_KEYBINDINGS.esc.key,
|
||||||
|
&mut app,
|
||||||
|
ActiveRadarrBlock::default(),
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
handler.ignore_special_keys(),
|
||||||
|
ignore_special_keys_for_textbox_input
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_collections_handler_not_ready_when_loading() {
|
fn test_collections_handler_not_ready_when_loading() {
|
||||||
let mut app = App::default();
|
let mut app = App::test_default();
|
||||||
app.is_loading = true;
|
app.is_loading = true;
|
||||||
|
|
||||||
let handler = CollectionsHandler::with(
|
let handler = CollectionsHandler::new(
|
||||||
DEFAULT_KEYBINDINGS.esc.key,
|
DEFAULT_KEYBINDINGS.esc.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
ActiveRadarrBlock::Collections,
|
ActiveRadarrBlock::Collections,
|
||||||
@@ -606,10 +603,10 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_collections_handler_not_ready_when_collections_is_empty() {
|
fn test_collections_handler_not_ready_when_collections_is_empty() {
|
||||||
let mut app = App::default();
|
let mut app = App::test_default();
|
||||||
app.is_loading = false;
|
app.is_loading = false;
|
||||||
|
|
||||||
let handler = CollectionsHandler::with(
|
let handler = CollectionsHandler::new(
|
||||||
DEFAULT_KEYBINDINGS.esc.key,
|
DEFAULT_KEYBINDINGS.esc.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
ActiveRadarrBlock::Collections,
|
ActiveRadarrBlock::Collections,
|
||||||
@@ -621,7 +618,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_collections_handler_ready_when_not_loading_and_collections_is_not_empty() {
|
fn test_collections_handler_ready_when_not_loading_and_collections_is_not_empty() {
|
||||||
let mut app = App::default();
|
let mut app = App::test_default();
|
||||||
app.is_loading = false;
|
app.is_loading = false;
|
||||||
app
|
app
|
||||||
.data
|
.data
|
||||||
@@ -629,7 +626,7 @@ mod tests {
|
|||||||
.collections
|
.collections
|
||||||
.set_items(vec![Collection::default()]);
|
.set_items(vec![Collection::default()]);
|
||||||
|
|
||||||
let handler = CollectionsHandler::with(
|
let handler = CollectionsHandler::new(
|
||||||
DEFAULT_KEYBINDINGS.esc.key,
|
DEFAULT_KEYBINDINGS.esc.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
ActiveRadarrBlock::Collections,
|
ActiveRadarrBlock::Collections,
|
||||||
@@ -644,7 +641,7 @@ mod tests {
|
|||||||
Collection {
|
Collection {
|
||||||
id: 3,
|
id: 3,
|
||||||
title: "test 1".into(),
|
title: "test 1".into(),
|
||||||
movies: Some(iter::repeat(CollectionMovie::default()).take(3).collect()),
|
movies: Some(iter::repeat_n(CollectionMovie::default(), 3).collect()),
|
||||||
root_folder_path: Some("/nfs/movies".into()),
|
root_folder_path: Some("/nfs/movies".into()),
|
||||||
quality_profile_id: 1,
|
quality_profile_id: 1,
|
||||||
search_on_add: false,
|
search_on_add: false,
|
||||||
@@ -654,7 +651,7 @@ mod tests {
|
|||||||
Collection {
|
Collection {
|
||||||
id: 2,
|
id: 2,
|
||||||
title: "test 2".into(),
|
title: "test 2".into(),
|
||||||
movies: Some(iter::repeat(CollectionMovie::default()).take(7).collect()),
|
movies: Some(iter::repeat_n(CollectionMovie::default(), 7).collect()),
|
||||||
root_folder_path: Some("/htpc/movies".into()),
|
root_folder_path: Some("/htpc/movies".into()),
|
||||||
quality_profile_id: 3,
|
quality_profile_id: 3,
|
||||||
search_on_add: true,
|
search_on_add: true,
|
||||||
@@ -664,7 +661,7 @@ mod tests {
|
|||||||
Collection {
|
Collection {
|
||||||
id: 1,
|
id: 1,
|
||||||
title: "test 3".into(),
|
title: "test 3".into(),
|
||||||
movies: Some(iter::repeat(CollectionMovie::default()).take(1).collect()),
|
movies: Some(iter::repeat_n(CollectionMovie::default(), 1).collect()),
|
||||||
root_folder_path: Some("/nfs/some/stupidly/long/path/to/test/with".into()),
|
root_folder_path: Some("/nfs/some/stupidly/long/path/to/test/with".into()),
|
||||||
quality_profile_id: 1,
|
quality_profile_id: 1,
|
||||||
search_on_add: false,
|
search_on_add: false,
|
||||||
|
|||||||
@@ -1,13 +1,12 @@
|
|||||||
use crate::app::key_binding::DEFAULT_KEYBINDINGS;
|
|
||||||
use crate::app::App;
|
use crate::app::App;
|
||||||
use crate::event::Key;
|
use crate::event::Key;
|
||||||
use crate::handlers::{handle_prompt_toggle, KeyEventHandler};
|
use crate::handlers::{KeyEventHandler, handle_prompt_toggle};
|
||||||
|
use crate::models::Scrollable;
|
||||||
use crate::models::radarr_models::EditCollectionParams;
|
use crate::models::radarr_models::EditCollectionParams;
|
||||||
use crate::models::servarr_data::radarr::modals::EditCollectionModal;
|
use crate::models::servarr_data::radarr::modals::EditCollectionModal;
|
||||||
use crate::models::servarr_data::radarr::radarr_data::{ActiveRadarrBlock, EDIT_COLLECTION_BLOCKS};
|
use crate::models::servarr_data::radarr::radarr_data::{ActiveRadarrBlock, EDIT_COLLECTION_BLOCKS};
|
||||||
use crate::models::Scrollable;
|
|
||||||
use crate::network::radarr_network::RadarrEvent;
|
use crate::network::radarr_network::RadarrEvent;
|
||||||
use crate::{handle_text_box_keys, handle_text_box_left_right_keys};
|
use crate::{handle_text_box_keys, handle_text_box_left_right_keys, matches_key};
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
#[path = "edit_collection_handler_tests.rs"]
|
#[path = "edit_collection_handler_tests.rs"]
|
||||||
@@ -20,8 +19,15 @@ pub(super) struct EditCollectionHandler<'a, 'b> {
|
|||||||
context: Option<ActiveRadarrBlock>,
|
context: Option<ActiveRadarrBlock>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'b> EditCollectionHandler<'a, 'b> {
|
impl EditCollectionHandler<'_, '_> {
|
||||||
fn build_edit_collection_params(&mut self) -> EditCollectionParams {
|
fn build_edit_collection_params(&mut self) -> EditCollectionParams {
|
||||||
|
let edit_collection_modal = self
|
||||||
|
.app
|
||||||
|
.data
|
||||||
|
.radarr_data
|
||||||
|
.edit_collection_modal
|
||||||
|
.take()
|
||||||
|
.expect("EditCollectionModal is None");
|
||||||
let collection_id = self.app.data.radarr_data.collections.current_selection().id;
|
let collection_id = self.app.data.radarr_data.collections.current_selection().id;
|
||||||
let EditCollectionModal {
|
let EditCollectionModal {
|
||||||
path,
|
path,
|
||||||
@@ -29,13 +35,7 @@ impl<'a, 'b> EditCollectionHandler<'a, 'b> {
|
|||||||
minimum_availability_list,
|
minimum_availability_list,
|
||||||
monitored,
|
monitored,
|
||||||
quality_profile_list,
|
quality_profile_list,
|
||||||
} = self
|
} = edit_collection_modal;
|
||||||
.app
|
|
||||||
.data
|
|
||||||
.radarr_data
|
|
||||||
.edit_collection_modal
|
|
||||||
.as_ref()
|
|
||||||
.unwrap();
|
|
||||||
let quality_profile = quality_profile_list.current_selection();
|
let quality_profile = quality_profile_list.current_selection();
|
||||||
let quality_profile_id = *self
|
let quality_profile_id = *self
|
||||||
.app
|
.app
|
||||||
@@ -48,15 +48,13 @@ impl<'a, 'b> EditCollectionHandler<'a, 'b> {
|
|||||||
.next()
|
.next()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let root_folder_path: String = path.text.clone();
|
let root_folder_path = path.text;
|
||||||
let monitored = monitored.unwrap_or_default();
|
|
||||||
let search_on_add = search_on_add.unwrap_or_default();
|
let search_on_add = search_on_add.unwrap_or_default();
|
||||||
let minimum_availability = *minimum_availability_list.current_selection();
|
let minimum_availability = *minimum_availability_list.current_selection();
|
||||||
self.app.data.radarr_data.edit_collection_modal = None;
|
|
||||||
|
|
||||||
EditCollectionParams {
|
EditCollectionParams {
|
||||||
collection_id,
|
collection_id,
|
||||||
monitored: Some(monitored),
|
monitored,
|
||||||
minimum_availability: Some(minimum_availability),
|
minimum_availability: Some(minimum_availability),
|
||||||
quality_profile_id: Some(quality_profile_id),
|
quality_profile_id: Some(quality_profile_id),
|
||||||
root_folder_path: Some(root_folder_path),
|
root_folder_path: Some(root_folder_path),
|
||||||
@@ -70,7 +68,11 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for EditCollectionHandle
|
|||||||
EDIT_COLLECTION_BLOCKS.contains(&active_block)
|
EDIT_COLLECTION_BLOCKS.contains(&active_block)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn with(
|
fn ignore_special_keys(&self) -> bool {
|
||||||
|
self.app.ignore_special_keys_for_textbox_input
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new(
|
||||||
key: Key,
|
key: Key,
|
||||||
app: &'a mut App<'b>,
|
app: &'a mut App<'b>,
|
||||||
active_block: ActiveRadarrBlock,
|
active_block: ActiveRadarrBlock,
|
||||||
@@ -263,7 +265,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for EditCollectionHandle
|
|||||||
)
|
)
|
||||||
.into(),
|
.into(),
|
||||||
);
|
);
|
||||||
self.app.should_ignore_quit_key = true;
|
self.app.ignore_special_keys_for_textbox_input = true;
|
||||||
}
|
}
|
||||||
ActiveRadarrBlock::EditCollectionToggleMonitored => {
|
ActiveRadarrBlock::EditCollectionToggleMonitored => {
|
||||||
self
|
self
|
||||||
@@ -312,7 +314,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for EditCollectionHandle
|
|||||||
| ActiveRadarrBlock::EditCollectionSelectQualityProfile => self.app.pop_navigation_stack(),
|
| ActiveRadarrBlock::EditCollectionSelectQualityProfile => self.app.pop_navigation_stack(),
|
||||||
ActiveRadarrBlock::EditCollectionRootFolderPathInput => {
|
ActiveRadarrBlock::EditCollectionRootFolderPathInput => {
|
||||||
self.app.pop_navigation_stack();
|
self.app.pop_navigation_stack();
|
||||||
self.app.should_ignore_quit_key = false;
|
self.app.ignore_special_keys_for_textbox_input = false;
|
||||||
}
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
@@ -322,7 +324,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for EditCollectionHandle
|
|||||||
match self.active_radarr_block {
|
match self.active_radarr_block {
|
||||||
ActiveRadarrBlock::EditCollectionRootFolderPathInput => {
|
ActiveRadarrBlock::EditCollectionRootFolderPathInput => {
|
||||||
self.app.pop_navigation_stack();
|
self.app.pop_navigation_stack();
|
||||||
self.app.should_ignore_quit_key = false;
|
self.app.ignore_special_keys_for_textbox_input = false;
|
||||||
}
|
}
|
||||||
ActiveRadarrBlock::EditCollectionPrompt => {
|
ActiveRadarrBlock::EditCollectionPrompt => {
|
||||||
self.app.pop_navigation_stack();
|
self.app.pop_navigation_stack();
|
||||||
@@ -355,7 +357,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for EditCollectionHandle
|
|||||||
ActiveRadarrBlock::EditCollectionPrompt => {
|
ActiveRadarrBlock::EditCollectionPrompt => {
|
||||||
if self.app.data.radarr_data.selected_block.get_active_block()
|
if self.app.data.radarr_data.selected_block.get_active_block()
|
||||||
== ActiveRadarrBlock::EditCollectionConfirmPrompt
|
== ActiveRadarrBlock::EditCollectionConfirmPrompt
|
||||||
&& key == DEFAULT_KEYBINDINGS.confirm.key
|
&& matches_key!(confirm, key)
|
||||||
{
|
{
|
||||||
self.app.data.radarr_data.prompt_confirm = true;
|
self.app.data.radarr_data.prompt_confirm = true;
|
||||||
self.app.data.radarr_data.prompt_confirm_action = Some(RadarrEvent::EditCollection(
|
self.app.data.radarr_data.prompt_confirm_action = Some(RadarrEvent::EditCollection(
|
||||||
@@ -369,4 +371,12 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for EditCollectionHandle
|
|||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn app_mut(&mut self) -> &mut App<'b> {
|
||||||
|
self.app
|
||||||
|
}
|
||||||
|
|
||||||
|
fn current_route(&self) -> crate::models::Route {
|
||||||
|
self.app.get_current_route()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,14 +2,17 @@
|
|||||||
mod tests {
|
mod tests {
|
||||||
use bimap::BiMap;
|
use bimap::BiMap;
|
||||||
use pretty_assertions::assert_str_eq;
|
use pretty_assertions::assert_str_eq;
|
||||||
|
use rstest::rstest;
|
||||||
use strum::IntoEnumIterator;
|
use strum::IntoEnumIterator;
|
||||||
|
|
||||||
use crate::app::key_binding::DEFAULT_KEYBINDINGS;
|
|
||||||
use crate::app::App;
|
use crate::app::App;
|
||||||
|
use crate::app::key_binding::DEFAULT_KEYBINDINGS;
|
||||||
|
use crate::assert_modal_absent;
|
||||||
|
use crate::assert_navigation_pushed;
|
||||||
use crate::event::Key;
|
use crate::event::Key;
|
||||||
|
use crate::handlers::KeyEventHandler;
|
||||||
use crate::handlers::radarr_handlers::collections::edit_collection_handler::EditCollectionHandler;
|
use crate::handlers::radarr_handlers::collections::edit_collection_handler::EditCollectionHandler;
|
||||||
use crate::handlers::radarr_handlers::radarr_handler_test_utils::utils::collection;
|
use crate::handlers::radarr_handlers::radarr_handler_test_utils::utils::collection;
|
||||||
use crate::handlers::KeyEventHandler;
|
|
||||||
use crate::models::radarr_models::{Collection, EditCollectionParams, MinimumAvailability};
|
use crate::models::radarr_models::{Collection, EditCollectionParams, MinimumAvailability};
|
||||||
use crate::models::servarr_data::radarr::modals::EditCollectionModal;
|
use crate::models::servarr_data::radarr::modals::EditCollectionModal;
|
||||||
use crate::models::servarr_data::radarr::radarr_data::{
|
use crate::models::servarr_data::radarr::radarr_data::{
|
||||||
@@ -21,9 +24,9 @@ mod tests {
|
|||||||
use rstest::rstest;
|
use rstest::rstest;
|
||||||
use strum::IntoEnumIterator;
|
use strum::IntoEnumIterator;
|
||||||
|
|
||||||
|
use crate::models::BlockSelectionState;
|
||||||
use crate::models::servarr_data::radarr::modals::EditCollectionModal;
|
use crate::models::servarr_data::radarr::modals::EditCollectionModal;
|
||||||
use crate::models::servarr_data::radarr::radarr_data::EDIT_COLLECTION_SELECTION_BLOCKS;
|
use crate::models::servarr_data::radarr::radarr_data::EDIT_COLLECTION_SELECTION_BLOCKS;
|
||||||
use crate::models::BlockSelectionState;
|
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
@@ -32,7 +35,7 @@ mod tests {
|
|||||||
#[values(DEFAULT_KEYBINDINGS.up.key, DEFAULT_KEYBINDINGS.down.key)] key: Key,
|
#[values(DEFAULT_KEYBINDINGS.up.key, DEFAULT_KEYBINDINGS.down.key)] key: Key,
|
||||||
) {
|
) {
|
||||||
let minimum_availability_vec = Vec::from_iter(MinimumAvailability::iter());
|
let minimum_availability_vec = Vec::from_iter(MinimumAvailability::iter());
|
||||||
let mut app = App::default();
|
let mut app = App::test_default();
|
||||||
app.data.radarr_data.edit_collection_modal = Some(EditCollectionModal::default());
|
app.data.radarr_data.edit_collection_modal = Some(EditCollectionModal::default());
|
||||||
app
|
app
|
||||||
.data
|
.data
|
||||||
@@ -45,7 +48,7 @@ mod tests {
|
|||||||
|
|
||||||
if key == Key::Up {
|
if key == Key::Up {
|
||||||
for i in (0..minimum_availability_vec.len()).rev() {
|
for i in (0..minimum_availability_vec.len()).rev() {
|
||||||
EditCollectionHandler::with(
|
EditCollectionHandler::new(
|
||||||
key,
|
key,
|
||||||
&mut app,
|
&mut app,
|
||||||
ActiveRadarrBlock::EditCollectionSelectMinimumAvailability,
|
ActiveRadarrBlock::EditCollectionSelectMinimumAvailability,
|
||||||
@@ -67,7 +70,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for i in 0..minimum_availability_vec.len() {
|
for i in 0..minimum_availability_vec.len() {
|
||||||
EditCollectionHandler::with(
|
EditCollectionHandler::new(
|
||||||
key,
|
key,
|
||||||
&mut app,
|
&mut app,
|
||||||
ActiveRadarrBlock::EditCollectionSelectMinimumAvailability,
|
ActiveRadarrBlock::EditCollectionSelectMinimumAvailability,
|
||||||
@@ -94,7 +97,7 @@ mod tests {
|
|||||||
fn test_edit_collection_select_quality_profile_scroll(
|
fn test_edit_collection_select_quality_profile_scroll(
|
||||||
#[values(DEFAULT_KEYBINDINGS.up.key, DEFAULT_KEYBINDINGS.down.key)] key: Key,
|
#[values(DEFAULT_KEYBINDINGS.up.key, DEFAULT_KEYBINDINGS.down.key)] key: Key,
|
||||||
) {
|
) {
|
||||||
let mut app = App::default();
|
let mut app = App::test_default();
|
||||||
app.data.radarr_data.edit_collection_modal = Some(EditCollectionModal::default());
|
app.data.radarr_data.edit_collection_modal = Some(EditCollectionModal::default());
|
||||||
app
|
app
|
||||||
.data
|
.data
|
||||||
@@ -105,7 +108,7 @@ mod tests {
|
|||||||
.quality_profile_list
|
.quality_profile_list
|
||||||
.set_items(vec!["Test 1".to_owned(), "Test 2".to_owned()]);
|
.set_items(vec!["Test 1".to_owned(), "Test 2".to_owned()]);
|
||||||
|
|
||||||
EditCollectionHandler::with(
|
EditCollectionHandler::new(
|
||||||
key,
|
key,
|
||||||
&mut app,
|
&mut app,
|
||||||
ActiveRadarrBlock::EditCollectionSelectQualityProfile,
|
ActiveRadarrBlock::EditCollectionSelectQualityProfile,
|
||||||
@@ -125,7 +128,7 @@ mod tests {
|
|||||||
"Test 2"
|
"Test 2"
|
||||||
);
|
);
|
||||||
|
|
||||||
EditCollectionHandler::with(
|
EditCollectionHandler::new(
|
||||||
key,
|
key,
|
||||||
&mut app,
|
&mut app,
|
||||||
ActiveRadarrBlock::EditCollectionSelectQualityProfile,
|
ActiveRadarrBlock::EditCollectionSelectQualityProfile,
|
||||||
@@ -148,13 +151,13 @@ mod tests {
|
|||||||
|
|
||||||
#[rstest]
|
#[rstest]
|
||||||
fn test_edit_collection_prompt_scroll(#[values(Key::Up, Key::Down)] key: Key) {
|
fn test_edit_collection_prompt_scroll(#[values(Key::Up, Key::Down)] key: Key) {
|
||||||
let mut app = App::default();
|
let mut app = App::test_default();
|
||||||
app.data.radarr_data.edit_collection_modal = Some(EditCollectionModal::default());
|
app.data.radarr_data.edit_collection_modal = Some(EditCollectionModal::default());
|
||||||
app.data.radarr_data.selected_block =
|
app.data.radarr_data.selected_block =
|
||||||
BlockSelectionState::new(EDIT_COLLECTION_SELECTION_BLOCKS);
|
BlockSelectionState::new(EDIT_COLLECTION_SELECTION_BLOCKS);
|
||||||
app.data.radarr_data.selected_block.down();
|
app.data.radarr_data.selected_block.down();
|
||||||
|
|
||||||
EditCollectionHandler::with(key, &mut app, ActiveRadarrBlock::EditCollectionPrompt, None)
|
EditCollectionHandler::new(key, &mut app, ActiveRadarrBlock::EditCollectionPrompt, None)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
if key == Key::Up {
|
if key == Key::Up {
|
||||||
@@ -174,14 +177,14 @@ mod tests {
|
|||||||
fn test_edit_collection_prompt_scroll_no_op_when_not_ready(
|
fn test_edit_collection_prompt_scroll_no_op_when_not_ready(
|
||||||
#[values(Key::Up, Key::Down)] key: Key,
|
#[values(Key::Up, Key::Down)] key: Key,
|
||||||
) {
|
) {
|
||||||
let mut app = App::default();
|
let mut app = App::test_default();
|
||||||
app.is_loading = true;
|
app.is_loading = true;
|
||||||
app.data.radarr_data.edit_collection_modal = Some(EditCollectionModal::default());
|
app.data.radarr_data.edit_collection_modal = Some(EditCollectionModal::default());
|
||||||
app.data.radarr_data.selected_block =
|
app.data.radarr_data.selected_block =
|
||||||
BlockSelectionState::new(EDIT_COLLECTION_SELECTION_BLOCKS);
|
BlockSelectionState::new(EDIT_COLLECTION_SELECTION_BLOCKS);
|
||||||
app.data.radarr_data.selected_block.down();
|
app.data.radarr_data.selected_block.down();
|
||||||
|
|
||||||
EditCollectionHandler::with(key, &mut app, ActiveRadarrBlock::EditCollectionPrompt, None)
|
EditCollectionHandler::new(key, &mut app, ActiveRadarrBlock::EditCollectionPrompt, None)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@@ -204,7 +207,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_edit_collection_select_minimum_availability_home_end() {
|
fn test_edit_collection_select_minimum_availability_home_end() {
|
||||||
let minimum_availability_vec = Vec::from_iter(MinimumAvailability::iter());
|
let minimum_availability_vec = Vec::from_iter(MinimumAvailability::iter());
|
||||||
let mut app = App::default();
|
let mut app = App::test_default();
|
||||||
app.data.radarr_data.edit_collection_modal = Some(EditCollectionModal::default());
|
app.data.radarr_data.edit_collection_modal = Some(EditCollectionModal::default());
|
||||||
app
|
app
|
||||||
.data
|
.data
|
||||||
@@ -215,7 +218,7 @@ mod tests {
|
|||||||
.minimum_availability_list
|
.minimum_availability_list
|
||||||
.set_items(minimum_availability_vec.clone());
|
.set_items(minimum_availability_vec.clone());
|
||||||
|
|
||||||
EditCollectionHandler::with(
|
EditCollectionHandler::new(
|
||||||
DEFAULT_KEYBINDINGS.end.key,
|
DEFAULT_KEYBINDINGS.end.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
ActiveRadarrBlock::EditCollectionSelectMinimumAvailability,
|
ActiveRadarrBlock::EditCollectionSelectMinimumAvailability,
|
||||||
@@ -235,7 +238,7 @@ mod tests {
|
|||||||
&minimum_availability_vec[minimum_availability_vec.len() - 1]
|
&minimum_availability_vec[minimum_availability_vec.len() - 1]
|
||||||
);
|
);
|
||||||
|
|
||||||
EditCollectionHandler::with(
|
EditCollectionHandler::new(
|
||||||
DEFAULT_KEYBINDINGS.home.key,
|
DEFAULT_KEYBINDINGS.home.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
ActiveRadarrBlock::EditCollectionSelectMinimumAvailability,
|
ActiveRadarrBlock::EditCollectionSelectMinimumAvailability,
|
||||||
@@ -258,7 +261,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_edit_collection_select_quality_profile_scroll() {
|
fn test_edit_collection_select_quality_profile_scroll() {
|
||||||
let mut app = App::default();
|
let mut app = App::test_default();
|
||||||
app.data.radarr_data.edit_collection_modal = Some(EditCollectionModal::default());
|
app.data.radarr_data.edit_collection_modal = Some(EditCollectionModal::default());
|
||||||
app
|
app
|
||||||
.data
|
.data
|
||||||
@@ -273,7 +276,7 @@ mod tests {
|
|||||||
"Test 3".to_owned(),
|
"Test 3".to_owned(),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
EditCollectionHandler::with(
|
EditCollectionHandler::new(
|
||||||
DEFAULT_KEYBINDINGS.end.key,
|
DEFAULT_KEYBINDINGS.end.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
ActiveRadarrBlock::EditCollectionSelectQualityProfile,
|
ActiveRadarrBlock::EditCollectionSelectQualityProfile,
|
||||||
@@ -293,7 +296,7 @@ mod tests {
|
|||||||
"Test 3"
|
"Test 3"
|
||||||
);
|
);
|
||||||
|
|
||||||
EditCollectionHandler::with(
|
EditCollectionHandler::new(
|
||||||
DEFAULT_KEYBINDINGS.home.key,
|
DEFAULT_KEYBINDINGS.home.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
ActiveRadarrBlock::EditCollectionSelectQualityProfile,
|
ActiveRadarrBlock::EditCollectionSelectQualityProfile,
|
||||||
@@ -316,13 +319,13 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_edit_collection_root_folder_path_input_home_end_keys() {
|
fn test_edit_collection_root_folder_path_input_home_end_keys() {
|
||||||
let mut app = App::default();
|
let mut app = App::test_default();
|
||||||
app.data.radarr_data.edit_collection_modal = Some(EditCollectionModal {
|
app.data.radarr_data.edit_collection_modal = Some(EditCollectionModal {
|
||||||
path: "Test".into(),
|
path: "Test".into(),
|
||||||
..EditCollectionModal::default()
|
..EditCollectionModal::default()
|
||||||
});
|
});
|
||||||
|
|
||||||
EditCollectionHandler::with(
|
EditCollectionHandler::new(
|
||||||
DEFAULT_KEYBINDINGS.home.key,
|
DEFAULT_KEYBINDINGS.home.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
ActiveRadarrBlock::EditCollectionRootFolderPathInput,
|
ActiveRadarrBlock::EditCollectionRootFolderPathInput,
|
||||||
@@ -343,7 +346,7 @@ mod tests {
|
|||||||
4
|
4
|
||||||
);
|
);
|
||||||
|
|
||||||
EditCollectionHandler::with(
|
EditCollectionHandler::new(
|
||||||
DEFAULT_KEYBINDINGS.end.key,
|
DEFAULT_KEYBINDINGS.end.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
ActiveRadarrBlock::EditCollectionRootFolderPathInput,
|
ActiveRadarrBlock::EditCollectionRootFolderPathInput,
|
||||||
@@ -376,14 +379,14 @@ mod tests {
|
|||||||
|
|
||||||
#[rstest]
|
#[rstest]
|
||||||
fn test_left_right_prompt_toggle(#[values(Key::Left, Key::Right)] key: Key) {
|
fn test_left_right_prompt_toggle(#[values(Key::Left, Key::Right)] key: Key) {
|
||||||
let mut app = App::default();
|
let mut app = App::test_default();
|
||||||
|
|
||||||
EditCollectionHandler::with(key, &mut app, ActiveRadarrBlock::EditCollectionPrompt, None)
|
EditCollectionHandler::new(key, &mut app, ActiveRadarrBlock::EditCollectionPrompt, None)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert!(app.data.radarr_data.prompt_confirm);
|
assert!(app.data.radarr_data.prompt_confirm);
|
||||||
|
|
||||||
EditCollectionHandler::with(key, &mut app, ActiveRadarrBlock::EditCollectionPrompt, None)
|
EditCollectionHandler::new(key, &mut app, ActiveRadarrBlock::EditCollectionPrompt, None)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert!(!app.data.radarr_data.prompt_confirm);
|
assert!(!app.data.radarr_data.prompt_confirm);
|
||||||
@@ -391,13 +394,13 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_edit_collection_root_folder_path_input_left_right_keys() {
|
fn test_edit_collection_root_folder_path_input_left_right_keys() {
|
||||||
let mut app = App::default();
|
let mut app = App::test_default();
|
||||||
app.data.radarr_data.edit_collection_modal = Some(EditCollectionModal {
|
app.data.radarr_data.edit_collection_modal = Some(EditCollectionModal {
|
||||||
path: "Test".into(),
|
path: "Test".into(),
|
||||||
..EditCollectionModal::default()
|
..EditCollectionModal::default()
|
||||||
});
|
});
|
||||||
|
|
||||||
EditCollectionHandler::with(
|
EditCollectionHandler::new(
|
||||||
DEFAULT_KEYBINDINGS.left.key,
|
DEFAULT_KEYBINDINGS.left.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
ActiveRadarrBlock::EditCollectionRootFolderPathInput,
|
ActiveRadarrBlock::EditCollectionRootFolderPathInput,
|
||||||
@@ -418,7 +421,7 @@ mod tests {
|
|||||||
1
|
1
|
||||||
);
|
);
|
||||||
|
|
||||||
EditCollectionHandler::with(
|
EditCollectionHandler::new(
|
||||||
DEFAULT_KEYBINDINGS.right.key,
|
DEFAULT_KEYBINDINGS.right.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
ActiveRadarrBlock::EditCollectionRootFolderPathInput,
|
ActiveRadarrBlock::EditCollectionRootFolderPathInput,
|
||||||
@@ -442,13 +445,13 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
mod test_handle_submit {
|
mod test_handle_submit {
|
||||||
use pretty_assertions::assert_eq;
|
use crate::assert_navigation_popped;
|
||||||
use rstest::rstest;
|
|
||||||
|
|
||||||
use crate::models::servarr_data::radarr::modals::EditCollectionModal;
|
use crate::models::servarr_data::radarr::modals::EditCollectionModal;
|
||||||
use crate::models::servarr_data::radarr::radarr_data::EDIT_COLLECTION_SELECTION_BLOCKS;
|
use crate::models::servarr_data::radarr::radarr_data::EDIT_COLLECTION_SELECTION_BLOCKS;
|
||||||
use crate::models::{BlockSelectionState, Route};
|
use crate::models::{BlockSelectionState, Route};
|
||||||
use crate::network::radarr_network::RadarrEvent;
|
use crate::network::radarr_network::RadarrEvent;
|
||||||
|
use pretty_assertions::assert_eq;
|
||||||
|
use rstest::rstest;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
@@ -456,8 +459,8 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_edit_collection_root_folder_path_input_submit() {
|
fn test_edit_collection_root_folder_path_input_submit() {
|
||||||
let mut app = App::default();
|
let mut app = App::test_default();
|
||||||
app.should_ignore_quit_key = true;
|
app.ignore_special_keys_for_textbox_input = true;
|
||||||
app.data.radarr_data.edit_collection_modal = Some(EditCollectionModal {
|
app.data.radarr_data.edit_collection_modal = Some(EditCollectionModal {
|
||||||
path: "Test Path".into(),
|
path: "Test Path".into(),
|
||||||
..EditCollectionModal::default()
|
..EditCollectionModal::default()
|
||||||
@@ -465,7 +468,7 @@ mod tests {
|
|||||||
app.push_navigation_stack(ActiveRadarrBlock::EditCollectionPrompt.into());
|
app.push_navigation_stack(ActiveRadarrBlock::EditCollectionPrompt.into());
|
||||||
app.push_navigation_stack(ActiveRadarrBlock::EditCollectionRootFolderPathInput.into());
|
app.push_navigation_stack(ActiveRadarrBlock::EditCollectionRootFolderPathInput.into());
|
||||||
|
|
||||||
EditCollectionHandler::with(
|
EditCollectionHandler::new(
|
||||||
SUBMIT_KEY,
|
SUBMIT_KEY,
|
||||||
&mut app,
|
&mut app,
|
||||||
ActiveRadarrBlock::EditCollectionRootFolderPathInput,
|
ActiveRadarrBlock::EditCollectionRootFolderPathInput,
|
||||||
@@ -473,25 +476,24 @@ mod tests {
|
|||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert!(!app.should_ignore_quit_key);
|
assert!(!app.ignore_special_keys_for_textbox_input);
|
||||||
assert!(!app
|
assert!(
|
||||||
.data
|
!app
|
||||||
.radarr_data
|
.data
|
||||||
.edit_collection_modal
|
.radarr_data
|
||||||
.as_ref()
|
.edit_collection_modal
|
||||||
.unwrap()
|
.as_ref()
|
||||||
.path
|
.unwrap()
|
||||||
.text
|
.path
|
||||||
.is_empty());
|
.text
|
||||||
assert_eq!(
|
.is_empty()
|
||||||
app.get_current_route(),
|
|
||||||
ActiveRadarrBlock::EditCollectionPrompt.into()
|
|
||||||
);
|
);
|
||||||
|
assert_navigation_popped!(app, ActiveRadarrBlock::EditCollectionPrompt.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_edit_collection_prompt_prompt_decline_submit() {
|
fn test_edit_collection_prompt_prompt_decline_submit() {
|
||||||
let mut app = App::default();
|
let mut app = App::test_default();
|
||||||
app.data.radarr_data.edit_collection_modal = Some(EditCollectionModal::default());
|
app.data.radarr_data.edit_collection_modal = Some(EditCollectionModal::default());
|
||||||
app.push_navigation_stack(ActiveRadarrBlock::Collections.into());
|
app.push_navigation_stack(ActiveRadarrBlock::Collections.into());
|
||||||
app.push_navigation_stack(ActiveRadarrBlock::EditCollectionPrompt.into());
|
app.push_navigation_stack(ActiveRadarrBlock::EditCollectionPrompt.into());
|
||||||
@@ -503,7 +505,7 @@ mod tests {
|
|||||||
.selected_block
|
.selected_block
|
||||||
.set_index(0, EDIT_COLLECTION_SELECTION_BLOCKS.len() - 1);
|
.set_index(0, EDIT_COLLECTION_SELECTION_BLOCKS.len() - 1);
|
||||||
|
|
||||||
EditCollectionHandler::with(
|
EditCollectionHandler::new(
|
||||||
SUBMIT_KEY,
|
SUBMIT_KEY,
|
||||||
&mut app,
|
&mut app,
|
||||||
ActiveRadarrBlock::EditCollectionPrompt,
|
ActiveRadarrBlock::EditCollectionPrompt,
|
||||||
@@ -511,16 +513,13 @@ mod tests {
|
|||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert_eq!(
|
assert_navigation_popped!(app, ActiveRadarrBlock::Collections.into());
|
||||||
app.get_current_route(),
|
assert_none!(app.data.radarr_data.prompt_confirm_action);
|
||||||
ActiveRadarrBlock::Collections.into()
|
|
||||||
);
|
|
||||||
assert_eq!(app.data.radarr_data.prompt_confirm_action, None);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_edit_collection_confirm_prompt_prompt_confirmation_submit() {
|
fn test_edit_collection_confirm_prompt_prompt_confirmation_submit() {
|
||||||
let mut app = App::default();
|
let mut app = App::test_default();
|
||||||
let mut edit_collection_modal = EditCollectionModal {
|
let mut edit_collection_modal = EditCollectionModal {
|
||||||
path: "/nfs/Test Path".into(),
|
path: "/nfs/Test Path".into(),
|
||||||
monitored: Some(false),
|
monitored: Some(false),
|
||||||
@@ -560,7 +559,7 @@ mod tests {
|
|||||||
.selected_block
|
.selected_block
|
||||||
.set_index(0, EDIT_COLLECTION_SELECTION_BLOCKS.len() - 1);
|
.set_index(0, EDIT_COLLECTION_SELECTION_BLOCKS.len() - 1);
|
||||||
|
|
||||||
EditCollectionHandler::with(
|
EditCollectionHandler::new(
|
||||||
SUBMIT_KEY,
|
SUBMIT_KEY,
|
||||||
&mut app,
|
&mut app,
|
||||||
ActiveRadarrBlock::EditCollectionPrompt,
|
ActiveRadarrBlock::EditCollectionPrompt,
|
||||||
@@ -568,21 +567,18 @@ mod tests {
|
|||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert_eq!(
|
assert_navigation_popped!(app, ActiveRadarrBlock::Collections.into());
|
||||||
app.get_current_route(),
|
|
||||||
ActiveRadarrBlock::Collections.into()
|
|
||||||
);
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.data.radarr_data.prompt_confirm_action,
|
app.data.radarr_data.prompt_confirm_action,
|
||||||
Some(RadarrEvent::EditCollection(expected_edit_collection_params))
|
Some(RadarrEvent::EditCollection(expected_edit_collection_params))
|
||||||
);
|
);
|
||||||
assert!(app.should_refresh);
|
assert!(app.should_refresh);
|
||||||
assert!(app.data.radarr_data.edit_collection_modal.is_none());
|
assert_modal_absent!(app.data.radarr_data.edit_collection_modal);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_edit_collection_confirm_prompt_prompt_confirmation_submit_no_op_when_not_ready() {
|
fn test_edit_collection_confirm_prompt_prompt_confirmation_submit_no_op_when_not_ready() {
|
||||||
let mut app = App::default();
|
let mut app = App::test_default();
|
||||||
app.is_loading = true;
|
app.is_loading = true;
|
||||||
app.data.radarr_data.edit_collection_modal = Some(EditCollectionModal::default());
|
app.data.radarr_data.edit_collection_modal = Some(EditCollectionModal::default());
|
||||||
app.push_navigation_stack(ActiveRadarrBlock::Collections.into());
|
app.push_navigation_stack(ActiveRadarrBlock::Collections.into());
|
||||||
@@ -596,7 +592,7 @@ mod tests {
|
|||||||
.selected_block
|
.selected_block
|
||||||
.set_index(0, EDIT_COLLECTION_SELECTION_BLOCKS.len() - 1);
|
.set_index(0, EDIT_COLLECTION_SELECTION_BLOCKS.len() - 1);
|
||||||
|
|
||||||
EditCollectionHandler::with(
|
EditCollectionHandler::new(
|
||||||
SUBMIT_KEY,
|
SUBMIT_KEY,
|
||||||
&mut app,
|
&mut app,
|
||||||
ActiveRadarrBlock::EditCollectionPrompt,
|
ActiveRadarrBlock::EditCollectionPrompt,
|
||||||
@@ -608,7 +604,7 @@ mod tests {
|
|||||||
app.get_current_route(),
|
app.get_current_route(),
|
||||||
ActiveRadarrBlock::EditCollectionPrompt.into()
|
ActiveRadarrBlock::EditCollectionPrompt.into()
|
||||||
);
|
);
|
||||||
assert_eq!(app.data.radarr_data.prompt_confirm_action, None);
|
assert_none!(app.data.radarr_data.prompt_confirm_action);
|
||||||
assert!(!app.should_refresh);
|
assert!(!app.should_refresh);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -618,13 +614,13 @@ mod tests {
|
|||||||
ActiveRadarrBlock::EditCollectionPrompt,
|
ActiveRadarrBlock::EditCollectionPrompt,
|
||||||
Some(ActiveRadarrBlock::Collections),
|
Some(ActiveRadarrBlock::Collections),
|
||||||
));
|
));
|
||||||
let mut app = App::default();
|
let mut app = App::test_default();
|
||||||
app.data.radarr_data.edit_collection_modal = Some(EditCollectionModal::default());
|
app.data.radarr_data.edit_collection_modal = Some(EditCollectionModal::default());
|
||||||
app.data.radarr_data.selected_block =
|
app.data.radarr_data.selected_block =
|
||||||
BlockSelectionState::new(EDIT_COLLECTION_SELECTION_BLOCKS);
|
BlockSelectionState::new(EDIT_COLLECTION_SELECTION_BLOCKS);
|
||||||
app.push_navigation_stack(current_route);
|
app.push_navigation_stack(current_route);
|
||||||
|
|
||||||
EditCollectionHandler::with(
|
EditCollectionHandler::new(
|
||||||
SUBMIT_KEY,
|
SUBMIT_KEY,
|
||||||
&mut app,
|
&mut app,
|
||||||
ActiveRadarrBlock::EditCollectionPrompt,
|
ActiveRadarrBlock::EditCollectionPrompt,
|
||||||
@@ -633,7 +629,7 @@ mod tests {
|
|||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert_eq!(app.get_current_route(), current_route);
|
assert_eq!(app.get_current_route(), current_route);
|
||||||
assert_eq!(
|
assert_some_eq_x!(
|
||||||
app
|
app
|
||||||
.data
|
.data
|
||||||
.radarr_data
|
.radarr_data
|
||||||
@@ -641,10 +637,10 @@ mod tests {
|
|||||||
.as_ref()
|
.as_ref()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.monitored,
|
.monitored,
|
||||||
Some(true)
|
true
|
||||||
);
|
);
|
||||||
|
|
||||||
EditCollectionHandler::with(
|
EditCollectionHandler::new(
|
||||||
SUBMIT_KEY,
|
SUBMIT_KEY,
|
||||||
&mut app,
|
&mut app,
|
||||||
ActiveRadarrBlock::EditCollectionPrompt,
|
ActiveRadarrBlock::EditCollectionPrompt,
|
||||||
@@ -653,7 +649,7 @@ mod tests {
|
|||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert_eq!(app.get_current_route(), current_route);
|
assert_eq!(app.get_current_route(), current_route);
|
||||||
assert_eq!(
|
assert_some_eq_x!(
|
||||||
app
|
app
|
||||||
.data
|
.data
|
||||||
.radarr_data
|
.radarr_data
|
||||||
@@ -661,7 +657,7 @@ mod tests {
|
|||||||
.as_ref()
|
.as_ref()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.monitored,
|
.monitored,
|
||||||
Some(false)
|
false
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -671,7 +667,7 @@ mod tests {
|
|||||||
ActiveRadarrBlock::EditCollectionPrompt,
|
ActiveRadarrBlock::EditCollectionPrompt,
|
||||||
Some(ActiveRadarrBlock::Collections),
|
Some(ActiveRadarrBlock::Collections),
|
||||||
));
|
));
|
||||||
let mut app = App::default();
|
let mut app = App::test_default();
|
||||||
app.data.radarr_data.edit_collection_modal = Some(EditCollectionModal::default());
|
app.data.radarr_data.edit_collection_modal = Some(EditCollectionModal::default());
|
||||||
app.data.radarr_data.selected_block =
|
app.data.radarr_data.selected_block =
|
||||||
BlockSelectionState::new(EDIT_COLLECTION_SELECTION_BLOCKS);
|
BlockSelectionState::new(EDIT_COLLECTION_SELECTION_BLOCKS);
|
||||||
@@ -682,7 +678,7 @@ mod tests {
|
|||||||
.set_index(0, EDIT_COLLECTION_SELECTION_BLOCKS.len() - 2);
|
.set_index(0, EDIT_COLLECTION_SELECTION_BLOCKS.len() - 2);
|
||||||
app.push_navigation_stack(current_route);
|
app.push_navigation_stack(current_route);
|
||||||
|
|
||||||
EditCollectionHandler::with(
|
EditCollectionHandler::new(
|
||||||
SUBMIT_KEY,
|
SUBMIT_KEY,
|
||||||
&mut app,
|
&mut app,
|
||||||
ActiveRadarrBlock::EditCollectionPrompt,
|
ActiveRadarrBlock::EditCollectionPrompt,
|
||||||
@@ -691,7 +687,7 @@ mod tests {
|
|||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert_eq!(app.get_current_route(), current_route);
|
assert_eq!(app.get_current_route(), current_route);
|
||||||
assert_eq!(
|
assert_some_eq_x!(
|
||||||
app
|
app
|
||||||
.data
|
.data
|
||||||
.radarr_data
|
.radarr_data
|
||||||
@@ -699,10 +695,10 @@ mod tests {
|
|||||||
.as_ref()
|
.as_ref()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.search_on_add,
|
.search_on_add,
|
||||||
Some(true)
|
true
|
||||||
);
|
);
|
||||||
|
|
||||||
EditCollectionHandler::with(
|
EditCollectionHandler::new(
|
||||||
SUBMIT_KEY,
|
SUBMIT_KEY,
|
||||||
&mut app,
|
&mut app,
|
||||||
ActiveRadarrBlock::EditCollectionPrompt,
|
ActiveRadarrBlock::EditCollectionPrompt,
|
||||||
@@ -711,7 +707,7 @@ mod tests {
|
|||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert_eq!(app.get_current_route(), current_route);
|
assert_eq!(app.get_current_route(), current_route);
|
||||||
assert_eq!(
|
assert_some_eq_x!(
|
||||||
app
|
app
|
||||||
.data
|
.data
|
||||||
.radarr_data
|
.radarr_data
|
||||||
@@ -719,7 +715,7 @@ mod tests {
|
|||||||
.as_ref()
|
.as_ref()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.search_on_add,
|
.search_on_add,
|
||||||
Some(false)
|
false
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -731,7 +727,7 @@ mod tests {
|
|||||||
#[case] selected_block: ActiveRadarrBlock,
|
#[case] selected_block: ActiveRadarrBlock,
|
||||||
#[case] index: usize,
|
#[case] index: usize,
|
||||||
) {
|
) {
|
||||||
let mut app = App::default();
|
let mut app = App::test_default();
|
||||||
app.data.radarr_data.edit_collection_modal = Some(EditCollectionModal::default());
|
app.data.radarr_data.edit_collection_modal = Some(EditCollectionModal::default());
|
||||||
app.push_navigation_stack(
|
app.push_navigation_stack(
|
||||||
(
|
(
|
||||||
@@ -744,7 +740,7 @@ mod tests {
|
|||||||
BlockSelectionState::new(EDIT_COLLECTION_SELECTION_BLOCKS);
|
BlockSelectionState::new(EDIT_COLLECTION_SELECTION_BLOCKS);
|
||||||
app.data.radarr_data.selected_block.set_index(0, index);
|
app.data.radarr_data.selected_block.set_index(0, index);
|
||||||
|
|
||||||
EditCollectionHandler::with(
|
EditCollectionHandler::new(
|
||||||
SUBMIT_KEY,
|
SUBMIT_KEY,
|
||||||
&mut app,
|
&mut app,
|
||||||
ActiveRadarrBlock::EditCollectionPrompt,
|
ActiveRadarrBlock::EditCollectionPrompt,
|
||||||
@@ -752,14 +748,14 @@ mod tests {
|
|||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert_eq!(
|
assert_navigation_pushed!(
|
||||||
app.get_current_route(),
|
app,
|
||||||
(selected_block, Some(ActiveRadarrBlock::Collections)).into()
|
(selected_block, Some(ActiveRadarrBlock::Collections)).into()
|
||||||
);
|
);
|
||||||
assert_eq!(app.data.radarr_data.prompt_confirm_action, None);
|
assert_none!(app.data.radarr_data.prompt_confirm_action);
|
||||||
|
|
||||||
if selected_block == ActiveRadarrBlock::EditCollectionRootFolderPathInput {
|
if selected_block == ActiveRadarrBlock::EditCollectionRootFolderPathInput {
|
||||||
assert!(app.should_ignore_quit_key);
|
assert!(app.ignore_special_keys_for_textbox_input);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -772,12 +768,12 @@ mod tests {
|
|||||||
)]
|
)]
|
||||||
active_radarr_block: ActiveRadarrBlock,
|
active_radarr_block: ActiveRadarrBlock,
|
||||||
) {
|
) {
|
||||||
let mut app = App::default();
|
let mut app = App::test_default();
|
||||||
app.data.radarr_data.edit_collection_modal = Some(EditCollectionModal::default());
|
app.data.radarr_data.edit_collection_modal = Some(EditCollectionModal::default());
|
||||||
app.push_navigation_stack(ActiveRadarrBlock::EditCollectionPrompt.into());
|
app.push_navigation_stack(ActiveRadarrBlock::EditCollectionPrompt.into());
|
||||||
app.push_navigation_stack(active_radarr_block.into());
|
app.push_navigation_stack(active_radarr_block.into());
|
||||||
|
|
||||||
EditCollectionHandler::with(
|
EditCollectionHandler::new(
|
||||||
SUBMIT_KEY,
|
SUBMIT_KEY,
|
||||||
&mut app,
|
&mut app,
|
||||||
active_radarr_block,
|
active_radarr_block,
|
||||||
@@ -785,22 +781,18 @@ mod tests {
|
|||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert_eq!(
|
assert_navigation_popped!(app, ActiveRadarrBlock::EditCollectionPrompt.into());
|
||||||
app.get_current_route(),
|
|
||||||
ActiveRadarrBlock::EditCollectionPrompt.into()
|
|
||||||
);
|
|
||||||
|
|
||||||
if active_radarr_block == ActiveRadarrBlock::EditCollectionRootFolderPathInput {
|
if active_radarr_block == ActiveRadarrBlock::EditCollectionRootFolderPathInput {
|
||||||
assert!(!app.should_ignore_quit_key);
|
assert!(!app.ignore_special_keys_for_textbox_input);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mod test_handle_esc {
|
mod test_handle_esc {
|
||||||
use pretty_assertions::assert_eq;
|
use crate::assert_navigation_popped;
|
||||||
use rstest::rstest;
|
|
||||||
|
|
||||||
use crate::models::servarr_data::radarr::radarr_data::radarr_test_utils::utils::create_test_radarr_data;
|
use crate::models::servarr_data::radarr::radarr_data::radarr_test_utils::utils::create_test_radarr_data;
|
||||||
|
use rstest::rstest;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
@@ -808,14 +800,14 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_edit_collection_root_folder_path_input_esc() {
|
fn test_edit_collection_root_folder_path_input_esc() {
|
||||||
let mut app = App::default();
|
let mut app = App::test_default();
|
||||||
app.data.radarr_data = create_test_radarr_data();
|
app.data.radarr_data = create_test_radarr_data();
|
||||||
app.data.radarr_data.edit_collection_modal = Some(EditCollectionModal::default());
|
app.data.radarr_data.edit_collection_modal = Some(EditCollectionModal::default());
|
||||||
app.should_ignore_quit_key = true;
|
app.ignore_special_keys_for_textbox_input = true;
|
||||||
app.push_navigation_stack(ActiveRadarrBlock::EditCollectionPrompt.into());
|
app.push_navigation_stack(ActiveRadarrBlock::EditCollectionPrompt.into());
|
||||||
app.push_navigation_stack(ActiveRadarrBlock::EditCollectionRootFolderPathInput.into());
|
app.push_navigation_stack(ActiveRadarrBlock::EditCollectionRootFolderPathInput.into());
|
||||||
|
|
||||||
EditCollectionHandler::with(
|
EditCollectionHandler::new(
|
||||||
ESC_KEY,
|
ESC_KEY,
|
||||||
&mut app,
|
&mut app,
|
||||||
ActiveRadarrBlock::EditCollectionRootFolderPathInput,
|
ActiveRadarrBlock::EditCollectionRootFolderPathInput,
|
||||||
@@ -823,21 +815,18 @@ mod tests {
|
|||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert!(!app.should_ignore_quit_key);
|
assert!(!app.ignore_special_keys_for_textbox_input);
|
||||||
assert_eq!(
|
assert_navigation_popped!(app, ActiveRadarrBlock::EditCollectionPrompt.into());
|
||||||
app.get_current_route(),
|
|
||||||
ActiveRadarrBlock::EditCollectionPrompt.into()
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_edit_collection_prompt_esc() {
|
fn test_edit_collection_prompt_esc() {
|
||||||
let mut app = App::default();
|
let mut app = App::test_default();
|
||||||
app.push_navigation_stack(ActiveRadarrBlock::Collections.into());
|
app.push_navigation_stack(ActiveRadarrBlock::Collections.into());
|
||||||
app.push_navigation_stack(ActiveRadarrBlock::EditCollectionPrompt.into());
|
app.push_navigation_stack(ActiveRadarrBlock::EditCollectionPrompt.into());
|
||||||
app.data.radarr_data = create_test_radarr_data();
|
app.data.radarr_data = create_test_radarr_data();
|
||||||
|
|
||||||
EditCollectionHandler::with(
|
EditCollectionHandler::new(
|
||||||
ESC_KEY,
|
ESC_KEY,
|
||||||
&mut app,
|
&mut app,
|
||||||
ActiveRadarrBlock::EditCollectionPrompt,
|
ActiveRadarrBlock::EditCollectionPrompt,
|
||||||
@@ -845,13 +834,10 @@ mod tests {
|
|||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert_eq!(
|
assert_navigation_popped!(app, ActiveRadarrBlock::Collections.into());
|
||||||
app.get_current_route(),
|
|
||||||
ActiveRadarrBlock::Collections.into()
|
|
||||||
);
|
|
||||||
let radarr_data = &app.data.radarr_data;
|
let radarr_data = &app.data.radarr_data;
|
||||||
|
|
||||||
assert!(radarr_data.edit_collection_modal.is_none());
|
assert_modal_absent!(radarr_data.edit_collection_modal);
|
||||||
assert!(!radarr_data.prompt_confirm);
|
assert!(!radarr_data.prompt_confirm);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -864,42 +850,40 @@ mod tests {
|
|||||||
active_radarr_block: ActiveRadarrBlock,
|
active_radarr_block: ActiveRadarrBlock,
|
||||||
#[values(true, false)] is_ready: bool,
|
#[values(true, false)] is_ready: bool,
|
||||||
) {
|
) {
|
||||||
let mut app = App::default();
|
let mut app = App::test_default();
|
||||||
app.is_loading = is_ready;
|
app.is_loading = is_ready;
|
||||||
app.data.radarr_data = create_test_radarr_data();
|
app.data.radarr_data = create_test_radarr_data();
|
||||||
app.push_navigation_stack(ActiveRadarrBlock::Collections.into());
|
app.push_navigation_stack(ActiveRadarrBlock::Collections.into());
|
||||||
app.push_navigation_stack(active_radarr_block.into());
|
app.push_navigation_stack(active_radarr_block.into());
|
||||||
|
|
||||||
EditCollectionHandler::with(ESC_KEY, &mut app, active_radarr_block, None).handle();
|
EditCollectionHandler::new(ESC_KEY, &mut app, active_radarr_block, None).handle();
|
||||||
|
|
||||||
assert_eq!(
|
assert_navigation_popped!(app, ActiveRadarrBlock::Collections.into());
|
||||||
app.get_current_route(),
|
|
||||||
ActiveRadarrBlock::Collections.into()
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mod test_handle_key_char {
|
mod test_handle_key_char {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::{
|
use crate::{
|
||||||
|
assert_navigation_popped,
|
||||||
models::{
|
models::{
|
||||||
|
BlockSelectionState,
|
||||||
servarr_data::radarr::{
|
servarr_data::radarr::{
|
||||||
modals::EditCollectionModal, radarr_data::EDIT_COLLECTION_SELECTION_BLOCKS,
|
modals::EditCollectionModal, radarr_data::EDIT_COLLECTION_SELECTION_BLOCKS,
|
||||||
},
|
},
|
||||||
BlockSelectionState,
|
|
||||||
},
|
},
|
||||||
network::radarr_network::RadarrEvent,
|
network::radarr_network::RadarrEvent,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_edit_collection_root_folder_path_input_backspace() {
|
fn test_edit_collection_root_folder_path_input_backspace() {
|
||||||
let mut app = App::default();
|
let mut app = App::test_default();
|
||||||
app.data.radarr_data.edit_collection_modal = Some(EditCollectionModal {
|
app.data.radarr_data.edit_collection_modal = Some(EditCollectionModal {
|
||||||
path: "Test".into(),
|
path: "Test".into(),
|
||||||
..EditCollectionModal::default()
|
..EditCollectionModal::default()
|
||||||
});
|
});
|
||||||
|
|
||||||
EditCollectionHandler::with(
|
EditCollectionHandler::new(
|
||||||
DEFAULT_KEYBINDINGS.backspace.key,
|
DEFAULT_KEYBINDINGS.backspace.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
ActiveRadarrBlock::EditCollectionRootFolderPathInput,
|
ActiveRadarrBlock::EditCollectionRootFolderPathInput,
|
||||||
@@ -922,11 +906,11 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_edit_collection_root_folder_path_input_char_key() {
|
fn test_edit_collection_root_folder_path_input_char_key() {
|
||||||
let mut app = App::default();
|
let mut app = App::test_default();
|
||||||
app.data.radarr_data.edit_collection_modal = Some(EditCollectionModal::default());
|
app.data.radarr_data.edit_collection_modal = Some(EditCollectionModal::default());
|
||||||
|
|
||||||
EditCollectionHandler::with(
|
EditCollectionHandler::new(
|
||||||
Key::Char('h'),
|
Key::Char('a'),
|
||||||
&mut app,
|
&mut app,
|
||||||
ActiveRadarrBlock::EditCollectionRootFolderPathInput,
|
ActiveRadarrBlock::EditCollectionRootFolderPathInput,
|
||||||
None,
|
None,
|
||||||
@@ -942,13 +926,13 @@ mod tests {
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
.path
|
.path
|
||||||
.text,
|
.text,
|
||||||
"h"
|
"a"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_edit_collection_confirm_prompt_prompt_confirmation_confirm() {
|
fn test_edit_collection_confirm_prompt_prompt_confirmation_confirm() {
|
||||||
let mut app = App::default();
|
let mut app = App::test_default();
|
||||||
let mut edit_collection_modal = EditCollectionModal {
|
let mut edit_collection_modal = EditCollectionModal {
|
||||||
path: "/nfs/Test Path".into(),
|
path: "/nfs/Test Path".into(),
|
||||||
monitored: Some(false),
|
monitored: Some(false),
|
||||||
@@ -987,7 +971,7 @@ mod tests {
|
|||||||
.selected_block
|
.selected_block
|
||||||
.set_index(0, EDIT_COLLECTION_SELECTION_BLOCKS.len() - 1);
|
.set_index(0, EDIT_COLLECTION_SELECTION_BLOCKS.len() - 1);
|
||||||
|
|
||||||
EditCollectionHandler::with(
|
EditCollectionHandler::new(
|
||||||
DEFAULT_KEYBINDINGS.confirm.key,
|
DEFAULT_KEYBINDINGS.confirm.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
ActiveRadarrBlock::EditCollectionPrompt,
|
ActiveRadarrBlock::EditCollectionPrompt,
|
||||||
@@ -995,16 +979,13 @@ mod tests {
|
|||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert_eq!(
|
assert_navigation_popped!(app, ActiveRadarrBlock::Collections.into());
|
||||||
app.get_current_route(),
|
|
||||||
ActiveRadarrBlock::Collections.into()
|
|
||||||
);
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.data.radarr_data.prompt_confirm_action,
|
app.data.radarr_data.prompt_confirm_action,
|
||||||
Some(RadarrEvent::EditCollection(expected_edit_collection_params))
|
Some(RadarrEvent::EditCollection(expected_edit_collection_params))
|
||||||
);
|
);
|
||||||
assert!(app.should_refresh);
|
assert!(app.should_refresh);
|
||||||
assert!(app.data.radarr_data.edit_collection_modal.is_none());
|
assert_modal_absent!(app.data.radarr_data.edit_collection_modal);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1019,9 +1000,28 @@ mod tests {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
fn test_edit_collection_handler_ignore_special_keys(
|
||||||
|
#[values(true, false)] ignore_special_keys_for_textbox_input: bool,
|
||||||
|
) {
|
||||||
|
let mut app = App::test_default();
|
||||||
|
app.ignore_special_keys_for_textbox_input = ignore_special_keys_for_textbox_input;
|
||||||
|
let handler = EditCollectionHandler::new(
|
||||||
|
DEFAULT_KEYBINDINGS.esc.key,
|
||||||
|
&mut app,
|
||||||
|
ActiveRadarrBlock::default(),
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
handler.ignore_special_keys(),
|
||||||
|
ignore_special_keys_for_textbox_input
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_build_edit_collection_params() {
|
fn test_build_edit_collection_params() {
|
||||||
let mut app = App::default();
|
let mut app = App::test_default();
|
||||||
let mut edit_collection_modal = EditCollectionModal {
|
let mut edit_collection_modal = EditCollectionModal {
|
||||||
path: "/nfs/Test Path".into(),
|
path: "/nfs/Test Path".into(),
|
||||||
monitored: Some(false),
|
monitored: Some(false),
|
||||||
@@ -1051,7 +1051,7 @@ mod tests {
|
|||||||
search_on_add: Some(false),
|
search_on_add: Some(false),
|
||||||
};
|
};
|
||||||
|
|
||||||
let edit_collection_params = EditCollectionHandler::with(
|
let edit_collection_params = EditCollectionHandler::new(
|
||||||
DEFAULT_KEYBINDINGS.esc.key,
|
DEFAULT_KEYBINDINGS.esc.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
ActiveRadarrBlock::EditCollectionPrompt,
|
ActiveRadarrBlock::EditCollectionPrompt,
|
||||||
@@ -1060,15 +1060,15 @@ mod tests {
|
|||||||
.build_edit_collection_params();
|
.build_edit_collection_params();
|
||||||
|
|
||||||
assert_eq!(edit_collection_params, expected_edit_collection_params);
|
assert_eq!(edit_collection_params, expected_edit_collection_params);
|
||||||
assert!(app.data.radarr_data.edit_collection_modal.is_none());
|
assert_modal_absent!(app.data.radarr_data.edit_collection_modal);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_edit_collection_handler_is_not_ready_when_loading() {
|
fn test_edit_collection_handler_is_not_ready_when_loading() {
|
||||||
let mut app = App::default();
|
let mut app = App::test_default();
|
||||||
app.is_loading = true;
|
app.is_loading = true;
|
||||||
|
|
||||||
let handler = EditCollectionHandler::with(
|
let handler = EditCollectionHandler::new(
|
||||||
DEFAULT_KEYBINDINGS.esc.key,
|
DEFAULT_KEYBINDINGS.esc.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
ActiveRadarrBlock::EditCollectionPrompt,
|
ActiveRadarrBlock::EditCollectionPrompt,
|
||||||
@@ -1080,10 +1080,10 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_edit_collection_handler_is_not_ready_when_edit_collection_modal_is_none() {
|
fn test_edit_collection_handler_is_not_ready_when_edit_collection_modal_is_none() {
|
||||||
let mut app = App::default();
|
let mut app = App::test_default();
|
||||||
app.is_loading = false;
|
app.is_loading = false;
|
||||||
|
|
||||||
let handler = EditCollectionHandler::with(
|
let handler = EditCollectionHandler::new(
|
||||||
DEFAULT_KEYBINDINGS.esc.key,
|
DEFAULT_KEYBINDINGS.esc.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
ActiveRadarrBlock::EditCollectionPrompt,
|
ActiveRadarrBlock::EditCollectionPrompt,
|
||||||
@@ -1095,11 +1095,11 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_edit_collection_handler_is_ready_when_edit_collection_modal_is_some() {
|
fn test_edit_collection_handler_is_ready_when_edit_collection_modal_is_some() {
|
||||||
let mut app = App::default();
|
let mut app = App::test_default();
|
||||||
app.is_loading = false;
|
app.is_loading = false;
|
||||||
app.data.radarr_data.edit_collection_modal = Some(EditCollectionModal::default());
|
app.data.radarr_data.edit_collection_modal = Some(EditCollectionModal::default());
|
||||||
|
|
||||||
let handler = EditCollectionHandler::with(
|
let handler = EditCollectionHandler::new(
|
||||||
DEFAULT_KEYBINDINGS.esc.key,
|
DEFAULT_KEYBINDINGS.esc.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
ActiveRadarrBlock::EditCollectionPrompt,
|
ActiveRadarrBlock::EditCollectionPrompt,
|
||||||
|
|||||||
@@ -1,18 +1,17 @@
|
|||||||
use crate::app::key_binding::DEFAULT_KEYBINDINGS;
|
|
||||||
use crate::app::App;
|
use crate::app::App;
|
||||||
use crate::event::Key;
|
use crate::event::Key;
|
||||||
use crate::handle_table_events;
|
|
||||||
use crate::handlers::radarr_handlers::collections::collection_details_handler::CollectionDetailsHandler;
|
use crate::handlers::radarr_handlers::collections::collection_details_handler::CollectionDetailsHandler;
|
||||||
use crate::handlers::radarr_handlers::collections::edit_collection_handler::EditCollectionHandler;
|
use crate::handlers::radarr_handlers::collections::edit_collection_handler::EditCollectionHandler;
|
||||||
use crate::handlers::radarr_handlers::handle_change_tab_left_right_keys;
|
use crate::handlers::radarr_handlers::handle_change_tab_left_right_keys;
|
||||||
use crate::handlers::table_handler::TableHandlingConfig;
|
use crate::handlers::table_handler::{TableHandlingConfig, handle_table};
|
||||||
use crate::handlers::{handle_clear_errors, handle_prompt_toggle, KeyEventHandler};
|
use crate::handlers::{KeyEventHandler, handle_clear_errors, handle_prompt_toggle};
|
||||||
|
use crate::matches_key;
|
||||||
|
use crate::models::BlockSelectionState;
|
||||||
use crate::models::radarr_models::Collection;
|
use crate::models::radarr_models::Collection;
|
||||||
use crate::models::servarr_data::radarr::radarr_data::{
|
use crate::models::servarr_data::radarr::radarr_data::{
|
||||||
ActiveRadarrBlock, COLLECTIONS_BLOCKS, EDIT_COLLECTION_SELECTION_BLOCKS,
|
ActiveRadarrBlock, COLLECTIONS_BLOCKS, EDIT_COLLECTION_SELECTION_BLOCKS,
|
||||||
};
|
};
|
||||||
use crate::models::stateful_table::SortOption;
|
use crate::models::stateful_table::SortOption;
|
||||||
use crate::models::BlockSelectionState;
|
|
||||||
use crate::network::radarr_network::RadarrEvent;
|
use crate::network::radarr_network::RadarrEvent;
|
||||||
|
|
||||||
mod collection_details_handler;
|
mod collection_details_handler;
|
||||||
@@ -29,21 +28,13 @@ pub(super) struct CollectionsHandler<'a, 'b> {
|
|||||||
context: Option<ActiveRadarrBlock>,
|
context: Option<ActiveRadarrBlock>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'b> CollectionsHandler<'a, 'b> {
|
impl CollectionsHandler<'_, '_> {}
|
||||||
handle_table_events!(
|
|
||||||
self,
|
|
||||||
collections,
|
|
||||||
self.app.data.radarr_data.collections,
|
|
||||||
Collection
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for CollectionsHandler<'a, 'b> {
|
impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for CollectionsHandler<'a, 'b> {
|
||||||
fn handle(&mut self) {
|
fn handle(&mut self) {
|
||||||
let collections_table_handling_config =
|
let collections_table_handling_config =
|
||||||
TableHandlingConfig::new(ActiveRadarrBlock::Collections.into())
|
TableHandlingConfig::new(ActiveRadarrBlock::Collections.into())
|
||||||
.sorting_block(ActiveRadarrBlock::CollectionsSortPrompt.into())
|
.sorting_block(ActiveRadarrBlock::CollectionsSortPrompt.into())
|
||||||
.sort_by_fn(|a: &Collection, b: &Collection| a.id.cmp(&b.id))
|
|
||||||
.sort_options(collections_sorting_options())
|
.sort_options(collections_sorting_options())
|
||||||
.searching_block(ActiveRadarrBlock::SearchCollection.into())
|
.searching_block(ActiveRadarrBlock::SearchCollection.into())
|
||||||
.search_error_block(ActiveRadarrBlock::SearchCollectionError.into())
|
.search_error_block(ActiveRadarrBlock::SearchCollectionError.into())
|
||||||
@@ -52,19 +43,18 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for CollectionsHandler<'
|
|||||||
.filter_error_block(ActiveRadarrBlock::FilterCollectionsError.into())
|
.filter_error_block(ActiveRadarrBlock::FilterCollectionsError.into())
|
||||||
.filter_field_fn(|collection| &collection.title.text);
|
.filter_field_fn(|collection| &collection.title.text);
|
||||||
|
|
||||||
if !self.handle_collections_table_events(collections_table_handling_config) {
|
if !handle_table(
|
||||||
|
self,
|
||||||
|
|app| &mut app.data.radarr_data.collections,
|
||||||
|
collections_table_handling_config,
|
||||||
|
) {
|
||||||
match self.active_radarr_block {
|
match self.active_radarr_block {
|
||||||
_ if CollectionDetailsHandler::accepts(self.active_radarr_block) => {
|
_ if CollectionDetailsHandler::accepts(self.active_radarr_block) => {
|
||||||
CollectionDetailsHandler::with(
|
CollectionDetailsHandler::new(self.key, self.app, self.active_radarr_block, self.context)
|
||||||
self.key,
|
.handle();
|
||||||
self.app,
|
|
||||||
self.active_radarr_block,
|
|
||||||
self.context,
|
|
||||||
)
|
|
||||||
.handle();
|
|
||||||
}
|
}
|
||||||
_ if EditCollectionHandler::accepts(self.active_radarr_block) => {
|
_ if EditCollectionHandler::accepts(self.active_radarr_block) => {
|
||||||
EditCollectionHandler::with(self.key, self.app, self.active_radarr_block, self.context)
|
EditCollectionHandler::new(self.key, self.app, self.active_radarr_block, self.context)
|
||||||
.handle();
|
.handle();
|
||||||
}
|
}
|
||||||
_ => self.handle_key_event(),
|
_ => self.handle_key_event(),
|
||||||
@@ -78,7 +68,11 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for CollectionsHandler<'
|
|||||||
|| COLLECTIONS_BLOCKS.contains(&active_block)
|
|| COLLECTIONS_BLOCKS.contains(&active_block)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn with(
|
fn ignore_special_keys(&self) -> bool {
|
||||||
|
self.app.ignore_special_keys_for_textbox_input
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new(
|
||||||
key: Key,
|
key: Key,
|
||||||
app: &'a mut App<'b>,
|
app: &'a mut App<'b>,
|
||||||
active_block: ActiveRadarrBlock,
|
active_block: ActiveRadarrBlock,
|
||||||
@@ -150,7 +144,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for CollectionsHandler<'
|
|||||||
let key = self.key;
|
let key = self.key;
|
||||||
match self.active_radarr_block {
|
match self.active_radarr_block {
|
||||||
ActiveRadarrBlock::Collections => match self.key {
|
ActiveRadarrBlock::Collections => match self.key {
|
||||||
_ if key == DEFAULT_KEYBINDINGS.edit.key => {
|
_ if matches_key!(edit, key) => {
|
||||||
self
|
self
|
||||||
.app
|
.app
|
||||||
.push_navigation_stack(ActiveRadarrBlock::EditCollectionPrompt.into());
|
.push_navigation_stack(ActiveRadarrBlock::EditCollectionPrompt.into());
|
||||||
@@ -159,18 +153,18 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for CollectionsHandler<'
|
|||||||
self.app.data.radarr_data.selected_block =
|
self.app.data.radarr_data.selected_block =
|
||||||
BlockSelectionState::new(EDIT_COLLECTION_SELECTION_BLOCKS);
|
BlockSelectionState::new(EDIT_COLLECTION_SELECTION_BLOCKS);
|
||||||
}
|
}
|
||||||
_ if key == DEFAULT_KEYBINDINGS.update.key => {
|
_ if matches_key!(update, key) => {
|
||||||
self
|
self
|
||||||
.app
|
.app
|
||||||
.push_navigation_stack(ActiveRadarrBlock::UpdateAllCollectionsPrompt.into());
|
.push_navigation_stack(ActiveRadarrBlock::UpdateAllCollectionsPrompt.into());
|
||||||
}
|
}
|
||||||
_ if key == DEFAULT_KEYBINDINGS.refresh.key => {
|
_ if matches_key!(refresh, key) => {
|
||||||
self.app.should_refresh = true;
|
self.app.should_refresh = true;
|
||||||
}
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
},
|
},
|
||||||
ActiveRadarrBlock::UpdateAllCollectionsPrompt => {
|
ActiveRadarrBlock::UpdateAllCollectionsPrompt => {
|
||||||
if key == DEFAULT_KEYBINDINGS.confirm.key {
|
if matches_key!(confirm, key) {
|
||||||
self.app.data.radarr_data.prompt_confirm = true;
|
self.app.data.radarr_data.prompt_confirm = true;
|
||||||
self.app.data.radarr_data.prompt_confirm_action = Some(RadarrEvent::UpdateCollections);
|
self.app.data.radarr_data.prompt_confirm_action = Some(RadarrEvent::UpdateCollections);
|
||||||
|
|
||||||
@@ -180,6 +174,14 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for CollectionsHandler<'
|
|||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn app_mut(&mut self) -> &mut App<'b> {
|
||||||
|
self.app
|
||||||
|
}
|
||||||
|
|
||||||
|
fn current_route(&self) -> crate::models::Route {
|
||||||
|
self.app.get_current_route()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn collections_sorting_options() -> Vec<SortOption<Collection>> {
|
fn collections_sorting_options() -> Vec<SortOption<Collection>> {
|
||||||
|
|||||||
@@ -1,14 +1,16 @@
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use pretty_assertions::assert_eq;
|
use pretty_assertions::assert_eq;
|
||||||
|
use rstest::rstest;
|
||||||
use strum::IntoEnumIterator;
|
use strum::IntoEnumIterator;
|
||||||
|
|
||||||
use crate::app::key_binding::DEFAULT_KEYBINDINGS;
|
|
||||||
use crate::app::App;
|
use crate::app::App;
|
||||||
|
use crate::app::key_binding::DEFAULT_KEYBINDINGS;
|
||||||
|
use crate::assert_navigation_pushed;
|
||||||
use crate::event::Key;
|
use crate::event::Key;
|
||||||
|
use crate::handlers::KeyEventHandler;
|
||||||
use crate::handlers::radarr_handlers::downloads::DownloadsHandler;
|
use crate::handlers::radarr_handlers::downloads::DownloadsHandler;
|
||||||
use crate::handlers::radarr_handlers::radarr_handler_test_utils::utils::download_record;
|
use crate::handlers::radarr_handlers::radarr_handler_test_utils::utils::download_record;
|
||||||
use crate::handlers::KeyEventHandler;
|
|
||||||
use crate::models::radarr_models::DownloadRecord;
|
use crate::models::radarr_models::DownloadRecord;
|
||||||
use crate::models::servarr_data::radarr::radarr_data::{ActiveRadarrBlock, DOWNLOADS_BLOCKS};
|
use crate::models::servarr_data::radarr::radarr_data::{ActiveRadarrBlock, DOWNLOADS_BLOCKS};
|
||||||
|
|
||||||
@@ -21,24 +23,21 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_delete_download_prompt() {
|
fn test_delete_download_prompt() {
|
||||||
let mut app = App::default();
|
let mut app = App::test_default();
|
||||||
app
|
app
|
||||||
.data
|
.data
|
||||||
.radarr_data
|
.radarr_data
|
||||||
.downloads
|
.downloads
|
||||||
.set_items(vec![DownloadRecord::default()]);
|
.set_items(vec![DownloadRecord::default()]);
|
||||||
|
|
||||||
DownloadsHandler::with(DELETE_KEY, &mut app, ActiveRadarrBlock::Downloads, None).handle();
|
DownloadsHandler::new(DELETE_KEY, &mut app, ActiveRadarrBlock::Downloads, None).handle();
|
||||||
|
|
||||||
assert_eq!(
|
assert_navigation_pushed!(app, ActiveRadarrBlock::DeleteDownloadPrompt.into());
|
||||||
app.get_current_route(),
|
|
||||||
ActiveRadarrBlock::DeleteDownloadPrompt.into()
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_delete_download_prompt_no_op_when_not_ready() {
|
fn test_delete_download_prompt_no_op_when_not_ready() {
|
||||||
let mut app = App::default();
|
let mut app = App::test_default();
|
||||||
app.is_loading = true;
|
app.is_loading = true;
|
||||||
app.push_navigation_stack(ActiveRadarrBlock::Downloads.into());
|
app.push_navigation_stack(ActiveRadarrBlock::Downloads.into());
|
||||||
app
|
app
|
||||||
@@ -47,7 +46,7 @@ mod tests {
|
|||||||
.downloads
|
.downloads
|
||||||
.set_items(vec![DownloadRecord::default()]);
|
.set_items(vec![DownloadRecord::default()]);
|
||||||
|
|
||||||
DownloadsHandler::with(DELETE_KEY, &mut app, ActiveRadarrBlock::Downloads, None).handle();
|
DownloadsHandler::new(DELETE_KEY, &mut app, ActiveRadarrBlock::Downloads, None).handle();
|
||||||
|
|
||||||
assert_eq!(app.get_current_route(), ActiveRadarrBlock::Downloads.into());
|
assert_eq!(app.get_current_route(), ActiveRadarrBlock::Downloads.into());
|
||||||
}
|
}
|
||||||
@@ -61,11 +60,11 @@ mod tests {
|
|||||||
|
|
||||||
#[rstest]
|
#[rstest]
|
||||||
fn test_downloads_tab_left(#[values(true, false)] is_ready: bool) {
|
fn test_downloads_tab_left(#[values(true, false)] is_ready: bool) {
|
||||||
let mut app = App::default();
|
let mut app = App::test_default();
|
||||||
app.is_loading = is_ready;
|
app.is_loading = is_ready;
|
||||||
app.data.radarr_data.main_tabs.set_index(2);
|
app.data.radarr_data.main_tabs.set_index(2);
|
||||||
|
|
||||||
DownloadsHandler::with(
|
DownloadsHandler::new(
|
||||||
DEFAULT_KEYBINDINGS.left.key,
|
DEFAULT_KEYBINDINGS.left.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
ActiveRadarrBlock::Downloads,
|
ActiveRadarrBlock::Downloads,
|
||||||
@@ -77,19 +76,16 @@ mod tests {
|
|||||||
app.data.radarr_data.main_tabs.get_active_route(),
|
app.data.radarr_data.main_tabs.get_active_route(),
|
||||||
ActiveRadarrBlock::Collections.into()
|
ActiveRadarrBlock::Collections.into()
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_navigation_pushed!(app, ActiveRadarrBlock::Collections.into());
|
||||||
app.get_current_route(),
|
|
||||||
ActiveRadarrBlock::Collections.into()
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rstest]
|
#[rstest]
|
||||||
fn test_downloads_tab_right(#[values(true, false)] is_ready: bool) {
|
fn test_downloads_tab_right(#[values(true, false)] is_ready: bool) {
|
||||||
let mut app = App::default();
|
let mut app = App::test_default();
|
||||||
app.is_loading = is_ready;
|
app.is_loading = is_ready;
|
||||||
app.data.radarr_data.main_tabs.set_index(2);
|
app.data.radarr_data.main_tabs.set_index(2);
|
||||||
|
|
||||||
DownloadsHandler::with(
|
DownloadsHandler::new(
|
||||||
DEFAULT_KEYBINDINGS.right.key,
|
DEFAULT_KEYBINDINGS.right.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
ActiveRadarrBlock::Downloads,
|
ActiveRadarrBlock::Downloads,
|
||||||
@@ -101,7 +97,7 @@ mod tests {
|
|||||||
app.data.radarr_data.main_tabs.get_active_route(),
|
app.data.radarr_data.main_tabs.get_active_route(),
|
||||||
ActiveRadarrBlock::Blocklist.into()
|
ActiveRadarrBlock::Blocklist.into()
|
||||||
);
|
);
|
||||||
assert_eq!(app.get_current_route(), ActiveRadarrBlock::Blocklist.into());
|
assert_navigation_pushed!(app, ActiveRadarrBlock::Blocklist.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rstest]
|
#[rstest]
|
||||||
@@ -113,13 +109,13 @@ mod tests {
|
|||||||
active_radarr_block: ActiveRadarrBlock,
|
active_radarr_block: ActiveRadarrBlock,
|
||||||
#[values(DEFAULT_KEYBINDINGS.left.key, DEFAULT_KEYBINDINGS.right.key)] key: Key,
|
#[values(DEFAULT_KEYBINDINGS.left.key, DEFAULT_KEYBINDINGS.right.key)] key: Key,
|
||||||
) {
|
) {
|
||||||
let mut app = App::default();
|
let mut app = App::test_default();
|
||||||
|
|
||||||
DownloadsHandler::with(key, &mut app, active_radarr_block, None).handle();
|
DownloadsHandler::new(key, &mut app, active_radarr_block, None).handle();
|
||||||
|
|
||||||
assert!(app.data.radarr_data.prompt_confirm);
|
assert!(app.data.radarr_data.prompt_confirm);
|
||||||
|
|
||||||
DownloadsHandler::with(key, &mut app, active_radarr_block, None).handle();
|
DownloadsHandler::new(key, &mut app, active_radarr_block, None).handle();
|
||||||
|
|
||||||
assert!(!app.data.radarr_data.prompt_confirm);
|
assert!(!app.data.radarr_data.prompt_confirm);
|
||||||
}
|
}
|
||||||
@@ -132,6 +128,7 @@ mod tests {
|
|||||||
use crate::network::radarr_network::RadarrEvent;
|
use crate::network::radarr_network::RadarrEvent;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use crate::assert_navigation_popped;
|
||||||
|
|
||||||
const SUBMIT_KEY: Key = DEFAULT_KEYBINDINGS.submit.key;
|
const SUBMIT_KEY: Key = DEFAULT_KEYBINDINGS.submit.key;
|
||||||
|
|
||||||
@@ -151,7 +148,7 @@ mod tests {
|
|||||||
#[case] prompt_block: ActiveRadarrBlock,
|
#[case] prompt_block: ActiveRadarrBlock,
|
||||||
#[case] expected_action: RadarrEvent,
|
#[case] expected_action: RadarrEvent,
|
||||||
) {
|
) {
|
||||||
let mut app = App::default();
|
let mut app = App::test_default();
|
||||||
app
|
app
|
||||||
.data
|
.data
|
||||||
.radarr_data
|
.radarr_data
|
||||||
@@ -161,14 +158,14 @@ mod tests {
|
|||||||
app.push_navigation_stack(base_route.into());
|
app.push_navigation_stack(base_route.into());
|
||||||
app.push_navigation_stack(prompt_block.into());
|
app.push_navigation_stack(prompt_block.into());
|
||||||
|
|
||||||
DownloadsHandler::with(SUBMIT_KEY, &mut app, prompt_block, None).handle();
|
DownloadsHandler::new(SUBMIT_KEY, &mut app, prompt_block, None).handle();
|
||||||
|
|
||||||
assert!(app.data.radarr_data.prompt_confirm);
|
assert!(app.data.radarr_data.prompt_confirm);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.data.radarr_data.prompt_confirm_action,
|
app.data.radarr_data.prompt_confirm_action,
|
||||||
Some(expected_action)
|
Some(expected_action)
|
||||||
);
|
);
|
||||||
assert_eq!(app.get_current_route(), base_route.into());
|
assert_navigation_popped!(app, base_route.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rstest]
|
#[rstest]
|
||||||
@@ -178,7 +175,7 @@ mod tests {
|
|||||||
#[case] base_route: ActiveRadarrBlock,
|
#[case] base_route: ActiveRadarrBlock,
|
||||||
#[case] prompt_block: ActiveRadarrBlock,
|
#[case] prompt_block: ActiveRadarrBlock,
|
||||||
) {
|
) {
|
||||||
let mut app = App::default();
|
let mut app = App::test_default();
|
||||||
app
|
app
|
||||||
.data
|
.data
|
||||||
.radarr_data
|
.radarr_data
|
||||||
@@ -187,19 +184,19 @@ mod tests {
|
|||||||
app.push_navigation_stack(base_route.into());
|
app.push_navigation_stack(base_route.into());
|
||||||
app.push_navigation_stack(prompt_block.into());
|
app.push_navigation_stack(prompt_block.into());
|
||||||
|
|
||||||
DownloadsHandler::with(SUBMIT_KEY, &mut app, prompt_block, None).handle();
|
DownloadsHandler::new(SUBMIT_KEY, &mut app, prompt_block, None).handle();
|
||||||
|
|
||||||
assert!(!app.data.radarr_data.prompt_confirm);
|
assert!(!app.data.radarr_data.prompt_confirm);
|
||||||
assert_eq!(app.data.radarr_data.prompt_confirm_action, None);
|
assert_none!(app.data.radarr_data.prompt_confirm_action);
|
||||||
assert_eq!(app.get_current_route(), base_route.into());
|
assert_navigation_popped!(app, base_route.into());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mod test_handle_esc {
|
mod test_handle_esc {
|
||||||
use pretty_assertions::assert_eq;
|
|
||||||
use rstest::rstest;
|
use rstest::rstest;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use crate::assert_navigation_popped;
|
||||||
|
|
||||||
const ESC_KEY: Key = DEFAULT_KEYBINDINGS.esc.key;
|
const ESC_KEY: Key = DEFAULT_KEYBINDINGS.esc.key;
|
||||||
|
|
||||||
@@ -210,50 +207,50 @@ mod tests {
|
|||||||
#[case] base_block: ActiveRadarrBlock,
|
#[case] base_block: ActiveRadarrBlock,
|
||||||
#[case] prompt_block: ActiveRadarrBlock,
|
#[case] prompt_block: ActiveRadarrBlock,
|
||||||
) {
|
) {
|
||||||
let mut app = App::default();
|
let mut app = App::test_default();
|
||||||
app.push_navigation_stack(base_block.into());
|
app.push_navigation_stack(base_block.into());
|
||||||
app.push_navigation_stack(prompt_block.into());
|
app.push_navigation_stack(prompt_block.into());
|
||||||
app.data.radarr_data.prompt_confirm = true;
|
app.data.radarr_data.prompt_confirm = true;
|
||||||
|
|
||||||
DownloadsHandler::with(ESC_KEY, &mut app, prompt_block, None).handle();
|
DownloadsHandler::new(ESC_KEY, &mut app, prompt_block, None).handle();
|
||||||
|
|
||||||
assert_eq!(app.get_current_route(), base_block.into());
|
assert_navigation_popped!(app, base_block.into());
|
||||||
assert!(!app.data.radarr_data.prompt_confirm);
|
assert!(!app.data.radarr_data.prompt_confirm);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rstest]
|
#[rstest]
|
||||||
fn test_default_esc(#[values(true, false)] is_ready: bool) {
|
fn test_default_esc(#[values(true, false)] is_ready: bool) {
|
||||||
let mut app = App::default();
|
let mut app = App::test_default();
|
||||||
app.is_loading = is_ready;
|
app.is_loading = is_ready;
|
||||||
app.error = "test error".to_owned().into();
|
app.error = "test error".to_owned().into();
|
||||||
app.push_navigation_stack(ActiveRadarrBlock::Downloads.into());
|
app.push_navigation_stack(ActiveRadarrBlock::Downloads.into());
|
||||||
app.push_navigation_stack(ActiveRadarrBlock::Downloads.into());
|
app.push_navigation_stack(ActiveRadarrBlock::Downloads.into());
|
||||||
|
|
||||||
DownloadsHandler::with(ESC_KEY, &mut app, ActiveRadarrBlock::Downloads, None).handle();
|
DownloadsHandler::new(ESC_KEY, &mut app, ActiveRadarrBlock::Downloads, None).handle();
|
||||||
|
|
||||||
assert_eq!(app.get_current_route(), ActiveRadarrBlock::Downloads.into());
|
assert_navigation_popped!(app, ActiveRadarrBlock::Downloads.into());
|
||||||
assert!(app.error.text.is_empty());
|
assert_is_empty!(app.error.text);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mod test_handle_key_char {
|
mod test_handle_key_char {
|
||||||
|
use crate::assert_navigation_popped;
|
||||||
|
use crate::network::radarr_network::RadarrEvent;
|
||||||
use pretty_assertions::assert_eq;
|
use pretty_assertions::assert_eq;
|
||||||
use rstest::rstest;
|
use rstest::rstest;
|
||||||
|
|
||||||
use crate::network::radarr_network::RadarrEvent;
|
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_update_downloads_key() {
|
fn test_update_downloads_key() {
|
||||||
let mut app = App::default();
|
let mut app = App::test_default();
|
||||||
app
|
app
|
||||||
.data
|
.data
|
||||||
.radarr_data
|
.radarr_data
|
||||||
.downloads
|
.downloads
|
||||||
.set_items(vec![DownloadRecord::default()]);
|
.set_items(vec![DownloadRecord::default()]);
|
||||||
|
|
||||||
DownloadsHandler::with(
|
DownloadsHandler::new(
|
||||||
DEFAULT_KEYBINDINGS.update.key,
|
DEFAULT_KEYBINDINGS.update.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
ActiveRadarrBlock::Downloads,
|
ActiveRadarrBlock::Downloads,
|
||||||
@@ -261,15 +258,12 @@ mod tests {
|
|||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert_eq!(
|
assert_navigation_pushed!(app, ActiveRadarrBlock::UpdateDownloadsPrompt.into());
|
||||||
app.get_current_route(),
|
|
||||||
ActiveRadarrBlock::UpdateDownloadsPrompt.into()
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_update_downloads_key_no_op_when_not_ready() {
|
fn test_update_downloads_key_no_op_when_not_ready() {
|
||||||
let mut app = App::default();
|
let mut app = App::test_default();
|
||||||
app.is_loading = true;
|
app.is_loading = true;
|
||||||
app.push_navigation_stack(ActiveRadarrBlock::Downloads.into());
|
app.push_navigation_stack(ActiveRadarrBlock::Downloads.into());
|
||||||
app
|
app
|
||||||
@@ -278,7 +272,7 @@ mod tests {
|
|||||||
.downloads
|
.downloads
|
||||||
.set_items(vec![DownloadRecord::default()]);
|
.set_items(vec![DownloadRecord::default()]);
|
||||||
|
|
||||||
DownloadsHandler::with(
|
DownloadsHandler::new(
|
||||||
DEFAULT_KEYBINDINGS.update.key,
|
DEFAULT_KEYBINDINGS.update.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
ActiveRadarrBlock::Downloads,
|
ActiveRadarrBlock::Downloads,
|
||||||
@@ -291,7 +285,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_refresh_downloads_key() {
|
fn test_refresh_downloads_key() {
|
||||||
let mut app = App::default();
|
let mut app = App::test_default();
|
||||||
app
|
app
|
||||||
.data
|
.data
|
||||||
.radarr_data
|
.radarr_data
|
||||||
@@ -299,7 +293,7 @@ mod tests {
|
|||||||
.set_items(vec![DownloadRecord::default()]);
|
.set_items(vec![DownloadRecord::default()]);
|
||||||
app.push_navigation_stack(ActiveRadarrBlock::Downloads.into());
|
app.push_navigation_stack(ActiveRadarrBlock::Downloads.into());
|
||||||
|
|
||||||
DownloadsHandler::with(
|
DownloadsHandler::new(
|
||||||
DEFAULT_KEYBINDINGS.refresh.key,
|
DEFAULT_KEYBINDINGS.refresh.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
ActiveRadarrBlock::Downloads,
|
ActiveRadarrBlock::Downloads,
|
||||||
@@ -307,13 +301,13 @@ mod tests {
|
|||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert_eq!(app.get_current_route(), ActiveRadarrBlock::Downloads.into());
|
assert_navigation_pushed!(app, ActiveRadarrBlock::Downloads.into());
|
||||||
assert!(app.should_refresh);
|
assert!(app.should_refresh);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_refresh_downloads_key_no_op_when_not_ready() {
|
fn test_refresh_downloads_key_no_op_when_not_ready() {
|
||||||
let mut app = App::default();
|
let mut app = App::test_default();
|
||||||
app.is_loading = true;
|
app.is_loading = true;
|
||||||
app.push_navigation_stack(ActiveRadarrBlock::Downloads.into());
|
app.push_navigation_stack(ActiveRadarrBlock::Downloads.into());
|
||||||
app
|
app
|
||||||
@@ -322,7 +316,7 @@ mod tests {
|
|||||||
.downloads
|
.downloads
|
||||||
.set_items(vec![DownloadRecord::default()]);
|
.set_items(vec![DownloadRecord::default()]);
|
||||||
|
|
||||||
DownloadsHandler::with(
|
DownloadsHandler::new(
|
||||||
DEFAULT_KEYBINDINGS.refresh.key,
|
DEFAULT_KEYBINDINGS.refresh.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
ActiveRadarrBlock::Downloads,
|
ActiveRadarrBlock::Downloads,
|
||||||
@@ -350,7 +344,7 @@ mod tests {
|
|||||||
#[case] prompt_block: ActiveRadarrBlock,
|
#[case] prompt_block: ActiveRadarrBlock,
|
||||||
#[case] expected_action: RadarrEvent,
|
#[case] expected_action: RadarrEvent,
|
||||||
) {
|
) {
|
||||||
let mut app = App::default();
|
let mut app = App::test_default();
|
||||||
app
|
app
|
||||||
.data
|
.data
|
||||||
.radarr_data
|
.radarr_data
|
||||||
@@ -359,7 +353,7 @@ mod tests {
|
|||||||
app.push_navigation_stack(base_route.into());
|
app.push_navigation_stack(base_route.into());
|
||||||
app.push_navigation_stack(prompt_block.into());
|
app.push_navigation_stack(prompt_block.into());
|
||||||
|
|
||||||
DownloadsHandler::with(
|
DownloadsHandler::new(
|
||||||
DEFAULT_KEYBINDINGS.confirm.key,
|
DEFAULT_KEYBINDINGS.confirm.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
prompt_block,
|
prompt_block,
|
||||||
@@ -372,7 +366,7 @@ mod tests {
|
|||||||
app.data.radarr_data.prompt_confirm_action,
|
app.data.radarr_data.prompt_confirm_action,
|
||||||
Some(expected_action)
|
Some(expected_action)
|
||||||
);
|
);
|
||||||
assert_eq!(app.get_current_route(), base_route.into());
|
assert_navigation_popped!(app, base_route.into());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -387,16 +381,35 @@ mod tests {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
fn test_downloads_handler_ignore_special_keys(
|
||||||
|
#[values(true, false)] ignore_special_keys_for_textbox_input: bool,
|
||||||
|
) {
|
||||||
|
let mut app = App::test_default();
|
||||||
|
app.ignore_special_keys_for_textbox_input = ignore_special_keys_for_textbox_input;
|
||||||
|
let handler = DownloadsHandler::new(
|
||||||
|
DEFAULT_KEYBINDINGS.esc.key,
|
||||||
|
&mut app,
|
||||||
|
ActiveRadarrBlock::default(),
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
handler.ignore_special_keys(),
|
||||||
|
ignore_special_keys_for_textbox_input
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_extract_download_id() {
|
fn test_extract_download_id() {
|
||||||
let mut app = App::default();
|
let mut app = App::test_default();
|
||||||
app
|
app
|
||||||
.data
|
.data
|
||||||
.radarr_data
|
.radarr_data
|
||||||
.downloads
|
.downloads
|
||||||
.set_items(vec![download_record()]);
|
.set_items(vec![download_record()]);
|
||||||
|
|
||||||
let download_id = DownloadsHandler::with(
|
let download_id = DownloadsHandler::new(
|
||||||
DEFAULT_KEYBINDINGS.esc.key,
|
DEFAULT_KEYBINDINGS.esc.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
ActiveRadarrBlock::Downloads,
|
ActiveRadarrBlock::Downloads,
|
||||||
@@ -409,10 +422,10 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_downloads_handler_not_ready_when_loading() {
|
fn test_downloads_handler_not_ready_when_loading() {
|
||||||
let mut app = App::default();
|
let mut app = App::test_default();
|
||||||
app.is_loading = true;
|
app.is_loading = true;
|
||||||
|
|
||||||
let handler = DownloadsHandler::with(
|
let handler = DownloadsHandler::new(
|
||||||
DEFAULT_KEYBINDINGS.esc.key,
|
DEFAULT_KEYBINDINGS.esc.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
ActiveRadarrBlock::Downloads,
|
ActiveRadarrBlock::Downloads,
|
||||||
@@ -424,10 +437,10 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_downloads_handler_not_ready_when_downloads_is_empty() {
|
fn test_downloads_handler_not_ready_when_downloads_is_empty() {
|
||||||
let mut app = App::default();
|
let mut app = App::test_default();
|
||||||
app.is_loading = false;
|
app.is_loading = false;
|
||||||
|
|
||||||
let handler = DownloadsHandler::with(
|
let handler = DownloadsHandler::new(
|
||||||
DEFAULT_KEYBINDINGS.esc.key,
|
DEFAULT_KEYBINDINGS.esc.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
ActiveRadarrBlock::Downloads,
|
ActiveRadarrBlock::Downloads,
|
||||||
@@ -439,7 +452,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_downloads_handler_ready_when_not_loading_and_downloads_is_not_empty() {
|
fn test_downloads_handler_ready_when_not_loading_and_downloads_is_not_empty() {
|
||||||
let mut app = App::default();
|
let mut app = App::test_default();
|
||||||
app.is_loading = false;
|
app.is_loading = false;
|
||||||
|
|
||||||
app
|
app
|
||||||
@@ -447,7 +460,7 @@ mod tests {
|
|||||||
.radarr_data
|
.radarr_data
|
||||||
.downloads
|
.downloads
|
||||||
.set_items(vec![DownloadRecord::default()]);
|
.set_items(vec![DownloadRecord::default()]);
|
||||||
let handler = DownloadsHandler::with(
|
let handler = DownloadsHandler::new(
|
||||||
DEFAULT_KEYBINDINGS.esc.key,
|
DEFAULT_KEYBINDINGS.esc.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
ActiveRadarrBlock::Downloads,
|
ActiveRadarrBlock::Downloads,
|
||||||
|
|||||||
@@ -1,11 +1,9 @@
|
|||||||
use crate::app::key_binding::DEFAULT_KEYBINDINGS;
|
|
||||||
use crate::app::App;
|
use crate::app::App;
|
||||||
use crate::event::Key;
|
use crate::event::Key;
|
||||||
use crate::handle_table_events;
|
|
||||||
use crate::handlers::radarr_handlers::handle_change_tab_left_right_keys;
|
use crate::handlers::radarr_handlers::handle_change_tab_left_right_keys;
|
||||||
use crate::handlers::table_handler::TableHandlingConfig;
|
use crate::handlers::table_handler::{TableHandlingConfig, handle_table};
|
||||||
use crate::handlers::{handle_clear_errors, handle_prompt_toggle, KeyEventHandler};
|
use crate::handlers::{KeyEventHandler, handle_clear_errors, handle_prompt_toggle};
|
||||||
use crate::models::radarr_models::DownloadRecord;
|
use crate::matches_key;
|
||||||
use crate::models::servarr_data::radarr::radarr_data::{ActiveRadarrBlock, DOWNLOADS_BLOCKS};
|
use crate::models::servarr_data::radarr::radarr_data::{ActiveRadarrBlock, DOWNLOADS_BLOCKS};
|
||||||
use crate::network::radarr_network::RadarrEvent;
|
use crate::network::radarr_network::RadarrEvent;
|
||||||
|
|
||||||
@@ -20,14 +18,7 @@ pub(super) struct DownloadsHandler<'a, 'b> {
|
|||||||
_context: Option<ActiveRadarrBlock>,
|
_context: Option<ActiveRadarrBlock>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'b> DownloadsHandler<'a, 'b> {
|
impl DownloadsHandler<'_, '_> {
|
||||||
handle_table_events!(
|
|
||||||
self,
|
|
||||||
downloads,
|
|
||||||
self.app.data.radarr_data.downloads,
|
|
||||||
DownloadRecord
|
|
||||||
);
|
|
||||||
|
|
||||||
fn extract_download_id(&self) -> i64 {
|
fn extract_download_id(&self) -> i64 {
|
||||||
self.app.data.radarr_data.downloads.current_selection().id
|
self.app.data.radarr_data.downloads.current_selection().id
|
||||||
}
|
}
|
||||||
@@ -38,7 +29,11 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for DownloadsHandler<'a,
|
|||||||
let downloads_table_handling_config =
|
let downloads_table_handling_config =
|
||||||
TableHandlingConfig::new(ActiveRadarrBlock::Downloads.into());
|
TableHandlingConfig::new(ActiveRadarrBlock::Downloads.into());
|
||||||
|
|
||||||
if !self.handle_downloads_table_events(downloads_table_handling_config) {
|
if !handle_table(
|
||||||
|
self,
|
||||||
|
|app| &mut app.data.radarr_data.downloads,
|
||||||
|
downloads_table_handling_config,
|
||||||
|
) {
|
||||||
self.handle_key_event();
|
self.handle_key_event();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -47,7 +42,11 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for DownloadsHandler<'a,
|
|||||||
DOWNLOADS_BLOCKS.contains(&active_block)
|
DOWNLOADS_BLOCKS.contains(&active_block)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn with(
|
fn ignore_special_keys(&self) -> bool {
|
||||||
|
self.app.ignore_special_keys_for_textbox_input
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new(
|
||||||
key: Key,
|
key: Key,
|
||||||
app: &'a mut App<'b>,
|
app: &'a mut App<'b>,
|
||||||
active_block: ActiveRadarrBlock,
|
active_block: ActiveRadarrBlock,
|
||||||
@@ -130,18 +129,18 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for DownloadsHandler<'a,
|
|||||||
let key = self.key;
|
let key = self.key;
|
||||||
match self.active_radarr_block {
|
match self.active_radarr_block {
|
||||||
ActiveRadarrBlock::Downloads => match self.key {
|
ActiveRadarrBlock::Downloads => match self.key {
|
||||||
_ if key == DEFAULT_KEYBINDINGS.update.key => {
|
_ if matches_key!(update, key) => {
|
||||||
self
|
self
|
||||||
.app
|
.app
|
||||||
.push_navigation_stack(ActiveRadarrBlock::UpdateDownloadsPrompt.into());
|
.push_navigation_stack(ActiveRadarrBlock::UpdateDownloadsPrompt.into());
|
||||||
}
|
}
|
||||||
_ if key == DEFAULT_KEYBINDINGS.refresh.key => {
|
_ if matches_key!(refresh, key) => {
|
||||||
self.app.should_refresh = true;
|
self.app.should_refresh = true;
|
||||||
}
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
},
|
},
|
||||||
ActiveRadarrBlock::DeleteDownloadPrompt => {
|
ActiveRadarrBlock::DeleteDownloadPrompt => {
|
||||||
if key == DEFAULT_KEYBINDINGS.confirm.key {
|
if matches_key!(confirm, key) {
|
||||||
self.app.data.radarr_data.prompt_confirm = true;
|
self.app.data.radarr_data.prompt_confirm = true;
|
||||||
self.app.data.radarr_data.prompt_confirm_action =
|
self.app.data.radarr_data.prompt_confirm_action =
|
||||||
Some(RadarrEvent::DeleteDownload(self.extract_download_id()));
|
Some(RadarrEvent::DeleteDownload(self.extract_download_id()));
|
||||||
@@ -150,7 +149,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for DownloadsHandler<'a,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
ActiveRadarrBlock::UpdateDownloadsPrompt => {
|
ActiveRadarrBlock::UpdateDownloadsPrompt => {
|
||||||
if key == DEFAULT_KEYBINDINGS.confirm.key {
|
if matches_key!(confirm, key) {
|
||||||
self.app.data.radarr_data.prompt_confirm = true;
|
self.app.data.radarr_data.prompt_confirm = true;
|
||||||
self.app.data.radarr_data.prompt_confirm_action = Some(RadarrEvent::UpdateDownloads);
|
self.app.data.radarr_data.prompt_confirm_action = Some(RadarrEvent::UpdateDownloads);
|
||||||
|
|
||||||
@@ -160,4 +159,12 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for DownloadsHandler<'a,
|
|||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn app_mut(&mut self) -> &mut App<'b> {
|
||||||
|
self.app
|
||||||
|
}
|
||||||
|
|
||||||
|
fn current_route(&self) -> crate::models::Route {
|
||||||
|
self.app.get_current_route()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
use crate::app::key_binding::DEFAULT_KEYBINDINGS;
|
|
||||||
use crate::app::App;
|
use crate::app::App;
|
||||||
use crate::event::Key;
|
use crate::event::Key;
|
||||||
use crate::handlers::{handle_prompt_toggle, KeyEventHandler};
|
use crate::handlers::{KeyEventHandler, handle_prompt_toggle};
|
||||||
use crate::models::servarr_data::modals::EditIndexerModal;
|
use crate::models::servarr_data::modals::EditIndexerModal;
|
||||||
use crate::models::servarr_data::radarr::radarr_data::{ActiveRadarrBlock, EDIT_INDEXER_BLOCKS};
|
use crate::models::servarr_data::radarr::radarr_data::{ActiveRadarrBlock, EDIT_INDEXER_BLOCKS};
|
||||||
use crate::models::servarr_models::EditIndexerParams;
|
use crate::models::servarr_models::EditIndexerParams;
|
||||||
use crate::network::radarr_network::RadarrEvent;
|
use crate::network::radarr_network::RadarrEvent;
|
||||||
use crate::{handle_prompt_left_right_keys, handle_text_box_keys, handle_text_box_left_right_keys};
|
use crate::{
|
||||||
|
handle_prompt_left_right_keys, handle_text_box_keys, handle_text_box_left_right_keys, matches_key,
|
||||||
|
};
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
#[path = "edit_indexer_handler_tests.rs"]
|
#[path = "edit_indexer_handler_tests.rs"]
|
||||||
@@ -19,58 +20,44 @@ pub(super) struct EditIndexerHandler<'a, 'b> {
|
|||||||
_context: Option<ActiveRadarrBlock>,
|
_context: Option<ActiveRadarrBlock>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'b> EditIndexerHandler<'a, 'b> {
|
impl EditIndexerHandler<'_, '_> {
|
||||||
fn build_edit_indexer_params(&mut self) -> EditIndexerParams {
|
fn build_edit_indexer_params(&mut self) -> EditIndexerParams {
|
||||||
let indexer_id = self.app.data.radarr_data.indexers.current_selection().id;
|
let edit_indexer_modal = self
|
||||||
let tags = self
|
|
||||||
.app
|
.app
|
||||||
.data
|
.data
|
||||||
.radarr_data
|
.radarr_data
|
||||||
.edit_indexer_modal
|
.edit_indexer_modal
|
||||||
.as_ref()
|
.take()
|
||||||
.unwrap()
|
.expect("Edit Indexer Modal is None");
|
||||||
.tags
|
let indexer_id = self.app.data.radarr_data.indexers.current_selection().id;
|
||||||
.text
|
let tags = edit_indexer_modal.tags.text;
|
||||||
.clone();
|
|
||||||
|
|
||||||
let params = {
|
let EditIndexerModal {
|
||||||
let EditIndexerModal {
|
name,
|
||||||
name,
|
enable_rss,
|
||||||
enable_rss,
|
enable_automatic_search,
|
||||||
enable_automatic_search,
|
enable_interactive_search,
|
||||||
enable_interactive_search,
|
url,
|
||||||
url,
|
api_key,
|
||||||
api_key,
|
seed_ratio,
|
||||||
seed_ratio,
|
priority,
|
||||||
priority,
|
..
|
||||||
..
|
} = edit_indexer_modal;
|
||||||
} = self
|
|
||||||
.app
|
|
||||||
.data
|
|
||||||
.radarr_data
|
|
||||||
.edit_indexer_modal
|
|
||||||
.as_ref()
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
EditIndexerParams {
|
EditIndexerParams {
|
||||||
indexer_id,
|
indexer_id,
|
||||||
name: Some(name.text.clone()),
|
name: Some(name.text),
|
||||||
enable_rss: Some(enable_rss.unwrap_or_default()),
|
enable_rss: Some(enable_rss.unwrap_or_default()),
|
||||||
enable_automatic_search: Some(enable_automatic_search.unwrap_or_default()),
|
enable_automatic_search: Some(enable_automatic_search.unwrap_or_default()),
|
||||||
enable_interactive_search: Some(enable_interactive_search.unwrap_or_default()),
|
enable_interactive_search: Some(enable_interactive_search.unwrap_or_default()),
|
||||||
url: Some(url.text.clone()),
|
url: Some(url.text),
|
||||||
api_key: Some(api_key.text.clone()),
|
api_key: Some(api_key.text),
|
||||||
seed_ratio: Some(seed_ratio.text.clone()),
|
seed_ratio: Some(seed_ratio.text),
|
||||||
tags: None,
|
tags: None,
|
||||||
tag_input_string: Some(tags),
|
tag_input_string: Some(tags),
|
||||||
priority: Some(*priority),
|
priority: Some(priority),
|
||||||
clear_tags: false,
|
clear_tags: false,
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
self.app.data.radarr_data.edit_indexer_modal = None;
|
|
||||||
|
|
||||||
params
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -79,7 +66,11 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for EditIndexerHandler<'
|
|||||||
EDIT_INDEXER_BLOCKS.contains(&active_block)
|
EDIT_INDEXER_BLOCKS.contains(&active_block)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn with(
|
fn ignore_special_keys(&self) -> bool {
|
||||||
|
self.app.ignore_special_keys_for_textbox_input
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new(
|
||||||
key: Key,
|
key: Key,
|
||||||
app: &'a mut App<'b>,
|
app: &'a mut App<'b>,
|
||||||
active_block: ActiveRadarrBlock,
|
active_block: ActiveRadarrBlock,
|
||||||
@@ -370,7 +361,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for EditIndexerHandler<'
|
|||||||
| ActiveRadarrBlock::EditIndexerSeedRatioInput
|
| ActiveRadarrBlock::EditIndexerSeedRatioInput
|
||||||
| ActiveRadarrBlock::EditIndexerTagsInput => {
|
| ActiveRadarrBlock::EditIndexerTagsInput => {
|
||||||
self.app.push_navigation_stack(selected_block.into());
|
self.app.push_navigation_stack(selected_block.into());
|
||||||
self.app.should_ignore_quit_key = true;
|
self.app.ignore_special_keys_for_textbox_input = true;
|
||||||
}
|
}
|
||||||
ActiveRadarrBlock::EditIndexerPriorityInput => self
|
ActiveRadarrBlock::EditIndexerPriorityInput => self
|
||||||
.app
|
.app
|
||||||
@@ -416,7 +407,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for EditIndexerHandler<'
|
|||||||
| ActiveRadarrBlock::EditIndexerSeedRatioInput
|
| ActiveRadarrBlock::EditIndexerSeedRatioInput
|
||||||
| ActiveRadarrBlock::EditIndexerTagsInput => {
|
| ActiveRadarrBlock::EditIndexerTagsInput => {
|
||||||
self.app.pop_navigation_stack();
|
self.app.pop_navigation_stack();
|
||||||
self.app.should_ignore_quit_key = false;
|
self.app.ignore_special_keys_for_textbox_input = false;
|
||||||
}
|
}
|
||||||
ActiveRadarrBlock::EditIndexerPriorityInput => self.app.pop_navigation_stack(),
|
ActiveRadarrBlock::EditIndexerPriorityInput => self.app.pop_navigation_stack(),
|
||||||
_ => (),
|
_ => (),
|
||||||
@@ -437,7 +428,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for EditIndexerHandler<'
|
|||||||
| ActiveRadarrBlock::EditIndexerPriorityInput
|
| ActiveRadarrBlock::EditIndexerPriorityInput
|
||||||
| ActiveRadarrBlock::EditIndexerTagsInput => {
|
| ActiveRadarrBlock::EditIndexerTagsInput => {
|
||||||
self.app.pop_navigation_stack();
|
self.app.pop_navigation_stack();
|
||||||
self.app.should_ignore_quit_key = false;
|
self.app.ignore_special_keys_for_textbox_input = false;
|
||||||
}
|
}
|
||||||
_ => self.app.pop_navigation_stack(),
|
_ => self.app.pop_navigation_stack(),
|
||||||
}
|
}
|
||||||
@@ -518,7 +509,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for EditIndexerHandler<'
|
|||||||
ActiveRadarrBlock::EditIndexerPrompt => {
|
ActiveRadarrBlock::EditIndexerPrompt => {
|
||||||
if self.app.data.radarr_data.selected_block.get_active_block()
|
if self.app.data.radarr_data.selected_block.get_active_block()
|
||||||
== ActiveRadarrBlock::EditIndexerConfirmPrompt
|
== ActiveRadarrBlock::EditIndexerConfirmPrompt
|
||||||
&& self.key == DEFAULT_KEYBINDINGS.confirm.key
|
&& matches_key!(confirm, self.key)
|
||||||
{
|
{
|
||||||
self.app.data.radarr_data.prompt_confirm = true;
|
self.app.data.radarr_data.prompt_confirm = true;
|
||||||
self.app.data.radarr_data.prompt_confirm_action =
|
self.app.data.radarr_data.prompt_confirm_action =
|
||||||
@@ -531,4 +522,12 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for EditIndexerHandler<'
|
|||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn app_mut(&mut self) -> &mut App<'b> {
|
||||||
|
self.app
|
||||||
|
}
|
||||||
|
|
||||||
|
fn current_route(&self) -> crate::models::Route {
|
||||||
|
self.app.get_current_route()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user