Remove unwanted file
This commit is contained in:
parent
e225d3ebbe
commit
8ee7580ff2
180 changed files with 0 additions and 37275 deletions
|
@ -1,12 +0,0 @@
|
||||||
module.exports = {
|
|
||||||
"extends": "airbnb-base",
|
|
||||||
"env": {
|
|
||||||
"browser": true,
|
|
||||||
},
|
|
||||||
"rules": {
|
|
||||||
"no-param-reassign": 0, // manipulate DOM style properties
|
|
||||||
"no-restricted-globals": 0, // currently Shaarli uses alert/confirm, could be be improved later
|
|
||||||
"no-alert": 0, // currently Shaarli uses alert/confirm, could be be improved later
|
|
||||||
"no-cond-assign": [2, "except-parens"], // assignment in while loops is readable and avoid assignment duplication
|
|
||||||
}
|
|
||||||
};
|
|
|
@ -1,15 +0,0 @@
|
||||||
module.exports = {
|
|
||||||
extends: 'stylelint-config-standard',
|
|
||||||
plugins: [
|
|
||||||
"stylelint-scss"
|
|
||||||
],
|
|
||||||
rules: {
|
|
||||||
"indentation": [2],
|
|
||||||
"number-leading-zero": null,
|
|
||||||
// Replace CSS @ with SASS ones
|
|
||||||
"at-rule-no-unknown": null,
|
|
||||||
"scss/at-rule-no-unknown": true,
|
|
||||||
// not compatible with SASS apparently
|
|
||||||
"no-descending-specificity": null
|
|
||||||
},
|
|
||||||
}
|
|
|
@ -1,13 +0,0 @@
|
||||||
<IfModule version_module>
|
|
||||||
<IfVersion >= 2.4>
|
|
||||||
Require all denied
|
|
||||||
</IfVersion>
|
|
||||||
<IfVersion < 2.4>
|
|
||||||
Allow from none
|
|
||||||
Deny from all
|
|
||||||
</IfVersion>
|
|
||||||
</IfModule>
|
|
||||||
|
|
||||||
<IfModule !version_module>
|
|
||||||
Require all denied
|
|
||||||
</IfModule>
|
|
|
@ -1,60 +0,0 @@
|
||||||
user nginx nginx;
|
|
||||||
daemon off;
|
|
||||||
worker_processes 4;
|
|
||||||
pid /var/run/nginx.pid;
|
|
||||||
|
|
||||||
events {
|
|
||||||
worker_connections 768;
|
|
||||||
}
|
|
||||||
|
|
||||||
http {
|
|
||||||
include mime.types;
|
|
||||||
default_type application/octet-stream;
|
|
||||||
keepalive_timeout 20;
|
|
||||||
|
|
||||||
client_max_body_size 10m;
|
|
||||||
|
|
||||||
index index.html index.php;
|
|
||||||
|
|
||||||
server {
|
|
||||||
listen 80;
|
|
||||||
listen [::]:80;
|
|
||||||
root /var/www/shaarli;
|
|
||||||
|
|
||||||
access_log /var/log/nginx/shaarli.access.log;
|
|
||||||
error_log /var/log/nginx/shaarli.error.log;
|
|
||||||
|
|
||||||
location ~* \.(?:ico|css|js|gif|jpe?g|png|ttf|oet|woff2?)$ {
|
|
||||||
# cache static assets
|
|
||||||
expires max;
|
|
||||||
add_header Pragma public;
|
|
||||||
add_header Cache-Control "public, must-revalidate, proxy-revalidate";
|
|
||||||
}
|
|
||||||
|
|
||||||
location = /favicon.ico {
|
|
||||||
# serve the Shaarli favicon from its custom location
|
|
||||||
alias /var/www/shaarli/images/favicon.ico;
|
|
||||||
}
|
|
||||||
|
|
||||||
location /doc/html/ {
|
|
||||||
default_type "text/html";
|
|
||||||
try_files $uri $uri/ $uri.html =404;
|
|
||||||
}
|
|
||||||
|
|
||||||
location / {
|
|
||||||
# Slim - rewrite URLs & do NOT serve static files through this location
|
|
||||||
try_files _ /index.php$is_args$args;
|
|
||||||
}
|
|
||||||
|
|
||||||
location ~ index\.php$ {
|
|
||||||
# Slim - split URL path into (script_filename, path_info)
|
|
||||||
try_files $uri =404;
|
|
||||||
fastcgi_split_path_info ^(index.php)(/.+)$;
|
|
||||||
|
|
||||||
# filter and proxy PHP requests to PHP-FPM
|
|
||||||
fastcgi_pass unix:/var/run/php-fpm.sock;
|
|
||||||
fastcgi_index index.php;
|
|
||||||
include fastcgi.conf;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,16 +0,0 @@
|
||||||
[global]
|
|
||||||
daemonize = no
|
|
||||||
|
|
||||||
[www]
|
|
||||||
user = nginx
|
|
||||||
group = nginx
|
|
||||||
listen.owner = nginx
|
|
||||||
listen.group = nginx
|
|
||||||
catch_workers_output = yes
|
|
||||||
listen = /var/run/php-fpm.sock
|
|
||||||
pm = dynamic
|
|
||||||
pm.max_children = 20
|
|
||||||
pm.start_servers = 1
|
|
||||||
pm.min_spare_servers = 1
|
|
||||||
pm.max_spare_servers = 3
|
|
||||||
pm.max_requests = 2048
|
|
|
@ -1,2 +0,0 @@
|
||||||
#!/bin/sh
|
|
||||||
/bin/true
|
|
|
@ -1,2 +0,0 @@
|
||||||
#!/bin/execlineb -P
|
|
||||||
nginx
|
|
|
@ -1,2 +0,0 @@
|
||||||
#!/bin/execlineb -P
|
|
||||||
php-fpm8 -F
|
|
|
@ -1,64 +0,0 @@
|
||||||
# Docker-ignore
|
|
||||||
.dev
|
|
||||||
.git
|
|
||||||
.github
|
|
||||||
.gitattributes
|
|
||||||
.gitignore
|
|
||||||
tests
|
|
||||||
|
|
||||||
# Docker related resources are not needed inside the container
|
|
||||||
.dockerignore
|
|
||||||
Dockerfile
|
|
||||||
Dockerfile.armhf
|
|
||||||
|
|
||||||
# Docker Compose resources
|
|
||||||
docker-compose.yml
|
|
||||||
|
|
||||||
# Shaarli runtime resources
|
|
||||||
cache/*
|
|
||||||
data/*
|
|
||||||
pagecache/*
|
|
||||||
tmp/*
|
|
||||||
|
|
||||||
# Shaarli's docs are created during the build
|
|
||||||
doc/html/
|
|
||||||
|
|
||||||
# Eclipse project files
|
|
||||||
.settings
|
|
||||||
.buildpath
|
|
||||||
.project
|
|
||||||
|
|
||||||
# Raintpl generated pages
|
|
||||||
*.rtpl.php
|
|
||||||
|
|
||||||
# 3rd-party dependencies
|
|
||||||
vendor/
|
|
||||||
|
|
||||||
# Release archives
|
|
||||||
*.tar.gz
|
|
||||||
*.zip
|
|
||||||
inc/languages/*/LC_MESSAGES/shaarli.mo
|
|
||||||
|
|
||||||
# Development and test resources
|
|
||||||
coverage
|
|
||||||
doxygen
|
|
||||||
sandbox
|
|
||||||
phpmd.html
|
|
||||||
|
|
||||||
# User plugin configuration
|
|
||||||
plugins/*/config.php
|
|
||||||
|
|
||||||
# 3rd party themes
|
|
||||||
tpl/*
|
|
||||||
!tpl/default
|
|
||||||
!tpl/vintage
|
|
||||||
|
|
||||||
# Front end
|
|
||||||
node_modules
|
|
||||||
tpl/default/js
|
|
||||||
tpl/default/css
|
|
||||||
tpl/default/fonts
|
|
||||||
tpl/default/img
|
|
||||||
tpl/vintage/js
|
|
||||||
tpl/vintage/css
|
|
||||||
tpl/vintage/img
|
|
|
@ -1,23 +0,0 @@
|
||||||
# EditorConfig: http://EditorConfig.org
|
|
||||||
|
|
||||||
root = true
|
|
||||||
|
|
||||||
[*]
|
|
||||||
charset = utf-8
|
|
||||||
end_of_line = lf
|
|
||||||
insert_final_newline = true
|
|
||||||
trim_trailing_whitespace = true
|
|
||||||
indent_style = space
|
|
||||||
indent_size = 4
|
|
||||||
|
|
||||||
[*.{htaccess,html,scss,js,json,xml,yml}]
|
|
||||||
indent_size = 2
|
|
||||||
|
|
||||||
[*.php]
|
|
||||||
max_line_length = 120
|
|
||||||
|
|
||||||
[Dockerfile]
|
|
||||||
max_line_length = 80
|
|
||||||
|
|
||||||
[Makefile]
|
|
||||||
indent_style = tab
|
|
47
.gitattributes
vendored
47
.gitattributes
vendored
|
@ -1,47 +0,0 @@
|
||||||
# Set default behavior
|
|
||||||
* text=auto eol=lf
|
|
||||||
|
|
||||||
# Ensure sources are processed
|
|
||||||
*.conf text
|
|
||||||
*.css text
|
|
||||||
*.html text diff=html
|
|
||||||
*.js text
|
|
||||||
*.md text
|
|
||||||
*.php text diff=php
|
|
||||||
Dockerfile text
|
|
||||||
|
|
||||||
# Do not alter images nor minified scripts nor fonts
|
|
||||||
*.ico binary
|
|
||||||
*.jpg binary
|
|
||||||
*.png binary
|
|
||||||
*.svg binary
|
|
||||||
*.otf binary
|
|
||||||
*.eot binary
|
|
||||||
*.woff binary
|
|
||||||
*.woff2 binary
|
|
||||||
*.ttf binary
|
|
||||||
*.min.css binary
|
|
||||||
*.min.js binary
|
|
||||||
*.mo binary
|
|
||||||
|
|
||||||
# Exclude from Git archives
|
|
||||||
.editorconfig export-ignore
|
|
||||||
.dev export-ignore
|
|
||||||
.gitattributes export-ignore
|
|
||||||
.github export-ignore
|
|
||||||
.gitignore export-ignore
|
|
||||||
.travis.yml export-ignore
|
|
||||||
doc/**/*.json export-ignore
|
|
||||||
doc/**/*.md export-ignore
|
|
||||||
.docker/ export-ignore
|
|
||||||
.dockerignore export-ignore
|
|
||||||
docker-compose.* export-ignore
|
|
||||||
Dockerfile* export-ignore
|
|
||||||
Doxyfile export-ignore
|
|
||||||
Makefile export-ignore
|
|
||||||
node_modules/ export-ignore
|
|
||||||
doc/conf.py export-ignore
|
|
||||||
doc/requirements.txt export-ignore
|
|
||||||
doc/html/.doctrees/ export-ignore
|
|
||||||
phpunit.xml export-ignore
|
|
||||||
tests/ export-ignore
|
|
22
.github/mailmap
vendored
22
.github/mailmap
vendored
|
@ -1,22 +0,0 @@
|
||||||
ArthurHoaro <arthur@hoa.ro> <arthur.hoareau@wizacha.com>
|
|
||||||
ArthurHoaro <arthur@hoa.ro> Arthur
|
|
||||||
Florian Eula <eula.florian@gmail.com> feula
|
|
||||||
Florian Eula <eula.florian@gmail.com> <mr.pikzen@gmail.com>
|
|
||||||
Immánuel Fodor <immanuelfactor+github@gmail.com>
|
|
||||||
Immánuel Fodor <immanuelfactor+github@gmail.com> Immánuel! <21174107+immanuelfodor@users.noreply.github.com>
|
|
||||||
kalvn <kalvnthereal@gmail.com> <kalvn@users.noreply.github.com>
|
|
||||||
kalvn <kalvnthereal@gmail.com> <kalvn@pm.me>
|
|
||||||
Neros <contact@neros.fr> <NerosTie@users.noreply.github.com>
|
|
||||||
Nicolas Danelon <hi@nicolasmd.com.ar> nicolasm
|
|
||||||
Nicolas Danelon <hi@nicolasmd.com.ar> <nda@3818.com.ar>
|
|
||||||
Nicolas Danelon <hi@nicolasmd.com.ar> <nicolasdanelon@gmail.com>
|
|
||||||
Nicolas Danelon <hi@nicolasmd.com.ar> <nicolasdanelon@users.noreply.github.com>
|
|
||||||
Sébastien Sauvage <sebsauvage@sebsauvage.net>
|
|
||||||
Sébastien NOBILI <code@pipoprods.org> <s-code-github@pipoprods.org>
|
|
||||||
Timo Van Neerden <fire@lehollandaisvolant.net>
|
|
||||||
Timo Van Neerden <fire@lehollandaisvolant.net> lehollandaisvolant <levoltigeurhollandais@gmail.com>
|
|
||||||
VirtualTam <virtualtam@flibidi.net> <tamisier.aurelien@gmail.com>
|
|
||||||
VirtualTam <virtualtam@flibidi.net> <virtualtam+github@flibidi.net>
|
|
||||||
VirtualTam <virtualtam@flibidi.net> <virtualtam@flibidi.org>
|
|
||||||
Willi Eggeling <thewilli@gmail.com> <mail@wje-online.de>
|
|
||||||
Willi Eggeling <thewilli@gmail.com> <thewilli@users.noreply.github.com>
|
|
106
.github/workflows/ci.yml
vendored
106
.github/workflows/ci.yml
vendored
|
@ -1,106 +0,0 @@
|
||||||
name: Shaarli CI
|
|
||||||
on: [push, pull_request]
|
|
||||||
jobs:
|
|
||||||
php:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
php-versions: ['7.4', '8.0', '8.1', '8.2']
|
|
||||||
name: PHP ${{ matrix.php-versions }}
|
|
||||||
steps:
|
|
||||||
- name: Set locales
|
|
||||||
run: |
|
|
||||||
sudo locale-gen de_DE.utf8 && \
|
|
||||||
sudo locale-gen en_US.utf8 && \
|
|
||||||
sudo locale-gen fr_FR.utf8 && \
|
|
||||||
sudo dpkg-reconfigure --frontend=noninteractive locales
|
|
||||||
|
|
||||||
- name: Install Gettext
|
|
||||||
run: sudo apt-get install gettext
|
|
||||||
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v3
|
|
||||||
|
|
||||||
- name: Setup PHP
|
|
||||||
uses: shivammathur/setup-php@v2
|
|
||||||
with:
|
|
||||||
php-version: ${{ matrix.php-versions }}
|
|
||||||
extensions: gd, xml, curl, mbstring, intl, gettext
|
|
||||||
tools: composer:v2
|
|
||||||
|
|
||||||
- name: Check PHP version
|
|
||||||
run: php -v
|
|
||||||
|
|
||||||
- name: Setup Composer from PHP version + update
|
|
||||||
run: composer config --unset platform && composer config platform.php ${{ matrix.php-versions }}
|
|
||||||
|
|
||||||
- name: Update dependencies for PHP 8.x
|
|
||||||
if: ${{ matrix.php-versions == '8.0' || matrix.php-versions == '8.1' }}
|
|
||||||
run: |
|
|
||||||
composer update && \
|
|
||||||
composer remove --dev phpunit/phpunit && \
|
|
||||||
composer require --dev phpunit/php-text-template ^2.0 && \
|
|
||||||
composer require --dev phpunit/phpunit ^9.0
|
|
||||||
|
|
||||||
- name: Update dependencies for PHP 7.x
|
|
||||||
if: ${{ matrix.php-versions != '8.0' && matrix.php-versions != '8.1' }}
|
|
||||||
run: composer update
|
|
||||||
|
|
||||||
- name: Clean up
|
|
||||||
run: make clean
|
|
||||||
|
|
||||||
- name: Check permissions
|
|
||||||
run: make check_permissions
|
|
||||||
|
|
||||||
- name: Run PHPCS
|
|
||||||
run: make code_sniffer
|
|
||||||
|
|
||||||
- name: Run tests
|
|
||||||
run: make all_tests
|
|
||||||
|
|
||||||
node:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v3
|
|
||||||
|
|
||||||
- name: Setup Node.js
|
|
||||||
uses: actions/setup-node@v3
|
|
||||||
with:
|
|
||||||
node-version: '14.x'
|
|
||||||
|
|
||||||
- name: Yarn install
|
|
||||||
run: yarnpkg install
|
|
||||||
|
|
||||||
- name: Verify successful frontend builds
|
|
||||||
run: yarnpkg run build
|
|
||||||
|
|
||||||
- name: JS static analysis
|
|
||||||
run: make eslint
|
|
||||||
|
|
||||||
- name: Linter for SASS syntax
|
|
||||||
run: make sasslint
|
|
||||||
|
|
||||||
python:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v3
|
|
||||||
|
|
||||||
- name: Setup Python
|
|
||||||
uses: actions/setup-python@v4
|
|
||||||
with:
|
|
||||||
python-version: 3.8
|
|
||||||
|
|
||||||
- name: Build documentation
|
|
||||||
run: make htmldoc
|
|
||||||
|
|
||||||
trivy-repo:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v3
|
|
||||||
|
|
||||||
- name: Run trivy scanner on repository (non-blocking)
|
|
||||||
run: make test_trivy_repo TRIVY_EXIT_CODE=0
|
|
45
.github/workflows/docker-latest.yml
vendored
45
.github/workflows/docker-latest.yml
vendored
|
@ -1,45 +0,0 @@
|
||||||
name: Build/push Docker image (master/latest)
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches: [ master ]
|
|
||||||
jobs:
|
|
||||||
docker-build:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Set up QEMU
|
|
||||||
uses: docker/setup-qemu-action@v2
|
|
||||||
- name: Set up Docker Buildx
|
|
||||||
uses: docker/setup-buildx-action@v2
|
|
||||||
|
|
||||||
- name: Login to DockerHub
|
|
||||||
uses: docker/login-action@v2
|
|
||||||
with:
|
|
||||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
|
||||||
- name: Login to GitHub Container Registry
|
|
||||||
uses: docker/login-action@v2
|
|
||||||
with:
|
|
||||||
registry: ghcr.io
|
|
||||||
username: ${{ github.repository_owner }}
|
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v3
|
|
||||||
|
|
||||||
- name: Set shaarli version to the latest commit hash
|
|
||||||
run: sed -i "s/dev/$(git rev-parse --short HEAD)/" shaarli_version.php
|
|
||||||
|
|
||||||
- name: Build and push
|
|
||||||
id: docker_build
|
|
||||||
uses: docker/build-push-action@v4
|
|
||||||
with:
|
|
||||||
context: .
|
|
||||||
push: true
|
|
||||||
platforms: linux/amd64,linux/arm64,linux/arm/v7
|
|
||||||
tags: |
|
|
||||||
${{ secrets.DOCKER_IMAGE }}:latest
|
|
||||||
ghcr.io/${{ secrets.DOCKER_IMAGE }}:latest
|
|
||||||
- name: Image digest
|
|
||||||
run: echo ${{ steps.docker_build.outputs.digest }}
|
|
||||||
- name: Run trivy scanner on latest docker image
|
|
||||||
run: make test_trivy_docker TRIVY_TARGET_DOCKER_IMAGE=ghcr.io/${{ secrets.DOCKER_IMAGE }}:latest
|
|
21
.github/workflows/docker-pr.yml
vendored
21
.github/workflows/docker-pr.yml
vendored
|
@ -1,21 +0,0 @@
|
||||||
name: Build Docker image (Pull Request)
|
|
||||||
on:
|
|
||||||
pull_request:
|
|
||||||
branches: [ master ]
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
docker-build:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Set up QEMU
|
|
||||||
uses: docker/setup-qemu-action@v1
|
|
||||||
- name: Set up Docker Buildx
|
|
||||||
uses: docker/setup-buildx-action@v1
|
|
||||||
- name: Build Docker image
|
|
||||||
id: docker_build
|
|
||||||
uses: docker/build-push-action@v2
|
|
||||||
with:
|
|
||||||
push: false
|
|
||||||
tags: shaarli/shaarli:pr-${{ github.event.number }}
|
|
||||||
- name: Image digest
|
|
||||||
run: echo ${{ steps.docker_build.outputs.digest }}
|
|
43
.github/workflows/docker-tags.yml
vendored
43
.github/workflows/docker-tags.yml
vendored
|
@ -1,43 +0,0 @@
|
||||||
name: Build/push Docker image (tags/releases)
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
tags:
|
|
||||||
- "v*.*.*"
|
|
||||||
branches:
|
|
||||||
- "v*.*"
|
|
||||||
- release
|
|
||||||
jobs:
|
|
||||||
docker-build:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Get the tag name
|
|
||||||
run: echo "REF=${GITHUB_REF##*/}" >> $GITHUB_ENV
|
|
||||||
- name: Set up QEMU
|
|
||||||
uses: docker/setup-qemu-action@v2
|
|
||||||
- name: Set up Docker Buildx
|
|
||||||
uses: docker/setup-buildx-action@v2
|
|
||||||
|
|
||||||
- name: Login to DockerHub
|
|
||||||
uses: docker/login-action@v2
|
|
||||||
with:
|
|
||||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
|
||||||
-
|
|
||||||
name: Login to GitHub Container Registry
|
|
||||||
uses: docker/login-action@v2
|
|
||||||
with:
|
|
||||||
registry: ghcr.io
|
|
||||||
username: ${{ github.repository_owner }}
|
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
|
|
||||||
- name: Build and push
|
|
||||||
id: docker_build
|
|
||||||
uses: docker/build-push-action@v3
|
|
||||||
with:
|
|
||||||
push: true
|
|
||||||
platforms: linux/amd64,linux/arm/v7
|
|
||||||
tags: |
|
|
||||||
${{ secrets.DOCKER_IMAGE }}:${{ env.REF }}
|
|
||||||
ghcr.io/${{ secrets.DOCKER_IMAGE }}:${{ env.REF }}
|
|
||||||
- name: Image digest
|
|
||||||
run: echo ${{ steps.docker_build.outputs.digest }}
|
|
74
Dockerfile
74
Dockerfile
|
@ -1,74 +0,0 @@
|
||||||
# Stage 1:
|
|
||||||
# - Copy Shaarli sources
|
|
||||||
# - Build documentation
|
|
||||||
FROM python:3-alpine as docs
|
|
||||||
ADD . /usr/src/app/shaarli
|
|
||||||
RUN cd /usr/src/app/shaarli \
|
|
||||||
&& apk add --no-cache gcc musl-dev make bash \
|
|
||||||
&& make htmldoc
|
|
||||||
|
|
||||||
# Stage 2:
|
|
||||||
# - Resolve PHP dependencies with Composer
|
|
||||||
FROM composer:latest as composer
|
|
||||||
COPY --from=docs /usr/src/app/shaarli /app/shaarli
|
|
||||||
RUN cd shaarli \
|
|
||||||
&& composer --prefer-dist --no-dev install
|
|
||||||
|
|
||||||
# Stage 3:
|
|
||||||
# - Frontend dependencies
|
|
||||||
FROM node:12-alpine as node
|
|
||||||
COPY --from=composer /app/shaarli shaarli
|
|
||||||
RUN cd shaarli \
|
|
||||||
&& yarnpkg install \
|
|
||||||
&& yarnpkg run build \
|
|
||||||
&& rm -rf node_modules
|
|
||||||
|
|
||||||
# Stage 4:
|
|
||||||
# - Shaarli image
|
|
||||||
FROM alpine:3.16.7
|
|
||||||
LABEL maintainer="Shaarli Community"
|
|
||||||
|
|
||||||
RUN apk --update --no-cache add \
|
|
||||||
ca-certificates \
|
|
||||||
nginx \
|
|
||||||
php8 \
|
|
||||||
php8-ctype \
|
|
||||||
php8-curl \
|
|
||||||
php8-fpm \
|
|
||||||
php8-gd \
|
|
||||||
php8-gettext \
|
|
||||||
php8-iconv \
|
|
||||||
php8-intl \
|
|
||||||
php8-json \
|
|
||||||
php8-ldap \
|
|
||||||
php8-mbstring \
|
|
||||||
php8-openssl \
|
|
||||||
php8-session \
|
|
||||||
php8-xml \
|
|
||||||
php8-simplexml \
|
|
||||||
php8-zlib \
|
|
||||||
s6
|
|
||||||
|
|
||||||
COPY .docker/nginx.conf /etc/nginx/nginx.conf
|
|
||||||
COPY .docker/php-fpm.conf /etc/php8/php-fpm.conf
|
|
||||||
COPY .docker/services.d /etc/services.d
|
|
||||||
|
|
||||||
RUN rm -rf /etc/php8/php-fpm.d/www.conf \
|
|
||||||
&& sed -i 's/post_max_size.*/post_max_size = 10M/' /etc/php8/php.ini \
|
|
||||||
&& sed -i 's/upload_max_filesize.*/upload_max_filesize = 10M/' /etc/php8/php.ini
|
|
||||||
|
|
||||||
|
|
||||||
WORKDIR /var/www
|
|
||||||
COPY --from=node /shaarli shaarli
|
|
||||||
|
|
||||||
RUN chown -R nginx:nginx . \
|
|
||||||
&& ln -sf /dev/stdout /var/log/nginx/shaarli.access.log \
|
|
||||||
&& ln -sf /dev/stderr /var/log/nginx/shaarli.error.log
|
|
||||||
|
|
||||||
VOLUME /var/www/shaarli/cache
|
|
||||||
VOLUME /var/www/shaarli/data
|
|
||||||
|
|
||||||
EXPOSE 80
|
|
||||||
|
|
||||||
ENTRYPOINT ["/bin/s6-svscan", "/etc/services.d"]
|
|
||||||
CMD []
|
|
215
Makefile
215
Makefile
|
@ -1,215 +0,0 @@
|
||||||
# The personal, minimalist, super fast, database-free, bookmarking service.
|
|
||||||
# Makefile for PHP code analysis & testing, documentation and release generation
|
|
||||||
|
|
||||||
BIN = vendor/bin
|
|
||||||
|
|
||||||
all: check_permissions test
|
|
||||||
|
|
||||||
##
|
|
||||||
# Docker test adapter
|
|
||||||
#
|
|
||||||
# Shaarli sources and vendored libraries are copied from a shared volume
|
|
||||||
# to a user-owned directory to enable running tests as a non-root user.
|
|
||||||
##
|
|
||||||
docker_%:
|
|
||||||
rsync -az /shaarli/ ~/shaarli/
|
|
||||||
cd ~/shaarli && make $*
|
|
||||||
|
|
||||||
##
|
|
||||||
# PHP_CodeSniffer
|
|
||||||
# Detects PHP syntax errors
|
|
||||||
# Documentation (usage, output formatting):
|
|
||||||
# - http://pear.php.net/manual/en/package.php.php-codesniffer.usage.php
|
|
||||||
# - http://pear.php.net/manual/en/package.php.php-codesniffer.reporting.php
|
|
||||||
##
|
|
||||||
PHPCS := $(BIN)/phpcs
|
|
||||||
|
|
||||||
# Use GNU Tar where available
|
|
||||||
ifneq (, $(shell which gtar))
|
|
||||||
TAR := gtar
|
|
||||||
else
|
|
||||||
TAR := tar
|
|
||||||
endif
|
|
||||||
|
|
||||||
code_sniffer:
|
|
||||||
@$(PHPCS)
|
|
||||||
|
|
||||||
### - errors by Git author
|
|
||||||
code_sniffer_blame:
|
|
||||||
@$(PHPCS) --report-gitblame
|
|
||||||
|
|
||||||
### - all errors/warnings
|
|
||||||
code_sniffer_full:
|
|
||||||
@$(PHPCS) --report-full --report-width=200
|
|
||||||
|
|
||||||
### - errors grouped by kind
|
|
||||||
code_sniffer_source:
|
|
||||||
@$(PHPCS) --report-source || exit 0
|
|
||||||
|
|
||||||
##
|
|
||||||
# Checks source file & script permissions
|
|
||||||
##
|
|
||||||
check_permissions:
|
|
||||||
@echo "----------------------"
|
|
||||||
@echo "Check file permissions"
|
|
||||||
@echo "----------------------"
|
|
||||||
@for file in `git ls-files | grep -v docker`; do \
|
|
||||||
if [ -x $$file ]; then \
|
|
||||||
errors=true; \
|
|
||||||
echo "$${file} is executable"; \
|
|
||||||
fi \
|
|
||||||
done; [ -z $$errors ] || false
|
|
||||||
|
|
||||||
##
|
|
||||||
# PHPUnit
|
|
||||||
# Runs unitary and functional tests
|
|
||||||
# Generates an HTML coverage report if Xdebug is enabled
|
|
||||||
#
|
|
||||||
# See phpunit.xml for configuration
|
|
||||||
# https://phpunit.de/manual/current/en/appendixes.configuration.html
|
|
||||||
##
|
|
||||||
test: translate
|
|
||||||
@echo "-------"
|
|
||||||
@echo "PHPUNIT"
|
|
||||||
@echo "-------"
|
|
||||||
@mkdir -p sandbox coverage
|
|
||||||
@$(BIN)/phpunit --coverage-php coverage/main.cov --bootstrap tests/bootstrap.php --testsuite unit-tests
|
|
||||||
|
|
||||||
locale_test_%:
|
|
||||||
@UT_LOCALE=$*.utf8 \
|
|
||||||
$(BIN)/phpunit \
|
|
||||||
--coverage-php coverage/$(firstword $(subst _, ,$*)).cov \
|
|
||||||
--bootstrap tests/languages/bootstrap.php \
|
|
||||||
--testsuite language-$(firstword $(subst _, ,$*))
|
|
||||||
|
|
||||||
all_tests: test locale_test_de_DE locale_test_en_US locale_test_fr_FR
|
|
||||||
@# --The current version is not compatible with PHP 7.2
|
|
||||||
@#$(BIN)/phpcov merge --html coverage coverage
|
|
||||||
@# --text doesn't work with phpunit 4.* (v5 requires PHP 5.6)
|
|
||||||
@#$(BIN)/phpcov merge --text coverage/txt coverage
|
|
||||||
|
|
||||||
### download 3rd-party PHP libraries, including dev dependencies
|
|
||||||
composer_dependencies_dev: clean
|
|
||||||
composer install --prefer-dist
|
|
||||||
|
|
||||||
##
|
|
||||||
# Custom release archive generation
|
|
||||||
#
|
|
||||||
# For each tagged revision, GitHub provides tar and zip archives that correspond
|
|
||||||
# to the output of git-archive
|
|
||||||
#
|
|
||||||
# These targets produce similar archives, featuring 3rd-party dependencies
|
|
||||||
# to ease deployment on shared hosting.
|
|
||||||
##
|
|
||||||
ARCHIVE_VERSION := shaarli-$$(git describe)-full
|
|
||||||
ARCHIVE_PREFIX=Shaarli/
|
|
||||||
|
|
||||||
release_archive: release_tar release_zip
|
|
||||||
|
|
||||||
### download 3rd-party PHP libraries
|
|
||||||
composer_dependencies: clean
|
|
||||||
composer install --no-dev --prefer-dist
|
|
||||||
find vendor/ -name ".git" -type d -exec rm -rf {} +
|
|
||||||
|
|
||||||
### download 3rd-party frontend libraries
|
|
||||||
frontend_dependencies:
|
|
||||||
yarnpkg install
|
|
||||||
|
|
||||||
### Build frontend dependencies
|
|
||||||
build_frontend: frontend_dependencies
|
|
||||||
yarnpkg run build
|
|
||||||
|
|
||||||
### generate a release tarball and include 3rd-party dependencies and translations
|
|
||||||
release_tar: composer_dependencies htmldoc translate build_frontend
|
|
||||||
git archive --prefix=$(ARCHIVE_PREFIX) -o $(ARCHIVE_VERSION).tar HEAD
|
|
||||||
$(TAR) rvf $(ARCHIVE_VERSION).tar --transform "s|^vendor|$(ARCHIVE_PREFIX)vendor|" vendor/
|
|
||||||
$(TAR) rvf $(ARCHIVE_VERSION).tar --transform "s|^doc/html|$(ARCHIVE_PREFIX)doc/html|" doc/html/
|
|
||||||
$(TAR) rvf $(ARCHIVE_VERSION).tar --transform "s|^tpl|$(ARCHIVE_PREFIX)tpl|" tpl/
|
|
||||||
gzip $(ARCHIVE_VERSION).tar
|
|
||||||
|
|
||||||
### generate a release zip and include 3rd-party dependencies and translations
|
|
||||||
release_zip: composer_dependencies htmldoc translate build_frontend
|
|
||||||
git archive --prefix=$(ARCHIVE_PREFIX) -o $(ARCHIVE_VERSION).zip -9 HEAD
|
|
||||||
mkdir -p $(ARCHIVE_PREFIX)/doc
|
|
||||||
mkdir -p $(ARCHIVE_PREFIX)/vendor
|
|
||||||
rsync -a doc/html/ $(ARCHIVE_PREFIX)doc/html/
|
|
||||||
zip -r $(ARCHIVE_VERSION).zip $(ARCHIVE_PREFIX)doc/
|
|
||||||
rsync -a vendor/ $(ARCHIVE_PREFIX)vendor/
|
|
||||||
zip -r $(ARCHIVE_VERSION).zip $(ARCHIVE_PREFIX)vendor/
|
|
||||||
rsync -a tpl/ $(ARCHIVE_PREFIX)tpl/
|
|
||||||
zip -r $(ARCHIVE_VERSION).zip $(ARCHIVE_PREFIX)tpl/
|
|
||||||
rm -rf $(ARCHIVE_PREFIX)
|
|
||||||
|
|
||||||
##
|
|
||||||
# Targets for repository and documentation maintenance
|
|
||||||
##
|
|
||||||
|
|
||||||
### remove all unversioned files
|
|
||||||
clean:
|
|
||||||
@git clean -df
|
|
||||||
@rm -rf sandbox trivy*
|
|
||||||
|
|
||||||
### generate the AUTHORS file from Git commit information
|
|
||||||
generate_authors:
|
|
||||||
@cp .github/mailmap .mailmap
|
|
||||||
@git shortlog -sne > AUTHORS
|
|
||||||
@rm .mailmap
|
|
||||||
|
|
||||||
### generate phpDocumentor documentation
|
|
||||||
phpdoc: clean
|
|
||||||
@docker run --rm -v $(PWD):/data -u `id -u`:`id -g` phpdoc/phpdoc
|
|
||||||
|
|
||||||
### generate HTML documentation from Markdown pages with Sphinx
|
|
||||||
htmldoc:
|
|
||||||
python3 -m venv venv/
|
|
||||||
bash -c 'source venv/bin/activate; \
|
|
||||||
pip install wheel; \
|
|
||||||
pip install sphinx==7.1.0 furo==2023.7.26 myst-parser sphinx-design; \
|
|
||||||
sphinx-build -b html -c doc/ doc/md/ doc/html/'
|
|
||||||
find doc/html/ -type f -exec chmod a-x '{}' \;
|
|
||||||
rm -r venv
|
|
||||||
|
|
||||||
### Generate Shaarli's translation compiled file (.mo)
|
|
||||||
translate:
|
|
||||||
@echo "----------------------"
|
|
||||||
@echo "Compile translation files"
|
|
||||||
@echo "----------------------"
|
|
||||||
@for pofile in `find inc/languages/ -name shaarli.po`; do \
|
|
||||||
echo "Compiling $$pofile"; \
|
|
||||||
msgfmt -v "$$pofile" -o "`dirname "$$pofile"`/`basename "$$pofile" .po`.mo"; \
|
|
||||||
done;
|
|
||||||
|
|
||||||
### Run ESLint check against Shaarli's JS files
|
|
||||||
eslint:
|
|
||||||
@yarnpkg run eslint -c .dev/.eslintrc.js assets/vintage/js/
|
|
||||||
@yarnpkg run eslint -c .dev/.eslintrc.js assets/default/js/
|
|
||||||
@yarnpkg run eslint -c .dev/.eslintrc.js assets/common/js/
|
|
||||||
|
|
||||||
### Run CSSLint check against Shaarli's SCSS files
|
|
||||||
sasslint:
|
|
||||||
@yarnpkg run stylelint --config .dev/.stylelintrc.js 'assets/default/scss/*.scss'
|
|
||||||
|
|
||||||
##
|
|
||||||
# Security scans
|
|
||||||
##
|
|
||||||
|
|
||||||
# trivy version (https://github.com/aquasecurity/trivy/releases)
|
|
||||||
TRIVY_VERSION=0.44.0
|
|
||||||
# default trivy exit code when vulnerabilities are found
|
|
||||||
TRIVY_EXIT_CODE=1
|
|
||||||
# default docker image to scan with trivy
|
|
||||||
TRIVY_TARGET_DOCKER_IMAGE=ghcr.io/shaarli/shaarli:latest
|
|
||||||
|
|
||||||
### download trivy vulneravbility scanner
|
|
||||||
download_trivy:
|
|
||||||
wget --quiet --continue -O trivy_$(TRIVY_VERSION)_Linux-64bit.tar.gz https://github.com/aquasecurity/trivy/releases/download/v$(TRIVY_VERSION)/trivy_$(TRIVY_VERSION)_Linux-64bit.tar.gz
|
|
||||||
tar -z -x trivy -f trivy_$(TRIVY_VERSION)_Linux-64bit.tar.gz
|
|
||||||
|
|
||||||
### run trivy vulnerability scanner on docker image
|
|
||||||
test_trivy_docker: download_trivy
|
|
||||||
./trivy --exit-code $(TRIVY_EXIT_CODE) image $(TRIVY_TARGET_DOCKER_IMAGE)
|
|
||||||
|
|
||||||
### run trivy vulnerability scanner on composer/yarn dependency trees
|
|
||||||
test_trivy_repo: download_trivy
|
|
||||||
./trivy --exit-code $(TRIVY_EXIT_CODE) fs composer.lock
|
|
||||||
./trivy --exit-code $(TRIVY_EXIT_CODE) fs yarn.lock
|
|
|
@ -1,62 +0,0 @@
|
||||||
---
|
|
||||||
# Shaarli - Docker Compose example configuration
|
|
||||||
#
|
|
||||||
# See:
|
|
||||||
# - https://shaarli.readthedocs.io/en/master/Docker/#docker-compose
|
|
||||||
#
|
|
||||||
# Environment variables:
|
|
||||||
# - SHAARLI_VIRTUAL_HOST Fully Qualified Domain Name for the Shaarli instance
|
|
||||||
# - SHAARLI_LETSENCRYPT_EMAIL Contact email for certificate renewal
|
|
||||||
# - SHAARLI_DOCKER_TAG Shaarli docker tag to use
|
|
||||||
# See: https://github.com/shaarli/Shaarli/pkgs/container/shaarli/versions?filters%5Bversion_type%5D=tagged
|
|
||||||
version: '3'
|
|
||||||
|
|
||||||
networks:
|
|
||||||
http-proxy:
|
|
||||||
|
|
||||||
volumes:
|
|
||||||
traefik-acme:
|
|
||||||
shaarli-cache:
|
|
||||||
shaarli-data:
|
|
||||||
|
|
||||||
services:
|
|
||||||
shaarli:
|
|
||||||
image: ghcr.io/shaarli/shaarli:${SHAARLI_DOCKER_TAG}
|
|
||||||
build: ./
|
|
||||||
networks:
|
|
||||||
- http-proxy
|
|
||||||
volumes:
|
|
||||||
- shaarli-cache:/var/www/shaarli/cache
|
|
||||||
- shaarli-data:/var/www/shaarli/data
|
|
||||||
labels:
|
|
||||||
traefik.domain: "${SHAARLI_VIRTUAL_HOST}"
|
|
||||||
traefik.backend: shaarli
|
|
||||||
traefik.frontend.rule: "Host:${SHAARLI_VIRTUAL_HOST}"
|
|
||||||
|
|
||||||
traefik:
|
|
||||||
image: traefik:1.7-alpine
|
|
||||||
command:
|
|
||||||
- "--defaultentrypoints=http,https"
|
|
||||||
- "--entrypoints=Name:http Address::80 Redirect.EntryPoint:https"
|
|
||||||
- "--entrypoints=Name:https Address::443 TLS"
|
|
||||||
- "--retry"
|
|
||||||
- "--docker"
|
|
||||||
- "--docker.domain=${SHAARLI_VIRTUAL_HOST}"
|
|
||||||
- "--docker.exposedbydefault=true"
|
|
||||||
- "--docker.watch=true"
|
|
||||||
- "--acme"
|
|
||||||
- "--acme.domains=${SHAARLI_VIRTUAL_HOST}"
|
|
||||||
- "--acme.email=${SHAARLI_LETSENCRYPT_EMAIL}"
|
|
||||||
- "--acme.entrypoint=https"
|
|
||||||
- "--acme.onhostrule=true"
|
|
||||||
- "--acme.storage=/acme/acme.json"
|
|
||||||
- "--acme.httpchallenge"
|
|
||||||
- "--acme.httpchallenge.entrypoint=http"
|
|
||||||
networks:
|
|
||||||
- http-proxy
|
|
||||||
ports:
|
|
||||||
- 80:80
|
|
||||||
- 443:443
|
|
||||||
volumes:
|
|
||||||
- /var/run/docker.sock:/var/run/docker.sock:ro
|
|
||||||
- traefik-acme:/acme
|
|
7486
package-lock.json
generated
7486
package-lock.json
generated
File diff suppressed because it is too large
Load diff
27
phpunit.xml
27
phpunit.xml
|
@ -1,27 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<phpunit
|
|
||||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
||||||
xsi:noNamespaceSchemaLocation="http://schema.phpunit.de/4.5/phpunit.xsd"
|
|
||||||
colors="true">
|
|
||||||
<testsuites>
|
|
||||||
<testsuite name="unit-tests">
|
|
||||||
<directory>tests</directory>
|
|
||||||
<exclude>tests/languages</exclude>
|
|
||||||
</testsuite>
|
|
||||||
<testsuite name="language-de">
|
|
||||||
<directory>tests/languages/de</directory>
|
|
||||||
</testsuite>
|
|
||||||
<testsuite name="language-en">
|
|
||||||
<directory>tests/languages/en</directory>
|
|
||||||
</testsuite>
|
|
||||||
<testsuite name="language-fr">
|
|
||||||
<directory>tests/languages/fr</directory>
|
|
||||||
</testsuite>
|
|
||||||
</testsuites>
|
|
||||||
|
|
||||||
<filter>
|
|
||||||
<whitelist addUncoveredFilesFromWhitelist="true">
|
|
||||||
<directory suffix=".php">application</directory>
|
|
||||||
</whitelist>
|
|
||||||
</filter>
|
|
||||||
</phpunit>
|
|
|
@ -1,13 +0,0 @@
|
||||||
<IfModule version_module>
|
|
||||||
<IfVersion >= 2.4>
|
|
||||||
Require all denied
|
|
||||||
</IfVersion>
|
|
||||||
<IfVersion < 2.4>
|
|
||||||
Allow from none
|
|
||||||
Deny from all
|
|
||||||
</IfVersion>
|
|
||||||
</IfModule>
|
|
||||||
|
|
||||||
<IfModule !version_module>
|
|
||||||
Require all denied
|
|
||||||
</IfModule>
|
|
|
@ -1,206 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace Shaarli;
|
|
||||||
|
|
||||||
use DateTime;
|
|
||||||
use Shaarli\Bookmark\Bookmark;
|
|
||||||
|
|
||||||
class HistoryTest extends \Shaarli\TestCase
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @var string History file path
|
|
||||||
*/
|
|
||||||
protected static $historyFilePath = 'sandbox/history.php';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Delete history file.
|
|
||||||
*/
|
|
||||||
protected function setUp(): void
|
|
||||||
{
|
|
||||||
if (file_exists(self::$historyFilePath)) {
|
|
||||||
unlink(self::$historyFilePath);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test that the history file is created if it doesn't exist.
|
|
||||||
*/
|
|
||||||
public function testConstructLazyLoading()
|
|
||||||
{
|
|
||||||
new History(self::$historyFilePath);
|
|
||||||
$this->assertFileNotExists(self::$historyFilePath);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test that the history file is created if it doesn't exist.
|
|
||||||
*/
|
|
||||||
public function testAddEventCreateFile()
|
|
||||||
{
|
|
||||||
$history = new History(self::$historyFilePath);
|
|
||||||
$history->updateSettings();
|
|
||||||
$this->assertFileExists(self::$historyFilePath);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Not writable history file: raise an exception.
|
|
||||||
*/
|
|
||||||
public function testConstructNotWritable()
|
|
||||||
{
|
|
||||||
$this->expectException(\Exception::class);
|
|
||||||
$this->expectExceptionMessage('History file isn\'t readable or writable');
|
|
||||||
|
|
||||||
touch(self::$historyFilePath);
|
|
||||||
chmod(self::$historyFilePath, 0440);
|
|
||||||
$history = new History(self::$historyFilePath);
|
|
||||||
$history->updateSettings();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Not parsable history file: raise an exception.
|
|
||||||
*/
|
|
||||||
public function testConstructNotParsable()
|
|
||||||
{
|
|
||||||
$this->expectException(\Exception::class);
|
|
||||||
$this->expectExceptionMessageRegExp('/Could not parse history file/');
|
|
||||||
|
|
||||||
file_put_contents(self::$historyFilePath, 'not parsable');
|
|
||||||
$history = new History(self::$historyFilePath);
|
|
||||||
// gzinflate generates a warning
|
|
||||||
@$history->updateSettings();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test add link event
|
|
||||||
*/
|
|
||||||
public function testAddLink()
|
|
||||||
{
|
|
||||||
$history = new History(self::$historyFilePath);
|
|
||||||
$bookmark = (new Bookmark())->setId(0);
|
|
||||||
$history->addLink($bookmark);
|
|
||||||
$actual = $history->getHistory()[0];
|
|
||||||
$this->assertEquals(History::CREATED, $actual['event']);
|
|
||||||
$this->assertTrue(new DateTime('-2 seconds') < $actual['datetime']);
|
|
||||||
$this->assertEquals(0, $actual['id']);
|
|
||||||
|
|
||||||
$history = new History(self::$historyFilePath);
|
|
||||||
$bookmark = (new Bookmark())->setId(1);
|
|
||||||
$history->addLink($bookmark);
|
|
||||||
$actual = $history->getHistory()[0];
|
|
||||||
$this->assertEquals(History::CREATED, $actual['event']);
|
|
||||||
$this->assertTrue(new DateTime('-2 seconds') < $actual['datetime']);
|
|
||||||
$this->assertEquals(1, $actual['id']);
|
|
||||||
}
|
|
||||||
|
|
||||||
// /**
|
|
||||||
// * Test updated link event
|
|
||||||
// */
|
|
||||||
// public function testUpdateLink()
|
|
||||||
// {
|
|
||||||
// $history = new History(self::$historyFilePath);
|
|
||||||
// $history->updateLink(['id' => 1]);
|
|
||||||
// $actual = $history->getHistory()[0];
|
|
||||||
// $this->assertEquals(History::UPDATED, $actual['event']);
|
|
||||||
// $this->assertTrue(new DateTime('-2 seconds') < $actual['datetime']);
|
|
||||||
// $this->assertEquals(1, $actual['id']);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// /**
|
|
||||||
// * Test delete link event
|
|
||||||
// */
|
|
||||||
// public function testDeleteLink()
|
|
||||||
// {
|
|
||||||
// $history = new History(self::$historyFilePath);
|
|
||||||
// $history->deleteLink(['id' => 1]);
|
|
||||||
// $actual = $history->getHistory()[0];
|
|
||||||
// $this->assertEquals(History::DELETED, $actual['event']);
|
|
||||||
// $this->assertTrue(new DateTime('-2 seconds') < $actual['datetime']);
|
|
||||||
// $this->assertEquals(1, $actual['id']);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// /**
|
|
||||||
// * Test updated settings event
|
|
||||||
// */
|
|
||||||
// public function testUpdateSettings()
|
|
||||||
// {
|
|
||||||
// $history = new History(self::$historyFilePath);
|
|
||||||
// $history->updateSettings();
|
|
||||||
// $actual = $history->getHistory()[0];
|
|
||||||
// $this->assertEquals(History::SETTINGS, $actual['event']);
|
|
||||||
// $this->assertTrue(new DateTime('-2 seconds') < $actual['datetime']);
|
|
||||||
// $this->assertEmpty($actual['id']);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// /**
|
|
||||||
// * Make sure that new items are stored at the beginning
|
|
||||||
// */
|
|
||||||
// public function testHistoryOrder()
|
|
||||||
// {
|
|
||||||
// $history = new History(self::$historyFilePath);
|
|
||||||
// $history->updateLink(['id' => 1]);
|
|
||||||
// $actual = $history->getHistory()[0];
|
|
||||||
// $this->assertEquals(History::UPDATED, $actual['event']);
|
|
||||||
// $this->assertTrue(new DateTime('-2 seconds') < $actual['datetime']);
|
|
||||||
// $this->assertEquals(1, $actual['id']);
|
|
||||||
//
|
|
||||||
// $history->addLink(['id' => 1]);
|
|
||||||
// $actual = $history->getHistory()[0];
|
|
||||||
// $this->assertEquals(History::CREATED, $actual['event']);
|
|
||||||
// $this->assertTrue(new DateTime('-2 seconds') < $actual['datetime']);
|
|
||||||
// $this->assertEquals(1, $actual['id']);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// /**
|
|
||||||
// * Re-read history from file after writing an event
|
|
||||||
// */
|
|
||||||
// public function testHistoryRead()
|
|
||||||
// {
|
|
||||||
// $history = new History(self::$historyFilePath);
|
|
||||||
// $history->updateLink(['id' => 1]);
|
|
||||||
// $history = new History(self::$historyFilePath);
|
|
||||||
// $actual = $history->getHistory()[0];
|
|
||||||
// $this->assertEquals(History::UPDATED, $actual['event']);
|
|
||||||
// $this->assertTrue(new DateTime('-2 seconds') < $actual['datetime']);
|
|
||||||
// $this->assertEquals(1, $actual['id']);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// /**
|
|
||||||
// * Re-read history from file after writing an event and make sure that the order is correct
|
|
||||||
// */
|
|
||||||
// public function testHistoryOrderRead()
|
|
||||||
// {
|
|
||||||
// $history = new History(self::$historyFilePath);
|
|
||||||
// $history->updateLink(['id' => 1]);
|
|
||||||
// $history->addLink(['id' => 1]);
|
|
||||||
//
|
|
||||||
// $history = new History(self::$historyFilePath);
|
|
||||||
// $actual = $history->getHistory()[0];
|
|
||||||
// $this->assertEquals(History::CREATED, $actual['event']);
|
|
||||||
// $this->assertTrue(new DateTime('-2 seconds') < $actual['datetime']);
|
|
||||||
// $this->assertEquals(1, $actual['id']);
|
|
||||||
//
|
|
||||||
// $actual = $history->getHistory()[1];
|
|
||||||
// $this->assertEquals(History::UPDATED, $actual['event']);
|
|
||||||
// $this->assertTrue(new DateTime('-2 seconds') < $actual['datetime']);
|
|
||||||
// $this->assertEquals(1, $actual['id']);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// /**
|
|
||||||
// * Test retention time: delete old entries.
|
|
||||||
// */
|
|
||||||
// public function testHistoryRententionTime()
|
|
||||||
// {
|
|
||||||
// $history = new History(self::$historyFilePath, 5);
|
|
||||||
// $history->updateLink(['id' => 1]);
|
|
||||||
// $this->assertEquals(1, count($history->getHistory()));
|
|
||||||
// $arr = $history->getHistory();
|
|
||||||
// $arr[0]['datetime'] = new DateTime('-1 hour');
|
|
||||||
// FileUtils::writeFlatDB(self::$historyFilePath, $arr);
|
|
||||||
//
|
|
||||||
// $history = new History(self::$historyFilePath, 60);
|
|
||||||
// $this->assertEquals(1, count($history->getHistory()));
|
|
||||||
// $this->assertEquals(1, $history->getHistory()[0]['id']);
|
|
||||||
// $history->updateLink(['id' => 2]);
|
|
||||||
// $this->assertEquals(1, count($history->getHistory()));
|
|
||||||
// $this->assertEquals(2, $history->getHistory()[0]['id']);
|
|
||||||
// }
|
|
||||||
}
|
|
|
@ -1,229 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace Shaarli;
|
|
||||||
|
|
||||||
use Shaarli\Config\ConfigManager;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Class LanguagesTest.
|
|
||||||
*/
|
|
||||||
class LanguagesTest extends \Shaarli\TestCase
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @var string Config file path (without extension).
|
|
||||||
*/
|
|
||||||
protected static $configFile = 'tests/utils/config/configJson';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var ConfigManager
|
|
||||||
*/
|
|
||||||
protected $conf;
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
protected function setUp(): void
|
|
||||||
{
|
|
||||||
$this->conf = new ConfigManager(self::$configFile);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test t() with a simple non identified value.
|
|
||||||
*/
|
|
||||||
public function testTranslateSingleNotIDGettext()
|
|
||||||
{
|
|
||||||
$this->conf->set('translation.mode', 'gettext');
|
|
||||||
new Languages('en', $this->conf);
|
|
||||||
$text = 'abcdé 564 fgK';
|
|
||||||
$this->assertEquals($text, t($text));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test t() with a simple identified value in gettext mode.
|
|
||||||
*/
|
|
||||||
public function testTranslateSingleIDGettext()
|
|
||||||
{
|
|
||||||
$this->conf->set('translation.mode', 'gettext');
|
|
||||||
new Languages('en', $this->conf);
|
|
||||||
$text = 'permalink';
|
|
||||||
$this->assertEquals($text, t($text));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test t() with a non identified plural form in gettext mode.
|
|
||||||
*/
|
|
||||||
public function testTranslatePluralNotIDGettext()
|
|
||||||
{
|
|
||||||
$this->conf->set('translation.mode', 'gettext');
|
|
||||||
new Languages('en', $this->conf);
|
|
||||||
$text = 'sandwich';
|
|
||||||
$nText = 'sandwiches';
|
|
||||||
$this->assertEquals('sandwiches', t($text, $nText, 0));
|
|
||||||
$this->assertEquals('sandwich', t($text, $nText, 1));
|
|
||||||
$this->assertEquals('sandwiches', t($text, $nText, 2));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test t() with an identified plural form in gettext mode.
|
|
||||||
*/
|
|
||||||
public function testTranslatePluralIDGettext()
|
|
||||||
{
|
|
||||||
$this->conf->set('translation.mode', 'gettext');
|
|
||||||
new Languages('en', $this->conf);
|
|
||||||
$text = 'shaare';
|
|
||||||
$nText = 'shaares';
|
|
||||||
// In english, zero is followed by plural form
|
|
||||||
$this->assertEquals('shaares', t($text, $nText, 0));
|
|
||||||
$this->assertEquals('shaare', t($text, $nText, 1));
|
|
||||||
$this->assertEquals('shaares', t($text, $nText, 2));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test t() with a simple non identified value.
|
|
||||||
*/
|
|
||||||
public function testTranslateSingleNotIDPhp()
|
|
||||||
{
|
|
||||||
$this->conf->set('translation.mode', 'php');
|
|
||||||
new Languages('en', $this->conf);
|
|
||||||
$text = 'abcdé 564 fgK';
|
|
||||||
$this->assertEquals($text, t($text));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test t() with a simple identified value in PHP mode.
|
|
||||||
*/
|
|
||||||
public function testTranslateSingleIDPhp()
|
|
||||||
{
|
|
||||||
$this->conf->set('translation.mode', 'php');
|
|
||||||
new Languages('en', $this->conf);
|
|
||||||
$text = 'permalink';
|
|
||||||
$this->assertEquals($text, t($text));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test t() with a non identified plural form in PHP mode.
|
|
||||||
*/
|
|
||||||
public function testTranslatePluralNotIDPhp()
|
|
||||||
{
|
|
||||||
$this->conf->set('translation.mode', 'php');
|
|
||||||
new Languages('en', $this->conf);
|
|
||||||
$text = 'sandwich';
|
|
||||||
$nText = 'sandwiches';
|
|
||||||
$this->assertEquals('sandwiches', t($text, $nText, 0));
|
|
||||||
$this->assertEquals('sandwich', t($text, $nText, 1));
|
|
||||||
$this->assertEquals('sandwiches', t($text, $nText, 2));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test t() with an identified plural form in PHP mode.
|
|
||||||
*/
|
|
||||||
public function testTranslatePluralIDPhp()
|
|
||||||
{
|
|
||||||
$this->conf->set('translation.mode', 'php');
|
|
||||||
new Languages('en', $this->conf);
|
|
||||||
$text = 'shaare';
|
|
||||||
$nText = 'shaares';
|
|
||||||
// In english, zero is followed by plural form
|
|
||||||
$this->assertEquals('shaares', t($text, $nText, 0));
|
|
||||||
$this->assertEquals('shaare', t($text, $nText, 1));
|
|
||||||
$this->assertEquals('shaares', t($text, $nText, 2));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test t() with an invalid language set in the configuration in gettext mode.
|
|
||||||
*/
|
|
||||||
public function testTranslateWithInvalidConfLanguageGettext()
|
|
||||||
{
|
|
||||||
$this->conf->set('translation.mode', 'gettext');
|
|
||||||
$this->conf->set('translation.language', 'nope');
|
|
||||||
new Languages('fr', $this->conf);
|
|
||||||
$text = 'grumble';
|
|
||||||
$this->assertEquals($text, t($text));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test t() with an invalid language set in the configuration in PHP mode.
|
|
||||||
*/
|
|
||||||
public function testTranslateWithInvalidConfLanguagePhp()
|
|
||||||
{
|
|
||||||
$this->conf->set('translation.mode', 'php');
|
|
||||||
$this->conf->set('translation.language', 'nope');
|
|
||||||
new Languages('fr', $this->conf);
|
|
||||||
$text = 'grumble';
|
|
||||||
$this->assertEquals($text, t($text));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test t() with an invalid language set with auto language in gettext mode.
|
|
||||||
*/
|
|
||||||
public function testTranslateWithInvalidAutoLanguageGettext()
|
|
||||||
{
|
|
||||||
$this->conf->set('translation.mode', 'gettext');
|
|
||||||
new Languages('nope', $this->conf);
|
|
||||||
$text = 'grumble';
|
|
||||||
$this->assertEquals($text, t($text));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test t() with an invalid language set with auto language in PHP mode.
|
|
||||||
*/
|
|
||||||
public function testTranslateWithInvalidAutoLanguagePhp()
|
|
||||||
{
|
|
||||||
$this->conf->set('translation.mode', 'php');
|
|
||||||
new Languages('nope', $this->conf);
|
|
||||||
$text = 'grumble';
|
|
||||||
$this->assertEquals($text, t($text));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test t() with an extension language file coming from the theme in gettext mode
|
|
||||||
*/
|
|
||||||
public function testTranslationThemeExtensionGettext()
|
|
||||||
{
|
|
||||||
$this->conf->set('translation.mode', 'gettext');
|
|
||||||
$this->conf->set('raintpl_tpl', 'tests/utils/customtpl/');
|
|
||||||
$this->conf->set('theme', 'dummy');
|
|
||||||
new Languages('en', $this->conf);
|
|
||||||
$txt = 'rooster'; // ignore me poedit
|
|
||||||
$this->assertEquals('rooster', t($txt, $txt, 1, 'dummy'));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test t() with an extension language file coming from the theme in PHP mode
|
|
||||||
*/
|
|
||||||
public function testTranslationThemeExtensionPhp()
|
|
||||||
{
|
|
||||||
$this->conf->set('translation.mode', 'php');
|
|
||||||
$this->conf->set('raintpl_tpl', 'tests/utils/customtpl/');
|
|
||||||
$this->conf->set('theme', 'dummy');
|
|
||||||
new Languages('en', $this->conf);
|
|
||||||
$txt = 'rooster'; // ignore me poedit
|
|
||||||
$this->assertEquals('rooster', t($txt, $txt, 1, 'dummy'));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test t() with an extension language file in gettext mode
|
|
||||||
*/
|
|
||||||
public function testTranslationExtensionGettext()
|
|
||||||
{
|
|
||||||
$this->conf->set('translation.mode', 'gettext');
|
|
||||||
$this->conf->set('translation.extensions.test', 'tests/utils/languages/');
|
|
||||||
new Languages('en', $this->conf);
|
|
||||||
$txt = 'car'; // ignore me poedit
|
|
||||||
$this->assertEquals('car', t($txt, $txt, 1, 'test'));
|
|
||||||
$this->assertEquals('Search', t('Search', 'Search', 1, 'test'));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test t() with an extension language file in PHP mode
|
|
||||||
*/
|
|
||||||
public function testTranslationExtensionPhp()
|
|
||||||
{
|
|
||||||
$this->conf->set('translation.mode', 'php');
|
|
||||||
$this->conf->set('translation.extensions.test', 'tests/utils/languages/');
|
|
||||||
new Languages('en', $this->conf);
|
|
||||||
$txt = 'car'; // ignore me poedit
|
|
||||||
$this->assertEquals('car', t($txt, $txt, 1, 'test'));
|
|
||||||
$this->assertEquals('Search', t('Search', 'Search', 1, 'test'));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,178 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace Shaarli\Plugin;
|
|
||||||
|
|
||||||
use Shaarli\Bookmark\Bookmark;
|
|
||||||
use Shaarli\Config\ConfigManager;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Unit tests for Plugins
|
|
||||||
*/
|
|
||||||
class PluginManagerTest extends \Shaarli\TestCase
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Path to tests plugin.
|
|
||||||
* @var string $pluginPath
|
|
||||||
*/
|
|
||||||
private static $pluginPath = 'tests/plugins';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test plugin.
|
|
||||||
* @var string $pluginName
|
|
||||||
*/
|
|
||||||
private static $pluginName = 'test';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var PluginManager $pluginManager Plugin Mananger instance.
|
|
||||||
*/
|
|
||||||
protected $pluginManager;
|
|
||||||
|
|
||||||
public function setUp(): void
|
|
||||||
{
|
|
||||||
$conf = new ConfigManager('');
|
|
||||||
$this->pluginManager = new PluginManager($conf);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test plugin loading and hook execution.
|
|
||||||
*/
|
|
||||||
public function testPlugin(): void
|
|
||||||
{
|
|
||||||
PluginManager::$PLUGINS_PATH = self::$pluginPath;
|
|
||||||
$this->pluginManager->load([self::$pluginName]);
|
|
||||||
|
|
||||||
$this->assertTrue(function_exists('hook_test_random'));
|
|
||||||
|
|
||||||
$data = [0 => 'woot'];
|
|
||||||
$this->pluginManager->executeHooks('random', $data);
|
|
||||||
|
|
||||||
static::assertCount(2, $data);
|
|
||||||
static::assertSame('woot', $data[1]);
|
|
||||||
|
|
||||||
$data = [0 => 'woot'];
|
|
||||||
$this->pluginManager->executeHooks('random', $data, ['target' => 'test']);
|
|
||||||
|
|
||||||
static::assertCount(2, $data);
|
|
||||||
static::assertSame('page test', $data[1]);
|
|
||||||
|
|
||||||
$data = [0 => 'woot'];
|
|
||||||
$this->pluginManager->executeHooks('random', $data, ['loggedin' => true]);
|
|
||||||
|
|
||||||
static::assertCount(2, $data);
|
|
||||||
static::assertEquals('loggedin', $data[1]);
|
|
||||||
|
|
||||||
$data = [0 => 'woot'];
|
|
||||||
$this->pluginManager->executeHooks('random', $data, ['loggedin' => null]);
|
|
||||||
|
|
||||||
static::assertCount(3, $data);
|
|
||||||
static::assertEquals('loggedin', $data[1]);
|
|
||||||
static::assertArrayHasKey(2, $data);
|
|
||||||
static::assertNull($data[2]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test plugin loading and hook execution with an error: raise an incompatibility error.
|
|
||||||
*/
|
|
||||||
public function testPluginWithPhpError(): void
|
|
||||||
{
|
|
||||||
PluginManager::$PLUGINS_PATH = self::$pluginPath;
|
|
||||||
$this->pluginManager->load([self::$pluginName]);
|
|
||||||
|
|
||||||
$this->assertTrue(function_exists('hook_test_error'));
|
|
||||||
|
|
||||||
$data = [];
|
|
||||||
$this->pluginManager->executeHooks('error', $data);
|
|
||||||
|
|
||||||
$this->assertRegExp(
|
|
||||||
'/test \[plugin incompatibility\]: Class [\'"]Unknown[\'"] not found/',
|
|
||||||
$this->pluginManager->getErrors()[0]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test missing plugin loading.
|
|
||||||
*/
|
|
||||||
public function testPluginNotFound(): void
|
|
||||||
{
|
|
||||||
$this->pluginManager->load([]);
|
|
||||||
$this->pluginManager->load(['nope', 'renope']);
|
|
||||||
$this->addToAssertionCount(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test plugin metadata loading.
|
|
||||||
*/
|
|
||||||
public function testGetPluginsMeta(): void
|
|
||||||
{
|
|
||||||
PluginManager::$PLUGINS_PATH = self::$pluginPath;
|
|
||||||
$this->pluginManager->load([self::$pluginName]);
|
|
||||||
|
|
||||||
$expectedParameters = [
|
|
||||||
'pop' => [
|
|
||||||
'value' => '',
|
|
||||||
'desc' => 'pop description',
|
|
||||||
],
|
|
||||||
'hip' => [
|
|
||||||
'value' => '',
|
|
||||||
'desc' => '',
|
|
||||||
],
|
|
||||||
];
|
|
||||||
$meta = $this->pluginManager->getPluginsMeta();
|
|
||||||
$this->assertEquals('test plugin', $meta[self::$pluginName]['description']);
|
|
||||||
$this->assertEquals($expectedParameters, $meta[self::$pluginName]['parameters']);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test plugin custom routes - note that there is no check on callable functions
|
|
||||||
*/
|
|
||||||
public function testRegisteredRoutes(): void
|
|
||||||
{
|
|
||||||
PluginManager::$PLUGINS_PATH = self::$pluginPath;
|
|
||||||
$this->pluginManager->load([self::$pluginName]);
|
|
||||||
|
|
||||||
$expectedParameters = [
|
|
||||||
[
|
|
||||||
'method' => 'GET',
|
|
||||||
'route' => '/test',
|
|
||||||
'callable' => 'getFunction',
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'method' => 'POST',
|
|
||||||
'route' => '/custom',
|
|
||||||
'callable' => 'postFunction',
|
|
||||||
],
|
|
||||||
];
|
|
||||||
$meta = $this->pluginManager->getRegisteredRoutes();
|
|
||||||
static::assertSame($expectedParameters, $meta[self::$pluginName]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test plugin custom routes with invalid route
|
|
||||||
*/
|
|
||||||
public function testRegisteredRoutesInvalid(): void
|
|
||||||
{
|
|
||||||
$plugin = 'test_route_invalid';
|
|
||||||
$this->pluginManager->load([$plugin]);
|
|
||||||
|
|
||||||
$meta = $this->pluginManager->getRegisteredRoutes();
|
|
||||||
static::assertSame([], $meta);
|
|
||||||
|
|
||||||
$errors = $this->pluginManager->getErrors();
|
|
||||||
static::assertSame(['test_route_invalid [plugin incompatibility]: trying to register invalid route.'], $errors);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testSearchFilterPlugin(): void
|
|
||||||
{
|
|
||||||
PluginManager::$PLUGINS_PATH = self::$pluginPath;
|
|
||||||
$this->pluginManager->load([self::$pluginName]);
|
|
||||||
|
|
||||||
static::assertNull($this->pluginManager->getFilterSearchEntryHooks());
|
|
||||||
|
|
||||||
static::assertTrue($this->pluginManager->filterSearchEntry(new Bookmark(), ['_result' => true]));
|
|
||||||
|
|
||||||
static::assertCount(1, $this->pluginManager->getFilterSearchEntryHooks());
|
|
||||||
static::assertSame('hook_test_filter_search_entry', $this->pluginManager->getFilterSearchEntryHooks()[0]);
|
|
||||||
|
|
||||||
static::assertFalse($this->pluginManager->filterSearchEntry(new Bookmark(), ['_result' => false]));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,77 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace Shaarli;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Helper class extending \PHPUnit\Framework\TestCase.
|
|
||||||
* Used to make Shaarli UT run on multiple versions of PHPUnit.
|
|
||||||
*/
|
|
||||||
class TestCase extends \PHPUnit\Framework\TestCase
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* expectExceptionMessageRegExp has been removed and replaced by expectExceptionMessageMatches in PHPUnit 9.
|
|
||||||
*/
|
|
||||||
public function expectExceptionMessageRegExp(string $regularExpression): void
|
|
||||||
{
|
|
||||||
if (method_exists($this, 'expectExceptionMessageMatches')) {
|
|
||||||
$this->expectExceptionMessageMatches($regularExpression);
|
|
||||||
} else {
|
|
||||||
parent::expectExceptionMessageRegExp($regularExpression);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* assertContains is now used for iterable, strings should use assertStringContainsString
|
|
||||||
*/
|
|
||||||
public function assertContainsPolyfill($expected, $actual, string $message = ''): void
|
|
||||||
{
|
|
||||||
if (is_string($actual) && method_exists($this, 'assertStringContainsString')) {
|
|
||||||
static::assertStringContainsString($expected, $actual, $message);
|
|
||||||
} else {
|
|
||||||
static::assertContains($expected, $actual, $message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* assertNotContains is now used for iterable, strings should use assertStringNotContainsString
|
|
||||||
*/
|
|
||||||
public function assertNotContainsPolyfill($expected, $actual, string $message = ''): void
|
|
||||||
{
|
|
||||||
if (is_string($actual) && method_exists($this, 'assertStringNotContainsString')) {
|
|
||||||
static::assertStringNotContainsString($expected, $actual, $message);
|
|
||||||
} else {
|
|
||||||
static::assertNotContains($expected, $actual, $message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* assertFileNotExists has been renamed in assertFileDoesNotExist
|
|
||||||
*/
|
|
||||||
public static function assertFileNotExists(string $filename, string $message = ''): void
|
|
||||||
{
|
|
||||||
if (method_exists(TestCase::class, 'assertFileDoesNotExist')) {
|
|
||||||
static::assertFileDoesNotExist($filename, $message);
|
|
||||||
} else {
|
|
||||||
parent::assertFileNotExists($filename, $message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* assertRegExp has been renamed in assertMatchesRegularExpression
|
|
||||||
*/
|
|
||||||
public static function assertRegExp(string $pattern, string $string, string $message = ''): void
|
|
||||||
{
|
|
||||||
if (method_exists(TestCase::class, 'assertMatchesRegularExpression')) {
|
|
||||||
static::assertMatchesRegularExpression($pattern, $string, $message);
|
|
||||||
} else {
|
|
||||||
parent::assertRegExp($pattern, $string, $message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function isInTestsContext(): bool
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,115 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace Shaarli;
|
|
||||||
|
|
||||||
use Shaarli\Config\ConfigManager;
|
|
||||||
use WebThumbnailer\Application\ConfigManager as WTConfigManager;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Class ThumbnailerTest
|
|
||||||
*
|
|
||||||
* We only make 1 thumb test because:
|
|
||||||
*
|
|
||||||
* 1. the thumbnailer library is itself tested
|
|
||||||
* 2. we don't want to make too many external requests during the tests
|
|
||||||
*/
|
|
||||||
class ThumbnailerTest extends TestCase
|
|
||||||
{
|
|
||||||
protected const WIDTH = 190;
|
|
||||||
|
|
||||||
protected const HEIGHT = 210;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var Thumbnailer;
|
|
||||||
*/
|
|
||||||
protected $thumbnailer;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var ConfigManager
|
|
||||||
*/
|
|
||||||
protected $conf;
|
|
||||||
|
|
||||||
protected function setUp(): void
|
|
||||||
{
|
|
||||||
$this->conf = new ConfigManager('tests/utils/config/configJson');
|
|
||||||
$this->conf->set('thumbnails.mode', Thumbnailer::MODE_ALL);
|
|
||||||
$this->conf->set('thumbnails.width', self::WIDTH);
|
|
||||||
$this->conf->set('thumbnails.height', self::HEIGHT);
|
|
||||||
$this->conf->set('dev.debug', true);
|
|
||||||
|
|
||||||
$this->thumbnailer = new Thumbnailer($this->conf);
|
|
||||||
// cache files in the sandbox
|
|
||||||
WTConfigManager::addFile('tests/utils/config/wt.json');
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function tearDown(): void
|
|
||||||
{
|
|
||||||
$this->rrmdirContent('sandbox/');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test a thumbnail with a custom size in 'all' mode.
|
|
||||||
*/
|
|
||||||
public function testThumbnailAllValid()
|
|
||||||
{
|
|
||||||
$thumb = $this->thumbnailer->get('https://gitlab.com/shaarli/Shaarli');
|
|
||||||
$this->assertNotFalse($thumb);
|
|
||||||
$image = imagecreatefromstring(file_get_contents($thumb));
|
|
||||||
$this->assertEquals(self::WIDTH, imagesx($image));
|
|
||||||
$this->assertEquals(self::HEIGHT, imagesy($image));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test a thumbnail with a custom size in 'common' mode.
|
|
||||||
*/
|
|
||||||
public function testThumbnailCommonValid()
|
|
||||||
{
|
|
||||||
$this->conf->set('thumbnails.mode', Thumbnailer::MODE_COMMON);
|
|
||||||
$thumb = $this->thumbnailer->get('https://imgur.com/jlFgGpe');
|
|
||||||
$this->assertNotFalse($thumb);
|
|
||||||
$image = imagecreatefromstring(file_get_contents($thumb));
|
|
||||||
$this->assertEquals(self::WIDTH, imagesx($image));
|
|
||||||
$this->assertEquals(self::HEIGHT, imagesy($image));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test a thumbnail in 'common' mode which isn't include in common websites.
|
|
||||||
*/
|
|
||||||
public function testThumbnailCommonInvalid()
|
|
||||||
{
|
|
||||||
$this->conf->set('thumbnails.mode', Thumbnailer::MODE_COMMON);
|
|
||||||
$thumb = $this->thumbnailer->get('https://github.com/shaarli/Shaarli/');
|
|
||||||
$this->assertFalse($thumb);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test a thumbnail that can't be retrieved.
|
|
||||||
*/
|
|
||||||
public function testThumbnailNotValid()
|
|
||||||
{
|
|
||||||
$oldlog = ini_get('error_log');
|
|
||||||
ini_set('error_log', '/dev/null');
|
|
||||||
|
|
||||||
$thumbnailer = new Thumbnailer(new ConfigManager());
|
|
||||||
$thumb = $thumbnailer->get('nope');
|
|
||||||
$this->assertFalse($thumb);
|
|
||||||
|
|
||||||
ini_set('error_log', $oldlog);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function rrmdirContent($dir)
|
|
||||||
{
|
|
||||||
if (is_dir($dir)) {
|
|
||||||
$objects = scandir($dir);
|
|
||||||
foreach ($objects as $object) {
|
|
||||||
if ($object != "." && $object != "..") {
|
|
||||||
if (is_dir($dir . "/" . $object)) {
|
|
||||||
$this->rrmdirContent($dir . "/" . $object);
|
|
||||||
} else {
|
|
||||||
unlink($dir . "/" . $object);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,104 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
/**
|
|
||||||
* TimeZone's tests
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Shaarli\Tests;
|
|
||||||
|
|
||||||
use Shaarli\TestCase;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Unitary tests for timezone utilities
|
|
||||||
*/
|
|
||||||
class TimeZoneTest extends TestCase
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @var array of timezones
|
|
||||||
*/
|
|
||||||
protected $installedTimezones;
|
|
||||||
|
|
||||||
protected function setUp(): void
|
|
||||||
{
|
|
||||||
$this->installedTimezones = [
|
|
||||||
'Antarctica/Syowa',
|
|
||||||
'Europe/London',
|
|
||||||
'Europe/Paris',
|
|
||||||
'UTC'
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generate a timezone selection form
|
|
||||||
*/
|
|
||||||
public function testGenerateTimeZoneForm()
|
|
||||||
{
|
|
||||||
$expected = [
|
|
||||||
'continents' => [
|
|
||||||
'Antarctica',
|
|
||||||
'Europe',
|
|
||||||
'UTC',
|
|
||||||
'selected' => '',
|
|
||||||
],
|
|
||||||
'cities' => [
|
|
||||||
['continent' => 'Antarctica', 'city' => 'Syowa'],
|
|
||||||
['continent' => 'Europe', 'city' => 'London'],
|
|
||||||
['continent' => 'Europe', 'city' => 'Paris'],
|
|
||||||
['continent' => 'UTC', 'city' => 'UTC'],
|
|
||||||
'selected' => '',
|
|
||||||
]
|
|
||||||
];
|
|
||||||
|
|
||||||
list($continents, $cities) = generateTimeZoneData($this->installedTimezones);
|
|
||||||
|
|
||||||
$this->assertEquals($expected['continents'], $continents);
|
|
||||||
$this->assertEquals($expected['cities'], $cities);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generate a timezone selection form, with a preselected timezone
|
|
||||||
*/
|
|
||||||
public function testGenerateTimeZoneFormPreselected()
|
|
||||||
{
|
|
||||||
$expected = [
|
|
||||||
'continents' => [
|
|
||||||
'Antarctica',
|
|
||||||
'Europe',
|
|
||||||
'UTC',
|
|
||||||
'selected' => 'Antarctica',
|
|
||||||
],
|
|
||||||
'cities' => [
|
|
||||||
['continent' => 'Antarctica', 'city' => 'Syowa'],
|
|
||||||
['continent' => 'Europe', 'city' => 'London'],
|
|
||||||
['continent' => 'Europe', 'city' => 'Paris'],
|
|
||||||
['continent' => 'UTC', 'city' => 'UTC'],
|
|
||||||
'selected' => 'Syowa',
|
|
||||||
]
|
|
||||||
];
|
|
||||||
|
|
||||||
list($continents, $cities) = generateTimeZoneData($this->installedTimezones, 'Antarctica/Syowa');
|
|
||||||
|
|
||||||
$this->assertEquals($expected['continents'], $continents);
|
|
||||||
$this->assertEquals($expected['cities'], $cities);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check valid timezones
|
|
||||||
*/
|
|
||||||
public function testValidTimeZone()
|
|
||||||
{
|
|
||||||
$this->assertTrue(isTimeZoneValid('America', 'Argentina/Ushuaia'));
|
|
||||||
$this->assertTrue(isTimeZoneValid('Europe', 'Oslo'));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check invalid timezones
|
|
||||||
*/
|
|
||||||
public function testInvalidTimeZone()
|
|
||||||
{
|
|
||||||
$this->assertFalse(isTimeZoneValid('CEST', 'CEST'));
|
|
||||||
$this->assertFalse(isTimeZoneValid('Europe', 'Atlantis'));
|
|
||||||
$this->assertFalse(isTimeZoneValid('Middle_Earth', 'Moria'));
|
|
||||||
$this->assertFalse(isTimeZoneValid('UTC', 'UTC'));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,463 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Utilities' tests
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Shaarli\Tests;
|
|
||||||
|
|
||||||
use DateTime;
|
|
||||||
use Shaarli\TestCase;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Unitary tests for Shaarli utilities
|
|
||||||
*/
|
|
||||||
class UtilsTest extends TestCase
|
|
||||||
{
|
|
||||||
// Log file
|
|
||||||
protected static $testLogFile = 'tests.log';
|
|
||||||
|
|
||||||
// Expected log date format
|
|
||||||
protected static $dateFormat = 'Y/m/d H:i:s';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var string Save the current timezone.
|
|
||||||
*/
|
|
||||||
protected static $defaultTimeZone;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Assign reference data
|
|
||||||
*/
|
|
||||||
public static function setUpBeforeClass(): void
|
|
||||||
{
|
|
||||||
self::$defaultTimeZone = date_default_timezone_get();
|
|
||||||
// Timezone without DST for test consistency
|
|
||||||
date_default_timezone_set('Africa/Nairobi');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reset the timezone
|
|
||||||
*/
|
|
||||||
public static function tearDownAfterClass(): void
|
|
||||||
{
|
|
||||||
date_default_timezone_set(self::$defaultTimeZone);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Resets test data before each test
|
|
||||||
*/
|
|
||||||
protected function setUp(): void
|
|
||||||
{
|
|
||||||
if (file_exists(self::$testLogFile)) {
|
|
||||||
unlink(self::$testLogFile);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a list of the elements from the last logged entry
|
|
||||||
*
|
|
||||||
* @return array (date, ip address, message)
|
|
||||||
*/
|
|
||||||
protected function getLastLogEntry()
|
|
||||||
{
|
|
||||||
$logFile = file(self::$testLogFile);
|
|
||||||
return explode(' - ', trim(array_pop($logFile), PHP_EOL));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Format a log a message - IPv4 client address
|
|
||||||
*/
|
|
||||||
public function testFormatLogIp4()
|
|
||||||
{
|
|
||||||
$message = 'IPv4 client connected';
|
|
||||||
$log = format_log($message, '127.0.0.1');
|
|
||||||
|
|
||||||
static::assertSame('- 127.0.0.1 - IPv4 client connected', $log);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Format a log a message - IPv6 client address
|
|
||||||
*/
|
|
||||||
public function testFormatLogIp6()
|
|
||||||
{
|
|
||||||
$message = 'IPv6 client connected';
|
|
||||||
$log = format_log($message, '2001:db8::ff00:42:8329');
|
|
||||||
|
|
||||||
static::assertSame('- 2001:db8::ff00:42:8329 - IPv6 client connected', $log);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Represent a link by its hash
|
|
||||||
*/
|
|
||||||
public function testSmallHash()
|
|
||||||
{
|
|
||||||
$this->assertEquals('CyAAJw', smallHash('http://test.io'));
|
|
||||||
$this->assertEquals(6, strlen(smallHash('https://github.com')));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Look for a substring at the beginning of a string
|
|
||||||
*/
|
|
||||||
public function testStartsWithCaseInsensitive()
|
|
||||||
{
|
|
||||||
$this->assertTrue(startsWith('Lorem ipsum', 'lorem', false));
|
|
||||||
$this->assertTrue(startsWith('Lorem ipsum', 'LoReM i', false));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Look for a substring at the beginning of a string (case-sensitive)
|
|
||||||
*/
|
|
||||||
public function testStartsWithCaseSensitive()
|
|
||||||
{
|
|
||||||
$this->assertTrue(startsWith('Lorem ipsum', 'Lorem', true));
|
|
||||||
$this->assertFalse(startsWith('Lorem ipsum', 'lorem', true));
|
|
||||||
$this->assertFalse(startsWith('Lorem ipsum', 'LoReM i', true));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Look for a substring at the beginning of a string (Unicode)
|
|
||||||
*/
|
|
||||||
public function testStartsWithSpecialChars()
|
|
||||||
{
|
|
||||||
$this->assertTrue(startsWith('å!ùµ', 'å!', false));
|
|
||||||
$this->assertTrue(startsWith('µ$åù', 'µ$', true));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Look for a substring at the end of a string
|
|
||||||
*/
|
|
||||||
public function testEndsWithCaseInsensitive()
|
|
||||||
{
|
|
||||||
$this->assertTrue(endsWith('Lorem ipsum', 'ipsum', false));
|
|
||||||
$this->assertTrue(endsWith('Lorem ipsum', 'm IpsUM', false));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Look for a substring at the end of a string (case-sensitive)
|
|
||||||
*/
|
|
||||||
public function testEndsWithCaseSensitive()
|
|
||||||
{
|
|
||||||
$this->assertTrue(endsWith('lorem Ipsum', 'Ipsum', true));
|
|
||||||
$this->assertFalse(endsWith('lorem Ipsum', 'ipsum', true));
|
|
||||||
$this->assertFalse(endsWith('lorem Ipsum', 'M IPsuM', true));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Look for a substring at the end of a string (Unicode)
|
|
||||||
*/
|
|
||||||
public function testEndsWithSpecialChars()
|
|
||||||
{
|
|
||||||
$this->assertTrue(endsWith('å!ùµ', 'ùµ', false));
|
|
||||||
$this->assertTrue(endsWith('µ$åù', 'åù', true));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check valid date strings, according to a DateTime format
|
|
||||||
*/
|
|
||||||
public function testCheckValidDateFormat()
|
|
||||||
{
|
|
||||||
$this->assertTrue(checkDateFormat('Ymd', '20150627'));
|
|
||||||
$this->assertTrue(checkDateFormat('Y-m-d', '2015-06-27'));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check erroneous date strings, according to a DateTime format
|
|
||||||
*/
|
|
||||||
public function testCheckInvalidDateFormat()
|
|
||||||
{
|
|
||||||
$this->assertFalse(checkDateFormat('Ymd', '2015'));
|
|
||||||
$this->assertFalse(checkDateFormat('Y-m-d', '2015-06'));
|
|
||||||
$this->assertFalse(checkDateFormat('Ymd', 'DeLorean'));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test generate location with valid data.
|
|
||||||
*/
|
|
||||||
public function testGenerateLocation()
|
|
||||||
{
|
|
||||||
$ref = 'http://localhost/?test';
|
|
||||||
$this->assertEquals($ref, generateLocation($ref, 'localhost'));
|
|
||||||
$ref = 'http://localhost:8080/?test';
|
|
||||||
$this->assertEquals($ref, generateLocation($ref, 'localhost:8080'));
|
|
||||||
$ref = '?localreferer#hash';
|
|
||||||
$this->assertEquals($ref, generateLocation($ref, 'localhost:8080'));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test generate location - anti loop.
|
|
||||||
*/
|
|
||||||
public function testGenerateLocationLoop()
|
|
||||||
{
|
|
||||||
$ref = 'http://localhost/?test';
|
|
||||||
$this->assertEquals('./?', generateLocation($ref, 'localhost', ['test']));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test generate location - from other domain.
|
|
||||||
*/
|
|
||||||
public function testGenerateLocationOut()
|
|
||||||
{
|
|
||||||
$ref = 'http://somewebsite.com/?test';
|
|
||||||
$this->assertEquals('./?', generateLocation($ref, 'localhost'));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test generateSecretApi.
|
|
||||||
*/
|
|
||||||
public function testGenerateSecretApi()
|
|
||||||
{
|
|
||||||
$this->assertEquals(12, strlen(generate_api_secret('foo', 'bar')));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test generateSecretApi with invalid parameters.
|
|
||||||
*/
|
|
||||||
public function testGenerateSecretApiInvalid()
|
|
||||||
{
|
|
||||||
$this->assertFalse(generate_api_secret('', ''));
|
|
||||||
$this->assertFalse(generate_api_secret(false, false));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test normalize_spaces.
|
|
||||||
*/
|
|
||||||
public function testNormalizeSpace()
|
|
||||||
{
|
|
||||||
$str = ' foo bar is important ';
|
|
||||||
$this->assertEquals('foo bar is important', normalize_spaces($str));
|
|
||||||
$this->assertEquals('foo', normalize_spaces('foo'));
|
|
||||||
$this->assertEquals('', normalize_spaces(''));
|
|
||||||
$this->assertEquals(null, normalize_spaces(null));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test arrays_combine
|
|
||||||
*/
|
|
||||||
public function testCartesianProductGenerator()
|
|
||||||
{
|
|
||||||
$arr = [['ab', 'cd'], ['ef', 'gh'], ['ij', 'kl'], ['m']];
|
|
||||||
$expected = [
|
|
||||||
['ab', 'ef', 'ij', 'm'],
|
|
||||||
['ab', 'ef', 'kl', 'm'],
|
|
||||||
['ab', 'gh', 'ij', 'm'],
|
|
||||||
['ab', 'gh', 'kl', 'm'],
|
|
||||||
['cd', 'ef', 'ij', 'm'],
|
|
||||||
['cd', 'ef', 'kl', 'm'],
|
|
||||||
['cd', 'gh', 'ij', 'm'],
|
|
||||||
['cd', 'gh', 'kl', 'm'],
|
|
||||||
];
|
|
||||||
$this->assertEquals($expected, iterator_to_array(cartesian_product_generator($arr)));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test date_format() with invalid parameter.
|
|
||||||
*/
|
|
||||||
public function testDateFormatInvalid()
|
|
||||||
{
|
|
||||||
$this->assertFalse(format_date([]));
|
|
||||||
$this->assertFalse(format_date(null));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test is_integer_mixed with valid values
|
|
||||||
*/
|
|
||||||
public function testIsIntegerMixedValid()
|
|
||||||
{
|
|
||||||
$this->assertTrue(is_integer_mixed(12));
|
|
||||||
$this->assertTrue(is_integer_mixed('12'));
|
|
||||||
$this->assertTrue(is_integer_mixed(-12));
|
|
||||||
$this->assertTrue(is_integer_mixed('-12'));
|
|
||||||
$this->assertTrue(is_integer_mixed(0));
|
|
||||||
$this->assertTrue(is_integer_mixed('0'));
|
|
||||||
$this->assertTrue(is_integer_mixed(0x0a));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test is_integer_mixed with invalid values
|
|
||||||
*/
|
|
||||||
public function testIsIntegerMixedInvalid()
|
|
||||||
{
|
|
||||||
$this->assertFalse(is_integer_mixed(true));
|
|
||||||
$this->assertFalse(is_integer_mixed(false));
|
|
||||||
$this->assertFalse(is_integer_mixed([]));
|
|
||||||
$this->assertFalse(is_integer_mixed(['test']));
|
|
||||||
$this->assertFalse(is_integer_mixed([12]));
|
|
||||||
$this->assertFalse(is_integer_mixed(new DateTime()));
|
|
||||||
$this->assertFalse(is_integer_mixed('0x0a'));
|
|
||||||
$this->assertFalse(is_integer_mixed('12k'));
|
|
||||||
$this->assertFalse(is_integer_mixed('k12'));
|
|
||||||
$this->assertFalse(is_integer_mixed(''));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test return_bytes
|
|
||||||
*/
|
|
||||||
public function testReturnBytes()
|
|
||||||
{
|
|
||||||
$this->assertEquals(2 * 1024, return_bytes('2k'));
|
|
||||||
$this->assertEquals(2 * 1024, return_bytes('2K'));
|
|
||||||
$this->assertEquals(2 * (pow(1024, 2)), return_bytes('2m'));
|
|
||||||
$this->assertEquals(2 * (pow(1024, 2)), return_bytes('2M'));
|
|
||||||
$this->assertEquals(2 * (pow(1024, 3)), return_bytes('2g'));
|
|
||||||
$this->assertEquals(2 * (pow(1024, 3)), return_bytes('2G'));
|
|
||||||
$this->assertEquals(374, return_bytes('374'));
|
|
||||||
$this->assertEquals(374, return_bytes(374));
|
|
||||||
$this->assertEquals(0, return_bytes('0'));
|
|
||||||
$this->assertEquals(0, return_bytes(0));
|
|
||||||
$this->assertEquals(-1, return_bytes('-1'));
|
|
||||||
$this->assertEquals(-1, return_bytes(-1));
|
|
||||||
$this->assertEquals('', return_bytes(''));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test human_bytes
|
|
||||||
*/
|
|
||||||
public function testHumanBytes()
|
|
||||||
{
|
|
||||||
$this->assertEquals('2' . t('kiB'), human_bytes(2 * 1024));
|
|
||||||
$this->assertEquals('2' . t('kiB'), human_bytes(strval(2 * 1024)));
|
|
||||||
$this->assertEquals('2' . t('MiB'), human_bytes(2 * (pow(1024, 2))));
|
|
||||||
$this->assertEquals('2' . t('MiB'), human_bytes(strval(2 * (pow(1024, 2)))));
|
|
||||||
$this->assertEquals('2' . t('GiB'), human_bytes(2 * (pow(1024, 3))));
|
|
||||||
$this->assertEquals('2' . t('GiB'), human_bytes(strval(2 * (pow(1024, 3)))));
|
|
||||||
$this->assertEquals('374' . t('B'), human_bytes(374));
|
|
||||||
$this->assertEquals('374' . t('B'), human_bytes('374'));
|
|
||||||
$this->assertEquals('232' . t('kiB'), human_bytes(237481));
|
|
||||||
$this->assertEquals(t('Unlimited'), human_bytes('0'));
|
|
||||||
$this->assertEquals(t('Unlimited'), human_bytes(0));
|
|
||||||
$this->assertEquals(t('Setting not set'), human_bytes(''));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test get_max_upload_size with formatting
|
|
||||||
*/
|
|
||||||
public function testGetMaxUploadSize()
|
|
||||||
{
|
|
||||||
$this->assertEquals('1' . t('MiB'), get_max_upload_size(2097152, '1024k'));
|
|
||||||
$this->assertEquals('1' . t('MiB'), get_max_upload_size('1m', '2m'));
|
|
||||||
$this->assertEquals('100' . t('B'), get_max_upload_size(100, 100));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test get_max_upload_size without formatting
|
|
||||||
*/
|
|
||||||
public function testGetMaxUploadSizeRaw()
|
|
||||||
{
|
|
||||||
$this->assertEquals('1048576', get_max_upload_size(2097152, '1024k', false));
|
|
||||||
$this->assertEquals('1048576', get_max_upload_size('1m', '2m', false));
|
|
||||||
$this->assertEquals('100', get_max_upload_size(100, 100, false));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test alphabetical_sort by value, not reversed, with php-intl.
|
|
||||||
*/
|
|
||||||
public function testAlphabeticalSortByValue()
|
|
||||||
{
|
|
||||||
$arr = [
|
|
||||||
'zZz',
|
|
||||||
'éee',
|
|
||||||
'éae',
|
|
||||||
'eee',
|
|
||||||
'A',
|
|
||||||
'a',
|
|
||||||
'zzz',
|
|
||||||
];
|
|
||||||
$expected = [
|
|
||||||
'a',
|
|
||||||
'A',
|
|
||||||
'éae',
|
|
||||||
'eee',
|
|
||||||
'éee',
|
|
||||||
'zzz',
|
|
||||||
'zZz',
|
|
||||||
];
|
|
||||||
|
|
||||||
alphabetical_sort($arr);
|
|
||||||
$this->assertEquals($expected, $arr);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test alphabetical_sort by value, reversed, with php-intl.
|
|
||||||
*/
|
|
||||||
public function testAlphabeticalSortByValueReversed()
|
|
||||||
{
|
|
||||||
$arr = [
|
|
||||||
'zZz',
|
|
||||||
'éee',
|
|
||||||
'éae',
|
|
||||||
'eee',
|
|
||||||
'A',
|
|
||||||
'a',
|
|
||||||
'zzz',
|
|
||||||
];
|
|
||||||
$expected = [
|
|
||||||
'zZz',
|
|
||||||
'zzz',
|
|
||||||
'éee',
|
|
||||||
'eee',
|
|
||||||
'éae',
|
|
||||||
'A',
|
|
||||||
'a',
|
|
||||||
];
|
|
||||||
|
|
||||||
alphabetical_sort($arr, true);
|
|
||||||
$this->assertEquals($expected, $arr);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test alphabetical_sort by keys, not reversed, with php-intl.
|
|
||||||
*/
|
|
||||||
public function testAlphabeticalSortByKeys()
|
|
||||||
{
|
|
||||||
$arr = [
|
|
||||||
'zZz' => true,
|
|
||||||
'éee' => true,
|
|
||||||
'éae' => true,
|
|
||||||
'eee' => true,
|
|
||||||
'A' => true,
|
|
||||||
'a' => true,
|
|
||||||
'zzz' => true,
|
|
||||||
];
|
|
||||||
$expected = [
|
|
||||||
'a' => true,
|
|
||||||
'A' => true,
|
|
||||||
'éae' => true,
|
|
||||||
'eee' => true,
|
|
||||||
'éee' => true,
|
|
||||||
'zzz' => true,
|
|
||||||
'zZz' => true,
|
|
||||||
];
|
|
||||||
|
|
||||||
alphabetical_sort($arr, true, true);
|
|
||||||
$this->assertEquals($expected, $arr);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test alphabetical_sort by keys, reversed, with php-intl.
|
|
||||||
*/
|
|
||||||
public function testAlphabeticalSortByKeysReversed()
|
|
||||||
{
|
|
||||||
$arr = [
|
|
||||||
'zZz' => true,
|
|
||||||
'éee' => true,
|
|
||||||
'éae' => true,
|
|
||||||
'eee' => true,
|
|
||||||
'A' => true,
|
|
||||||
'a' => true,
|
|
||||||
'zzz' => true,
|
|
||||||
];
|
|
||||||
$expected = [
|
|
||||||
'zZz' => true,
|
|
||||||
'zzz' => true,
|
|
||||||
'éee' => true,
|
|
||||||
'eee' => true,
|
|
||||||
'éae' => true,
|
|
||||||
'A' => true,
|
|
||||||
'a' => true,
|
|
||||||
];
|
|
||||||
|
|
||||||
alphabetical_sort($arr, true, true);
|
|
||||||
$this->assertEquals($expected, $arr);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,262 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace Shaarli\Api;
|
|
||||||
|
|
||||||
use Shaarli\Config\ConfigManager;
|
|
||||||
use Shaarli\History;
|
|
||||||
use Shaarli\Plugin\PluginManager;
|
|
||||||
use Shaarli\Tests\Utils\ReferenceLinkDB;
|
|
||||||
use Slim\Container;
|
|
||||||
use Slim\Http\Environment;
|
|
||||||
use Slim\Http\Request;
|
|
||||||
use Slim\Http\Response;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Class ApiMiddlewareTest
|
|
||||||
*
|
|
||||||
* Test the REST API Slim Middleware.
|
|
||||||
*
|
|
||||||
* Note that we can't test a valid use case here, because the middleware
|
|
||||||
* needs to call a valid controller/action during its execution.
|
|
||||||
*
|
|
||||||
* @package Api
|
|
||||||
*/
|
|
||||||
class ApiMiddlewareTest extends \Shaarli\TestCase
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @var string datastore to test write operations
|
|
||||||
*/
|
|
||||||
protected static $testDatastore = 'sandbox/datastore.php';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var ConfigManager instance
|
|
||||||
*/
|
|
||||||
protected $conf;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var ReferenceLinkDB instance.
|
|
||||||
*/
|
|
||||||
protected $refDB = null;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var Container instance.
|
|
||||||
*/
|
|
||||||
protected $container;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Before every test, instantiate a new Api with its config, plugins and bookmarks.
|
|
||||||
*/
|
|
||||||
protected function setUp(): void
|
|
||||||
{
|
|
||||||
$this->conf = new ConfigManager('tests/utils/config/configJson');
|
|
||||||
$this->conf->set('api.secret', 'NapoleonWasALizard');
|
|
||||||
|
|
||||||
$this->refDB = new ReferenceLinkDB();
|
|
||||||
$this->refDB->write(self::$testDatastore);
|
|
||||||
|
|
||||||
$history = new History('sandbox/history.php');
|
|
||||||
|
|
||||||
$this->container = new Container();
|
|
||||||
$this->container['conf'] = $this->conf;
|
|
||||||
$this->container['history'] = $history;
|
|
||||||
$this->container['pluginManager'] = new PluginManager($this->conf);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* After every test, remove the test datastore.
|
|
||||||
*/
|
|
||||||
protected function tearDown(): void
|
|
||||||
{
|
|
||||||
@unlink(self::$testDatastore);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Invoke the middleware with a valid token
|
|
||||||
*/
|
|
||||||
public function testInvokeMiddlewareWithValidToken(): void
|
|
||||||
{
|
|
||||||
$next = function (Request $request, Response $response): Response {
|
|
||||||
return $response;
|
|
||||||
};
|
|
||||||
$mw = new ApiMiddleware($this->container);
|
|
||||||
$env = Environment::mock([
|
|
||||||
'REQUEST_METHOD' => 'GET',
|
|
||||||
'REQUEST_URI' => '/echo',
|
|
||||||
'HTTP_AUTHORIZATION' => 'Bearer ' . ApiUtilsTest::generateValidJwtToken('NapoleonWasALizard'),
|
|
||||||
]);
|
|
||||||
$request = Request::createFromEnvironment($env);
|
|
||||||
$response = new Response();
|
|
||||||
/** @var Response $response */
|
|
||||||
$response = $mw($request, $response, $next);
|
|
||||||
|
|
||||||
$this->assertEquals(200, $response->getStatusCode());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Invoke the middleware with a valid token
|
|
||||||
* Using specific Apache CGI redirected authorization.
|
|
||||||
*/
|
|
||||||
public function testInvokeMiddlewareWithValidTokenFromRedirectedHeader(): void
|
|
||||||
{
|
|
||||||
$next = function (Request $request, Response $response): Response {
|
|
||||||
return $response;
|
|
||||||
};
|
|
||||||
|
|
||||||
$token = 'Bearer ' . ApiUtilsTest::generateValidJwtToken('NapoleonWasALizard');
|
|
||||||
$this->container->environment['REDIRECT_HTTP_AUTHORIZATION'] = $token;
|
|
||||||
$mw = new ApiMiddleware($this->container);
|
|
||||||
$env = Environment::mock([
|
|
||||||
'REQUEST_METHOD' => 'GET',
|
|
||||||
'REQUEST_URI' => '/echo',
|
|
||||||
]);
|
|
||||||
$request = Request::createFromEnvironment($env);
|
|
||||||
$response = new Response();
|
|
||||||
/** @var Response $response */
|
|
||||||
$response = $mw($request, $response, $next);
|
|
||||||
|
|
||||||
$this->assertEquals(200, $response->getStatusCode());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Invoke the middleware with the API disabled:
|
|
||||||
* should return a 401 error Unauthorized.
|
|
||||||
*/
|
|
||||||
public function testInvokeMiddlewareApiDisabled()
|
|
||||||
{
|
|
||||||
$this->conf->set('api.enabled', false);
|
|
||||||
$mw = new ApiMiddleware($this->container);
|
|
||||||
$env = Environment::mock([
|
|
||||||
'REQUEST_METHOD' => 'GET',
|
|
||||||
'REQUEST_URI' => '/echo',
|
|
||||||
]);
|
|
||||||
$request = Request::createFromEnvironment($env);
|
|
||||||
$response = new Response();
|
|
||||||
/** @var Response $response */
|
|
||||||
$response = $mw($request, $response, null);
|
|
||||||
|
|
||||||
$this->assertEquals(401, $response->getStatusCode());
|
|
||||||
$body = json_decode((string) $response->getBody());
|
|
||||||
$this->assertEquals('Not authorized', $body);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Invoke the middleware with the API disabled in debug mode:
|
|
||||||
* should return a 401 error Unauthorized - with a specific message and a stacktrace.
|
|
||||||
*/
|
|
||||||
public function testInvokeMiddlewareApiDisabledDebug()
|
|
||||||
{
|
|
||||||
$this->conf->set('api.enabled', false);
|
|
||||||
$this->conf->set('dev.debug', true);
|
|
||||||
$mw = new ApiMiddleware($this->container);
|
|
||||||
$env = Environment::mock([
|
|
||||||
'REQUEST_METHOD' => 'GET',
|
|
||||||
'REQUEST_URI' => '/echo',
|
|
||||||
]);
|
|
||||||
$request = Request::createFromEnvironment($env);
|
|
||||||
$response = new Response();
|
|
||||||
/** @var Response $response */
|
|
||||||
$response = $mw($request, $response, null);
|
|
||||||
|
|
||||||
$this->assertEquals(401, $response->getStatusCode());
|
|
||||||
$body = json_decode((string) $response->getBody());
|
|
||||||
$this->assertEquals('Not authorized: API is disabled', $body->message);
|
|
||||||
$this->assertContainsPolyfill('ApiAuthorizationException', $body->stacktrace);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Invoke the middleware without a token (debug):
|
|
||||||
* should return a 401 error Unauthorized - with a specific message and a stacktrace.
|
|
||||||
*/
|
|
||||||
public function testInvokeMiddlewareNoTokenProvidedDebug()
|
|
||||||
{
|
|
||||||
$this->conf->set('dev.debug', true);
|
|
||||||
$mw = new ApiMiddleware($this->container);
|
|
||||||
$env = Environment::mock([
|
|
||||||
'REQUEST_METHOD' => 'GET',
|
|
||||||
'REQUEST_URI' => '/echo',
|
|
||||||
]);
|
|
||||||
$request = Request::createFromEnvironment($env);
|
|
||||||
$response = new Response();
|
|
||||||
/** @var Response $response */
|
|
||||||
$response = $mw($request, $response, null);
|
|
||||||
|
|
||||||
$this->assertEquals(401, $response->getStatusCode());
|
|
||||||
$body = json_decode((string) $response->getBody());
|
|
||||||
$this->assertEquals('Not authorized: JWT token not provided', $body->message);
|
|
||||||
$this->assertContainsPolyfill('ApiAuthorizationException', $body->stacktrace);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Invoke the middleware without a secret set in settings (debug):
|
|
||||||
* should return a 401 error Unauthorized - with a specific message and a stacktrace.
|
|
||||||
*/
|
|
||||||
public function testInvokeMiddlewareNoSecretSetDebug()
|
|
||||||
{
|
|
||||||
$this->conf->set('dev.debug', true);
|
|
||||||
$this->conf->set('api.secret', '');
|
|
||||||
$mw = new ApiMiddleware($this->container);
|
|
||||||
$env = Environment::mock([
|
|
||||||
'REQUEST_METHOD' => 'GET',
|
|
||||||
'REQUEST_URI' => '/echo',
|
|
||||||
'HTTP_AUTHORIZATION' => 'Bearer jwt',
|
|
||||||
]);
|
|
||||||
$request = Request::createFromEnvironment($env);
|
|
||||||
$response = new Response();
|
|
||||||
/** @var Response $response */
|
|
||||||
$response = $mw($request, $response, null);
|
|
||||||
|
|
||||||
$this->assertEquals(401, $response->getStatusCode());
|
|
||||||
$body = json_decode((string) $response->getBody());
|
|
||||||
$this->assertEquals('Not authorized: Token secret must be set in Shaarli\'s administration', $body->message);
|
|
||||||
$this->assertContainsPolyfill('ApiAuthorizationException', $body->stacktrace);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Invoke the middleware with an invalid JWT token header
|
|
||||||
*/
|
|
||||||
public function testInvalidJwtAuthHeaderDebug()
|
|
||||||
{
|
|
||||||
$this->conf->set('dev.debug', true);
|
|
||||||
$mw = new ApiMiddleware($this->container);
|
|
||||||
$env = Environment::mock([
|
|
||||||
'REQUEST_METHOD' => 'GET',
|
|
||||||
'REQUEST_URI' => '/echo',
|
|
||||||
'HTTP_AUTHORIZATION' => 'PolarBearer jwt',
|
|
||||||
]);
|
|
||||||
$request = Request::createFromEnvironment($env);
|
|
||||||
$response = new Response();
|
|
||||||
/** @var Response $response */
|
|
||||||
$response = $mw($request, $response, null);
|
|
||||||
|
|
||||||
$this->assertEquals(401, $response->getStatusCode());
|
|
||||||
$body = json_decode((string) $response->getBody());
|
|
||||||
$this->assertEquals('Not authorized: Invalid JWT header', $body->message);
|
|
||||||
$this->assertContainsPolyfill('ApiAuthorizationException', $body->stacktrace);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Invoke the middleware with an invalid JWT token (debug):
|
|
||||||
* should return a 401 error Unauthorized - with a specific message and a stacktrace.
|
|
||||||
*
|
|
||||||
* Note: specific JWT errors tests are handled in ApiUtilsTest.
|
|
||||||
*/
|
|
||||||
public function testInvokeMiddlewareInvalidJwtDebug()
|
|
||||||
{
|
|
||||||
$this->conf->set('dev.debug', true);
|
|
||||||
$mw = new ApiMiddleware($this->container);
|
|
||||||
$env = Environment::mock([
|
|
||||||
'REQUEST_METHOD' => 'GET',
|
|
||||||
'REQUEST_URI' => '/echo',
|
|
||||||
'HTTP_AUTHORIZATION' => 'Bearer jwt',
|
|
||||||
]);
|
|
||||||
$request = Request::createFromEnvironment($env);
|
|
||||||
$response = new Response();
|
|
||||||
/** @var Response $response */
|
|
||||||
$response = $mw($request, $response, null);
|
|
||||||
|
|
||||||
$this->assertEquals(401, $response->getStatusCode());
|
|
||||||
$body = json_decode((string) $response->getBody());
|
|
||||||
$this->assertEquals('Not authorized: Malformed JWT token', $body->message);
|
|
||||||
$this->assertContainsPolyfill('ApiAuthorizationException', $body->stacktrace);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,354 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace Shaarli\Api;
|
|
||||||
|
|
||||||
use Shaarli\Bookmark\Bookmark;
|
|
||||||
use Shaarli\Http\Base64Url;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Class ApiUtilsTest
|
|
||||||
*/
|
|
||||||
class ApiUtilsTest extends \Shaarli\TestCase
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Force the timezone for ISO datetimes.
|
|
||||||
*/
|
|
||||||
public static function setUpBeforeClass(): void
|
|
||||||
{
|
|
||||||
date_default_timezone_set('UTC');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generate a valid JWT token.
|
|
||||||
*
|
|
||||||
* @param string $secret API secret used to generate the signature.
|
|
||||||
*
|
|
||||||
* @return string Generated token.
|
|
||||||
*/
|
|
||||||
public static function generateValidJwtToken($secret)
|
|
||||||
{
|
|
||||||
$header = Base64Url::encode('{
|
|
||||||
"typ": "JWT",
|
|
||||||
"alg": "HS512"
|
|
||||||
}');
|
|
||||||
$payload = Base64Url::encode('{
|
|
||||||
"iat": ' . time() . '
|
|
||||||
}');
|
|
||||||
$signature = Base64Url::encode(hash_hmac('sha512', $header . '.' . $payload, $secret, true));
|
|
||||||
return $header . '.' . $payload . '.' . $signature;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generate a JWT token from given header and payload.
|
|
||||||
*
|
|
||||||
* @param string $header Header in JSON format.
|
|
||||||
* @param string $payload Payload in JSON format.
|
|
||||||
* @param string $secret API secret used to hash the signature.
|
|
||||||
*
|
|
||||||
* @return string JWT token.
|
|
||||||
*/
|
|
||||||
public static function generateCustomJwtToken($header, $payload, $secret)
|
|
||||||
{
|
|
||||||
$header = Base64Url::encode($header);
|
|
||||||
$payload = Base64Url::encode($payload);
|
|
||||||
$signature = Base64Url::encode(hash_hmac('sha512', $header . '.' . $payload, $secret, true));
|
|
||||||
return $header . '.' . $payload . '.' . $signature;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test validateJwtToken() with a valid JWT token.
|
|
||||||
*/
|
|
||||||
public function testValidateJwtTokenValid()
|
|
||||||
{
|
|
||||||
$secret = 'WarIsPeace';
|
|
||||||
$this->assertTrue(ApiUtils::validateJwtToken(self::generateValidJwtToken($secret), $secret));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test validateJwtToken() with a malformed JWT token.
|
|
||||||
*/
|
|
||||||
public function testValidateJwtTokenMalformed()
|
|
||||||
{
|
|
||||||
$this->expectException(\Shaarli\Api\Exceptions\ApiAuthorizationException::class);
|
|
||||||
$this->expectExceptionMessage('Malformed JWT token');
|
|
||||||
|
|
||||||
$token = 'ABC.DEF';
|
|
||||||
ApiUtils::validateJwtToken($token, 'foo');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test validateJwtToken() with an empty JWT token.
|
|
||||||
*/
|
|
||||||
public function testValidateJwtTokenMalformedEmpty()
|
|
||||||
{
|
|
||||||
$this->expectException(\Shaarli\Api\Exceptions\ApiAuthorizationException::class);
|
|
||||||
$this->expectExceptionMessage('Malformed JWT token');
|
|
||||||
|
|
||||||
$token = false;
|
|
||||||
ApiUtils::validateJwtToken($token, 'foo');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test validateJwtToken() with a JWT token without header.
|
|
||||||
*/
|
|
||||||
public function testValidateJwtTokenMalformedEmptyHeader()
|
|
||||||
{
|
|
||||||
$this->expectException(\Shaarli\Api\Exceptions\ApiAuthorizationException::class);
|
|
||||||
$this->expectExceptionMessage('Malformed JWT token');
|
|
||||||
|
|
||||||
$token = '.payload.signature';
|
|
||||||
ApiUtils::validateJwtToken($token, 'foo');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test validateJwtToken() with a JWT token without payload
|
|
||||||
*/
|
|
||||||
public function testValidateJwtTokenMalformedEmptyPayload()
|
|
||||||
{
|
|
||||||
$this->expectException(\Shaarli\Api\Exceptions\ApiAuthorizationException::class);
|
|
||||||
$this->expectExceptionMessage('Malformed JWT token');
|
|
||||||
|
|
||||||
$token = 'header..signature';
|
|
||||||
ApiUtils::validateJwtToken($token, 'foo');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test validateJwtToken() with a JWT token with an empty signature.
|
|
||||||
*/
|
|
||||||
public function testValidateJwtTokenInvalidSignatureEmpty()
|
|
||||||
{
|
|
||||||
$this->expectException(\Shaarli\Api\Exceptions\ApiAuthorizationException::class);
|
|
||||||
$this->expectExceptionMessage('Invalid JWT signature');
|
|
||||||
|
|
||||||
$token = 'header.payload.';
|
|
||||||
ApiUtils::validateJwtToken($token, 'foo');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test validateJwtToken() with a JWT token with an invalid signature.
|
|
||||||
*/
|
|
||||||
public function testValidateJwtTokenInvalidSignature()
|
|
||||||
{
|
|
||||||
$this->expectException(\Shaarli\Api\Exceptions\ApiAuthorizationException::class);
|
|
||||||
$this->expectExceptionMessage('Invalid JWT signature');
|
|
||||||
|
|
||||||
$token = 'header.payload.nope';
|
|
||||||
ApiUtils::validateJwtToken($token, 'foo');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test validateJwtToken() with a JWT token with a signature generated with the wrong API secret.
|
|
||||||
*/
|
|
||||||
public function testValidateJwtTokenInvalidSignatureSecret()
|
|
||||||
{
|
|
||||||
$this->expectException(\Shaarli\Api\Exceptions\ApiAuthorizationException::class);
|
|
||||||
$this->expectExceptionMessage('Invalid JWT signature');
|
|
||||||
|
|
||||||
ApiUtils::validateJwtToken(self::generateValidJwtToken('foo'), 'bar');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test validateJwtToken() with a JWT token with a an invalid header (not JSON).
|
|
||||||
*/
|
|
||||||
public function testValidateJwtTokenInvalidHeader()
|
|
||||||
{
|
|
||||||
$this->expectException(\Shaarli\Api\Exceptions\ApiAuthorizationException::class);
|
|
||||||
$this->expectExceptionMessage('Invalid JWT header');
|
|
||||||
|
|
||||||
$token = $this->generateCustomJwtToken('notJSON', '{"JSON":1}', 'secret');
|
|
||||||
ApiUtils::validateJwtToken($token, 'secret');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test validateJwtToken() with a JWT token with a an invalid payload (not JSON).
|
|
||||||
*/
|
|
||||||
public function testValidateJwtTokenInvalidPayload()
|
|
||||||
{
|
|
||||||
$this->expectException(\Shaarli\Api\Exceptions\ApiAuthorizationException::class);
|
|
||||||
$this->expectExceptionMessage('Invalid JWT payload');
|
|
||||||
|
|
||||||
$token = $this->generateCustomJwtToken('{"JSON":1}', 'notJSON', 'secret');
|
|
||||||
ApiUtils::validateJwtToken($token, 'secret');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test validateJwtToken() with a JWT token without issued time.
|
|
||||||
*/
|
|
||||||
public function testValidateJwtTokenInvalidTimeEmpty()
|
|
||||||
{
|
|
||||||
$this->expectException(\Shaarli\Api\Exceptions\ApiAuthorizationException::class);
|
|
||||||
$this->expectExceptionMessage('Invalid JWT issued time');
|
|
||||||
|
|
||||||
$token = $this->generateCustomJwtToken('{"JSON":1}', '{"JSON":1}', 'secret');
|
|
||||||
ApiUtils::validateJwtToken($token, 'secret');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test validateJwtToken() with an expired JWT token.
|
|
||||||
*/
|
|
||||||
public function testValidateJwtTokenInvalidTimeExpired()
|
|
||||||
{
|
|
||||||
$this->expectException(\Shaarli\Api\Exceptions\ApiAuthorizationException::class);
|
|
||||||
$this->expectExceptionMessage('Invalid JWT issued time');
|
|
||||||
|
|
||||||
$token = $this->generateCustomJwtToken('{"JSON":1}', '{"iat":' . (time() - 600) . '}', 'secret');
|
|
||||||
ApiUtils::validateJwtToken($token, 'secret');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test validateJwtToken() with a JWT token issued in the future.
|
|
||||||
*/
|
|
||||||
public function testValidateJwtTokenInvalidTimeFuture()
|
|
||||||
{
|
|
||||||
$this->expectException(\Shaarli\Api\Exceptions\ApiAuthorizationException::class);
|
|
||||||
$this->expectExceptionMessage('Invalid JWT issued time');
|
|
||||||
|
|
||||||
$token = $this->generateCustomJwtToken('{"JSON":1}', '{"iat":' . (time() + 60) . '}', 'secret');
|
|
||||||
ApiUtils::validateJwtToken($token, 'secret');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test formatLink() with a link using all useful fields.
|
|
||||||
*/
|
|
||||||
public function testFormatLinkComplete()
|
|
||||||
{
|
|
||||||
$indexUrl = 'https://domain.tld/sub/';
|
|
||||||
$data = [
|
|
||||||
'id' => 12,
|
|
||||||
'url' => 'http://lol.lol',
|
|
||||||
'shorturl' => 'abc',
|
|
||||||
'title' => 'Important Title',
|
|
||||||
'description' => 'It is very lol<tag>' . PHP_EOL . 'new line',
|
|
||||||
'tags' => 'blip .blop ',
|
|
||||||
'private' => '1',
|
|
||||||
'created' => \DateTime::createFromFormat('Ymd_His', '20170107_160102'),
|
|
||||||
'updated' => \DateTime::createFromFormat('Ymd_His', '20170107_160612'),
|
|
||||||
];
|
|
||||||
$bookmark = new Bookmark();
|
|
||||||
$bookmark->fromArray($data);
|
|
||||||
|
|
||||||
$expected = [
|
|
||||||
'id' => 12,
|
|
||||||
'url' => 'http://lol.lol',
|
|
||||||
'shorturl' => 'abc',
|
|
||||||
'title' => 'Important Title',
|
|
||||||
'description' => 'It is very lol<tag>' . PHP_EOL . 'new line',
|
|
||||||
'tags' => ['blip', '.blop'],
|
|
||||||
'private' => true,
|
|
||||||
'created' => '2017-01-07T16:01:02+00:00',
|
|
||||||
'updated' => '2017-01-07T16:06:12+00:00',
|
|
||||||
];
|
|
||||||
|
|
||||||
$this->assertEquals($expected, ApiUtils::formatLink($bookmark, $indexUrl));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test formatLink() with only minimal fields filled, and internal link.
|
|
||||||
*/
|
|
||||||
public function testFormatLinkMinimalNote()
|
|
||||||
{
|
|
||||||
$indexUrl = 'https://domain.tld/sub/';
|
|
||||||
$data = [
|
|
||||||
'id' => 12,
|
|
||||||
'url' => '?abc',
|
|
||||||
'shorturl' => 'abc',
|
|
||||||
'title' => 'Note',
|
|
||||||
'description' => '',
|
|
||||||
'tags' => '',
|
|
||||||
'private' => '',
|
|
||||||
'created' => \DateTime::createFromFormat('Ymd_His', '20170107_160102'),
|
|
||||||
];
|
|
||||||
$bookmark = new Bookmark();
|
|
||||||
$bookmark->fromArray($data);
|
|
||||||
|
|
||||||
$expected = [
|
|
||||||
'id' => 12,
|
|
||||||
'url' => 'https://domain.tld/sub/?abc',
|
|
||||||
'shorturl' => 'abc',
|
|
||||||
'title' => 'Note',
|
|
||||||
'description' => '',
|
|
||||||
'tags' => [],
|
|
||||||
'private' => false,
|
|
||||||
'created' => '2017-01-07T16:01:02+00:00',
|
|
||||||
'updated' => '',
|
|
||||||
];
|
|
||||||
|
|
||||||
$this->assertEquals($expected, ApiUtils::formatLink($bookmark, $indexUrl));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test updateLink with valid data, and also unnecessary fields.
|
|
||||||
*/
|
|
||||||
public function testUpdateLink()
|
|
||||||
{
|
|
||||||
$created = \DateTime::createFromFormat('Ymd_His', '20170107_160102');
|
|
||||||
$data = [
|
|
||||||
'id' => 12,
|
|
||||||
'url' => '?abc',
|
|
||||||
'shorturl' => 'abc',
|
|
||||||
'title' => 'Note',
|
|
||||||
'description' => '',
|
|
||||||
'tags' => '',
|
|
||||||
'private' => '',
|
|
||||||
'created' => $created,
|
|
||||||
];
|
|
||||||
$old = new Bookmark();
|
|
||||||
$old->fromArray($data);
|
|
||||||
|
|
||||||
$data = [
|
|
||||||
'id' => 13,
|
|
||||||
'shorturl' => 'nope',
|
|
||||||
'url' => 'http://somewhere.else',
|
|
||||||
'title' => 'Le Cid',
|
|
||||||
'description' => 'Percé jusques au fond du cœur [...]',
|
|
||||||
'tags' => 'corneille rodrigue',
|
|
||||||
'private' => true,
|
|
||||||
'created' => 'creation',
|
|
||||||
'updated' => 'updation',
|
|
||||||
];
|
|
||||||
$new = new Bookmark();
|
|
||||||
$new->fromArray($data);
|
|
||||||
|
|
||||||
$result = ApiUtils::updateLink($old, $new);
|
|
||||||
$this->assertEquals(12, $result->getId());
|
|
||||||
$this->assertEquals('http://somewhere.else', $result->getUrl());
|
|
||||||
$this->assertEquals('abc', $result->getShortUrl());
|
|
||||||
$this->assertEquals('Le Cid', $result->getTitle());
|
|
||||||
$this->assertEquals('Percé jusques au fond du cœur [...]', $result->getDescription());
|
|
||||||
$this->assertEquals('corneille rodrigue', $result->getTagsString());
|
|
||||||
$this->assertEquals(true, $result->isPrivate());
|
|
||||||
$this->assertEquals($created, $result->getCreated());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test updateLink with minimal data.
|
|
||||||
*/
|
|
||||||
public function testUpdateLinkMinimal()
|
|
||||||
{
|
|
||||||
$created = \DateTime::createFromFormat('Ymd_His', '20170107_160102');
|
|
||||||
$data = [
|
|
||||||
'id' => 12,
|
|
||||||
'url' => '?abc',
|
|
||||||
'shorturl' => 'abc',
|
|
||||||
'title' => 'Note',
|
|
||||||
'description' => 'Interesting description!',
|
|
||||||
'tags' => 'doggo',
|
|
||||||
'private' => true,
|
|
||||||
'created' => $created,
|
|
||||||
];
|
|
||||||
$old = new Bookmark();
|
|
||||||
$old->fromArray($data);
|
|
||||||
|
|
||||||
$new = new Bookmark();
|
|
||||||
|
|
||||||
$result = ApiUtils::updateLink($old, $new);
|
|
||||||
$this->assertEquals(12, $result->getId());
|
|
||||||
$this->assertEquals('', $result->getUrl());
|
|
||||||
$this->assertEquals('abc', $result->getShortUrl());
|
|
||||||
$this->assertEquals('', $result->getTitle());
|
|
||||||
$this->assertEquals('', $result->getDescription());
|
|
||||||
$this->assertEquals('', $result->getTagsString());
|
|
||||||
$this->assertEquals(false, $result->isPrivate());
|
|
||||||
$this->assertEquals($created, $result->getCreated());
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,215 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace Shaarli\Api\Controllers;
|
|
||||||
|
|
||||||
use Shaarli\Config\ConfigManager;
|
|
||||||
use Shaarli\History;
|
|
||||||
use Shaarli\TestCase;
|
|
||||||
use Shaarli\Tests\Utils\ReferenceHistory;
|
|
||||||
use Slim\Container;
|
|
||||||
use Slim\Http\Environment;
|
|
||||||
use Slim\Http\Request;
|
|
||||||
use Slim\Http\Response;
|
|
||||||
|
|
||||||
class HistoryTest extends TestCase
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @var string datastore to test write operations
|
|
||||||
*/
|
|
||||||
protected static $testHistory = 'sandbox/history.php';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var ConfigManager instance
|
|
||||||
*/
|
|
||||||
protected $conf;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var ReferenceHistory instance.
|
|
||||||
*/
|
|
||||||
protected $refHistory = null;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var Container instance.
|
|
||||||
*/
|
|
||||||
protected $container;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var HistoryController controller instance.
|
|
||||||
*/
|
|
||||||
protected $controller;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Before every test, instantiate a new Api with its config, plugins and bookmarks.
|
|
||||||
*/
|
|
||||||
protected function setUp(): void
|
|
||||||
{
|
|
||||||
$this->conf = new ConfigManager('tests/utils/config/configJson');
|
|
||||||
$this->refHistory = new ReferenceHistory();
|
|
||||||
$this->refHistory->write(self::$testHistory);
|
|
||||||
$this->container = new Container();
|
|
||||||
$this->container['conf'] = $this->conf;
|
|
||||||
$this->container['db'] = true;
|
|
||||||
$this->container['history'] = new History(self::$testHistory);
|
|
||||||
|
|
||||||
$this->controller = new HistoryController($this->container);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* After every test, remove the test datastore.
|
|
||||||
*/
|
|
||||||
protected function tearDown(): void
|
|
||||||
{
|
|
||||||
@unlink(self::$testHistory);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test /history service without parameter.
|
|
||||||
*/
|
|
||||||
public function testGetHistory()
|
|
||||||
{
|
|
||||||
$env = Environment::mock([
|
|
||||||
'REQUEST_METHOD' => 'GET',
|
|
||||||
]);
|
|
||||||
$request = Request::createFromEnvironment($env);
|
|
||||||
|
|
||||||
$response = $this->controller->getHistory($request, new Response());
|
|
||||||
$this->assertEquals(200, $response->getStatusCode());
|
|
||||||
$data = json_decode((string) $response->getBody(), true);
|
|
||||||
|
|
||||||
$this->assertEquals($this->refHistory->count(), count($data));
|
|
||||||
|
|
||||||
$this->assertEquals(History::DELETED, $data[0]['event']);
|
|
||||||
$this->assertEquals(
|
|
||||||
\DateTime::createFromFormat('Ymd_His', '20170303_121216')->format(\DateTime::ATOM),
|
|
||||||
$data[0]['datetime']
|
|
||||||
);
|
|
||||||
$this->assertEquals(124, $data[0]['id']);
|
|
||||||
|
|
||||||
$this->assertEquals(History::SETTINGS, $data[1]['event']);
|
|
||||||
$this->assertEquals(
|
|
||||||
\DateTime::createFromFormat('Ymd_His', '20170302_121215')->format(\DateTime::ATOM),
|
|
||||||
$data[1]['datetime']
|
|
||||||
);
|
|
||||||
$this->assertNull($data[1]['id']);
|
|
||||||
|
|
||||||
$this->assertEquals(History::UPDATED, $data[2]['event']);
|
|
||||||
$this->assertEquals(
|
|
||||||
\DateTime::createFromFormat('Ymd_His', '20170301_121214')->format(\DateTime::ATOM),
|
|
||||||
$data[2]['datetime']
|
|
||||||
);
|
|
||||||
$this->assertEquals(123, $data[2]['id']);
|
|
||||||
|
|
||||||
$this->assertEquals(History::CREATED, $data[3]['event']);
|
|
||||||
$this->assertEquals(
|
|
||||||
\DateTime::createFromFormat('Ymd_His', '20170201_121214')->format(\DateTime::ATOM),
|
|
||||||
$data[3]['datetime']
|
|
||||||
);
|
|
||||||
$this->assertEquals(124, $data[3]['id']);
|
|
||||||
|
|
||||||
$this->assertEquals(History::CREATED, $data[4]['event']);
|
|
||||||
$this->assertEquals(
|
|
||||||
\DateTime::createFromFormat('Ymd_His', '20170101_121212')->format(\DateTime::ATOM),
|
|
||||||
$data[4]['datetime']
|
|
||||||
);
|
|
||||||
$this->assertEquals(123, $data[4]['id']);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test /history service with limit parameter.
|
|
||||||
*/
|
|
||||||
public function testGetHistoryLimit()
|
|
||||||
{
|
|
||||||
$env = Environment::mock([
|
|
||||||
'REQUEST_METHOD' => 'GET',
|
|
||||||
'QUERY_STRING' => 'limit=1'
|
|
||||||
]);
|
|
||||||
$request = Request::createFromEnvironment($env);
|
|
||||||
|
|
||||||
$response = $this->controller->getHistory($request, new Response());
|
|
||||||
$this->assertEquals(200, $response->getStatusCode());
|
|
||||||
$data = json_decode((string) $response->getBody(), true);
|
|
||||||
|
|
||||||
$this->assertEquals(1, count($data));
|
|
||||||
|
|
||||||
$this->assertEquals(History::DELETED, $data[0]['event']);
|
|
||||||
$this->assertEquals(
|
|
||||||
\DateTime::createFromFormat('Ymd_His', '20170303_121216')->format(\DateTime::ATOM),
|
|
||||||
$data[0]['datetime']
|
|
||||||
);
|
|
||||||
$this->assertEquals(124, $data[0]['id']);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test /history service with offset parameter.
|
|
||||||
*/
|
|
||||||
public function testGetHistoryOffset()
|
|
||||||
{
|
|
||||||
$env = Environment::mock([
|
|
||||||
'REQUEST_METHOD' => 'GET',
|
|
||||||
'QUERY_STRING' => 'offset=4'
|
|
||||||
]);
|
|
||||||
$request = Request::createFromEnvironment($env);
|
|
||||||
|
|
||||||
$response = $this->controller->getHistory($request, new Response());
|
|
||||||
$this->assertEquals(200, $response->getStatusCode());
|
|
||||||
$data = json_decode((string) $response->getBody(), true);
|
|
||||||
|
|
||||||
$this->assertEquals(1, count($data));
|
|
||||||
|
|
||||||
$this->assertEquals(History::CREATED, $data[0]['event']);
|
|
||||||
$this->assertEquals(
|
|
||||||
\DateTime::createFromFormat('Ymd_His', '20170101_121212')->format(\DateTime::ATOM),
|
|
||||||
$data[0]['datetime']
|
|
||||||
);
|
|
||||||
$this->assertEquals(123, $data[0]['id']);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test /history service with since parameter.
|
|
||||||
*/
|
|
||||||
public function testGetHistorySince()
|
|
||||||
{
|
|
||||||
$env = Environment::mock([
|
|
||||||
'REQUEST_METHOD' => 'GET',
|
|
||||||
'QUERY_STRING' => 'since=2017-03-03T00:00:00%2B00:00'
|
|
||||||
]);
|
|
||||||
$request = Request::createFromEnvironment($env);
|
|
||||||
|
|
||||||
$response = $this->controller->getHistory($request, new Response());
|
|
||||||
$this->assertEquals(200, $response->getStatusCode());
|
|
||||||
$data = json_decode((string) $response->getBody(), true);
|
|
||||||
|
|
||||||
$this->assertEquals(1, count($data));
|
|
||||||
|
|
||||||
$this->assertEquals(History::DELETED, $data[0]['event']);
|
|
||||||
$this->assertEquals(
|
|
||||||
\DateTime::createFromFormat('Ymd_His', '20170303_121216')->format(\DateTime::ATOM),
|
|
||||||
$data[0]['datetime']
|
|
||||||
);
|
|
||||||
$this->assertEquals(124, $data[0]['id']);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test /history service with since parameter.
|
|
||||||
*/
|
|
||||||
public function testGetHistorySinceOffsetLimit()
|
|
||||||
{
|
|
||||||
$env = Environment::mock([
|
|
||||||
'REQUEST_METHOD' => 'GET',
|
|
||||||
'QUERY_STRING' => 'since=2017-02-01T00:00:00%2B00:00&offset=1&limit=1'
|
|
||||||
]);
|
|
||||||
$request = Request::createFromEnvironment($env);
|
|
||||||
|
|
||||||
$response = $this->controller->getHistory($request, new Response());
|
|
||||||
$this->assertEquals(200, $response->getStatusCode());
|
|
||||||
$data = json_decode((string) $response->getBody(), true);
|
|
||||||
|
|
||||||
$this->assertEquals(1, count($data));
|
|
||||||
|
|
||||||
$this->assertEquals(History::SETTINGS, $data[0]['event']);
|
|
||||||
$this->assertEquals(
|
|
||||||
\DateTime::createFromFormat('Ymd_His', '20170302_121215')->format(\DateTime::ATOM),
|
|
||||||
$data[0]['datetime']
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,131 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace Shaarli\Api\Controllers;
|
|
||||||
|
|
||||||
use malkusch\lock\mutex\NoMutex;
|
|
||||||
use Shaarli\Bookmark\BookmarkFileService;
|
|
||||||
use Shaarli\Config\ConfigManager;
|
|
||||||
use Shaarli\History;
|
|
||||||
use Shaarli\Plugin\PluginManager;
|
|
||||||
use Shaarli\TestCase;
|
|
||||||
use Shaarli\Tests\Utils\ReferenceLinkDB;
|
|
||||||
use Slim\Container;
|
|
||||||
use Slim\Http\Environment;
|
|
||||||
use Slim\Http\Request;
|
|
||||||
use Slim\Http\Response;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Class InfoTest
|
|
||||||
*
|
|
||||||
* Test REST API controller Info.
|
|
||||||
*
|
|
||||||
* @package Api\Controllers
|
|
||||||
*/
|
|
||||||
class InfoTest extends TestCase
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @var string datastore to test write operations
|
|
||||||
*/
|
|
||||||
protected static $testDatastore = 'sandbox/datastore.php';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var ConfigManager instance
|
|
||||||
*/
|
|
||||||
protected $conf;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var ReferenceLinkDB instance.
|
|
||||||
*/
|
|
||||||
protected $refDB = null;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var Container instance.
|
|
||||||
*/
|
|
||||||
protected $container;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var Info controller instance.
|
|
||||||
*/
|
|
||||||
protected $controller;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Before every test, instantiate a new Api with its config, plugins and bookmarks.
|
|
||||||
*/
|
|
||||||
protected function setUp(): void
|
|
||||||
{
|
|
||||||
$mutex = new NoMutex();
|
|
||||||
$this->conf = new ConfigManager('tests/utils/config/configJson');
|
|
||||||
$this->conf->set('resource.datastore', self::$testDatastore);
|
|
||||||
$this->refDB = new ReferenceLinkDB();
|
|
||||||
$this->refDB->write(self::$testDatastore);
|
|
||||||
$this->pluginManager = new PluginManager($this->conf);
|
|
||||||
$history = new History('sandbox/history.php');
|
|
||||||
|
|
||||||
$this->container = new Container();
|
|
||||||
$this->container['conf'] = $this->conf;
|
|
||||||
$this->container['db'] = new BookmarkFileService(
|
|
||||||
$this->conf,
|
|
||||||
$this->pluginManager,
|
|
||||||
$history,
|
|
||||||
$mutex,
|
|
||||||
true
|
|
||||||
);
|
|
||||||
$this->container['history'] = null;
|
|
||||||
|
|
||||||
$this->controller = new Info($this->container);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* After every test, remove the test datastore.
|
|
||||||
*/
|
|
||||||
protected function tearDown(): void
|
|
||||||
{
|
|
||||||
@unlink(self::$testDatastore);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test /info service.
|
|
||||||
*/
|
|
||||||
public function testGetInfo()
|
|
||||||
{
|
|
||||||
$env = Environment::mock([
|
|
||||||
'REQUEST_METHOD' => 'GET',
|
|
||||||
]);
|
|
||||||
$request = Request::createFromEnvironment($env);
|
|
||||||
|
|
||||||
$response = $this->controller->getInfo($request, new Response());
|
|
||||||
$this->assertEquals(200, $response->getStatusCode());
|
|
||||||
$data = json_decode((string) $response->getBody(), true);
|
|
||||||
|
|
||||||
$this->assertEquals(ReferenceLinkDB::$NB_LINKS_TOTAL, $data['global_counter']);
|
|
||||||
$this->assertEquals(2, $data['private_counter']);
|
|
||||||
$this->assertEquals('Shaarli', $data['settings']['title']);
|
|
||||||
$this->assertEquals('?', $data['settings']['header_link']);
|
|
||||||
$this->assertEquals('Europe/Paris', $data['settings']['timezone']);
|
|
||||||
$this->assertEquals(ConfigManager::$DEFAULT_PLUGINS, $data['settings']['enabled_plugins']);
|
|
||||||
$this->assertEquals(true, $data['settings']['default_private_links']);
|
|
||||||
|
|
||||||
$title = 'My bookmarks';
|
|
||||||
$headerLink = 'http://shaarli.tld';
|
|
||||||
$timezone = 'Europe/Paris';
|
|
||||||
$enabledPlugins = ['foo', 'bar'];
|
|
||||||
$defaultPrivateLinks = true;
|
|
||||||
$this->conf->set('general.title', $title);
|
|
||||||
$this->conf->set('general.header_link', $headerLink);
|
|
||||||
$this->conf->set('general.timezone', $timezone);
|
|
||||||
$this->conf->set('general.enabled_plugins', $enabledPlugins);
|
|
||||||
$this->conf->set('privacy.default_private_links', $defaultPrivateLinks);
|
|
||||||
|
|
||||||
$response = $this->controller->getInfo($request, new Response());
|
|
||||||
$this->assertEquals(200, $response->getStatusCode());
|
|
||||||
$data = json_decode((string) $response->getBody(), true);
|
|
||||||
|
|
||||||
$this->assertEquals(ReferenceLinkDB::$NB_LINKS_TOTAL, $data['global_counter']);
|
|
||||||
$this->assertEquals(2, $data['private_counter']);
|
|
||||||
$this->assertEquals($title, $data['settings']['title']);
|
|
||||||
$this->assertEquals($headerLink, $data['settings']['header_link']);
|
|
||||||
$this->assertEquals($timezone, $data['settings']['timezone']);
|
|
||||||
$this->assertEquals($enabledPlugins, $data['settings']['enabled_plugins']);
|
|
||||||
$this->assertEquals($defaultPrivateLinks, $data['settings']['default_private_links']);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,153 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace Shaarli\Api\Controllers;
|
|
||||||
|
|
||||||
use malkusch\lock\mutex\NoMutex;
|
|
||||||
use Shaarli\Bookmark\BookmarkFileService;
|
|
||||||
use Shaarli\Config\ConfigManager;
|
|
||||||
use Shaarli\History;
|
|
||||||
use Shaarli\Plugin\PluginManager;
|
|
||||||
use Shaarli\Tests\Utils\ReferenceHistory;
|
|
||||||
use Shaarli\Tests\Utils\ReferenceLinkDB;
|
|
||||||
use Slim\Container;
|
|
||||||
use Slim\Http\Environment;
|
|
||||||
use Slim\Http\Request;
|
|
||||||
use Slim\Http\Response;
|
|
||||||
|
|
||||||
class DeleteLinkTest extends \Shaarli\TestCase
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @var string datastore to test write operations
|
|
||||||
*/
|
|
||||||
protected static $testDatastore = 'sandbox/datastore.php';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var string datastore to test write operations
|
|
||||||
*/
|
|
||||||
protected static $testHistory = 'sandbox/history.php';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var ConfigManager instance
|
|
||||||
*/
|
|
||||||
protected $conf;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var ReferenceLinkDB instance.
|
|
||||||
*/
|
|
||||||
protected $refDB = null;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var BookmarkFileService instance.
|
|
||||||
*/
|
|
||||||
protected $bookmarkService;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var HistoryController instance.
|
|
||||||
*/
|
|
||||||
protected $history;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var Container instance.
|
|
||||||
*/
|
|
||||||
protected $container;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var Links controller instance.
|
|
||||||
*/
|
|
||||||
protected $controller;
|
|
||||||
|
|
||||||
/** @var NoMutex */
|
|
||||||
protected $mutex;
|
|
||||||
|
|
||||||
/** @var PluginManager */
|
|
||||||
protected $pluginManager;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Before each test, instantiate a new Api with its config, plugins and bookmarks.
|
|
||||||
*/
|
|
||||||
protected function setUp(): void
|
|
||||||
{
|
|
||||||
$this->mutex = new NoMutex();
|
|
||||||
$this->conf = new ConfigManager('tests/utils/config/configJson');
|
|
||||||
$this->conf->set('resource.datastore', self::$testDatastore);
|
|
||||||
$this->refDB = new ReferenceLinkDB();
|
|
||||||
$this->refDB->write(self::$testDatastore);
|
|
||||||
$refHistory = new ReferenceHistory();
|
|
||||||
$refHistory->write(self::$testHistory);
|
|
||||||
$this->history = new History(self::$testHistory);
|
|
||||||
$this->pluginManager = new PluginManager($this->conf);
|
|
||||||
$this->bookmarkService = new BookmarkFileService(
|
|
||||||
$this->conf,
|
|
||||||
$this->pluginManager,
|
|
||||||
$this->history,
|
|
||||||
$this->mutex,
|
|
||||||
true
|
|
||||||
);
|
|
||||||
|
|
||||||
$this->container = new Container();
|
|
||||||
$this->container['conf'] = $this->conf;
|
|
||||||
$this->container['db'] = $this->bookmarkService;
|
|
||||||
$this->container['history'] = $this->history;
|
|
||||||
|
|
||||||
$this->controller = new Links($this->container);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* After each test, remove the test datastore.
|
|
||||||
*/
|
|
||||||
protected function tearDown(): void
|
|
||||||
{
|
|
||||||
@unlink(self::$testDatastore);
|
|
||||||
@unlink(self::$testHistory);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test DELETE link endpoint: the link should be removed.
|
|
||||||
*/
|
|
||||||
public function testDeleteLinkValid()
|
|
||||||
{
|
|
||||||
$id = '41';
|
|
||||||
$this->assertTrue($this->bookmarkService->exists($id));
|
|
||||||
$env = Environment::mock([
|
|
||||||
'REQUEST_METHOD' => 'DELETE',
|
|
||||||
]);
|
|
||||||
$request = Request::createFromEnvironment($env);
|
|
||||||
|
|
||||||
$response = $this->controller->deleteLink($request, new Response(), ['id' => $id]);
|
|
||||||
$this->assertEquals(204, $response->getStatusCode());
|
|
||||||
$this->assertEmpty((string) $response->getBody());
|
|
||||||
|
|
||||||
$this->bookmarkService = new BookmarkFileService(
|
|
||||||
$this->conf,
|
|
||||||
$this->pluginManager,
|
|
||||||
$this->history,
|
|
||||||
$this->mutex,
|
|
||||||
true
|
|
||||||
);
|
|
||||||
$this->assertFalse($this->bookmarkService->exists($id));
|
|
||||||
|
|
||||||
$historyEntry = $this->history->getHistory()[0];
|
|
||||||
$this->assertEquals(History::DELETED, $historyEntry['event']);
|
|
||||||
$this->assertTrue(
|
|
||||||
(new \DateTime())->add(\DateInterval::createFromDateString('-5 seconds')) < $historyEntry['datetime']
|
|
||||||
);
|
|
||||||
$this->assertEquals($id, $historyEntry['id']);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test DELETE link endpoint: reach not existing ID.
|
|
||||||
*/
|
|
||||||
public function testDeleteLink404()
|
|
||||||
{
|
|
||||||
$this->expectException(\Shaarli\Api\Exceptions\ApiLinkNotFoundException::class);
|
|
||||||
|
|
||||||
$id = -1;
|
|
||||||
$this->assertFalse($this->bookmarkService->exists($id));
|
|
||||||
$env = Environment::mock([
|
|
||||||
'REQUEST_METHOD' => 'DELETE',
|
|
||||||
]);
|
|
||||||
$request = Request::createFromEnvironment($env);
|
|
||||||
|
|
||||||
$this->controller->deleteLink($request, new Response(), ['id' => $id]);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,147 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace Shaarli\Api\Controllers;
|
|
||||||
|
|
||||||
use malkusch\lock\mutex\NoMutex;
|
|
||||||
use Shaarli\Bookmark\Bookmark;
|
|
||||||
use Shaarli\Bookmark\BookmarkFileService;
|
|
||||||
use Shaarli\Config\ConfigManager;
|
|
||||||
use Shaarli\History;
|
|
||||||
use Shaarli\Plugin\PluginManager;
|
|
||||||
use Shaarli\Tests\Utils\ReferenceLinkDB;
|
|
||||||
use Slim\Container;
|
|
||||||
use Slim\Http\Environment;
|
|
||||||
use Slim\Http\Request;
|
|
||||||
use Slim\Http\Response;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Class GetLinkIdTest
|
|
||||||
*
|
|
||||||
* Test getLink by ID API service.
|
|
||||||
*
|
|
||||||
* @see http://shaarli.github.io/api-documentation/#links-link-get
|
|
||||||
*
|
|
||||||
* @package Shaarli\Api\Controllers
|
|
||||||
*/
|
|
||||||
class GetLinkIdTest extends \Shaarli\TestCase
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @var string datastore to test write operations
|
|
||||||
*/
|
|
||||||
protected static $testDatastore = 'sandbox/datastore.php';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var ConfigManager instance
|
|
||||||
*/
|
|
||||||
protected $conf;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var ReferenceLinkDB instance.
|
|
||||||
*/
|
|
||||||
protected $refDB = null;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var Container instance.
|
|
||||||
*/
|
|
||||||
protected $container;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var Links controller instance.
|
|
||||||
*/
|
|
||||||
protected $controller;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Number of JSON fields per link.
|
|
||||||
*/
|
|
||||||
protected const NB_FIELDS_LINK = 9;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Before each test, instantiate a new Api with its config, plugins and bookmarks.
|
|
||||||
*/
|
|
||||||
protected function setUp(): void
|
|
||||||
{
|
|
||||||
$mutex = new NoMutex();
|
|
||||||
$this->conf = new ConfigManager('tests/utils/config/configJson');
|
|
||||||
$this->conf->set('resource.datastore', self::$testDatastore);
|
|
||||||
$this->refDB = new ReferenceLinkDB();
|
|
||||||
$this->refDB->write(self::$testDatastore);
|
|
||||||
$history = new History('sandbox/history.php');
|
|
||||||
|
|
||||||
$this->container = new Container();
|
|
||||||
$this->container['conf'] = $this->conf;
|
|
||||||
$pluginManager = new PluginManager($this->conf);
|
|
||||||
$this->container['db'] = new BookmarkFileService(
|
|
||||||
$this->conf,
|
|
||||||
$pluginManager,
|
|
||||||
$history,
|
|
||||||
$mutex,
|
|
||||||
true
|
|
||||||
);
|
|
||||||
$this->container['history'] = null;
|
|
||||||
|
|
||||||
$this->controller = new Links($this->container);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* After each test, remove the test datastore.
|
|
||||||
*/
|
|
||||||
protected function tearDown(): void
|
|
||||||
{
|
|
||||||
@unlink(self::$testDatastore);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test basic getLink service: return link ID=41.
|
|
||||||
*/
|
|
||||||
public function testGetLinkId()
|
|
||||||
{
|
|
||||||
// Used by index_url().
|
|
||||||
$_SERVER['SERVER_NAME'] = 'domain.tld';
|
|
||||||
$_SERVER['SERVER_PORT'] = 80;
|
|
||||||
$_SERVER['SCRIPT_NAME'] = '/';
|
|
||||||
|
|
||||||
$id = 41;
|
|
||||||
$env = Environment::mock([
|
|
||||||
'REQUEST_METHOD' => 'GET',
|
|
||||||
]);
|
|
||||||
$request = Request::createFromEnvironment($env);
|
|
||||||
|
|
||||||
$response = $this->controller->getLink($request, new Response(), ['id' => $id]);
|
|
||||||
$this->assertEquals(200, $response->getStatusCode());
|
|
||||||
$data = json_decode((string) $response->getBody(), true);
|
|
||||||
$this->assertEquals(self::NB_FIELDS_LINK, count($data));
|
|
||||||
$this->assertEquals($id, $data['id']);
|
|
||||||
|
|
||||||
// Check link elements
|
|
||||||
$this->assertEquals('http://domain.tld/shaare/WDWyig', $data['url']);
|
|
||||||
$this->assertEquals('WDWyig', $data['shorturl']);
|
|
||||||
$this->assertEquals('Link title: @website', $data['title']);
|
|
||||||
$this->assertEquals(
|
|
||||||
'Stallman has a beard and is part of the Free Software Foundation (or not). Seriously, read this. #hashtag',
|
|
||||||
$data['description']
|
|
||||||
);
|
|
||||||
$this->assertEquals('sTuff', $data['tags'][0]);
|
|
||||||
$this->assertEquals(false, $data['private']);
|
|
||||||
$this->assertEquals(
|
|
||||||
\DateTime::createFromFormat(Bookmark::LINK_DATE_FORMAT, '20150310_114651')->format(\DateTime::ATOM),
|
|
||||||
$data['created']
|
|
||||||
);
|
|
||||||
$this->assertEmpty($data['updated']);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test basic getLink service: get non existent link => ApiLinkNotFoundException.
|
|
||||||
*/
|
|
||||||
public function testGetLink404()
|
|
||||||
{
|
|
||||||
$this->expectException(\Shaarli\Api\Exceptions\ApiLinkNotFoundException::class);
|
|
||||||
$this->expectExceptionMessage('Link not found');
|
|
||||||
|
|
||||||
$env = Environment::mock([
|
|
||||||
'REQUEST_METHOD' => 'GET',
|
|
||||||
]);
|
|
||||||
$request = Request::createFromEnvironment($env);
|
|
||||||
|
|
||||||
$this->controller->getLink($request, new Response(), ['id' => -1]);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,492 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace Shaarli\Api\Controllers;
|
|
||||||
|
|
||||||
use malkusch\lock\mutex\NoMutex;
|
|
||||||
use Shaarli\Bookmark\Bookmark;
|
|
||||||
use Shaarli\Bookmark\BookmarkFileService;
|
|
||||||
use Shaarli\Bookmark\LinkDB;
|
|
||||||
use Shaarli\Config\ConfigManager;
|
|
||||||
use Shaarli\History;
|
|
||||||
use Shaarli\Plugin\PluginManager;
|
|
||||||
use Shaarli\Tests\Utils\ReferenceLinkDB;
|
|
||||||
use Slim\Container;
|
|
||||||
use Slim\Http\Environment;
|
|
||||||
use Slim\Http\Request;
|
|
||||||
use Slim\Http\Response;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Class GetLinksTest
|
|
||||||
*
|
|
||||||
* Test get Link list REST API service.
|
|
||||||
*
|
|
||||||
* @see http://shaarli.github.io/api-documentation/#links-links-collection-get
|
|
||||||
*
|
|
||||||
* @package Shaarli\Api\Controllers
|
|
||||||
*/
|
|
||||||
class GetLinksTest extends \Shaarli\TestCase
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @var string datastore to test write operations
|
|
||||||
*/
|
|
||||||
protected static $testDatastore = 'sandbox/datastore.php';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var ConfigManager instance
|
|
||||||
*/
|
|
||||||
protected $conf;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var ReferenceLinkDB instance.
|
|
||||||
*/
|
|
||||||
protected $refDB = null;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var Container instance.
|
|
||||||
*/
|
|
||||||
protected $container;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var Links controller instance.
|
|
||||||
*/
|
|
||||||
protected $controller;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Number of JSON field per link.
|
|
||||||
*/
|
|
||||||
protected const NB_FIELDS_LINK = 9;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Before every test, instantiate a new Api with its config, plugins and bookmarks.
|
|
||||||
*/
|
|
||||||
protected function setUp(): void
|
|
||||||
{
|
|
||||||
$mutex = new NoMutex();
|
|
||||||
$this->conf = new ConfigManager('tests/utils/config/configJson');
|
|
||||||
$this->conf->set('resource.datastore', self::$testDatastore);
|
|
||||||
$this->refDB = new ReferenceLinkDB();
|
|
||||||
$this->refDB->write(self::$testDatastore);
|
|
||||||
$history = new History('sandbox/history.php');
|
|
||||||
|
|
||||||
$this->container = new Container();
|
|
||||||
$this->container['conf'] = $this->conf;
|
|
||||||
$pluginManager = new PluginManager($this->conf);
|
|
||||||
$this->container['db'] = new BookmarkFileService(
|
|
||||||
$this->conf,
|
|
||||||
$pluginManager,
|
|
||||||
$history,
|
|
||||||
$mutex,
|
|
||||||
true
|
|
||||||
);
|
|
||||||
$this->container['history'] = null;
|
|
||||||
|
|
||||||
$this->controller = new Links($this->container);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* After every test, remove the test datastore.
|
|
||||||
*/
|
|
||||||
protected function tearDown(): void
|
|
||||||
{
|
|
||||||
@unlink(self::$testDatastore);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test basic getLinks service: returns all bookmarks.
|
|
||||||
*/
|
|
||||||
public function testGetLinks()
|
|
||||||
{
|
|
||||||
// Used by index_url().
|
|
||||||
$_SERVER['SERVER_NAME'] = 'domain.tld';
|
|
||||||
$_SERVER['SERVER_PORT'] = 80;
|
|
||||||
$_SERVER['SCRIPT_NAME'] = '/';
|
|
||||||
|
|
||||||
$env = Environment::mock([
|
|
||||||
'REQUEST_METHOD' => 'GET',
|
|
||||||
]);
|
|
||||||
$request = Request::createFromEnvironment($env);
|
|
||||||
|
|
||||||
$response = $this->controller->getLinks($request, new Response());
|
|
||||||
$this->assertEquals(200, $response->getStatusCode());
|
|
||||||
$data = json_decode((string) $response->getBody(), true);
|
|
||||||
$this->assertEquals($this->refDB->countLinks(), count($data));
|
|
||||||
|
|
||||||
// Check order
|
|
||||||
$order = [10, 11, 41, 8, 6, 7, 0, 1, 9, 4, 42];
|
|
||||||
$cpt = 0;
|
|
||||||
foreach ($data as $link) {
|
|
||||||
$this->assertEquals(self::NB_FIELDS_LINK, count($link));
|
|
||||||
$this->assertEquals($order[$cpt++], $link['id']);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check first element fields
|
|
||||||
$first = $data[2];
|
|
||||||
$this->assertEquals('http://domain.tld/shaare/WDWyig', $first['url']);
|
|
||||||
$this->assertEquals('WDWyig', $first['shorturl']);
|
|
||||||
$this->assertEquals('Link title: @website', $first['title']);
|
|
||||||
$this->assertEquals(
|
|
||||||
'Stallman has a beard and is part of the Free Software Foundation (or not). Seriously, read this. #hashtag',
|
|
||||||
$first['description']
|
|
||||||
);
|
|
||||||
$this->assertEquals('sTuff', $first['tags'][0]);
|
|
||||||
$this->assertEquals(false, $first['private']);
|
|
||||||
$this->assertEquals(
|
|
||||||
\DateTime::createFromFormat(Bookmark::LINK_DATE_FORMAT, '20150310_114651')->format(\DateTime::ATOM),
|
|
||||||
$first['created']
|
|
||||||
);
|
|
||||||
$this->assertEmpty($first['updated']);
|
|
||||||
|
|
||||||
// Multi tags
|
|
||||||
$link = $data[3];
|
|
||||||
$this->assertEquals(7, count($link['tags']));
|
|
||||||
|
|
||||||
// Update date
|
|
||||||
$this->assertEquals(
|
|
||||||
\DateTime::createFromFormat(Bookmark::LINK_DATE_FORMAT, '20160803_093033')->format(\DateTime::ATOM),
|
|
||||||
$link['updated']
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test getLinks service with offset and limit parameter:
|
|
||||||
* limit=1 and offset=1 should return only the second link, ID=8 (ordered by creation date DESC).
|
|
||||||
*/
|
|
||||||
public function testGetLinksOffsetLimit()
|
|
||||||
{
|
|
||||||
$env = Environment::mock([
|
|
||||||
'REQUEST_METHOD' => 'GET',
|
|
||||||
'QUERY_STRING' => 'offset=3&limit=1'
|
|
||||||
]);
|
|
||||||
$request = Request::createFromEnvironment($env);
|
|
||||||
$response = $this->controller->getLinks($request, new Response());
|
|
||||||
$this->assertEquals(200, $response->getStatusCode());
|
|
||||||
$data = json_decode((string) $response->getBody(), true);
|
|
||||||
$this->assertEquals(1, count($data));
|
|
||||||
$this->assertEquals(8, $data[0]['id']);
|
|
||||||
$this->assertEquals(self::NB_FIELDS_LINK, count($data[0]));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test getLinks with limit=all (return all link).
|
|
||||||
*/
|
|
||||||
public function testGetLinksLimitAll()
|
|
||||||
{
|
|
||||||
$env = Environment::mock([
|
|
||||||
'REQUEST_METHOD' => 'GET',
|
|
||||||
'QUERY_STRING' => 'limit=all'
|
|
||||||
]);
|
|
||||||
$request = Request::createFromEnvironment($env);
|
|
||||||
$response = $this->controller->getLinks($request, new Response());
|
|
||||||
$this->assertEquals(200, $response->getStatusCode());
|
|
||||||
$data = json_decode((string) $response->getBody(), true);
|
|
||||||
$this->assertEquals($this->refDB->countLinks(), count($data));
|
|
||||||
// Check order
|
|
||||||
$order = [10, 11, 41, 8, 6, 7, 0, 1, 9, 4, 42];
|
|
||||||
$cpt = 0;
|
|
||||||
foreach ($data as $link) {
|
|
||||||
$this->assertEquals(self::NB_FIELDS_LINK, count($link));
|
|
||||||
$this->assertEquals($order[$cpt++], $link['id']);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test getLinks service with offset and limit parameter:
|
|
||||||
* limit=1 and offset=1 should return only the second link, ID=8 (ordered by creation date DESC).
|
|
||||||
*/
|
|
||||||
public function testGetLinksOffsetTooHigh()
|
|
||||||
{
|
|
||||||
$env = Environment::mock([
|
|
||||||
'REQUEST_METHOD' => 'GET',
|
|
||||||
'QUERY_STRING' => 'offset=100'
|
|
||||||
]);
|
|
||||||
$request = Request::createFromEnvironment($env);
|
|
||||||
$response = $this->controller->getLinks($request, new Response());
|
|
||||||
$this->assertEquals(200, $response->getStatusCode());
|
|
||||||
$data = json_decode((string) $response->getBody(), true);
|
|
||||||
$this->assertEmpty(count($data));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test getLinks with visibility parameter set to all
|
|
||||||
*/
|
|
||||||
public function testGetLinksVisibilityAll()
|
|
||||||
{
|
|
||||||
$env = Environment::mock(
|
|
||||||
[
|
|
||||||
'REQUEST_METHOD' => 'GET',
|
|
||||||
'QUERY_STRING' => 'visibility=all'
|
|
||||||
]
|
|
||||||
);
|
|
||||||
$request = Request::createFromEnvironment($env);
|
|
||||||
$response = $this->controller->getLinks($request, new Response());
|
|
||||||
$this->assertEquals(200, $response->getStatusCode());
|
|
||||||
$data = json_decode((string)$response->getBody(), true);
|
|
||||||
$this->assertEquals($this->refDB->countLinks(), count($data));
|
|
||||||
$this->assertEquals(10, $data[0]['id']);
|
|
||||||
$this->assertEquals(41, $data[2]['id']);
|
|
||||||
$this->assertEquals(self::NB_FIELDS_LINK, count($data[0]));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test getLinks with visibility parameter set to private
|
|
||||||
*/
|
|
||||||
public function testGetLinksVisibilityPrivate()
|
|
||||||
{
|
|
||||||
$env = Environment::mock([
|
|
||||||
'REQUEST_METHOD' => 'GET',
|
|
||||||
'QUERY_STRING' => 'visibility=private'
|
|
||||||
]);
|
|
||||||
$request = Request::createFromEnvironment($env);
|
|
||||||
$response = $this->controller->getLinks($request, new Response());
|
|
||||||
$this->assertEquals(200, $response->getStatusCode());
|
|
||||||
$data = json_decode((string) $response->getBody(), true);
|
|
||||||
$this->assertEquals($this->refDB->countPrivateLinks(), count($data));
|
|
||||||
$this->assertEquals(6, $data[0]['id']);
|
|
||||||
$this->assertEquals(self::NB_FIELDS_LINK, count($data[0]));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test getLinks with visibility parameter set to public
|
|
||||||
*/
|
|
||||||
public function testGetLinksVisibilityPublic()
|
|
||||||
{
|
|
||||||
$env = Environment::mock(
|
|
||||||
[
|
|
||||||
'REQUEST_METHOD' => 'GET',
|
|
||||||
'QUERY_STRING' => 'visibility=public'
|
|
||||||
]
|
|
||||||
);
|
|
||||||
$request = Request::createFromEnvironment($env);
|
|
||||||
$response = $this->controller->getLinks($request, new Response());
|
|
||||||
$this->assertEquals(200, $response->getStatusCode());
|
|
||||||
$data = json_decode((string)$response->getBody(), true);
|
|
||||||
$this->assertEquals($this->refDB->countPublicLinks(), count($data));
|
|
||||||
$this->assertEquals(10, $data[0]['id']);
|
|
||||||
$this->assertEquals(41, $data[2]['id']);
|
|
||||||
$this->assertEquals(self::NB_FIELDS_LINK, count($data[0]));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test getLinks service with offset and limit parameter:
|
|
||||||
* limit=1 and offset=1 should return only the second link, ID=8 (ordered by creation date DESC).
|
|
||||||
*/
|
|
||||||
public function testGetLinksSearchTerm()
|
|
||||||
{
|
|
||||||
// Only in description - 1 result
|
|
||||||
$env = Environment::mock([
|
|
||||||
'REQUEST_METHOD' => 'GET',
|
|
||||||
'QUERY_STRING' => 'searchterm=Tropical'
|
|
||||||
]);
|
|
||||||
$request = Request::createFromEnvironment($env);
|
|
||||||
$response = $this->controller->getLinks($request, new Response());
|
|
||||||
$this->assertEquals(200, $response->getStatusCode());
|
|
||||||
$data = json_decode((string) $response->getBody(), true);
|
|
||||||
$this->assertEquals(1, count($data));
|
|
||||||
$this->assertEquals(1, $data[0]['id']);
|
|
||||||
$this->assertEquals(self::NB_FIELDS_LINK, count($data[0]));
|
|
||||||
|
|
||||||
// Only in tags - 1 result
|
|
||||||
$env = Environment::mock([
|
|
||||||
'REQUEST_METHOD' => 'GET',
|
|
||||||
'QUERY_STRING' => 'searchterm=tag3'
|
|
||||||
]);
|
|
||||||
$request = Request::createFromEnvironment($env);
|
|
||||||
$response = $this->controller->getLinks($request, new Response());
|
|
||||||
$this->assertEquals(200, $response->getStatusCode());
|
|
||||||
$data = json_decode((string) $response->getBody(), true);
|
|
||||||
$this->assertEquals(1, count($data));
|
|
||||||
$this->assertEquals(0, $data[0]['id']);
|
|
||||||
$this->assertEquals(self::NB_FIELDS_LINK, count($data[0]));
|
|
||||||
|
|
||||||
// Multiple results (2)
|
|
||||||
$env = Environment::mock([
|
|
||||||
'REQUEST_METHOD' => 'GET',
|
|
||||||
'QUERY_STRING' => 'searchterm=stallman'
|
|
||||||
]);
|
|
||||||
$request = Request::createFromEnvironment($env);
|
|
||||||
$response = $this->controller->getLinks($request, new Response());
|
|
||||||
$this->assertEquals(200, $response->getStatusCode());
|
|
||||||
$data = json_decode((string) $response->getBody(), true);
|
|
||||||
$this->assertEquals(2, count($data));
|
|
||||||
$this->assertEquals(41, $data[0]['id']);
|
|
||||||
$this->assertEquals(self::NB_FIELDS_LINK, count($data[0]));
|
|
||||||
$this->assertEquals(8, $data[1]['id']);
|
|
||||||
$this->assertEquals(self::NB_FIELDS_LINK, count($data[1]));
|
|
||||||
|
|
||||||
// Multiword - 2 results
|
|
||||||
$env = Environment::mock([
|
|
||||||
'REQUEST_METHOD' => 'GET',
|
|
||||||
'QUERY_STRING' => 'searchterm=stallman+software'
|
|
||||||
]);
|
|
||||||
$request = Request::createFromEnvironment($env);
|
|
||||||
$response = $this->controller->getLinks($request, new Response());
|
|
||||||
$this->assertEquals(200, $response->getStatusCode());
|
|
||||||
$data = json_decode((string) $response->getBody(), true);
|
|
||||||
$this->assertEquals(2, count($data));
|
|
||||||
$this->assertEquals(41, $data[0]['id']);
|
|
||||||
$this->assertEquals(self::NB_FIELDS_LINK, count($data[0]));
|
|
||||||
$this->assertEquals(8, $data[1]['id']);
|
|
||||||
$this->assertEquals(self::NB_FIELDS_LINK, count($data[1]));
|
|
||||||
|
|
||||||
// URL encoding
|
|
||||||
$env = Environment::mock([
|
|
||||||
'REQUEST_METHOD' => 'GET',
|
|
||||||
'QUERY_STRING' => 'searchterm=' . urlencode('@web')
|
|
||||||
]);
|
|
||||||
$request = Request::createFromEnvironment($env);
|
|
||||||
$response = $this->controller->getLinks($request, new Response());
|
|
||||||
$this->assertEquals(200, $response->getStatusCode());
|
|
||||||
$data = json_decode((string) $response->getBody(), true);
|
|
||||||
$this->assertEquals(2, count($data));
|
|
||||||
$this->assertEquals(41, $data[0]['id']);
|
|
||||||
$this->assertEquals(self::NB_FIELDS_LINK, count($data[0]));
|
|
||||||
$this->assertEquals(8, $data[1]['id']);
|
|
||||||
$this->assertEquals(self::NB_FIELDS_LINK, count($data[1]));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testGetLinksSearchTermNoResult()
|
|
||||||
{
|
|
||||||
$env = Environment::mock([
|
|
||||||
'REQUEST_METHOD' => 'GET',
|
|
||||||
'QUERY_STRING' => 'searchterm=nope'
|
|
||||||
]);
|
|
||||||
$request = Request::createFromEnvironment($env);
|
|
||||||
$response = $this->controller->getLinks($request, new Response());
|
|
||||||
$this->assertEquals(200, $response->getStatusCode());
|
|
||||||
$data = json_decode((string) $response->getBody(), true);
|
|
||||||
$this->assertEquals(0, count($data));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testGetLinksSearchTags()
|
|
||||||
{
|
|
||||||
// Single tag
|
|
||||||
$env = Environment::mock([
|
|
||||||
'REQUEST_METHOD' => 'GET',
|
|
||||||
'QUERY_STRING' => 'searchtags=dev',
|
|
||||||
]);
|
|
||||||
$request = Request::createFromEnvironment($env);
|
|
||||||
$response = $this->controller->getLinks($request, new Response());
|
|
||||||
$this->assertEquals(200, $response->getStatusCode());
|
|
||||||
$data = json_decode((string) $response->getBody(), true);
|
|
||||||
$this->assertEquals(2, count($data));
|
|
||||||
$this->assertEquals(0, $data[0]['id']);
|
|
||||||
$this->assertEquals(self::NB_FIELDS_LINK, count($data[0]));
|
|
||||||
$this->assertEquals(4, $data[1]['id']);
|
|
||||||
$this->assertEquals(self::NB_FIELDS_LINK, count($data[1]));
|
|
||||||
|
|
||||||
// Multitag + exclude
|
|
||||||
$env = Environment::mock([
|
|
||||||
'REQUEST_METHOD' => 'GET',
|
|
||||||
'QUERY_STRING' => 'searchtags=stuff+-gnu',
|
|
||||||
]);
|
|
||||||
$request = Request::createFromEnvironment($env);
|
|
||||||
$response = $this->controller->getLinks($request, new Response());
|
|
||||||
$this->assertEquals(200, $response->getStatusCode());
|
|
||||||
$data = json_decode((string) $response->getBody(), true);
|
|
||||||
$this->assertEquals(1, count($data));
|
|
||||||
$this->assertEquals(41, $data[0]['id']);
|
|
||||||
$this->assertEquals(self::NB_FIELDS_LINK, count($data[0]));
|
|
||||||
|
|
||||||
// wildcard: placeholder at the start
|
|
||||||
$env = Environment::mock([
|
|
||||||
'REQUEST_METHOD' => 'GET',
|
|
||||||
'QUERY_STRING' => 'searchtags=*Tuff',
|
|
||||||
]);
|
|
||||||
$request = Request::createFromEnvironment($env);
|
|
||||||
$response = $this->controller->getLinks($request, new Response());
|
|
||||||
$this->assertEquals(200, $response->getStatusCode());
|
|
||||||
$data = json_decode((string) $response->getBody(), true);
|
|
||||||
$this->assertEquals(2, count($data));
|
|
||||||
$this->assertEquals(41, $data[0]['id']);
|
|
||||||
|
|
||||||
// wildcard: placeholder at the end
|
|
||||||
$env = Environment::mock([
|
|
||||||
'REQUEST_METHOD' => 'GET',
|
|
||||||
'QUERY_STRING' => 'searchtags=c*',
|
|
||||||
]);
|
|
||||||
$request = Request::createFromEnvironment($env);
|
|
||||||
$response = $this->controller->getLinks($request, new Response());
|
|
||||||
$this->assertEquals(200, $response->getStatusCode());
|
|
||||||
$data = json_decode((string) $response->getBody(), true);
|
|
||||||
$this->assertEquals(5, count($data));
|
|
||||||
$this->assertEquals(6, $data[0]['id']);
|
|
||||||
|
|
||||||
// wildcard: placeholder at the middle
|
|
||||||
$env = Environment::mock([
|
|
||||||
'REQUEST_METHOD' => 'GET',
|
|
||||||
'QUERY_STRING' => 'searchtags=w*b',
|
|
||||||
]);
|
|
||||||
$request = Request::createFromEnvironment($env);
|
|
||||||
$response = $this->controller->getLinks($request, new Response());
|
|
||||||
$this->assertEquals(200, $response->getStatusCode());
|
|
||||||
$data = json_decode((string) $response->getBody(), true);
|
|
||||||
$this->assertEquals(4, count($data));
|
|
||||||
$this->assertEquals(6, $data[0]['id']);
|
|
||||||
|
|
||||||
// wildcard: match all
|
|
||||||
$env = Environment::mock([
|
|
||||||
'REQUEST_METHOD' => 'GET',
|
|
||||||
'QUERY_STRING' => 'searchtags=*',
|
|
||||||
]);
|
|
||||||
$request = Request::createFromEnvironment($env);
|
|
||||||
$response = $this->controller->getLinks($request, new Response());
|
|
||||||
$this->assertEquals(200, $response->getStatusCode());
|
|
||||||
$data = json_decode((string) $response->getBody(), true);
|
|
||||||
$this->assertEquals(ReferenceLinkDB::$NB_LINKS_TOTAL, count($data));
|
|
||||||
$this->assertEquals(10, $data[0]['id']);
|
|
||||||
$this->assertEquals(41, $data[2]['id']);
|
|
||||||
|
|
||||||
// wildcard: optional ('*' does not need to expand)
|
|
||||||
$env = Environment::mock([
|
|
||||||
'REQUEST_METHOD' => 'GET',
|
|
||||||
'QUERY_STRING' => 'searchtags=*stuff*',
|
|
||||||
]);
|
|
||||||
$request = Request::createFromEnvironment($env);
|
|
||||||
$response = $this->controller->getLinks($request, new Response());
|
|
||||||
$this->assertEquals(200, $response->getStatusCode());
|
|
||||||
$data = json_decode((string) $response->getBody(), true);
|
|
||||||
$this->assertEquals(2, count($data));
|
|
||||||
$this->assertEquals(41, $data[0]['id']);
|
|
||||||
|
|
||||||
// wildcard: exclusions
|
|
||||||
$env = Environment::mock([
|
|
||||||
'REQUEST_METHOD' => 'GET',
|
|
||||||
'QUERY_STRING' => 'searchtags=*a*+-*e*',
|
|
||||||
]);
|
|
||||||
$request = Request::createFromEnvironment($env);
|
|
||||||
$response = $this->controller->getLinks($request, new Response());
|
|
||||||
$this->assertEquals(200, $response->getStatusCode());
|
|
||||||
$data = json_decode((string) $response->getBody(), true);
|
|
||||||
$this->assertEquals(1, count($data));
|
|
||||||
$this->assertEquals(41, $data[0]['id']); // finds '#hashtag' in descr.
|
|
||||||
|
|
||||||
// wildcard: exclude all
|
|
||||||
$env = Environment::mock([
|
|
||||||
'REQUEST_METHOD' => 'GET',
|
|
||||||
'QUERY_STRING' => 'searchtags=-*',
|
|
||||||
]);
|
|
||||||
$request = Request::createFromEnvironment($env);
|
|
||||||
$response = $this->controller->getLinks($request, new Response());
|
|
||||||
$this->assertEquals(200, $response->getStatusCode());
|
|
||||||
$data = json_decode((string) $response->getBody(), true);
|
|
||||||
$this->assertEquals(0, count($data));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test getLinks service with search tags+terms.
|
|
||||||
*/
|
|
||||||
public function testGetLinksSearchTermsAndTags()
|
|
||||||
{
|
|
||||||
$env = Environment::mock([
|
|
||||||
'REQUEST_METHOD' => 'GET',
|
|
||||||
'QUERY_STRING' => 'searchterm=poke&searchtags=dev',
|
|
||||||
]);
|
|
||||||
$request = Request::createFromEnvironment($env);
|
|
||||||
$response = $this->controller->getLinks($request, new Response());
|
|
||||||
$this->assertEquals(200, $response->getStatusCode());
|
|
||||||
$data = json_decode((string) $response->getBody(), true);
|
|
||||||
$this->assertEquals(1, count($data));
|
|
||||||
$this->assertEquals(0, $data[0]['id']);
|
|
||||||
$this->assertEquals(self::NB_FIELDS_LINK, count($data[0]));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,289 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace Shaarli\Api\Controllers;
|
|
||||||
|
|
||||||
use malkusch\lock\mutex\NoMutex;
|
|
||||||
use Shaarli\Bookmark\Bookmark;
|
|
||||||
use Shaarli\Bookmark\BookmarkFileService;
|
|
||||||
use Shaarli\Config\ConfigManager;
|
|
||||||
use Shaarli\History;
|
|
||||||
use Shaarli\Plugin\PluginManager;
|
|
||||||
use Shaarli\TestCase;
|
|
||||||
use Shaarli\Tests\Utils\ReferenceHistory;
|
|
||||||
use Shaarli\Tests\Utils\ReferenceLinkDB;
|
|
||||||
use Slim\Container;
|
|
||||||
use Slim\Http\Environment;
|
|
||||||
use Slim\Http\Request;
|
|
||||||
use Slim\Http\Response;
|
|
||||||
use Slim\Router;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Class PostLinkTest
|
|
||||||
*
|
|
||||||
* Test POST Link REST API service.
|
|
||||||
*
|
|
||||||
* @package Shaarli\Api\Controllers
|
|
||||||
*/
|
|
||||||
class PostLinkTest extends TestCase
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @var string datastore to test write operations
|
|
||||||
*/
|
|
||||||
protected static $testDatastore = 'sandbox/datastore.php';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var string datastore to test write operations
|
|
||||||
*/
|
|
||||||
protected static $testHistory = 'sandbox/history.php';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var ConfigManager instance
|
|
||||||
*/
|
|
||||||
protected $conf;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var ReferenceLinkDB instance.
|
|
||||||
*/
|
|
||||||
protected $refDB = null;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var BookmarkFileService instance.
|
|
||||||
*/
|
|
||||||
protected $bookmarkService;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var HistoryController instance.
|
|
||||||
*/
|
|
||||||
protected $history;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var Container instance.
|
|
||||||
*/
|
|
||||||
protected $container;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var Links controller instance.
|
|
||||||
*/
|
|
||||||
protected $controller;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Number of JSON field per link.
|
|
||||||
*/
|
|
||||||
protected const NB_FIELDS_LINK = 9;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Before every test, instantiate a new Api with its config, plugins and bookmarks.
|
|
||||||
*/
|
|
||||||
protected function setUp(): void
|
|
||||||
{
|
|
||||||
$mutex = new NoMutex();
|
|
||||||
$this->conf = new ConfigManager('tests/utils/config/configJson');
|
|
||||||
$this->conf->set('resource.datastore', self::$testDatastore);
|
|
||||||
$this->refDB = new ReferenceLinkDB();
|
|
||||||
$this->refDB->write(self::$testDatastore);
|
|
||||||
$refHistory = new ReferenceHistory();
|
|
||||||
$refHistory->write(self::$testHistory);
|
|
||||||
$this->history = new History(self::$testHistory);
|
|
||||||
$pluginManager = new PluginManager($this->conf);
|
|
||||||
$this->bookmarkService = new BookmarkFileService(
|
|
||||||
$this->conf,
|
|
||||||
$pluginManager,
|
|
||||||
$this->history,
|
|
||||||
$mutex,
|
|
||||||
true
|
|
||||||
);
|
|
||||||
$this->container = new Container();
|
|
||||||
$this->container['conf'] = $this->conf;
|
|
||||||
$this->container['db'] = $this->bookmarkService;
|
|
||||||
$this->container['history'] = $this->history;
|
|
||||||
|
|
||||||
$this->controller = new Links($this->container);
|
|
||||||
|
|
||||||
$mock = $this->createMock(Router::class);
|
|
||||||
$mock->expects($this->any())
|
|
||||||
->method('pathFor')
|
|
||||||
->willReturn('/api/v1/bookmarks/1');
|
|
||||||
|
|
||||||
// affect @property-read... seems to work
|
|
||||||
$this->controller->getCi()->router = $mock;
|
|
||||||
|
|
||||||
// Used by index_url().
|
|
||||||
$this->controller->getCi()['environment'] = [
|
|
||||||
'SERVER_NAME' => 'domain.tld',
|
|
||||||
'SERVER_PORT' => 80,
|
|
||||||
'SCRIPT_NAME' => '/',
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* After every test, remove the test datastore.
|
|
||||||
*/
|
|
||||||
protected function tearDown(): void
|
|
||||||
{
|
|
||||||
@unlink(self::$testDatastore);
|
|
||||||
@unlink(self::$testHistory);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test link creation without any field: creates a blank note.
|
|
||||||
*/
|
|
||||||
public function testPostLinkMinimal()
|
|
||||||
{
|
|
||||||
$env = Environment::mock([
|
|
||||||
'REQUEST_METHOD' => 'POST',
|
|
||||||
]);
|
|
||||||
|
|
||||||
$request = Request::createFromEnvironment($env);
|
|
||||||
|
|
||||||
$response = $this->controller->postLink($request, new Response());
|
|
||||||
$this->assertEquals(201, $response->getStatusCode());
|
|
||||||
$this->assertEquals('/api/v1/bookmarks/1', $response->getHeader('Location')[0]);
|
|
||||||
$data = json_decode((string) $response->getBody(), true);
|
|
||||||
$this->assertEquals(self::NB_FIELDS_LINK, count($data));
|
|
||||||
$this->assertEquals(43, $data['id']);
|
|
||||||
$this->assertRegExp('/[\w_-]{6}/', $data['shorturl']);
|
|
||||||
$this->assertEquals('http://domain.tld/shaare/' . $data['shorturl'], $data['url']);
|
|
||||||
$this->assertEquals('/shaare/' . $data['shorturl'], $data['title']);
|
|
||||||
$this->assertEquals('', $data['description']);
|
|
||||||
$this->assertEquals([], $data['tags']);
|
|
||||||
$this->assertEquals(true, $data['private']);
|
|
||||||
$this->assertTrue(
|
|
||||||
new \DateTime('5 seconds ago') < \DateTime::createFromFormat(\DateTime::ATOM, $data['created'])
|
|
||||||
);
|
|
||||||
$this->assertEquals('', $data['updated']);
|
|
||||||
|
|
||||||
$historyEntry = $this->history->getHistory()[0];
|
|
||||||
$this->assertEquals(History::CREATED, $historyEntry['event']);
|
|
||||||
$this->assertTrue(
|
|
||||||
(new \DateTime())->add(\DateInterval::createFromDateString('-5 seconds')) < $historyEntry['datetime']
|
|
||||||
);
|
|
||||||
$this->assertEquals(43, $historyEntry['id']);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test link creation with all available fields.
|
|
||||||
*/
|
|
||||||
public function testPostLinkFull()
|
|
||||||
{
|
|
||||||
$link = [
|
|
||||||
'url' => 'website.tld/test?foo=bar',
|
|
||||||
'title' => 'new entry',
|
|
||||||
'description' => 'shaare description',
|
|
||||||
'tags' => ['one', 'two'],
|
|
||||||
'private' => true,
|
|
||||||
'created' => '2015-05-05T12:30:00+03:00',
|
|
||||||
'updated' => '2016-06-05T14:32:10+03:00',
|
|
||||||
];
|
|
||||||
$env = Environment::mock([
|
|
||||||
'REQUEST_METHOD' => 'POST',
|
|
||||||
'CONTENT_TYPE' => 'application/json'
|
|
||||||
]);
|
|
||||||
|
|
||||||
$request = Request::createFromEnvironment($env);
|
|
||||||
$request = $request->withParsedBody($link);
|
|
||||||
$response = $this->controller->postLink($request, new Response());
|
|
||||||
|
|
||||||
$this->assertEquals(201, $response->getStatusCode());
|
|
||||||
$this->assertEquals('/api/v1/bookmarks/1', $response->getHeader('Location')[0]);
|
|
||||||
$data = json_decode((string) $response->getBody(), true);
|
|
||||||
$this->assertEquals(self::NB_FIELDS_LINK, count($data));
|
|
||||||
$this->assertEquals(43, $data['id']);
|
|
||||||
$this->assertRegExp('/[\w_-]{6}/', $data['shorturl']);
|
|
||||||
$this->assertEquals('http://' . $link['url'], $data['url']);
|
|
||||||
$this->assertEquals($link['title'], $data['title']);
|
|
||||||
$this->assertEquals($link['description'], $data['description']);
|
|
||||||
$this->assertEquals($link['tags'], $data['tags']);
|
|
||||||
$this->assertEquals(true, $data['private']);
|
|
||||||
$this->assertSame($link['created'], $data['created']);
|
|
||||||
$this->assertSame($link['updated'], $data['updated']);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test link creation with an existing link (duplicate URL). Should return a 409 HTTP error and the existing link.
|
|
||||||
*/
|
|
||||||
public function testPostLinkDuplicate()
|
|
||||||
{
|
|
||||||
$link = [
|
|
||||||
'url' => 'mediagoblin.org/',
|
|
||||||
'title' => 'new entry',
|
|
||||||
'description' => 'shaare description',
|
|
||||||
'tags' => ['one', 'two'],
|
|
||||||
'private' => true,
|
|
||||||
];
|
|
||||||
$env = Environment::mock([
|
|
||||||
'REQUEST_METHOD' => 'POST',
|
|
||||||
'CONTENT_TYPE' => 'application/json'
|
|
||||||
]);
|
|
||||||
|
|
||||||
$request = Request::createFromEnvironment($env);
|
|
||||||
$request = $request->withParsedBody($link);
|
|
||||||
$response = $this->controller->postLink($request, new Response());
|
|
||||||
|
|
||||||
$this->assertEquals(409, $response->getStatusCode());
|
|
||||||
$data = json_decode((string) $response->getBody(), true);
|
|
||||||
$this->assertEquals(self::NB_FIELDS_LINK, count($data));
|
|
||||||
$this->assertEquals(7, $data['id']);
|
|
||||||
$this->assertEquals('IuWvgA', $data['shorturl']);
|
|
||||||
$this->assertEquals('http://mediagoblin.org/', $data['url']);
|
|
||||||
$this->assertEquals('MediaGoblin', $data['title']);
|
|
||||||
$this->assertEquals('A free software media publishing platform #hashtagOther', $data['description']);
|
|
||||||
$this->assertEquals(['gnu', 'media', 'web', '.hidden', 'hashtag'], $data['tags']);
|
|
||||||
$this->assertEquals(false, $data['private']);
|
|
||||||
$this->assertEquals(
|
|
||||||
\DateTime::createFromFormat(Bookmark::LINK_DATE_FORMAT, '20130614_184135'),
|
|
||||||
\DateTime::createFromFormat(\DateTime::ATOM, $data['created'])
|
|
||||||
);
|
|
||||||
$this->assertEquals(
|
|
||||||
\DateTime::createFromFormat(Bookmark::LINK_DATE_FORMAT, '20130615_184230'),
|
|
||||||
\DateTime::createFromFormat(\DateTime::ATOM, $data['updated'])
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test link creation with a tag string provided
|
|
||||||
*/
|
|
||||||
public function testPostLinkWithTagString(): void
|
|
||||||
{
|
|
||||||
$link = [
|
|
||||||
'tags' => 'one two',
|
|
||||||
];
|
|
||||||
$env = Environment::mock([
|
|
||||||
'REQUEST_METHOD' => 'POST',
|
|
||||||
'CONTENT_TYPE' => 'application/json'
|
|
||||||
]);
|
|
||||||
|
|
||||||
$request = Request::createFromEnvironment($env);
|
|
||||||
$request = $request->withParsedBody($link);
|
|
||||||
$response = $this->controller->postLink($request, new Response());
|
|
||||||
|
|
||||||
$this->assertEquals(201, $response->getStatusCode());
|
|
||||||
$this->assertEquals('/api/v1/bookmarks/1', $response->getHeader('Location')[0]);
|
|
||||||
$data = json_decode((string) $response->getBody(), true);
|
|
||||||
$this->assertEquals(self::NB_FIELDS_LINK, count($data));
|
|
||||||
$this->assertEquals(['one', 'two'], $data['tags']);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test link creation with a tag string provided
|
|
||||||
*/
|
|
||||||
public function testPostLinkWithTagString2(): void
|
|
||||||
{
|
|
||||||
$link = [
|
|
||||||
'tags' => ['one two'],
|
|
||||||
];
|
|
||||||
$env = Environment::mock([
|
|
||||||
'REQUEST_METHOD' => 'POST',
|
|
||||||
'CONTENT_TYPE' => 'application/json'
|
|
||||||
]);
|
|
||||||
|
|
||||||
$request = Request::createFromEnvironment($env);
|
|
||||||
$request = $request->withParsedBody($link);
|
|
||||||
$response = $this->controller->postLink($request, new Response());
|
|
||||||
|
|
||||||
$this->assertEquals(201, $response->getStatusCode());
|
|
||||||
$this->assertEquals('/api/v1/bookmarks/1', $response->getHeader('Location')[0]);
|
|
||||||
$data = json_decode((string) $response->getBody(), true);
|
|
||||||
$this->assertEquals(self::NB_FIELDS_LINK, count($data));
|
|
||||||
$this->assertEquals(['one', 'two'], $data['tags']);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,292 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace Shaarli\Api\Controllers;
|
|
||||||
|
|
||||||
use malkusch\lock\mutex\NoMutex;
|
|
||||||
use Shaarli\Bookmark\Bookmark;
|
|
||||||
use Shaarli\Bookmark\BookmarkFileService;
|
|
||||||
use Shaarli\Config\ConfigManager;
|
|
||||||
use Shaarli\History;
|
|
||||||
use Shaarli\Plugin\PluginManager;
|
|
||||||
use Shaarli\Tests\Utils\ReferenceHistory;
|
|
||||||
use Shaarli\Tests\Utils\ReferenceLinkDB;
|
|
||||||
use Slim\Container;
|
|
||||||
use Slim\Http\Environment;
|
|
||||||
use Slim\Http\Request;
|
|
||||||
use Slim\Http\Response;
|
|
||||||
|
|
||||||
class PutLinkTest extends \Shaarli\TestCase
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @var string datastore to test write operations
|
|
||||||
*/
|
|
||||||
protected static $testDatastore = 'sandbox/datastore.php';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var string datastore to test write operations
|
|
||||||
*/
|
|
||||||
protected static $testHistory = 'sandbox/history.php';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var ConfigManager instance
|
|
||||||
*/
|
|
||||||
protected $conf;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var ReferenceLinkDB instance.
|
|
||||||
*/
|
|
||||||
protected $refDB = null;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var BookmarkFileService instance.
|
|
||||||
*/
|
|
||||||
protected $bookmarkService;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var HistoryController instance.
|
|
||||||
*/
|
|
||||||
protected $history;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var Container instance.
|
|
||||||
*/
|
|
||||||
protected $container;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var Links controller instance.
|
|
||||||
*/
|
|
||||||
protected $controller;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Number of JSON field per link.
|
|
||||||
*/
|
|
||||||
protected const NB_FIELDS_LINK = 9;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Before every test, instantiate a new Api with its config, plugins and bookmarks.
|
|
||||||
*/
|
|
||||||
protected function setUp(): void
|
|
||||||
{
|
|
||||||
$mutex = new NoMutex();
|
|
||||||
$this->conf = new ConfigManager('tests/utils/config/configJson');
|
|
||||||
$this->conf->set('resource.datastore', self::$testDatastore);
|
|
||||||
$this->refDB = new ReferenceLinkDB();
|
|
||||||
$this->refDB->write(self::$testDatastore);
|
|
||||||
$refHistory = new ReferenceHistory();
|
|
||||||
$refHistory->write(self::$testHistory);
|
|
||||||
$this->history = new History(self::$testHistory);
|
|
||||||
$pluginManager = new PluginManager($this->conf);
|
|
||||||
$this->bookmarkService = new BookmarkFileService(
|
|
||||||
$this->conf,
|
|
||||||
$pluginManager,
|
|
||||||
$this->history,
|
|
||||||
$mutex,
|
|
||||||
true
|
|
||||||
);
|
|
||||||
$this->container = new Container();
|
|
||||||
$this->container['conf'] = $this->conf;
|
|
||||||
$this->container['db'] = $this->bookmarkService;
|
|
||||||
$this->container['history'] = $this->history;
|
|
||||||
|
|
||||||
$this->controller = new Links($this->container);
|
|
||||||
|
|
||||||
// Used by index_url().
|
|
||||||
$this->controller->getCi()['environment'] = [
|
|
||||||
'SERVER_NAME' => 'domain.tld',
|
|
||||||
'SERVER_PORT' => 80,
|
|
||||||
'SCRIPT_NAME' => '/',
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* After every test, remove the test datastore.
|
|
||||||
*/
|
|
||||||
protected function tearDown(): void
|
|
||||||
{
|
|
||||||
@unlink(self::$testDatastore);
|
|
||||||
@unlink(self::$testHistory);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test link update without value: reset the link to default values
|
|
||||||
*/
|
|
||||||
public function testPutLinkMinimal()
|
|
||||||
{
|
|
||||||
$env = Environment::mock([
|
|
||||||
'REQUEST_METHOD' => 'PUT',
|
|
||||||
]);
|
|
||||||
$id = '41';
|
|
||||||
$request = Request::createFromEnvironment($env);
|
|
||||||
|
|
||||||
$response = $this->controller->putLink($request, new Response(), ['id' => $id]);
|
|
||||||
$this->assertEquals(200, $response->getStatusCode());
|
|
||||||
$data = json_decode((string) $response->getBody(), true);
|
|
||||||
$this->assertEquals(self::NB_FIELDS_LINK, count($data));
|
|
||||||
$this->assertEquals($id, $data['id']);
|
|
||||||
$this->assertEquals('WDWyig', $data['shorturl']);
|
|
||||||
$this->assertEquals('http://domain.tld/shaare/WDWyig', $data['url']);
|
|
||||||
$this->assertEquals('/shaare/WDWyig', $data['title']);
|
|
||||||
$this->assertEquals('', $data['description']);
|
|
||||||
$this->assertEquals([], $data['tags']);
|
|
||||||
$this->assertEquals(true, $data['private']);
|
|
||||||
$this->assertEquals(
|
|
||||||
\DateTime::createFromFormat('Ymd_His', '20150310_114651'),
|
|
||||||
\DateTime::createFromFormat(\DateTime::ATOM, $data['created'])
|
|
||||||
);
|
|
||||||
$this->assertTrue(
|
|
||||||
new \DateTime('5 seconds ago') < \DateTime::createFromFormat(\DateTime::ATOM, $data['updated'])
|
|
||||||
);
|
|
||||||
|
|
||||||
$historyEntry = $this->history->getHistory()[0];
|
|
||||||
$this->assertEquals(History::UPDATED, $historyEntry['event']);
|
|
||||||
$this->assertTrue(
|
|
||||||
(new \DateTime())->add(\DateInterval::createFromDateString('-5 seconds')) < $historyEntry['datetime']
|
|
||||||
);
|
|
||||||
$this->assertEquals($id, $historyEntry['id']);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test link update with new values
|
|
||||||
*/
|
|
||||||
public function testPutLinkWithValues()
|
|
||||||
{
|
|
||||||
$env = Environment::mock([
|
|
||||||
'REQUEST_METHOD' => 'PUT',
|
|
||||||
'CONTENT_TYPE' => 'application/json'
|
|
||||||
]);
|
|
||||||
$id = 41;
|
|
||||||
$update = [
|
|
||||||
'url' => 'http://somewhere.else',
|
|
||||||
'title' => 'Le Cid',
|
|
||||||
'description' => 'Percé jusques au fond du cœur [...]',
|
|
||||||
'tags' => ['corneille', 'rodrigue'],
|
|
||||||
'private' => true,
|
|
||||||
];
|
|
||||||
$request = Request::createFromEnvironment($env);
|
|
||||||
$request = $request->withParsedBody($update);
|
|
||||||
|
|
||||||
$response = $this->controller->putLink($request, new Response(), ['id' => $id]);
|
|
||||||
$this->assertEquals(200, $response->getStatusCode());
|
|
||||||
$data = json_decode((string) $response->getBody(), true);
|
|
||||||
$this->assertEquals(self::NB_FIELDS_LINK, count($data));
|
|
||||||
$this->assertEquals($id, $data['id']);
|
|
||||||
$this->assertEquals('WDWyig', $data['shorturl']);
|
|
||||||
$this->assertEquals('http://somewhere.else', $data['url']);
|
|
||||||
$this->assertEquals('Le Cid', $data['title']);
|
|
||||||
$this->assertEquals('Percé jusques au fond du cœur [...]', $data['description']);
|
|
||||||
$this->assertEquals(['corneille', 'rodrigue'], $data['tags']);
|
|
||||||
$this->assertEquals(true, $data['private']);
|
|
||||||
$this->assertEquals(
|
|
||||||
\DateTime::createFromFormat('Ymd_His', '20150310_114651'),
|
|
||||||
\DateTime::createFromFormat(\DateTime::ATOM, $data['created'])
|
|
||||||
);
|
|
||||||
$this->assertTrue(
|
|
||||||
new \DateTime('5 seconds ago') < \DateTime::createFromFormat(\DateTime::ATOM, $data['updated'])
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test link update with an existing URL: 409 Conflict with the existing link as body
|
|
||||||
*/
|
|
||||||
public function testPutLinkDuplicate()
|
|
||||||
{
|
|
||||||
$link = [
|
|
||||||
'url' => 'mediagoblin.org/',
|
|
||||||
'title' => 'new entry',
|
|
||||||
'description' => 'shaare description',
|
|
||||||
'tags' => ['one', 'two'],
|
|
||||||
'private' => true,
|
|
||||||
];
|
|
||||||
$env = Environment::mock([
|
|
||||||
'REQUEST_METHOD' => 'PUT',
|
|
||||||
'CONTENT_TYPE' => 'application/json'
|
|
||||||
]);
|
|
||||||
|
|
||||||
$request = Request::createFromEnvironment($env);
|
|
||||||
$request = $request->withParsedBody($link);
|
|
||||||
$response = $this->controller->putLink($request, new Response(), ['id' => 41]);
|
|
||||||
|
|
||||||
$this->assertEquals(409, $response->getStatusCode());
|
|
||||||
$data = json_decode((string) $response->getBody(), true);
|
|
||||||
$this->assertEquals(self::NB_FIELDS_LINK, count($data));
|
|
||||||
$this->assertEquals(7, $data['id']);
|
|
||||||
$this->assertEquals('IuWvgA', $data['shorturl']);
|
|
||||||
$this->assertEquals('http://mediagoblin.org/', $data['url']);
|
|
||||||
$this->assertEquals('MediaGoblin', $data['title']);
|
|
||||||
$this->assertEquals('A free software media publishing platform #hashtagOther', $data['description']);
|
|
||||||
$this->assertEquals(['gnu', 'media', 'web', '.hidden', 'hashtag'], $data['tags']);
|
|
||||||
$this->assertEquals(false, $data['private']);
|
|
||||||
$this->assertEquals(
|
|
||||||
\DateTime::createFromFormat(Bookmark::LINK_DATE_FORMAT, '20130614_184135'),
|
|
||||||
\DateTime::createFromFormat(\DateTime::ATOM, $data['created'])
|
|
||||||
);
|
|
||||||
$this->assertEquals(
|
|
||||||
\DateTime::createFromFormat(Bookmark::LINK_DATE_FORMAT, '20130615_184230'),
|
|
||||||
\DateTime::createFromFormat(\DateTime::ATOM, $data['updated'])
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test link update on non existent link => ApiLinkNotFoundException.
|
|
||||||
*/
|
|
||||||
public function testGetLink404()
|
|
||||||
{
|
|
||||||
$this->expectException(\Shaarli\Api\Exceptions\ApiLinkNotFoundException::class);
|
|
||||||
$this->expectExceptionMessage('Link not found');
|
|
||||||
|
|
||||||
$env = Environment::mock([
|
|
||||||
'REQUEST_METHOD' => 'PUT',
|
|
||||||
]);
|
|
||||||
$request = Request::createFromEnvironment($env);
|
|
||||||
|
|
||||||
$this->controller->putLink($request, new Response(), ['id' => -1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test link creation with a tag string provided
|
|
||||||
*/
|
|
||||||
public function testPutLinkWithTagString(): void
|
|
||||||
{
|
|
||||||
$link = [
|
|
||||||
'tags' => 'one two',
|
|
||||||
];
|
|
||||||
$id = '41';
|
|
||||||
$env = Environment::mock([
|
|
||||||
'REQUEST_METHOD' => 'PUT',
|
|
||||||
'CONTENT_TYPE' => 'application/json'
|
|
||||||
]);
|
|
||||||
|
|
||||||
$request = Request::createFromEnvironment($env);
|
|
||||||
$request = $request->withParsedBody($link);
|
|
||||||
$response = $this->controller->putLink($request, new Response(), ['id' => $id]);
|
|
||||||
|
|
||||||
$this->assertEquals(200, $response->getStatusCode());
|
|
||||||
$data = json_decode((string) $response->getBody(), true);
|
|
||||||
$this->assertEquals(self::NB_FIELDS_LINK, count($data));
|
|
||||||
$this->assertEquals(['one', 'two'], $data['tags']);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test link creation with a tag string provided
|
|
||||||
*/
|
|
||||||
public function testPutLinkWithTagString2(): void
|
|
||||||
{
|
|
||||||
$link = [
|
|
||||||
'tags' => ['one two'],
|
|
||||||
];
|
|
||||||
$id = '41';
|
|
||||||
$env = Environment::mock([
|
|
||||||
'REQUEST_METHOD' => 'PUT',
|
|
||||||
'CONTENT_TYPE' => 'application/json'
|
|
||||||
]);
|
|
||||||
|
|
||||||
$request = Request::createFromEnvironment($env);
|
|
||||||
$request = $request->withParsedBody($link);
|
|
||||||
$response = $this->controller->putLink($request, new Response(), ['id' => $id]);
|
|
||||||
|
|
||||||
$this->assertEquals(200, $response->getStatusCode());
|
|
||||||
$data = json_decode((string) $response->getBody(), true);
|
|
||||||
$this->assertEquals(self::NB_FIELDS_LINK, count($data));
|
|
||||||
$this->assertEquals(['one', 'two'], $data['tags']);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,198 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace Shaarli\Api\Controllers;
|
|
||||||
|
|
||||||
use malkusch\lock\mutex\NoMutex;
|
|
||||||
use Shaarli\Bookmark\BookmarkFileService;
|
|
||||||
use Shaarli\Bookmark\LinkDB;
|
|
||||||
use Shaarli\Config\ConfigManager;
|
|
||||||
use Shaarli\History;
|
|
||||||
use Shaarli\Plugin\PluginManager;
|
|
||||||
use Shaarli\Tests\Utils\ReferenceHistory;
|
|
||||||
use Shaarli\Tests\Utils\ReferenceLinkDB;
|
|
||||||
use Slim\Container;
|
|
||||||
use Slim\Http\Environment;
|
|
||||||
use Slim\Http\Request;
|
|
||||||
use Slim\Http\Response;
|
|
||||||
|
|
||||||
class DeleteTagTest extends \Shaarli\TestCase
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @var string datastore to test write operations
|
|
||||||
*/
|
|
||||||
protected static $testDatastore = 'sandbox/datastore.php';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var string datastore to test write operations
|
|
||||||
*/
|
|
||||||
protected static $testHistory = 'sandbox/history.php';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var ConfigManager instance
|
|
||||||
*/
|
|
||||||
protected $conf;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var ReferenceLinkDB instance.
|
|
||||||
*/
|
|
||||||
protected $refDB = null;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var BookmarkFileService instance.
|
|
||||||
*/
|
|
||||||
protected $bookmarkService;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var HistoryController instance.
|
|
||||||
*/
|
|
||||||
protected $history;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var Container instance.
|
|
||||||
*/
|
|
||||||
protected $container;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var Tags controller instance.
|
|
||||||
*/
|
|
||||||
protected $controller;
|
|
||||||
|
|
||||||
/** @var PluginManager */
|
|
||||||
protected $pluginManager;
|
|
||||||
|
|
||||||
/** @var NoMutex */
|
|
||||||
protected $mutex;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Before each test, instantiate a new Api with its config, plugins and bookmarks.
|
|
||||||
*/
|
|
||||||
protected function setUp(): void
|
|
||||||
{
|
|
||||||
$this->mutex = new NoMutex();
|
|
||||||
$this->conf = new ConfigManager('tests/utils/config/configJson');
|
|
||||||
$this->conf->set('resource.datastore', self::$testDatastore);
|
|
||||||
$this->refDB = new ReferenceLinkDB();
|
|
||||||
$this->refDB->write(self::$testDatastore);
|
|
||||||
$refHistory = new ReferenceHistory();
|
|
||||||
$refHistory->write(self::$testHistory);
|
|
||||||
$this->history = new History(self::$testHistory);
|
|
||||||
$this->pluginManager = new PluginManager($this->conf);
|
|
||||||
$this->bookmarkService = new BookmarkFileService(
|
|
||||||
$this->conf,
|
|
||||||
$this->pluginManager,
|
|
||||||
$this->history,
|
|
||||||
$this->mutex,
|
|
||||||
true
|
|
||||||
);
|
|
||||||
|
|
||||||
$this->container = new Container();
|
|
||||||
$this->container['conf'] = $this->conf;
|
|
||||||
$this->container['db'] = $this->bookmarkService;
|
|
||||||
$this->container['history'] = $this->history;
|
|
||||||
|
|
||||||
$this->controller = new Tags($this->container);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* After each test, remove the test datastore.
|
|
||||||
*/
|
|
||||||
protected function tearDown(): void
|
|
||||||
{
|
|
||||||
@unlink(self::$testDatastore);
|
|
||||||
@unlink(self::$testHistory);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test DELETE tag endpoint: the tag should be removed.
|
|
||||||
*/
|
|
||||||
public function testDeleteTagValid()
|
|
||||||
{
|
|
||||||
$tagName = 'gnu';
|
|
||||||
$tags = $this->bookmarkService->bookmarksCountPerTag();
|
|
||||||
$this->assertTrue($tags[$tagName] > 0);
|
|
||||||
$env = Environment::mock([
|
|
||||||
'REQUEST_METHOD' => 'DELETE',
|
|
||||||
]);
|
|
||||||
$request = Request::createFromEnvironment($env);
|
|
||||||
|
|
||||||
$response = $this->controller->deleteTag($request, new Response(), ['tagName' => $tagName]);
|
|
||||||
$this->assertEquals(204, $response->getStatusCode());
|
|
||||||
$this->assertEmpty((string) $response->getBody());
|
|
||||||
|
|
||||||
$this->bookmarkService = new BookmarkFileService(
|
|
||||||
$this->conf,
|
|
||||||
$this->pluginManager,
|
|
||||||
$this->history,
|
|
||||||
$this->mutex,
|
|
||||||
true
|
|
||||||
);
|
|
||||||
$tags = $this->bookmarkService->bookmarksCountPerTag();
|
|
||||||
$this->assertFalse(isset($tags[$tagName]));
|
|
||||||
|
|
||||||
// 2 bookmarks affected
|
|
||||||
$historyEntry = $this->history->getHistory()[0];
|
|
||||||
$this->assertEquals(History::UPDATED, $historyEntry['event']);
|
|
||||||
$this->assertTrue(
|
|
||||||
(new \DateTime())->add(\DateInterval::createFromDateString('-5 seconds')) < $historyEntry['datetime']
|
|
||||||
);
|
|
||||||
$historyEntry = $this->history->getHistory()[1];
|
|
||||||
$this->assertEquals(History::UPDATED, $historyEntry['event']);
|
|
||||||
$this->assertTrue(
|
|
||||||
(new \DateTime())->add(\DateInterval::createFromDateString('-5 seconds')) < $historyEntry['datetime']
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test DELETE tag endpoint: the tag should be removed.
|
|
||||||
*/
|
|
||||||
public function testDeleteTagCaseSensitivity()
|
|
||||||
{
|
|
||||||
$tagName = 'sTuff';
|
|
||||||
$tags = $this->bookmarkService->bookmarksCountPerTag();
|
|
||||||
$this->assertTrue($tags[$tagName] > 0);
|
|
||||||
$env = Environment::mock([
|
|
||||||
'REQUEST_METHOD' => 'DELETE',
|
|
||||||
]);
|
|
||||||
$request = Request::createFromEnvironment($env);
|
|
||||||
|
|
||||||
$response = $this->controller->deleteTag($request, new Response(), ['tagName' => $tagName]);
|
|
||||||
$this->assertEquals(204, $response->getStatusCode());
|
|
||||||
$this->assertEmpty((string) $response->getBody());
|
|
||||||
|
|
||||||
$this->bookmarkService = new BookmarkFileService(
|
|
||||||
$this->conf,
|
|
||||||
$this->pluginManager,
|
|
||||||
$this->history,
|
|
||||||
$this->mutex,
|
|
||||||
true
|
|
||||||
);
|
|
||||||
$tags = $this->bookmarkService->bookmarksCountPerTag();
|
|
||||||
$this->assertFalse(isset($tags[$tagName]));
|
|
||||||
$this->assertTrue($tags[strtolower($tagName)] > 0);
|
|
||||||
|
|
||||||
$historyEntry = $this->history->getHistory()[0];
|
|
||||||
$this->assertEquals(History::UPDATED, $historyEntry['event']);
|
|
||||||
$this->assertTrue(
|
|
||||||
(new \DateTime())->add(\DateInterval::createFromDateString('-5 seconds')) < $historyEntry['datetime']
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test DELETE tag endpoint: reach not existing tag.
|
|
||||||
*/
|
|
||||||
public function testDeleteLink404()
|
|
||||||
{
|
|
||||||
$this->expectException(\Shaarli\Api\Exceptions\ApiTagNotFoundException::class);
|
|
||||||
$this->expectExceptionMessage('Tag not found');
|
|
||||||
|
|
||||||
$tagName = 'nopenope';
|
|
||||||
$tags = $this->bookmarkService->bookmarksCountPerTag();
|
|
||||||
$this->assertFalse(isset($tags[$tagName]));
|
|
||||||
$env = Environment::mock([
|
|
||||||
'REQUEST_METHOD' => 'DELETE',
|
|
||||||
]);
|
|
||||||
$request = Request::createFromEnvironment($env);
|
|
||||||
|
|
||||||
$this->controller->deleteTag($request, new Response(), ['tagName' => $tagName]);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,147 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace Shaarli\Api\Controllers;
|
|
||||||
|
|
||||||
use malkusch\lock\mutex\NoMutex;
|
|
||||||
use Shaarli\Bookmark\BookmarkFileService;
|
|
||||||
use Shaarli\Bookmark\LinkDB;
|
|
||||||
use Shaarli\Config\ConfigManager;
|
|
||||||
use Shaarli\History;
|
|
||||||
use Shaarli\Plugin\PluginManager;
|
|
||||||
use Shaarli\Tests\Utils\ReferenceLinkDB;
|
|
||||||
use Slim\Container;
|
|
||||||
use Slim\Http\Environment;
|
|
||||||
use Slim\Http\Request;
|
|
||||||
use Slim\Http\Response;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Class GetTagNameTest
|
|
||||||
*
|
|
||||||
* Test getTag by tag name API service.
|
|
||||||
*
|
|
||||||
* @package Shaarli\Api\Controllers
|
|
||||||
*/
|
|
||||||
class GetTagNameTest extends \Shaarli\TestCase
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @var string datastore to test write operations
|
|
||||||
*/
|
|
||||||
protected static $testDatastore = 'sandbox/datastore.php';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var ConfigManager instance
|
|
||||||
*/
|
|
||||||
protected $conf;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var ReferenceLinkDB instance.
|
|
||||||
*/
|
|
||||||
protected $refDB = null;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var Container instance.
|
|
||||||
*/
|
|
||||||
protected $container;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var Tags controller instance.
|
|
||||||
*/
|
|
||||||
protected $controller;
|
|
||||||
|
|
||||||
/** @var PluginManager */
|
|
||||||
protected $pluginManager;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Number of JSON fields per link.
|
|
||||||
*/
|
|
||||||
protected const NB_FIELDS_TAG = 2;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Before each test, instantiate a new Api with its config, plugins and bookmarks.
|
|
||||||
*/
|
|
||||||
protected function setUp(): void
|
|
||||||
{
|
|
||||||
$mutex = new NoMutex();
|
|
||||||
$this->conf = new ConfigManager('tests/utils/config/configJson');
|
|
||||||
$this->conf->set('resource.datastore', self::$testDatastore);
|
|
||||||
$this->refDB = new ReferenceLinkDB();
|
|
||||||
$this->refDB->write(self::$testDatastore);
|
|
||||||
$history = new History('sandbox/history.php');
|
|
||||||
|
|
||||||
$this->container = new Container();
|
|
||||||
$this->container['conf'] = $this->conf;
|
|
||||||
$this->pluginManager = new PluginManager($this->conf);
|
|
||||||
$this->container['db'] = new BookmarkFileService(
|
|
||||||
$this->conf,
|
|
||||||
$this->pluginManager,
|
|
||||||
$history,
|
|
||||||
$mutex,
|
|
||||||
true
|
|
||||||
);
|
|
||||||
$this->container['history'] = null;
|
|
||||||
|
|
||||||
$this->controller = new Tags($this->container);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* After each test, remove the test datastore.
|
|
||||||
*/
|
|
||||||
protected function tearDown(): void
|
|
||||||
{
|
|
||||||
@unlink(self::$testDatastore);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test basic getTag service: return gnu tag with 2 occurrences.
|
|
||||||
*/
|
|
||||||
public function testGetTag()
|
|
||||||
{
|
|
||||||
$tagName = 'gnu';
|
|
||||||
$env = Environment::mock([
|
|
||||||
'REQUEST_METHOD' => 'GET',
|
|
||||||
]);
|
|
||||||
$request = Request::createFromEnvironment($env);
|
|
||||||
|
|
||||||
$response = $this->controller->getTag($request, new Response(), ['tagName' => $tagName]);
|
|
||||||
$this->assertEquals(200, $response->getStatusCode());
|
|
||||||
$data = json_decode((string) $response->getBody(), true);
|
|
||||||
$this->assertEquals(self::NB_FIELDS_TAG, count($data));
|
|
||||||
$this->assertEquals($tagName, $data['name']);
|
|
||||||
$this->assertEquals(2, $data['occurrences']);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test getTag service which is not case sensitive: occurrences with both sTuff and stuff
|
|
||||||
*/
|
|
||||||
public function testGetTagNotCaseSensitive()
|
|
||||||
{
|
|
||||||
$tagName = 'sTuff';
|
|
||||||
$env = Environment::mock([
|
|
||||||
'REQUEST_METHOD' => 'GET',
|
|
||||||
]);
|
|
||||||
$request = Request::createFromEnvironment($env);
|
|
||||||
|
|
||||||
$response = $this->controller->getTag($request, new Response(), ['tagName' => $tagName]);
|
|
||||||
$this->assertEquals(200, $response->getStatusCode());
|
|
||||||
$data = json_decode((string) $response->getBody(), true);
|
|
||||||
$this->assertEquals(self::NB_FIELDS_TAG, count($data));
|
|
||||||
$this->assertEquals($tagName, $data['name']);
|
|
||||||
$this->assertEquals(2, $data['occurrences']);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test basic getTag service: get non existent tag => ApiTagNotFoundException.
|
|
||||||
*/
|
|
||||||
public function testGetTag404()
|
|
||||||
{
|
|
||||||
$this->expectException(\Shaarli\Api\Exceptions\ApiTagNotFoundException::class);
|
|
||||||
$this->expectExceptionMessage('Tag not found');
|
|
||||||
|
|
||||||
$env = Environment::mock([
|
|
||||||
'REQUEST_METHOD' => 'GET',
|
|
||||||
]);
|
|
||||||
$request = Request::createFromEnvironment($env);
|
|
||||||
|
|
||||||
$this->controller->getTag($request, new Response(), ['tagName' => 'nopenope']);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,227 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace Shaarli\Api\Controllers;
|
|
||||||
|
|
||||||
use malkusch\lock\mutex\NoMutex;
|
|
||||||
use Shaarli\Bookmark\BookmarkFileService;
|
|
||||||
use Shaarli\Bookmark\LinkDB;
|
|
||||||
use Shaarli\Config\ConfigManager;
|
|
||||||
use Shaarli\History;
|
|
||||||
use Shaarli\Plugin\PluginManager;
|
|
||||||
use Shaarli\Tests\Utils\ReferenceLinkDB;
|
|
||||||
use Slim\Container;
|
|
||||||
use Slim\Http\Environment;
|
|
||||||
use Slim\Http\Request;
|
|
||||||
use Slim\Http\Response;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Class GetTagsTest
|
|
||||||
*
|
|
||||||
* Test get tag list REST API service.
|
|
||||||
*
|
|
||||||
* @package Shaarli\Api\Controllers
|
|
||||||
*/
|
|
||||||
class GetTagsTest extends \Shaarli\TestCase
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @var string datastore to test write operations
|
|
||||||
*/
|
|
||||||
protected static $testDatastore = 'sandbox/datastore.php';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var ConfigManager instance
|
|
||||||
*/
|
|
||||||
protected $conf;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var ReferenceLinkDB instance.
|
|
||||||
*/
|
|
||||||
protected $refDB = null;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var Container instance.
|
|
||||||
*/
|
|
||||||
protected $container;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var BookmarkFileService instance.
|
|
||||||
*/
|
|
||||||
protected $bookmarkService;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var Tags controller instance.
|
|
||||||
*/
|
|
||||||
protected $controller;
|
|
||||||
|
|
||||||
/** @var PluginManager */
|
|
||||||
protected $pluginManager;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Number of JSON field per link.
|
|
||||||
*/
|
|
||||||
protected const NB_FIELDS_TAG = 2;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Before every test, instantiate a new Api with its config, plugins and bookmarks.
|
|
||||||
*/
|
|
||||||
protected function setUp(): void
|
|
||||||
{
|
|
||||||
$mutex = new NoMutex();
|
|
||||||
$this->conf = new ConfigManager('tests/utils/config/configJson');
|
|
||||||
$this->conf->set('resource.datastore', self::$testDatastore);
|
|
||||||
$this->refDB = new ReferenceLinkDB();
|
|
||||||
$this->refDB->write(self::$testDatastore);
|
|
||||||
$history = new History('sandbox/history.php');
|
|
||||||
$this->pluginManager = new PluginManager($this->conf);
|
|
||||||
$this->bookmarkService = new BookmarkFileService(
|
|
||||||
$this->conf,
|
|
||||||
$this->pluginManager,
|
|
||||||
$history,
|
|
||||||
$mutex,
|
|
||||||
true
|
|
||||||
);
|
|
||||||
$this->container = new Container();
|
|
||||||
$this->container['conf'] = $this->conf;
|
|
||||||
$this->container['db'] = $this->bookmarkService;
|
|
||||||
$this->container['history'] = null;
|
|
||||||
|
|
||||||
$this->controller = new Tags($this->container);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* After every test, remove the test datastore.
|
|
||||||
*/
|
|
||||||
protected function tearDown(): void
|
|
||||||
{
|
|
||||||
@unlink(self::$testDatastore);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test basic getTags service: returns all tags.
|
|
||||||
*/
|
|
||||||
public function testGetTagsAll()
|
|
||||||
{
|
|
||||||
$tags = $this->bookmarkService->bookmarksCountPerTag();
|
|
||||||
$env = Environment::mock([
|
|
||||||
'REQUEST_METHOD' => 'GET',
|
|
||||||
]);
|
|
||||||
$request = Request::createFromEnvironment($env);
|
|
||||||
|
|
||||||
$response = $this->controller->getTags($request, new Response());
|
|
||||||
$this->assertEquals(200, $response->getStatusCode());
|
|
||||||
$data = json_decode((string) $response->getBody(), true);
|
|
||||||
$this->assertEquals(count($tags), count($data));
|
|
||||||
|
|
||||||
// Check order
|
|
||||||
$this->assertEquals(self::NB_FIELDS_TAG, count($data[0]));
|
|
||||||
$this->assertEquals('web', $data[0]['name']);
|
|
||||||
$this->assertEquals(4, $data[0]['occurrences']);
|
|
||||||
$this->assertEquals(self::NB_FIELDS_TAG, count($data[1]));
|
|
||||||
$this->assertEquals('cartoon', $data[1]['name']);
|
|
||||||
$this->assertEquals(3, $data[1]['occurrences']);
|
|
||||||
// Case insensitive
|
|
||||||
$this->assertEquals(self::NB_FIELDS_TAG, count($data[5]));
|
|
||||||
$this->assertEquals('sTuff', $data[5]['name']);
|
|
||||||
$this->assertEquals(2, $data[5]['occurrences']);
|
|
||||||
// End
|
|
||||||
$this->assertEquals(self::NB_FIELDS_TAG, count($data[count($data) - 1]));
|
|
||||||
$this->assertEquals('w3c', $data[count($data) - 1]['name']);
|
|
||||||
$this->assertEquals(1, $data[count($data) - 1]['occurrences']);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test getTags service with offset and limit parameter:
|
|
||||||
* limit=1 and offset=1 should return only the second tag, cartoon with 3 occurrences
|
|
||||||
*/
|
|
||||||
public function testGetTagsOffsetLimit()
|
|
||||||
{
|
|
||||||
$env = Environment::mock([
|
|
||||||
'REQUEST_METHOD' => 'GET',
|
|
||||||
'QUERY_STRING' => 'offset=1&limit=1'
|
|
||||||
]);
|
|
||||||
$request = Request::createFromEnvironment($env);
|
|
||||||
$response = $this->controller->getTags($request, new Response());
|
|
||||||
$this->assertEquals(200, $response->getStatusCode());
|
|
||||||
$data = json_decode((string) $response->getBody(), true);
|
|
||||||
$this->assertEquals(1, count($data));
|
|
||||||
$this->assertEquals(self::NB_FIELDS_TAG, count($data[0]));
|
|
||||||
$this->assertEquals('cartoon', $data[0]['name']);
|
|
||||||
$this->assertEquals(3, $data[0]['occurrences']);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test getTags with limit=all (return all tags).
|
|
||||||
*/
|
|
||||||
public function testGetTagsLimitAll()
|
|
||||||
{
|
|
||||||
$tags = $this->bookmarkService->bookmarksCountPerTag();
|
|
||||||
$env = Environment::mock([
|
|
||||||
'REQUEST_METHOD' => 'GET',
|
|
||||||
'QUERY_STRING' => 'limit=all'
|
|
||||||
]);
|
|
||||||
$request = Request::createFromEnvironment($env);
|
|
||||||
$response = $this->controller->getTags($request, new Response());
|
|
||||||
$this->assertEquals(200, $response->getStatusCode());
|
|
||||||
$data = json_decode((string) $response->getBody(), true);
|
|
||||||
$this->assertEquals(count($tags), count($data));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test getTags service with offset and limit parameter:
|
|
||||||
* limit=1 and offset=1 should not return any tag
|
|
||||||
*/
|
|
||||||
public function testGetTagsOffsetTooHigh()
|
|
||||||
{
|
|
||||||
$env = Environment::mock([
|
|
||||||
'REQUEST_METHOD' => 'GET',
|
|
||||||
'QUERY_STRING' => 'offset=100'
|
|
||||||
]);
|
|
||||||
$request = Request::createFromEnvironment($env);
|
|
||||||
$response = $this->controller->getTags($request, new Response());
|
|
||||||
$this->assertEquals(200, $response->getStatusCode());
|
|
||||||
$data = json_decode((string) $response->getBody(), true);
|
|
||||||
$this->assertEmpty(count($data));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test getTags with visibility parameter set to private
|
|
||||||
*/
|
|
||||||
public function testGetTagsVisibilityPrivate()
|
|
||||||
{
|
|
||||||
$tags = $this->bookmarkService->bookmarksCountPerTag([], 'private');
|
|
||||||
$env = Environment::mock([
|
|
||||||
'REQUEST_METHOD' => 'GET',
|
|
||||||
'QUERY_STRING' => 'visibility=private'
|
|
||||||
]);
|
|
||||||
$request = Request::createFromEnvironment($env);
|
|
||||||
$response = $this->controller->getTags($request, new Response());
|
|
||||||
$this->assertEquals(200, $response->getStatusCode());
|
|
||||||
$data = json_decode((string) $response->getBody(), true);
|
|
||||||
$this->assertEquals(count($tags), count($data));
|
|
||||||
$this->assertEquals(self::NB_FIELDS_TAG, count($data[0]));
|
|
||||||
$this->assertEquals('Mercurial', $data[0]['name']);
|
|
||||||
$this->assertEquals(1, $data[0]['occurrences']);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test getTags with visibility parameter set to public
|
|
||||||
*/
|
|
||||||
public function testGetTagsVisibilityPublic()
|
|
||||||
{
|
|
||||||
$tags = $this->bookmarkService->bookmarksCountPerTag([], 'public');
|
|
||||||
$env = Environment::mock(
|
|
||||||
[
|
|
||||||
'REQUEST_METHOD' => 'GET',
|
|
||||||
'QUERY_STRING' => 'visibility=public'
|
|
||||||
]
|
|
||||||
);
|
|
||||||
$request = Request::createFromEnvironment($env);
|
|
||||||
$response = $this->controller->getTags($request, new Response());
|
|
||||||
$this->assertEquals(200, $response->getStatusCode());
|
|
||||||
$data = json_decode((string)$response->getBody(), true);
|
|
||||||
$this->assertEquals(count($tags), count($data));
|
|
||||||
$this->assertEquals(self::NB_FIELDS_TAG, count($data[0]));
|
|
||||||
$this->assertEquals('web', $data[0]['name']);
|
|
||||||
$this->assertEquals(3, $data[0]['occurrences']);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,225 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace Shaarli\Api\Controllers;
|
|
||||||
|
|
||||||
use malkusch\lock\mutex\NoMutex;
|
|
||||||
use Shaarli\Api\Exceptions\ApiBadParametersException;
|
|
||||||
use Shaarli\Bookmark\BookmarkFileService;
|
|
||||||
use Shaarli\Bookmark\LinkDB;
|
|
||||||
use Shaarli\Config\ConfigManager;
|
|
||||||
use Shaarli\History;
|
|
||||||
use Shaarli\Plugin\PluginManager;
|
|
||||||
use Shaarli\Tests\Utils\ReferenceHistory;
|
|
||||||
use Shaarli\Tests\Utils\ReferenceLinkDB;
|
|
||||||
use Slim\Container;
|
|
||||||
use Slim\Http\Environment;
|
|
||||||
use Slim\Http\Request;
|
|
||||||
use Slim\Http\Response;
|
|
||||||
|
|
||||||
class PutTagTest extends \Shaarli\TestCase
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @var string datastore to test write operations
|
|
||||||
*/
|
|
||||||
protected static $testDatastore = 'sandbox/datastore.php';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var string datastore to test write operations
|
|
||||||
*/
|
|
||||||
protected static $testHistory = 'sandbox/history.php';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var ConfigManager instance
|
|
||||||
*/
|
|
||||||
protected $conf;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var ReferenceLinkDB instance.
|
|
||||||
*/
|
|
||||||
protected $refDB = null;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var HistoryController instance.
|
|
||||||
*/
|
|
||||||
protected $history;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var Container instance.
|
|
||||||
*/
|
|
||||||
protected $container;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var BookmarkFileService instance.
|
|
||||||
*/
|
|
||||||
protected $bookmarkService;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var Tags controller instance.
|
|
||||||
*/
|
|
||||||
protected $controller;
|
|
||||||
|
|
||||||
/** @var PluginManager */
|
|
||||||
protected $pluginManager;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Number of JSON field per link.
|
|
||||||
*/
|
|
||||||
protected const NB_FIELDS_TAG = 2;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Before every test, instantiate a new Api with its config, plugins and bookmarks.
|
|
||||||
*/
|
|
||||||
protected function setUp(): void
|
|
||||||
{
|
|
||||||
$mutex = new NoMutex();
|
|
||||||
$this->conf = new ConfigManager('tests/utils/config/configJson');
|
|
||||||
$this->conf->set('resource.datastore', self::$testDatastore);
|
|
||||||
$this->refDB = new ReferenceLinkDB();
|
|
||||||
$this->refDB->write(self::$testDatastore);
|
|
||||||
$refHistory = new ReferenceHistory();
|
|
||||||
$refHistory->write(self::$testHistory);
|
|
||||||
$this->history = new History(self::$testHistory);
|
|
||||||
$this->pluginManager = new PluginManager($this->conf);
|
|
||||||
$this->bookmarkService = new BookmarkFileService(
|
|
||||||
$this->conf,
|
|
||||||
$this->pluginManager,
|
|
||||||
$this->history,
|
|
||||||
$mutex,
|
|
||||||
true
|
|
||||||
);
|
|
||||||
|
|
||||||
$this->container = new Container();
|
|
||||||
$this->container['conf'] = $this->conf;
|
|
||||||
$this->container['db'] = $this->bookmarkService;
|
|
||||||
$this->container['history'] = $this->history;
|
|
||||||
|
|
||||||
$this->controller = new Tags($this->container);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* After every test, remove the test datastore.
|
|
||||||
*/
|
|
||||||
protected function tearDown(): void
|
|
||||||
{
|
|
||||||
@unlink(self::$testDatastore);
|
|
||||||
@unlink(self::$testHistory);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test tags update
|
|
||||||
*/
|
|
||||||
public function testPutLinkValid()
|
|
||||||
{
|
|
||||||
$env = Environment::mock([
|
|
||||||
'REQUEST_METHOD' => 'PUT',
|
|
||||||
]);
|
|
||||||
$tagName = 'gnu';
|
|
||||||
$update = ['name' => $newName = 'newtag'];
|
|
||||||
$request = Request::createFromEnvironment($env);
|
|
||||||
$request = $request->withParsedBody($update);
|
|
||||||
|
|
||||||
$response = $this->controller->putTag($request, new Response(), ['tagName' => $tagName]);
|
|
||||||
$this->assertEquals(200, $response->getStatusCode());
|
|
||||||
$data = json_decode((string) $response->getBody(), true);
|
|
||||||
$this->assertEquals(self::NB_FIELDS_TAG, count($data));
|
|
||||||
$this->assertEquals($newName, $data['name']);
|
|
||||||
$this->assertEquals(2, $data['occurrences']);
|
|
||||||
|
|
||||||
$tags = $this->bookmarkService->bookmarksCountPerTag();
|
|
||||||
$this->assertNotTrue(isset($tags[$tagName]));
|
|
||||||
$this->assertEquals(2, $tags[$newName]);
|
|
||||||
|
|
||||||
$historyEntry = $this->history->getHistory()[0];
|
|
||||||
$this->assertEquals(History::UPDATED, $historyEntry['event']);
|
|
||||||
$this->assertTrue(
|
|
||||||
(new \DateTime())->add(\DateInterval::createFromDateString('-5 seconds')) < $historyEntry['datetime']
|
|
||||||
);
|
|
||||||
$historyEntry = $this->history->getHistory()[1];
|
|
||||||
$this->assertEquals(History::UPDATED, $historyEntry['event']);
|
|
||||||
$this->assertTrue(
|
|
||||||
(new \DateTime())->add(\DateInterval::createFromDateString('-5 seconds')) < $historyEntry['datetime']
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test tag update with an existing tag: they should be merged
|
|
||||||
*/
|
|
||||||
public function testPutTagMerge()
|
|
||||||
{
|
|
||||||
$tagName = 'gnu';
|
|
||||||
$newName = 'w3c';
|
|
||||||
|
|
||||||
$tags = $this->bookmarkService->bookmarksCountPerTag();
|
|
||||||
$this->assertEquals(1, $tags[$newName]);
|
|
||||||
$this->assertEquals(2, $tags[$tagName]);
|
|
||||||
|
|
||||||
$env = Environment::mock([
|
|
||||||
'REQUEST_METHOD' => 'PUT',
|
|
||||||
]);
|
|
||||||
$update = ['name' => $newName];
|
|
||||||
$request = Request::createFromEnvironment($env);
|
|
||||||
$request = $request->withParsedBody($update);
|
|
||||||
|
|
||||||
$response = $this->controller->putTag($request, new Response(), ['tagName' => $tagName]);
|
|
||||||
$this->assertEquals(200, $response->getStatusCode());
|
|
||||||
$data = json_decode((string) $response->getBody(), true);
|
|
||||||
$this->assertEquals(self::NB_FIELDS_TAG, count($data));
|
|
||||||
$this->assertEquals($newName, $data['name']);
|
|
||||||
$this->assertEquals(3, $data['occurrences']);
|
|
||||||
|
|
||||||
$tags = $this->bookmarkService->bookmarksCountPerTag();
|
|
||||||
$this->assertNotTrue(isset($tags[$tagName]));
|
|
||||||
$this->assertEquals(3, $tags[$newName]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test tag update with an empty new tag name => ApiBadParametersException
|
|
||||||
*/
|
|
||||||
public function testPutTagEmpty()
|
|
||||||
{
|
|
||||||
$this->expectException(\Shaarli\Api\Exceptions\ApiBadParametersException::class);
|
|
||||||
$this->expectExceptionMessage('New tag name is required in the request body');
|
|
||||||
|
|
||||||
$tagName = 'gnu';
|
|
||||||
$newName = '';
|
|
||||||
|
|
||||||
$tags = $this->bookmarkService->bookmarksCountPerTag();
|
|
||||||
$this->assertEquals(2, $tags[$tagName]);
|
|
||||||
|
|
||||||
$env = Environment::mock([
|
|
||||||
'REQUEST_METHOD' => 'PUT',
|
|
||||||
]);
|
|
||||||
$request = Request::createFromEnvironment($env);
|
|
||||||
|
|
||||||
$env = Environment::mock([
|
|
||||||
'REQUEST_METHOD' => 'PUT',
|
|
||||||
]);
|
|
||||||
$update = ['name' => $newName];
|
|
||||||
$request = Request::createFromEnvironment($env);
|
|
||||||
$request = $request->withParsedBody($update);
|
|
||||||
|
|
||||||
try {
|
|
||||||
$this->controller->putTag($request, new Response(), ['tagName' => $tagName]);
|
|
||||||
} catch (ApiBadParametersException $e) {
|
|
||||||
$tags = $this->bookmarkService->bookmarksCountPerTag();
|
|
||||||
$this->assertEquals(2, $tags[$tagName]);
|
|
||||||
throw $e;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test tag update on non existent tag => ApiTagNotFoundException.
|
|
||||||
*/
|
|
||||||
public function testPutTag404()
|
|
||||||
{
|
|
||||||
$this->expectException(\Shaarli\Api\Exceptions\ApiTagNotFoundException::class);
|
|
||||||
$this->expectExceptionMessage('Tag not found');
|
|
||||||
|
|
||||||
$env = Environment::mock([
|
|
||||||
'REQUEST_METHOD' => 'PUT',
|
|
||||||
]);
|
|
||||||
$request = Request::createFromEnvironment($env);
|
|
||||||
|
|
||||||
$this->controller->putTag($request, new Response(), ['tagName' => 'nopenope']);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,224 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace Shaarli\Bookmark;
|
|
||||||
|
|
||||||
use Shaarli\TestCase;
|
|
||||||
use Shaarli\Tests\Utils\ReferenceLinkDB;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Class BookmarkArrayTest
|
|
||||||
*/
|
|
||||||
class BookmarkArrayTest extends TestCase
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Test the constructor and make sure that the instance is properly initialized
|
|
||||||
*/
|
|
||||||
public function testArrayConstructorEmpty()
|
|
||||||
{
|
|
||||||
$array = new BookmarkArray();
|
|
||||||
$this->assertTrue(is_iterable($array));
|
|
||||||
$this->assertEmpty($array);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test adding entries to the array, specifying the key offset or not.
|
|
||||||
*/
|
|
||||||
public function testArrayAccessAddEntries()
|
|
||||||
{
|
|
||||||
$array = new BookmarkArray();
|
|
||||||
$bookmark = new Bookmark();
|
|
||||||
$bookmark->setId(11)->validate();
|
|
||||||
$array[] = $bookmark;
|
|
||||||
$this->assertCount(1, $array);
|
|
||||||
$this->assertTrue(isset($array[11]));
|
|
||||||
$this->assertNull($array[0]);
|
|
||||||
$this->assertEquals($bookmark, $array[11]);
|
|
||||||
|
|
||||||
$bookmark = new Bookmark();
|
|
||||||
$bookmark->setId(14)->validate();
|
|
||||||
$array[14] = $bookmark;
|
|
||||||
$this->assertCount(2, $array);
|
|
||||||
$this->assertTrue(isset($array[14]));
|
|
||||||
$this->assertNull($array[0]);
|
|
||||||
$this->assertEquals($bookmark, $array[14]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test adding a bad entry: wrong type
|
|
||||||
*/
|
|
||||||
public function testArrayAccessAddBadEntryInstance()
|
|
||||||
{
|
|
||||||
$this->expectException(\Shaarli\Bookmark\Exception\InvalidBookmarkException::class);
|
|
||||||
|
|
||||||
$array = new BookmarkArray();
|
|
||||||
$array[] = 'nope';
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test adding a bad entry: no id
|
|
||||||
*/
|
|
||||||
public function testArrayAccessAddBadEntryNoId()
|
|
||||||
{
|
|
||||||
$this->expectException(\Shaarli\Bookmark\Exception\InvalidBookmarkException::class);
|
|
||||||
|
|
||||||
$array = new BookmarkArray();
|
|
||||||
$bookmark = new Bookmark();
|
|
||||||
$array[] = $bookmark;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test adding a bad entry: no url
|
|
||||||
*/
|
|
||||||
public function testArrayAccessAddBadEntryNoUrl()
|
|
||||||
{
|
|
||||||
$this->expectException(\Shaarli\Bookmark\Exception\InvalidBookmarkException::class);
|
|
||||||
|
|
||||||
$array = new BookmarkArray();
|
|
||||||
$bookmark = (new Bookmark())->setId(11);
|
|
||||||
$array[] = $bookmark;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test adding a bad entry: invalid offset
|
|
||||||
*/
|
|
||||||
public function testArrayAccessAddBadEntryOffset()
|
|
||||||
{
|
|
||||||
$this->expectException(\Shaarli\Bookmark\Exception\InvalidBookmarkException::class);
|
|
||||||
|
|
||||||
$array = new BookmarkArray();
|
|
||||||
$bookmark = (new Bookmark())->setId(11);
|
|
||||||
$bookmark->validate();
|
|
||||||
$array['nope'] = $bookmark;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test adding a bad entry: ID/offset not consistent
|
|
||||||
*/
|
|
||||||
public function testArrayAccessAddBadEntryIdOffset()
|
|
||||||
{
|
|
||||||
$this->expectException(\Shaarli\Bookmark\Exception\InvalidBookmarkException::class);
|
|
||||||
|
|
||||||
$array = new BookmarkArray();
|
|
||||||
$bookmark = (new Bookmark())->setId(11);
|
|
||||||
$bookmark->validate();
|
|
||||||
$array[14] = $bookmark;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test update entries through array access.
|
|
||||||
*/
|
|
||||||
public function testArrayAccessUpdateEntries()
|
|
||||||
{
|
|
||||||
$array = new BookmarkArray();
|
|
||||||
$bookmark = new Bookmark();
|
|
||||||
$bookmark->setId(11)->validate();
|
|
||||||
$bookmark->setTitle('old');
|
|
||||||
$array[] = $bookmark;
|
|
||||||
$bookmark = new Bookmark();
|
|
||||||
$bookmark->setId(11)->validate();
|
|
||||||
$bookmark->setTitle('test');
|
|
||||||
$array[] = $bookmark;
|
|
||||||
$this->assertCount(1, $array);
|
|
||||||
$this->assertEquals('test', $array[11]->getTitle());
|
|
||||||
|
|
||||||
$bookmark = new Bookmark();
|
|
||||||
$bookmark->setId(11)->validate();
|
|
||||||
$bookmark->setTitle('test2');
|
|
||||||
$array[11] = $bookmark;
|
|
||||||
$this->assertCount(1, $array);
|
|
||||||
$this->assertEquals('test2', $array[11]->getTitle());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test delete entries through array access.
|
|
||||||
*/
|
|
||||||
public function testArrayAccessDeleteEntries()
|
|
||||||
{
|
|
||||||
$array = new BookmarkArray();
|
|
||||||
$bookmark11 = new Bookmark();
|
|
||||||
$bookmark11->setId(11)->validate();
|
|
||||||
$array[] = $bookmark11;
|
|
||||||
$bookmark14 = new Bookmark();
|
|
||||||
$bookmark14->setId(14)->validate();
|
|
||||||
$array[] = $bookmark14;
|
|
||||||
$bookmark23 = new Bookmark();
|
|
||||||
$bookmark23->setId(23)->validate();
|
|
||||||
$array[] = $bookmark23;
|
|
||||||
$bookmark0 = new Bookmark();
|
|
||||||
$bookmark0->setId(0)->validate();
|
|
||||||
$array[] = $bookmark0;
|
|
||||||
$this->assertCount(4, $array);
|
|
||||||
|
|
||||||
unset($array[14]);
|
|
||||||
$this->assertCount(3, $array);
|
|
||||||
$this->assertEquals($bookmark11, $array[11]);
|
|
||||||
$this->assertEquals($bookmark23, $array[23]);
|
|
||||||
$this->assertEquals($bookmark0, $array[0]);
|
|
||||||
|
|
||||||
unset($array[23]);
|
|
||||||
$this->assertCount(2, $array);
|
|
||||||
$this->assertEquals($bookmark11, $array[11]);
|
|
||||||
$this->assertEquals($bookmark0, $array[0]);
|
|
||||||
|
|
||||||
unset($array[11]);
|
|
||||||
$this->assertCount(1, $array);
|
|
||||||
$this->assertEquals($bookmark0, $array[0]);
|
|
||||||
|
|
||||||
unset($array[0]);
|
|
||||||
$this->assertCount(0, $array);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test iterating through array access.
|
|
||||||
*/
|
|
||||||
public function testArrayAccessIterate()
|
|
||||||
{
|
|
||||||
$array = new BookmarkArray();
|
|
||||||
$bookmark11 = new Bookmark();
|
|
||||||
$bookmark11->setId(11)->validate();
|
|
||||||
$array[] = $bookmark11;
|
|
||||||
$bookmark14 = new Bookmark();
|
|
||||||
$bookmark14->setId(14)->validate();
|
|
||||||
$array[] = $bookmark14;
|
|
||||||
$bookmark23 = new Bookmark();
|
|
||||||
$bookmark23->setId(23)->validate();
|
|
||||||
$array[] = $bookmark23;
|
|
||||||
$this->assertCount(3, $array);
|
|
||||||
|
|
||||||
foreach ($array as $id => $bookmark) {
|
|
||||||
$this->assertEquals(${'bookmark' . $id}, $bookmark);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test reordering the array.
|
|
||||||
*/
|
|
||||||
public function testReorder()
|
|
||||||
{
|
|
||||||
$refDB = new ReferenceLinkDB();
|
|
||||||
$refDB->write('sandbox/datastore.php');
|
|
||||||
|
|
||||||
|
|
||||||
$bookmarks = $refDB->getLinks();
|
|
||||||
$bookmarks->reorder('ASC');
|
|
||||||
$this->assertInstanceOf(BookmarkArray::class, $bookmarks);
|
|
||||||
|
|
||||||
$stickyIds = [11, 10];
|
|
||||||
$standardIds = [42, 4, 9, 1, 0, 7, 6, 8, 41];
|
|
||||||
$linkIds = array_merge($stickyIds, $standardIds);
|
|
||||||
$cpt = 0;
|
|
||||||
foreach ($bookmarks as $key => $value) {
|
|
||||||
$this->assertEquals($linkIds[$cpt++], $key);
|
|
||||||
}
|
|
||||||
|
|
||||||
$bookmarks = $refDB->getLinks();
|
|
||||||
$bookmarks->reorder('DESC');
|
|
||||||
$this->assertInstanceOf(BookmarkArray::class, $bookmarks);
|
|
||||||
|
|
||||||
$linkIds = array_merge(array_reverse($stickyIds), array_reverse($standardIds));
|
|
||||||
$cpt = 0;
|
|
||||||
foreach ($bookmarks as $key => $value) {
|
|
||||||
$this->assertEquals($linkIds[$cpt++], $key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,554 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace Shaarli\Bookmark;
|
|
||||||
|
|
||||||
use malkusch\lock\mutex\NoMutex;
|
|
||||||
use Shaarli\Config\ConfigManager;
|
|
||||||
use Shaarli\History;
|
|
||||||
use Shaarli\Plugin\PluginManager;
|
|
||||||
use Shaarli\TestCase;
|
|
||||||
use Shaarli\Tests\Utils\FakeBookmarkService;
|
|
||||||
use Shaarli\Tests\Utils\ReferenceLinkDB;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Class BookmarkFilterTest.
|
|
||||||
*/
|
|
||||||
class BookmarkFilterTest extends TestCase
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @var string Test datastore path.
|
|
||||||
*/
|
|
||||||
protected static $testDatastore = 'sandbox/datastore.php';
|
|
||||||
/**
|
|
||||||
* @var BookmarkFilter instance.
|
|
||||||
*/
|
|
||||||
protected static $linkFilter;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var ReferenceLinkDB instance
|
|
||||||
*/
|
|
||||||
protected static $refDB;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var BookmarkFileService instance
|
|
||||||
*/
|
|
||||||
protected static $bookmarkService;
|
|
||||||
|
|
||||||
/** @var PluginManager */
|
|
||||||
protected static $pluginManager;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Instantiate linkFilter with ReferenceLinkDB data.
|
|
||||||
*/
|
|
||||||
public static function setUpBeforeClass(): void
|
|
||||||
{
|
|
||||||
|
|
||||||
$mutex = new NoMutex();
|
|
||||||
$conf = new ConfigManager('tests/utils/config/configJson');
|
|
||||||
$conf->set('resource.datastore', self::$testDatastore);
|
|
||||||
static::$pluginManager = new PluginManager($conf);
|
|
||||||
self::$refDB = new ReferenceLinkDB();
|
|
||||||
self::$refDB->write(self::$testDatastore);
|
|
||||||
$history = new History('sandbox/history.php');
|
|
||||||
self::$bookmarkService = new FakeBookmarkService($conf, static::$pluginManager, $history, $mutex, true);
|
|
||||||
self::$linkFilter = new BookmarkFilter(self::$bookmarkService->getBookmarks(), $conf, static::$pluginManager);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Blank filter.
|
|
||||||
*/
|
|
||||||
public function testFilter()
|
|
||||||
{
|
|
||||||
$this->assertEquals(
|
|
||||||
self::$refDB->countLinks(),
|
|
||||||
count(self::$linkFilter->filter('', ''))
|
|
||||||
);
|
|
||||||
|
|
||||||
$this->assertEquals(
|
|
||||||
self::$refDB->countLinks(),
|
|
||||||
count(self::$linkFilter->filter('', '', 'all'))
|
|
||||||
);
|
|
||||||
|
|
||||||
$this->assertEquals(
|
|
||||||
self::$refDB->countLinks(),
|
|
||||||
count(self::$linkFilter->filter('', '', 'randomstr'))
|
|
||||||
);
|
|
||||||
|
|
||||||
// Private only.
|
|
||||||
$this->assertEquals(
|
|
||||||
self::$refDB->countPrivateLinks(),
|
|
||||||
count(self::$linkFilter->filter('', '', false, 'private'))
|
|
||||||
);
|
|
||||||
|
|
||||||
// Public only.
|
|
||||||
$this->assertEquals(
|
|
||||||
self::$refDB->countPublicLinks(),
|
|
||||||
count(self::$linkFilter->filter('', '', false, 'public'))
|
|
||||||
);
|
|
||||||
|
|
||||||
$this->assertEquals(
|
|
||||||
ReferenceLinkDB::$NB_LINKS_TOTAL,
|
|
||||||
count(self::$linkFilter->filter(BookmarkFilter::$FILTER_TAG, ''))
|
|
||||||
);
|
|
||||||
|
|
||||||
$this->assertEquals(
|
|
||||||
self::$refDB->countUntaggedLinks(),
|
|
||||||
count(
|
|
||||||
self::$linkFilter->filter(
|
|
||||||
BookmarkFilter::$FILTER_TAG,
|
|
||||||
/*$request=*/
|
|
||||||
'',
|
|
||||||
/*$casesensitive=*/
|
|
||||||
false,
|
|
||||||
/*$visibility=*/
|
|
||||||
'all',
|
|
||||||
/*$untaggedonly=*/
|
|
||||||
true
|
|
||||||
)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
$this->assertEquals(
|
|
||||||
ReferenceLinkDB::$NB_LINKS_TOTAL,
|
|
||||||
count(self::$linkFilter->filter(BookmarkFilter::$FILTER_TEXT, ''))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Filter bookmarks using a tag
|
|
||||||
*/
|
|
||||||
public function testFilterOneTag()
|
|
||||||
{
|
|
||||||
$this->assertEquals(
|
|
||||||
4,
|
|
||||||
count(self::$linkFilter->filter(BookmarkFilter::$FILTER_TAG, 'web', false))
|
|
||||||
);
|
|
||||||
|
|
||||||
$this->assertEquals(
|
|
||||||
4,
|
|
||||||
count(self::$linkFilter->filter(BookmarkFilter::$FILTER_TAG, '+web', false))
|
|
||||||
);
|
|
||||||
|
|
||||||
$this->assertEquals(
|
|
||||||
4,
|
|
||||||
count(self::$linkFilter->filter(BookmarkFilter::$FILTER_TAG, 'web', false, 'all'))
|
|
||||||
);
|
|
||||||
|
|
||||||
$this->assertEquals(
|
|
||||||
4,
|
|
||||||
count(self::$linkFilter->filter(BookmarkFilter::$FILTER_TAG, 'web', false, 'default-blabla'))
|
|
||||||
);
|
|
||||||
|
|
||||||
// Private only.
|
|
||||||
$this->assertEquals(
|
|
||||||
1,
|
|
||||||
count(self::$linkFilter->filter(BookmarkFilter::$FILTER_TAG, 'web', false, 'private'))
|
|
||||||
);
|
|
||||||
|
|
||||||
// Public only.
|
|
||||||
$this->assertEquals(
|
|
||||||
3,
|
|
||||||
count(self::$linkFilter->filter(BookmarkFilter::$FILTER_TAG, 'web', false, 'public'))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Filter bookmarks using a tag - case-sensitive
|
|
||||||
*/
|
|
||||||
public function testFilterCaseSensitiveTag()
|
|
||||||
{
|
|
||||||
$this->assertEquals(
|
|
||||||
0,
|
|
||||||
count(self::$linkFilter->filter(BookmarkFilter::$FILTER_TAG, 'mercurial', true))
|
|
||||||
);
|
|
||||||
|
|
||||||
$this->assertEquals(
|
|
||||||
1,
|
|
||||||
count(self::$linkFilter->filter(BookmarkFilter::$FILTER_TAG, 'Mercurial', true))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Filter bookmarks using a tag combination
|
|
||||||
*/
|
|
||||||
public function testFilterMultipleTags()
|
|
||||||
{
|
|
||||||
$this->assertEquals(
|
|
||||||
2,
|
|
||||||
count(self::$linkFilter->filter(BookmarkFilter::$FILTER_TAG, 'dev cartoon', false))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Filter bookmarks using a non-existent tag
|
|
||||||
*/
|
|
||||||
public function testFilterUnknownTag()
|
|
||||||
{
|
|
||||||
$this->assertEquals(
|
|
||||||
0,
|
|
||||||
count(self::$linkFilter->filter(BookmarkFilter::$FILTER_TAG, 'null', false))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieve a link entry with its hash
|
|
||||||
*/
|
|
||||||
public function testFilterSmallHash()
|
|
||||||
{
|
|
||||||
$links = self::$linkFilter->filter(BookmarkFilter::$FILTER_HASH, 'IuWvgA');
|
|
||||||
|
|
||||||
$this->assertEquals(
|
|
||||||
1,
|
|
||||||
count($links)
|
|
||||||
);
|
|
||||||
|
|
||||||
$this->assertEquals(
|
|
||||||
'MediaGoblin',
|
|
||||||
$links[7]->getTitle()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* No link for this hash
|
|
||||||
*/
|
|
||||||
public function testFilterUnknownSmallHash()
|
|
||||||
{
|
|
||||||
$this->expectException(\Shaarli\Bookmark\Exception\BookmarkNotFoundException::class);
|
|
||||||
|
|
||||||
self::$linkFilter->filter(BookmarkFilter::$FILTER_HASH, 'Iblaah');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Full-text search - no result found.
|
|
||||||
*/
|
|
||||||
public function testFilterFullTextNoResult()
|
|
||||||
{
|
|
||||||
$this->assertEquals(
|
|
||||||
0,
|
|
||||||
count(self::$linkFilter->filter(BookmarkFilter::$FILTER_TEXT, 'azertyuiop'))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Full-text search - result from a link's URL
|
|
||||||
*/
|
|
||||||
public function testFilterFullTextURL()
|
|
||||||
{
|
|
||||||
$this->assertEquals(
|
|
||||||
2,
|
|
||||||
count(self::$linkFilter->filter(BookmarkFilter::$FILTER_TEXT, 'ars.userfriendly.org'))
|
|
||||||
);
|
|
||||||
|
|
||||||
$this->assertEquals(
|
|
||||||
2,
|
|
||||||
count(self::$linkFilter->filter(BookmarkFilter::$FILTER_TEXT, 'ars org'))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Full-text search - result from a link's title only
|
|
||||||
*/
|
|
||||||
public function testFilterFullTextTitle()
|
|
||||||
{
|
|
||||||
// use miscellaneous cases
|
|
||||||
$this->assertEquals(
|
|
||||||
2,
|
|
||||||
count(self::$linkFilter->filter(BookmarkFilter::$FILTER_TEXT, 'userfriendly -'))
|
|
||||||
);
|
|
||||||
$this->assertEquals(
|
|
||||||
2,
|
|
||||||
count(self::$linkFilter->filter(BookmarkFilter::$FILTER_TEXT, 'UserFriendly -'))
|
|
||||||
);
|
|
||||||
$this->assertEquals(
|
|
||||||
2,
|
|
||||||
count(self::$linkFilter->filter(BookmarkFilter::$FILTER_TEXT, 'uSeRFrIendlY -'))
|
|
||||||
);
|
|
||||||
|
|
||||||
// use miscellaneous case and offset
|
|
||||||
$this->assertEquals(
|
|
||||||
2,
|
|
||||||
count(self::$linkFilter->filter(BookmarkFilter::$FILTER_TEXT, 'RFrIendL'))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Full-text search - result from the link's description only
|
|
||||||
*/
|
|
||||||
public function testFilterFullTextDescription()
|
|
||||||
{
|
|
||||||
$this->assertEquals(
|
|
||||||
1,
|
|
||||||
count(self::$linkFilter->filter(BookmarkFilter::$FILTER_TEXT, 'publishing media'))
|
|
||||||
);
|
|
||||||
|
|
||||||
$this->assertEquals(
|
|
||||||
1,
|
|
||||||
count(self::$linkFilter->filter(BookmarkFilter::$FILTER_TEXT, 'mercurial w3c'))
|
|
||||||
);
|
|
||||||
|
|
||||||
$this->assertEquals(
|
|
||||||
3,
|
|
||||||
count(self::$linkFilter->filter(BookmarkFilter::$FILTER_TEXT, '"free software"'))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Full-text search - result from the link's tags only
|
|
||||||
*/
|
|
||||||
public function testFilterFullTextTags()
|
|
||||||
{
|
|
||||||
$this->assertEquals(
|
|
||||||
6,
|
|
||||||
count(self::$linkFilter->filter(BookmarkFilter::$FILTER_TEXT, 'web'))
|
|
||||||
);
|
|
||||||
|
|
||||||
$this->assertEquals(
|
|
||||||
6,
|
|
||||||
count(self::$linkFilter->filter(BookmarkFilter::$FILTER_TEXT, 'web', 'all'))
|
|
||||||
);
|
|
||||||
|
|
||||||
$this->assertEquals(
|
|
||||||
6,
|
|
||||||
count(self::$linkFilter->filter(BookmarkFilter::$FILTER_TEXT, 'web', 'bla'))
|
|
||||||
);
|
|
||||||
|
|
||||||
// Private only.
|
|
||||||
$this->assertEquals(
|
|
||||||
1,
|
|
||||||
count(self::$linkFilter->filter(BookmarkFilter::$FILTER_TEXT, 'web', false, 'private'))
|
|
||||||
);
|
|
||||||
|
|
||||||
// Public only.
|
|
||||||
$this->assertEquals(
|
|
||||||
5,
|
|
||||||
count(self::$linkFilter->filter(BookmarkFilter::$FILTER_TEXT, 'web', false, 'public'))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Full-text search - result set from mixed sources
|
|
||||||
*/
|
|
||||||
public function testFilterFullTextMixed()
|
|
||||||
{
|
|
||||||
$this->assertEquals(
|
|
||||||
3,
|
|
||||||
count(self::$linkFilter->filter(BookmarkFilter::$FILTER_TEXT, 'free software'))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Full-text search - test exclusion with '-'.
|
|
||||||
*/
|
|
||||||
public function testExcludeSearch()
|
|
||||||
{
|
|
||||||
$this->assertEquals(
|
|
||||||
1,
|
|
||||||
count(self::$linkFilter->filter(BookmarkFilter::$FILTER_TEXT, 'free -gnu'))
|
|
||||||
);
|
|
||||||
|
|
||||||
$this->assertEquals(
|
|
||||||
ReferenceLinkDB::$NB_LINKS_TOTAL - 1,
|
|
||||||
count(self::$linkFilter->filter(BookmarkFilter::$FILTER_TEXT, '-revolution'))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Full-text search - test AND, exact terms and exclusion combined, across fields.
|
|
||||||
*/
|
|
||||||
public function testMultiSearch()
|
|
||||||
{
|
|
||||||
$this->assertEquals(
|
|
||||||
2,
|
|
||||||
count(self::$linkFilter->filter(
|
|
||||||
BookmarkFilter::$FILTER_TEXT,
|
|
||||||
'"Free Software " stallman "read this" @website stuff'
|
|
||||||
))
|
|
||||||
);
|
|
||||||
|
|
||||||
$this->assertEquals(
|
|
||||||
1,
|
|
||||||
count(self::$linkFilter->filter(
|
|
||||||
BookmarkFilter::$FILTER_TEXT,
|
|
||||||
'"free software " stallman "read this" -beard @website stuff'
|
|
||||||
))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Full-text search - make sure that exact search won't work across fields.
|
|
||||||
*/
|
|
||||||
public function testSearchExactTermMultiFieldsKo()
|
|
||||||
{
|
|
||||||
$this->assertEquals(
|
|
||||||
0,
|
|
||||||
count(self::$linkFilter->filter(
|
|
||||||
BookmarkFilter::$FILTER_TEXT,
|
|
||||||
'"designer naming"'
|
|
||||||
))
|
|
||||||
);
|
|
||||||
|
|
||||||
$this->assertEquals(
|
|
||||||
0,
|
|
||||||
count(self::$linkFilter->filter(
|
|
||||||
BookmarkFilter::$FILTER_TEXT,
|
|
||||||
'"designernaming"'
|
|
||||||
))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tag search with exclusion.
|
|
||||||
*/
|
|
||||||
public function testTagFilterWithExclusion()
|
|
||||||
{
|
|
||||||
$this->assertEquals(
|
|
||||||
1,
|
|
||||||
count(self::$linkFilter->filter(BookmarkFilter::$FILTER_TAG, 'gnu -free'))
|
|
||||||
);
|
|
||||||
|
|
||||||
$this->assertEquals(
|
|
||||||
ReferenceLinkDB::$NB_LINKS_TOTAL - 1,
|
|
||||||
count(self::$linkFilter->filter(BookmarkFilter::$FILTER_TAG, '-free'))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test crossed search (terms + tags).
|
|
||||||
*/
|
|
||||||
public function testFilterCrossedSearch()
|
|
||||||
{
|
|
||||||
$terms = '"Free Software " stallman "read this" @website stuff';
|
|
||||||
$tags = 'free';
|
|
||||||
$this->assertEquals(
|
|
||||||
1,
|
|
||||||
count(self::$linkFilter->filter(
|
|
||||||
BookmarkFilter::$FILTER_TAG | BookmarkFilter::$FILTER_TEXT,
|
|
||||||
[$tags, $terms]
|
|
||||||
))
|
|
||||||
);
|
|
||||||
$this->assertEquals(
|
|
||||||
2,
|
|
||||||
count(self::$linkFilter->filter(
|
|
||||||
BookmarkFilter::$FILTER_TAG | BookmarkFilter::$FILTER_TEXT,
|
|
||||||
['', $terms]
|
|
||||||
))
|
|
||||||
);
|
|
||||||
$this->assertEquals(
|
|
||||||
1,
|
|
||||||
count(self::$linkFilter->filter(
|
|
||||||
BookmarkFilter::$FILTER_TAG | BookmarkFilter::$FILTER_TEXT,
|
|
||||||
[false, 'PSR-2']
|
|
||||||
))
|
|
||||||
);
|
|
||||||
$this->assertEquals(
|
|
||||||
1,
|
|
||||||
count(self::$linkFilter->filter(
|
|
||||||
BookmarkFilter::$FILTER_TAG | BookmarkFilter::$FILTER_TEXT,
|
|
||||||
[$tags, '']
|
|
||||||
))
|
|
||||||
);
|
|
||||||
$this->assertEquals(
|
|
||||||
ReferenceLinkDB::$NB_LINKS_TOTAL,
|
|
||||||
count(self::$linkFilter->filter(
|
|
||||||
BookmarkFilter::$FILTER_TAG | BookmarkFilter::$FILTER_TEXT,
|
|
||||||
''
|
|
||||||
))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tag search with OR optional tags.
|
|
||||||
*/
|
|
||||||
public function testTagFilterOr()
|
|
||||||
{
|
|
||||||
$this->assertEquals(
|
|
||||||
5,
|
|
||||||
count(self::$linkFilter->filter(BookmarkFilter::$FILTER_TAG, '~cartoon ~web'))
|
|
||||||
);
|
|
||||||
|
|
||||||
$this->assertEquals(
|
|
||||||
6,
|
|
||||||
count(self::$linkFilter->filter(BookmarkFilter::$FILTER_TAG, '~c*t*n ~st*'))
|
|
||||||
);
|
|
||||||
|
|
||||||
$this->assertEquals(
|
|
||||||
2,
|
|
||||||
count(self::$linkFilter->filter(BookmarkFilter::$FILTER_TAG, '~cartoon ~web dev'))
|
|
||||||
);
|
|
||||||
|
|
||||||
$this->assertEquals(
|
|
||||||
2,
|
|
||||||
count(self::$linkFilter->filter(BookmarkFilter::$FILTER_TAG, '~cartoon ~web +dev'))
|
|
||||||
);
|
|
||||||
|
|
||||||
$this->assertEquals(
|
|
||||||
4,
|
|
||||||
count(self::$linkFilter->filter(BookmarkFilter::$FILTER_TAG, '~cartoon ~web -samba'))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Filter bookmarks by #hashtag.
|
|
||||||
*/
|
|
||||||
public function testFilterByHashtag()
|
|
||||||
{
|
|
||||||
$hashtag = 'hashtag';
|
|
||||||
$this->assertEquals(
|
|
||||||
3,
|
|
||||||
count(self::$linkFilter->filter(
|
|
||||||
BookmarkFilter::$FILTER_TAG,
|
|
||||||
$hashtag
|
|
||||||
))
|
|
||||||
);
|
|
||||||
|
|
||||||
$hashtag = 'private';
|
|
||||||
$this->assertEquals(
|
|
||||||
1,
|
|
||||||
count(self::$linkFilter->filter(
|
|
||||||
BookmarkFilter::$FILTER_TAG,
|
|
||||||
$hashtag,
|
|
||||||
false,
|
|
||||||
'private'
|
|
||||||
))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test search result highlights in every field of bookmark reference #9.
|
|
||||||
*/
|
|
||||||
public function testFullTextSearchHighlight(): void
|
|
||||||
{
|
|
||||||
$bookmarks = self::$linkFilter->filter(
|
|
||||||
BookmarkFilter::$FILTER_TEXT,
|
|
||||||
'"psr-2" coding guide http fig "psr-2/" "This guide" basic standard. coding-style quality assurance'
|
|
||||||
);
|
|
||||||
|
|
||||||
static::assertCount(1, $bookmarks);
|
|
||||||
static::assertArrayHasKey(9, $bookmarks);
|
|
||||||
|
|
||||||
$bookmark = $bookmarks[9];
|
|
||||||
$expectedHighlights = [
|
|
||||||
'title' => [
|
|
||||||
['start' => 0, 'end' => 5], // "psr-2"
|
|
||||||
['start' => 7, 'end' => 13], // coding
|
|
||||||
['start' => 20, 'end' => 25], // guide
|
|
||||||
],
|
|
||||||
'description' => [
|
|
||||||
['start' => 0, 'end' => 10], // "This guide"
|
|
||||||
['start' => 45, 'end' => 50], // basic
|
|
||||||
['start' => 58, 'end' => 67], // standard.
|
|
||||||
],
|
|
||||||
'url' => [
|
|
||||||
['start' => 0, 'end' => 4], // http
|
|
||||||
['start' => 15, 'end' => 18], // fig
|
|
||||||
['start' => 27, 'end' => 33], // "psr-2/"
|
|
||||||
],
|
|
||||||
'tags' => [
|
|
||||||
['start' => 0, 'end' => 12], // coding-style
|
|
||||||
['start' => 23, 'end' => 30], // quality
|
|
||||||
['start' => 31, 'end' => 40], // assurance
|
|
||||||
],
|
|
||||||
];
|
|
||||||
static::assertSame($expectedHighlights, $bookmark->getAdditionalContentEntry('search_highlight'));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,185 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace Shaarli\Bookmark;
|
|
||||||
|
|
||||||
use malkusch\lock\mutex\NoMutex;
|
|
||||||
use Shaarli\Config\ConfigManager;
|
|
||||||
use Shaarli\History;
|
|
||||||
use Shaarli\Plugin\PluginManager;
|
|
||||||
use Shaarli\TestCase;
|
|
||||||
use Shaarli\Tests\Utils\ReferenceLinkDB;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Class BookmarkInitializerTest
|
|
||||||
* @package Shaarli\Bookmark
|
|
||||||
*/
|
|
||||||
class BookmarkInitializerTest extends TestCase
|
|
||||||
{
|
|
||||||
/** @var string Path of test data store */
|
|
||||||
protected static $testDatastore = 'sandbox/datastore.php';
|
|
||||||
|
|
||||||
/** @var string Path of test config file */
|
|
||||||
protected static $testConf = 'sandbox/config';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var ConfigManager instance.
|
|
||||||
*/
|
|
||||||
protected $conf;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var History instance.
|
|
||||||
*/
|
|
||||||
protected $history;
|
|
||||||
|
|
||||||
/** @var BookmarkServiceInterface instance */
|
|
||||||
protected $bookmarkService;
|
|
||||||
|
|
||||||
/** @var BookmarkInitializer instance */
|
|
||||||
protected $initializer;
|
|
||||||
|
|
||||||
/** @var NoMutex */
|
|
||||||
protected $mutex;
|
|
||||||
|
|
||||||
/** @var PluginManager */
|
|
||||||
protected $pluginManager;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize an empty BookmarkFileService
|
|
||||||
*/
|
|
||||||
public function setUp(): void
|
|
||||||
{
|
|
||||||
$this->mutex = new NoMutex();
|
|
||||||
if (file_exists(self::$testDatastore)) {
|
|
||||||
unlink(self::$testDatastore);
|
|
||||||
}
|
|
||||||
|
|
||||||
copy('tests/utils/config/configJson.json.php', self::$testConf . '.json.php');
|
|
||||||
$this->conf = new ConfigManager(self::$testConf);
|
|
||||||
$this->conf->set('resource.datastore', self::$testDatastore);
|
|
||||||
$this->pluginManager = new PluginManager($this->conf);
|
|
||||||
$this->history = new History('sandbox/history.php');
|
|
||||||
$this->bookmarkService = new BookmarkFileService(
|
|
||||||
$this->conf,
|
|
||||||
$this->pluginManager,
|
|
||||||
$this->history,
|
|
||||||
$this->mutex,
|
|
||||||
true
|
|
||||||
);
|
|
||||||
|
|
||||||
$this->initializer = new BookmarkInitializer($this->bookmarkService);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test initialize() with a data store containing bookmarks.
|
|
||||||
*/
|
|
||||||
public function testInitializeNotEmptyDataStore(): void
|
|
||||||
{
|
|
||||||
$refDB = new ReferenceLinkDB();
|
|
||||||
$refDB->write(self::$testDatastore);
|
|
||||||
$this->bookmarkService = new BookmarkFileService(
|
|
||||||
$this->conf,
|
|
||||||
$this->pluginManager,
|
|
||||||
$this->history,
|
|
||||||
$this->mutex,
|
|
||||||
true
|
|
||||||
);
|
|
||||||
$this->initializer = new BookmarkInitializer($this->bookmarkService);
|
|
||||||
|
|
||||||
$this->initializer->initialize();
|
|
||||||
|
|
||||||
$this->assertEquals($refDB->countLinks() + 3, $this->bookmarkService->count());
|
|
||||||
|
|
||||||
$bookmark = $this->bookmarkService->get(43);
|
|
||||||
$this->assertStringStartsWith(
|
|
||||||
'Shaarli will automatically pick up the thumbnail for links to a variety of websites.',
|
|
||||||
$bookmark->getDescription()
|
|
||||||
);
|
|
||||||
$this->assertTrue($bookmark->isPrivate());
|
|
||||||
|
|
||||||
$bookmark = $this->bookmarkService->get(44);
|
|
||||||
$this->assertStringStartsWith(
|
|
||||||
'Adding a shaare without entering a URL creates a text-only "note" post such as this one.',
|
|
||||||
$bookmark->getDescription()
|
|
||||||
);
|
|
||||||
$this->assertTrue($bookmark->isPrivate());
|
|
||||||
|
|
||||||
$bookmark = $this->bookmarkService->get(45);
|
|
||||||
$this->assertStringStartsWith(
|
|
||||||
'Welcome to Shaarli!',
|
|
||||||
$bookmark->getDescription()
|
|
||||||
);
|
|
||||||
$this->assertFalse($bookmark->isPrivate());
|
|
||||||
|
|
||||||
$this->bookmarkService->save();
|
|
||||||
|
|
||||||
// Reload from file
|
|
||||||
$this->bookmarkService = new BookmarkFileService(
|
|
||||||
$this->conf,
|
|
||||||
$this->pluginManager,
|
|
||||||
$this->history,
|
|
||||||
$this->mutex,
|
|
||||||
true
|
|
||||||
);
|
|
||||||
$this->assertEquals($refDB->countLinks() + 3, $this->bookmarkService->count());
|
|
||||||
|
|
||||||
$bookmark = $this->bookmarkService->get(43);
|
|
||||||
$this->assertStringStartsWith(
|
|
||||||
'Shaarli will automatically pick up the thumbnail for links to a variety of websites.',
|
|
||||||
$bookmark->getDescription()
|
|
||||||
);
|
|
||||||
$this->assertTrue($bookmark->isPrivate());
|
|
||||||
|
|
||||||
$bookmark = $this->bookmarkService->get(44);
|
|
||||||
$this->assertStringStartsWith(
|
|
||||||
'Adding a shaare without entering a URL creates a text-only "note" post such as this one.',
|
|
||||||
$bookmark->getDescription()
|
|
||||||
);
|
|
||||||
$this->assertTrue($bookmark->isPrivate());
|
|
||||||
|
|
||||||
$bookmark = $this->bookmarkService->get(45);
|
|
||||||
$this->assertStringStartsWith(
|
|
||||||
'Welcome to Shaarli!',
|
|
||||||
$bookmark->getDescription()
|
|
||||||
);
|
|
||||||
$this->assertFalse($bookmark->isPrivate());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test initialize() with an a non existent datastore file .
|
|
||||||
*/
|
|
||||||
public function testInitializeNonExistentDataStore(): void
|
|
||||||
{
|
|
||||||
$this->conf->set('resource.datastore', static::$testDatastore . '_empty');
|
|
||||||
$this->bookmarkService = new BookmarkFileService(
|
|
||||||
$this->conf,
|
|
||||||
$this->pluginManager,
|
|
||||||
$this->history,
|
|
||||||
$this->mutex,
|
|
||||||
true
|
|
||||||
);
|
|
||||||
|
|
||||||
$this->initializer->initialize();
|
|
||||||
|
|
||||||
$this->assertEquals(3, $this->bookmarkService->count());
|
|
||||||
$bookmark = $this->bookmarkService->get(0);
|
|
||||||
$this->assertStringStartsWith(
|
|
||||||
'Shaarli will automatically pick up the thumbnail for links to a variety of websites.',
|
|
||||||
$bookmark->getDescription()
|
|
||||||
);
|
|
||||||
$this->assertTrue($bookmark->isPrivate());
|
|
||||||
|
|
||||||
$bookmark = $this->bookmarkService->get(1);
|
|
||||||
$this->assertStringStartsWith(
|
|
||||||
'Adding a shaare without entering a URL creates a text-only "note" post such as this one.',
|
|
||||||
$bookmark->getDescription()
|
|
||||||
);
|
|
||||||
$this->assertTrue($bookmark->isPrivate());
|
|
||||||
|
|
||||||
$bookmark = $this->bookmarkService->get(2);
|
|
||||||
$this->assertStringStartsWith(
|
|
||||||
'Welcome to Shaarli!',
|
|
||||||
$bookmark->getDescription()
|
|
||||||
);
|
|
||||||
$this->assertFalse($bookmark->isPrivate());
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,468 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace Shaarli\Bookmark;
|
|
||||||
|
|
||||||
use Shaarli\Bookmark\Exception\InvalidBookmarkException;
|
|
||||||
use Shaarli\TestCase;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Class BookmarkTest
|
|
||||||
*/
|
|
||||||
class BookmarkTest extends TestCase
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Test fromArray() with a link with full data
|
|
||||||
*/
|
|
||||||
public function testFromArrayFull()
|
|
||||||
{
|
|
||||||
$data = [
|
|
||||||
'id' => 1,
|
|
||||||
'shorturl' => 'abc',
|
|
||||||
'url' => 'https://domain.tld/oof.html?param=value#anchor',
|
|
||||||
'title' => 'This is an array link',
|
|
||||||
'description' => 'HTML desc<br><p>hi!</p>',
|
|
||||||
'thumbnail' => 'https://domain.tld/pic.png',
|
|
||||||
'sticky' => true,
|
|
||||||
'created' => new \DateTime('-1 minute'),
|
|
||||||
'tags' => ['tag1', 'tag2', 'chair'],
|
|
||||||
'updated' => new \DateTime(),
|
|
||||||
'private' => true,
|
|
||||||
];
|
|
||||||
|
|
||||||
$bookmark = (new Bookmark())->fromArray($data);
|
|
||||||
$this->assertEquals($data['id'], $bookmark->getId());
|
|
||||||
$this->assertEquals($data['shorturl'], $bookmark->getShortUrl());
|
|
||||||
$this->assertEquals($data['url'], $bookmark->getUrl());
|
|
||||||
$this->assertEquals($data['title'], $bookmark->getTitle());
|
|
||||||
$this->assertEquals($data['description'], $bookmark->getDescription());
|
|
||||||
$this->assertEquals($data['thumbnail'], $bookmark->getThumbnail());
|
|
||||||
$this->assertEquals($data['sticky'], $bookmark->isSticky());
|
|
||||||
$this->assertEquals($data['created'], $bookmark->getCreated());
|
|
||||||
$this->assertEquals($data['tags'], $bookmark->getTags());
|
|
||||||
$this->assertEquals('tag1 tag2 chair', $bookmark->getTagsString());
|
|
||||||
$this->assertEquals($data['updated'], $bookmark->getUpdated());
|
|
||||||
$this->assertEquals($data['private'], $bookmark->isPrivate());
|
|
||||||
$this->assertFalse($bookmark->isNote());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test fromArray() with a link with minimal data.
|
|
||||||
* Note that I use null values everywhere but this should not happen in the real world.
|
|
||||||
*/
|
|
||||||
public function testFromArrayMinimal()
|
|
||||||
{
|
|
||||||
$data = [
|
|
||||||
'id' => null,
|
|
||||||
'shorturl' => null,
|
|
||||||
'url' => null,
|
|
||||||
'title' => null,
|
|
||||||
'description' => null,
|
|
||||||
'created' => null,
|
|
||||||
'tags' => null,
|
|
||||||
'private' => null,
|
|
||||||
];
|
|
||||||
|
|
||||||
$bookmark = (new Bookmark())->fromArray($data);
|
|
||||||
$this->assertNull($bookmark->getId());
|
|
||||||
$this->assertNull($bookmark->getShortUrl());
|
|
||||||
$this->assertNull($bookmark->getUrl());
|
|
||||||
$this->assertNull($bookmark->getTitle());
|
|
||||||
$this->assertEquals('', $bookmark->getDescription());
|
|
||||||
$this->assertNull($bookmark->getCreated());
|
|
||||||
$this->assertEquals([], $bookmark->getTags());
|
|
||||||
$this->assertEquals('', $bookmark->getTagsString());
|
|
||||||
$this->assertNull($bookmark->getUpdated());
|
|
||||||
$this->assertFalse($bookmark->getThumbnail());
|
|
||||||
$this->assertFalse($bookmark->isSticky());
|
|
||||||
$this->assertFalse($bookmark->isPrivate());
|
|
||||||
$this->assertTrue($bookmark->isNote());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test fromArray() with a link with a custom tags separator
|
|
||||||
*/
|
|
||||||
public function testFromArrayCustomTagsSeparator()
|
|
||||||
{
|
|
||||||
$data = [
|
|
||||||
'id' => 1,
|
|
||||||
'tags' => ['tag1', 'tag2', 'chair'],
|
|
||||||
];
|
|
||||||
|
|
||||||
$bookmark = (new Bookmark())->fromArray($data, '@');
|
|
||||||
$this->assertEquals($data['id'], $bookmark->getId());
|
|
||||||
$this->assertEquals($data['tags'], $bookmark->getTags());
|
|
||||||
$this->assertEquals('tag1@tag2@chair', $bookmark->getTagsString('@'));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test validate() with a valid minimal bookmark
|
|
||||||
*/
|
|
||||||
public function testValidateValidFullBookmark()
|
|
||||||
{
|
|
||||||
$bookmark = new Bookmark();
|
|
||||||
$bookmark->setId(2);
|
|
||||||
$bookmark->setShortUrl('abc');
|
|
||||||
$bookmark->setCreated($date = \DateTime::createFromFormat('Ymd_His', '20190514_200102'));
|
|
||||||
$bookmark->setUpdated($dateUp = \DateTime::createFromFormat('Ymd_His', '20190514_210203'));
|
|
||||||
$bookmark->setUrl($url = 'https://domain.tld/oof.html?param=value#anchor');
|
|
||||||
$bookmark->setTitle($title = 'This is an array link');
|
|
||||||
$bookmark->setDescription($desc = 'HTML desc<br><p>hi!</p>');
|
|
||||||
$bookmark->setTags($tags = ['tag1', 'tag2', 'chair']);
|
|
||||||
$bookmark->setThumbnail($thumb = 'https://domain.tld/pic.png');
|
|
||||||
$bookmark->setPrivate(true);
|
|
||||||
$bookmark->validate();
|
|
||||||
|
|
||||||
$this->assertEquals(2, $bookmark->getId());
|
|
||||||
$this->assertEquals('abc', $bookmark->getShortUrl());
|
|
||||||
$this->assertEquals($date, $bookmark->getCreated());
|
|
||||||
$this->assertEquals($dateUp, $bookmark->getUpdated());
|
|
||||||
$this->assertEquals($url, $bookmark->getUrl());
|
|
||||||
$this->assertEquals($title, $bookmark->getTitle());
|
|
||||||
$this->assertEquals($desc, $bookmark->getDescription());
|
|
||||||
$this->assertEquals($tags, $bookmark->getTags());
|
|
||||||
$this->assertEquals(implode(' ', $tags), $bookmark->getTagsString());
|
|
||||||
$this->assertEquals($thumb, $bookmark->getThumbnail());
|
|
||||||
$this->assertTrue($bookmark->isPrivate());
|
|
||||||
$this->assertFalse($bookmark->isNote());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test validate() with a valid minimal bookmark
|
|
||||||
*/
|
|
||||||
public function testValidateValidMinimalBookmark()
|
|
||||||
{
|
|
||||||
$bookmark = new Bookmark();
|
|
||||||
$bookmark->setId(1);
|
|
||||||
$bookmark->setShortUrl('abc');
|
|
||||||
$bookmark->setCreated($date = \DateTime::createFromFormat('Ymd_His', '20190514_200102'));
|
|
||||||
$bookmark->validate();
|
|
||||||
|
|
||||||
$this->assertEquals(1, $bookmark->getId());
|
|
||||||
$this->assertEquals('abc', $bookmark->getShortUrl());
|
|
||||||
$this->assertEquals($date, $bookmark->getCreated());
|
|
||||||
$this->assertEquals('/shaare/abc', $bookmark->getUrl());
|
|
||||||
$this->assertEquals('/shaare/abc', $bookmark->getTitle());
|
|
||||||
$this->assertEquals('', $bookmark->getDescription());
|
|
||||||
$this->assertEquals([], $bookmark->getTags());
|
|
||||||
$this->assertEquals('', $bookmark->getTagsString());
|
|
||||||
$this->assertFalse($bookmark->getThumbnail());
|
|
||||||
$this->assertFalse($bookmark->isPrivate());
|
|
||||||
$this->assertTrue($bookmark->isNote());
|
|
||||||
$this->assertNull($bookmark->getUpdated());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test validate() with a a bookmark without ID.
|
|
||||||
*/
|
|
||||||
public function testValidateNotValidNoId()
|
|
||||||
{
|
|
||||||
$bookmark = new Bookmark();
|
|
||||||
$bookmark->setShortUrl('abc');
|
|
||||||
$bookmark->setCreated(\DateTime::createFromFormat('Ymd_His', '20190514_200102'));
|
|
||||||
$exception = null;
|
|
||||||
try {
|
|
||||||
$bookmark->validate();
|
|
||||||
} catch (InvalidBookmarkException $e) {
|
|
||||||
$exception = $e;
|
|
||||||
}
|
|
||||||
$this->assertNotNull($exception);
|
|
||||||
$this->assertContainsPolyfill('- ID: ' . PHP_EOL, $exception->getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test validate() with a a bookmark without short url.
|
|
||||||
*/
|
|
||||||
public function testValidateNotValidNoShortUrl()
|
|
||||||
{
|
|
||||||
$bookmark = new Bookmark();
|
|
||||||
$bookmark->setId(1);
|
|
||||||
$bookmark->setCreated(\DateTime::createFromFormat('Ymd_His', '20190514_200102'));
|
|
||||||
$bookmark->setShortUrl(null);
|
|
||||||
$exception = null;
|
|
||||||
try {
|
|
||||||
$bookmark->validate();
|
|
||||||
} catch (InvalidBookmarkException $e) {
|
|
||||||
$exception = $e;
|
|
||||||
}
|
|
||||||
$this->assertNotNull($exception);
|
|
||||||
$this->assertContainsPolyfill('- ShortUrl: ' . PHP_EOL, $exception->getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test validate() with a a bookmark without created datetime.
|
|
||||||
*/
|
|
||||||
public function testValidateNotValidNoCreated()
|
|
||||||
{
|
|
||||||
$bookmark = new Bookmark();
|
|
||||||
$bookmark->setId(1);
|
|
||||||
$bookmark->setShortUrl('abc');
|
|
||||||
$bookmark->setCreated(null);
|
|
||||||
$exception = null;
|
|
||||||
try {
|
|
||||||
$bookmark->validate();
|
|
||||||
} catch (InvalidBookmarkException $e) {
|
|
||||||
$exception = $e;
|
|
||||||
}
|
|
||||||
$this->assertNotNull($exception);
|
|
||||||
$this->assertContainsPolyfill('- Created: ' . PHP_EOL, $exception->getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test setId() and make sure that default fields are generated.
|
|
||||||
*/
|
|
||||||
public function testSetIdEmptyGeneratedFields()
|
|
||||||
{
|
|
||||||
$bookmark = new Bookmark();
|
|
||||||
$bookmark->setId(2);
|
|
||||||
|
|
||||||
$this->assertEquals(2, $bookmark->getId());
|
|
||||||
$this->assertRegExp('/[\w\-]{6}/', $bookmark->getShortUrl());
|
|
||||||
$this->assertTrue(new \DateTime('5 seconds ago') < $bookmark->getCreated());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test setId() and with generated fields already set.
|
|
||||||
*/
|
|
||||||
public function testSetIdSetGeneratedFields()
|
|
||||||
{
|
|
||||||
$bookmark = new Bookmark();
|
|
||||||
$bookmark->setShortUrl('abc');
|
|
||||||
$bookmark->setCreated($date = \DateTime::createFromFormat('Ymd_His', '20190514_200102'));
|
|
||||||
$bookmark->setId(2);
|
|
||||||
|
|
||||||
$this->assertEquals(2, $bookmark->getId());
|
|
||||||
$this->assertEquals('abc', $bookmark->getShortUrl());
|
|
||||||
$this->assertEquals($date, $bookmark->getCreated());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test setUrl() and make sure it accepts custom protocols
|
|
||||||
*/
|
|
||||||
public function testGetUrlWithValidProtocols()
|
|
||||||
{
|
|
||||||
$bookmark = new Bookmark();
|
|
||||||
$bookmark->setUrl($url = 'myprotocol://helloworld', ['myprotocol']);
|
|
||||||
$this->assertEquals($url, $bookmark->getUrl());
|
|
||||||
|
|
||||||
$bookmark->setUrl($url = 'https://helloworld.tld', ['myprotocol']);
|
|
||||||
$this->assertEquals($url, $bookmark->getUrl());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test setUrl() and make sure it accepts custom protocols
|
|
||||||
*/
|
|
||||||
public function testGetUrlWithNotValidProtocols()
|
|
||||||
{
|
|
||||||
$bookmark = new Bookmark();
|
|
||||||
$bookmark->setUrl('myprotocol://helloworld', []);
|
|
||||||
$this->assertEquals('http://helloworld', $bookmark->getUrl());
|
|
||||||
|
|
||||||
$bookmark->setUrl($url = 'https://helloworld.tld', []);
|
|
||||||
$this->assertEquals($url, $bookmark->getUrl());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test addTag() and DeleteTag()
|
|
||||||
*/
|
|
||||||
|
|
||||||
public function testAddDeleteTags()
|
|
||||||
{
|
|
||||||
$bookmark = new Bookmark();
|
|
||||||
|
|
||||||
$bookmark->addTag('tag1');
|
|
||||||
$this->assertEquals(
|
|
||||||
[
|
|
||||||
'tag1',
|
|
||||||
],
|
|
||||||
$bookmark->getTags()
|
|
||||||
);
|
|
||||||
|
|
||||||
// Ignore if tag is already present
|
|
||||||
$bookmark->addTag('tag2');
|
|
||||||
$bookmark->addTag('tag1');
|
|
||||||
$this->assertEquals(
|
|
||||||
[
|
|
||||||
'tag1',
|
|
||||||
'tag2',
|
|
||||||
],
|
|
||||||
$bookmark->getTags()
|
|
||||||
);
|
|
||||||
|
|
||||||
// Ignore deleting tags not present
|
|
||||||
$bookmark->deleteTag('tag5');
|
|
||||||
$this->assertEquals(
|
|
||||||
[
|
|
||||||
'tag1',
|
|
||||||
'tag2',
|
|
||||||
],
|
|
||||||
$bookmark->getTags()
|
|
||||||
);
|
|
||||||
|
|
||||||
// Delete multiples
|
|
||||||
$bookmark->setTags(['tag3', 'tag1', 'tag4', 'tag3', 'tag3', 'tag4']);
|
|
||||||
$bookmark->deleteTag('tag3');
|
|
||||||
$this->assertEquals(
|
|
||||||
[
|
|
||||||
'tag1',
|
|
||||||
'tag4',
|
|
||||||
'tag4',
|
|
||||||
],
|
|
||||||
$bookmark->getTags()
|
|
||||||
);
|
|
||||||
$bookmark->deleteTag('tag4');
|
|
||||||
$this->assertEquals(
|
|
||||||
[
|
|
||||||
'tag1',
|
|
||||||
],
|
|
||||||
$bookmark->getTags()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test setTagsString() with exotic data
|
|
||||||
*/
|
|
||||||
public function testSetTagsString()
|
|
||||||
{
|
|
||||||
$bookmark = new Bookmark();
|
|
||||||
|
|
||||||
$str = 'tag1 tag2 tag3.tag3-2 tag4 -tag5 ';
|
|
||||||
$bookmark->setTagsString($str);
|
|
||||||
$this->assertEquals(
|
|
||||||
[
|
|
||||||
'tag1',
|
|
||||||
'tag2',
|
|
||||||
'tag3.tag3-2',
|
|
||||||
'tag4',
|
|
||||||
'tag5',
|
|
||||||
],
|
|
||||||
$bookmark->getTags()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test setTags() with exotic data
|
|
||||||
*/
|
|
||||||
public function testSetTags()
|
|
||||||
{
|
|
||||||
$bookmark = new Bookmark();
|
|
||||||
|
|
||||||
$array = [
|
|
||||||
'tag1 ',
|
|
||||||
' tag2',
|
|
||||||
'tag3.tag3-2',
|
|
||||||
' tag4',
|
|
||||||
' ',
|
|
||||||
'-tag5 ',
|
|
||||||
];
|
|
||||||
$bookmark->setTags($array);
|
|
||||||
$this->assertEquals(
|
|
||||||
[
|
|
||||||
'tag1',
|
|
||||||
'tag2',
|
|
||||||
'tag3.tag3-2',
|
|
||||||
'tag4',
|
|
||||||
'tag5',
|
|
||||||
],
|
|
||||||
$bookmark->getTags()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test renameTag()
|
|
||||||
*/
|
|
||||||
public function testRenameTag()
|
|
||||||
{
|
|
||||||
$bookmark = new Bookmark();
|
|
||||||
$bookmark->setTags(['tag1', 'tag2', 'chair']);
|
|
||||||
$bookmark->renameTag('chair', 'table');
|
|
||||||
$this->assertEquals(['tag1', 'tag2', 'table'], $bookmark->getTags());
|
|
||||||
$bookmark->renameTag('tag1', 'tag42');
|
|
||||||
$this->assertEquals(['tag42', 'tag2', 'table'], $bookmark->getTags());
|
|
||||||
$bookmark->renameTag('tag42', 'tag43');
|
|
||||||
$this->assertEquals(['tag43', 'tag2', 'table'], $bookmark->getTags());
|
|
||||||
$bookmark->renameTag('table', 'desk');
|
|
||||||
$this->assertEquals(['tag43', 'tag2', 'desk'], $bookmark->getTags());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test renameTag() with a tag that is not present in the bookmark
|
|
||||||
*/
|
|
||||||
public function testRenameTagNotExists()
|
|
||||||
{
|
|
||||||
$bookmark = new Bookmark();
|
|
||||||
$bookmark->setTags(['tag1', 'tag2', 'chair']);
|
|
||||||
$bookmark->renameTag('nope', 'table');
|
|
||||||
$this->assertEquals(['tag1', 'tag2', 'chair'], $bookmark->getTags());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test deleteTag()
|
|
||||||
*/
|
|
||||||
public function testDeleteTag()
|
|
||||||
{
|
|
||||||
$bookmark = new Bookmark();
|
|
||||||
$bookmark->setTags(['tag1', 'tag2', 'chair']);
|
|
||||||
$bookmark->deleteTag('chair');
|
|
||||||
$this->assertEquals(['tag1', 'tag2'], $bookmark->getTags());
|
|
||||||
$bookmark->deleteTag('tag1');
|
|
||||||
$this->assertEquals(['tag2'], $bookmark->getTags());
|
|
||||||
$bookmark->deleteTag('tag2');
|
|
||||||
$this->assertEquals([], $bookmark->getTags());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test deleteTag() with a tag that is not present in the bookmark
|
|
||||||
*/
|
|
||||||
public function testDeleteTagNotExists()
|
|
||||||
{
|
|
||||||
$bookmark = new Bookmark();
|
|
||||||
$bookmark->setTags(['tag1', 'tag2', 'chair']);
|
|
||||||
$bookmark->deleteTag('nope');
|
|
||||||
$this->assertEquals(['tag1', 'tag2', 'chair'], $bookmark->getTags());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test shouldUpdateThumbnail() with bookmarks needing an update.
|
|
||||||
*/
|
|
||||||
public function testShouldUpdateThumbnail(): void
|
|
||||||
{
|
|
||||||
$bookmark = (new Bookmark())->setUrl('http://domain.tld/with-image');
|
|
||||||
|
|
||||||
static::assertTrue($bookmark->shouldUpdateThumbnail());
|
|
||||||
|
|
||||||
$bookmark = (new Bookmark())
|
|
||||||
->setUrl('http://domain.tld/with-image')
|
|
||||||
->setThumbnail('unknown file')
|
|
||||||
;
|
|
||||||
|
|
||||||
static::assertTrue($bookmark->shouldUpdateThumbnail());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test shouldUpdateThumbnail() with bookmarks that should not update.
|
|
||||||
*/
|
|
||||||
public function testShouldNotUpdateThumbnail(): void
|
|
||||||
{
|
|
||||||
$bookmark = (new Bookmark());
|
|
||||||
|
|
||||||
static::assertFalse($bookmark->shouldUpdateThumbnail());
|
|
||||||
|
|
||||||
$bookmark = (new Bookmark())
|
|
||||||
->setUrl('ftp://domain.tld/other-protocol', ['ftp'])
|
|
||||||
;
|
|
||||||
|
|
||||||
static::assertFalse($bookmark->shouldUpdateThumbnail());
|
|
||||||
|
|
||||||
$bookmark = (new Bookmark())
|
|
||||||
->setUrl('http://domain.tld/with-image')
|
|
||||||
->setThumbnail(__FILE__)
|
|
||||||
;
|
|
||||||
|
|
||||||
static::assertFalse($bookmark->shouldUpdateThumbnail());
|
|
||||||
|
|
||||||
$bookmark = (new Bookmark())->setUrl('/shaare/abcdef');
|
|
||||||
|
|
||||||
static::assertFalse($bookmark->shouldUpdateThumbnail());
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,767 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace Shaarli\Bookmark;
|
|
||||||
|
|
||||||
use Shaarli\TestCase;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Class LinkUtilsTest.
|
|
||||||
*/
|
|
||||||
class LinkUtilsTest extends TestCase
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Test html_extract_title() when the title is found.
|
|
||||||
*/
|
|
||||||
public function testHtmlExtractExistentTitle()
|
|
||||||
{
|
|
||||||
$title = 'Read me please.';
|
|
||||||
$html = '<html><meta>stuff</meta><title>' . $title . '</title></html>';
|
|
||||||
$this->assertEquals($title, html_extract_title($html));
|
|
||||||
$html = '<html><title>' . $title . '</title>blabla<title>another</title></html>';
|
|
||||||
$this->assertEquals($title, html_extract_title($html));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test html_extract_title() when the title is not found.
|
|
||||||
*/
|
|
||||||
public function testHtmlExtractNonExistentTitle()
|
|
||||||
{
|
|
||||||
$html = '<html><meta>stuff</meta></html>';
|
|
||||||
$this->assertFalse(html_extract_title($html));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test headers_extract_charset() when the charset is found.
|
|
||||||
*/
|
|
||||||
public function testHeadersExtractExistentCharset()
|
|
||||||
{
|
|
||||||
$charset = 'x-MacCroatian';
|
|
||||||
$headers = 'text/html; charset=' . $charset;
|
|
||||||
$this->assertEquals(strtolower($charset), header_extract_charset($headers));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test headers_extract_charset() when the charset is found with odd quotes.
|
|
||||||
*/
|
|
||||||
public function testHeadersExtractExistentCharsetWithQuotes()
|
|
||||||
{
|
|
||||||
$charset = 'x-MacCroatian';
|
|
||||||
$headers = 'text/html; charset="' . $charset . '"otherstuff="test"';
|
|
||||||
$this->assertEquals(strtolower($charset), header_extract_charset($headers));
|
|
||||||
|
|
||||||
$headers = 'text/html; charset=\'' . $charset . '\'otherstuff="test"';
|
|
||||||
$this->assertEquals(strtolower($charset), header_extract_charset($headers));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test headers_extract_charset() when the charset is not found.
|
|
||||||
*/
|
|
||||||
public function testHeadersExtractNonExistentCharset()
|
|
||||||
{
|
|
||||||
$headers = '';
|
|
||||||
$this->assertFalse(header_extract_charset($headers));
|
|
||||||
|
|
||||||
$headers = 'text/html';
|
|
||||||
$this->assertFalse(header_extract_charset($headers));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test html_extract_charset() when the charset is found.
|
|
||||||
*/
|
|
||||||
public function testHtmlExtractExistentCharset()
|
|
||||||
{
|
|
||||||
$charset = 'x-MacCroatian';
|
|
||||||
$html = '<html><meta>stuff2</meta><meta charset="' . $charset . '"/></html>';
|
|
||||||
$this->assertEquals(strtolower($charset), html_extract_charset($html));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test html_extract_charset() when the charset is not found.
|
|
||||||
*/
|
|
||||||
public function testHtmlExtractNonExistentCharset()
|
|
||||||
{
|
|
||||||
$html = '<html><meta>stuff</meta></html>';
|
|
||||||
$this->assertFalse(html_extract_charset($html));
|
|
||||||
$html = '<html><meta>stuff</meta><meta charset=""/></html>';
|
|
||||||
$this->assertFalse(html_extract_charset($html));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test html_extract_tag() when the tag <meta name= is found.
|
|
||||||
*/
|
|
||||||
public function testHtmlExtractExistentNameTag()
|
|
||||||
{
|
|
||||||
$description = 'Bob and Alice share cookies.';
|
|
||||||
|
|
||||||
// Simple one line
|
|
||||||
$html = '<html><meta>stuff2</meta><meta name="description" content="' . $description . '"/></html>';
|
|
||||||
$this->assertEquals($description, html_extract_tag('description', $html));
|
|
||||||
|
|
||||||
// Simple OpenGraph
|
|
||||||
$html = '<meta property="og:description" content="' . $description . '">';
|
|
||||||
$this->assertEquals($description, html_extract_tag('description', $html));
|
|
||||||
|
|
||||||
// Simple reversed OpenGraph
|
|
||||||
$html = '<meta content="' . $description . '" property="og:description">';
|
|
||||||
$this->assertEquals($description, html_extract_tag('description', $html));
|
|
||||||
|
|
||||||
// ItemProp OpenGraph
|
|
||||||
$html = '<meta itemprop="og:description" content="' . $description . '">';
|
|
||||||
$this->assertEquals($description, html_extract_tag('description', $html));
|
|
||||||
|
|
||||||
// OpenGraph without quotes
|
|
||||||
$html = '<meta property=og:description content="' . $description . '">';
|
|
||||||
$this->assertEquals($description, html_extract_tag('description', $html));
|
|
||||||
|
|
||||||
// OpenGraph reversed without quotes
|
|
||||||
$html = '<meta content="' . $description . '" property=og:description>';
|
|
||||||
$this->assertEquals($description, html_extract_tag('description', $html));
|
|
||||||
|
|
||||||
// OpenGraph with noise
|
|
||||||
$html = '<meta tag1="content1" property="og:description" tag2="content2" content="' .
|
|
||||||
$description . '" tag3="content3">';
|
|
||||||
$this->assertEquals($description, html_extract_tag('description', $html));
|
|
||||||
|
|
||||||
// OpenGraph reversed with noise
|
|
||||||
$html = '<meta tag1="content1" content="' . $description . '" ' .
|
|
||||||
'tag3="content3" tag2="content2" property="og:description">';
|
|
||||||
$this->assertEquals($description, html_extract_tag('description', $html));
|
|
||||||
|
|
||||||
// OpenGraph multiple properties start
|
|
||||||
$html = '<meta property="unrelated og:description" content="' . $description . '">';
|
|
||||||
$this->assertEquals($description, html_extract_tag('description', $html));
|
|
||||||
|
|
||||||
// OpenGraph multiple properties end
|
|
||||||
$html = '<meta property="og:description unrelated" content="' . $description . '">';
|
|
||||||
$this->assertEquals($description, html_extract_tag('description', $html));
|
|
||||||
|
|
||||||
// OpenGraph multiple properties both end
|
|
||||||
$html = '<meta property="og:unrelated1 og:description og:unrelated2" content="' . $description . '">';
|
|
||||||
$this->assertEquals($description, html_extract_tag('description', $html));
|
|
||||||
|
|
||||||
// OpenGraph multiple properties both end with noise
|
|
||||||
$html = '<meta tag1="content1" property="og:unrelated1 og:description og:unrelated2" ' .
|
|
||||||
'tag2="content2" content="' . $description . '" tag3="content3">';
|
|
||||||
$this->assertEquals($description, html_extract_tag('description', $html));
|
|
||||||
|
|
||||||
// OpenGraph reversed multiple properties start
|
|
||||||
$html = '<meta content="' . $description . '" property="unrelated og:description">';
|
|
||||||
$this->assertEquals($description, html_extract_tag('description', $html));
|
|
||||||
|
|
||||||
// OpenGraph reversed multiple properties end
|
|
||||||
$html = '<meta content="' . $description . '" property="og:description unrelated">';
|
|
||||||
$this->assertEquals($description, html_extract_tag('description', $html));
|
|
||||||
|
|
||||||
// OpenGraph reversed multiple properties both end
|
|
||||||
$html = '<meta content="' . $description . '" property="og:unrelated1 og:description og:unrelated2">';
|
|
||||||
$this->assertEquals($description, html_extract_tag('description', $html));
|
|
||||||
|
|
||||||
// OpenGraph reversed multiple properties both end with noise
|
|
||||||
$html = '<meta tag1="content1" content="' . $description . '" tag2="content2" ' .
|
|
||||||
'property="og:unrelated1 og:description og:unrelated2" tag3="content3">';
|
|
||||||
$this->assertEquals($description, html_extract_tag('description', $html));
|
|
||||||
|
|
||||||
// Suggestion from #1375
|
|
||||||
$html = '<meta property="og:description" name="description" content="' . $description . '">';
|
|
||||||
$this->assertEquals($description, html_extract_tag('description', $html));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test html_extract_tag() with double quoted content containing single quote, and the opposite.
|
|
||||||
*/
|
|
||||||
public function testHtmlExtractExistentNameTagWithMixedQuotes(): void
|
|
||||||
{
|
|
||||||
$description = 'Bob and Alice share M&M\'s.';
|
|
||||||
|
|
||||||
$html = '<meta property="og:description" content="' . $description . '">';
|
|
||||||
$this->assertEquals($description, html_extract_tag('description', $html));
|
|
||||||
|
|
||||||
$html = '<meta tag1="content1" property="og:unrelated1 og:description og:unrelated2" ' .
|
|
||||||
'tag2="content2" content="' . $description . '" tag3="content3">';
|
|
||||||
$this->assertEquals($description, html_extract_tag('description', $html));
|
|
||||||
|
|
||||||
$html = '<meta property="og:description" name="description" content="' . $description . '">';
|
|
||||||
$this->assertEquals($description, html_extract_tag('description', $html));
|
|
||||||
|
|
||||||
$description = 'Bob and Alice share "cookies".';
|
|
||||||
|
|
||||||
$html = '<meta property="og:description" content=\'' . $description . '\'>';
|
|
||||||
$this->assertEquals($description, html_extract_tag('description', $html));
|
|
||||||
|
|
||||||
$html = '<meta tag1="content1" property="og:unrelated1 og:description og:unrelated2" ' .
|
|
||||||
'tag2="content2" content=\'' . $description . '\' tag3="content3">';
|
|
||||||
$this->assertEquals($description, html_extract_tag('description', $html));
|
|
||||||
|
|
||||||
$html = '<meta property="og:description" name="description" content=\'' . $description . '\'>';
|
|
||||||
$this->assertEquals($description, html_extract_tag('description', $html));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test html_extract_tag() when the tag <meta name= is not found.
|
|
||||||
*/
|
|
||||||
public function testHtmlExtractNonExistentNameTag()
|
|
||||||
{
|
|
||||||
$html = '<html><meta>stuff2</meta><meta name="image" content="img"/></html>';
|
|
||||||
$this->assertFalse(html_extract_tag('description', $html));
|
|
||||||
|
|
||||||
// Partial meta tag
|
|
||||||
$html = '<meta content="Brief description">';
|
|
||||||
$this->assertFalse(html_extract_tag('description', $html));
|
|
||||||
|
|
||||||
$html = '<meta property="og:description">';
|
|
||||||
$this->assertFalse(html_extract_tag('description', $html));
|
|
||||||
|
|
||||||
$html = '<meta tag1="content1" property="og:description">';
|
|
||||||
$this->assertFalse(html_extract_tag('description', $html));
|
|
||||||
|
|
||||||
$html = '<meta property="og:description" tag1="content1">';
|
|
||||||
$this->assertFalse(html_extract_tag('description', $html));
|
|
||||||
|
|
||||||
$html = '<meta tag1="content1" content="Brief description">';
|
|
||||||
$this->assertFalse(html_extract_tag('description', $html));
|
|
||||||
|
|
||||||
$html = '<meta content="Brief description" tag1="content1">';
|
|
||||||
$this->assertFalse(html_extract_tag('description', $html));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test html_extract_tag() when the tag <meta property="og: is found.
|
|
||||||
*/
|
|
||||||
public function testHtmlExtractExistentOgTag()
|
|
||||||
{
|
|
||||||
$description = 'Bob and Alice share cookies.';
|
|
||||||
$html = '<html><meta>stuff2</meta><meta property="og:description" content="' . $description . '"/></html>';
|
|
||||||
$this->assertEquals($description, html_extract_tag('description', $html));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test html_extract_tag() when the tag <meta property="og: is not found.
|
|
||||||
*/
|
|
||||||
public function testHtmlExtractNonExistentOgTag()
|
|
||||||
{
|
|
||||||
$html = '<html><meta>stuff2</meta><meta name="image" content="img"/></html>';
|
|
||||||
$this->assertFalse(html_extract_tag('description', $html));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testHtmlExtractDescriptionFromGoogleRealCase(): void
|
|
||||||
{
|
|
||||||
$html = 'id="gsr"><meta content="Fêtes de fin d\'année" property="twitter:title"><meta ' .
|
|
||||||
'content="Bonnes fêtes de fin d\'année ! #GoogleDoodle" property="twitter:description">' .
|
|
||||||
'<meta content="Bonnes fêtes de fin d\'année ! #GoogleDoodle" property="og:description">' .
|
|
||||||
'<meta content="summary_large_image" property="twitter:card"><meta co'
|
|
||||||
;
|
|
||||||
$this->assertSame('Bonnes fêtes de fin d\'année ! #GoogleDoodle', html_extract_tag('description', $html));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test the header callback with valid value
|
|
||||||
*/
|
|
||||||
public function testCurlHeaderCallbackOk(): void
|
|
||||||
{
|
|
||||||
$callback = get_curl_header_callback($charset, 'ut_curl_getinfo_ok');
|
|
||||||
$data = [
|
|
||||||
'HTTP/1.1 200 OK',
|
|
||||||
'Server: GitHub.com',
|
|
||||||
'Date: Sat, 28 Oct 2017 12:01:33 GMT',
|
|
||||||
'Content-Type: text/html; charset=utf-8',
|
|
||||||
'Status: 200 OK',
|
|
||||||
];
|
|
||||||
|
|
||||||
foreach ($data as $chunk) {
|
|
||||||
static::assertIsInt($callback(null, $chunk));
|
|
||||||
}
|
|
||||||
|
|
||||||
static::assertSame('utf-8', $charset);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test the download callback with valid value
|
|
||||||
*/
|
|
||||||
public function testCurlDownloadCallbackOk(): void
|
|
||||||
{
|
|
||||||
$charset = 'utf-8';
|
|
||||||
$callback = get_curl_download_callback(
|
|
||||||
$charset,
|
|
||||||
$title,
|
|
||||||
$desc,
|
|
||||||
$keywords,
|
|
||||||
false,
|
|
||||||
' '
|
|
||||||
);
|
|
||||||
|
|
||||||
$data = [
|
|
||||||
'th=device-width">'
|
|
||||||
. '<title>Refactoring · GitHub</title>'
|
|
||||||
. '<link rel="search" type="application/opensea',
|
|
||||||
'<title>ignored</title>'
|
|
||||||
. '<meta name="description" content="desc" />'
|
|
||||||
. '<meta name="keywords" content="key1,key2" />',
|
|
||||||
];
|
|
||||||
|
|
||||||
foreach ($data as $chunk) {
|
|
||||||
static::assertSame(strlen($chunk), $callback(null, $chunk));
|
|
||||||
}
|
|
||||||
|
|
||||||
static::assertSame('utf-8', $charset);
|
|
||||||
static::assertSame('Refactoring · GitHub', $title);
|
|
||||||
static::assertEmpty($desc);
|
|
||||||
static::assertEmpty($keywords);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test the header callback with valid value
|
|
||||||
*/
|
|
||||||
public function testCurlHeaderCallbackNoCharset(): void
|
|
||||||
{
|
|
||||||
$callback = get_curl_header_callback($charset, 'ut_curl_getinfo_no_charset');
|
|
||||||
$data = [
|
|
||||||
'HTTP/1.1 200 OK',
|
|
||||||
];
|
|
||||||
|
|
||||||
foreach ($data as $chunk) {
|
|
||||||
static::assertSame(strlen($chunk), $callback(null, $chunk));
|
|
||||||
}
|
|
||||||
|
|
||||||
static::assertFalse($charset);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test the download callback with valid values and no charset
|
|
||||||
*/
|
|
||||||
public function testCurlDownloadCallbackOkNoCharset(): void
|
|
||||||
{
|
|
||||||
$charset = null;
|
|
||||||
$callback = get_curl_download_callback(
|
|
||||||
$charset,
|
|
||||||
$title,
|
|
||||||
$desc,
|
|
||||||
$keywords,
|
|
||||||
false,
|
|
||||||
' '
|
|
||||||
);
|
|
||||||
|
|
||||||
$data = [
|
|
||||||
'end' => 'th=device-width">'
|
|
||||||
. '<title>Refactoring · GitHub</title>'
|
|
||||||
. '<link rel="search" type="application/opensea',
|
|
||||||
'<title>ignored</title>'
|
|
||||||
. '<meta name="description" content="desc" />'
|
|
||||||
. '<meta name="keywords" content="key1,key2" />',
|
|
||||||
];
|
|
||||||
|
|
||||||
foreach ($data as $chunk) {
|
|
||||||
static::assertSame(strlen($chunk), $callback(null, $chunk));
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->assertEmpty($charset);
|
|
||||||
$this->assertEquals('Refactoring · GitHub', $title);
|
|
||||||
$this->assertEmpty($desc);
|
|
||||||
$this->assertEmpty($keywords);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test the download callback with valid values and no charset
|
|
||||||
*/
|
|
||||||
public function testCurlDownloadCallbackOkHtmlCharset(): void
|
|
||||||
{
|
|
||||||
$charset = null;
|
|
||||||
$callback = get_curl_download_callback(
|
|
||||||
$charset,
|
|
||||||
$title,
|
|
||||||
$desc,
|
|
||||||
$keywords,
|
|
||||||
false,
|
|
||||||
' '
|
|
||||||
);
|
|
||||||
|
|
||||||
$data = [
|
|
||||||
'<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />',
|
|
||||||
'end' => 'th=device-width">'
|
|
||||||
. '<title>Refactoring · GitHub</title>'
|
|
||||||
. '<link rel="search" type="application/opensea',
|
|
||||||
'<title>ignored</title>'
|
|
||||||
. '<meta name="description" content="desc" />'
|
|
||||||
. '<meta name="keywords" content="key1,key2" />',
|
|
||||||
];
|
|
||||||
foreach ($data as $chunk) {
|
|
||||||
static::assertSame(strlen($chunk), $callback(null, $chunk));
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->assertEquals('utf-8', $charset);
|
|
||||||
$this->assertEquals('Refactoring · GitHub', $title);
|
|
||||||
$this->assertEmpty($desc);
|
|
||||||
$this->assertEmpty($keywords);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test the download callback with valid values and no title
|
|
||||||
*/
|
|
||||||
public function testCurlDownloadCallbackOkNoTitle(): void
|
|
||||||
{
|
|
||||||
$charset = 'utf-8';
|
|
||||||
$callback = get_curl_download_callback(
|
|
||||||
$charset,
|
|
||||||
$title,
|
|
||||||
$desc,
|
|
||||||
$keywords,
|
|
||||||
false,
|
|
||||||
' '
|
|
||||||
);
|
|
||||||
|
|
||||||
$data = [
|
|
||||||
'end' => 'th=device-width">Refactoring · GitHub<link rel="search" type="application/opensea',
|
|
||||||
'ignored',
|
|
||||||
];
|
|
||||||
|
|
||||||
foreach ($data as $chunk) {
|
|
||||||
static::assertSame(strlen($chunk), $callback(null, $chunk));
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->assertEquals('utf-8', $charset);
|
|
||||||
$this->assertEmpty($title);
|
|
||||||
$this->assertEmpty($desc);
|
|
||||||
$this->assertEmpty($keywords);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test the header callback with an invalid content type.
|
|
||||||
*/
|
|
||||||
public function testCurlHeaderCallbackInvalidContentType(): void
|
|
||||||
{
|
|
||||||
$callback = get_curl_header_callback($charset, 'ut_curl_getinfo_ct_ko');
|
|
||||||
$data = [
|
|
||||||
'HTTP/1.1 200 OK',
|
|
||||||
];
|
|
||||||
|
|
||||||
static::assertFalse($callback(null, $data[0]));
|
|
||||||
static::assertNull($charset);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test the header callback with an invalid response code.
|
|
||||||
*/
|
|
||||||
public function testCurlHeaderCallbackInvalidResponseCode(): void
|
|
||||||
{
|
|
||||||
$callback = get_curl_header_callback($charset, 'ut_curl_getinfo_rc_ko');
|
|
||||||
|
|
||||||
static::assertFalse($callback(null, ''));
|
|
||||||
static::assertNull($charset);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test the header callback with an invalid content type and response code.
|
|
||||||
*/
|
|
||||||
public function testCurlHeaderCallbackInvalidContentTypeAndResponseCode(): void
|
|
||||||
{
|
|
||||||
$callback = get_curl_header_callback($charset, 'ut_curl_getinfo_rs_ct_ko');
|
|
||||||
|
|
||||||
static::assertFalse($callback(null, ''));
|
|
||||||
static::assertNull($charset);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test the download callback with valid value, and retrieve_description option enabled.
|
|
||||||
*/
|
|
||||||
public function testCurlDownloadCallbackOkWithDesc(): void
|
|
||||||
{
|
|
||||||
$charset = 'utf-8';
|
|
||||||
$callback = get_curl_download_callback(
|
|
||||||
$charset,
|
|
||||||
$title,
|
|
||||||
$desc,
|
|
||||||
$keywords,
|
|
||||||
true,
|
|
||||||
' '
|
|
||||||
);
|
|
||||||
$data = [
|
|
||||||
'th=device-width">'
|
|
||||||
. '<title>Refactoring · GitHub</title>'
|
|
||||||
. '<link rel="search" type="application/opensea',
|
|
||||||
'end' => '<title>ignored</title>'
|
|
||||||
. '<meta name="description" content="link desc" />'
|
|
||||||
. '<meta name="keywords" content="key1,key2" />',
|
|
||||||
];
|
|
||||||
|
|
||||||
foreach ($data as $chunk) {
|
|
||||||
static::assertSame(strlen($chunk), $callback(null, $chunk));
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->assertEquals('utf-8', $charset);
|
|
||||||
$this->assertEquals('Refactoring · GitHub', $title);
|
|
||||||
$this->assertEquals('link desc', $desc);
|
|
||||||
$this->assertEquals('key1 key2', $keywords);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test the download callback with valid value, and retrieve_description option enabled,
|
|
||||||
* but no desc or keyword defined in the page.
|
|
||||||
*/
|
|
||||||
public function testCurlDownloadCallbackOkWithDescNotFound(): void
|
|
||||||
{
|
|
||||||
$charset = 'utf-8';
|
|
||||||
$callback = get_curl_download_callback(
|
|
||||||
$charset,
|
|
||||||
$title,
|
|
||||||
$desc,
|
|
||||||
$keywords,
|
|
||||||
true,
|
|
||||||
'ut_curl_getinfo_ok'
|
|
||||||
);
|
|
||||||
$data = [
|
|
||||||
'th=device-width">'
|
|
||||||
. '<title>Refactoring · GitHub</title>'
|
|
||||||
. '<link rel="search" type="application/opensea',
|
|
||||||
'end' => '<title>ignored</title>',
|
|
||||||
];
|
|
||||||
|
|
||||||
foreach ($data as $chunk) {
|
|
||||||
static::assertSame(strlen($chunk), $callback(null, $chunk));
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->assertEquals('utf-8', $charset);
|
|
||||||
$this->assertEquals('Refactoring · GitHub', $title);
|
|
||||||
$this->assertEmpty($desc);
|
|
||||||
$this->assertEmpty($keywords);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test text2clickable.
|
|
||||||
*/
|
|
||||||
public function testText2clickable()
|
|
||||||
{
|
|
||||||
$text = 'stuff http://hello.there/is=someone#here otherstuff';
|
|
||||||
$expectedText = 'stuff <a href="http://hello.there/is=someone#here">'
|
|
||||||
. 'http://hello.there/is=someone#here</a> otherstuff';
|
|
||||||
$processedText = text2clickable($text);
|
|
||||||
$this->assertEquals($expectedText, $processedText);
|
|
||||||
|
|
||||||
$text = 'stuff http://hello.there/is=someone#here(please) otherstuff';
|
|
||||||
$expectedText = 'stuff <a href="http://hello.there/is=someone#here(please)">'
|
|
||||||
. 'http://hello.there/is=someone#here(please)</a> otherstuff';
|
|
||||||
$processedText = text2clickable($text);
|
|
||||||
$this->assertEquals($expectedText, $processedText);
|
|
||||||
|
|
||||||
$text = 'stuff http://hello.there/is=someone#here(please)&no otherstuff';
|
|
||||||
$text = 'stuff http://hello.there/is=someone#here(please)&no otherstuff';
|
|
||||||
$expectedText = 'stuff <a href="http://hello.there/is=someone#here(please)&no">'
|
|
||||||
. 'http://hello.there/is=someone#here(please)&no</a> otherstuff';
|
|
||||||
$processedText = text2clickable($text);
|
|
||||||
$this->assertEquals($expectedText, $processedText);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test testSpace2nbsp.
|
|
||||||
*/
|
|
||||||
public function testSpace2nbsp()
|
|
||||||
{
|
|
||||||
$text = ' Are you thrilled by flags ?' . PHP_EOL . ' Really?';
|
|
||||||
$expectedText = ' Are you thrilled by flags ?' . PHP_EOL . ' Really?';
|
|
||||||
$processedText = space2nbsp($text);
|
|
||||||
$this->assertEquals($expectedText, $processedText);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test hashtags auto-link.
|
|
||||||
*/
|
|
||||||
public function testHashtagAutolink()
|
|
||||||
{
|
|
||||||
$index = 'http://domain.tld/';
|
|
||||||
$rawDescription = '#hashtag\n
|
|
||||||
# nothashtag\n
|
|
||||||
test#nothashtag #hashtag \#nothashtag\n
|
|
||||||
test #hashtag #hashtag test #hashtag.test\n
|
|
||||||
#hashtag #hashtag-nothashtag #hashtag_hashtag\n
|
|
||||||
What is #ашок anyway?\n
|
|
||||||
カタカナ #カタカナ」カタカナ\n';
|
|
||||||
$autolinkedDescription = hashtag_autolink($rawDescription, $index);
|
|
||||||
|
|
||||||
$this->assertContainsPolyfill($this->getHashtagLink('hashtag', $index), $autolinkedDescription);
|
|
||||||
$this->assertNotContainsPolyfill(' #hashtag', $autolinkedDescription);
|
|
||||||
$this->assertNotContainsPolyfill('>#nothashtag', $autolinkedDescription);
|
|
||||||
$this->assertContainsPolyfill($this->getHashtagLink('ашок', $index), $autolinkedDescription);
|
|
||||||
$this->assertContainsPolyfill($this->getHashtagLink('カタカナ', $index), $autolinkedDescription);
|
|
||||||
$this->assertContainsPolyfill($this->getHashtagLink('hashtag_hashtag', $index), $autolinkedDescription);
|
|
||||||
$this->assertNotContainsPolyfill($this->getHashtagLink('hashtag-nothashtag', $index), $autolinkedDescription);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test hashtags auto-link without index URL.
|
|
||||||
*/
|
|
||||||
public function testHashtagAutolinkNoIndex()
|
|
||||||
{
|
|
||||||
$rawDescription = 'blabla #hashtag x#nothashtag';
|
|
||||||
$autolinkedDescription = hashtag_autolink($rawDescription);
|
|
||||||
|
|
||||||
$this->assertContainsPolyfill($this->getHashtagLink('hashtag'), $autolinkedDescription);
|
|
||||||
$this->assertNotContainsPolyfill(' #hashtag', $autolinkedDescription);
|
|
||||||
$this->assertNotContainsPolyfill('>#nothashtag', $autolinkedDescription);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test is_note with note URLs.
|
|
||||||
*/
|
|
||||||
public function testIsNote()
|
|
||||||
{
|
|
||||||
$this->assertTrue(is_note('?'));
|
|
||||||
$this->assertTrue(is_note('?abcDEf'));
|
|
||||||
$this->assertTrue(is_note('?_abcDEf#123'));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test is_note with non note URLs.
|
|
||||||
*/
|
|
||||||
public function testIsNotNote()
|
|
||||||
{
|
|
||||||
$this->assertFalse(is_note(''));
|
|
||||||
$this->assertFalse(is_note('nope'));
|
|
||||||
$this->assertFalse(is_note('https://github.com/shaarli/Shaarli/?hi'));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test tags_str2array with whitespace separator.
|
|
||||||
*/
|
|
||||||
public function testTagsStr2ArrayWithSpaceSeparator(): void
|
|
||||||
{
|
|
||||||
$separator = ' ';
|
|
||||||
|
|
||||||
static::assertSame(['tag1', 'tag2', 'tag3'], tags_str2array('tag1 tag2 tag3', $separator));
|
|
||||||
static::assertSame(['tag1', 'tag2', 'tag3'], tags_str2array('tag1 tag2 tag3', $separator));
|
|
||||||
static::assertSame(['tag1', 'tag2', 'tag3'], tags_str2array(' tag1 tag2 tag3 ', $separator));
|
|
||||||
static::assertSame(['tag1@', 'tag2,', '.tag3'], tags_str2array(' tag1@ tag2, .tag3 ', $separator));
|
|
||||||
static::assertSame([], tags_str2array('', $separator));
|
|
||||||
static::assertSame([], tags_str2array(' ', $separator));
|
|
||||||
static::assertSame([], tags_str2array(null, $separator));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test tags_str2array with @ separator.
|
|
||||||
*/
|
|
||||||
public function testTagsStr2ArrayWithCharSeparator(): void
|
|
||||||
{
|
|
||||||
$separator = '@';
|
|
||||||
|
|
||||||
static::assertSame(['tag1', 'tag2', 'tag3'], tags_str2array('tag1@tag2@tag3', $separator));
|
|
||||||
static::assertSame(['tag1', 'tag2', 'tag3'], tags_str2array('tag1@@@@tag2@@@@tag3', $separator));
|
|
||||||
static::assertSame(['tag1', 'tag2', 'tag3'], tags_str2array('@@@tag1@@@tag2@@@@tag3@@', $separator));
|
|
||||||
static::assertSame(
|
|
||||||
['tag1#', 'tag2, and other', '.tag3'],
|
|
||||||
tags_str2array('@@@ tag1# @@@ tag2, and other @@@@.tag3@@', $separator)
|
|
||||||
);
|
|
||||||
static::assertSame([], tags_str2array('', $separator));
|
|
||||||
static::assertSame([], tags_str2array(' ', $separator));
|
|
||||||
static::assertSame([], tags_str2array(null, $separator));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test tags_str2array with / separator.
|
|
||||||
*/
|
|
||||||
public function testTagsStr2ArrayWithRegexDelimiterSeparator(): void
|
|
||||||
{
|
|
||||||
$separator = '/';
|
|
||||||
|
|
||||||
static::assertSame(['tag1', 'tag2', 'tag3'], tags_str2array('tag1/tag2/tag3', $separator));
|
|
||||||
static::assertSame(['tag1', 'tag2', 'tag3'], tags_str2array('tag1////tag2////tag3', $separator));
|
|
||||||
static::assertSame(['tag1', 'tag2', 'tag3'], tags_str2array('///tag1///tag2////tag3//', $separator));
|
|
||||||
static::assertSame(
|
|
||||||
['tag1#', 'tag2, and other', '.tag3'],
|
|
||||||
tags_str2array('/// tag1# /// tag2, and other ////.tag3//', $separator)
|
|
||||||
);
|
|
||||||
static::assertSame([], tags_str2array('', $separator));
|
|
||||||
static::assertSame([], tags_str2array(' ', $separator));
|
|
||||||
static::assertSame([], tags_str2array(null, $separator));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test tags_array2str with ' ' separator.
|
|
||||||
*/
|
|
||||||
public function testTagsArray2StrWithSpaceSeparator(): void
|
|
||||||
{
|
|
||||||
$separator = ' ';
|
|
||||||
|
|
||||||
static::assertSame('tag1 tag2 tag3', tags_array2str(['tag1', 'tag2', 'tag3'], $separator));
|
|
||||||
static::assertSame('tag1, tag2@ tag3', tags_array2str(['tag1,', 'tag2@', 'tag3'], $separator));
|
|
||||||
static::assertSame('tag1 tag2 tag3', tags_array2str([' tag1 ', 'tag2', 'tag3 '], $separator));
|
|
||||||
static::assertSame('tag1 tag2 tag3', tags_array2str([' tag1 ', ' ', 'tag2', ' ', 'tag3 '], $separator));
|
|
||||||
static::assertSame('tag1', tags_array2str([' tag1 '], $separator));
|
|
||||||
static::assertSame('', tags_array2str([' '], $separator));
|
|
||||||
static::assertSame('', tags_array2str([], $separator));
|
|
||||||
static::assertSame('', tags_array2str(null, $separator));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test tags_array2str with @ separator.
|
|
||||||
*/
|
|
||||||
public function testTagsArray2StrWithCharSeparator(): void
|
|
||||||
{
|
|
||||||
$separator = '@';
|
|
||||||
|
|
||||||
static::assertSame('tag1@tag2@tag3', tags_array2str(['tag1', 'tag2', 'tag3'], $separator));
|
|
||||||
static::assertSame('tag1,@tag2@tag3', tags_array2str(['tag1,', 'tag2@', 'tag3'], $separator));
|
|
||||||
static::assertSame(
|
|
||||||
'tag1@tag2, and other@tag3',
|
|
||||||
tags_array2str(['@@@@ tag1@@@', ' @tag2, and other @', 'tag3@@@@'], $separator)
|
|
||||||
);
|
|
||||||
static::assertSame('tag1@tag2@tag3', tags_array2str(['@@@tag1@@@', '@', 'tag2', '@@@', 'tag3@@@'], $separator));
|
|
||||||
static::assertSame('tag1', tags_array2str(['@@@@tag1@@@@'], $separator));
|
|
||||||
static::assertSame('', tags_array2str(['@@@'], $separator));
|
|
||||||
static::assertSame('', tags_array2str([], $separator));
|
|
||||||
static::assertSame('', tags_array2str(null, $separator));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test tags_array2str with @ separator.
|
|
||||||
*/
|
|
||||||
public function testTagsFilterWithSpaceSeparator(): void
|
|
||||||
{
|
|
||||||
$separator = ' ';
|
|
||||||
|
|
||||||
static::assertSame(['tag1', 'tag2', 'tag3'], tags_filter(['tag1', 'tag2', 'tag3'], $separator));
|
|
||||||
static::assertSame(['tag1,', 'tag2@', 'tag3'], tags_filter(['tag1,', 'tag2@', 'tag3'], $separator));
|
|
||||||
static::assertSame(['tag1', 'tag2', 'tag3'], tags_filter([' tag1 ', 'tag2', 'tag3 '], $separator));
|
|
||||||
static::assertSame(
|
|
||||||
['tag1', 'tag2', 'tag3'],
|
|
||||||
tags_filter([' tag1 ', ' ', 'tag2', ' ', 'tag3 '], $separator)
|
|
||||||
);
|
|
||||||
static::assertSame(['tag1'], tags_filter([' tag1 '], $separator));
|
|
||||||
static::assertSame([], tags_filter([' '], $separator));
|
|
||||||
static::assertSame([], tags_filter([], $separator));
|
|
||||||
static::assertSame([], tags_filter(null, $separator));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test tags_array2str with @ separator.
|
|
||||||
*/
|
|
||||||
public function testTagsArrayFilterWithSpaceSeparator(): void
|
|
||||||
{
|
|
||||||
$separator = '@';
|
|
||||||
|
|
||||||
static::assertSame(['tag1', 'tag2', 'tag3'], tags_filter(['tag1', 'tag2', 'tag3'], $separator));
|
|
||||||
static::assertSame(['tag1,', 'tag2#', 'tag3'], tags_filter(['tag1,', 'tag2#', 'tag3'], $separator));
|
|
||||||
static::assertSame(
|
|
||||||
['tag1', 'tag2, and other', 'tag3'],
|
|
||||||
tags_filter(['@@@@ tag1@@@', ' @tag2, and other @', 'tag3@@@@'], $separator)
|
|
||||||
);
|
|
||||||
static::assertSame(
|
|
||||||
['tag1', 'tag2', 'tag3'],
|
|
||||||
tags_filter(['@@@tag1@@@', '@', 'tag2', '@@@', 'tag3@@@'], $separator)
|
|
||||||
);
|
|
||||||
static::assertSame(['tag1'], tags_filter(['@@@@tag1@@@@'], $separator));
|
|
||||||
static::assertSame([], tags_filter(['@@@'], $separator));
|
|
||||||
static::assertSame([], tags_filter([], $separator));
|
|
||||||
static::assertSame([], tags_filter(null, $separator));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Util function to build an hashtag link.
|
|
||||||
*
|
|
||||||
* @param string $hashtag Hashtag name.
|
|
||||||
* @param string $index Index URL.
|
|
||||||
*
|
|
||||||
* @return string HTML hashtag link.
|
|
||||||
*/
|
|
||||||
private function getHashtagLink($hashtag, $index = '')
|
|
||||||
{
|
|
||||||
$hashtagLink = '<a href="' . $index . './add-tag/$1" title="Hashtag $1">#$1</a>';
|
|
||||||
return str_replace('$1', $hashtag, $hashtagLink);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,125 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace Shaarli\Bookmark;
|
|
||||||
|
|
||||||
use Shaarli\TestCase;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test SearchResult class.
|
|
||||||
*/
|
|
||||||
class SearchResultTest extends TestCase
|
|
||||||
{
|
|
||||||
/** Create a SearchResult without any pagination parameter. */
|
|
||||||
public function testResultNoParameters(): void
|
|
||||||
{
|
|
||||||
$searchResult = SearchResult::getSearchResult($data = ['a', 'b', 'c', 'd', 'e', 'f']);
|
|
||||||
|
|
||||||
static::assertSame($data, $searchResult->getBookmarks());
|
|
||||||
static::assertSame(6, $searchResult->getResultCount());
|
|
||||||
static::assertSame(6, $searchResult->getTotalCount());
|
|
||||||
static::assertSame(null, $searchResult->getLimit());
|
|
||||||
static::assertSame(0, $searchResult->getOffset());
|
|
||||||
static::assertSame(1, $searchResult->getPage());
|
|
||||||
static::assertSame(1, $searchResult->getLastPage());
|
|
||||||
static::assertTrue($searchResult->isFirstPage());
|
|
||||||
static::assertTrue($searchResult->isLastPage());
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Create a SearchResult with only an offset parameter */
|
|
||||||
public function testResultWithOffset(): void
|
|
||||||
{
|
|
||||||
$searchResult = SearchResult::getSearchResult(['a', 'b', 'c', 'd', 'e', 'f'], 2);
|
|
||||||
|
|
||||||
static::assertSame([2 => 'c', 3 => 'd', 4 => 'e', 5 => 'f'], $searchResult->getBookmarks());
|
|
||||||
static::assertSame(4, $searchResult->getResultCount());
|
|
||||||
static::assertSame(6, $searchResult->getTotalCount());
|
|
||||||
static::assertSame(null, $searchResult->getLimit());
|
|
||||||
static::assertSame(2, $searchResult->getOffset());
|
|
||||||
static::assertSame(2, $searchResult->getPage());
|
|
||||||
static::assertSame(2, $searchResult->getLastPage());
|
|
||||||
static::assertFalse($searchResult->isFirstPage());
|
|
||||||
static::assertTrue($searchResult->isLastPage());
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Create a SearchResult with only a limit parameter */
|
|
||||||
public function testResultWithLimit(): void
|
|
||||||
{
|
|
||||||
$searchResult = SearchResult::getSearchResult(['a', 'b', 'c', 'd', 'e', 'f'], 0, 2);
|
|
||||||
|
|
||||||
static::assertSame([0 => 'a', 1 => 'b'], $searchResult->getBookmarks());
|
|
||||||
static::assertSame(2, $searchResult->getResultCount());
|
|
||||||
static::assertSame(6, $searchResult->getTotalCount());
|
|
||||||
static::assertSame(2, $searchResult->getLimit());
|
|
||||||
static::assertSame(0, $searchResult->getOffset());
|
|
||||||
static::assertSame(1, $searchResult->getPage());
|
|
||||||
static::assertSame(3, $searchResult->getLastPage());
|
|
||||||
static::assertTrue($searchResult->isFirstPage());
|
|
||||||
static::assertFalse($searchResult->isLastPage());
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Create a SearchResult with offset and limit parameters */
|
|
||||||
public function testResultWithLimitAndOffset(): void
|
|
||||||
{
|
|
||||||
$searchResult = SearchResult::getSearchResult(['a', 'b', 'c', 'd', 'e', 'f'], 2, 2);
|
|
||||||
|
|
||||||
static::assertSame([2 => 'c', 3 => 'd'], $searchResult->getBookmarks());
|
|
||||||
static::assertSame(2, $searchResult->getResultCount());
|
|
||||||
static::assertSame(6, $searchResult->getTotalCount());
|
|
||||||
static::assertSame(2, $searchResult->getLimit());
|
|
||||||
static::assertSame(2, $searchResult->getOffset());
|
|
||||||
static::assertSame(2, $searchResult->getPage());
|
|
||||||
static::assertSame(3, $searchResult->getLastPage());
|
|
||||||
static::assertFalse($searchResult->isFirstPage());
|
|
||||||
static::assertFalse($searchResult->isLastPage());
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Create a SearchResult with offset and limit parameters displaying the last page */
|
|
||||||
public function testResultWithLimitAndOffsetLastPage(): void
|
|
||||||
{
|
|
||||||
$searchResult = SearchResult::getSearchResult(['a', 'b', 'c', 'd', 'e', 'f'], 4, 2);
|
|
||||||
|
|
||||||
static::assertSame([4 => 'e', 5 => 'f'], $searchResult->getBookmarks());
|
|
||||||
static::assertSame(2, $searchResult->getResultCount());
|
|
||||||
static::assertSame(6, $searchResult->getTotalCount());
|
|
||||||
static::assertSame(2, $searchResult->getLimit());
|
|
||||||
static::assertSame(4, $searchResult->getOffset());
|
|
||||||
static::assertSame(3, $searchResult->getPage());
|
|
||||||
static::assertSame(3, $searchResult->getLastPage());
|
|
||||||
static::assertFalse($searchResult->isFirstPage());
|
|
||||||
static::assertTrue($searchResult->isLastPage());
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Create a SearchResult with offset and limit parameters out of bound (display the last page) */
|
|
||||||
public function testResultWithLimitAndOffsetOutOfBounds(): void
|
|
||||||
{
|
|
||||||
$searchResult = SearchResult::getSearchResult(['a', 'b', 'c', 'd', 'e', 'f'], 12, 2);
|
|
||||||
|
|
||||||
static::assertSame([4 => 'e', 5 => 'f'], $searchResult->getBookmarks());
|
|
||||||
static::assertSame(2, $searchResult->getResultCount());
|
|
||||||
static::assertSame(6, $searchResult->getTotalCount());
|
|
||||||
static::assertSame(2, $searchResult->getLimit());
|
|
||||||
static::assertSame(-2, $searchResult->getOffset());
|
|
||||||
static::assertSame(3, $searchResult->getPage());
|
|
||||||
static::assertSame(3, $searchResult->getLastPage());
|
|
||||||
static::assertFalse($searchResult->isFirstPage());
|
|
||||||
static::assertTrue($searchResult->isLastPage());
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Create a SearchResult with offset and limit parameters out of bound (no result) */
|
|
||||||
public function testResultWithLimitAndOffsetOutOfBoundsNoResult(): void
|
|
||||||
{
|
|
||||||
$searchResult = SearchResult::getSearchResult(['a', 'b', 'c', 'd', 'e', 'f'], 12, 2, true);
|
|
||||||
|
|
||||||
static::assertSame([], $searchResult->getBookmarks());
|
|
||||||
static::assertSame(0, $searchResult->getResultCount());
|
|
||||||
static::assertSame(6, $searchResult->getTotalCount());
|
|
||||||
static::assertSame(2, $searchResult->getLimit());
|
|
||||||
static::assertSame(12, $searchResult->getOffset());
|
|
||||||
static::assertSame(7, $searchResult->getPage());
|
|
||||||
static::assertSame(3, $searchResult->getLastPage());
|
|
||||||
static::assertFalse($searchResult->isFirstPage());
|
|
||||||
static::assertFalse($searchResult->isLastPage());
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,45 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
require_once 'vendor/autoload.php';
|
|
||||||
|
|
||||||
use Shaarli\Tests\Utils\ReferenceSessionIdHashes;
|
|
||||||
|
|
||||||
$conf = new \Shaarli\Config\ConfigManager('tests/utils/config/configJson');
|
|
||||||
new \Shaarli\Languages('en', $conf);
|
|
||||||
|
|
||||||
// is_iterable is only compatible with PHP 7.1+
|
|
||||||
if (!function_exists('is_iterable')) {
|
|
||||||
function is_iterable($var)
|
|
||||||
{
|
|
||||||
return is_array($var) || $var instanceof \Traversable;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// raw functions
|
|
||||||
require_once 'application/config/ConfigPlugin.php';
|
|
||||||
require_once 'application/bookmark/LinkUtils.php';
|
|
||||||
require_once 'application/http/UrlUtils.php';
|
|
||||||
require_once 'application/http/HttpUtils.php';
|
|
||||||
require_once 'application/Utils.php';
|
|
||||||
require_once 'application/TimeZone.php';
|
|
||||||
require_once 'tests/utils/CurlUtils.php';
|
|
||||||
require_once 'tests/utils/RainTPL.php';
|
|
||||||
|
|
||||||
// TODO: remove this after fixing UT
|
|
||||||
require_once 'tests/TestCase.php';
|
|
||||||
require_once 'tests/container/ShaarliTestContainer.php';
|
|
||||||
require_once 'tests/front/controller/visitor/FrontControllerMockHelper.php';
|
|
||||||
require_once 'tests/front/controller/admin/FrontAdminControllerMockHelper.php';
|
|
||||||
require_once 'tests/updater/DummyUpdater.php';
|
|
||||||
require_once 'tests/utils/FakeApplicationUtils.php';
|
|
||||||
require_once 'tests/utils/FakeBookmarkService.php';
|
|
||||||
require_once 'tests/utils/FakeConfigManager.php';
|
|
||||||
require_once 'tests/utils/ReferenceHistory.php';
|
|
||||||
require_once 'tests/utils/ReferenceLinkDB.php';
|
|
||||||
require_once 'tests/utils/ReferenceSessionIdHashes.php';
|
|
||||||
|
|
||||||
ReferenceSessionIdHashes::genAllHashes();
|
|
||||||
|
|
||||||
if (!defined('SHAARLI_MUTEX_FILE')) {
|
|
||||||
define('SHAARLI_MUTEX_FILE', __FILE__);
|
|
||||||
}
|
|
|
@ -1,121 +0,0 @@
|
||||||
<?php
|
|
||||||
namespace Shaarli\Config;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Class ConfigJsonTest
|
|
||||||
*/
|
|
||||||
class ConfigJsonTest extends \Shaarli\TestCase
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @var ConfigJson
|
|
||||||
*/
|
|
||||||
protected $configIO;
|
|
||||||
|
|
||||||
protected function setUp(): void
|
|
||||||
{
|
|
||||||
$this->configIO = new ConfigJson();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Read a simple existing config file.
|
|
||||||
*/
|
|
||||||
public function testRead()
|
|
||||||
{
|
|
||||||
$conf = $this->configIO->read('tests/utils/config/configJson.json.php');
|
|
||||||
$this->assertEquals('root', $conf['credentials']['login']);
|
|
||||||
$this->assertEquals('lala', $conf['redirector']['url']);
|
|
||||||
$this->assertEquals('sandbox/datastore.php', $conf['resource']['datastore']);
|
|
||||||
$this->assertEquals('1', $conf['plugins']['WALLABAG_VERSION']);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Read a non existent config file -> empty array.
|
|
||||||
*/
|
|
||||||
public function testReadNonExistent()
|
|
||||||
{
|
|
||||||
$this->assertEquals(array(), $this->configIO->read('nope'));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Read a non existent config file -> empty array.
|
|
||||||
*/
|
|
||||||
public function testReadInvalidJson()
|
|
||||||
{
|
|
||||||
$this->expectException(\Exception::class);
|
|
||||||
$this->expectExceptionMessageRegExp('/An error occurred while parsing JSON configuration file \\([\\w\\/\\.]+\\): error code #4/');
|
|
||||||
|
|
||||||
$this->configIO->read('tests/utils/config/configInvalid.json.php');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Write a new config file.
|
|
||||||
*/
|
|
||||||
public function testWriteNew()
|
|
||||||
{
|
|
||||||
$dataFile = 'tests/utils/config/configWrite.json.php';
|
|
||||||
$data = array(
|
|
||||||
'credentials' => array(
|
|
||||||
'login' => 'root',
|
|
||||||
),
|
|
||||||
'resource' => array(
|
|
||||||
'datastore' => 'data/datastore.php',
|
|
||||||
),
|
|
||||||
'redirector' => array(
|
|
||||||
'url' => 'lala',
|
|
||||||
),
|
|
||||||
'plugins' => array(
|
|
||||||
'WALLABAG_VERSION' => '1',
|
|
||||||
)
|
|
||||||
);
|
|
||||||
$this->configIO->write($dataFile, $data);
|
|
||||||
// PHP 5.3 doesn't support json pretty print.
|
|
||||||
if (defined('JSON_PRETTY_PRINT')) {
|
|
||||||
$expected = '{
|
|
||||||
"credentials": {
|
|
||||||
"login": "root"
|
|
||||||
},
|
|
||||||
"resource": {
|
|
||||||
"datastore": "data\/datastore.php"
|
|
||||||
},
|
|
||||||
"redirector": {
|
|
||||||
"url": "lala"
|
|
||||||
},
|
|
||||||
"plugins": {
|
|
||||||
"WALLABAG_VERSION": "1"
|
|
||||||
}
|
|
||||||
}';
|
|
||||||
} else {
|
|
||||||
$expected = '{"credentials":{"login":"root"},"resource":{"datastore":"data\/datastore.php"},"redirector":{"url":"lala"},"plugins":{"WALLABAG_VERSION":"1"}}';
|
|
||||||
}
|
|
||||||
$expected = ConfigJson::getPhpHeaders() . $expected . ConfigJson::getPhpSuffix();
|
|
||||||
$this->assertEquals($expected, file_get_contents($dataFile));
|
|
||||||
unlink($dataFile);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Overwrite an existing setting.
|
|
||||||
*/
|
|
||||||
public function testOverwrite()
|
|
||||||
{
|
|
||||||
$source = 'tests/utils/config/configJson.json.php';
|
|
||||||
$dest = 'tests/utils/config/configOverwrite.json.php';
|
|
||||||
copy($source, $dest);
|
|
||||||
$conf = $this->configIO->read($dest);
|
|
||||||
$conf['redirector']['url'] = 'blabla';
|
|
||||||
$this->configIO->write($dest, $conf);
|
|
||||||
$conf = $this->configIO->read($dest);
|
|
||||||
$this->assertEquals('blabla', $conf['redirector']['url']);
|
|
||||||
unlink($dest);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Write to invalid path.
|
|
||||||
*/
|
|
||||||
public function testWriteInvalidBlank()
|
|
||||||
{
|
|
||||||
$this->expectException(\Shaarli\Exceptions\IOException::class);
|
|
||||||
|
|
||||||
$conf = array('conf' => 'value');
|
|
||||||
@$this->configIO->write('', $conf);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,197 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace Shaarli\Config;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Unit tests for Class ConfigManagerTest
|
|
||||||
*
|
|
||||||
* Note: it only test the manager with ConfigJson,
|
|
||||||
* ConfigPhp is only a workaround to handle the transition to JSON type.
|
|
||||||
*/
|
|
||||||
class ConfigManagerTest extends \Shaarli\TestCase
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @var ConfigManager
|
|
||||||
*/
|
|
||||||
protected $conf;
|
|
||||||
|
|
||||||
protected function setUp(): void
|
|
||||||
{
|
|
||||||
$this->conf = new ConfigManager('tests/utils/config/configJson');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Simple config test:
|
|
||||||
* 1. Set settings.
|
|
||||||
* 2. Check settings value.
|
|
||||||
*/
|
|
||||||
public function testSetGet()
|
|
||||||
{
|
|
||||||
$this->conf->set('paramInt', 42);
|
|
||||||
$this->conf->set('paramString', 'value1');
|
|
||||||
$this->conf->set('paramBool', false);
|
|
||||||
$this->conf->set('paramArray', ['foo' => 'bar']);
|
|
||||||
$this->conf->set('paramNull', null);
|
|
||||||
|
|
||||||
$this->assertEquals(42, $this->conf->get('paramInt'));
|
|
||||||
$this->assertEquals('value1', $this->conf->get('paramString'));
|
|
||||||
$this->assertFalse($this->conf->get('paramBool'));
|
|
||||||
$this->assertEquals(['foo' => 'bar'], $this->conf->get('paramArray'));
|
|
||||||
$this->assertEquals(null, $this->conf->get('paramNull'));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set/write/get config test:
|
|
||||||
* 1. Set settings.
|
|
||||||
* 2. Write it to the config file.
|
|
||||||
* 3. Read the file.
|
|
||||||
* 4. Check settings value.
|
|
||||||
*/
|
|
||||||
public function testSetWriteGet()
|
|
||||||
{
|
|
||||||
$this->conf->set('paramInt', 42);
|
|
||||||
$this->conf->set('paramString', 'value1');
|
|
||||||
$this->conf->set('paramBool', false);
|
|
||||||
$this->conf->set('paramArray', ['foo' => 'bar']);
|
|
||||||
$this->conf->set('paramNull', null);
|
|
||||||
|
|
||||||
$this->conf->setConfigFile('tests/utils/config/configTmp');
|
|
||||||
$this->conf->write(true);
|
|
||||||
$this->conf->reload();
|
|
||||||
unlink($this->conf->getConfigFileExt());
|
|
||||||
|
|
||||||
$this->assertEquals(42, $this->conf->get('paramInt'));
|
|
||||||
$this->assertEquals('value1', $this->conf->get('paramString'));
|
|
||||||
$this->assertFalse($this->conf->get('paramBool'));
|
|
||||||
$this->assertEquals(['foo' => 'bar'], $this->conf->get('paramArray'));
|
|
||||||
$this->assertEquals(null, $this->conf->get('paramNull'));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test set/write/get with nested keys.
|
|
||||||
*/
|
|
||||||
public function testSetWriteGetNested()
|
|
||||||
{
|
|
||||||
$this->conf->set('foo.bar.key.stuff', 'testSetWriteGetNested');
|
|
||||||
|
|
||||||
$this->conf->setConfigFile('tests/utils/config/configTmp');
|
|
||||||
$this->conf->write(true);
|
|
||||||
$this->conf->reload();
|
|
||||||
unlink($this->conf->getConfigFileExt());
|
|
||||||
|
|
||||||
$this->assertEquals('testSetWriteGetNested', $this->conf->get('foo.bar.key.stuff'));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testSetDeleteNested()
|
|
||||||
{
|
|
||||||
$this->conf->set('foo.bar.key.stuff', 'testSetDeleteNested');
|
|
||||||
$this->assertTrue($this->conf->exists('foo.bar'));
|
|
||||||
$this->assertTrue($this->conf->exists('foo.bar.key.stuff'));
|
|
||||||
$this->assertEquals('testSetDeleteNested', $this->conf->get('foo.bar.key.stuff'));
|
|
||||||
|
|
||||||
$this->conf->remove('foo.bar');
|
|
||||||
$this->assertFalse($this->conf->exists('foo.bar.key.stuff'));
|
|
||||||
$this->assertFalse($this->conf->exists('foo.bar'));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set with an empty key.
|
|
||||||
*/
|
|
||||||
public function testSetEmptyKey()
|
|
||||||
{
|
|
||||||
$this->expectException(\Exception::class);
|
|
||||||
$this->expectExceptionMessageRegExp('#^Invalid setting key parameter. String expected, got.*#');
|
|
||||||
|
|
||||||
$this->conf->set('', 'stuff');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set with an array key.
|
|
||||||
*/
|
|
||||||
public function testSetArrayKey()
|
|
||||||
{
|
|
||||||
$this->expectException(\Exception::class);
|
|
||||||
$this->expectExceptionMessageRegExp('#^Invalid setting key parameter. String expected, got.*#');
|
|
||||||
|
|
||||||
$this->conf->set(['foo' => 'bar'], 'stuff');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove with an empty key.
|
|
||||||
*/
|
|
||||||
public function testRmoveEmptyKey()
|
|
||||||
{
|
|
||||||
$this->expectException(\Exception::class);
|
|
||||||
$this->expectExceptionMessageRegExp('#^Invalid setting key parameter. String expected, got.*#');
|
|
||||||
|
|
||||||
$this->conf->remove('');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Try to write the config without mandatory parameter (e.g. 'login').
|
|
||||||
*/
|
|
||||||
public function testWriteMissingParameter()
|
|
||||||
{
|
|
||||||
$this->expectException(\Shaarli\Config\Exception\MissingFieldConfigException::class);
|
|
||||||
|
|
||||||
$this->conf->setConfigFile('tests/utils/config/configTmp');
|
|
||||||
$this->assertFalse(file_exists($this->conf->getConfigFileExt()));
|
|
||||||
$this->conf->reload();
|
|
||||||
|
|
||||||
$this->conf->write(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Try to get non existent config keys.
|
|
||||||
*/
|
|
||||||
public function testGetNonExistent()
|
|
||||||
{
|
|
||||||
$this->assertEquals('', $this->conf->get('nope.test'));
|
|
||||||
$this->assertEquals('default', $this->conf->get('nope.test', 'default'));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test the 'exists' method with existent values.
|
|
||||||
*/
|
|
||||||
public function testExistsOk()
|
|
||||||
{
|
|
||||||
$this->assertTrue($this->conf->exists('credentials.login'));
|
|
||||||
$this->assertTrue($this->conf->exists('config.foo'));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test the 'exists' method with non existent or invalid values.
|
|
||||||
*/
|
|
||||||
public function testExistsKo()
|
|
||||||
{
|
|
||||||
$this->assertFalse($this->conf->exists('nope'));
|
|
||||||
$this->assertFalse($this->conf->exists('nope.nope'));
|
|
||||||
$this->assertFalse($this->conf->exists(''));
|
|
||||||
$this->assertFalse($this->conf->exists(false));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reset the ConfigManager instance.
|
|
||||||
*/
|
|
||||||
public function testReset()
|
|
||||||
{
|
|
||||||
$confIO = $this->conf->getConfigIO();
|
|
||||||
$this->conf->reset();
|
|
||||||
$this->assertFalse($confIO === $this->conf->getConfigIO());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reload the config from file.
|
|
||||||
*/
|
|
||||||
public function testReload()
|
|
||||||
{
|
|
||||||
$this->conf->setConfigFile('tests/utils/config/configTmp');
|
|
||||||
$newConf = ConfigJson::getPhpHeaders() . '{ "key": "value" }';
|
|
||||||
file_put_contents($this->conf->getConfigFileExt(), $newConf);
|
|
||||||
$this->conf->reload();
|
|
||||||
unlink($this->conf->getConfigFileExt());
|
|
||||||
// Previous conf no longer exists, and new values have been loaded.
|
|
||||||
$this->assertFalse($this->conf->exists('credentials.login'));
|
|
||||||
$this->assertEquals('value', $this->conf->get('key'));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,100 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace Shaarli\Config;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Class ConfigPhpTest
|
|
||||||
*
|
|
||||||
* We run tests in separate processes due to the usage for $GLOBALS
|
|
||||||
* which are kept between tests.
|
|
||||||
* @runTestsInSeparateProcesses
|
|
||||||
*/
|
|
||||||
class ConfigPhpTest extends \Shaarli\TestCase
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @var ConfigPhp
|
|
||||||
*/
|
|
||||||
protected $configIO;
|
|
||||||
|
|
||||||
protected function setUp(): void
|
|
||||||
{
|
|
||||||
$this->configIO = new ConfigPhp();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Read a simple existing config file.
|
|
||||||
*/
|
|
||||||
public function testRead()
|
|
||||||
{
|
|
||||||
$conf = $this->configIO->read('tests/utils/config/configPhp.php');
|
|
||||||
$this->assertEquals('root', $conf['login']);
|
|
||||||
$this->assertEquals('lala', $conf['redirector']);
|
|
||||||
$this->assertEquals('data/datastore.php', $conf['config']['DATASTORE']);
|
|
||||||
$this->assertEquals('1', $conf['plugins']['WALLABAG_VERSION']);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Read a non existent config file -> empty array.
|
|
||||||
*/
|
|
||||||
public function testReadNonExistent()
|
|
||||||
{
|
|
||||||
$this->assertEquals([], $this->configIO->read('nope'));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Read an empty existent config file -> array with blank default values.
|
|
||||||
*/
|
|
||||||
public function testReadEmpty()
|
|
||||||
{
|
|
||||||
$dataFile = 'tests/utils/config/emptyConfigPhp.php';
|
|
||||||
$conf = $this->configIO->read($dataFile);
|
|
||||||
$this->assertEmpty($conf['login']);
|
|
||||||
$this->assertEmpty($conf['title']);
|
|
||||||
$this->assertEmpty($conf['titleLink']);
|
|
||||||
$this->assertEmpty($conf['config']);
|
|
||||||
$this->assertEmpty($conf['plugins']);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Write a new config file.
|
|
||||||
*/
|
|
||||||
public function testWriteNew()
|
|
||||||
{
|
|
||||||
$dataFile = 'tests/utils/config/configWrite.php';
|
|
||||||
$data = [
|
|
||||||
'login' => 'root',
|
|
||||||
'redirector' => 'lala',
|
|
||||||
'config' => [
|
|
||||||
'DATASTORE' => 'data/datastore.php',
|
|
||||||
],
|
|
||||||
'plugins' => [
|
|
||||||
'WALLABAG_VERSION' => '1',
|
|
||||||
]
|
|
||||||
];
|
|
||||||
$this->configIO->write($dataFile, $data);
|
|
||||||
$expected = '<?php
|
|
||||||
$GLOBALS[\'login\'] = \'root\';
|
|
||||||
$GLOBALS[\'redirector\'] = \'lala\';
|
|
||||||
$GLOBALS[\'config\'][\'DATASTORE\'] = \'data/datastore.php\';
|
|
||||||
$GLOBALS[\'plugins\'][\'WALLABAG_VERSION\'] = \'1\';
|
|
||||||
';
|
|
||||||
$this->assertEquals($expected, file_get_contents($dataFile));
|
|
||||||
unlink($dataFile);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Overwrite an existing setting.
|
|
||||||
*/
|
|
||||||
public function testOverwrite()
|
|
||||||
{
|
|
||||||
$source = 'tests/utils/config/configPhp.php';
|
|
||||||
$dest = 'tests/utils/config/configOverwrite.php';
|
|
||||||
copy($source, $dest);
|
|
||||||
$conf = $this->configIO->read($dest);
|
|
||||||
$conf['redirector'] = 'blabla';
|
|
||||||
$this->configIO->write($dest, $conf);
|
|
||||||
$conf = $this->configIO->read($dest);
|
|
||||||
$this->assertEquals('blabla', $conf['redirector']);
|
|
||||||
unlink($dest);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,133 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace Shaarli\Config;
|
|
||||||
|
|
||||||
use Shaarli\Config\Exception\PluginConfigOrderException;
|
|
||||||
use Shaarli\Plugin\PluginManager;
|
|
||||||
use Shaarli\TestCase;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Unitary tests for Shaarli config related functions
|
|
||||||
*/
|
|
||||||
class ConfigPluginTest extends TestCase
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Test save_plugin_config with valid data.
|
|
||||||
*
|
|
||||||
* @throws PluginConfigOrderException
|
|
||||||
*/
|
|
||||||
public function testSavePluginConfigValid()
|
|
||||||
{
|
|
||||||
$data = [
|
|
||||||
'order_plugin1' => 2, // no plugin related
|
|
||||||
'plugin2' => 0, // new - at the end
|
|
||||||
'plugin3' => 0, // 2nd
|
|
||||||
'order_plugin3' => 8,
|
|
||||||
'plugin4' => 0, // 1st
|
|
||||||
'order_plugin4' => 5,
|
|
||||||
];
|
|
||||||
|
|
||||||
$expected = [
|
|
||||||
'plugin3',
|
|
||||||
'plugin4',
|
|
||||||
'plugin2',
|
|
||||||
];
|
|
||||||
|
|
||||||
mkdir($path = __DIR__ . '/folder');
|
|
||||||
PluginManager::$PLUGINS_PATH = $path;
|
|
||||||
array_map(function (string $plugin) use ($path) {
|
|
||||||
touch($path . '/' . $plugin);
|
|
||||||
}, $expected);
|
|
||||||
|
|
||||||
$out = save_plugin_config($data);
|
|
||||||
$this->assertEquals($expected, $out);
|
|
||||||
|
|
||||||
array_map(function (string $plugin) use ($path) {
|
|
||||||
unlink($path . '/' . $plugin);
|
|
||||||
}, $expected);
|
|
||||||
rmdir($path);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test save_plugin_config with invalid data.
|
|
||||||
*/
|
|
||||||
public function testSavePluginConfigInvalid()
|
|
||||||
{
|
|
||||||
$this->expectException(PluginConfigOrderException::class);
|
|
||||||
|
|
||||||
$data = [
|
|
||||||
'plugin2' => 0,
|
|
||||||
'plugin3' => 0,
|
|
||||||
'order_plugin3' => 0,
|
|
||||||
'plugin4' => 0,
|
|
||||||
'order_plugin4' => 0,
|
|
||||||
];
|
|
||||||
|
|
||||||
save_plugin_config($data);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test save_plugin_config without data.
|
|
||||||
*/
|
|
||||||
public function testSavePluginConfigEmpty()
|
|
||||||
{
|
|
||||||
$this->assertEquals([], save_plugin_config([]));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test validate_plugin_order with valid data.
|
|
||||||
*/
|
|
||||||
public function testValidatePluginOrderValid()
|
|
||||||
{
|
|
||||||
$data = [
|
|
||||||
'order_plugin1' => 2,
|
|
||||||
'plugin2' => 0,
|
|
||||||
'plugin3' => 0,
|
|
||||||
'order_plugin3' => 1,
|
|
||||||
'plugin4' => 0,
|
|
||||||
'order_plugin4' => 5,
|
|
||||||
];
|
|
||||||
|
|
||||||
$this->assertTrue(validate_plugin_order($data));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test validate_plugin_order with invalid data.
|
|
||||||
*/
|
|
||||||
public function testValidatePluginOrderInvalid()
|
|
||||||
{
|
|
||||||
$data = [
|
|
||||||
'order_plugin1' => 2,
|
|
||||||
'order_plugin3' => 1,
|
|
||||||
'order_plugin4' => 1,
|
|
||||||
];
|
|
||||||
|
|
||||||
$this->assertFalse(validate_plugin_order($data));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test load_plugin_parameter_values.
|
|
||||||
*/
|
|
||||||
public function testLoadPluginParameterValues()
|
|
||||||
{
|
|
||||||
$plugins = [
|
|
||||||
'plugin_name' => [
|
|
||||||
'parameters' => [
|
|
||||||
'param1' => ['value' => true],
|
|
||||||
'param2' => ['value' => false],
|
|
||||||
'param3' => ['value' => ''],
|
|
||||||
]
|
|
||||||
]
|
|
||||||
];
|
|
||||||
|
|
||||||
$parameters = [
|
|
||||||
'param1' => 'value1',
|
|
||||||
'param2' => 'value2',
|
|
||||||
];
|
|
||||||
|
|
||||||
$result = load_plugin_parameter_values($plugins, $parameters);
|
|
||||||
$this->assertEquals('value1', $result['plugin_name']['parameters']['param1']['value']);
|
|
||||||
$this->assertEquals('value2', $result['plugin_name']['parameters']['param2']['value']);
|
|
||||||
$this->assertEquals('', $result['plugin_name']['parameters']['param3']['value']);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,98 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace Shaarli\Container;
|
|
||||||
|
|
||||||
use Psr\Log\LoggerInterface;
|
|
||||||
use Shaarli\Bookmark\BookmarkServiceInterface;
|
|
||||||
use Shaarli\Config\ConfigManager;
|
|
||||||
use Shaarli\Feed\FeedBuilder;
|
|
||||||
use Shaarli\Formatter\FormatterFactory;
|
|
||||||
use Shaarli\Front\Controller\Visitor\ErrorController;
|
|
||||||
use Shaarli\Front\Controller\Visitor\ErrorNotFoundController;
|
|
||||||
use Shaarli\History;
|
|
||||||
use Shaarli\Http\HttpAccess;
|
|
||||||
use Shaarli\Http\MetadataRetriever;
|
|
||||||
use Shaarli\Netscape\NetscapeBookmarkUtils;
|
|
||||||
use Shaarli\Plugin\PluginManager;
|
|
||||||
use Shaarli\Render\PageBuilder;
|
|
||||||
use Shaarli\Render\PageCacheManager;
|
|
||||||
use Shaarli\Security\CookieManager;
|
|
||||||
use Shaarli\Security\LoginManager;
|
|
||||||
use Shaarli\Security\SessionManager;
|
|
||||||
use Shaarli\TestCase;
|
|
||||||
use Shaarli\Thumbnailer;
|
|
||||||
use Shaarli\Updater\Updater;
|
|
||||||
use Slim\Http\Environment;
|
|
||||||
|
|
||||||
class ContainerBuilderTest extends TestCase
|
|
||||||
{
|
|
||||||
/** @var ConfigManager */
|
|
||||||
protected $conf;
|
|
||||||
|
|
||||||
/** @var SessionManager */
|
|
||||||
protected $sessionManager;
|
|
||||||
|
|
||||||
/** @var LoginManager */
|
|
||||||
protected $loginManager;
|
|
||||||
|
|
||||||
/** @var ContainerBuilder */
|
|
||||||
protected $containerBuilder;
|
|
||||||
|
|
||||||
/** @var CookieManager */
|
|
||||||
protected $cookieManager;
|
|
||||||
|
|
||||||
/** @var PluginManager */
|
|
||||||
protected $pluginManager;
|
|
||||||
|
|
||||||
public function setUp(): void
|
|
||||||
{
|
|
||||||
$this->conf = new ConfigManager('tests/utils/config/configJson');
|
|
||||||
$this->sessionManager = $this->createMock(SessionManager::class);
|
|
||||||
$this->cookieManager = $this->createMock(CookieManager::class);
|
|
||||||
$this->pluginManager = $this->createMock(PluginManager::class);
|
|
||||||
|
|
||||||
$this->loginManager = $this->createMock(LoginManager::class);
|
|
||||||
$this->loginManager->method('isLoggedIn')->willReturn(true);
|
|
||||||
|
|
||||||
$this->containerBuilder = new ContainerBuilder(
|
|
||||||
$this->conf,
|
|
||||||
$this->sessionManager,
|
|
||||||
$this->cookieManager,
|
|
||||||
$this->loginManager,
|
|
||||||
$this->pluginManager,
|
|
||||||
$this->createMock(LoggerInterface::class)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testBuildContainer(): void
|
|
||||||
{
|
|
||||||
$container = $this->containerBuilder->build();
|
|
||||||
|
|
||||||
static::assertInstanceOf(BookmarkServiceInterface::class, $container->bookmarkService);
|
|
||||||
static::assertInstanceOf(CookieManager::class, $container->cookieManager);
|
|
||||||
static::assertInstanceOf(ConfigManager::class, $container->conf);
|
|
||||||
static::assertInstanceOf(ErrorController::class, $container->errorHandler);
|
|
||||||
static::assertInstanceOf(Environment::class, $container->environment);
|
|
||||||
static::assertInstanceOf(FeedBuilder::class, $container->feedBuilder);
|
|
||||||
static::assertInstanceOf(FormatterFactory::class, $container->formatterFactory);
|
|
||||||
static::assertInstanceOf(History::class, $container->history);
|
|
||||||
static::assertInstanceOf(HttpAccess::class, $container->httpAccess);
|
|
||||||
static::assertInstanceOf(LoginManager::class, $container->loginManager);
|
|
||||||
static::assertInstanceOf(LoggerInterface::class, $container->logger);
|
|
||||||
static::assertInstanceOf(MetadataRetriever::class, $container->metadataRetriever);
|
|
||||||
static::assertInstanceOf(NetscapeBookmarkUtils::class, $container->netscapeBookmarkUtils);
|
|
||||||
static::assertInstanceOf(PageBuilder::class, $container->pageBuilder);
|
|
||||||
static::assertInstanceOf(PageCacheManager::class, $container->pageCacheManager);
|
|
||||||
static::assertInstanceOf(ErrorController::class, $container->phpErrorHandler);
|
|
||||||
static::assertInstanceOf(ErrorNotFoundController::class, $container->notFoundHandler);
|
|
||||||
static::assertInstanceOf(PluginManager::class, $container->pluginManager);
|
|
||||||
static::assertInstanceOf(SessionManager::class, $container->sessionManager);
|
|
||||||
static::assertInstanceOf(Thumbnailer::class, $container->thumbnailer);
|
|
||||||
static::assertInstanceOf(Updater::class, $container->updater);
|
|
||||||
|
|
||||||
// Set by the middleware
|
|
||||||
static::assertNull($container->basePath);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,41 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace Shaarli\Container;
|
|
||||||
|
|
||||||
use PHPUnit\Framework\MockObject\MockObject;
|
|
||||||
use Shaarli\Bookmark\BookmarkServiceInterface;
|
|
||||||
use Shaarli\Config\ConfigManager;
|
|
||||||
use Shaarli\Feed\FeedBuilder;
|
|
||||||
use Shaarli\Formatter\FormatterFactory;
|
|
||||||
use Shaarli\History;
|
|
||||||
use Shaarli\Http\HttpAccess;
|
|
||||||
use Shaarli\Plugin\PluginManager;
|
|
||||||
use Shaarli\Render\PageBuilder;
|
|
||||||
use Shaarli\Render\PageCacheManager;
|
|
||||||
use Shaarli\Security\LoginManager;
|
|
||||||
use Shaarli\Security\SessionManager;
|
|
||||||
use Shaarli\Thumbnailer;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test helper allowing auto-completion for MockObjects.
|
|
||||||
*
|
|
||||||
* @property mixed[] $environment $_SERVER automatically injected by Slim
|
|
||||||
* @property MockObject|ConfigManager $conf
|
|
||||||
* @property MockObject|SessionManager $sessionManager
|
|
||||||
* @property MockObject|LoginManager $loginManager
|
|
||||||
* @property MockObject|string $webPath
|
|
||||||
* @property MockObject|History $history
|
|
||||||
* @property MockObject|BookmarkServiceInterface $bookmarkService
|
|
||||||
* @property MockObject|PageBuilder $pageBuilder
|
|
||||||
* @property MockObject|PluginManager $pluginManager
|
|
||||||
* @property MockObject|FormatterFactory $formatterFactory
|
|
||||||
* @property MockObject|PageCacheManager $pageCacheManager
|
|
||||||
* @property MockObject|FeedBuilder $feedBuilder
|
|
||||||
* @property MockObject|Thumbnailer $thumbnailer
|
|
||||||
* @property MockObject|HttpAccess $httpAccess
|
|
||||||
*/
|
|
||||||
class ShaarliTestContainer extends ShaarliContainer
|
|
||||||
{
|
|
||||||
}
|
|
|
@ -1,36 +0,0 @@
|
||||||
FROM alpine:3.16
|
|
||||||
MAINTAINER Shaarli Community
|
|
||||||
|
|
||||||
RUN apk --update --no-cache add \
|
|
||||||
ca-certificates \
|
|
||||||
curl \
|
|
||||||
make \
|
|
||||||
php8 \
|
|
||||||
php8-ctype \
|
|
||||||
php8-curl \
|
|
||||||
php8-dom \
|
|
||||||
php8-gd \
|
|
||||||
php8-gettext \
|
|
||||||
php8-iconv \
|
|
||||||
php8-intl \
|
|
||||||
php8-json \
|
|
||||||
php8-mbstring \
|
|
||||||
php8-openssl \
|
|
||||||
php8-phar \
|
|
||||||
php8-session \
|
|
||||||
php8-simplexml \
|
|
||||||
php8-tokenizer \
|
|
||||||
php8-xdebug \
|
|
||||||
php8-xmlwriter \
|
|
||||||
php8-xml \
|
|
||||||
php8-zlib \
|
|
||||||
rsync
|
|
||||||
|
|
||||||
RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
|
|
||||||
|
|
||||||
RUN mkdir /shaarli
|
|
||||||
WORKDIR /shaarli
|
|
||||||
VOLUME /shaarli
|
|
||||||
|
|
||||||
ENTRYPOINT ["make"]
|
|
||||||
CMD []
|
|
|
@ -1,35 +0,0 @@
|
||||||
FROM debian:jessie
|
|
||||||
MAINTAINER Shaarli Community
|
|
||||||
|
|
||||||
ENV TERM dumb
|
|
||||||
ENV DEBIAN_FRONTEND noninteractive
|
|
||||||
ENV LANG en_US.UTF-8
|
|
||||||
ENV LANGUAGE en_US:en
|
|
||||||
|
|
||||||
RUN apt-get update \
|
|
||||||
&& apt-get install --no-install-recommends -y \
|
|
||||||
ca-certificates \
|
|
||||||
curl \
|
|
||||||
locales \
|
|
||||||
make \
|
|
||||||
php5 \
|
|
||||||
php5-curl \
|
|
||||||
php5-gd \
|
|
||||||
php5-intl \
|
|
||||||
php5-xdebug \
|
|
||||||
rsync \
|
|
||||||
&& apt-get clean
|
|
||||||
|
|
||||||
RUN locale-gen en_US.UTF-8 \
|
|
||||||
&& locale-gen de_DE.UTF-8 \
|
|
||||||
&& locale-gen fr_FR.UTF-8
|
|
||||||
|
|
||||||
ADD https://getcomposer.org/composer.phar /usr/local/bin/composer
|
|
||||||
RUN chmod 755 /usr/local/bin/composer
|
|
||||||
|
|
||||||
RUN mkdir /shaarli
|
|
||||||
WORKDIR /shaarli
|
|
||||||
VOLUME /shaarli
|
|
||||||
|
|
||||||
ENTRYPOINT ["make"]
|
|
||||||
CMD []
|
|
|
@ -1,36 +0,0 @@
|
||||||
FROM debian:stretch
|
|
||||||
MAINTAINER Shaarli Community
|
|
||||||
|
|
||||||
ENV TERM dumb
|
|
||||||
ENV DEBIAN_FRONTEND noninteractive
|
|
||||||
ENV LANG en_US.UTF-8
|
|
||||||
ENV LANGUAGE en_US:en
|
|
||||||
|
|
||||||
RUN apt-get update \
|
|
||||||
&& apt-get install --no-install-recommends -y \
|
|
||||||
ca-certificates \
|
|
||||||
curl \
|
|
||||||
locales \
|
|
||||||
make \
|
|
||||||
php7.0 \
|
|
||||||
php7.0-curl \
|
|
||||||
php7.0-gd \
|
|
||||||
php7.0-intl \
|
|
||||||
php7.0-xml \
|
|
||||||
php-xdebug \
|
|
||||||
rsync \
|
|
||||||
&& apt-get clean
|
|
||||||
|
|
||||||
RUN locale-gen en_US.UTF-8 \
|
|
||||||
&& locale-gen de_DE.UTF-8 \
|
|
||||||
&& locale-gen fr_FR.UTF-8
|
|
||||||
|
|
||||||
ADD https://getcomposer.org/composer.phar /usr/local/bin/composer
|
|
||||||
RUN chmod 755 /usr/local/bin/composer
|
|
||||||
|
|
||||||
RUN mkdir /shaarli
|
|
||||||
WORKDIR /shaarli
|
|
||||||
VOLUME /shaarli
|
|
||||||
|
|
||||||
ENTRYPOINT ["make"]
|
|
||||||
CMD []
|
|
|
@ -1,36 +0,0 @@
|
||||||
FROM ubuntu:16.04
|
|
||||||
MAINTAINER Shaarli Community
|
|
||||||
|
|
||||||
ENV TERM dumb
|
|
||||||
ENV DEBIAN_FRONTEND noninteractive
|
|
||||||
ENV LANG en_US.UTF-8
|
|
||||||
ENV LANGUAGE en_US:en
|
|
||||||
|
|
||||||
RUN apt-get update \
|
|
||||||
&& apt-get install --no-install-recommends -y \
|
|
||||||
ca-certificates \
|
|
||||||
curl \
|
|
||||||
language-pack-de \
|
|
||||||
language-pack-en \
|
|
||||||
language-pack-fr \
|
|
||||||
locales \
|
|
||||||
make \
|
|
||||||
php7.0 \
|
|
||||||
php7.0-curl \
|
|
||||||
php7.0-gd \
|
|
||||||
php7.0-intl \
|
|
||||||
php7.0-xml \
|
|
||||||
php-xdebug \
|
|
||||||
rsync \
|
|
||||||
&& apt-get clean
|
|
||||||
|
|
||||||
ADD https://getcomposer.org/composer.phar /usr/local/bin/composer
|
|
||||||
RUN chmod 755 /usr/local/bin/composer
|
|
||||||
|
|
||||||
RUN useradd -m dev \
|
|
||||||
&& mkdir /shaarli
|
|
||||||
USER dev
|
|
||||||
WORKDIR /shaarli
|
|
||||||
|
|
||||||
ENTRYPOINT ["make"]
|
|
||||||
CMD []
|
|
|
@ -1,162 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
/**
|
|
||||||
* PageCache tests
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Shaarli\Feed;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Unitary tests for cached pages
|
|
||||||
*/
|
|
||||||
class CachedPageTest extends \Shaarli\TestCase
|
|
||||||
{
|
|
||||||
// test cache directory
|
|
||||||
protected static $testCacheDir = 'sandbox/pagecache';
|
|
||||||
protected static $url = 'http://shaar.li/feed/atom';
|
|
||||||
protected static $filename;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create the cache directory if needed
|
|
||||||
*/
|
|
||||||
public static function setUpBeforeClass(): void
|
|
||||||
{
|
|
||||||
if (!is_dir(self::$testCacheDir)) {
|
|
||||||
mkdir(self::$testCacheDir);
|
|
||||||
}
|
|
||||||
self::$filename = self::$testCacheDir . '/' . sha1(self::$url) . '.cache';
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reset the page cache
|
|
||||||
*/
|
|
||||||
protected function setUp(): void
|
|
||||||
{
|
|
||||||
if (file_exists(self::$filename)) {
|
|
||||||
unlink(self::$filename);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new cached page
|
|
||||||
*/
|
|
||||||
public function testConstruct()
|
|
||||||
{
|
|
||||||
new CachedPage(self::$testCacheDir, '', true, null);
|
|
||||||
new CachedPage(self::$testCacheDir, '', false, null);
|
|
||||||
new CachedPage(self::$testCacheDir, 'http://shaar.li/feed/rss', true, null);
|
|
||||||
new CachedPage(self::$testCacheDir, 'http://shaar.li/feed/atom', false, null);
|
|
||||||
$this->addToAssertionCount(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Cache a page's content
|
|
||||||
*/
|
|
||||||
public function testCache()
|
|
||||||
{
|
|
||||||
$page = new CachedPage(self::$testCacheDir, self::$url, true, null);
|
|
||||||
|
|
||||||
$this->assertFileNotExists(self::$filename);
|
|
||||||
$page->cache('<p>Some content</p>');
|
|
||||||
$this->assertFileExists(self::$filename);
|
|
||||||
$this->assertEquals(
|
|
||||||
'<p>Some content</p>',
|
|
||||||
file_get_contents(self::$filename)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* "Cache" a page's content - the page is not to be cached
|
|
||||||
*/
|
|
||||||
public function testShouldNotCache()
|
|
||||||
{
|
|
||||||
$page = new CachedPage(self::$testCacheDir, self::$url, false, null);
|
|
||||||
|
|
||||||
$this->assertFileNotExists(self::$filename);
|
|
||||||
$page->cache('<p>Some content</p>');
|
|
||||||
$this->assertFileNotExists(self::$filename);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return a page's cached content
|
|
||||||
*/
|
|
||||||
public function testCachedVersion()
|
|
||||||
{
|
|
||||||
$page = new CachedPage(self::$testCacheDir, self::$url, true, null);
|
|
||||||
|
|
||||||
$this->assertFileNotExists(self::$filename);
|
|
||||||
$page->cache('<p>Some content</p>');
|
|
||||||
$this->assertFileExists(self::$filename);
|
|
||||||
$this->assertEquals(
|
|
||||||
'<p>Some content</p>',
|
|
||||||
$page->cachedVersion()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return a page's cached content - the file does not exist
|
|
||||||
*/
|
|
||||||
public function testCachedVersionNoFile()
|
|
||||||
{
|
|
||||||
$page = new CachedPage(self::$testCacheDir, self::$url, true, null);
|
|
||||||
|
|
||||||
$this->assertFileNotExists(self::$filename);
|
|
||||||
$this->assertEquals(
|
|
||||||
null,
|
|
||||||
$page->cachedVersion()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return a page's cached content - the page is not to be cached
|
|
||||||
*/
|
|
||||||
public function testNoCachedVersion()
|
|
||||||
{
|
|
||||||
$page = new CachedPage(self::$testCacheDir, self::$url, false, null);
|
|
||||||
|
|
||||||
$this->assertFileNotExists(self::$filename);
|
|
||||||
$this->assertEquals(
|
|
||||||
null,
|
|
||||||
$page->cachedVersion()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return a page's cached content within date period
|
|
||||||
*/
|
|
||||||
public function testCachedVersionInDatePeriod()
|
|
||||||
{
|
|
||||||
$period = new \DatePeriod(
|
|
||||||
new \DateTime('yesterday'),
|
|
||||||
new \DateInterval('P1D'),
|
|
||||||
new \DateTime('tomorrow')
|
|
||||||
);
|
|
||||||
$page = new CachedPage(self::$testCacheDir, self::$url, true, $period);
|
|
||||||
|
|
||||||
$this->assertFileNotExists(self::$filename);
|
|
||||||
$page->cache('<p>Some content</p>');
|
|
||||||
$this->assertFileExists(self::$filename);
|
|
||||||
$this->assertEquals(
|
|
||||||
'<p>Some content</p>',
|
|
||||||
$page->cachedVersion()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return a page's cached content outside of date period
|
|
||||||
*/
|
|
||||||
public function testCachedVersionNotInDatePeriod()
|
|
||||||
{
|
|
||||||
$period = new \DatePeriod(
|
|
||||||
new \DateTime('yesterday noon'),
|
|
||||||
new \DateInterval('P1D'),
|
|
||||||
new \DateTime('yesterday midnight')
|
|
||||||
);
|
|
||||||
$page = new CachedPage(self::$testCacheDir, self::$url, true, $period);
|
|
||||||
|
|
||||||
$this->assertFileNotExists(self::$filename);
|
|
||||||
$page->cache('<p>Some content</p>');
|
|
||||||
$this->assertFileExists(self::$filename);
|
|
||||||
$this->assertNull($page->cachedVersion());
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,304 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace Shaarli\Feed;
|
|
||||||
|
|
||||||
use DateTime;
|
|
||||||
use malkusch\lock\mutex\NoMutex;
|
|
||||||
use Shaarli\Bookmark\Bookmark;
|
|
||||||
use Shaarli\Bookmark\BookmarkFileService;
|
|
||||||
use Shaarli\Bookmark\LinkDB;
|
|
||||||
use Shaarli\Config\ConfigManager;
|
|
||||||
use Shaarli\Formatter\FormatterFactory;
|
|
||||||
use Shaarli\History;
|
|
||||||
use Shaarli\Plugin\PluginManager;
|
|
||||||
use Shaarli\TestCase;
|
|
||||||
use Shaarli\Tests\Utils\ReferenceLinkDB;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* FeedBuilderTest class.
|
|
||||||
*
|
|
||||||
* Unit tests for FeedBuilder.
|
|
||||||
*/
|
|
||||||
class FeedBuilderTest extends TestCase
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @var string locale Basque (Spain).
|
|
||||||
*/
|
|
||||||
public static $LOCALE = 'eu_ES';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var string language in RSS format.
|
|
||||||
*/
|
|
||||||
public static $RSS_LANGUAGE = 'eu-es';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var string language in ATOM format.
|
|
||||||
*/
|
|
||||||
public static $ATOM_LANGUAGUE = 'eu';
|
|
||||||
|
|
||||||
protected static $testDatastore = 'sandbox/datastore.php';
|
|
||||||
|
|
||||||
public static $bookmarkService;
|
|
||||||
|
|
||||||
public static $formatter;
|
|
||||||
|
|
||||||
public static $serverInfo;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called before every test method.
|
|
||||||
*/
|
|
||||||
public static function setUpBeforeClass(): void
|
|
||||||
{
|
|
||||||
$mutex = new NoMutex();
|
|
||||||
$conf = new ConfigManager('tests/utils/config/configJson');
|
|
||||||
$conf->set('resource.datastore', self::$testDatastore);
|
|
||||||
$refLinkDB = new ReferenceLinkDB();
|
|
||||||
$refLinkDB->write(self::$testDatastore);
|
|
||||||
$history = new History('sandbox/history.php');
|
|
||||||
$factory = new FormatterFactory($conf, true);
|
|
||||||
$pluginManager = new PluginManager($conf);
|
|
||||||
self::$formatter = $factory->getFormatter();
|
|
||||||
self::$bookmarkService = new BookmarkFileService(
|
|
||||||
$conf,
|
|
||||||
$pluginManager,
|
|
||||||
$history,
|
|
||||||
$mutex,
|
|
||||||
true
|
|
||||||
);
|
|
||||||
|
|
||||||
self::$serverInfo = [
|
|
||||||
'HTTPS' => 'Off',
|
|
||||||
'SERVER_NAME' => 'host.tld',
|
|
||||||
'SERVER_PORT' => '80',
|
|
||||||
'SCRIPT_NAME' => '/index.php',
|
|
||||||
'REQUEST_URI' => '/feed/atom',
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test buildData with RSS feed.
|
|
||||||
*/
|
|
||||||
public function testRSSBuildData()
|
|
||||||
{
|
|
||||||
$feedBuilder = new FeedBuilder(
|
|
||||||
self::$bookmarkService,
|
|
||||||
self::$formatter,
|
|
||||||
static::$serverInfo,
|
|
||||||
false
|
|
||||||
);
|
|
||||||
$feedBuilder->setLocale(self::$LOCALE);
|
|
||||||
$data = $feedBuilder->buildData(FeedBuilder::$FEED_RSS, null);
|
|
||||||
// Test headers (RSS)
|
|
||||||
$this->assertEquals(self::$RSS_LANGUAGE, $data['language']);
|
|
||||||
$this->assertRegExp('/Wed, 03 Aug 2016 09:30:33 \+\d{4}/', $data['last_update']);
|
|
||||||
$this->assertEquals(true, $data['show_dates']);
|
|
||||||
$this->assertEquals('http://host.tld/feed/atom', $data['self_link']);
|
|
||||||
$this->assertEquals('http://host.tld/', $data['index_url']);
|
|
||||||
$this->assertFalse($data['usepermalinks']);
|
|
||||||
$this->assertEquals(ReferenceLinkDB::$NB_LINKS_TOTAL, count($data['links']));
|
|
||||||
|
|
||||||
// Test first not pinned link (note link)
|
|
||||||
$link = $data['links'][array_keys($data['links'])[0]];
|
|
||||||
$this->assertEquals(41, $link['id']);
|
|
||||||
$this->assertEquals(
|
|
||||||
DateTime::createFromFormat(Bookmark::LINK_DATE_FORMAT, '20150310_114651'),
|
|
||||||
$link['created']
|
|
||||||
);
|
|
||||||
$this->assertEquals('http://host.tld/shaare/WDWyig', $link['guid']);
|
|
||||||
$this->assertEquals('http://host.tld/shaare/WDWyig', $link['url']);
|
|
||||||
$this->assertRegExp('/Tue, 10 Mar 2015 11:46:51 \+\d{4}/', $link['pub_iso_date']);
|
|
||||||
$pub = DateTime::createFromFormat(DateTime::RSS, $link['pub_iso_date']);
|
|
||||||
$up = DateTime::createFromFormat(DateTime::ATOM, $link['up_iso_date']);
|
|
||||||
$this->assertEquals($pub, $up);
|
|
||||||
$this->assertContainsPolyfill('Stallman has a beard', $link['description']);
|
|
||||||
$this->assertContainsPolyfill('Permalink', $link['description']);
|
|
||||||
$this->assertContainsPolyfill('http://host.tld/shaare/WDWyig', $link['description']);
|
|
||||||
$this->assertEquals(1, count($link['taglist']));
|
|
||||||
$this->assertEquals('sTuff', $link['taglist'][0]);
|
|
||||||
|
|
||||||
// Test URL with external link.
|
|
||||||
$this->assertEquals('https://static.fsf.org/nosvn/faif-2.0.pdf', $data['links'][8]['url']);
|
|
||||||
|
|
||||||
// Test multitags.
|
|
||||||
$this->assertEquals(5, count($data['links'][6]['taglist']));
|
|
||||||
$this->assertEquals('css', $data['links'][6]['taglist'][0]);
|
|
||||||
|
|
||||||
// Test update date
|
|
||||||
$this->assertRegExp('/2016-08-03T09:30:33\+\d{2}:\d{2}/', $data['links'][8]['up_iso_date']);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test buildData with ATOM feed (test only specific to ATOM).
|
|
||||||
*/
|
|
||||||
public function testAtomBuildData()
|
|
||||||
{
|
|
||||||
$feedBuilder = new FeedBuilder(
|
|
||||||
self::$bookmarkService,
|
|
||||||
self::$formatter,
|
|
||||||
static::$serverInfo,
|
|
||||||
false
|
|
||||||
);
|
|
||||||
$feedBuilder->setLocale(self::$LOCALE);
|
|
||||||
$data = $feedBuilder->buildData(FeedBuilder::$FEED_ATOM, null);
|
|
||||||
$this->assertEquals(ReferenceLinkDB::$NB_LINKS_TOTAL, count($data['links']));
|
|
||||||
$this->assertRegExp('/2016-08-03T09:30:33\+\d{2}:\d{2}/', $data['last_update']);
|
|
||||||
$link = $data['links'][array_keys($data['links'])[0]];
|
|
||||||
$this->assertRegExp('/2015-03-10T11:46:51\+\d{2}:\d{2}/', $link['pub_iso_date']);
|
|
||||||
$this->assertRegExp('/2016-08-03T09:30:33\+\d{2}:\d{2}/', $data['links'][8]['up_iso_date']);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test buildData with search criteria.
|
|
||||||
*/
|
|
||||||
public function testBuildDataFiltered()
|
|
||||||
{
|
|
||||||
$criteria = [
|
|
||||||
'searchtags' => 'stuff',
|
|
||||||
'searchterm' => 'beard',
|
|
||||||
];
|
|
||||||
$feedBuilder = new FeedBuilder(
|
|
||||||
self::$bookmarkService,
|
|
||||||
self::$formatter,
|
|
||||||
static::$serverInfo,
|
|
||||||
false
|
|
||||||
);
|
|
||||||
$feedBuilder->setLocale(self::$LOCALE);
|
|
||||||
$data = $feedBuilder->buildData(FeedBuilder::$FEED_ATOM, $criteria);
|
|
||||||
$this->assertEquals(1, count($data['links']));
|
|
||||||
$link = array_shift($data['links']);
|
|
||||||
$this->assertEquals(41, $link['id']);
|
|
||||||
$this->assertEquals(
|
|
||||||
DateTime::createFromFormat(Bookmark::LINK_DATE_FORMAT, '20150310_114651'),
|
|
||||||
$link['created']
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test buildData with nb limit.
|
|
||||||
*/
|
|
||||||
public function testBuildDataCount()
|
|
||||||
{
|
|
||||||
$criteria = [
|
|
||||||
'nb' => '3',
|
|
||||||
];
|
|
||||||
$feedBuilder = new FeedBuilder(
|
|
||||||
self::$bookmarkService,
|
|
||||||
self::$formatter,
|
|
||||||
static::$serverInfo,
|
|
||||||
false
|
|
||||||
);
|
|
||||||
$feedBuilder->setLocale(self::$LOCALE);
|
|
||||||
$data = $feedBuilder->buildData(FeedBuilder::$FEED_ATOM, $criteria);
|
|
||||||
$this->assertEquals(3, count($data['links']));
|
|
||||||
$link = $data['links'][array_keys($data['links'])[0]];
|
|
||||||
$this->assertEquals(41, $link['id']);
|
|
||||||
$this->assertEquals(
|
|
||||||
DateTime::createFromFormat(Bookmark::LINK_DATE_FORMAT, '20150310_114651'),
|
|
||||||
$link['created']
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test buildData with permalinks on.
|
|
||||||
*/
|
|
||||||
public function testBuildDataPermalinks()
|
|
||||||
{
|
|
||||||
$feedBuilder = new FeedBuilder(
|
|
||||||
self::$bookmarkService,
|
|
||||||
self::$formatter,
|
|
||||||
static::$serverInfo,
|
|
||||||
false
|
|
||||||
);
|
|
||||||
$feedBuilder->setLocale(self::$LOCALE);
|
|
||||||
$feedBuilder->setUsePermalinks(true);
|
|
||||||
$data = $feedBuilder->buildData(FeedBuilder::$FEED_ATOM, null);
|
|
||||||
$this->assertEquals(ReferenceLinkDB::$NB_LINKS_TOTAL, count($data['links']));
|
|
||||||
$this->assertTrue($data['usepermalinks']);
|
|
||||||
// First link is a permalink
|
|
||||||
$link = $data['links'][array_keys($data['links'])[0]];
|
|
||||||
$this->assertEquals(41, $link['id']);
|
|
||||||
$this->assertEquals(
|
|
||||||
DateTime::createFromFormat(Bookmark::LINK_DATE_FORMAT, '20150310_114651'),
|
|
||||||
$link['created']
|
|
||||||
);
|
|
||||||
$this->assertEquals('http://host.tld/shaare/WDWyig', $link['guid']);
|
|
||||||
$this->assertEquals('http://host.tld/shaare/WDWyig', $link['url']);
|
|
||||||
$this->assertContainsPolyfill('Direct link', $link['description']);
|
|
||||||
$this->assertContainsPolyfill('http://host.tld/shaare/WDWyig', $link['description']);
|
|
||||||
// Second link is a direct link
|
|
||||||
$link = $data['links'][array_keys($data['links'])[1]];
|
|
||||||
$this->assertEquals(8, $link['id']);
|
|
||||||
$this->assertEquals(
|
|
||||||
DateTime::createFromFormat(Bookmark::LINK_DATE_FORMAT, '20150310_114633'),
|
|
||||||
$link['created']
|
|
||||||
);
|
|
||||||
$this->assertEquals('http://host.tld/shaare/RttfEw', $link['guid']);
|
|
||||||
$this->assertEquals('https://static.fsf.org/nosvn/faif-2.0.pdf', $link['url']);
|
|
||||||
$this->assertContainsPolyfill('Direct link', $link['description']);
|
|
||||||
$this->assertContainsPolyfill('https://static.fsf.org/nosvn/faif-2.0.pdf', $link['description']);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test buildData with hide dates settings.
|
|
||||||
*/
|
|
||||||
public function testBuildDataHideDates()
|
|
||||||
{
|
|
||||||
$feedBuilder = new FeedBuilder(
|
|
||||||
self::$bookmarkService,
|
|
||||||
self::$formatter,
|
|
||||||
static::$serverInfo,
|
|
||||||
false
|
|
||||||
);
|
|
||||||
$feedBuilder->setLocale(self::$LOCALE);
|
|
||||||
$feedBuilder->setHideDates(true);
|
|
||||||
$data = $feedBuilder->buildData(FeedBuilder::$FEED_ATOM, null);
|
|
||||||
$this->assertEquals(ReferenceLinkDB::$NB_LINKS_TOTAL, count($data['links']));
|
|
||||||
$this->assertFalse($data['show_dates']);
|
|
||||||
|
|
||||||
// Show dates while logged in
|
|
||||||
$feedBuilder = new FeedBuilder(
|
|
||||||
self::$bookmarkService,
|
|
||||||
self::$formatter,
|
|
||||||
static::$serverInfo,
|
|
||||||
true
|
|
||||||
);
|
|
||||||
$feedBuilder->setLocale(self::$LOCALE);
|
|
||||||
$feedBuilder->setHideDates(true);
|
|
||||||
$data = $feedBuilder->buildData(FeedBuilder::$FEED_ATOM, null);
|
|
||||||
$this->assertEquals(ReferenceLinkDB::$NB_LINKS_TOTAL, count($data['links']));
|
|
||||||
$this->assertTrue($data['show_dates']);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test buildData when Shaarli is served from a subdirectory
|
|
||||||
*/
|
|
||||||
public function testBuildDataServerSubdir()
|
|
||||||
{
|
|
||||||
$serverInfo = [
|
|
||||||
'HTTPS' => 'Off',
|
|
||||||
'SERVER_NAME' => 'host.tld',
|
|
||||||
'SERVER_PORT' => '8080',
|
|
||||||
'SCRIPT_NAME' => '/~user/shaarli/index.php',
|
|
||||||
'REQUEST_URI' => '/~user/shaarli/feed/atom',
|
|
||||||
];
|
|
||||||
$feedBuilder = new FeedBuilder(
|
|
||||||
self::$bookmarkService,
|
|
||||||
self::$formatter,
|
|
||||||
$serverInfo,
|
|
||||||
false
|
|
||||||
);
|
|
||||||
$feedBuilder->setLocale(self::$LOCALE);
|
|
||||||
$data = $feedBuilder->buildData(FeedBuilder::$FEED_ATOM, null);
|
|
||||||
|
|
||||||
$this->assertEquals(
|
|
||||||
'http://host.tld:8080/~user/shaarli/feed/atom',
|
|
||||||
$data['self_link']
|
|
||||||
);
|
|
||||||
|
|
||||||
// Test first link (note link)
|
|
||||||
$link = $data['links'][array_keys($data['links'])[0]];
|
|
||||||
$this->assertEquals('http://host.tld:8080/~user/shaarli/shaare/WDWyig', $link['guid']);
|
|
||||||
$this->assertEquals('http://host.tld:8080/~user/shaarli/shaare/WDWyig', $link['url']);
|
|
||||||
$this->assertContainsPolyfill('http://host.tld:8080/~user/shaarli/./add-tag/hashtag', $link['description']);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,319 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace Shaarli\Formatter;
|
|
||||||
|
|
||||||
use DateTime;
|
|
||||||
use Shaarli\Bookmark\Bookmark;
|
|
||||||
use Shaarli\Config\ConfigManager;
|
|
||||||
use Shaarli\TestCase;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Class BookmarkDefaultFormatterTest
|
|
||||||
* @package Shaarli\Formatter
|
|
||||||
*/
|
|
||||||
class BookmarkDefaultFormatterTest extends TestCase
|
|
||||||
{
|
|
||||||
/** @var string Path of test config file */
|
|
||||||
protected static $testConf = 'sandbox/config';
|
|
||||||
|
|
||||||
/** @var BookmarkFormatter */
|
|
||||||
protected $formatter;
|
|
||||||
|
|
||||||
/** @var ConfigManager instance */
|
|
||||||
protected $conf;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize formatter instance.
|
|
||||||
*/
|
|
||||||
protected function setUp(): void
|
|
||||||
{
|
|
||||||
copy('tests/utils/config/configJson.json.php', self::$testConf . '.json.php');
|
|
||||||
$this->conf = new ConfigManager(self::$testConf);
|
|
||||||
$this->formatter = new BookmarkDefaultFormatter($this->conf, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test formatting a bookmark with all its attribute filled.
|
|
||||||
*/
|
|
||||||
public function testFormatFull()
|
|
||||||
{
|
|
||||||
$bookmark = new Bookmark();
|
|
||||||
$bookmark->setId($id = 11);
|
|
||||||
$bookmark->setShortUrl($short = 'abcdef');
|
|
||||||
$bookmark->setUrl('https://sub.domain.tld?query=here&for=real#hash');
|
|
||||||
$bookmark->setTitle($title = 'This is a <strong>bookmark</strong>');
|
|
||||||
$bookmark->setDescription($desc = '<h2>Content</h2><p>`Here is some content</p>');
|
|
||||||
$bookmark->setTags($tags = ['tag1', 'bookmark', 'other', '<script>alert("xss");</script>']);
|
|
||||||
$bookmark->setThumbnail('http://domain2.tdl2/?type=img&name=file.png');
|
|
||||||
$bookmark->setSticky(true);
|
|
||||||
$bookmark->setCreated($created = DateTime::createFromFormat('Ymd_His', '20190521_190412'));
|
|
||||||
$bookmark->setUpdated($updated = DateTime::createFromFormat('Ymd_His', '20190521_191213'));
|
|
||||||
$bookmark->setPrivate(true);
|
|
||||||
|
|
||||||
$link = $this->formatter->format($bookmark);
|
|
||||||
$this->assertEquals($id, $link['id']);
|
|
||||||
$this->assertEquals($short, $link['shorturl']);
|
|
||||||
$this->assertEquals('https://sub.domain.tld?query=here&for=real#hash', $link['url']);
|
|
||||||
$this->assertEquals(
|
|
||||||
'https://sub.domain.tld?query=here&for=real#hash',
|
|
||||||
$link['real_url']
|
|
||||||
);
|
|
||||||
$this->assertEquals('This is a <strong>bookmark</strong>', $link['title']);
|
|
||||||
$this->assertEquals(
|
|
||||||
'<h2>Content</h2><p>`Here is some content</p>',
|
|
||||||
$link['description']
|
|
||||||
);
|
|
||||||
$tags[3] = '<script>alert("xss");</script>';
|
|
||||||
$this->assertEquals($tags, $link['taglist']);
|
|
||||||
$this->assertEquals(implode(' ', $tags), $link['tags']);
|
|
||||||
$this->assertEquals(
|
|
||||||
'http://domain2.tdl2/?type=img&name=file.png',
|
|
||||||
$link['thumbnail']
|
|
||||||
);
|
|
||||||
$this->assertEquals($created, $link['created']);
|
|
||||||
$this->assertEquals($created->getTimestamp(), $link['timestamp']);
|
|
||||||
$this->assertEquals($updated, $link['updated']);
|
|
||||||
$this->assertEquals($updated->getTimestamp(), $link['updated_timestamp']);
|
|
||||||
$this->assertTrue($link['private']);
|
|
||||||
$this->assertTrue($link['sticky']);
|
|
||||||
$this->assertEquals('private', $link['class']);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test formatting a bookmark with all its attribute filled.
|
|
||||||
*/
|
|
||||||
public function testFormatMinimal()
|
|
||||||
{
|
|
||||||
$bookmark = new Bookmark();
|
|
||||||
|
|
||||||
$link = $this->formatter->format($bookmark);
|
|
||||||
$this->assertEmpty($link['id']);
|
|
||||||
$this->assertEmpty($link['shorturl']);
|
|
||||||
$this->assertEmpty($link['url']);
|
|
||||||
$this->assertEmpty($link['real_url']);
|
|
||||||
$this->assertEmpty($link['title']);
|
|
||||||
$this->assertEmpty($link['description']);
|
|
||||||
$this->assertEmpty($link['taglist']);
|
|
||||||
$this->assertEmpty($link['tags']);
|
|
||||||
$this->assertEmpty($link['thumbnail']);
|
|
||||||
$this->assertEmpty($link['created']);
|
|
||||||
$this->assertEmpty($link['timestamp']);
|
|
||||||
$this->assertEmpty($link['updated']);
|
|
||||||
$this->assertEmpty($link['updated_timestamp']);
|
|
||||||
$this->assertFalse($link['private']);
|
|
||||||
$this->assertFalse($link['sticky']);
|
|
||||||
$this->assertEmpty($link['class']);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Make sure that the description is properly formatted by the default formatter.
|
|
||||||
*/
|
|
||||||
public function testFormatDescription()
|
|
||||||
{
|
|
||||||
$description = [];
|
|
||||||
$description[] = 'This a <strong>description</strong>' . PHP_EOL;
|
|
||||||
$description[] = 'text https://sub.domain.tld?query=here&for=real#hash more text' . PHP_EOL;
|
|
||||||
$description[] = 'Also, there is an #hashtag added' . PHP_EOL;
|
|
||||||
$description[] = ' A N D KEEP SPACES ! ' . PHP_EOL;
|
|
||||||
|
|
||||||
$bookmark = new Bookmark();
|
|
||||||
$bookmark->setDescription(implode('', $description));
|
|
||||||
$link = $this->formatter->format($bookmark);
|
|
||||||
|
|
||||||
$description[0] = 'This a <strong>description</strong><br />';
|
|
||||||
$url = 'https://sub.domain.tld?query=here&for=real#hash';
|
|
||||||
$description[1] = 'text <a href="' . $url . '">' . $url . '</a> more text<br />';
|
|
||||||
$description[2] = 'Also, there is an <a href="./add-tag/hashtag" ' .
|
|
||||||
'title="Hashtag hashtag">#hashtag</a> added<br />';
|
|
||||||
$description[3] = ' A N D KEEP ' .
|
|
||||||
'SPACES ! <br />';
|
|
||||||
|
|
||||||
$this->assertEquals(implode(PHP_EOL, $description) . PHP_EOL, $link['description']);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test formatting URL with an index_url set
|
|
||||||
* It should prepend relative links.
|
|
||||||
*/
|
|
||||||
public function testFormatNoteWithIndexUrl()
|
|
||||||
{
|
|
||||||
$bookmark = new Bookmark();
|
|
||||||
$bookmark->setUrl($short = '?abcdef');
|
|
||||||
$description = 'Text #hashtag more text';
|
|
||||||
$bookmark->setDescription($description);
|
|
||||||
|
|
||||||
$this->formatter->addContextData('index_url', $root = 'https://domain.tld/hithere/');
|
|
||||||
|
|
||||||
$link = $this->formatter->format($bookmark);
|
|
||||||
$this->assertEquals($root . $short, $link['url']);
|
|
||||||
$this->assertEquals($root . $short, $link['real_url']);
|
|
||||||
$this->assertEquals(
|
|
||||||
'Text <a href="' . $root . './add-tag/hashtag" title="Hashtag hashtag">' .
|
|
||||||
'#hashtag</a> more text',
|
|
||||||
$link['description']
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Make sure that private tags are properly filtered out when the user is logged out.
|
|
||||||
*/
|
|
||||||
public function testFormatTagListRemovePrivate(): void
|
|
||||||
{
|
|
||||||
$this->formatter = new BookmarkDefaultFormatter($this->conf, false);
|
|
||||||
|
|
||||||
$bookmark = new Bookmark();
|
|
||||||
$bookmark->setId($id = 11);
|
|
||||||
$bookmark->setTags($tags = ['bookmark', '.private', 'othertag']);
|
|
||||||
|
|
||||||
$link = $this->formatter->format($bookmark);
|
|
||||||
|
|
||||||
unset($tags[1]);
|
|
||||||
$tags = array_values($tags);
|
|
||||||
|
|
||||||
$this->assertSame(11, $link['id']);
|
|
||||||
$this->assertSame($tags, $link['taglist']);
|
|
||||||
$this->assertSame(implode(' ', $tags), $link['tags']);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test formatTitleHtml with search result highlight.
|
|
||||||
*/
|
|
||||||
public function testFormatTitleHtmlWithSearchHighlight(): void
|
|
||||||
{
|
|
||||||
$this->formatter = new BookmarkDefaultFormatter($this->conf, false);
|
|
||||||
|
|
||||||
$bookmark = new Bookmark();
|
|
||||||
$bookmark->setTitle('PSR-2: Coding Style Guide');
|
|
||||||
$bookmark->setAdditionalContentEntry(
|
|
||||||
'search_highlight',
|
|
||||||
['title' => [
|
|
||||||
['start' => 0, 'end' => 5], // "psr-2"
|
|
||||||
['start' => 7, 'end' => 13], // coding
|
|
||||||
['start' => 20, 'end' => 25], // guide
|
|
||||||
]]
|
|
||||||
);
|
|
||||||
|
|
||||||
$link = $this->formatter->format($bookmark);
|
|
||||||
|
|
||||||
$this->assertSame(
|
|
||||||
'<span class="search-highlight">PSR-2</span>: ' .
|
|
||||||
'<span class="search-highlight">Coding</span> Style ' .
|
|
||||||
'<span class="search-highlight">Guide</span>',
|
|
||||||
$link['title_html']
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test formatDescription with search result highlight.
|
|
||||||
*/
|
|
||||||
public function testFormatDescriptionWithSearchHighlight(): void
|
|
||||||
{
|
|
||||||
$this->formatter = new BookmarkDefaultFormatter($this->conf, false);
|
|
||||||
|
|
||||||
$bookmark = new Bookmark();
|
|
||||||
$bookmark->setDescription(
|
|
||||||
'This guide extends and expands on PSR-1, the basic coding standard.' . PHP_EOL .
|
|
||||||
'https://www.php-fig.org/psr/psr-1/'
|
|
||||||
);
|
|
||||||
$bookmark->setAdditionalContentEntry(
|
|
||||||
'search_highlight',
|
|
||||||
['description' => [
|
|
||||||
['start' => 0, 'end' => 10], // "This guide"
|
|
||||||
['start' => 45, 'end' => 50], // basic
|
|
||||||
['start' => 58, 'end' => 67], // standard.
|
|
||||||
['start' => 84, 'end' => 87], // fig
|
|
||||||
]]
|
|
||||||
);
|
|
||||||
|
|
||||||
$link = $this->formatter->format($bookmark);
|
|
||||||
|
|
||||||
$this->assertSame(
|
|
||||||
'<span class="search-highlight">This guide</span> extends and expands on PSR-1, the ' .
|
|
||||||
'<span class="search-highlight">basic</span> coding ' .
|
|
||||||
'<span class="search-highlight">standard.</span><br />' . PHP_EOL .
|
|
||||||
'<a href="https://www.php-fig.org/psr/psr-1/">' .
|
|
||||||
'https://www.php-<span class="search-highlight">fig</span>.org/psr/psr-1/' .
|
|
||||||
'</a>',
|
|
||||||
$link['description']
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test formatUrlHtml with search result highlight.
|
|
||||||
*/
|
|
||||||
public function testFormatUrlHtmlWithSearchHighlight(): void
|
|
||||||
{
|
|
||||||
$this->formatter = new BookmarkDefaultFormatter($this->conf, false);
|
|
||||||
|
|
||||||
$bookmark = new Bookmark();
|
|
||||||
$bookmark->setUrl('http://www.php-fig.org/psr/psr-2/');
|
|
||||||
$bookmark->setAdditionalContentEntry(
|
|
||||||
'search_highlight',
|
|
||||||
['url' => [
|
|
||||||
['start' => 0, 'end' => 4], // http
|
|
||||||
['start' => 15, 'end' => 18], // fig
|
|
||||||
['start' => 27, 'end' => 33], // "psr-2/"
|
|
||||||
]]
|
|
||||||
);
|
|
||||||
|
|
||||||
$link = $this->formatter->format($bookmark);
|
|
||||||
|
|
||||||
$this->assertSame(
|
|
||||||
'<span class="search-highlight">http</span>://www.php-' .
|
|
||||||
'<span class="search-highlight">fig</span>.org/psr/' .
|
|
||||||
'<span class="search-highlight">psr-2/</span>',
|
|
||||||
$link['url_html']
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test formatTagListHtml with search result highlight.
|
|
||||||
*/
|
|
||||||
public function testFormatTagListHtmlWithSearchHighlight(): void
|
|
||||||
{
|
|
||||||
$this->formatter = new BookmarkDefaultFormatter($this->conf, false);
|
|
||||||
|
|
||||||
$bookmark = new Bookmark();
|
|
||||||
$bookmark->setTagsString('coding-style standards quality assurance');
|
|
||||||
$bookmark->setAdditionalContentEntry(
|
|
||||||
'search_highlight',
|
|
||||||
['tags' => [
|
|
||||||
['start' => 0, 'end' => 12], // coding-style
|
|
||||||
['start' => 23, 'end' => 30], // quality
|
|
||||||
['start' => 31, 'end' => 40], // assurance
|
|
||||||
],]
|
|
||||||
);
|
|
||||||
|
|
||||||
$link = $this->formatter->format($bookmark);
|
|
||||||
|
|
||||||
$this->assertSame(
|
|
||||||
[
|
|
||||||
'<span class="search-highlight">coding-style</span>',
|
|
||||||
'standards',
|
|
||||||
'<span class="search-highlight">quality</span>',
|
|
||||||
'<span class="search-highlight">assurance</span>',
|
|
||||||
],
|
|
||||||
$link['taglist_html']
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test default formatting with formatter_settings.autolink set to false:
|
|
||||||
* URLs and hashtags should not be transformed
|
|
||||||
*/
|
|
||||||
public function testFormatDescriptionWithoutLinkification(): void
|
|
||||||
{
|
|
||||||
$this->conf->set('formatter_settings.autolink', false);
|
|
||||||
$this->formatter = new BookmarkDefaultFormatter($this->conf, false);
|
|
||||||
|
|
||||||
$bookmark = new Bookmark();
|
|
||||||
$bookmark->setDescription('Hi!' . PHP_EOL . 'https://thisisaurl.tld #hashtag');
|
|
||||||
|
|
||||||
$link = $this->formatter->format($bookmark);
|
|
||||||
|
|
||||||
static::assertSame(
|
|
||||||
'Hi!<br />' . PHP_EOL . 'https://thisisaurl.tld #hashtag',
|
|
||||||
$link['description']
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,162 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace Shaarli\Formatter;
|
|
||||||
|
|
||||||
use DateTime;
|
|
||||||
use PHPUnit\Framework\TestCase;
|
|
||||||
use Shaarli\Bookmark\Bookmark;
|
|
||||||
use Shaarli\Config\ConfigManager;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Class BookmarkMarkdownExtraFormatterTest
|
|
||||||
* @package Shaarli\Formatter
|
|
||||||
*/
|
|
||||||
class BookmarkMarkdownExtraFormatterTest extends TestCase
|
|
||||||
{
|
|
||||||
/** @var string Path of test config file */
|
|
||||||
protected static $testConf = 'sandbox/config';
|
|
||||||
|
|
||||||
/** @var BookmarkFormatter */
|
|
||||||
protected $formatter;
|
|
||||||
|
|
||||||
/** @var ConfigManager instance */
|
|
||||||
protected $conf;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize formatter instance.
|
|
||||||
*/
|
|
||||||
public function setUp(): void
|
|
||||||
{
|
|
||||||
copy('tests/utils/config/configJson.json.php', self::$testConf . '.json.php');
|
|
||||||
$this->conf = new ConfigManager(self::$testConf);
|
|
||||||
$this->formatter = new BookmarkMarkdownExtraFormatter($this->conf, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test formatting a bookmark with all its attribute filled.
|
|
||||||
*/
|
|
||||||
public function testFormatExtra(): void
|
|
||||||
{
|
|
||||||
$bookmark = new Bookmark();
|
|
||||||
$bookmark->setId($id = 11);
|
|
||||||
$bookmark->setShortUrl($short = 'abcdef');
|
|
||||||
$bookmark->setUrl('https://sub.domain.tld?query=here&for=real#hash');
|
|
||||||
$bookmark->setTitle($title = 'This is a <strong>bookmark</strong>');
|
|
||||||
$bookmark->setDescription('<h2>Content</h2><p>`Here is some content</p>');
|
|
||||||
$bookmark->setTags($tags = ['tag1', 'bookmark', 'other', '<script>alert("xss");</script>']);
|
|
||||||
$bookmark->setThumbnail('http://domain2.tdl2/?type=img&name=file.png');
|
|
||||||
$bookmark->setSticky(true);
|
|
||||||
$bookmark->setCreated($created = DateTime::createFromFormat('Ymd_His', '20190521_190412'));
|
|
||||||
$bookmark->setUpdated($updated = DateTime::createFromFormat('Ymd_His', '20190521_191213'));
|
|
||||||
$bookmark->setPrivate(true);
|
|
||||||
|
|
||||||
$link = $this->formatter->format($bookmark);
|
|
||||||
$this->assertEquals($id, $link['id']);
|
|
||||||
$this->assertEquals($short, $link['shorturl']);
|
|
||||||
$this->assertEquals('https://sub.domain.tld?query=here&for=real#hash', $link['url']);
|
|
||||||
$this->assertEquals(
|
|
||||||
'https://sub.domain.tld?query=here&for=real#hash',
|
|
||||||
$link['real_url']
|
|
||||||
);
|
|
||||||
$this->assertEquals('This is a <strong>bookmark</strong>', $link['title']);
|
|
||||||
$this->assertEquals(
|
|
||||||
'<div class="markdown"><p>' .
|
|
||||||
'<h2>Content</h2><p>`Here is some content</p>' .
|
|
||||||
'</p></div>',
|
|
||||||
$link['description']
|
|
||||||
);
|
|
||||||
$tags[3] = '<script>alert("xss");</script>';
|
|
||||||
$this->assertEquals($tags, $link['taglist']);
|
|
||||||
$this->assertEquals(implode(' ', $tags), $link['tags']);
|
|
||||||
$this->assertEquals(
|
|
||||||
'http://domain2.tdl2/?type=img&name=file.png',
|
|
||||||
$link['thumbnail']
|
|
||||||
);
|
|
||||||
$this->assertEquals($created, $link['created']);
|
|
||||||
$this->assertEquals($created->getTimestamp(), $link['timestamp']);
|
|
||||||
$this->assertEquals($updated, $link['updated']);
|
|
||||||
$this->assertEquals($updated->getTimestamp(), $link['updated_timestamp']);
|
|
||||||
$this->assertTrue($link['private']);
|
|
||||||
$this->assertTrue($link['sticky']);
|
|
||||||
$this->assertEquals('private', $link['class']);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test formatting a bookmark with all its attribute filled.
|
|
||||||
*/
|
|
||||||
public function testFormatExtraMinimal(): void
|
|
||||||
{
|
|
||||||
$bookmark = new Bookmark();
|
|
||||||
|
|
||||||
$link = $this->formatter->format($bookmark);
|
|
||||||
$this->assertEmpty($link['id']);
|
|
||||||
$this->assertEmpty($link['shorturl']);
|
|
||||||
$this->assertEmpty($link['url']);
|
|
||||||
$this->assertEmpty($link['real_url']);
|
|
||||||
$this->assertEmpty($link['title']);
|
|
||||||
$this->assertEmpty($link['description']);
|
|
||||||
$this->assertEmpty($link['taglist']);
|
|
||||||
$this->assertEmpty($link['tags']);
|
|
||||||
$this->assertEmpty($link['thumbnail']);
|
|
||||||
$this->assertEmpty($link['created']);
|
|
||||||
$this->assertEmpty($link['timestamp']);
|
|
||||||
$this->assertEmpty($link['updated']);
|
|
||||||
$this->assertEmpty($link['updated_timestamp']);
|
|
||||||
$this->assertFalse($link['private']);
|
|
||||||
$this->assertFalse($link['sticky']);
|
|
||||||
$this->assertEmpty($link['class']);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Make sure that the description is properly formatted by the default formatter.
|
|
||||||
*/
|
|
||||||
public function testFormatExtrraDescription(): void
|
|
||||||
{
|
|
||||||
$description = 'This a <strong>description</strong>' . PHP_EOL;
|
|
||||||
$description .= 'text https://sub.domain.tld?query=here&for=real#hash more text' . PHP_EOL;
|
|
||||||
$description .= 'Also, there is an #hashtag added' . PHP_EOL;
|
|
||||||
$description .= ' A N D KEEP SPACES ! ' . PHP_EOL;
|
|
||||||
$description .= '# Header {.class}' . PHP_EOL;
|
|
||||||
|
|
||||||
$bookmark = new Bookmark();
|
|
||||||
$bookmark->setDescription($description);
|
|
||||||
$link = $this->formatter->format($bookmark);
|
|
||||||
|
|
||||||
$description = '<div class="markdown"><p>';
|
|
||||||
$description .= 'This a <strong>description</strong><br />' . PHP_EOL;
|
|
||||||
$url = 'https://sub.domain.tld?query=here&for=real#hash';
|
|
||||||
$description .= 'text <a href="' . $url . '">' . $url . '</a> more text<br />' . PHP_EOL;
|
|
||||||
$description .= 'Also, there is an <a href="./add-tag/hashtag">#hashtag</a> added<br />' . PHP_EOL;
|
|
||||||
$description .= 'A N D KEEP SPACES ! </p>' . PHP_EOL;
|
|
||||||
$description .= '<h1 class="class">Header</h1>';
|
|
||||||
$description .= '</div>';
|
|
||||||
|
|
||||||
$this->assertEquals($description, $link['description']);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test formatting URL with an index_url set
|
|
||||||
* It should prepend relative links.
|
|
||||||
*/
|
|
||||||
public function testFormatExtraNoteWithIndexUrl(): void
|
|
||||||
{
|
|
||||||
$bookmark = new Bookmark();
|
|
||||||
$bookmark->setUrl($short = '?abcdef');
|
|
||||||
$description = 'Text #hashtag more text';
|
|
||||||
$bookmark->setDescription($description);
|
|
||||||
|
|
||||||
$this->formatter->addContextData('index_url', $root = 'https://domain.tld/hithere/');
|
|
||||||
|
|
||||||
$description = '<div class="markdown"><p>';
|
|
||||||
$description .= 'Text <a href="' . $root . './add-tag/hashtag">#hashtag</a> more text';
|
|
||||||
$description .= '</p></div>';
|
|
||||||
|
|
||||||
$link = $this->formatter->format($bookmark);
|
|
||||||
$this->assertEquals($root . $short, $link['url']);
|
|
||||||
$this->assertEquals($root . $short, $link['real_url']);
|
|
||||||
$this->assertEquals(
|
|
||||||
$description,
|
|
||||||
$link['description']
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,203 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace Shaarli\Formatter;
|
|
||||||
|
|
||||||
use DateTime;
|
|
||||||
use Shaarli\Bookmark\Bookmark;
|
|
||||||
use Shaarli\Config\ConfigManager;
|
|
||||||
use Shaarli\TestCase;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Class BookmarkMarkdownFormatterTest
|
|
||||||
* @package Shaarli\Formatter
|
|
||||||
*/
|
|
||||||
class BookmarkMarkdownFormatterTest extends TestCase
|
|
||||||
{
|
|
||||||
/** @var string Path of test config file */
|
|
||||||
protected static $testConf = 'sandbox/config';
|
|
||||||
|
|
||||||
/** @var BookmarkFormatter */
|
|
||||||
protected $formatter;
|
|
||||||
|
|
||||||
/** @var ConfigManager instance */
|
|
||||||
protected $conf;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize formatter instance.
|
|
||||||
*/
|
|
||||||
protected function setUp(): void
|
|
||||||
{
|
|
||||||
copy('tests/utils/config/configJson.json.php', self::$testConf . '.json.php');
|
|
||||||
$this->conf = new ConfigManager(self::$testConf);
|
|
||||||
$this->formatter = new BookmarkMarkdownFormatter($this->conf, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test formatting a bookmark with all its attribute filled.
|
|
||||||
*/
|
|
||||||
public function testFormatFull()
|
|
||||||
{
|
|
||||||
$bookmark = new Bookmark();
|
|
||||||
$bookmark->setId($id = 11);
|
|
||||||
$bookmark->setShortUrl($short = 'abcdef');
|
|
||||||
$bookmark->setUrl('https://sub.domain.tld?query=here&for=real#hash');
|
|
||||||
$bookmark->setTitle($title = 'This is a <strong>bookmark</strong>');
|
|
||||||
$bookmark->setDescription('<h2>Content</h2><p>`Here is some content</p>');
|
|
||||||
$bookmark->setTags($tags = ['tag1', 'bookmark', 'other', '<script>alert("xss");</script>']);
|
|
||||||
$bookmark->setThumbnail('http://domain2.tdl2/?type=img&name=file.png');
|
|
||||||
$bookmark->setSticky(true);
|
|
||||||
$bookmark->setCreated($created = DateTime::createFromFormat('Ymd_His', '20190521_190412'));
|
|
||||||
$bookmark->setUpdated($updated = DateTime::createFromFormat('Ymd_His', '20190521_191213'));
|
|
||||||
$bookmark->setPrivate(true);
|
|
||||||
|
|
||||||
$link = $this->formatter->format($bookmark);
|
|
||||||
$this->assertEquals($id, $link['id']);
|
|
||||||
$this->assertEquals($short, $link['shorturl']);
|
|
||||||
$this->assertEquals('https://sub.domain.tld?query=here&for=real#hash', $link['url']);
|
|
||||||
$this->assertEquals(
|
|
||||||
'https://sub.domain.tld?query=here&for=real#hash',
|
|
||||||
$link['real_url']
|
|
||||||
);
|
|
||||||
$this->assertEquals('This is a <strong>bookmark</strong>', $link['title']);
|
|
||||||
$this->assertEquals(
|
|
||||||
'<div class="markdown"><p>' .
|
|
||||||
'<h2>Content</h2><p>`Here is some content</p>' .
|
|
||||||
'</p></div>',
|
|
||||||
$link['description']
|
|
||||||
);
|
|
||||||
$tags[3] = '<script>alert("xss");</script>';
|
|
||||||
$this->assertEquals($tags, $link['taglist']);
|
|
||||||
$this->assertEquals(implode(' ', $tags), $link['tags']);
|
|
||||||
$this->assertEquals(
|
|
||||||
'http://domain2.tdl2/?type=img&name=file.png',
|
|
||||||
$link['thumbnail']
|
|
||||||
);
|
|
||||||
$this->assertEquals($created, $link['created']);
|
|
||||||
$this->assertEquals($created->getTimestamp(), $link['timestamp']);
|
|
||||||
$this->assertEquals($updated, $link['updated']);
|
|
||||||
$this->assertEquals($updated->getTimestamp(), $link['updated_timestamp']);
|
|
||||||
$this->assertTrue($link['private']);
|
|
||||||
$this->assertTrue($link['sticky']);
|
|
||||||
$this->assertEquals('private', $link['class']);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test formatting a bookmark with all its attribute filled.
|
|
||||||
*/
|
|
||||||
public function testFormatMinimal()
|
|
||||||
{
|
|
||||||
$bookmark = new Bookmark();
|
|
||||||
|
|
||||||
$link = $this->formatter->format($bookmark);
|
|
||||||
$this->assertEmpty($link['id']);
|
|
||||||
$this->assertEmpty($link['shorturl']);
|
|
||||||
$this->assertEmpty($link['url']);
|
|
||||||
$this->assertEmpty($link['real_url']);
|
|
||||||
$this->assertEmpty($link['title']);
|
|
||||||
$this->assertEmpty($link['description']);
|
|
||||||
$this->assertEmpty($link['taglist']);
|
|
||||||
$this->assertEmpty($link['tags']);
|
|
||||||
$this->assertEmpty($link['thumbnail']);
|
|
||||||
$this->assertEmpty($link['created']);
|
|
||||||
$this->assertEmpty($link['timestamp']);
|
|
||||||
$this->assertEmpty($link['updated']);
|
|
||||||
$this->assertEmpty($link['updated_timestamp']);
|
|
||||||
$this->assertFalse($link['private']);
|
|
||||||
$this->assertFalse($link['sticky']);
|
|
||||||
$this->assertEmpty($link['class']);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Make sure that the description is properly formatted by the default formatter.
|
|
||||||
*/
|
|
||||||
public function testFormatDescription()
|
|
||||||
{
|
|
||||||
$description = 'This a <strong>description</strong>' . PHP_EOL;
|
|
||||||
$description .= 'text https://sub.domain.tld?query=here&for=real#hash more text' . PHP_EOL;
|
|
||||||
$description .= 'Also, there is an #hashtag added' . PHP_EOL;
|
|
||||||
$description .= ' A N D KEEP SPACES ! ' . PHP_EOL;
|
|
||||||
|
|
||||||
$bookmark = new Bookmark();
|
|
||||||
$bookmark->setDescription($description);
|
|
||||||
$link = $this->formatter->format($bookmark);
|
|
||||||
|
|
||||||
$description = '<div class="markdown"><p>';
|
|
||||||
$description .= 'This a <strong>description</strong><br />' . PHP_EOL;
|
|
||||||
$url = 'https://sub.domain.tld?query=here&for=real#hash';
|
|
||||||
$description .= 'text <a href="' . $url . '">' . $url . '</a> more text<br />' . PHP_EOL;
|
|
||||||
$description .= 'Also, there is an <a href="./add-tag/hashtag">#hashtag</a> added<br />' . PHP_EOL;
|
|
||||||
$description .= 'A N D KEEP SPACES ! ';
|
|
||||||
$description .= '</p></div>';
|
|
||||||
|
|
||||||
$this->assertEquals($description, $link['description']);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Make sure that the description is properly formatted by the default formatter.
|
|
||||||
*/
|
|
||||||
public function testFormatDescriptionWithSearchHighlight()
|
|
||||||
{
|
|
||||||
$description = 'This a <strong>description</strong>' . PHP_EOL;
|
|
||||||
$description .= 'text https://sub.domain.tld?query=here&for=real#hash more text' . PHP_EOL;
|
|
||||||
$description .= 'Also, there is an #hashtag added' . PHP_EOL;
|
|
||||||
$description .= ' A N D KEEP SPACES ! ' . PHP_EOL;
|
|
||||||
$description .= 'And [yet another link](https://other.domain.tld)' . PHP_EOL;
|
|
||||||
|
|
||||||
$bookmark = new Bookmark();
|
|
||||||
$bookmark->setDescription($description);
|
|
||||||
$bookmark->setAdditionalContentEntry(
|
|
||||||
'search_highlight',
|
|
||||||
['description' => [
|
|
||||||
['start' => 18, 'end' => 26], // cription
|
|
||||||
['start' => 49, 'end' => 52], // sub
|
|
||||||
['start' => 84, 'end' => 88], // hash
|
|
||||||
['start' => 118, 'end' => 123], // hasht
|
|
||||||
['start' => 203, 'end' => 215], // other.domain
|
|
||||||
]]
|
|
||||||
);
|
|
||||||
|
|
||||||
$link = $this->formatter->format($bookmark);
|
|
||||||
|
|
||||||
$description = '<div class="markdown"><p>';
|
|
||||||
$description .= 'This a <strong>des<span class="search-highlight">cription</span></strong><br />' .
|
|
||||||
PHP_EOL;
|
|
||||||
$url = 'https://sub.domain.tld?query=here&for=real#hash';
|
|
||||||
$highlighted = 'https://<span class="search-highlight">sub</span>.domain.tld';
|
|
||||||
$highlighted .= '?query=here&for=real#<span class="search-highlight">hash</span>';
|
|
||||||
$description .= 'text <a href="' . $url . '">' . $highlighted . '</a> more text<br />' . PHP_EOL;
|
|
||||||
$description .= 'Also, there is an <a href="./add-tag/hashtag">#<span class="search-highlight">hasht</span>' .
|
|
||||||
'ag</a> added<br />' . PHP_EOL;
|
|
||||||
$description .= 'A N D KEEP SPACES !<br />' . PHP_EOL;
|
|
||||||
$description .= 'And <a href="https://other.domain.tld">' .
|
|
||||||
'<span class="search-highlight">yet another link</span></a>';
|
|
||||||
$description .= '</p></div>';
|
|
||||||
|
|
||||||
$this->assertEquals($description, $link['description']);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test formatting URL with an index_url set
|
|
||||||
* It should prepend relative links.
|
|
||||||
*/
|
|
||||||
public function testFormatNoteWithIndexUrl()
|
|
||||||
{
|
|
||||||
$bookmark = new Bookmark();
|
|
||||||
$bookmark->setUrl($short = '?abcdef');
|
|
||||||
$description = 'Text #hashtag more text';
|
|
||||||
$bookmark->setDescription($description);
|
|
||||||
|
|
||||||
$this->formatter->addContextData('index_url', $root = 'https://domain.tld/hithere/');
|
|
||||||
|
|
||||||
$description = '<div class="markdown"><p>';
|
|
||||||
$description .= 'Text <a href="' . $root . './add-tag/hashtag">#hashtag</a> more text';
|
|
||||||
$description .= '</p></div>';
|
|
||||||
|
|
||||||
$link = $this->formatter->format($bookmark);
|
|
||||||
$this->assertEquals($root . $short, $link['url']);
|
|
||||||
$this->assertEquals($root . $short, $link['real_url']);
|
|
||||||
$this->assertEquals(
|
|
||||||
$description,
|
|
||||||
$link['description']
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,97 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace Shaarli\Formatter;
|
|
||||||
|
|
||||||
use DateTime;
|
|
||||||
use Shaarli\Bookmark\Bookmark;
|
|
||||||
use Shaarli\Config\ConfigManager;
|
|
||||||
use Shaarli\TestCase;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Class BookmarkRawFormatterTest
|
|
||||||
* @package Shaarli\Formatter
|
|
||||||
*/
|
|
||||||
class BookmarkRawFormatterTest extends TestCase
|
|
||||||
{
|
|
||||||
/** @var string Path of test config file */
|
|
||||||
protected static $testConf = 'sandbox/config';
|
|
||||||
|
|
||||||
/** @var BookmarkFormatter */
|
|
||||||
protected $formatter;
|
|
||||||
|
|
||||||
/** @var ConfigManager instance */
|
|
||||||
protected $conf;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize formatter instance.
|
|
||||||
*/
|
|
||||||
protected function setUp(): void
|
|
||||||
{
|
|
||||||
copy('tests/utils/config/configJson.json.php', self::$testConf . '.json.php');
|
|
||||||
$this->conf = new ConfigManager(self::$testConf);
|
|
||||||
$this->formatter = new BookmarkRawFormatter($this->conf, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test formatting a bookmark with all its attribute filled.
|
|
||||||
*/
|
|
||||||
public function testFormatFull()
|
|
||||||
{
|
|
||||||
$bookmark = new Bookmark();
|
|
||||||
$bookmark->setId($id = 11);
|
|
||||||
$bookmark->setShortUrl($short = 'abcdef');
|
|
||||||
$bookmark->setUrl($url = 'https://sub.domain.tld?query=here&for=real#hash');
|
|
||||||
$bookmark->setTitle($title = 'This is a <strong>bookmark</strong>');
|
|
||||||
$bookmark->setDescription($desc = '<h2>Content</h2><p>`Here is some content</p>');
|
|
||||||
$bookmark->setTags($tags = ['tag1', 'bookmark', 'other', '<script>alert("xss");</script>']);
|
|
||||||
$bookmark->setThumbnail($thumb = 'http://domain2.tdl2/file.png');
|
|
||||||
$bookmark->setSticky(true);
|
|
||||||
$bookmark->setCreated($created = DateTime::createFromFormat('Ymd_His', '20190521_190412'));
|
|
||||||
$bookmark->setUpdated($updated = DateTime::createFromFormat('Ymd_His', '20190521_191213'));
|
|
||||||
$bookmark->setPrivate(true);
|
|
||||||
|
|
||||||
$link = $this->formatter->format($bookmark);
|
|
||||||
$this->assertEquals($id, $link['id']);
|
|
||||||
$this->assertEquals($short, $link['shorturl']);
|
|
||||||
$this->assertEquals($url, $link['url']);
|
|
||||||
$this->assertEquals($url, $link['real_url']);
|
|
||||||
$this->assertEquals($title, $link['title']);
|
|
||||||
$this->assertEquals($desc, $link['description']);
|
|
||||||
$this->assertEquals($tags, $link['taglist']);
|
|
||||||
$this->assertEquals(implode(' ', $tags), $link['tags']);
|
|
||||||
$this->assertEquals($thumb, $link['thumbnail']);
|
|
||||||
$this->assertEquals($created, $link['created']);
|
|
||||||
$this->assertEquals($created->getTimestamp(), $link['timestamp']);
|
|
||||||
$this->assertEquals($updated, $link['updated']);
|
|
||||||
$this->assertEquals($updated->getTimestamp(), $link['updated_timestamp']);
|
|
||||||
$this->assertTrue($link['private']);
|
|
||||||
$this->assertTrue($link['sticky']);
|
|
||||||
$this->assertEquals('private', $link['class']);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test formatting a bookmark with all its attribute filled.
|
|
||||||
*/
|
|
||||||
public function testFormatMinimal()
|
|
||||||
{
|
|
||||||
$bookmark = new Bookmark();
|
|
||||||
|
|
||||||
$link = $this->formatter->format($bookmark);
|
|
||||||
$this->assertEmpty($link['id']);
|
|
||||||
$this->assertEmpty($link['shorturl']);
|
|
||||||
$this->assertEmpty($link['url']);
|
|
||||||
$this->assertEmpty($link['real_url']);
|
|
||||||
$this->assertEmpty($link['title']);
|
|
||||||
$this->assertEmpty($link['description']);
|
|
||||||
$this->assertEmpty($link['taglist']);
|
|
||||||
$this->assertEmpty($link['tags']);
|
|
||||||
$this->assertEmpty($link['thumbnail']);
|
|
||||||
$this->assertEmpty($link['created']);
|
|
||||||
$this->assertEmpty($link['timestamp']);
|
|
||||||
$this->assertEmpty($link['updated']);
|
|
||||||
$this->assertEmpty($link['updated_timestamp']);
|
|
||||||
$this->assertFalse($link['private']);
|
|
||||||
$this->assertFalse($link['sticky']);
|
|
||||||
$this->assertEmpty($link['class']);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,101 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace Shaarli\Formatter;
|
|
||||||
|
|
||||||
use Shaarli\Config\ConfigManager;
|
|
||||||
use Shaarli\TestCase;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Class FormatterFactoryTest
|
|
||||||
*
|
|
||||||
* @package Shaarli\Formatter
|
|
||||||
*/
|
|
||||||
class FormatterFactoryTest extends TestCase
|
|
||||||
{
|
|
||||||
/** @var string Path of test config file */
|
|
||||||
protected static $testConf = 'sandbox/config';
|
|
||||||
|
|
||||||
/** @var FormatterFactory instance */
|
|
||||||
protected $factory;
|
|
||||||
|
|
||||||
/** @var ConfigManager instance */
|
|
||||||
protected $conf;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize FormatterFactory instance
|
|
||||||
*/
|
|
||||||
protected function setUp(): void
|
|
||||||
{
|
|
||||||
copy('tests/utils/config/configJson.json.php', self::$testConf . '.json.php');
|
|
||||||
$this->conf = new ConfigManager(self::$testConf);
|
|
||||||
$this->factory = new FormatterFactory($this->conf, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test creating an instance of BookmarkFormatter without any setting -> default formatter
|
|
||||||
*/
|
|
||||||
public function testCreateInstanceDefault()
|
|
||||||
{
|
|
||||||
$this->assertInstanceOf(BookmarkDefaultFormatter::class, $this->factory->getFormatter());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test creating an instance of BookmarkDefaultFormatter from settings
|
|
||||||
*/
|
|
||||||
public function testCreateInstanceDefaultSetting()
|
|
||||||
{
|
|
||||||
$this->conf->set('formatter', 'default');
|
|
||||||
$this->assertInstanceOf(BookmarkDefaultFormatter::class, $this->factory->getFormatter());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test creating an instance of BookmarkDefaultFormatter from parameter
|
|
||||||
*/
|
|
||||||
public function testCreateInstanceDefaultParameter()
|
|
||||||
{
|
|
||||||
$this->assertInstanceOf(
|
|
||||||
BookmarkDefaultFormatter::class,
|
|
||||||
$this->factory->getFormatter('default')
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test creating an instance of BookmarkRawFormatter from settings
|
|
||||||
*/
|
|
||||||
public function testCreateInstanceRawSetting()
|
|
||||||
{
|
|
||||||
$this->conf->set('formatter', 'raw');
|
|
||||||
$this->assertInstanceOf(BookmarkRawFormatter::class, $this->factory->getFormatter());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test creating an instance of BookmarkRawFormatter from parameter
|
|
||||||
*/
|
|
||||||
public function testCreateInstanceRawParameter()
|
|
||||||
{
|
|
||||||
$this->assertInstanceOf(
|
|
||||||
BookmarkRawFormatter::class,
|
|
||||||
$this->factory->getFormatter('raw')
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test creating an instance of BookmarkMarkdownFormatter from settings
|
|
||||||
*/
|
|
||||||
public function testCreateInstanceMarkdownSetting()
|
|
||||||
{
|
|
||||||
$this->conf->set('formatter', 'markdown');
|
|
||||||
$this->assertInstanceOf(BookmarkMarkdownFormatter::class, $this->factory->getFormatter());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test creating an instance of BookmarkMarkdownFormatter from parameter
|
|
||||||
*/
|
|
||||||
public function testCreateInstanceMarkdownParameter()
|
|
||||||
{
|
|
||||||
$this->assertInstanceOf(
|
|
||||||
BookmarkMarkdownFormatter::class,
|
|
||||||
$this->factory->getFormatter('markdown')
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,101 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace Shaarli\Front;
|
|
||||||
|
|
||||||
use Shaarli\Config\ConfigManager;
|
|
||||||
use Shaarli\Container\ShaarliContainer;
|
|
||||||
use Shaarli\Security\LoginManager;
|
|
||||||
use Shaarli\TestCase;
|
|
||||||
use Shaarli\Updater\Updater;
|
|
||||||
use Slim\Http\Request;
|
|
||||||
use Slim\Http\Response;
|
|
||||||
use Slim\Http\Uri;
|
|
||||||
|
|
||||||
class ShaarliAdminMiddlewareTest extends TestCase
|
|
||||||
{
|
|
||||||
protected const TMP_MOCK_FILE = '.tmp';
|
|
||||||
|
|
||||||
/** @var ShaarliContainer */
|
|
||||||
protected $container;
|
|
||||||
|
|
||||||
/** @var ShaarliMiddleware */
|
|
||||||
protected $middleware;
|
|
||||||
|
|
||||||
public function setUp(): void
|
|
||||||
{
|
|
||||||
$this->container = $this->createMock(ShaarliContainer::class);
|
|
||||||
|
|
||||||
touch(static::TMP_MOCK_FILE);
|
|
||||||
|
|
||||||
$this->container->conf = $this->createMock(ConfigManager::class);
|
|
||||||
$this->container->conf->method('getConfigFileExt')->willReturn(static::TMP_MOCK_FILE);
|
|
||||||
|
|
||||||
$this->container->loginManager = $this->createMock(LoginManager::class);
|
|
||||||
$this->container->updater = $this->createMock(Updater::class);
|
|
||||||
|
|
||||||
$this->container->environment = ['REQUEST_URI' => 'http://shaarli/subfolder/path'];
|
|
||||||
|
|
||||||
$this->middleware = new ShaarliAdminMiddleware($this->container);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function tearDown(): void
|
|
||||||
{
|
|
||||||
unlink(static::TMP_MOCK_FILE);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Try to access an admin controller while logged out -> redirected to login page.
|
|
||||||
*/
|
|
||||||
public function testMiddlewareWhileLoggedOut(): void
|
|
||||||
{
|
|
||||||
$this->container->loginManager->expects(static::once())->method('isLoggedIn')->willReturn(false);
|
|
||||||
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$request->method('getUri')->willReturnCallback(function (): Uri {
|
|
||||||
$uri = $this->createMock(Uri::class);
|
|
||||||
$uri->method('getBasePath')->willReturn('/subfolder');
|
|
||||||
|
|
||||||
return $uri;
|
|
||||||
});
|
|
||||||
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
/** @var Response $result */
|
|
||||||
$result = $this->middleware->__invoke($request, $response, function () {
|
|
||||||
});
|
|
||||||
|
|
||||||
static::assertSame(302, $result->getStatusCode());
|
|
||||||
static::assertSame(
|
|
||||||
'/subfolder/login?returnurl=' . urlencode('http://shaarli/subfolder/path'),
|
|
||||||
$result->getHeader('location')[0]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Process controller while logged in.
|
|
||||||
*/
|
|
||||||
public function testMiddlewareWhileLoggedIn(): void
|
|
||||||
{
|
|
||||||
$this->container->loginManager->method('isLoggedIn')->willReturn(true);
|
|
||||||
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$request->method('getUri')->willReturnCallback(function (): Uri {
|
|
||||||
$uri = $this->createMock(Uri::class);
|
|
||||||
$uri->method('getBasePath')->willReturn('/subfolder');
|
|
||||||
|
|
||||||
return $uri;
|
|
||||||
});
|
|
||||||
|
|
||||||
$response = new Response();
|
|
||||||
$controller = function (Request $request, Response $response): Response {
|
|
||||||
return $response->withStatus(418); // I'm a tea pot
|
|
||||||
};
|
|
||||||
|
|
||||||
/** @var Response $result */
|
|
||||||
$result = $this->middleware->__invoke($request, $response, $controller);
|
|
||||||
|
|
||||||
static::assertSame(418, $result->getStatusCode());
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,222 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace Shaarli\Front;
|
|
||||||
|
|
||||||
use Shaarli\Config\ConfigManager;
|
|
||||||
use Shaarli\Container\ShaarliContainer;
|
|
||||||
use Shaarli\Front\Exception\LoginBannedException;
|
|
||||||
use Shaarli\Front\Exception\UnauthorizedException;
|
|
||||||
use Shaarli\Render\PageBuilder;
|
|
||||||
use Shaarli\Render\PageCacheManager;
|
|
||||||
use Shaarli\Security\LoginManager;
|
|
||||||
use Shaarli\TestCase;
|
|
||||||
use Shaarli\Updater\Updater;
|
|
||||||
use Slim\Http\Request;
|
|
||||||
use Slim\Http\Response;
|
|
||||||
use Slim\Http\Uri;
|
|
||||||
|
|
||||||
class ShaarliMiddlewareTest extends TestCase
|
|
||||||
{
|
|
||||||
protected const TMP_MOCK_FILE = '.tmp';
|
|
||||||
|
|
||||||
/** @var ShaarliContainer */
|
|
||||||
protected $container;
|
|
||||||
|
|
||||||
/** @var ShaarliMiddleware */
|
|
||||||
protected $middleware;
|
|
||||||
|
|
||||||
public function setUp(): void
|
|
||||||
{
|
|
||||||
$this->container = $this->createMock(ShaarliContainer::class);
|
|
||||||
|
|
||||||
touch(static::TMP_MOCK_FILE);
|
|
||||||
|
|
||||||
$this->container->conf = $this->createMock(ConfigManager::class);
|
|
||||||
$this->container->conf->method('getConfigFileExt')->willReturn(static::TMP_MOCK_FILE);
|
|
||||||
|
|
||||||
$this->container->loginManager = $this->createMock(LoginManager::class);
|
|
||||||
|
|
||||||
$this->container->environment = ['REQUEST_URI' => 'http://shaarli/subfolder/path'];
|
|
||||||
|
|
||||||
$this->middleware = new ShaarliMiddleware($this->container);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function tearDown(): void
|
|
||||||
{
|
|
||||||
unlink(static::TMP_MOCK_FILE);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test middleware execution with valid controller call
|
|
||||||
*/
|
|
||||||
public function testMiddlewareExecution(): void
|
|
||||||
{
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$request->method('getUri')->willReturnCallback(function (): Uri {
|
|
||||||
$uri = $this->createMock(Uri::class);
|
|
||||||
$uri->method('getBasePath')->willReturn('/subfolder');
|
|
||||||
|
|
||||||
return $uri;
|
|
||||||
});
|
|
||||||
|
|
||||||
$response = new Response();
|
|
||||||
$controller = function (Request $request, Response $response): Response {
|
|
||||||
return $response->withStatus(418); // I'm a tea pot
|
|
||||||
};
|
|
||||||
|
|
||||||
/** @var Response $result */
|
|
||||||
$result = $this->middleware->__invoke($request, $response, $controller);
|
|
||||||
|
|
||||||
static::assertInstanceOf(Response::class, $result);
|
|
||||||
static::assertSame(418, $result->getStatusCode());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test middleware execution with controller throwing a known front exception.
|
|
||||||
* The exception should be thrown to be later handled by the error handler.
|
|
||||||
*/
|
|
||||||
public function testMiddlewareExecutionWithFrontException(): void
|
|
||||||
{
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$request->method('getUri')->willReturnCallback(function (): Uri {
|
|
||||||
$uri = $this->createMock(Uri::class);
|
|
||||||
$uri->method('getBasePath')->willReturn('/subfolder');
|
|
||||||
|
|
||||||
return $uri;
|
|
||||||
});
|
|
||||||
|
|
||||||
$response = new Response();
|
|
||||||
$controller = function (): void {
|
|
||||||
$exception = new LoginBannedException();
|
|
||||||
|
|
||||||
throw new $exception();
|
|
||||||
};
|
|
||||||
|
|
||||||
$pageBuilder = $this->createMock(PageBuilder::class);
|
|
||||||
$pageBuilder->method('render')->willReturnCallback(function (string $message): string {
|
|
||||||
return $message;
|
|
||||||
});
|
|
||||||
$this->container->pageBuilder = $pageBuilder;
|
|
||||||
|
|
||||||
$this->expectException(LoginBannedException::class);
|
|
||||||
|
|
||||||
$this->middleware->__invoke($request, $response, $controller);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test middleware execution with controller throwing a not authorized exception
|
|
||||||
* The middle should send a redirection response to the login page.
|
|
||||||
*/
|
|
||||||
public function testMiddlewareExecutionWithUnauthorizedException(): void
|
|
||||||
{
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$request->method('getUri')->willReturnCallback(function (): Uri {
|
|
||||||
$uri = $this->createMock(Uri::class);
|
|
||||||
$uri->method('getBasePath')->willReturn('/subfolder');
|
|
||||||
|
|
||||||
return $uri;
|
|
||||||
});
|
|
||||||
|
|
||||||
$response = new Response();
|
|
||||||
$controller = function (): void {
|
|
||||||
throw new UnauthorizedException();
|
|
||||||
};
|
|
||||||
|
|
||||||
/** @var Response $result */
|
|
||||||
$result = $this->middleware->__invoke($request, $response, $controller);
|
|
||||||
|
|
||||||
static::assertSame(302, $result->getStatusCode());
|
|
||||||
static::assertSame(
|
|
||||||
'/subfolder/login?returnurl=' . urlencode('http://shaarli/subfolder/path'),
|
|
||||||
$result->getHeader('location')[0]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test middleware execution with controller throwing a not authorized exception.
|
|
||||||
* The exception should be thrown to be later handled by the error handler.
|
|
||||||
*/
|
|
||||||
public function testMiddlewareExecutionWithServerException(): void
|
|
||||||
{
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$request->method('getUri')->willReturnCallback(function (): Uri {
|
|
||||||
$uri = $this->createMock(Uri::class);
|
|
||||||
$uri->method('getBasePath')->willReturn('/subfolder');
|
|
||||||
|
|
||||||
return $uri;
|
|
||||||
});
|
|
||||||
|
|
||||||
$dummyException = new class () extends \Exception {
|
|
||||||
};
|
|
||||||
|
|
||||||
$response = new Response();
|
|
||||||
$controller = function () use ($dummyException): void {
|
|
||||||
throw $dummyException;
|
|
||||||
};
|
|
||||||
|
|
||||||
$parameters = [];
|
|
||||||
$this->container->pageBuilder = $this->createMock(PageBuilder::class);
|
|
||||||
$this->container->pageBuilder->method('render')->willReturnCallback(function (string $message): string {
|
|
||||||
return $message;
|
|
||||||
});
|
|
||||||
$this->container->pageBuilder
|
|
||||||
->method('assign')
|
|
||||||
->willReturnCallback(function (string $key, string $value) use (&$parameters): void {
|
|
||||||
$parameters[$key] = $value;
|
|
||||||
})
|
|
||||||
;
|
|
||||||
|
|
||||||
$this->expectException(get_class($dummyException));
|
|
||||||
|
|
||||||
$this->middleware->__invoke($request, $response, $controller);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testMiddlewareExecutionWithUpdates(): void
|
|
||||||
{
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$request->method('getUri')->willReturnCallback(function (): Uri {
|
|
||||||
$uri = $this->createMock(Uri::class);
|
|
||||||
$uri->method('getBasePath')->willReturn('/subfolder');
|
|
||||||
|
|
||||||
return $uri;
|
|
||||||
});
|
|
||||||
|
|
||||||
$response = new Response();
|
|
||||||
$controller = function (Request $request, Response $response): Response {
|
|
||||||
return $response->withStatus(418); // I'm a tea pot
|
|
||||||
};
|
|
||||||
|
|
||||||
$this->container->loginManager = $this->createMock(LoginManager::class);
|
|
||||||
$this->container->loginManager->method('isLoggedIn')->willReturn(true);
|
|
||||||
|
|
||||||
$this->container->conf = $this->createMock(ConfigManager::class);
|
|
||||||
$this->container->conf->method('get')->willReturnCallback(function (string $key): string {
|
|
||||||
return $key;
|
|
||||||
});
|
|
||||||
$this->container->conf->method('getConfigFileExt')->willReturn(static::TMP_MOCK_FILE);
|
|
||||||
|
|
||||||
$this->container->pageCacheManager = $this->createMock(PageCacheManager::class);
|
|
||||||
$this->container->pageCacheManager->expects(static::once())->method('invalidateCaches');
|
|
||||||
|
|
||||||
$this->container->updater = $this->createMock(Updater::class);
|
|
||||||
$this->container->updater
|
|
||||||
->expects(static::once())
|
|
||||||
->method('update')
|
|
||||||
->willReturn(['update123'])
|
|
||||||
;
|
|
||||||
$this->container->updater->method('getDoneUpdates')->willReturn($updates = ['update123', 'other']);
|
|
||||||
$this->container->updater
|
|
||||||
->expects(static::once())
|
|
||||||
->method('writeUpdates')
|
|
||||||
->with('resource.updates', $updates)
|
|
||||||
;
|
|
||||||
|
|
||||||
/** @var Response $result */
|
|
||||||
$result = $this->middleware->__invoke($request, $response, $controller);
|
|
||||||
|
|
||||||
static::assertInstanceOf(Response::class, $result);
|
|
||||||
static::assertSame(418, $result->getStatusCode());
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,250 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace Shaarli\Front\Controller\Admin;
|
|
||||||
|
|
||||||
use Shaarli\Config\ConfigManager;
|
|
||||||
use Shaarli\Front\Exception\WrongTokenException;
|
|
||||||
use Shaarli\Security\SessionManager;
|
|
||||||
use Shaarli\TestCase;
|
|
||||||
use Shaarli\Thumbnailer;
|
|
||||||
use Slim\Http\Request;
|
|
||||||
use Slim\Http\Response;
|
|
||||||
|
|
||||||
class ConfigureControllerTest extends TestCase
|
|
||||||
{
|
|
||||||
use FrontAdminControllerMockHelper;
|
|
||||||
|
|
||||||
/** @var ConfigureController */
|
|
||||||
protected $controller;
|
|
||||||
|
|
||||||
public function setUp(): void
|
|
||||||
{
|
|
||||||
$this->createContainer();
|
|
||||||
|
|
||||||
$this->controller = new ConfigureController($this->container);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test displaying configure page - it should display all config variables
|
|
||||||
*/
|
|
||||||
public function testIndex(): void
|
|
||||||
{
|
|
||||||
$assignedVariables = [];
|
|
||||||
$this->assignTemplateVars($assignedVariables);
|
|
||||||
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
$this->container->conf = $this->createMock(ConfigManager::class);
|
|
||||||
$this->container->conf->method('get')->willReturnCallback(function (string $key) {
|
|
||||||
return $key;
|
|
||||||
});
|
|
||||||
|
|
||||||
$result = $this->controller->index($request, $response);
|
|
||||||
|
|
||||||
static::assertSame(200, $result->getStatusCode());
|
|
||||||
static::assertSame('configure', (string) $result->getBody());
|
|
||||||
|
|
||||||
static::assertSame('Configure - general.title', $assignedVariables['pagetitle']);
|
|
||||||
static::assertSame('general.title', $assignedVariables['title']);
|
|
||||||
static::assertSame('resource.theme', $assignedVariables['theme']);
|
|
||||||
static::assertEmpty($assignedVariables['theme_available']);
|
|
||||||
static::assertSame(['default', 'markdown', 'markdownExtra'], $assignedVariables['formatter_available']);
|
|
||||||
static::assertNotEmpty($assignedVariables['continents']);
|
|
||||||
static::assertNotEmpty($assignedVariables['cities']);
|
|
||||||
static::assertSame('general.retrieve_description', $assignedVariables['retrieve_description']);
|
|
||||||
static::assertSame('privacy.default_private_links', $assignedVariables['private_links_default']);
|
|
||||||
static::assertSame('security.session_protection_disabled', $assignedVariables['session_protection_disabled']);
|
|
||||||
static::assertSame('feed.rss_permalinks', $assignedVariables['enable_rss_permalinks']);
|
|
||||||
static::assertSame('updates.check_updates', $assignedVariables['enable_update_check']);
|
|
||||||
static::assertSame('privacy.hide_public_links', $assignedVariables['hide_public_links']);
|
|
||||||
static::assertSame('api.enabled', $assignedVariables['api_enabled']);
|
|
||||||
static::assertSame('api.secret', $assignedVariables['api_secret']);
|
|
||||||
static::assertCount(7, $assignedVariables['languages']);
|
|
||||||
static::assertArrayHasKey('gd_enabled', $assignedVariables);
|
|
||||||
static::assertSame('thumbnails.mode', $assignedVariables['thumbnails_mode']);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test posting a new config - make sure that everything is saved properly, without errors.
|
|
||||||
*/
|
|
||||||
public function testSaveNewConfig(): void
|
|
||||||
{
|
|
||||||
$session = [];
|
|
||||||
$this->assignSessionVars($session);
|
|
||||||
|
|
||||||
$parameters = [
|
|
||||||
'token' => 'token',
|
|
||||||
'continent' => 'Europe',
|
|
||||||
'city' => 'Moscow',
|
|
||||||
'title' => 'Shaarli',
|
|
||||||
'titleLink' => './',
|
|
||||||
'retrieveDescription' => 'on',
|
|
||||||
'theme' => 'vintage',
|
|
||||||
'disablesessionprotection' => null,
|
|
||||||
'privateLinkByDefault' => true,
|
|
||||||
'enableRssPermalinks' => true,
|
|
||||||
'updateCheck' => false,
|
|
||||||
'hidePublicLinks' => 'on',
|
|
||||||
'enableApi' => 'on',
|
|
||||||
'apiSecret' => 'abcdef',
|
|
||||||
'formatter' => 'markdown',
|
|
||||||
'language' => 'fr',
|
|
||||||
'enableThumbnails' => Thumbnailer::MODE_NONE,
|
|
||||||
];
|
|
||||||
|
|
||||||
$parametersConfigMapping = [
|
|
||||||
'general.timezone' => $parameters['continent'] . '/' . $parameters['city'],
|
|
||||||
'general.title' => $parameters['title'],
|
|
||||||
'general.header_link' => $parameters['titleLink'],
|
|
||||||
'general.retrieve_description' => !!$parameters['retrieveDescription'],
|
|
||||||
'resource.theme' => $parameters['theme'],
|
|
||||||
'security.session_protection_disabled' => !!$parameters['disablesessionprotection'],
|
|
||||||
'privacy.default_private_links' => !!$parameters['privateLinkByDefault'],
|
|
||||||
'feed.rss_permalinks' => !!$parameters['enableRssPermalinks'],
|
|
||||||
'updates.check_updates' => !!$parameters['updateCheck'],
|
|
||||||
'privacy.hide_public_links' => !!$parameters['hidePublicLinks'],
|
|
||||||
'api.enabled' => !!$parameters['enableApi'],
|
|
||||||
'api.secret' => $parameters['apiSecret'],
|
|
||||||
'formatter' => $parameters['formatter'],
|
|
||||||
'translation.language' => $parameters['language'],
|
|
||||||
'thumbnails.mode' => $parameters['enableThumbnails'],
|
|
||||||
];
|
|
||||||
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$request
|
|
||||||
->expects(static::atLeastOnce())
|
|
||||||
->method('getParam')->willReturnCallback(function (string $key) use ($parameters) {
|
|
||||||
if (false === array_key_exists($key, $parameters)) {
|
|
||||||
static::fail('unknown key: ' . $key);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $parameters[$key];
|
|
||||||
});
|
|
||||||
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
$this->container->conf = $this->createMock(ConfigManager::class);
|
|
||||||
$this->container->conf
|
|
||||||
->expects(static::atLeastOnce())
|
|
||||||
->method('set')
|
|
||||||
->willReturnCallback(function (string $key, $value) use ($parametersConfigMapping): void {
|
|
||||||
if (false === array_key_exists($key, $parametersConfigMapping)) {
|
|
||||||
static::fail('unknown key: ' . $key);
|
|
||||||
}
|
|
||||||
|
|
||||||
static::assertSame($parametersConfigMapping[$key], $value);
|
|
||||||
});
|
|
||||||
|
|
||||||
$result = $this->controller->save($request, $response);
|
|
||||||
static::assertSame(302, $result->getStatusCode());
|
|
||||||
static::assertSame(['/subfolder/admin/configure'], $result->getHeader('Location'));
|
|
||||||
|
|
||||||
static::assertArrayNotHasKey(SessionManager::KEY_WARNING_MESSAGES, $session);
|
|
||||||
static::assertArrayNotHasKey(SessionManager::KEY_ERROR_MESSAGES, $session);
|
|
||||||
static::assertArrayHasKey(SessionManager::KEY_SUCCESS_MESSAGES, $session);
|
|
||||||
static::assertSame(['Configuration was saved.'], $session[SessionManager::KEY_SUCCESS_MESSAGES]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test posting a new config - wrong token.
|
|
||||||
*/
|
|
||||||
public function testSaveNewConfigWrongToken(): void
|
|
||||||
{
|
|
||||||
$this->container->sessionManager = $this->createMock(SessionManager::class);
|
|
||||||
$this->container->sessionManager->method('checkToken')->willReturn(false);
|
|
||||||
|
|
||||||
$this->container->conf->expects(static::never())->method('set');
|
|
||||||
$this->container->conf->expects(static::never())->method('write');
|
|
||||||
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
$this->expectException(WrongTokenException::class);
|
|
||||||
|
|
||||||
$this->controller->save($request, $response);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test posting a new config - thumbnail activation.
|
|
||||||
*/
|
|
||||||
public function testSaveNewConfigThumbnailsActivation(): void
|
|
||||||
{
|
|
||||||
$session = [];
|
|
||||||
$this->assignSessionVars($session);
|
|
||||||
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$request
|
|
||||||
->expects(static::atLeastOnce())
|
|
||||||
->method('getParam')->willReturnCallback(function (string $key) {
|
|
||||||
if ('enableThumbnails' === $key) {
|
|
||||||
return Thumbnailer::MODE_ALL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $key;
|
|
||||||
})
|
|
||||||
;
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
$result = $this->controller->save($request, $response);
|
|
||||||
|
|
||||||
static::assertSame(302, $result->getStatusCode());
|
|
||||||
static::assertSame(['/subfolder/admin/configure'], $result->getHeader('Location'));
|
|
||||||
|
|
||||||
static::assertArrayNotHasKey(SessionManager::KEY_ERROR_MESSAGES, $session);
|
|
||||||
static::assertArrayHasKey(SessionManager::KEY_WARNING_MESSAGES, $session);
|
|
||||||
static::assertStringContainsString(
|
|
||||||
'You have enabled or changed thumbnails mode',
|
|
||||||
$session[SessionManager::KEY_WARNING_MESSAGES][0]
|
|
||||||
);
|
|
||||||
static::assertArrayHasKey(SessionManager::KEY_SUCCESS_MESSAGES, $session);
|
|
||||||
static::assertSame(['Configuration was saved.'], $session[SessionManager::KEY_SUCCESS_MESSAGES]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test posting a new config - thumbnail activation.
|
|
||||||
*/
|
|
||||||
public function testSaveNewConfigThumbnailsAlreadyActive(): void
|
|
||||||
{
|
|
||||||
$session = [];
|
|
||||||
$this->assignSessionVars($session);
|
|
||||||
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$request
|
|
||||||
->expects(static::atLeastOnce())
|
|
||||||
->method('getParam')->willReturnCallback(function (string $key) {
|
|
||||||
if ('enableThumbnails' === $key) {
|
|
||||||
return Thumbnailer::MODE_ALL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $key;
|
|
||||||
})
|
|
||||||
;
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
$this->container->conf = $this->createMock(ConfigManager::class);
|
|
||||||
$this->container->conf
|
|
||||||
->expects(static::atLeastOnce())
|
|
||||||
->method('get')
|
|
||||||
->willReturnCallback(function (string $key): string {
|
|
||||||
if ('thumbnails.mode' === $key) {
|
|
||||||
return Thumbnailer::MODE_ALL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $key;
|
|
||||||
})
|
|
||||||
;
|
|
||||||
|
|
||||||
$result = $this->controller->save($request, $response);
|
|
||||||
|
|
||||||
static::assertSame(302, $result->getStatusCode());
|
|
||||||
static::assertSame(['/subfolder/admin/configure'], $result->getHeader('Location'));
|
|
||||||
|
|
||||||
static::assertArrayNotHasKey(SessionManager::KEY_ERROR_MESSAGES, $session);
|
|
||||||
static::assertArrayNotHasKey(SessionManager::KEY_WARNING_MESSAGES, $session);
|
|
||||||
static::assertArrayHasKey(SessionManager::KEY_SUCCESS_MESSAGES, $session);
|
|
||||||
static::assertSame(['Configuration was saved.'], $session[SessionManager::KEY_SUCCESS_MESSAGES]);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,166 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace Shaarli\Front\Controller\Admin;
|
|
||||||
|
|
||||||
use Shaarli\Bookmark\Bookmark;
|
|
||||||
use Shaarli\Formatter\BookmarkFormatter;
|
|
||||||
use Shaarli\Formatter\BookmarkRawFormatter;
|
|
||||||
use Shaarli\Netscape\NetscapeBookmarkUtils;
|
|
||||||
use Shaarli\Security\SessionManager;
|
|
||||||
use Shaarli\TestCase;
|
|
||||||
use Slim\Http\Request;
|
|
||||||
use Slim\Http\Response;
|
|
||||||
|
|
||||||
class ExportControllerTest extends TestCase
|
|
||||||
{
|
|
||||||
use FrontAdminControllerMockHelper;
|
|
||||||
|
|
||||||
/** @var ExportController */
|
|
||||||
protected $controller;
|
|
||||||
|
|
||||||
public function setUp(): void
|
|
||||||
{
|
|
||||||
$this->createContainer();
|
|
||||||
|
|
||||||
$this->controller = new ExportController($this->container);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test displaying export page
|
|
||||||
*/
|
|
||||||
public function testIndex(): void
|
|
||||||
{
|
|
||||||
$assignedVariables = [];
|
|
||||||
$this->assignTemplateVars($assignedVariables);
|
|
||||||
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
$result = $this->controller->index($request, $response);
|
|
||||||
|
|
||||||
static::assertSame(200, $result->getStatusCode());
|
|
||||||
static::assertSame('export', (string) $result->getBody());
|
|
||||||
|
|
||||||
static::assertSame('Export - Shaarli', $assignedVariables['pagetitle']);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test posting an export request
|
|
||||||
*/
|
|
||||||
public function testExportDefault(): void
|
|
||||||
{
|
|
||||||
$assignedVariables = [];
|
|
||||||
$this->assignTemplateVars($assignedVariables);
|
|
||||||
|
|
||||||
$parameters = [
|
|
||||||
'selection' => 'all',
|
|
||||||
'prepend_note_url' => 'on',
|
|
||||||
];
|
|
||||||
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$request->method('getParam')->willReturnCallback(function (string $key) use ($parameters) {
|
|
||||||
return $parameters[$key] ?? null;
|
|
||||||
});
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
$bookmarks = [
|
|
||||||
(new Bookmark())->setUrl('http://link1.tld')->setTitle('Title 1'),
|
|
||||||
(new Bookmark())->setUrl('http://link2.tld')->setTitle('Title 2'),
|
|
||||||
];
|
|
||||||
|
|
||||||
$this->container->netscapeBookmarkUtils = $this->createMock(NetscapeBookmarkUtils::class);
|
|
||||||
$this->container->netscapeBookmarkUtils
|
|
||||||
->expects(static::once())
|
|
||||||
->method('filterAndFormat')
|
|
||||||
->willReturnCallback(
|
|
||||||
function (
|
|
||||||
BookmarkFormatter $formatter,
|
|
||||||
string $selection,
|
|
||||||
bool $prependNoteUrl,
|
|
||||||
string $indexUrl
|
|
||||||
) use (
|
|
||||||
$parameters,
|
|
||||||
$bookmarks
|
|
||||||
): array {
|
|
||||||
static::assertInstanceOf(BookmarkRawFormatter::class, $formatter);
|
|
||||||
static::assertSame($parameters['selection'], $selection);
|
|
||||||
static::assertTrue($prependNoteUrl);
|
|
||||||
static::assertSame('http://shaarli/subfolder/', $indexUrl);
|
|
||||||
|
|
||||||
return $bookmarks;
|
|
||||||
}
|
|
||||||
)
|
|
||||||
;
|
|
||||||
|
|
||||||
$result = $this->controller->export($request, $response);
|
|
||||||
|
|
||||||
static::assertSame(200, $result->getStatusCode());
|
|
||||||
static::assertSame('export.bookmarks', (string) $result->getBody());
|
|
||||||
static::assertSame(['text/html; charset=utf-8'], $result->getHeader('content-type'));
|
|
||||||
static::assertRegExp(
|
|
||||||
'/attachment; filename=bookmarks_all_[\d]{8}_[\d]{6}\.html/',
|
|
||||||
$result->getHeader('content-disposition')[0]
|
|
||||||
);
|
|
||||||
|
|
||||||
static::assertNotEmpty($assignedVariables['date']);
|
|
||||||
static::assertSame(PHP_EOL, $assignedVariables['eol']);
|
|
||||||
static::assertSame('all', $assignedVariables['selection']);
|
|
||||||
static::assertSame($bookmarks, $assignedVariables['links']);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test posting an export request - without selection parameter
|
|
||||||
*/
|
|
||||||
public function testExportSelectionMissing(): void
|
|
||||||
{
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
$this->container->sessionManager
|
|
||||||
->expects(static::once())
|
|
||||||
->method('setSessionParameter')
|
|
||||||
->with(SessionManager::KEY_ERROR_MESSAGES, ['Please select an export mode.'])
|
|
||||||
;
|
|
||||||
|
|
||||||
$result = $this->controller->export($request, $response);
|
|
||||||
|
|
||||||
static::assertSame(302, $result->getStatusCode());
|
|
||||||
static::assertSame(['/subfolder/admin/export'], $result->getHeader('location'));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test posting an export request - without selection parameter
|
|
||||||
*/
|
|
||||||
public function testExportErrorEncountered(): void
|
|
||||||
{
|
|
||||||
$parameters = [
|
|
||||||
'selection' => 'all',
|
|
||||||
];
|
|
||||||
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$request->method('getParam')->willReturnCallback(function (string $key) use ($parameters) {
|
|
||||||
return $parameters[$key] ?? null;
|
|
||||||
});
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
$this->container->netscapeBookmarkUtils = $this->createMock(NetscapeBookmarkUtils::class);
|
|
||||||
$this->container->netscapeBookmarkUtils
|
|
||||||
->expects(static::once())
|
|
||||||
->method('filterAndFormat')
|
|
||||||
->willThrowException(new \Exception($message = 'error message'));
|
|
||||||
;
|
|
||||||
|
|
||||||
$this->container->sessionManager
|
|
||||||
->expects(static::once())
|
|
||||||
->method('setSessionParameter')
|
|
||||||
->with(SessionManager::KEY_ERROR_MESSAGES, [$message])
|
|
||||||
;
|
|
||||||
|
|
||||||
$result = $this->controller->export($request, $response);
|
|
||||||
|
|
||||||
static::assertSame(302, $result->getStatusCode());
|
|
||||||
static::assertSame(['/subfolder/admin/export'], $result->getHeader('location'));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,56 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace Shaarli\Front\Controller\Admin;
|
|
||||||
|
|
||||||
use Shaarli\Container\ShaarliTestContainer;
|
|
||||||
use Shaarli\Front\Controller\Visitor\FrontControllerMockHelper;
|
|
||||||
use Shaarli\History;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Trait FrontControllerMockHelper
|
|
||||||
*
|
|
||||||
* Helper trait used to initialize the ShaarliContainer and mock its services for admin controller tests.
|
|
||||||
*
|
|
||||||
* @property ShaarliTestContainer $container
|
|
||||||
*/
|
|
||||||
trait FrontAdminControllerMockHelper
|
|
||||||
{
|
|
||||||
use FrontControllerMockHelper {
|
|
||||||
FrontControllerMockHelper::createContainer as parentCreateContainer;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Mock the container instance
|
|
||||||
*/
|
|
||||||
protected function createContainer(): void
|
|
||||||
{
|
|
||||||
$this->parentCreateContainer();
|
|
||||||
|
|
||||||
$this->container->history = $this->createMock(History::class);
|
|
||||||
|
|
||||||
$this->container->loginManager->method('isLoggedIn')->willReturn(true);
|
|
||||||
$this->container->sessionManager->method('checkToken')->willReturn(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Pass a reference of an array which will be populated by `sessionManager->setSessionParameter`
|
|
||||||
* calls during execution.
|
|
||||||
*
|
|
||||||
* @param mixed $variables Array reference to populate.
|
|
||||||
*/
|
|
||||||
protected function assignSessionVars(array &$variables): void
|
|
||||||
{
|
|
||||||
$this->container->sessionManager
|
|
||||||
->expects(static::atLeastOnce())
|
|
||||||
->method('setSessionParameter')
|
|
||||||
->willReturnCallback(function ($key, $value) use (&$variables) {
|
|
||||||
$variables[$key] = $value;
|
|
||||||
|
|
||||||
return $this->container->sessionManager;
|
|
||||||
})
|
|
||||||
;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,151 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace Shaarli\Front\Controller\Admin;
|
|
||||||
|
|
||||||
use Psr\Http\Message\UploadedFileInterface;
|
|
||||||
use Shaarli\Netscape\NetscapeBookmarkUtils;
|
|
||||||
use Shaarli\Security\SessionManager;
|
|
||||||
use Shaarli\TestCase;
|
|
||||||
use Slim\Http\Request;
|
|
||||||
use Slim\Http\Response;
|
|
||||||
use Slim\Http\UploadedFile;
|
|
||||||
|
|
||||||
class ImportControllerTest extends TestCase
|
|
||||||
{
|
|
||||||
use FrontAdminControllerMockHelper;
|
|
||||||
|
|
||||||
/** @var ImportController */
|
|
||||||
protected $controller;
|
|
||||||
|
|
||||||
public function setUp(): void
|
|
||||||
{
|
|
||||||
$this->createContainer();
|
|
||||||
|
|
||||||
$this->controller = new ImportController($this->container);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test displaying import page
|
|
||||||
*/
|
|
||||||
public function testIndex(): void
|
|
||||||
{
|
|
||||||
$assignedVariables = [];
|
|
||||||
$this->assignTemplateVars($assignedVariables);
|
|
||||||
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
$result = $this->controller->index($request, $response);
|
|
||||||
|
|
||||||
static::assertSame(200, $result->getStatusCode());
|
|
||||||
static::assertSame('import', (string) $result->getBody());
|
|
||||||
|
|
||||||
static::assertSame('Import - Shaarli', $assignedVariables['pagetitle']);
|
|
||||||
static::assertIsInt($assignedVariables['maxfilesize']);
|
|
||||||
static::assertRegExp('/\d+[KM]iB/', $assignedVariables['maxfilesizeHuman']);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test importing a file with default and valid parameters
|
|
||||||
*/
|
|
||||||
public function testImportDefault(): void
|
|
||||||
{
|
|
||||||
$parameters = [
|
|
||||||
'abc' => 'def',
|
|
||||||
'other' => 'param',
|
|
||||||
];
|
|
||||||
|
|
||||||
$requestFile = new UploadedFile('file', 'name', 'type', 123);
|
|
||||||
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$request->method('getParams')->willReturnCallback(function () use ($parameters) {
|
|
||||||
return $parameters;
|
|
||||||
});
|
|
||||||
$request->method('getUploadedFiles')->willReturn(['filetoupload' => $requestFile]);
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
$this->container->netscapeBookmarkUtils = $this->createMock(NetscapeBookmarkUtils::class);
|
|
||||||
$this->container->netscapeBookmarkUtils
|
|
||||||
->expects(static::once())
|
|
||||||
->method('import')
|
|
||||||
->willReturnCallback(
|
|
||||||
function (
|
|
||||||
array $post,
|
|
||||||
UploadedFileInterface $file
|
|
||||||
) use (
|
|
||||||
$parameters,
|
|
||||||
$requestFile
|
|
||||||
): string {
|
|
||||||
static::assertSame($parameters, $post);
|
|
||||||
static::assertSame($requestFile, $file);
|
|
||||||
|
|
||||||
return 'status';
|
|
||||||
}
|
|
||||||
)
|
|
||||||
;
|
|
||||||
|
|
||||||
$this->container->sessionManager
|
|
||||||
->expects(static::once())
|
|
||||||
->method('setSessionParameter')
|
|
||||||
->with(SessionManager::KEY_SUCCESS_MESSAGES, ['status'])
|
|
||||||
;
|
|
||||||
|
|
||||||
$result = $this->controller->import($request, $response);
|
|
||||||
|
|
||||||
static::assertSame(302, $result->getStatusCode());
|
|
||||||
static::assertSame(['/subfolder/admin/import'], $result->getHeader('location'));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test posting an import request - without import file
|
|
||||||
*/
|
|
||||||
public function testImportFileMissing(): void
|
|
||||||
{
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
$this->container->sessionManager
|
|
||||||
->expects(static::once())
|
|
||||||
->method('setSessionParameter')
|
|
||||||
->with(SessionManager::KEY_ERROR_MESSAGES, ['No import file provided.'])
|
|
||||||
;
|
|
||||||
|
|
||||||
$result = $this->controller->import($request, $response);
|
|
||||||
|
|
||||||
static::assertSame(302, $result->getStatusCode());
|
|
||||||
static::assertSame(['/subfolder/admin/import'], $result->getHeader('location'));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test posting an import request - with an empty file
|
|
||||||
*/
|
|
||||||
public function testImportEmptyFile(): void
|
|
||||||
{
|
|
||||||
$requestFile = new UploadedFile('file', 'name', 'type', 0);
|
|
||||||
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$request->method('getUploadedFiles')->willReturn(['filetoupload' => $requestFile]);
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
$this->container->netscapeBookmarkUtils = $this->createMock(NetscapeBookmarkUtils::class);
|
|
||||||
$this->container->netscapeBookmarkUtils->expects(static::never())->method('filterAndFormat');
|
|
||||||
|
|
||||||
$this->container->sessionManager
|
|
||||||
->expects(static::once())
|
|
||||||
->method('setSessionParameter')
|
|
||||||
->willReturnCallback(function (string $key, array $value): SessionManager {
|
|
||||||
static::assertSame(SessionManager::KEY_ERROR_MESSAGES, $key);
|
|
||||||
static::assertStringStartsWith('The file you are trying to upload is probably bigger', $value[0]);
|
|
||||||
|
|
||||||
return $this->container->sessionManager;
|
|
||||||
})
|
|
||||||
;
|
|
||||||
|
|
||||||
$result = $this->controller->import($request, $response);
|
|
||||||
|
|
||||||
static::assertSame(302, $result->getStatusCode());
|
|
||||||
static::assertSame(['/subfolder/admin/import'], $result->getHeader('location'));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,50 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace Shaarli\Front\Controller\Admin;
|
|
||||||
|
|
||||||
use Shaarli\Security\CookieManager;
|
|
||||||
use Shaarli\Security\SessionManager;
|
|
||||||
use Shaarli\TestCase;
|
|
||||||
use Slim\Http\Request;
|
|
||||||
use Slim\Http\Response;
|
|
||||||
|
|
||||||
class LogoutControllerTest extends TestCase
|
|
||||||
{
|
|
||||||
use FrontAdminControllerMockHelper;
|
|
||||||
|
|
||||||
/** @var LogoutController */
|
|
||||||
protected $controller;
|
|
||||||
|
|
||||||
public function setUp(): void
|
|
||||||
{
|
|
||||||
$this->createContainer();
|
|
||||||
|
|
||||||
$this->controller = new LogoutController($this->container);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testValidControllerInvoke(): void
|
|
||||||
{
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
$this->container->pageCacheManager->expects(static::once())->method('invalidateCaches');
|
|
||||||
|
|
||||||
$this->container->sessionManager = $this->createMock(SessionManager::class);
|
|
||||||
$this->container->sessionManager->expects(static::once())->method('logout');
|
|
||||||
|
|
||||||
$this->container->cookieManager = $this->createMock(CookieManager::class);
|
|
||||||
$this->container->cookieManager
|
|
||||||
->expects(static::once())
|
|
||||||
->method('setCookieParameter')
|
|
||||||
->with(CookieManager::STAY_SIGNED_IN, 'false', 0, '/subfolder/')
|
|
||||||
;
|
|
||||||
|
|
||||||
$result = $this->controller->index($request, $response);
|
|
||||||
|
|
||||||
static::assertInstanceOf(Response::class, $result);
|
|
||||||
static::assertSame(302, $result->getStatusCode());
|
|
||||||
static::assertSame(['/subfolder/'], $result->getHeader('location'));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,409 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace Shaarli\Front\Controller\Admin;
|
|
||||||
|
|
||||||
use Shaarli\Bookmark\Bookmark;
|
|
||||||
use Shaarli\Bookmark\BookmarkFilter;
|
|
||||||
use Shaarli\Bookmark\SearchResult;
|
|
||||||
use Shaarli\Config\ConfigManager;
|
|
||||||
use Shaarli\Front\Exception\WrongTokenException;
|
|
||||||
use Shaarli\Security\SessionManager;
|
|
||||||
use Shaarli\TestCase;
|
|
||||||
use Slim\Http\Request;
|
|
||||||
use Slim\Http\Response;
|
|
||||||
|
|
||||||
class ManageTagControllerTest extends TestCase
|
|
||||||
{
|
|
||||||
use FrontAdminControllerMockHelper;
|
|
||||||
|
|
||||||
/** @var ManageTagController */
|
|
||||||
protected $controller;
|
|
||||||
|
|
||||||
public function setUp(): void
|
|
||||||
{
|
|
||||||
$this->createContainer();
|
|
||||||
|
|
||||||
$this->controller = new ManageTagController($this->container);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test displaying manage tag page
|
|
||||||
*/
|
|
||||||
public function testIndex(): void
|
|
||||||
{
|
|
||||||
$assignedVariables = [];
|
|
||||||
$this->assignTemplateVars($assignedVariables);
|
|
||||||
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$request->method('getParam')->with('fromtag')->willReturn('fromtag');
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
$result = $this->controller->index($request, $response);
|
|
||||||
|
|
||||||
static::assertSame(200, $result->getStatusCode());
|
|
||||||
static::assertSame('changetag', (string) $result->getBody());
|
|
||||||
|
|
||||||
static::assertSame('fromtag', $assignedVariables['fromtag']);
|
|
||||||
static::assertSame('@', $assignedVariables['tags_separator']);
|
|
||||||
static::assertSame('Manage tags - Shaarli', $assignedVariables['pagetitle']);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test displaying manage tag page
|
|
||||||
*/
|
|
||||||
public function testIndexWhitespaceSeparator(): void
|
|
||||||
{
|
|
||||||
$assignedVariables = [];
|
|
||||||
$this->assignTemplateVars($assignedVariables);
|
|
||||||
|
|
||||||
$this->container->conf = $this->createMock(ConfigManager::class);
|
|
||||||
$this->container->conf->method('get')->willReturnCallback(function (string $key) {
|
|
||||||
return $key === 'general.tags_separator' ? ' ' : $key;
|
|
||||||
});
|
|
||||||
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
$this->controller->index($request, $response);
|
|
||||||
|
|
||||||
static::assertSame(' ', $assignedVariables['tags_separator']);
|
|
||||||
static::assertSame('whitespace', $assignedVariables['tags_separator_desc']);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test posting a tag update - rename tag - valid info provided.
|
|
||||||
*/
|
|
||||||
public function testSaveRenameTagValid(): void
|
|
||||||
{
|
|
||||||
$session = [];
|
|
||||||
$this->assignSessionVars($session);
|
|
||||||
|
|
||||||
$requestParameters = [
|
|
||||||
'renametag' => 'rename',
|
|
||||||
'fromtag' => 'old-tag',
|
|
||||||
'totag' => 'new-tag',
|
|
||||||
];
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$request
|
|
||||||
->expects(static::atLeastOnce())
|
|
||||||
->method('getParam')
|
|
||||||
->willReturnCallback(function (string $key) use ($requestParameters): ?string {
|
|
||||||
return $requestParameters[$key] ?? null;
|
|
||||||
})
|
|
||||||
;
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
$bookmark1 = $this->createMock(Bookmark::class);
|
|
||||||
$bookmark2 = $this->createMock(Bookmark::class);
|
|
||||||
$this->container->bookmarkService
|
|
||||||
->expects(static::once())
|
|
||||||
->method('search')
|
|
||||||
->with(['searchtags' => 'old-tag'], BookmarkFilter::$ALL, true)
|
|
||||||
->willReturnCallback(function () use ($bookmark1, $bookmark2): SearchResult {
|
|
||||||
$bookmark1->expects(static::once())->method('renameTag')->with('old-tag', 'new-tag');
|
|
||||||
$bookmark2->expects(static::once())->method('renameTag')->with('old-tag', 'new-tag');
|
|
||||||
|
|
||||||
return SearchResult::getSearchResult([$bookmark1, $bookmark2]);
|
|
||||||
})
|
|
||||||
;
|
|
||||||
$this->container->bookmarkService
|
|
||||||
->expects(static::exactly(2))
|
|
||||||
->method('set')
|
|
||||||
->withConsecutive([$bookmark1, false], [$bookmark2, false])
|
|
||||||
;
|
|
||||||
$this->container->bookmarkService->expects(static::once())->method('save');
|
|
||||||
|
|
||||||
$result = $this->controller->save($request, $response);
|
|
||||||
|
|
||||||
static::assertSame(302, $result->getStatusCode());
|
|
||||||
static::assertSame(['/subfolder/?searchtags=new-tag'], $result->getHeader('location'));
|
|
||||||
|
|
||||||
static::assertArrayNotHasKey(SessionManager::KEY_ERROR_MESSAGES, $session);
|
|
||||||
static::assertArrayNotHasKey(SessionManager::KEY_WARNING_MESSAGES, $session);
|
|
||||||
static::assertArrayHasKey(SessionManager::KEY_SUCCESS_MESSAGES, $session);
|
|
||||||
static::assertSame(['The tag was renamed in 2 bookmarks.'], $session[SessionManager::KEY_SUCCESS_MESSAGES]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test posting a tag update - delete tag - valid info provided.
|
|
||||||
*/
|
|
||||||
public function testSaveDeleteTagValid(): void
|
|
||||||
{
|
|
||||||
$session = [];
|
|
||||||
$this->assignSessionVars($session);
|
|
||||||
|
|
||||||
$requestParameters = [
|
|
||||||
'deletetag' => 'delete',
|
|
||||||
'fromtag' => 'old-tag',
|
|
||||||
];
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$request
|
|
||||||
->expects(static::atLeastOnce())
|
|
||||||
->method('getParam')
|
|
||||||
->willReturnCallback(function (string $key) use ($requestParameters): ?string {
|
|
||||||
return $requestParameters[$key] ?? null;
|
|
||||||
})
|
|
||||||
;
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
$bookmark1 = $this->createMock(Bookmark::class);
|
|
||||||
$bookmark2 = $this->createMock(Bookmark::class);
|
|
||||||
$this->container->bookmarkService
|
|
||||||
->expects(static::once())
|
|
||||||
->method('search')
|
|
||||||
->with(['searchtags' => 'old-tag'], BookmarkFilter::$ALL, true)
|
|
||||||
->willReturnCallback(function () use ($bookmark1, $bookmark2): SearchResult {
|
|
||||||
$bookmark1->expects(static::once())->method('deleteTag')->with('old-tag');
|
|
||||||
$bookmark2->expects(static::once())->method('deleteTag')->with('old-tag');
|
|
||||||
|
|
||||||
return SearchResult::getSearchResult([$bookmark1, $bookmark2]);
|
|
||||||
})
|
|
||||||
;
|
|
||||||
$this->container->bookmarkService
|
|
||||||
->expects(static::exactly(2))
|
|
||||||
->method('set')
|
|
||||||
->withConsecutive([$bookmark1, false], [$bookmark2, false])
|
|
||||||
;
|
|
||||||
$this->container->bookmarkService->expects(static::once())->method('save');
|
|
||||||
|
|
||||||
$result = $this->controller->save($request, $response);
|
|
||||||
|
|
||||||
static::assertSame(302, $result->getStatusCode());
|
|
||||||
static::assertSame(['/subfolder/admin/tags'], $result->getHeader('location'));
|
|
||||||
|
|
||||||
static::assertArrayNotHasKey(SessionManager::KEY_ERROR_MESSAGES, $session);
|
|
||||||
static::assertArrayNotHasKey(SessionManager::KEY_WARNING_MESSAGES, $session);
|
|
||||||
static::assertArrayHasKey(SessionManager::KEY_SUCCESS_MESSAGES, $session);
|
|
||||||
static::assertSame(['The tag was removed from 2 bookmarks.'], $session[SessionManager::KEY_SUCCESS_MESSAGES]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test posting a tag update - wrong token.
|
|
||||||
*/
|
|
||||||
public function testSaveWrongToken(): void
|
|
||||||
{
|
|
||||||
$this->container->sessionManager = $this->createMock(SessionManager::class);
|
|
||||||
$this->container->sessionManager->method('checkToken')->willReturn(false);
|
|
||||||
|
|
||||||
$this->container->conf->expects(static::never())->method('set');
|
|
||||||
$this->container->conf->expects(static::never())->method('write');
|
|
||||||
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
$this->expectException(WrongTokenException::class);
|
|
||||||
|
|
||||||
$this->controller->save($request, $response);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test posting a tag update - rename tag - missing "FROM" tag.
|
|
||||||
*/
|
|
||||||
public function testSaveRenameTagMissingFrom(): void
|
|
||||||
{
|
|
||||||
$session = [];
|
|
||||||
$this->assignSessionVars($session);
|
|
||||||
|
|
||||||
$requestParameters = [
|
|
||||||
'renametag' => 'rename',
|
|
||||||
];
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$request
|
|
||||||
->expects(static::atLeastOnce())
|
|
||||||
->method('getParam')
|
|
||||||
->willReturnCallback(function (string $key) use ($requestParameters): ?string {
|
|
||||||
return $requestParameters[$key] ?? null;
|
|
||||||
})
|
|
||||||
;
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
$result = $this->controller->save($request, $response);
|
|
||||||
|
|
||||||
static::assertSame(302, $result->getStatusCode());
|
|
||||||
static::assertSame(['/subfolder/admin/tags'], $result->getHeader('location'));
|
|
||||||
|
|
||||||
static::assertArrayNotHasKey(SessionManager::KEY_ERROR_MESSAGES, $session);
|
|
||||||
static::assertArrayHasKey(SessionManager::KEY_WARNING_MESSAGES, $session);
|
|
||||||
static::assertArrayNotHasKey(SessionManager::KEY_SUCCESS_MESSAGES, $session);
|
|
||||||
static::assertSame(['Invalid tags provided.'], $session[SessionManager::KEY_WARNING_MESSAGES]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test posting a tag update - delete tag - missing "FROM" tag.
|
|
||||||
*/
|
|
||||||
public function testSaveDeleteTagMissingFrom(): void
|
|
||||||
{
|
|
||||||
$session = [];
|
|
||||||
$this->assignSessionVars($session);
|
|
||||||
|
|
||||||
$requestParameters = [
|
|
||||||
'deletetag' => 'delete',
|
|
||||||
];
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$request
|
|
||||||
->expects(static::atLeastOnce())
|
|
||||||
->method('getParam')
|
|
||||||
->willReturnCallback(function (string $key) use ($requestParameters): ?string {
|
|
||||||
return $requestParameters[$key] ?? null;
|
|
||||||
})
|
|
||||||
;
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
$result = $this->controller->save($request, $response);
|
|
||||||
|
|
||||||
static::assertSame(302, $result->getStatusCode());
|
|
||||||
static::assertSame(['/subfolder/admin/tags'], $result->getHeader('location'));
|
|
||||||
|
|
||||||
static::assertArrayNotHasKey(SessionManager::KEY_ERROR_MESSAGES, $session);
|
|
||||||
static::assertArrayHasKey(SessionManager::KEY_WARNING_MESSAGES, $session);
|
|
||||||
static::assertArrayNotHasKey(SessionManager::KEY_SUCCESS_MESSAGES, $session);
|
|
||||||
static::assertSame(['Invalid tags provided.'], $session[SessionManager::KEY_WARNING_MESSAGES]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test posting a tag update - rename tag - missing "TO" tag.
|
|
||||||
*/
|
|
||||||
public function testSaveRenameTagMissingTo(): void
|
|
||||||
{
|
|
||||||
$session = [];
|
|
||||||
$this->assignSessionVars($session);
|
|
||||||
|
|
||||||
$requestParameters = [
|
|
||||||
'renametag' => 'rename',
|
|
||||||
'fromtag' => 'old-tag'
|
|
||||||
];
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$request
|
|
||||||
->expects(static::atLeastOnce())
|
|
||||||
->method('getParam')
|
|
||||||
->willReturnCallback(function (string $key) use ($requestParameters): ?string {
|
|
||||||
return $requestParameters[$key] ?? null;
|
|
||||||
})
|
|
||||||
;
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
$result = $this->controller->save($request, $response);
|
|
||||||
|
|
||||||
static::assertSame(302, $result->getStatusCode());
|
|
||||||
static::assertSame(['/subfolder/admin/tags'], $result->getHeader('location'));
|
|
||||||
|
|
||||||
static::assertArrayNotHasKey(SessionManager::KEY_ERROR_MESSAGES, $session);
|
|
||||||
static::assertArrayHasKey(SessionManager::KEY_WARNING_MESSAGES, $session);
|
|
||||||
static::assertArrayNotHasKey(SessionManager::KEY_SUCCESS_MESSAGES, $session);
|
|
||||||
static::assertSame(['Invalid tags provided.'], $session[SessionManager::KEY_WARNING_MESSAGES]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test changeSeparator to '#': redirection + success message.
|
|
||||||
*/
|
|
||||||
public function testChangeSeparatorValid(): void
|
|
||||||
{
|
|
||||||
$toSeparator = '#';
|
|
||||||
|
|
||||||
$session = [];
|
|
||||||
$this->assignSessionVars($session);
|
|
||||||
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$request
|
|
||||||
->expects(static::atLeastOnce())
|
|
||||||
->method('getParam')
|
|
||||||
->willReturnCallback(function (string $key) use ($toSeparator): ?string {
|
|
||||||
return $key === 'separator' ? $toSeparator : $key;
|
|
||||||
})
|
|
||||||
;
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
$this->container->conf
|
|
||||||
->expects(static::once())
|
|
||||||
->method('set')
|
|
||||||
->with('general.tags_separator', $toSeparator, true, true)
|
|
||||||
;
|
|
||||||
|
|
||||||
$result = $this->controller->changeSeparator($request, $response);
|
|
||||||
|
|
||||||
static::assertSame(302, $result->getStatusCode());
|
|
||||||
static::assertSame(['/subfolder/admin/tags'], $result->getHeader('location'));
|
|
||||||
|
|
||||||
static::assertArrayNotHasKey(SessionManager::KEY_ERROR_MESSAGES, $session);
|
|
||||||
static::assertArrayNotHasKey(SessionManager::KEY_WARNING_MESSAGES, $session);
|
|
||||||
static::assertArrayHasKey(SessionManager::KEY_SUCCESS_MESSAGES, $session);
|
|
||||||
static::assertSame(
|
|
||||||
['Your tags separator setting has been updated!'],
|
|
||||||
$session[SessionManager::KEY_SUCCESS_MESSAGES]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test changeSeparator to '#@' (too long): redirection + error message.
|
|
||||||
*/
|
|
||||||
public function testChangeSeparatorInvalidTooLong(): void
|
|
||||||
{
|
|
||||||
$toSeparator = '#@';
|
|
||||||
|
|
||||||
$session = [];
|
|
||||||
$this->assignSessionVars($session);
|
|
||||||
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$request
|
|
||||||
->expects(static::atLeastOnce())
|
|
||||||
->method('getParam')
|
|
||||||
->willReturnCallback(function (string $key) use ($toSeparator): ?string {
|
|
||||||
return $key === 'separator' ? $toSeparator : $key;
|
|
||||||
})
|
|
||||||
;
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
$this->container->conf->expects(static::never())->method('set');
|
|
||||||
|
|
||||||
$result = $this->controller->changeSeparator($request, $response);
|
|
||||||
|
|
||||||
static::assertSame(302, $result->getStatusCode());
|
|
||||||
static::assertSame(['/subfolder/admin/tags'], $result->getHeader('location'));
|
|
||||||
|
|
||||||
static::assertArrayNotHasKey(SessionManager::KEY_SUCCESS_MESSAGES, $session);
|
|
||||||
static::assertArrayNotHasKey(SessionManager::KEY_WARNING_MESSAGES, $session);
|
|
||||||
static::assertArrayHasKey(SessionManager::KEY_ERROR_MESSAGES, $session);
|
|
||||||
static::assertSame(
|
|
||||||
['Tags separator must be a single character.'],
|
|
||||||
$session[SessionManager::KEY_ERROR_MESSAGES]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test changeSeparator to '#@' (too long): redirection + error message.
|
|
||||||
*/
|
|
||||||
public function testChangeSeparatorInvalidReservedCharacter(): void
|
|
||||||
{
|
|
||||||
$toSeparator = '*';
|
|
||||||
|
|
||||||
$session = [];
|
|
||||||
$this->assignSessionVars($session);
|
|
||||||
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$request
|
|
||||||
->expects(static::atLeastOnce())
|
|
||||||
->method('getParam')
|
|
||||||
->willReturnCallback(function (string $key) use ($toSeparator): ?string {
|
|
||||||
return $key === 'separator' ? $toSeparator : $key;
|
|
||||||
})
|
|
||||||
;
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
$this->container->conf->expects(static::never())->method('set');
|
|
||||||
|
|
||||||
$result = $this->controller->changeSeparator($request, $response);
|
|
||||||
|
|
||||||
static::assertSame(302, $result->getStatusCode());
|
|
||||||
static::assertSame(['/subfolder/admin/tags'], $result->getHeader('location'));
|
|
||||||
|
|
||||||
static::assertArrayNotHasKey(SessionManager::KEY_SUCCESS_MESSAGES, $session);
|
|
||||||
static::assertArrayNotHasKey(SessionManager::KEY_WARNING_MESSAGES, $session);
|
|
||||||
static::assertArrayHasKey(SessionManager::KEY_ERROR_MESSAGES, $session);
|
|
||||||
static::assertStringStartsWith(
|
|
||||||
'These characters are reserved and can\'t be used as tags separator',
|
|
||||||
$session[SessionManager::KEY_ERROR_MESSAGES][0]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,203 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace Shaarli\Front\Controller\Admin;
|
|
||||||
|
|
||||||
use Shaarli\Config\ConfigManager;
|
|
||||||
use Shaarli\Front\Exception\OpenShaarliPasswordException;
|
|
||||||
use Shaarli\Front\Exception\WrongTokenException;
|
|
||||||
use Shaarli\Security\SessionManager;
|
|
||||||
use Shaarli\TestCase;
|
|
||||||
use Slim\Http\Request;
|
|
||||||
use Slim\Http\Response;
|
|
||||||
|
|
||||||
class PasswordControllerTest extends TestCase
|
|
||||||
{
|
|
||||||
use FrontAdminControllerMockHelper;
|
|
||||||
|
|
||||||
/** @var PasswordController */
|
|
||||||
protected $controller;
|
|
||||||
|
|
||||||
/** @var mixed[] Variables assigned to the template */
|
|
||||||
protected $assignedVariables = [];
|
|
||||||
|
|
||||||
public function setUp(): void
|
|
||||||
{
|
|
||||||
$this->createContainer();
|
|
||||||
$this->assignTemplateVars($this->assignedVariables);
|
|
||||||
|
|
||||||
$this->controller = new PasswordController($this->container);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test displaying the change password page.
|
|
||||||
*/
|
|
||||||
public function testGetPage(): void
|
|
||||||
{
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
$result = $this->controller->index($request, $response);
|
|
||||||
|
|
||||||
static::assertSame(200, $result->getStatusCode());
|
|
||||||
static::assertSame('changepassword', (string) $result->getBody());
|
|
||||||
static::assertSame('Change password - Shaarli', $this->assignedVariables['pagetitle']);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Change the password with valid parameters
|
|
||||||
*/
|
|
||||||
public function testPostNewPasswordDefault(): void
|
|
||||||
{
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$request->method('getParam')->willReturnCallback(function (string $key): string {
|
|
||||||
if ('oldpassword' === $key) {
|
|
||||||
return 'old';
|
|
||||||
}
|
|
||||||
if ('setpassword' === $key) {
|
|
||||||
return 'new';
|
|
||||||
}
|
|
||||||
|
|
||||||
return $key;
|
|
||||||
});
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
$this->container->conf = $this->createMock(ConfigManager::class);
|
|
||||||
$this->container->conf->method('get')->willReturnCallback(function (string $key, $default) {
|
|
||||||
if ('credentials.hash' === $key) {
|
|
||||||
return sha1('old' . 'credentials.login' . 'credentials.salt');
|
|
||||||
}
|
|
||||||
|
|
||||||
return strpos($key, 'credentials') !== false ? $key : $default;
|
|
||||||
});
|
|
||||||
$this->container->conf->expects(static::once())->method('write')->with(true);
|
|
||||||
|
|
||||||
$this->container->conf
|
|
||||||
->method('set')
|
|
||||||
->willReturnCallback(function (string $key, string $value) {
|
|
||||||
if ('credentials.hash' === $key) {
|
|
||||||
static::assertSame(sha1('new' . 'credentials.login' . 'credentials.salt'), $value);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
;
|
|
||||||
|
|
||||||
$result = $this->controller->change($request, $response);
|
|
||||||
|
|
||||||
static::assertSame(200, $result->getStatusCode());
|
|
||||||
static::assertSame('changepassword', (string) $result->getBody());
|
|
||||||
static::assertSame('Change password - Shaarli', $this->assignedVariables['pagetitle']);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Change the password with a wrong existing password
|
|
||||||
*/
|
|
||||||
public function testPostNewPasswordWrongOldPassword(): void
|
|
||||||
{
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$request->method('getParam')->willReturnCallback(function (string $key): string {
|
|
||||||
if ('oldpassword' === $key) {
|
|
||||||
return 'wrong';
|
|
||||||
}
|
|
||||||
if ('setpassword' === $key) {
|
|
||||||
return 'new';
|
|
||||||
}
|
|
||||||
|
|
||||||
return $key;
|
|
||||||
});
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
$this->container->conf = $this->createMock(ConfigManager::class);
|
|
||||||
$this->container->conf->method('get')->willReturnCallback(function (string $key, $default) {
|
|
||||||
if ('credentials.hash' === $key) {
|
|
||||||
return sha1('old' . 'credentials.login' . 'credentials.salt');
|
|
||||||
}
|
|
||||||
|
|
||||||
return strpos($key, 'credentials') !== false ? $key : $default;
|
|
||||||
});
|
|
||||||
|
|
||||||
$this->container->conf->expects(static::never())->method('set');
|
|
||||||
$this->container->conf->expects(static::never())->method('write');
|
|
||||||
|
|
||||||
$this->container->sessionManager
|
|
||||||
->expects(static::once())
|
|
||||||
->method('setSessionParameter')
|
|
||||||
->with(SessionManager::KEY_ERROR_MESSAGES, ['The old password is not correct.'])
|
|
||||||
;
|
|
||||||
|
|
||||||
$result = $this->controller->change($request, $response);
|
|
||||||
|
|
||||||
static::assertSame(400, $result->getStatusCode());
|
|
||||||
static::assertSame('changepassword', (string) $result->getBody());
|
|
||||||
static::assertSame('Change password - Shaarli', $this->assignedVariables['pagetitle']);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Change the password with a wrong existing password
|
|
||||||
*/
|
|
||||||
public function testPostNewPasswordWrongToken(): void
|
|
||||||
{
|
|
||||||
$this->container->sessionManager = $this->createMock(SessionManager::class);
|
|
||||||
$this->container->sessionManager->method('checkToken')->willReturn(false);
|
|
||||||
|
|
||||||
$this->container->conf->expects(static::never())->method('set');
|
|
||||||
$this->container->conf->expects(static::never())->method('write');
|
|
||||||
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
$this->expectException(WrongTokenException::class);
|
|
||||||
|
|
||||||
$this->controller->change($request, $response);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Change the password with an empty new password
|
|
||||||
*/
|
|
||||||
public function testPostNewEmptyPassword(): void
|
|
||||||
{
|
|
||||||
$this->container->sessionManager
|
|
||||||
->expects(static::once())
|
|
||||||
->method('setSessionParameter')
|
|
||||||
->with(SessionManager::KEY_ERROR_MESSAGES, ['You must provide the current and new password to change it.'])
|
|
||||||
;
|
|
||||||
|
|
||||||
$this->container->conf->expects(static::never())->method('set');
|
|
||||||
$this->container->conf->expects(static::never())->method('write');
|
|
||||||
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$request->method('getParam')->willReturnCallback(function (string $key): string {
|
|
||||||
if ('oldpassword' === $key) {
|
|
||||||
return 'old';
|
|
||||||
}
|
|
||||||
if ('setpassword' === $key) {
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
|
|
||||||
return $key;
|
|
||||||
});
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
$result = $this->controller->change($request, $response);
|
|
||||||
|
|
||||||
static::assertSame(400, $result->getStatusCode());
|
|
||||||
static::assertSame('changepassword', (string) $result->getBody());
|
|
||||||
static::assertSame('Change password - Shaarli', $this->assignedVariables['pagetitle']);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Change the password on an open shaarli
|
|
||||||
*/
|
|
||||||
public function testPostNewPasswordOnOpenShaarli(): void
|
|
||||||
{
|
|
||||||
$this->container->conf = $this->createMock(ConfigManager::class);
|
|
||||||
$this->container->conf->method('get')->with('security.open_shaarli')->willReturn(true);
|
|
||||||
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
$this->expectException(OpenShaarliPasswordException::class);
|
|
||||||
|
|
||||||
$this->controller->change($request, $response);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,209 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace Shaarli\Front\Controller\Admin;
|
|
||||||
|
|
||||||
use Shaarli\Config\ConfigManager;
|
|
||||||
use Shaarli\Front\Exception\WrongTokenException;
|
|
||||||
use Shaarli\Plugin\PluginManager;
|
|
||||||
use Shaarli\Security\SessionManager;
|
|
||||||
use Shaarli\TestCase;
|
|
||||||
use Slim\Http\Request;
|
|
||||||
use Slim\Http\Response;
|
|
||||||
|
|
||||||
class PluginsControllerTest extends TestCase
|
|
||||||
{
|
|
||||||
use FrontAdminControllerMockHelper;
|
|
||||||
|
|
||||||
protected const PLUGIN_NAMES = ['plugin1', 'plugin2', 'plugin3', 'plugin4'];
|
|
||||||
|
|
||||||
/** @var PluginsController */
|
|
||||||
protected $controller;
|
|
||||||
|
|
||||||
public function setUp(): void
|
|
||||||
{
|
|
||||||
$this->createContainer();
|
|
||||||
|
|
||||||
$this->controller = new PluginsController($this->container);
|
|
||||||
|
|
||||||
mkdir($path = __DIR__ . '/folder');
|
|
||||||
PluginManager::$PLUGINS_PATH = $path;
|
|
||||||
array_map(function (string $plugin) use ($path) {
|
|
||||||
touch($path . '/' . $plugin);
|
|
||||||
}, static::PLUGIN_NAMES);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function tearDown(): void
|
|
||||||
{
|
|
||||||
$path = __DIR__ . '/folder';
|
|
||||||
array_map(function (string $plugin) use ($path) {
|
|
||||||
unlink($path . '/' . $plugin);
|
|
||||||
}, static::PLUGIN_NAMES);
|
|
||||||
rmdir($path);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test displaying plugins admin page
|
|
||||||
*/
|
|
||||||
public function testIndex(): void
|
|
||||||
{
|
|
||||||
$assignedVariables = [];
|
|
||||||
$this->assignTemplateVars($assignedVariables);
|
|
||||||
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
$data = [
|
|
||||||
'plugin1' => ['order' => 2, 'other' => 'field'],
|
|
||||||
'plugin2' => ['order' => 1],
|
|
||||||
'plugin3' => ['order' => false, 'abc' => 'def'],
|
|
||||||
'plugin4' => [],
|
|
||||||
];
|
|
||||||
|
|
||||||
$this->container->pluginManager
|
|
||||||
->expects(static::once())
|
|
||||||
->method('getPluginsMeta')
|
|
||||||
->willReturn($data);
|
|
||||||
|
|
||||||
$result = $this->controller->index($request, $response);
|
|
||||||
|
|
||||||
static::assertSame(200, $result->getStatusCode());
|
|
||||||
static::assertSame('pluginsadmin', (string) $result->getBody());
|
|
||||||
|
|
||||||
static::assertSame('Plugin Administration - Shaarli', $assignedVariables['pagetitle']);
|
|
||||||
static::assertSame(
|
|
||||||
['plugin2' => $data['plugin2'], 'plugin1' => $data['plugin1']],
|
|
||||||
$assignedVariables['enabledPlugins']
|
|
||||||
);
|
|
||||||
static::assertSame(
|
|
||||||
['plugin3' => $data['plugin3'], 'plugin4' => $data['plugin4']],
|
|
||||||
$assignedVariables['disabledPlugins']
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test save plugins admin page
|
|
||||||
*/
|
|
||||||
public function testSaveEnabledPlugins(): void
|
|
||||||
{
|
|
||||||
$parameters = [
|
|
||||||
'plugin1' => 'on',
|
|
||||||
'order_plugin1' => '2',
|
|
||||||
'plugin2' => 'on',
|
|
||||||
];
|
|
||||||
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$request
|
|
||||||
->expects(static::atLeastOnce())
|
|
||||||
->method('getParams')
|
|
||||||
->willReturnCallback(function () use ($parameters): array {
|
|
||||||
return $parameters;
|
|
||||||
})
|
|
||||||
;
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
$this->container->pluginManager
|
|
||||||
->expects(static::once())
|
|
||||||
->method('executeHooks')
|
|
||||||
->with('save_plugin_parameters', $parameters)
|
|
||||||
;
|
|
||||||
$this->container->conf
|
|
||||||
->expects(static::atLeastOnce())
|
|
||||||
->method('set')
|
|
||||||
->with('general.enabled_plugins', ['plugin1', 'plugin2'])
|
|
||||||
;
|
|
||||||
|
|
||||||
$result = $this->controller->save($request, $response);
|
|
||||||
|
|
||||||
static::assertSame(302, $result->getStatusCode());
|
|
||||||
static::assertSame(['/subfolder/admin/plugins'], $result->getHeader('location'));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test save plugin parameters
|
|
||||||
*/
|
|
||||||
public function testSavePluginParameters(): void
|
|
||||||
{
|
|
||||||
$parameters = [
|
|
||||||
'parameters_form' => true,
|
|
||||||
'parameter1' => 'blip',
|
|
||||||
'parameter2' => 'blop',
|
|
||||||
'token' => 'this parameter should not be saved'
|
|
||||||
];
|
|
||||||
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$request
|
|
||||||
->expects(static::atLeastOnce())
|
|
||||||
->method('getParams')
|
|
||||||
->willReturnCallback(function () use ($parameters): array {
|
|
||||||
return $parameters;
|
|
||||||
})
|
|
||||||
;
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
$this->container->pluginManager
|
|
||||||
->expects(static::once())
|
|
||||||
->method('executeHooks')
|
|
||||||
->with('save_plugin_parameters', $parameters)
|
|
||||||
;
|
|
||||||
$this->container->conf
|
|
||||||
->expects(static::exactly(2))
|
|
||||||
->method('set')
|
|
||||||
->withConsecutive(['plugins.parameter1', 'blip'], ['plugins.parameter2', 'blop'])
|
|
||||||
;
|
|
||||||
|
|
||||||
$result = $this->controller->save($request, $response);
|
|
||||||
|
|
||||||
static::assertSame(302, $result->getStatusCode());
|
|
||||||
static::assertSame(['/subfolder/admin/plugins'], $result->getHeader('location'));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test save plugin parameters - error encountered
|
|
||||||
*/
|
|
||||||
public function testSaveWithError(): void
|
|
||||||
{
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
$this->container->conf = $this->createMock(ConfigManager::class);
|
|
||||||
$this->container->conf
|
|
||||||
->expects(static::atLeastOnce())
|
|
||||||
->method('write')
|
|
||||||
->willThrowException(new \Exception($message = 'error message'))
|
|
||||||
;
|
|
||||||
|
|
||||||
$this->container->sessionManager = $this->createMock(SessionManager::class);
|
|
||||||
$this->container->sessionManager->method('checkToken')->willReturn(true);
|
|
||||||
$this->container->sessionManager
|
|
||||||
->expects(static::once())
|
|
||||||
->method('setSessionParameter')
|
|
||||||
->with(
|
|
||||||
SessionManager::KEY_ERROR_MESSAGES,
|
|
||||||
['Error while saving plugin configuration: ' . PHP_EOL . $message]
|
|
||||||
)
|
|
||||||
;
|
|
||||||
|
|
||||||
$result = $this->controller->save($request, $response);
|
|
||||||
|
|
||||||
static::assertSame(302, $result->getStatusCode());
|
|
||||||
static::assertSame(['/subfolder/admin/plugins'], $result->getHeader('location'));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test save plugin parameters - wrong token
|
|
||||||
*/
|
|
||||||
public function testSaveWrongToken(): void
|
|
||||||
{
|
|
||||||
$this->container->sessionManager = $this->createMock(SessionManager::class);
|
|
||||||
$this->container->sessionManager->method('checkToken')->willReturn(false);
|
|
||||||
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
$this->expectException(WrongTokenException::class);
|
|
||||||
|
|
||||||
$this->controller->save($request, $response);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,184 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace Shaarli\Front\Controller\Admin;
|
|
||||||
|
|
||||||
use Shaarli\Config\ConfigManager;
|
|
||||||
use Shaarli\Security\SessionManager;
|
|
||||||
use Shaarli\TestCase;
|
|
||||||
use Slim\Http\Request;
|
|
||||||
use Slim\Http\Response;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test Server administration controller.
|
|
||||||
*/
|
|
||||||
class ServerControllerTest extends TestCase
|
|
||||||
{
|
|
||||||
use FrontAdminControllerMockHelper;
|
|
||||||
|
|
||||||
/** @var ServerController */
|
|
||||||
protected $controller;
|
|
||||||
|
|
||||||
public function setUp(): void
|
|
||||||
{
|
|
||||||
$this->createContainer();
|
|
||||||
|
|
||||||
$this->controller = new ServerController($this->container);
|
|
||||||
|
|
||||||
// initialize dummy cache
|
|
||||||
@mkdir('sandbox/');
|
|
||||||
foreach (['pagecache', 'tmp', 'cache'] as $folder) {
|
|
||||||
@mkdir('sandbox/' . $folder);
|
|
||||||
@touch('sandbox/' . $folder . '/.htaccess');
|
|
||||||
@touch('sandbox/' . $folder . '/1');
|
|
||||||
@touch('sandbox/' . $folder . '/2');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function tearDown(): void
|
|
||||||
{
|
|
||||||
foreach (['pagecache', 'tmp', 'cache'] as $folder) {
|
|
||||||
@unlink('sandbox/' . $folder . '/.htaccess');
|
|
||||||
@unlink('sandbox/' . $folder . '/1');
|
|
||||||
@unlink('sandbox/' . $folder . '/2');
|
|
||||||
@rmdir('sandbox/' . $folder);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test default display of server administration page.
|
|
||||||
*/
|
|
||||||
public function testIndex(): void
|
|
||||||
{
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
// Save RainTPL assigned variables
|
|
||||||
$assignedVariables = [];
|
|
||||||
$this->assignTemplateVars($assignedVariables);
|
|
||||||
|
|
||||||
$result = $this->controller->index($request, $response);
|
|
||||||
|
|
||||||
static::assertSame(200, $result->getStatusCode());
|
|
||||||
static::assertSame('server', (string) $result->getBody());
|
|
||||||
|
|
||||||
static::assertSame(PHP_VERSION, $assignedVariables['php_version']);
|
|
||||||
static::assertArrayHasKey('php_has_reached_eol', $assignedVariables);
|
|
||||||
static::assertArrayHasKey('php_eol', $assignedVariables);
|
|
||||||
static::assertArrayHasKey('php_extensions', $assignedVariables);
|
|
||||||
static::assertArrayHasKey('permissions', $assignedVariables);
|
|
||||||
static::assertEmpty($assignedVariables['permissions']);
|
|
||||||
|
|
||||||
static::assertRegExp(
|
|
||||||
'#https://github\.com/shaarli/Shaarli/releases/tag/v\d+\.\d+\.\d+#',
|
|
||||||
$assignedVariables['release_url']
|
|
||||||
);
|
|
||||||
static::assertRegExp('#v\d+\.\d+\.\d+#', $assignedVariables['latest_version']);
|
|
||||||
static::assertRegExp('#(v\d+\.\d+\.\d+|dev)#', $assignedVariables['current_version']);
|
|
||||||
static::assertArrayHasKey('index_url', $assignedVariables);
|
|
||||||
static::assertArrayHasKey('client_ip', $assignedVariables);
|
|
||||||
static::assertArrayHasKey('trusted_proxies', $assignedVariables);
|
|
||||||
|
|
||||||
static::assertSame('Server administration - Shaarli', $assignedVariables['pagetitle']);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test clearing the main cache
|
|
||||||
*/
|
|
||||||
public function testClearMainCache(): void
|
|
||||||
{
|
|
||||||
$this->container->conf = $this->createMock(ConfigManager::class);
|
|
||||||
$this->container->conf->method('get')->willReturnCallback(function (string $key, $default) {
|
|
||||||
if ($key === 'resource.page_cache') {
|
|
||||||
return 'sandbox/pagecache';
|
|
||||||
} elseif ($key === 'resource.raintpl_tmp') {
|
|
||||||
return 'sandbox/tmp';
|
|
||||||
} elseif ($key === 'resource.thumbnails_cache') {
|
|
||||||
return 'sandbox/cache';
|
|
||||||
} else {
|
|
||||||
return $default;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
$this->container->sessionManager
|
|
||||||
->expects(static::once())
|
|
||||||
->method('setSessionParameter')
|
|
||||||
->with(SessionManager::KEY_SUCCESS_MESSAGES, ['Shaarli\'s cache folder has been cleared!'])
|
|
||||||
;
|
|
||||||
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$request->method('getQueryParam')->with('type')->willReturn('main');
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
$result = $this->controller->clearCache($request, $response);
|
|
||||||
|
|
||||||
static::assertSame(302, $result->getStatusCode());
|
|
||||||
static::assertSame('/subfolder/admin/server', (string) $result->getHeaderLine('Location'));
|
|
||||||
|
|
||||||
static::assertFileNotExists('sandbox/pagecache/1');
|
|
||||||
static::assertFileNotExists('sandbox/pagecache/2');
|
|
||||||
static::assertFileNotExists('sandbox/tmp/1');
|
|
||||||
static::assertFileNotExists('sandbox/tmp/2');
|
|
||||||
|
|
||||||
static::assertFileExists('sandbox/pagecache/.htaccess');
|
|
||||||
static::assertFileExists('sandbox/tmp/.htaccess');
|
|
||||||
static::assertFileExists('sandbox/cache');
|
|
||||||
static::assertFileExists('sandbox/cache/.htaccess');
|
|
||||||
static::assertFileExists('sandbox/cache/1');
|
|
||||||
static::assertFileExists('sandbox/cache/2');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test clearing thumbnails cache
|
|
||||||
*/
|
|
||||||
public function testClearThumbnailsCache(): void
|
|
||||||
{
|
|
||||||
$this->container->conf = $this->createMock(ConfigManager::class);
|
|
||||||
$this->container->conf->method('get')->willReturnCallback(function (string $key, $default) {
|
|
||||||
if ($key === 'resource.page_cache') {
|
|
||||||
return 'sandbox/pagecache';
|
|
||||||
} elseif ($key === 'resource.raintpl_tmp') {
|
|
||||||
return 'sandbox/tmp';
|
|
||||||
} elseif ($key === 'resource.thumbnails_cache') {
|
|
||||||
return 'sandbox/cache';
|
|
||||||
} else {
|
|
||||||
return $default;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
$this->container->sessionManager
|
|
||||||
->expects(static::once())
|
|
||||||
->method('setSessionParameter')
|
|
||||||
->willReturnCallback(function (string $key, array $value): SessionManager {
|
|
||||||
static::assertSame(SessionManager::KEY_WARNING_MESSAGES, $key);
|
|
||||||
static::assertCount(1, $value);
|
|
||||||
static::assertStringStartsWith('Thumbnails cache has been cleared.', $value[0]);
|
|
||||||
|
|
||||||
return $this->container->sessionManager;
|
|
||||||
});
|
|
||||||
;
|
|
||||||
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$request->method('getQueryParam')->with('type')->willReturn('thumbnails');
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
$result = $this->controller->clearCache($request, $response);
|
|
||||||
|
|
||||||
static::assertSame(302, $result->getStatusCode());
|
|
||||||
static::assertSame('/subfolder/admin/server', (string) $result->getHeaderLine('Location'));
|
|
||||||
|
|
||||||
static::assertFileNotExists('sandbox/cache/1');
|
|
||||||
static::assertFileNotExists('sandbox/cache/2');
|
|
||||||
|
|
||||||
static::assertFileExists('sandbox/cache/.htaccess');
|
|
||||||
static::assertFileExists('sandbox/pagecache');
|
|
||||||
static::assertFileExists('sandbox/pagecache/.htaccess');
|
|
||||||
static::assertFileExists('sandbox/pagecache/1');
|
|
||||||
static::assertFileExists('sandbox/pagecache/2');
|
|
||||||
static::assertFileExists('sandbox/tmp');
|
|
||||||
static::assertFileExists('sandbox/tmp/.htaccess');
|
|
||||||
static::assertFileExists('sandbox/tmp/1');
|
|
||||||
static::assertFileExists('sandbox/tmp/2');
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,177 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace Shaarli\Front\Controller\Admin;
|
|
||||||
|
|
||||||
use Shaarli\Security\LoginManager;
|
|
||||||
use Shaarli\Security\SessionManager;
|
|
||||||
use Shaarli\TestCase;
|
|
||||||
use Slim\Http\Request;
|
|
||||||
use Slim\Http\Response;
|
|
||||||
|
|
||||||
class SessionFilterControllerTest extends TestCase
|
|
||||||
{
|
|
||||||
use FrontAdminControllerMockHelper;
|
|
||||||
|
|
||||||
/** @var SessionFilterController */
|
|
||||||
protected $controller;
|
|
||||||
|
|
||||||
public function setUp(): void
|
|
||||||
{
|
|
||||||
$this->createContainer();
|
|
||||||
|
|
||||||
$this->controller = new SessionFilterController($this->container);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Visibility - Default call for private filter while logged in without current value
|
|
||||||
*/
|
|
||||||
public function testVisibility(): void
|
|
||||||
{
|
|
||||||
$arg = ['visibility' => 'private'];
|
|
||||||
|
|
||||||
$this->container->environment['HTTP_REFERER'] = 'http://shaarli/subfolder/controller/?searchtag=abc';
|
|
||||||
|
|
||||||
$this->container->loginManager->method('isLoggedIn')->willReturn(true);
|
|
||||||
$this->container->sessionManager
|
|
||||||
->expects(static::once())
|
|
||||||
->method('setSessionParameter')
|
|
||||||
->with(SessionManager::KEY_VISIBILITY, 'private')
|
|
||||||
;
|
|
||||||
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
$result = $this->controller->visibility($request, $response, $arg);
|
|
||||||
|
|
||||||
static::assertInstanceOf(Response::class, $result);
|
|
||||||
static::assertSame(302, $result->getStatusCode());
|
|
||||||
static::assertSame(['/subfolder/controller/?searchtag=abc'], $result->getHeader('location'));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Visibility - Toggle off private visibility
|
|
||||||
*/
|
|
||||||
public function testVisibilityToggleOff(): void
|
|
||||||
{
|
|
||||||
$arg = ['visibility' => 'private'];
|
|
||||||
|
|
||||||
$this->container->environment['HTTP_REFERER'] = 'http://shaarli/subfolder/controller/?searchtag=abc';
|
|
||||||
|
|
||||||
$this->container->loginManager->method('isLoggedIn')->willReturn(true);
|
|
||||||
$this->container->sessionManager
|
|
||||||
->method('getSessionParameter')
|
|
||||||
->with(SessionManager::KEY_VISIBILITY)
|
|
||||||
->willReturn('private')
|
|
||||||
;
|
|
||||||
$this->container->sessionManager
|
|
||||||
->expects(static::never())
|
|
||||||
->method('setSessionParameter')
|
|
||||||
;
|
|
||||||
$this->container->sessionManager
|
|
||||||
->expects(static::once())
|
|
||||||
->method('deleteSessionParameter')
|
|
||||||
->with(SessionManager::KEY_VISIBILITY)
|
|
||||||
;
|
|
||||||
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
$result = $this->controller->visibility($request, $response, $arg);
|
|
||||||
|
|
||||||
static::assertInstanceOf(Response::class, $result);
|
|
||||||
static::assertSame(302, $result->getStatusCode());
|
|
||||||
static::assertSame(['/subfolder/controller/?searchtag=abc'], $result->getHeader('location'));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Visibility - Change private to public
|
|
||||||
*/
|
|
||||||
public function testVisibilitySwitch(): void
|
|
||||||
{
|
|
||||||
$arg = ['visibility' => 'private'];
|
|
||||||
|
|
||||||
$this->container->loginManager->method('isLoggedIn')->willReturn(true);
|
|
||||||
$this->container->sessionManager
|
|
||||||
->method('getSessionParameter')
|
|
||||||
->with(SessionManager::KEY_VISIBILITY)
|
|
||||||
->willReturn('public')
|
|
||||||
;
|
|
||||||
$this->container->sessionManager
|
|
||||||
->expects(static::once())
|
|
||||||
->method('setSessionParameter')
|
|
||||||
->with(SessionManager::KEY_VISIBILITY, 'private')
|
|
||||||
;
|
|
||||||
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
$result = $this->controller->visibility($request, $response, $arg);
|
|
||||||
|
|
||||||
static::assertInstanceOf(Response::class, $result);
|
|
||||||
static::assertSame(302, $result->getStatusCode());
|
|
||||||
static::assertSame(['/subfolder/'], $result->getHeader('location'));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Visibility - With invalid value - should remove any visibility setting
|
|
||||||
*/
|
|
||||||
public function testVisibilityInvalidValue(): void
|
|
||||||
{
|
|
||||||
$arg = ['visibility' => 'test'];
|
|
||||||
|
|
||||||
$this->container->environment['HTTP_REFERER'] = 'http://shaarli/subfolder/controller/?searchtag=abc';
|
|
||||||
|
|
||||||
$this->container->loginManager->method('isLoggedIn')->willReturn(true);
|
|
||||||
$this->container->sessionManager
|
|
||||||
->expects(static::never())
|
|
||||||
->method('setSessionParameter')
|
|
||||||
;
|
|
||||||
$this->container->sessionManager
|
|
||||||
->expects(static::once())
|
|
||||||
->method('deleteSessionParameter')
|
|
||||||
->with(SessionManager::KEY_VISIBILITY)
|
|
||||||
;
|
|
||||||
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
$result = $this->controller->visibility($request, $response, $arg);
|
|
||||||
|
|
||||||
static::assertInstanceOf(Response::class, $result);
|
|
||||||
static::assertSame(302, $result->getStatusCode());
|
|
||||||
static::assertSame(['/subfolder/controller/?searchtag=abc'], $result->getHeader('location'));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Visibility - Try to change visibility while logged out
|
|
||||||
*/
|
|
||||||
public function testVisibilityLoggedOut(): void
|
|
||||||
{
|
|
||||||
$arg = ['visibility' => 'test'];
|
|
||||||
|
|
||||||
$this->container->environment['HTTP_REFERER'] = 'http://shaarli/subfolder/controller/?searchtag=abc';
|
|
||||||
|
|
||||||
$this->container->loginManager = $this->createMock(LoginManager::class);
|
|
||||||
$this->container->loginManager->method('isLoggedIn')->willReturn(false);
|
|
||||||
$this->container->sessionManager
|
|
||||||
->expects(static::never())
|
|
||||||
->method('setSessionParameter')
|
|
||||||
;
|
|
||||||
$this->container->sessionManager
|
|
||||||
->expects(static::never())
|
|
||||||
->method('deleteSessionParameter')
|
|
||||||
->with(SessionManager::KEY_VISIBILITY)
|
|
||||||
;
|
|
||||||
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
$result = $this->controller->visibility($request, $response, $arg);
|
|
||||||
|
|
||||||
static::assertInstanceOf(Response::class, $result);
|
|
||||||
static::assertSame(302, $result->getStatusCode());
|
|
||||||
static::assertSame(['/subfolder/controller/?searchtag=abc'], $result->getHeader('location'));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,97 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace Shaarli\Front\Controller\Admin;
|
|
||||||
|
|
||||||
use Shaarli\Config\ConfigManager;
|
|
||||||
use Shaarli\Formatter\BookmarkMarkdownFormatter;
|
|
||||||
use Shaarli\Http\HttpAccess;
|
|
||||||
use Shaarli\TestCase;
|
|
||||||
use Slim\Http\Request;
|
|
||||||
use Slim\Http\Response;
|
|
||||||
|
|
||||||
class ShaareAddControllerTest extends TestCase
|
|
||||||
{
|
|
||||||
use FrontAdminControllerMockHelper;
|
|
||||||
|
|
||||||
/** @var ShaareAddController */
|
|
||||||
protected $controller;
|
|
||||||
|
|
||||||
public function setUp(): void
|
|
||||||
{
|
|
||||||
$this->createContainer();
|
|
||||||
|
|
||||||
$this->container->httpAccess = $this->createMock(HttpAccess::class);
|
|
||||||
$this->controller = new ShaareAddController($this->container);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test displaying add link page
|
|
||||||
*/
|
|
||||||
public function testAddShaare(): void
|
|
||||||
{
|
|
||||||
$assignedVariables = [];
|
|
||||||
$this->assignTemplateVars($assignedVariables);
|
|
||||||
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
$expectedTags = [
|
|
||||||
'tag1' => 32,
|
|
||||||
'tag2' => 24,
|
|
||||||
'tag3' => 1,
|
|
||||||
];
|
|
||||||
$this->container->bookmarkService
|
|
||||||
->expects(static::once())
|
|
||||||
->method('bookmarksCountPerTag')
|
|
||||||
->willReturn($expectedTags)
|
|
||||||
;
|
|
||||||
$expectedTags = array_merge($expectedTags, [BookmarkMarkdownFormatter::NO_MD_TAG => 1]);
|
|
||||||
|
|
||||||
$this->container->conf = $this->createMock(ConfigManager::class);
|
|
||||||
$this->container->conf->method('get')->willReturnCallback(function (string $key, $default) {
|
|
||||||
return $key === 'formatter' ? 'markdown' : $default;
|
|
||||||
});
|
|
||||||
|
|
||||||
$result = $this->controller->addShaare($request, $response);
|
|
||||||
|
|
||||||
static::assertSame(200, $result->getStatusCode());
|
|
||||||
static::assertSame('addlink', (string) $result->getBody());
|
|
||||||
|
|
||||||
static::assertSame('Shaare a new link - Shaarli', $assignedVariables['pagetitle']);
|
|
||||||
static::assertFalse($assignedVariables['default_private_links']);
|
|
||||||
static::assertTrue($assignedVariables['async_metadata']);
|
|
||||||
static::assertSame($expectedTags, $assignedVariables['tags']);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test displaying add link page
|
|
||||||
*/
|
|
||||||
public function testAddShaareWithoutMd(): void
|
|
||||||
{
|
|
||||||
$assignedVariables = [];
|
|
||||||
$this->assignTemplateVars($assignedVariables);
|
|
||||||
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
$expectedTags = [
|
|
||||||
'tag1' => 32,
|
|
||||||
'tag2' => 24,
|
|
||||||
'tag3' => 1,
|
|
||||||
];
|
|
||||||
$this->container->bookmarkService
|
|
||||||
->expects(static::once())
|
|
||||||
->method('bookmarksCountPerTag')
|
|
||||||
->willReturn($expectedTags)
|
|
||||||
;
|
|
||||||
|
|
||||||
$result = $this->controller->addShaare($request, $response);
|
|
||||||
|
|
||||||
static::assertSame(200, $result->getStatusCode());
|
|
||||||
static::assertSame('addlink', (string) $result->getBody());
|
|
||||||
|
|
||||||
static::assertSame($expectedTags, $assignedVariables['tags']);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,380 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace Shaarli\Front\Controller\Admin\ShaareManageControllerTest;
|
|
||||||
|
|
||||||
use Shaarli\Bookmark\Bookmark;
|
|
||||||
use Shaarli\Bookmark\Exception\BookmarkNotFoundException;
|
|
||||||
use Shaarli\Formatter\BookmarkFormatter;
|
|
||||||
use Shaarli\Formatter\BookmarkRawFormatter;
|
|
||||||
use Shaarli\Formatter\FormatterFactory;
|
|
||||||
use Shaarli\Front\Controller\Admin\FrontAdminControllerMockHelper;
|
|
||||||
use Shaarli\Front\Controller\Admin\ShaareManageController;
|
|
||||||
use Shaarli\Http\HttpAccess;
|
|
||||||
use Shaarli\Security\SessionManager;
|
|
||||||
use Shaarli\TestCase;
|
|
||||||
use Slim\Http\Request;
|
|
||||||
use Slim\Http\Response;
|
|
||||||
|
|
||||||
class AddOrDeleteTagTest extends TestCase
|
|
||||||
{
|
|
||||||
use FrontAdminControllerMockHelper;
|
|
||||||
|
|
||||||
/** @var ShaareManageController */
|
|
||||||
protected $controller;
|
|
||||||
|
|
||||||
public function setUp(): void
|
|
||||||
{
|
|
||||||
$this->createContainer();
|
|
||||||
|
|
||||||
$this->container->httpAccess = $this->createMock(HttpAccess::class);
|
|
||||||
$this->controller = new ShaareManageController($this->container);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add 1 tag to 1 bookmark
|
|
||||||
*/
|
|
||||||
public function testAddOneTagOnOneBookmark(): void
|
|
||||||
{
|
|
||||||
$parameters = ['id' => '123', 'tag' => 'newtag', 'action' => 'add'];
|
|
||||||
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$request
|
|
||||||
->method('getParam')
|
|
||||||
->willReturnCallback(function (string $key) use ($parameters): ?string {
|
|
||||||
return $parameters[$key] ?? null;
|
|
||||||
})
|
|
||||||
;
|
|
||||||
$response = new Response();
|
|
||||||
$bookmark = (new Bookmark())
|
|
||||||
->setId(123)->setUrl('http://domain.tld')->setTitle('Title 123')
|
|
||||||
->setTagsString('first second');
|
|
||||||
|
|
||||||
static::assertSame(['first', 'second'], $bookmark->getTags());
|
|
||||||
|
|
||||||
$this->container->bookmarkService->expects(static::once())->method('get')->with(123)->willReturn($bookmark);
|
|
||||||
$this->container->bookmarkService->expects(static::once())->method('set')->with($bookmark, false);
|
|
||||||
$this->container->bookmarkService->expects(static::once())->method('save');
|
|
||||||
$this->container->formatterFactory = $this->createMock(FormatterFactory::class);
|
|
||||||
$this->container->formatterFactory
|
|
||||||
->expects(static::once())
|
|
||||||
->method('getFormatter')
|
|
||||||
->with('raw')
|
|
||||||
->willReturnCallback(function () use ($bookmark): BookmarkFormatter {
|
|
||||||
return new BookmarkRawFormatter($this->container->conf, true);
|
|
||||||
})
|
|
||||||
;
|
|
||||||
|
|
||||||
// Make sure that PluginManager hook is triggered
|
|
||||||
$this->container->pluginManager
|
|
||||||
->expects(static::once())
|
|
||||||
->method('executeHooks')
|
|
||||||
->with('save_link')
|
|
||||||
;
|
|
||||||
|
|
||||||
$result = $this->controller->addOrDeleteTags($request, $response);
|
|
||||||
|
|
||||||
static::assertSame(['first', 'second', 'newtag'], $bookmark->getTags());
|
|
||||||
|
|
||||||
static::assertSame(302, $result->getStatusCode());
|
|
||||||
static::assertSame(['/subfolder/'], $result->getHeader('location'));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add 2 tags to 2 bookmarks
|
|
||||||
*/
|
|
||||||
public function testAddTwoTagsOnTwoBookmarks(): void
|
|
||||||
{
|
|
||||||
$parameters = ['id' => '123 456', 'tag' => 'newtag@othertag', 'action' => 'add'];
|
|
||||||
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$request
|
|
||||||
->method('getParam')
|
|
||||||
->willReturnCallback(function (string $key) use ($parameters): ?string {
|
|
||||||
return $parameters[$key] ?? null;
|
|
||||||
})
|
|
||||||
;
|
|
||||||
$response = new Response();
|
|
||||||
$bookmark1 = (new Bookmark())
|
|
||||||
->setId(123)->setUrl('http://domain.tld')->setTitle('Title 123')
|
|
||||||
->setTagsString('first second');
|
|
||||||
$bookmark2 = (new Bookmark())
|
|
||||||
->setId(456)->setUrl('http://domain.tld')->setTitle('Title 123');
|
|
||||||
|
|
||||||
static::assertSame(['first', 'second'], $bookmark1->getTags());
|
|
||||||
static::assertSame([], $bookmark2->getTags());
|
|
||||||
|
|
||||||
$this->container->bookmarkService->expects(static::exactly(2))->method('get')
|
|
||||||
->withConsecutive([123], [456])
|
|
||||||
->willReturnOnConsecutiveCalls($bookmark1, $bookmark2);
|
|
||||||
$this->container->bookmarkService->expects(static::exactly(2))->method('set')
|
|
||||||
->withConsecutive([$bookmark1, false], [$bookmark2, false]);
|
|
||||||
$this->container->bookmarkService->expects(static::once())->method('save');
|
|
||||||
$this->container->formatterFactory = $this->createMock(FormatterFactory::class);
|
|
||||||
$this->container->formatterFactory
|
|
||||||
->expects(static::once())
|
|
||||||
->method('getFormatter')
|
|
||||||
->with('raw')
|
|
||||||
->willReturnCallback(function (): BookmarkFormatter {
|
|
||||||
return new BookmarkRawFormatter($this->container->conf, true);
|
|
||||||
})
|
|
||||||
;
|
|
||||||
|
|
||||||
// Make sure that PluginManager hook is triggered
|
|
||||||
$this->container->pluginManager
|
|
||||||
->expects(static::exactly(2))
|
|
||||||
->method('executeHooks')
|
|
||||||
->with('save_link')
|
|
||||||
;
|
|
||||||
|
|
||||||
$result = $this->controller->addOrDeleteTags($request, $response);
|
|
||||||
|
|
||||||
static::assertSame(['first', 'second', 'newtag', 'othertag'], $bookmark1->getTags());
|
|
||||||
static::assertSame(['newtag', 'othertag'], $bookmark2->getTags());
|
|
||||||
|
|
||||||
static::assertSame(302, $result->getStatusCode());
|
|
||||||
static::assertSame(['/subfolder/'], $result->getHeader('location'));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Delete 1 tag to 1 bookmark
|
|
||||||
*/
|
|
||||||
public function testDeleteOneTagOnOneBookmark(): void
|
|
||||||
{
|
|
||||||
$parameters = ['id' => '123', 'tag' => 'second', 'action' => 'delete'];
|
|
||||||
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$request
|
|
||||||
->method('getParam')
|
|
||||||
->willReturnCallback(function (string $key) use ($parameters): ?string {
|
|
||||||
return $parameters[$key] ?? null;
|
|
||||||
})
|
|
||||||
;
|
|
||||||
$response = new Response();
|
|
||||||
$bookmark = (new Bookmark())
|
|
||||||
->setId(123)->setUrl('http://domain.tld')->setTitle('Title 123')
|
|
||||||
->setTagsString('first second third');
|
|
||||||
|
|
||||||
static::assertSame(['first', 'second', 'third'], $bookmark->getTags());
|
|
||||||
|
|
||||||
$this->container->bookmarkService->expects(static::once())->method('get')->with(123)->willReturn($bookmark);
|
|
||||||
$this->container->bookmarkService->expects(static::once())->method('set')->with($bookmark, false);
|
|
||||||
$this->container->bookmarkService->expects(static::once())->method('save');
|
|
||||||
$this->container->formatterFactory = $this->createMock(FormatterFactory::class);
|
|
||||||
$this->container->formatterFactory
|
|
||||||
->expects(static::once())
|
|
||||||
->method('getFormatter')
|
|
||||||
->with('raw')
|
|
||||||
->willReturnCallback(function () use ($bookmark): BookmarkFormatter {
|
|
||||||
return new BookmarkRawFormatter($this->container->conf, true);
|
|
||||||
})
|
|
||||||
;
|
|
||||||
|
|
||||||
// Make sure that PluginManager hook is triggered
|
|
||||||
$this->container->pluginManager
|
|
||||||
->expects(static::once())
|
|
||||||
->method('executeHooks')
|
|
||||||
->with('save_link')
|
|
||||||
;
|
|
||||||
|
|
||||||
$result = $this->controller->addOrDeleteTags($request, $response);
|
|
||||||
|
|
||||||
static::assertSame(['first', 'third'], $bookmark->getTags());
|
|
||||||
|
|
||||||
static::assertSame(302, $result->getStatusCode());
|
|
||||||
static::assertSame(['/subfolder/'], $result->getHeader('location'));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Delete 2 tags to 2 bookmarks
|
|
||||||
*/
|
|
||||||
public function testDeleteTwoTagOnTwoBookmarks(): void
|
|
||||||
{
|
|
||||||
$parameters = ['id' => '123 456', 'tag' => 'second@first', 'action' => 'delete'];
|
|
||||||
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$request
|
|
||||||
->method('getParam')
|
|
||||||
->willReturnCallback(function (string $key) use ($parameters): ?string {
|
|
||||||
return $parameters[$key] ?? null;
|
|
||||||
})
|
|
||||||
;
|
|
||||||
$response = new Response();
|
|
||||||
$bookmark1 = (new Bookmark())
|
|
||||||
->setId(123)->setUrl('http://domain.tld')->setTitle('Title 123')
|
|
||||||
->setTagsString('first second third other');
|
|
||||||
$bookmark2 = (new Bookmark())
|
|
||||||
->setId(456)->setUrl('http://domain.tld')->setTitle('Title 123')
|
|
||||||
->setTagsString('first second');
|
|
||||||
|
|
||||||
static::assertSame(['first', 'second', 'third', 'other'], $bookmark1->getTags());
|
|
||||||
static::assertSame(['first', 'second'], $bookmark2->getTags());
|
|
||||||
|
|
||||||
$this->container->bookmarkService->expects(static::exactly(2))->method('get')
|
|
||||||
->withConsecutive([123], [456])
|
|
||||||
->willReturnOnConsecutiveCalls($bookmark1, $bookmark2);
|
|
||||||
$this->container->bookmarkService->expects(static::exactly(2))->method('set')
|
|
||||||
->withConsecutive([$bookmark1, false], [$bookmark2, false]);
|
|
||||||
$this->container->bookmarkService->expects(static::once())->method('save');
|
|
||||||
$this->container->formatterFactory = $this->createMock(FormatterFactory::class);
|
|
||||||
$this->container->formatterFactory
|
|
||||||
->expects(static::once())
|
|
||||||
->method('getFormatter')
|
|
||||||
->with('raw')
|
|
||||||
->willReturnCallback(function (): BookmarkFormatter {
|
|
||||||
return new BookmarkRawFormatter($this->container->conf, true);
|
|
||||||
})
|
|
||||||
;
|
|
||||||
|
|
||||||
// Make sure that PluginManager hook is triggered
|
|
||||||
$this->container->pluginManager
|
|
||||||
->expects(static::exactly(2))
|
|
||||||
->method('executeHooks')
|
|
||||||
->with('save_link')
|
|
||||||
;
|
|
||||||
|
|
||||||
$result = $this->controller->addOrDeleteTags($request, $response);
|
|
||||||
|
|
||||||
static::assertSame(['third', 'other'], $bookmark1->getTags());
|
|
||||||
static::assertSame([], $bookmark2->getTags());
|
|
||||||
|
|
||||||
static::assertSame(302, $result->getStatusCode());
|
|
||||||
static::assertSame(['/subfolder/'], $result->getHeader('location'));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test add a tag without passing an ID.
|
|
||||||
*/
|
|
||||||
public function testAddTagWithoutId(): void
|
|
||||||
{
|
|
||||||
$parameters = ['tag' => 'newtag', 'action' => 'add'];
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$request
|
|
||||||
->method('getParam')
|
|
||||||
->willReturnCallback(function (string $key) use ($parameters): ?string {
|
|
||||||
return $parameters[$key] ?? null;
|
|
||||||
})
|
|
||||||
;
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
$this->container->sessionManager
|
|
||||||
->expects(static::once())
|
|
||||||
->method('setSessionParameter')
|
|
||||||
->with(SessionManager::KEY_ERROR_MESSAGES, ['Invalid bookmark ID provided.'])
|
|
||||||
;
|
|
||||||
|
|
||||||
$result = $this->controller->addOrDeleteTags($request, $response);
|
|
||||||
|
|
||||||
static::assertSame(302, $result->getStatusCode());
|
|
||||||
static::assertSame(['/subfolder/'], $result->getHeader('location'));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test add a tag without passing an ID.
|
|
||||||
*/
|
|
||||||
public function testDeleteTagWithoutId(): void
|
|
||||||
{
|
|
||||||
$parameters = ['tag' => 'newtag', 'action' => 'delete'];
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$request
|
|
||||||
->method('getParam')
|
|
||||||
->willReturnCallback(function (string $key) use ($parameters): ?string {
|
|
||||||
return $parameters[$key] ?? null;
|
|
||||||
})
|
|
||||||
;
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
$this->container->sessionManager
|
|
||||||
->expects(static::once())
|
|
||||||
->method('setSessionParameter')
|
|
||||||
->with(SessionManager::KEY_ERROR_MESSAGES, ['Invalid bookmark ID provided.'])
|
|
||||||
;
|
|
||||||
|
|
||||||
$result = $this->controller->addOrDeleteTags($request, $response);
|
|
||||||
|
|
||||||
static::assertSame(302, $result->getStatusCode());
|
|
||||||
static::assertSame(['/subfolder/'], $result->getHeader('location'));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test add a tag without passing an action.
|
|
||||||
*/
|
|
||||||
public function testAddTagWithoutAction(): void
|
|
||||||
{
|
|
||||||
$parameters = ['id' => '123', 'tag' => 'newtag'];
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$request
|
|
||||||
->method('getParam')
|
|
||||||
->willReturnCallback(function (string $key) use ($parameters): ?string {
|
|
||||||
return $parameters[$key] ?? null;
|
|
||||||
})
|
|
||||||
;
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
$this->container->sessionManager
|
|
||||||
->expects(static::once())
|
|
||||||
->method('setSessionParameter')
|
|
||||||
->with(SessionManager::KEY_ERROR_MESSAGES, ['Invalid action provided.'])
|
|
||||||
;
|
|
||||||
|
|
||||||
$result = $this->controller->addOrDeleteTags($request, $response);
|
|
||||||
|
|
||||||
static::assertSame(302, $result->getStatusCode());
|
|
||||||
static::assertSame(['/subfolder/'], $result->getHeader('location'));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test add a tag without passing a tag string value.
|
|
||||||
*/
|
|
||||||
public function testAddTagWithoutValue(): void
|
|
||||||
{
|
|
||||||
$parameters = ['id' => '123', 'tag' => '', 'action' => 'add'];
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$request
|
|
||||||
->method('getParam')
|
|
||||||
->willReturnCallback(function (string $key) use ($parameters): ?string {
|
|
||||||
return $parameters[$key] ?? null;
|
|
||||||
})
|
|
||||||
;
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
$this->container->sessionManager
|
|
||||||
->expects(static::once())
|
|
||||||
->method('setSessionParameter')
|
|
||||||
->with(SessionManager::KEY_ERROR_MESSAGES, ['Invalid tag name provided.'])
|
|
||||||
;
|
|
||||||
|
|
||||||
$result = $this->controller->addOrDeleteTags($request, $response);
|
|
||||||
|
|
||||||
static::assertSame(302, $result->getStatusCode());
|
|
||||||
static::assertSame(['/subfolder/'], $result->getHeader('location'));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test delete a tag without passing a tag string value.
|
|
||||||
*/
|
|
||||||
public function testDeleteTagWithoutValue(): void
|
|
||||||
{
|
|
||||||
$parameters = ['id' => '123', 'tag' => '', 'action' => 'delete'];
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$request
|
|
||||||
->method('getParam')
|
|
||||||
->willReturnCallback(function (string $key) use ($parameters): ?string {
|
|
||||||
return $parameters[$key] ?? null;
|
|
||||||
})
|
|
||||||
;
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
$this->container->sessionManager
|
|
||||||
->expects(static::once())
|
|
||||||
->method('setSessionParameter')
|
|
||||||
->with(SessionManager::KEY_ERROR_MESSAGES, ['Invalid tag name provided.'])
|
|
||||||
;
|
|
||||||
|
|
||||||
$result = $this->controller->addOrDeleteTags($request, $response);
|
|
||||||
|
|
||||||
static::assertSame(302, $result->getStatusCode());
|
|
||||||
static::assertSame(['/subfolder/'], $result->getHeader('location'));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,418 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace Shaarli\Front\Controller\Admin\ShaareManageControllerTest;
|
|
||||||
|
|
||||||
use Shaarli\Bookmark\Bookmark;
|
|
||||||
use Shaarli\Bookmark\Exception\BookmarkNotFoundException;
|
|
||||||
use Shaarli\Formatter\BookmarkFormatter;
|
|
||||||
use Shaarli\Formatter\BookmarkRawFormatter;
|
|
||||||
use Shaarli\Formatter\FormatterFactory;
|
|
||||||
use Shaarli\Front\Controller\Admin\FrontAdminControllerMockHelper;
|
|
||||||
use Shaarli\Front\Controller\Admin\ShaareManageController;
|
|
||||||
use Shaarli\Http\HttpAccess;
|
|
||||||
use Shaarli\Security\SessionManager;
|
|
||||||
use Shaarli\TestCase;
|
|
||||||
use Slim\Http\Request;
|
|
||||||
use Slim\Http\Response;
|
|
||||||
|
|
||||||
class ChangeVisibilityBookmarkTest extends TestCase
|
|
||||||
{
|
|
||||||
use FrontAdminControllerMockHelper;
|
|
||||||
|
|
||||||
/** @var ShaareManageController */
|
|
||||||
protected $controller;
|
|
||||||
|
|
||||||
public function setUp(): void
|
|
||||||
{
|
|
||||||
$this->createContainer();
|
|
||||||
|
|
||||||
$this->container->httpAccess = $this->createMock(HttpAccess::class);
|
|
||||||
$this->controller = new ShaareManageController($this->container);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Change bookmark visibility - Set private - Single public bookmark with valid parameters
|
|
||||||
*/
|
|
||||||
public function testSetSingleBookmarkPrivate(): void
|
|
||||||
{
|
|
||||||
$parameters = ['id' => '123', 'newVisibility' => 'private'];
|
|
||||||
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$request
|
|
||||||
->method('getParam')
|
|
||||||
->willReturnCallback(function (string $key) use ($parameters): ?string {
|
|
||||||
return $parameters[$key] ?? null;
|
|
||||||
})
|
|
||||||
;
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
$bookmark = (new Bookmark())->setId(123)->setUrl('http://domain.tld')->setTitle('Title 123')->setPrivate(false);
|
|
||||||
|
|
||||||
static::assertFalse($bookmark->isPrivate());
|
|
||||||
|
|
||||||
$this->container->bookmarkService->expects(static::once())->method('get')->with(123)->willReturn($bookmark);
|
|
||||||
$this->container->bookmarkService->expects(static::once())->method('set')->with($bookmark, false);
|
|
||||||
$this->container->bookmarkService->expects(static::once())->method('save');
|
|
||||||
$this->container->formatterFactory = $this->createMock(FormatterFactory::class);
|
|
||||||
$this->container->formatterFactory
|
|
||||||
->expects(static::once())
|
|
||||||
->method('getFormatter')
|
|
||||||
->with('raw')
|
|
||||||
->willReturnCallback(function () use ($bookmark): BookmarkFormatter {
|
|
||||||
return new BookmarkRawFormatter($this->container->conf, true);
|
|
||||||
})
|
|
||||||
;
|
|
||||||
|
|
||||||
// Make sure that PluginManager hook is triggered
|
|
||||||
$this->container->pluginManager
|
|
||||||
->expects(static::once())
|
|
||||||
->method('executeHooks')
|
|
||||||
->with('save_link')
|
|
||||||
;
|
|
||||||
|
|
||||||
$result = $this->controller->changeVisibility($request, $response);
|
|
||||||
|
|
||||||
static::assertTrue($bookmark->isPrivate());
|
|
||||||
|
|
||||||
static::assertSame(302, $result->getStatusCode());
|
|
||||||
static::assertSame(['/subfolder/'], $result->getHeader('location'));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Change bookmark visibility - Set public - Single private bookmark with valid parameters
|
|
||||||
*/
|
|
||||||
public function testSetSingleBookmarkPublic(): void
|
|
||||||
{
|
|
||||||
$parameters = ['id' => '123', 'newVisibility' => 'public'];
|
|
||||||
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$request
|
|
||||||
->method('getParam')
|
|
||||||
->willReturnCallback(function (string $key) use ($parameters): ?string {
|
|
||||||
return $parameters[$key] ?? null;
|
|
||||||
})
|
|
||||||
;
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
$bookmark = (new Bookmark())->setId(123)->setUrl('http://domain.tld')->setTitle('Title 123')->setPrivate(true);
|
|
||||||
|
|
||||||
static::assertTrue($bookmark->isPrivate());
|
|
||||||
|
|
||||||
$this->container->bookmarkService->expects(static::once())->method('get')->with(123)->willReturn($bookmark);
|
|
||||||
$this->container->bookmarkService->expects(static::once())->method('set')->with($bookmark, false);
|
|
||||||
$this->container->bookmarkService->expects(static::once())->method('save');
|
|
||||||
$this->container->formatterFactory = $this->createMock(FormatterFactory::class);
|
|
||||||
$this->container->formatterFactory
|
|
||||||
->expects(static::once())
|
|
||||||
->method('getFormatter')
|
|
||||||
->with('raw')
|
|
||||||
->willReturn(new BookmarkRawFormatter($this->container->conf, true))
|
|
||||||
;
|
|
||||||
|
|
||||||
// Make sure that PluginManager hook is triggered
|
|
||||||
$this->container->pluginManager
|
|
||||||
->expects(static::once())
|
|
||||||
->method('executeHooks')
|
|
||||||
->with('save_link')
|
|
||||||
;
|
|
||||||
|
|
||||||
$result = $this->controller->changeVisibility($request, $response);
|
|
||||||
|
|
||||||
static::assertFalse($bookmark->isPrivate());
|
|
||||||
|
|
||||||
static::assertSame(302, $result->getStatusCode());
|
|
||||||
static::assertSame(['/subfolder/'], $result->getHeader('location'));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Change bookmark visibility - Set private on single already private bookmark
|
|
||||||
*/
|
|
||||||
public function testSetSinglePrivateBookmarkPrivate(): void
|
|
||||||
{
|
|
||||||
$parameters = ['id' => '123', 'newVisibility' => 'private'];
|
|
||||||
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$request
|
|
||||||
->method('getParam')
|
|
||||||
->willReturnCallback(function (string $key) use ($parameters): ?string {
|
|
||||||
return $parameters[$key] ?? null;
|
|
||||||
})
|
|
||||||
;
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
$bookmark = (new Bookmark())->setId(123)->setUrl('http://domain.tld')->setTitle('Title 123')->setPrivate(true);
|
|
||||||
|
|
||||||
static::assertTrue($bookmark->isPrivate());
|
|
||||||
|
|
||||||
$this->container->bookmarkService->expects(static::once())->method('get')->with(123)->willReturn($bookmark);
|
|
||||||
$this->container->bookmarkService->expects(static::once())->method('set')->with($bookmark, false);
|
|
||||||
$this->container->bookmarkService->expects(static::once())->method('save');
|
|
||||||
$this->container->formatterFactory = $this->createMock(FormatterFactory::class);
|
|
||||||
$this->container->formatterFactory
|
|
||||||
->expects(static::once())
|
|
||||||
->method('getFormatter')
|
|
||||||
->with('raw')
|
|
||||||
->willReturn(new BookmarkRawFormatter($this->container->conf, true))
|
|
||||||
;
|
|
||||||
|
|
||||||
// Make sure that PluginManager hook is triggered
|
|
||||||
$this->container->pluginManager
|
|
||||||
->expects(static::once())
|
|
||||||
->method('executeHooks')
|
|
||||||
->with('save_link')
|
|
||||||
;
|
|
||||||
|
|
||||||
$result = $this->controller->changeVisibility($request, $response);
|
|
||||||
|
|
||||||
static::assertTrue($bookmark->isPrivate());
|
|
||||||
|
|
||||||
static::assertSame(302, $result->getStatusCode());
|
|
||||||
static::assertSame(['/subfolder/'], $result->getHeader('location'));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Change bookmark visibility - Set multiple bookmarks private
|
|
||||||
*/
|
|
||||||
public function testSetMultipleBookmarksPrivate(): void
|
|
||||||
{
|
|
||||||
$parameters = ['id' => '123 456 789', 'newVisibility' => 'private'];
|
|
||||||
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$request
|
|
||||||
->method('getParam')
|
|
||||||
->willReturnCallback(function (string $key) use ($parameters): ?string {
|
|
||||||
return $parameters[$key] ?? null;
|
|
||||||
})
|
|
||||||
;
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
$bookmarks = [
|
|
||||||
(new Bookmark())->setId(123)->setUrl('http://domain.tld')->setTitle('Title 123')->setPrivate(false),
|
|
||||||
(new Bookmark())->setId(456)->setUrl('http://domain.tld')->setTitle('Title 456')->setPrivate(true),
|
|
||||||
(new Bookmark())->setId(789)->setUrl('http://domain.tld')->setTitle('Title 789')->setPrivate(false),
|
|
||||||
];
|
|
||||||
|
|
||||||
$this->container->bookmarkService
|
|
||||||
->expects(static::exactly(3))
|
|
||||||
->method('get')
|
|
||||||
->withConsecutive([123], [456], [789])
|
|
||||||
->willReturnOnConsecutiveCalls(...$bookmarks)
|
|
||||||
;
|
|
||||||
$this->container->bookmarkService
|
|
||||||
->expects(static::exactly(3))
|
|
||||||
->method('set')
|
|
||||||
->withConsecutive(...array_map(function (Bookmark $bookmark): array {
|
|
||||||
return [$bookmark, false];
|
|
||||||
}, $bookmarks))
|
|
||||||
;
|
|
||||||
$this->container->bookmarkService->expects(static::once())->method('save');
|
|
||||||
$this->container->formatterFactory = $this->createMock(FormatterFactory::class);
|
|
||||||
$this->container->formatterFactory
|
|
||||||
->expects(static::once())
|
|
||||||
->method('getFormatter')
|
|
||||||
->with('raw')
|
|
||||||
->willReturn(new BookmarkRawFormatter($this->container->conf, true))
|
|
||||||
;
|
|
||||||
|
|
||||||
// Make sure that PluginManager hook is triggered
|
|
||||||
$this->container->pluginManager
|
|
||||||
->expects(static::exactly(3))
|
|
||||||
->method('executeHooks')
|
|
||||||
->with('save_link')
|
|
||||||
;
|
|
||||||
|
|
||||||
$result = $this->controller->changeVisibility($request, $response);
|
|
||||||
|
|
||||||
static::assertTrue($bookmarks[0]->isPrivate());
|
|
||||||
static::assertTrue($bookmarks[1]->isPrivate());
|
|
||||||
static::assertTrue($bookmarks[2]->isPrivate());
|
|
||||||
|
|
||||||
static::assertSame(302, $result->getStatusCode());
|
|
||||||
static::assertSame(['/subfolder/'], $result->getHeader('location'));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Change bookmark visibility - Single bookmark not found.
|
|
||||||
*/
|
|
||||||
public function testChangeVisibilitySingleBookmarkNotFound(): void
|
|
||||||
{
|
|
||||||
$parameters = ['id' => '123', 'newVisibility' => 'private'];
|
|
||||||
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$request
|
|
||||||
->method('getParam')
|
|
||||||
->willReturnCallback(function (string $key) use ($parameters): ?string {
|
|
||||||
return $parameters[$key] ?? null;
|
|
||||||
})
|
|
||||||
;
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
$this->container->bookmarkService
|
|
||||||
->expects(static::once())
|
|
||||||
->method('get')
|
|
||||||
->willThrowException(new BookmarkNotFoundException())
|
|
||||||
;
|
|
||||||
$this->container->bookmarkService->expects(static::never())->method('set');
|
|
||||||
$this->container->bookmarkService->expects(static::never())->method('save');
|
|
||||||
$this->container->formatterFactory = $this->createMock(FormatterFactory::class);
|
|
||||||
$this->container->formatterFactory
|
|
||||||
->expects(static::once())
|
|
||||||
->method('getFormatter')
|
|
||||||
->with('raw')
|
|
||||||
->willReturn(new BookmarkRawFormatter($this->container->conf, true))
|
|
||||||
;
|
|
||||||
|
|
||||||
// Make sure that PluginManager hook is not triggered
|
|
||||||
$this->container->pluginManager
|
|
||||||
->expects(static::never())
|
|
||||||
->method('executeHooks')
|
|
||||||
->with('save_link')
|
|
||||||
;
|
|
||||||
|
|
||||||
$result = $this->controller->changeVisibility($request, $response);
|
|
||||||
|
|
||||||
static::assertSame(302, $result->getStatusCode());
|
|
||||||
static::assertSame(['/subfolder/'], $result->getHeader('location'));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Change bookmark visibility - Multiple bookmarks with one not found.
|
|
||||||
*/
|
|
||||||
public function testChangeVisibilityMultipleBookmarksOneNotFound(): void
|
|
||||||
{
|
|
||||||
$parameters = ['id' => '123 456 789', 'newVisibility' => 'public'];
|
|
||||||
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$request
|
|
||||||
->method('getParam')
|
|
||||||
->willReturnCallback(function (string $key) use ($parameters): ?string {
|
|
||||||
return $parameters[$key] ?? null;
|
|
||||||
})
|
|
||||||
;
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
$bookmarks = [
|
|
||||||
(new Bookmark())->setId(123)->setUrl('http://domain.tld')->setTitle('Title 123')->setPrivate(true),
|
|
||||||
(new Bookmark())->setId(789)->setUrl('http://domain.tld')->setTitle('Title 789')->setPrivate(false),
|
|
||||||
];
|
|
||||||
|
|
||||||
$this->container->bookmarkService
|
|
||||||
->expects(static::exactly(3))
|
|
||||||
->method('get')
|
|
||||||
->withConsecutive([123], [456], [789])
|
|
||||||
->willReturnCallback(function (int $id) use ($bookmarks): Bookmark {
|
|
||||||
if ($id === 123) {
|
|
||||||
return $bookmarks[0];
|
|
||||||
}
|
|
||||||
if ($id === 789) {
|
|
||||||
return $bookmarks[1];
|
|
||||||
}
|
|
||||||
throw new BookmarkNotFoundException();
|
|
||||||
})
|
|
||||||
;
|
|
||||||
$this->container->bookmarkService
|
|
||||||
->expects(static::exactly(2))
|
|
||||||
->method('set')
|
|
||||||
->withConsecutive(...array_map(function (Bookmark $bookmark): array {
|
|
||||||
return [$bookmark, false];
|
|
||||||
}, $bookmarks))
|
|
||||||
;
|
|
||||||
$this->container->bookmarkService->expects(static::once())->method('save');
|
|
||||||
|
|
||||||
// Make sure that PluginManager hook is not triggered
|
|
||||||
$this->container->pluginManager
|
|
||||||
->expects(static::exactly(2))
|
|
||||||
->method('executeHooks')
|
|
||||||
->with('save_link')
|
|
||||||
;
|
|
||||||
|
|
||||||
$this->container->sessionManager
|
|
||||||
->expects(static::once())
|
|
||||||
->method('setSessionParameter')
|
|
||||||
->with(SessionManager::KEY_ERROR_MESSAGES, ['Bookmark with identifier 456 could not be found.'])
|
|
||||||
;
|
|
||||||
|
|
||||||
$result = $this->controller->changeVisibility($request, $response);
|
|
||||||
|
|
||||||
static::assertSame(302, $result->getStatusCode());
|
|
||||||
static::assertSame(['/subfolder/'], $result->getHeader('location'));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Change bookmark visibility - Invalid ID
|
|
||||||
*/
|
|
||||||
public function testChangeVisibilityInvalidId(): void
|
|
||||||
{
|
|
||||||
$parameters = ['id' => 'nope not an ID', 'newVisibility' => 'private'];
|
|
||||||
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$request
|
|
||||||
->method('getParam')
|
|
||||||
->willReturnCallback(function (string $key) use ($parameters): ?string {
|
|
||||||
return $parameters[$key] ?? null;
|
|
||||||
})
|
|
||||||
;
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
$this->container->sessionManager
|
|
||||||
->expects(static::once())
|
|
||||||
->method('setSessionParameter')
|
|
||||||
->with(SessionManager::KEY_ERROR_MESSAGES, ['Invalid bookmark ID provided.'])
|
|
||||||
;
|
|
||||||
|
|
||||||
$result = $this->controller->changeVisibility($request, $response);
|
|
||||||
|
|
||||||
static::assertSame(302, $result->getStatusCode());
|
|
||||||
static::assertSame(['/subfolder/'], $result->getHeader('location'));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Change bookmark visibility - Empty ID
|
|
||||||
*/
|
|
||||||
public function testChangeVisibilityEmptyId(): void
|
|
||||||
{
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
$this->container->sessionManager
|
|
||||||
->expects(static::once())
|
|
||||||
->method('setSessionParameter')
|
|
||||||
->with(SessionManager::KEY_ERROR_MESSAGES, ['Invalid bookmark ID provided.'])
|
|
||||||
;
|
|
||||||
|
|
||||||
$result = $this->controller->changeVisibility($request, $response);
|
|
||||||
|
|
||||||
static::assertSame(302, $result->getStatusCode());
|
|
||||||
static::assertSame(['/subfolder/'], $result->getHeader('location'));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Change bookmark visibility - with invalid visibility
|
|
||||||
*/
|
|
||||||
public function testChangeVisibilityWithInvalidVisibility(): void
|
|
||||||
{
|
|
||||||
$parameters = ['id' => '123', 'newVisibility' => 'invalid'];
|
|
||||||
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$request
|
|
||||||
->method('getParam')
|
|
||||||
->willReturnCallback(function (string $key) use ($parameters): ?string {
|
|
||||||
return $parameters[$key] ?? null;
|
|
||||||
})
|
|
||||||
;
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
$this->container->sessionManager
|
|
||||||
->expects(static::once())
|
|
||||||
->method('setSessionParameter')
|
|
||||||
->with(SessionManager::KEY_ERROR_MESSAGES, ['Invalid visibility provided.'])
|
|
||||||
;
|
|
||||||
|
|
||||||
$result = $this->controller->changeVisibility($request, $response);
|
|
||||||
|
|
||||||
static::assertSame(302, $result->getStatusCode());
|
|
||||||
static::assertSame(['/subfolder/'], $result->getHeader('location'));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,427 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace Shaarli\Front\Controller\Admin\ShaareManageControllerTest;
|
|
||||||
|
|
||||||
use Shaarli\Bookmark\Bookmark;
|
|
||||||
use Shaarli\Bookmark\Exception\BookmarkNotFoundException;
|
|
||||||
use Shaarli\Formatter\BookmarkFormatter;
|
|
||||||
use Shaarli\Formatter\FormatterFactory;
|
|
||||||
use Shaarli\Front\Controller\Admin\FrontAdminControllerMockHelper;
|
|
||||||
use Shaarli\Front\Controller\Admin\ShaareManageController;
|
|
||||||
use Shaarli\Http\HttpAccess;
|
|
||||||
use Shaarli\Security\SessionManager;
|
|
||||||
use Shaarli\TestCase;
|
|
||||||
use Slim\Http\Request;
|
|
||||||
use Slim\Http\Response;
|
|
||||||
|
|
||||||
class DeleteBookmarkTest extends TestCase
|
|
||||||
{
|
|
||||||
use FrontAdminControllerMockHelper;
|
|
||||||
|
|
||||||
/** @var ShaareManageController */
|
|
||||||
protected $controller;
|
|
||||||
|
|
||||||
public function setUp(): void
|
|
||||||
{
|
|
||||||
$this->createContainer();
|
|
||||||
|
|
||||||
$this->container->httpAccess = $this->createMock(HttpAccess::class);
|
|
||||||
$this->controller = new ShaareManageController($this->container);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Delete bookmark - Single bookmark with valid parameters
|
|
||||||
*/
|
|
||||||
public function testDeleteSingleBookmark(): void
|
|
||||||
{
|
|
||||||
$parameters = ['id' => '123'];
|
|
||||||
|
|
||||||
$this->container->environment['HTTP_REFERER'] = 'http://shaarli/subfolder/shaare/abcdef';
|
|
||||||
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$request
|
|
||||||
->method('getParam')
|
|
||||||
->willReturnCallback(function (string $key) use ($parameters): ?string {
|
|
||||||
return $parameters[$key] ?? null;
|
|
||||||
})
|
|
||||||
;
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
$bookmark = (new Bookmark())->setId(123)->setUrl('http://domain.tld')->setTitle('Title 123');
|
|
||||||
|
|
||||||
$this->container->bookmarkService->expects(static::once())->method('get')->with(123)->willReturn($bookmark);
|
|
||||||
$this->container->bookmarkService->expects(static::once())->method('remove')->with($bookmark, false);
|
|
||||||
$this->container->bookmarkService->expects(static::once())->method('save');
|
|
||||||
$this->container->formatterFactory = $this->createMock(FormatterFactory::class);
|
|
||||||
$this->container->formatterFactory
|
|
||||||
->expects(static::once())
|
|
||||||
->method('getFormatter')
|
|
||||||
->with('raw')
|
|
||||||
->willReturnCallback(function () use ($bookmark): BookmarkFormatter {
|
|
||||||
$formatter = $this->createMock(BookmarkFormatter::class);
|
|
||||||
$formatter
|
|
||||||
->expects(static::once())
|
|
||||||
->method('format')
|
|
||||||
->with($bookmark)
|
|
||||||
->willReturn(['formatted' => $bookmark])
|
|
||||||
;
|
|
||||||
|
|
||||||
return $formatter;
|
|
||||||
})
|
|
||||||
;
|
|
||||||
|
|
||||||
// Make sure that PluginManager hook is triggered
|
|
||||||
$this->container->pluginManager
|
|
||||||
->expects(static::once())
|
|
||||||
->method('executeHooks')
|
|
||||||
->with('delete_link', ['formatted' => $bookmark])
|
|
||||||
;
|
|
||||||
|
|
||||||
$result = $this->controller->deleteBookmark($request, $response);
|
|
||||||
|
|
||||||
static::assertSame(302, $result->getStatusCode());
|
|
||||||
static::assertSame(['/subfolder/'], $result->getHeader('location'));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Delete bookmark - Multiple bookmarks with valid parameters
|
|
||||||
*/
|
|
||||||
public function testDeleteMultipleBookmarks(): void
|
|
||||||
{
|
|
||||||
$parameters = ['id' => '123 456 789'];
|
|
||||||
|
|
||||||
$this->container->environment['HTTP_REFERER'] = 'http://shaarli/subfolder/?searchtags=abcdef';
|
|
||||||
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$request
|
|
||||||
->method('getParam')
|
|
||||||
->willReturnCallback(function (string $key) use ($parameters): ?string {
|
|
||||||
return $parameters[$key] ?? null;
|
|
||||||
})
|
|
||||||
;
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
$bookmarks = [
|
|
||||||
(new Bookmark())->setId(123)->setUrl('http://domain.tld')->setTitle('Title 123'),
|
|
||||||
(new Bookmark())->setId(456)->setUrl('http://domain.tld')->setTitle('Title 456'),
|
|
||||||
(new Bookmark())->setId(789)->setUrl('http://domain.tld')->setTitle('Title 789'),
|
|
||||||
];
|
|
||||||
|
|
||||||
$this->container->bookmarkService
|
|
||||||
->expects(static::exactly(3))
|
|
||||||
->method('get')
|
|
||||||
->withConsecutive([123], [456], [789])
|
|
||||||
->willReturnOnConsecutiveCalls(...$bookmarks)
|
|
||||||
;
|
|
||||||
$this->container->bookmarkService
|
|
||||||
->expects(static::exactly(3))
|
|
||||||
->method('remove')
|
|
||||||
->withConsecutive(...array_map(function (Bookmark $bookmark): array {
|
|
||||||
return [$bookmark, false];
|
|
||||||
}, $bookmarks))
|
|
||||||
;
|
|
||||||
$this->container->bookmarkService->expects(static::once())->method('save');
|
|
||||||
$this->container->formatterFactory = $this->createMock(FormatterFactory::class);
|
|
||||||
$this->container->formatterFactory
|
|
||||||
->expects(static::once())
|
|
||||||
->method('getFormatter')
|
|
||||||
->with('raw')
|
|
||||||
->willReturnCallback(function () use ($bookmarks): BookmarkFormatter {
|
|
||||||
$formatter = $this->createMock(BookmarkFormatter::class);
|
|
||||||
|
|
||||||
$formatter
|
|
||||||
->expects(static::exactly(3))
|
|
||||||
->method('format')
|
|
||||||
->withConsecutive(...array_map(function (Bookmark $bookmark): array {
|
|
||||||
return [$bookmark];
|
|
||||||
}, $bookmarks))
|
|
||||||
->willReturnOnConsecutiveCalls(...array_map(function (Bookmark $bookmark): array {
|
|
||||||
return ['formatted' => $bookmark];
|
|
||||||
}, $bookmarks))
|
|
||||||
;
|
|
||||||
|
|
||||||
return $formatter;
|
|
||||||
})
|
|
||||||
;
|
|
||||||
|
|
||||||
// Make sure that PluginManager hook is triggered
|
|
||||||
$this->container->pluginManager
|
|
||||||
->expects(static::exactly(3))
|
|
||||||
->method('executeHooks')
|
|
||||||
->with('delete_link')
|
|
||||||
;
|
|
||||||
|
|
||||||
$result = $this->controller->deleteBookmark($request, $response);
|
|
||||||
|
|
||||||
static::assertSame(302, $result->getStatusCode());
|
|
||||||
static::assertSame(['/subfolder/?searchtags=abcdef'], $result->getHeader('location'));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Delete bookmark - Single bookmark not found in the data store
|
|
||||||
*/
|
|
||||||
public function testDeleteSingleBookmarkNotFound(): void
|
|
||||||
{
|
|
||||||
$parameters = ['id' => '123'];
|
|
||||||
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$request
|
|
||||||
->method('getParam')
|
|
||||||
->willReturnCallback(function (string $key) use ($parameters): ?string {
|
|
||||||
return $parameters[$key] ?? null;
|
|
||||||
})
|
|
||||||
;
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
$this->container->bookmarkService
|
|
||||||
->expects(static::once())
|
|
||||||
->method('get')
|
|
||||||
->willThrowException(new BookmarkNotFoundException())
|
|
||||||
;
|
|
||||||
$this->container->bookmarkService->expects(static::never())->method('remove');
|
|
||||||
$this->container->bookmarkService->expects(static::never())->method('save');
|
|
||||||
$this->container->formatterFactory = $this->createMock(FormatterFactory::class);
|
|
||||||
$this->container->formatterFactory
|
|
||||||
->expects(static::once())
|
|
||||||
->method('getFormatter')
|
|
||||||
->with('raw')
|
|
||||||
->willReturnCallback(function (): BookmarkFormatter {
|
|
||||||
$formatter = $this->createMock(BookmarkFormatter::class);
|
|
||||||
|
|
||||||
$formatter->expects(static::never())->method('format');
|
|
||||||
|
|
||||||
return $formatter;
|
|
||||||
})
|
|
||||||
;
|
|
||||||
// Make sure that PluginManager hook is not triggered
|
|
||||||
$this->container->pluginManager
|
|
||||||
->expects(static::never())
|
|
||||||
->method('executeHooks')
|
|
||||||
->with('delete_link')
|
|
||||||
;
|
|
||||||
|
|
||||||
$result = $this->controller->deleteBookmark($request, $response);
|
|
||||||
|
|
||||||
static::assertSame(302, $result->getStatusCode());
|
|
||||||
static::assertSame(['/subfolder/'], $result->getHeader('location'));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Delete bookmark - Multiple bookmarks with one not found in the data store
|
|
||||||
*/
|
|
||||||
public function testDeleteMultipleBookmarksOneNotFound(): void
|
|
||||||
{
|
|
||||||
$parameters = ['id' => '123 456 789'];
|
|
||||||
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$request
|
|
||||||
->method('getParam')
|
|
||||||
->willReturnCallback(function (string $key) use ($parameters): ?string {
|
|
||||||
return $parameters[$key] ?? null;
|
|
||||||
})
|
|
||||||
;
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
$bookmarks = [
|
|
||||||
(new Bookmark())->setId(123)->setUrl('http://domain.tld')->setTitle('Title 123'),
|
|
||||||
(new Bookmark())->setId(789)->setUrl('http://domain.tld')->setTitle('Title 789'),
|
|
||||||
];
|
|
||||||
|
|
||||||
$this->container->bookmarkService
|
|
||||||
->expects(static::exactly(3))
|
|
||||||
->method('get')
|
|
||||||
->withConsecutive([123], [456], [789])
|
|
||||||
->willReturnCallback(function (int $id) use ($bookmarks): Bookmark {
|
|
||||||
if ($id === 123) {
|
|
||||||
return $bookmarks[0];
|
|
||||||
}
|
|
||||||
if ($id === 789) {
|
|
||||||
return $bookmarks[1];
|
|
||||||
}
|
|
||||||
throw new BookmarkNotFoundException();
|
|
||||||
})
|
|
||||||
;
|
|
||||||
$this->container->bookmarkService
|
|
||||||
->expects(static::exactly(2))
|
|
||||||
->method('remove')
|
|
||||||
->withConsecutive(...array_map(function (Bookmark $bookmark): array {
|
|
||||||
return [$bookmark, false];
|
|
||||||
}, $bookmarks))
|
|
||||||
;
|
|
||||||
$this->container->bookmarkService->expects(static::once())->method('save');
|
|
||||||
$this->container->formatterFactory = $this->createMock(FormatterFactory::class);
|
|
||||||
$this->container->formatterFactory
|
|
||||||
->expects(static::once())
|
|
||||||
->method('getFormatter')
|
|
||||||
->with('raw')
|
|
||||||
->willReturnCallback(function () use ($bookmarks): BookmarkFormatter {
|
|
||||||
$formatter = $this->createMock(BookmarkFormatter::class);
|
|
||||||
|
|
||||||
$formatter
|
|
||||||
->expects(static::exactly(2))
|
|
||||||
->method('format')
|
|
||||||
->withConsecutive(...array_map(function (Bookmark $bookmark): array {
|
|
||||||
return [$bookmark];
|
|
||||||
}, $bookmarks))
|
|
||||||
->willReturnOnConsecutiveCalls(...array_map(function (Bookmark $bookmark): array {
|
|
||||||
return ['formatted' => $bookmark];
|
|
||||||
}, $bookmarks))
|
|
||||||
;
|
|
||||||
|
|
||||||
return $formatter;
|
|
||||||
})
|
|
||||||
;
|
|
||||||
|
|
||||||
// Make sure that PluginManager hook is not triggered
|
|
||||||
$this->container->pluginManager
|
|
||||||
->expects(static::exactly(2))
|
|
||||||
->method('executeHooks')
|
|
||||||
->with('delete_link')
|
|
||||||
;
|
|
||||||
|
|
||||||
$this->container->sessionManager
|
|
||||||
->expects(static::once())
|
|
||||||
->method('setSessionParameter')
|
|
||||||
->with(SessionManager::KEY_ERROR_MESSAGES, ['Bookmark with identifier 456 could not be found.'])
|
|
||||||
;
|
|
||||||
|
|
||||||
$result = $this->controller->deleteBookmark($request, $response);
|
|
||||||
|
|
||||||
static::assertSame(302, $result->getStatusCode());
|
|
||||||
static::assertSame(['/subfolder/'], $result->getHeader('location'));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Delete bookmark - Invalid ID
|
|
||||||
*/
|
|
||||||
public function testDeleteInvalidId(): void
|
|
||||||
{
|
|
||||||
$parameters = ['id' => 'nope not an ID'];
|
|
||||||
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$request
|
|
||||||
->method('getParam')
|
|
||||||
->willReturnCallback(function (string $key) use ($parameters): ?string {
|
|
||||||
return $parameters[$key] ?? null;
|
|
||||||
})
|
|
||||||
;
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
$this->container->sessionManager
|
|
||||||
->expects(static::once())
|
|
||||||
->method('setSessionParameter')
|
|
||||||
->with(SessionManager::KEY_ERROR_MESSAGES, ['Invalid bookmark ID provided.'])
|
|
||||||
;
|
|
||||||
|
|
||||||
$result = $this->controller->deleteBookmark($request, $response);
|
|
||||||
|
|
||||||
static::assertSame(302, $result->getStatusCode());
|
|
||||||
static::assertSame(['/subfolder/'], $result->getHeader('location'));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Delete bookmark - Empty ID
|
|
||||||
*/
|
|
||||||
public function testDeleteEmptyId(): void
|
|
||||||
{
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
$this->container->sessionManager
|
|
||||||
->expects(static::once())
|
|
||||||
->method('setSessionParameter')
|
|
||||||
->with(SessionManager::KEY_ERROR_MESSAGES, ['Invalid bookmark ID provided.'])
|
|
||||||
;
|
|
||||||
|
|
||||||
$result = $this->controller->deleteBookmark($request, $response);
|
|
||||||
|
|
||||||
static::assertSame(302, $result->getStatusCode());
|
|
||||||
static::assertSame(['/subfolder/'], $result->getHeader('location'));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Delete bookmark - from bookmarklet
|
|
||||||
*/
|
|
||||||
public function testDeleteBookmarkFromBookmarklet(): void
|
|
||||||
{
|
|
||||||
$parameters = [
|
|
||||||
'id' => '123',
|
|
||||||
'source' => 'bookmarklet',
|
|
||||||
];
|
|
||||||
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$request
|
|
||||||
->method('getParam')
|
|
||||||
->willReturnCallback(function (string $key) use ($parameters): ?string {
|
|
||||||
return $parameters[$key] ?? null;
|
|
||||||
})
|
|
||||||
;
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
$this->container->bookmarkService->method('get')->with('123')->willReturn(
|
|
||||||
(new Bookmark())->setId(123)->setUrl('http://domain.tld')->setTitle('Title 123')
|
|
||||||
);
|
|
||||||
$this->container->bookmarkService->expects(static::once())->method('remove');
|
|
||||||
|
|
||||||
$this->container->formatterFactory = $this->createMock(FormatterFactory::class);
|
|
||||||
$this->container->formatterFactory
|
|
||||||
->expects(static::once())
|
|
||||||
->method('getFormatter')
|
|
||||||
->willReturnCallback(function (): BookmarkFormatter {
|
|
||||||
$formatter = $this->createMock(BookmarkFormatter::class);
|
|
||||||
$formatter->method('format')->willReturn(['formatted']);
|
|
||||||
|
|
||||||
return $formatter;
|
|
||||||
})
|
|
||||||
;
|
|
||||||
|
|
||||||
$result = $this->controller->deleteBookmark($request, $response);
|
|
||||||
|
|
||||||
static::assertSame(200, $result->getStatusCode());
|
|
||||||
static::assertSame('<script>self.close();</script>', (string) $result->getBody());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Delete bookmark - from batch view
|
|
||||||
*/
|
|
||||||
public function testDeleteBookmarkFromBatch(): void
|
|
||||||
{
|
|
||||||
$parameters = [
|
|
||||||
'id' => '123',
|
|
||||||
'source' => 'batch',
|
|
||||||
];
|
|
||||||
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$request
|
|
||||||
->method('getParam')
|
|
||||||
->willReturnCallback(function (string $key) use ($parameters): ?string {
|
|
||||||
return $parameters[$key] ?? null;
|
|
||||||
})
|
|
||||||
;
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
$this->container->bookmarkService->method('get')->with('123')->willReturn(
|
|
||||||
(new Bookmark())->setId(123)->setUrl('http://domain.tld')->setTitle('Title 123')
|
|
||||||
);
|
|
||||||
$this->container->bookmarkService->expects(static::once())->method('remove');
|
|
||||||
|
|
||||||
$this->container->formatterFactory = $this->createMock(FormatterFactory::class);
|
|
||||||
$this->container->formatterFactory
|
|
||||||
->expects(static::once())
|
|
||||||
->method('getFormatter')
|
|
||||||
->willReturnCallback(function (): BookmarkFormatter {
|
|
||||||
$formatter = $this->createMock(BookmarkFormatter::class);
|
|
||||||
$formatter->method('format')->willReturn(['formatted']);
|
|
||||||
|
|
||||||
return $formatter;
|
|
||||||
})
|
|
||||||
;
|
|
||||||
|
|
||||||
$result = $this->controller->deleteBookmark($request, $response);
|
|
||||||
|
|
||||||
static::assertSame(204, $result->getStatusCode());
|
|
||||||
static::assertEmpty((string) $result->getBody());
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,145 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace Shaarli\Front\Controller\Admin\ShaareManageControllerTest;
|
|
||||||
|
|
||||||
use Shaarli\Bookmark\Bookmark;
|
|
||||||
use Shaarli\Bookmark\Exception\BookmarkNotFoundException;
|
|
||||||
use Shaarli\Front\Controller\Admin\FrontAdminControllerMockHelper;
|
|
||||||
use Shaarli\Front\Controller\Admin\ShaareManageController;
|
|
||||||
use Shaarli\Http\HttpAccess;
|
|
||||||
use Shaarli\Security\SessionManager;
|
|
||||||
use Shaarli\TestCase;
|
|
||||||
use Slim\Http\Request;
|
|
||||||
use Slim\Http\Response;
|
|
||||||
|
|
||||||
class PinBookmarkTest extends TestCase
|
|
||||||
{
|
|
||||||
use FrontAdminControllerMockHelper;
|
|
||||||
|
|
||||||
/** @var ShaareManageController */
|
|
||||||
protected $controller;
|
|
||||||
|
|
||||||
public function setUp(): void
|
|
||||||
{
|
|
||||||
$this->createContainer();
|
|
||||||
|
|
||||||
$this->container->httpAccess = $this->createMock(HttpAccess::class);
|
|
||||||
$this->controller = new ShaareManageController($this->container);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test pin bookmark - with valid input
|
|
||||||
*
|
|
||||||
* @dataProvider initialStickyValuesProvider()
|
|
||||||
*/
|
|
||||||
public function testPinBookmarkIsStickyNull(?bool $sticky, bool $expectedValue): void
|
|
||||||
{
|
|
||||||
$id = 123;
|
|
||||||
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
$bookmark = (new Bookmark())
|
|
||||||
->setId(123)
|
|
||||||
->setUrl('http://domain.tld')
|
|
||||||
->setTitle('Title 123')
|
|
||||||
->setSticky($sticky)
|
|
||||||
;
|
|
||||||
|
|
||||||
$this->container->bookmarkService->expects(static::once())->method('get')->with(123)->willReturn($bookmark);
|
|
||||||
$this->container->bookmarkService->expects(static::once())->method('set')->with($bookmark, true);
|
|
||||||
|
|
||||||
// Make sure that PluginManager hook is triggered
|
|
||||||
$this->container->pluginManager
|
|
||||||
->expects(static::once())
|
|
||||||
->method('executeHooks')
|
|
||||||
->with('save_link')
|
|
||||||
;
|
|
||||||
|
|
||||||
$result = $this->controller->pinBookmark($request, $response, ['id' => (string) $id]);
|
|
||||||
|
|
||||||
static::assertSame(302, $result->getStatusCode());
|
|
||||||
static::assertSame(['/subfolder/'], $result->getHeader('location'));
|
|
||||||
|
|
||||||
static::assertSame($expectedValue, $bookmark->isSticky());
|
|
||||||
}
|
|
||||||
|
|
||||||
public function initialStickyValuesProvider(): array
|
|
||||||
{
|
|
||||||
// [initialStickyState, isStickyAfterPin]
|
|
||||||
return [[null, true], [false, true], [true, false]];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test pin bookmark - invalid bookmark ID
|
|
||||||
*/
|
|
||||||
public function testDisplayEditFormInvalidId(): void
|
|
||||||
{
|
|
||||||
$id = 'invalid';
|
|
||||||
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
$this->container->sessionManager
|
|
||||||
->expects(static::once())
|
|
||||||
->method('setSessionParameter')
|
|
||||||
->with(SessionManager::KEY_ERROR_MESSAGES, ['Bookmark with identifier invalid could not be found.'])
|
|
||||||
;
|
|
||||||
|
|
||||||
$result = $this->controller->pinBookmark($request, $response, ['id' => $id]);
|
|
||||||
|
|
||||||
static::assertSame(302, $result->getStatusCode());
|
|
||||||
static::assertSame(['/subfolder/'], $result->getHeader('location'));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test pin bookmark - Bookmark ID not provided
|
|
||||||
*/
|
|
||||||
public function testDisplayEditFormIdNotProvided(): void
|
|
||||||
{
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
$this->container->sessionManager
|
|
||||||
->expects(static::once())
|
|
||||||
->method('setSessionParameter')
|
|
||||||
->with(SessionManager::KEY_ERROR_MESSAGES, ['Bookmark with identifier could not be found.'])
|
|
||||||
;
|
|
||||||
|
|
||||||
$result = $this->controller->pinBookmark($request, $response, []);
|
|
||||||
|
|
||||||
static::assertSame(302, $result->getStatusCode());
|
|
||||||
static::assertSame(['/subfolder/'], $result->getHeader('location'));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test pin bookmark - bookmark not found
|
|
||||||
*/
|
|
||||||
public function testDisplayEditFormBookmarkNotFound(): void
|
|
||||||
{
|
|
||||||
$id = 123;
|
|
||||||
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
$this->container->bookmarkService
|
|
||||||
->expects(static::once())
|
|
||||||
->method('get')
|
|
||||||
->with($id)
|
|
||||||
->willThrowException(new BookmarkNotFoundException())
|
|
||||||
;
|
|
||||||
|
|
||||||
$this->container->sessionManager
|
|
||||||
->expects(static::once())
|
|
||||||
->method('setSessionParameter')
|
|
||||||
->with(SessionManager::KEY_ERROR_MESSAGES, ['Bookmark with identifier 123 could not be found.'])
|
|
||||||
;
|
|
||||||
|
|
||||||
$result = $this->controller->pinBookmark($request, $response, ['id' => (string) $id]);
|
|
||||||
|
|
||||||
static::assertSame(302, $result->getStatusCode());
|
|
||||||
static::assertSame(['/subfolder/'], $result->getHeader('location'));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,139 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace Shaarli\Front\Controller\Admin\ShaareManageControllerTest;
|
|
||||||
|
|
||||||
use Shaarli\Bookmark\Bookmark;
|
|
||||||
use Shaarli\Front\Controller\Admin\FrontAdminControllerMockHelper;
|
|
||||||
use Shaarli\Front\Controller\Admin\ShaareManageController;
|
|
||||||
use Shaarli\Http\HttpAccess;
|
|
||||||
use Shaarli\TestCase;
|
|
||||||
use Slim\Http\Request;
|
|
||||||
use Slim\Http\Response;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test GET /admin/shaare/private/{hash}
|
|
||||||
*/
|
|
||||||
class SharePrivateTest extends TestCase
|
|
||||||
{
|
|
||||||
use FrontAdminControllerMockHelper;
|
|
||||||
|
|
||||||
/** @var ShaareManageController */
|
|
||||||
protected $controller;
|
|
||||||
|
|
||||||
public function setUp(): void
|
|
||||||
{
|
|
||||||
$this->createContainer();
|
|
||||||
|
|
||||||
$this->container->httpAccess = $this->createMock(HttpAccess::class);
|
|
||||||
$this->controller = new ShaareManageController($this->container);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test shaare private with a private bookmark which does not have a key yet.
|
|
||||||
*/
|
|
||||||
public function testSharePrivateWithNewPrivateBookmark(): void
|
|
||||||
{
|
|
||||||
$hash = 'abcdcef';
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
$bookmark = (new Bookmark())
|
|
||||||
->setId(123)
|
|
||||||
->setUrl('http://domain.tld')
|
|
||||||
->setTitle('Title 123')
|
|
||||||
->setPrivate(true)
|
|
||||||
;
|
|
||||||
|
|
||||||
$this->container->bookmarkService
|
|
||||||
->expects(static::once())
|
|
||||||
->method('findByHash')
|
|
||||||
->with($hash)
|
|
||||||
->willReturn($bookmark)
|
|
||||||
;
|
|
||||||
$this->container->bookmarkService
|
|
||||||
->expects(static::once())
|
|
||||||
->method('set')
|
|
||||||
->with($bookmark, true)
|
|
||||||
->willReturnCallback(function (Bookmark $bookmark): Bookmark {
|
|
||||||
static::assertSame(32, strlen($bookmark->getAdditionalContentEntry('private_key')));
|
|
||||||
|
|
||||||
return $bookmark;
|
|
||||||
})
|
|
||||||
;
|
|
||||||
|
|
||||||
$result = $this->controller->sharePrivate($request, $response, ['hash' => $hash]);
|
|
||||||
|
|
||||||
static::assertSame(302, $result->getStatusCode());
|
|
||||||
static::assertRegExp('#/subfolder/shaare/' . $hash . '\?key=\w{32}#', $result->getHeaderLine('Location'));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test shaare private with a private bookmark which does already have a key.
|
|
||||||
*/
|
|
||||||
public function testSharePrivateWithExistingPrivateBookmark(): void
|
|
||||||
{
|
|
||||||
$hash = 'abcdcef';
|
|
||||||
$existingKey = 'this is a private key';
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
$bookmark = (new Bookmark())
|
|
||||||
->setId(123)
|
|
||||||
->setUrl('http://domain.tld')
|
|
||||||
->setTitle('Title 123')
|
|
||||||
->setPrivate(true)
|
|
||||||
->setAdditionalContentEntry('private_key', $existingKey)
|
|
||||||
;
|
|
||||||
|
|
||||||
$this->container->bookmarkService
|
|
||||||
->expects(static::once())
|
|
||||||
->method('findByHash')
|
|
||||||
->with($hash)
|
|
||||||
->willReturn($bookmark)
|
|
||||||
;
|
|
||||||
$this->container->bookmarkService
|
|
||||||
->expects(static::never())
|
|
||||||
->method('set')
|
|
||||||
;
|
|
||||||
|
|
||||||
$result = $this->controller->sharePrivate($request, $response, ['hash' => $hash]);
|
|
||||||
|
|
||||||
static::assertSame(302, $result->getStatusCode());
|
|
||||||
static::assertSame('/subfolder/shaare/' . $hash . '?key=' . $existingKey, $result->getHeaderLine('Location'));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test shaare private with a public bookmark.
|
|
||||||
*/
|
|
||||||
public function testSharePrivateWithPublicBookmark(): void
|
|
||||||
{
|
|
||||||
$hash = 'abcdcef';
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
$bookmark = (new Bookmark())
|
|
||||||
->setId(123)
|
|
||||||
->setUrl('http://domain.tld')
|
|
||||||
->setTitle('Title 123')
|
|
||||||
->setPrivate(false)
|
|
||||||
;
|
|
||||||
|
|
||||||
$this->container->bookmarkService
|
|
||||||
->expects(static::once())
|
|
||||||
->method('findByHash')
|
|
||||||
->with($hash)
|
|
||||||
->willReturn($bookmark)
|
|
||||||
;
|
|
||||||
$this->container->bookmarkService
|
|
||||||
->expects(static::never())
|
|
||||||
->method('set')
|
|
||||||
;
|
|
||||||
|
|
||||||
$result = $this->controller->sharePrivate($request, $response, ['hash' => $hash]);
|
|
||||||
|
|
||||||
static::assertSame(302, $result->getStatusCode());
|
|
||||||
static::assertSame('/subfolder/shaare/' . $hash, $result->getHeaderLine('Location'));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,63 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace Shaarli\Front\Controller\Admin\ShaarePublishControllerTest;
|
|
||||||
|
|
||||||
use Shaarli\Front\Controller\Admin\FrontAdminControllerMockHelper;
|
|
||||||
use Shaarli\Front\Controller\Admin\ShaarePublishController;
|
|
||||||
use Shaarli\Http\HttpAccess;
|
|
||||||
use Shaarli\Http\MetadataRetriever;
|
|
||||||
use Shaarli\TestCase;
|
|
||||||
use Slim\Http\Request;
|
|
||||||
use Slim\Http\Response;
|
|
||||||
|
|
||||||
class DisplayCreateBatchFormTest extends TestCase
|
|
||||||
{
|
|
||||||
use FrontAdminControllerMockHelper;
|
|
||||||
|
|
||||||
/** @var ShaarePublishController */
|
|
||||||
protected $controller;
|
|
||||||
|
|
||||||
public function setUp(): void
|
|
||||||
{
|
|
||||||
$this->createContainer();
|
|
||||||
|
|
||||||
$this->container->httpAccess = $this->createMock(HttpAccess::class);
|
|
||||||
$this->container->metadataRetriever = $this->createMock(MetadataRetriever::class);
|
|
||||||
$this->controller = new ShaarePublishController($this->container);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* TODO
|
|
||||||
*/
|
|
||||||
public function testDisplayCreateFormBatch(): void
|
|
||||||
{
|
|
||||||
$urls = [
|
|
||||||
'https://domain1.tld/url1',
|
|
||||||
'https://domain2.tld/url2',
|
|
||||||
' ',
|
|
||||||
'https://domain3.tld/url3',
|
|
||||||
];
|
|
||||||
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$request->method('getParam')->willReturnCallback(function (string $key) use ($urls): ?string {
|
|
||||||
return $key === 'urls' ? implode(PHP_EOL, $urls) : null;
|
|
||||||
});
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
$assignedVariables = [];
|
|
||||||
$this->assignTemplateVars($assignedVariables);
|
|
||||||
|
|
||||||
$result = $this->controller->displayCreateBatchForms($request, $response);
|
|
||||||
|
|
||||||
static::assertSame(200, $result->getStatusCode());
|
|
||||||
static::assertSame('editlink.batch', (string) $result->getBody());
|
|
||||||
|
|
||||||
static::assertTrue($assignedVariables['batch_mode']);
|
|
||||||
static::assertCount(3, $assignedVariables['links']);
|
|
||||||
static::assertSame($urls[0], $assignedVariables['links'][0]['link']['url']);
|
|
||||||
static::assertSame($urls[1], $assignedVariables['links'][1]['link']['url']);
|
|
||||||
static::assertSame($urls[3], $assignedVariables['links'][2]['link']['url']);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,367 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace Shaarli\Front\Controller\Admin\ShaarePublishControllerTest;
|
|
||||||
|
|
||||||
use Shaarli\Bookmark\Bookmark;
|
|
||||||
use Shaarli\Config\ConfigManager;
|
|
||||||
use Shaarli\Front\Controller\Admin\FrontAdminControllerMockHelper;
|
|
||||||
use Shaarli\Front\Controller\Admin\ShaarePublishController;
|
|
||||||
use Shaarli\Http\HttpAccess;
|
|
||||||
use Shaarli\Http\MetadataRetriever;
|
|
||||||
use Shaarli\TestCase;
|
|
||||||
use Slim\Http\Request;
|
|
||||||
use Slim\Http\Response;
|
|
||||||
|
|
||||||
class DisplayCreateFormTest extends TestCase
|
|
||||||
{
|
|
||||||
use FrontAdminControllerMockHelper;
|
|
||||||
|
|
||||||
/** @var ShaarePublishController */
|
|
||||||
protected $controller;
|
|
||||||
|
|
||||||
public function setUp(): void
|
|
||||||
{
|
|
||||||
$this->createContainer();
|
|
||||||
|
|
||||||
$this->container->httpAccess = $this->createMock(HttpAccess::class);
|
|
||||||
$this->container->metadataRetriever = $this->createMock(MetadataRetriever::class);
|
|
||||||
$this->controller = new ShaarePublishController($this->container);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test displaying bookmark create form
|
|
||||||
* Ensure that every step of the standard workflow works properly.
|
|
||||||
*/
|
|
||||||
public function testDisplayCreateFormWithUrlAndWithMetadataRetrieval(): void
|
|
||||||
{
|
|
||||||
$this->container->environment = [
|
|
||||||
'HTTP_REFERER' => $referer = 'http://shaarli/subfolder/controller/?searchtag=abc'
|
|
||||||
];
|
|
||||||
|
|
||||||
$assignedVariables = [];
|
|
||||||
$this->assignTemplateVars($assignedVariables);
|
|
||||||
|
|
||||||
$url = 'http://url.tld/other?part=3&utm_ad=pay#hash';
|
|
||||||
$expectedUrl = str_replace('&utm_ad=pay', '', $url);
|
|
||||||
$remoteTitle = 'Remote Title';
|
|
||||||
$remoteDesc = 'Sometimes the meta description is relevant.';
|
|
||||||
$remoteTags = 'abc def';
|
|
||||||
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$request->method('getParam')->willReturnCallback(function (string $key) use ($url): ?string {
|
|
||||||
return $key === 'post' ? $url : null;
|
|
||||||
});
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
$this->container->conf = $this->createMock(ConfigManager::class);
|
|
||||||
$this->container->conf->method('get')->willReturnCallback(function (string $param, $default) {
|
|
||||||
if ($param === 'general.enable_async_metadata') {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $default;
|
|
||||||
});
|
|
||||||
|
|
||||||
$this->container->metadataRetriever->expects(static::once())->method('retrieve')->willReturn([
|
|
||||||
'title' => $remoteTitle,
|
|
||||||
'description' => $remoteDesc,
|
|
||||||
'tags' => $remoteTags,
|
|
||||||
]);
|
|
||||||
|
|
||||||
$this->container->bookmarkService
|
|
||||||
->expects(static::once())
|
|
||||||
->method('bookmarksCountPerTag')
|
|
||||||
->willReturn($tags = ['tag1' => 2, 'tag2' => 1])
|
|
||||||
;
|
|
||||||
|
|
||||||
// Make sure that PluginManager hook is triggered
|
|
||||||
$this->container->pluginManager
|
|
||||||
->expects(static::atLeastOnce())
|
|
||||||
->method('executeHooks')
|
|
||||||
->withConsecutive(['render_editlink'], ['render_includes'])
|
|
||||||
->willReturnCallback(function (string $hook, array $data) use ($remoteTitle, $remoteDesc): array {
|
|
||||||
if ('render_editlink' === $hook) {
|
|
||||||
static::assertSame($remoteTitle, $data['link']['title']);
|
|
||||||
static::assertSame($remoteDesc, $data['link']['description']);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $data;
|
|
||||||
})
|
|
||||||
;
|
|
||||||
|
|
||||||
$result = $this->controller->displayCreateForm($request, $response);
|
|
||||||
|
|
||||||
static::assertSame(200, $result->getStatusCode());
|
|
||||||
static::assertSame('editlink', (string) $result->getBody());
|
|
||||||
|
|
||||||
static::assertSame('Shaare - Shaarli', $assignedVariables['pagetitle']);
|
|
||||||
|
|
||||||
static::assertSame($expectedUrl, $assignedVariables['link']['url']);
|
|
||||||
static::assertSame($remoteTitle, $assignedVariables['link']['title']);
|
|
||||||
static::assertSame($remoteDesc, $assignedVariables['link']['description']);
|
|
||||||
static::assertSame($remoteTags . ' ', $assignedVariables['link']['tags']);
|
|
||||||
static::assertFalse($assignedVariables['link']['private']);
|
|
||||||
|
|
||||||
static::assertTrue($assignedVariables['link_is_new']);
|
|
||||||
static::assertSame($referer, $assignedVariables['http_referer']);
|
|
||||||
static::assertSame($tags, $assignedVariables['tags']);
|
|
||||||
static::assertArrayHasKey('source', $assignedVariables);
|
|
||||||
static::assertArrayHasKey('default_private_links', $assignedVariables);
|
|
||||||
static::assertArrayHasKey('async_metadata', $assignedVariables);
|
|
||||||
static::assertArrayHasKey('retrieve_description', $assignedVariables);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test displaying bookmark create form without any external metadata retrieval attempt
|
|
||||||
*/
|
|
||||||
public function testDisplayCreateFormWithUrlAndWithoutMetadata(): void
|
|
||||||
{
|
|
||||||
$this->container->environment = [
|
|
||||||
'HTTP_REFERER' => $referer = 'http://shaarli/subfolder/controller/?searchtag=abc'
|
|
||||||
];
|
|
||||||
|
|
||||||
$assignedVariables = [];
|
|
||||||
$this->assignTemplateVars($assignedVariables);
|
|
||||||
|
|
||||||
$url = 'http://url.tld/other?part=3&utm_ad=pay#hash';
|
|
||||||
$expectedUrl = str_replace('&utm_ad=pay', '', $url);
|
|
||||||
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$request->method('getParam')->willReturnCallback(function (string $key) use ($url): ?string {
|
|
||||||
return $key === 'post' ? $url : null;
|
|
||||||
});
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
$this->container->metadataRetriever->expects(static::never())->method('retrieve');
|
|
||||||
|
|
||||||
$this->container->bookmarkService
|
|
||||||
->expects(static::once())
|
|
||||||
->method('bookmarksCountPerTag')
|
|
||||||
->willReturn($tags = ['tag1' => 2, 'tag2' => 1])
|
|
||||||
;
|
|
||||||
|
|
||||||
// Make sure that PluginManager hook is triggered
|
|
||||||
$this->container->pluginManager
|
|
||||||
->expects(static::atLeastOnce())
|
|
||||||
->method('executeHooks')
|
|
||||||
->withConsecutive(['render_editlink'], ['render_includes'])
|
|
||||||
->willReturnCallback(function (string $hook, array $data): array {
|
|
||||||
if ('render_editlink' === $hook) {
|
|
||||||
static::assertSame('', $data['link']['title']);
|
|
||||||
static::assertSame('', $data['link']['description']);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $data;
|
|
||||||
})
|
|
||||||
;
|
|
||||||
|
|
||||||
$result = $this->controller->displayCreateForm($request, $response);
|
|
||||||
|
|
||||||
static::assertSame(200, $result->getStatusCode());
|
|
||||||
static::assertSame('editlink', (string) $result->getBody());
|
|
||||||
|
|
||||||
static::assertSame('Shaare - Shaarli', $assignedVariables['pagetitle']);
|
|
||||||
|
|
||||||
static::assertSame($expectedUrl, $assignedVariables['link']['url']);
|
|
||||||
static::assertSame('', $assignedVariables['link']['title']);
|
|
||||||
static::assertSame('', $assignedVariables['link']['description']);
|
|
||||||
static::assertSame('', $assignedVariables['link']['tags']);
|
|
||||||
static::assertFalse($assignedVariables['link']['private']);
|
|
||||||
|
|
||||||
static::assertTrue($assignedVariables['link_is_new']);
|
|
||||||
static::assertSame($referer, $assignedVariables['http_referer']);
|
|
||||||
static::assertSame($tags, $assignedVariables['tags']);
|
|
||||||
static::assertArrayHasKey('source', $assignedVariables);
|
|
||||||
static::assertArrayHasKey('default_private_links', $assignedVariables);
|
|
||||||
static::assertArrayHasKey('async_metadata', $assignedVariables);
|
|
||||||
static::assertArrayHasKey('retrieve_description', $assignedVariables);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test displaying bookmark create form
|
|
||||||
* Ensure all available query parameters are handled properly.
|
|
||||||
*/
|
|
||||||
public function testDisplayCreateFormWithFullParameters(): void
|
|
||||||
{
|
|
||||||
$assignedVariables = [];
|
|
||||||
$this->assignTemplateVars($assignedVariables);
|
|
||||||
|
|
||||||
$parameters = [
|
|
||||||
'post' => 'http://url.tld/other?part=3&utm_ad=pay#hash',
|
|
||||||
'title' => 'Provided Title',
|
|
||||||
'description' => 'Provided description.',
|
|
||||||
'tags' => 'abc@def',
|
|
||||||
'private' => '1',
|
|
||||||
'source' => 'apps',
|
|
||||||
];
|
|
||||||
$expectedUrl = str_replace('&utm_ad=pay', '', $parameters['post']);
|
|
||||||
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$request
|
|
||||||
->method('getParam')
|
|
||||||
->willReturnCallback(function (string $key) use ($parameters): ?string {
|
|
||||||
return $parameters[$key] ?? null;
|
|
||||||
});
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
$result = $this->controller->displayCreateForm($request, $response);
|
|
||||||
|
|
||||||
static::assertSame(200, $result->getStatusCode());
|
|
||||||
static::assertSame('editlink', (string) $result->getBody());
|
|
||||||
|
|
||||||
static::assertSame('Shaare - Shaarli', $assignedVariables['pagetitle']);
|
|
||||||
|
|
||||||
static::assertSame($expectedUrl, $assignedVariables['link']['url']);
|
|
||||||
static::assertSame($parameters['title'], $assignedVariables['link']['title']);
|
|
||||||
static::assertSame($parameters['description'], $assignedVariables['link']['description']);
|
|
||||||
static::assertSame($parameters['tags'] . '@', $assignedVariables['link']['tags']);
|
|
||||||
static::assertTrue($assignedVariables['link']['private']);
|
|
||||||
static::assertTrue($assignedVariables['link_is_new']);
|
|
||||||
static::assertSame($parameters['source'], $assignedVariables['source']);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test displaying bookmark create form
|
|
||||||
* Without any parameter.
|
|
||||||
*/
|
|
||||||
public function testDisplayCreateFormEmpty(): void
|
|
||||||
{
|
|
||||||
$assignedVariables = [];
|
|
||||||
$this->assignTemplateVars($assignedVariables);
|
|
||||||
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
$this->container->httpAccess->expects(static::never())->method('getHttpResponse');
|
|
||||||
$this->container->httpAccess->expects(static::never())->method('getCurlDownloadCallback');
|
|
||||||
|
|
||||||
$result = $this->controller->displayCreateForm($request, $response);
|
|
||||||
|
|
||||||
static::assertSame(200, $result->getStatusCode());
|
|
||||||
static::assertSame('editlink', (string) $result->getBody());
|
|
||||||
static::assertSame('', $assignedVariables['link']['url']);
|
|
||||||
static::assertSame('Note: ', $assignedVariables['link']['title']);
|
|
||||||
static::assertSame('', $assignedVariables['link']['description']);
|
|
||||||
static::assertSame('', $assignedVariables['link']['tags']);
|
|
||||||
static::assertFalse($assignedVariables['link']['private']);
|
|
||||||
static::assertTrue($assignedVariables['link_is_new']);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test displaying bookmark create form
|
|
||||||
* URL not using HTTP protocol: do not try to retrieve the title
|
|
||||||
*/
|
|
||||||
public function testDisplayCreateFormNotHttp(): void
|
|
||||||
{
|
|
||||||
$assignedVariables = [];
|
|
||||||
$this->assignTemplateVars($assignedVariables);
|
|
||||||
|
|
||||||
$url = 'magnet://kubuntu.torrent';
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$request
|
|
||||||
->method('getParam')
|
|
||||||
->willReturnCallback(function (string $key) use ($url): ?string {
|
|
||||||
return $key === 'post' ? $url : null;
|
|
||||||
});
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
$this->container->httpAccess->expects(static::never())->method('getHttpResponse');
|
|
||||||
$this->container->httpAccess->expects(static::never())->method('getCurlDownloadCallback');
|
|
||||||
|
|
||||||
$result = $this->controller->displayCreateForm($request, $response);
|
|
||||||
|
|
||||||
static::assertSame(200, $result->getStatusCode());
|
|
||||||
static::assertSame('editlink', (string) $result->getBody());
|
|
||||||
static::assertSame($url, $assignedVariables['link']['url']);
|
|
||||||
static::assertTrue($assignedVariables['link_is_new']);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test displaying bookmark create form
|
|
||||||
* When markdown formatter is enabled, the no markdown tag should be added to existing tags.
|
|
||||||
*/
|
|
||||||
public function testDisplayCreateFormWithMarkdownEnabled(): void
|
|
||||||
{
|
|
||||||
$assignedVariables = [];
|
|
||||||
$this->assignTemplateVars($assignedVariables);
|
|
||||||
|
|
||||||
$this->container->conf = $this->createMock(ConfigManager::class);
|
|
||||||
$this->container->conf
|
|
||||||
->expects(static::atLeastOnce())
|
|
||||||
->method('get')->willReturnCallback(function (string $key): ?string {
|
|
||||||
if ($key === 'formatter') {
|
|
||||||
return 'markdown';
|
|
||||||
}
|
|
||||||
|
|
||||||
return $key;
|
|
||||||
})
|
|
||||||
;
|
|
||||||
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
$result = $this->controller->displayCreateForm($request, $response);
|
|
||||||
|
|
||||||
static::assertSame(200, $result->getStatusCode());
|
|
||||||
static::assertSame('editlink', (string) $result->getBody());
|
|
||||||
static::assertSame(['nomarkdown' => 1], $assignedVariables['tags']);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test displaying bookmark create form
|
|
||||||
* When an existing URL is submitted, we want to edit the existing link.
|
|
||||||
*/
|
|
||||||
public function testDisplayCreateFormWithExistingUrl(): void
|
|
||||||
{
|
|
||||||
$assignedVariables = [];
|
|
||||||
$this->assignTemplateVars($assignedVariables);
|
|
||||||
|
|
||||||
$url = 'http://url.tld/other?part=3&utm_ad=pay#hash';
|
|
||||||
$expectedUrl = str_replace('&utm_ad=pay', '', $url);
|
|
||||||
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$request
|
|
||||||
->method('getParam')
|
|
||||||
->willReturnCallback(function (string $key) use ($url): ?string {
|
|
||||||
return $key === 'post' ? $url : null;
|
|
||||||
});
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
$this->container->httpAccess->expects(static::never())->method('getHttpResponse');
|
|
||||||
$this->container->httpAccess->expects(static::never())->method('getCurlDownloadCallback');
|
|
||||||
|
|
||||||
$this->container->bookmarkService
|
|
||||||
->expects(static::once())
|
|
||||||
->method('findByUrl')
|
|
||||||
->with($expectedUrl)
|
|
||||||
->willReturn(
|
|
||||||
(new Bookmark())
|
|
||||||
->setId($id = 23)
|
|
||||||
->setUrl($expectedUrl)
|
|
||||||
->setTitle($title = 'Bookmark Title')
|
|
||||||
->setDescription($description = 'Bookmark description.')
|
|
||||||
->setTags($tags = ['abc', 'def'])
|
|
||||||
->setPrivate(true)
|
|
||||||
->setCreated($createdAt = new \DateTime('2020-06-10 18:45:44'))
|
|
||||||
)
|
|
||||||
;
|
|
||||||
|
|
||||||
$result = $this->controller->displayCreateForm($request, $response);
|
|
||||||
|
|
||||||
static::assertSame(200, $result->getStatusCode());
|
|
||||||
static::assertSame('editlink', (string) $result->getBody());
|
|
||||||
|
|
||||||
static::assertSame('Edit Shaare - Shaarli', $assignedVariables['pagetitle']);
|
|
||||||
static::assertFalse($assignedVariables['link_is_new']);
|
|
||||||
|
|
||||||
static::assertSame($id, $assignedVariables['link']['id']);
|
|
||||||
static::assertSame($expectedUrl, $assignedVariables['link']['url']);
|
|
||||||
static::assertSame($title, $assignedVariables['link']['title']);
|
|
||||||
static::assertSame($description, $assignedVariables['link']['description']);
|
|
||||||
static::assertSame(implode('@', $tags) . '@', $assignedVariables['link']['tags']);
|
|
||||||
static::assertTrue($assignedVariables['link']['private']);
|
|
||||||
static::assertSame($createdAt, $assignedVariables['link']['created']);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,155 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace Shaarli\Front\Controller\Admin\ShaarePublishControllerTest;
|
|
||||||
|
|
||||||
use Shaarli\Bookmark\Bookmark;
|
|
||||||
use Shaarli\Bookmark\Exception\BookmarkNotFoundException;
|
|
||||||
use Shaarli\Front\Controller\Admin\FrontAdminControllerMockHelper;
|
|
||||||
use Shaarli\Front\Controller\Admin\ShaarePublishController;
|
|
||||||
use Shaarli\Http\HttpAccess;
|
|
||||||
use Shaarli\Security\SessionManager;
|
|
||||||
use Shaarli\TestCase;
|
|
||||||
use Slim\Http\Request;
|
|
||||||
use Slim\Http\Response;
|
|
||||||
|
|
||||||
class DisplayEditFormTest extends TestCase
|
|
||||||
{
|
|
||||||
use FrontAdminControllerMockHelper;
|
|
||||||
|
|
||||||
/** @var ShaarePublishController */
|
|
||||||
protected $controller;
|
|
||||||
|
|
||||||
public function setUp(): void
|
|
||||||
{
|
|
||||||
$this->createContainer();
|
|
||||||
|
|
||||||
$this->container->httpAccess = $this->createMock(HttpAccess::class);
|
|
||||||
$this->controller = new ShaarePublishController($this->container);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test displaying bookmark edit form
|
|
||||||
* When an existing ID is provided, ensure that default workflow works properly.
|
|
||||||
*/
|
|
||||||
public function testDisplayEditFormDefault(): void
|
|
||||||
{
|
|
||||||
$assignedVariables = [];
|
|
||||||
$this->assignTemplateVars($assignedVariables);
|
|
||||||
|
|
||||||
$id = 11;
|
|
||||||
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
$this->container->httpAccess->expects(static::never())->method('getHttpResponse');
|
|
||||||
$this->container->httpAccess->expects(static::never())->method('getCurlDownloadCallback');
|
|
||||||
|
|
||||||
$this->container->bookmarkService
|
|
||||||
->expects(static::once())
|
|
||||||
->method('get')
|
|
||||||
->with($id)
|
|
||||||
->willReturn(
|
|
||||||
(new Bookmark())
|
|
||||||
->setId($id)
|
|
||||||
->setUrl($url = 'http://domain.tld')
|
|
||||||
->setTitle($title = 'Bookmark Title')
|
|
||||||
->setDescription($description = 'Bookmark description.')
|
|
||||||
->setTags($tags = ['abc', 'def'])
|
|
||||||
->setPrivate(true)
|
|
||||||
->setCreated($createdAt = new \DateTime('2020-06-10 18:45:44'))
|
|
||||||
)
|
|
||||||
;
|
|
||||||
|
|
||||||
$result = $this->controller->displayEditForm($request, $response, ['id' => (string) $id]);
|
|
||||||
|
|
||||||
static::assertSame(200, $result->getStatusCode());
|
|
||||||
static::assertSame('editlink', (string) $result->getBody());
|
|
||||||
|
|
||||||
static::assertSame('Edit Shaare - Shaarli', $assignedVariables['pagetitle']);
|
|
||||||
static::assertFalse($assignedVariables['link_is_new']);
|
|
||||||
|
|
||||||
static::assertSame($id, $assignedVariables['link']['id']);
|
|
||||||
static::assertSame($url, $assignedVariables['link']['url']);
|
|
||||||
static::assertSame($title, $assignedVariables['link']['title']);
|
|
||||||
static::assertSame($description, $assignedVariables['link']['description']);
|
|
||||||
static::assertSame(implode('@', $tags) . '@', $assignedVariables['link']['tags']);
|
|
||||||
static::assertTrue($assignedVariables['link']['private']);
|
|
||||||
static::assertSame($createdAt, $assignedVariables['link']['created']);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test displaying bookmark edit form
|
|
||||||
* Invalid ID provided.
|
|
||||||
*/
|
|
||||||
public function testDisplayEditFormInvalidId(): void
|
|
||||||
{
|
|
||||||
$id = 'invalid';
|
|
||||||
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
$this->container->sessionManager
|
|
||||||
->expects(static::once())
|
|
||||||
->method('setSessionParameter')
|
|
||||||
->with(SessionManager::KEY_ERROR_MESSAGES, ['Bookmark with identifier invalid could not be found.'])
|
|
||||||
;
|
|
||||||
|
|
||||||
$result = $this->controller->displayEditForm($request, $response, ['id' => $id]);
|
|
||||||
|
|
||||||
static::assertSame(302, $result->getStatusCode());
|
|
||||||
static::assertSame(['/subfolder/'], $result->getHeader('location'));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test displaying bookmark edit form
|
|
||||||
* ID not provided.
|
|
||||||
*/
|
|
||||||
public function testDisplayEditFormIdNotProvided(): void
|
|
||||||
{
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
$this->container->sessionManager
|
|
||||||
->expects(static::once())
|
|
||||||
->method('setSessionParameter')
|
|
||||||
->with(SessionManager::KEY_ERROR_MESSAGES, ['Bookmark with identifier could not be found.'])
|
|
||||||
;
|
|
||||||
|
|
||||||
$result = $this->controller->displayEditForm($request, $response, []);
|
|
||||||
|
|
||||||
static::assertSame(302, $result->getStatusCode());
|
|
||||||
static::assertSame(['/subfolder/'], $result->getHeader('location'));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test displaying bookmark edit form
|
|
||||||
* Bookmark not found.
|
|
||||||
*/
|
|
||||||
public function testDisplayEditFormBookmarkNotFound(): void
|
|
||||||
{
|
|
||||||
$id = 123;
|
|
||||||
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
$this->container->bookmarkService
|
|
||||||
->expects(static::once())
|
|
||||||
->method('get')
|
|
||||||
->with($id)
|
|
||||||
->willThrowException(new BookmarkNotFoundException())
|
|
||||||
;
|
|
||||||
|
|
||||||
$this->container->sessionManager
|
|
||||||
->expects(static::once())
|
|
||||||
->method('setSessionParameter')
|
|
||||||
->with(SessionManager::KEY_ERROR_MESSAGES, ['Bookmark with identifier 123 could not be found.'])
|
|
||||||
;
|
|
||||||
|
|
||||||
$result = $this->controller->displayEditForm($request, $response, ['id' => (string) $id]);
|
|
||||||
|
|
||||||
static::assertSame(302, $result->getStatusCode());
|
|
||||||
static::assertSame(['/subfolder/'], $result->getHeader('location'));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,368 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace Shaarli\Front\Controller\Admin\ShaarePublishControllerTest;
|
|
||||||
|
|
||||||
use Shaarli\Bookmark\Bookmark;
|
|
||||||
use Shaarli\Config\ConfigManager;
|
|
||||||
use Shaarli\Front\Controller\Admin\FrontAdminControllerMockHelper;
|
|
||||||
use Shaarli\Front\Controller\Admin\ShaarePublishController;
|
|
||||||
use Shaarli\Front\Exception\WrongTokenException;
|
|
||||||
use Shaarli\Http\HttpAccess;
|
|
||||||
use Shaarli\Security\SessionManager;
|
|
||||||
use Shaarli\TestCase;
|
|
||||||
use Shaarli\Thumbnailer;
|
|
||||||
use Slim\Http\Request;
|
|
||||||
use Slim\Http\Response;
|
|
||||||
|
|
||||||
class SaveBookmarkTest extends TestCase
|
|
||||||
{
|
|
||||||
use FrontAdminControllerMockHelper;
|
|
||||||
|
|
||||||
/** @var ShaarePublishController */
|
|
||||||
protected $controller;
|
|
||||||
|
|
||||||
public function setUp(): void
|
|
||||||
{
|
|
||||||
$this->createContainer();
|
|
||||||
|
|
||||||
$this->container->httpAccess = $this->createMock(HttpAccess::class);
|
|
||||||
$this->controller = new ShaarePublishController($this->container);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test save a new bookmark
|
|
||||||
*/
|
|
||||||
public function testSaveBookmark(): void
|
|
||||||
{
|
|
||||||
$id = 21;
|
|
||||||
$parameters = [
|
|
||||||
'lf_url' => 'http://url.tld/other?part=3#hash',
|
|
||||||
'lf_title' => 'Provided Title',
|
|
||||||
'lf_description' => 'Provided description.',
|
|
||||||
'lf_tags' => 'abc def',
|
|
||||||
'lf_private' => '1',
|
|
||||||
'returnurl' => 'http://shaarli/subfolder/admin/add-shaare'
|
|
||||||
];
|
|
||||||
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$request
|
|
||||||
->method('getParam')
|
|
||||||
->willReturnCallback(function (string $key) use ($parameters): ?string {
|
|
||||||
return $parameters[$key] ?? null;
|
|
||||||
})
|
|
||||||
;
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
$checkBookmark = function (Bookmark $bookmark) use ($parameters) {
|
|
||||||
static::assertSame($parameters['lf_url'], $bookmark->getUrl());
|
|
||||||
static::assertSame($parameters['lf_title'], $bookmark->getTitle());
|
|
||||||
static::assertSame($parameters['lf_description'], $bookmark->getDescription());
|
|
||||||
static::assertSame($parameters['lf_tags'], $bookmark->getTagsString());
|
|
||||||
static::assertTrue($bookmark->isPrivate());
|
|
||||||
};
|
|
||||||
|
|
||||||
$this->container->bookmarkService
|
|
||||||
->expects(static::once())
|
|
||||||
->method('addOrSet')
|
|
||||||
->willReturnCallback(function (Bookmark $bookmark, bool $save) use ($checkBookmark, $id): Bookmark {
|
|
||||||
static::assertFalse($save);
|
|
||||||
|
|
||||||
$checkBookmark($bookmark);
|
|
||||||
|
|
||||||
$bookmark->setId($id);
|
|
||||||
|
|
||||||
return $bookmark;
|
|
||||||
})
|
|
||||||
;
|
|
||||||
$this->container->bookmarkService
|
|
||||||
->expects(static::once())
|
|
||||||
->method('set')
|
|
||||||
->willReturnCallback(function (Bookmark $bookmark, bool $save) use ($checkBookmark, $id): Bookmark {
|
|
||||||
static::assertTrue($save);
|
|
||||||
|
|
||||||
$checkBookmark($bookmark);
|
|
||||||
|
|
||||||
static::assertSame($id, $bookmark->getId());
|
|
||||||
|
|
||||||
return $bookmark;
|
|
||||||
})
|
|
||||||
;
|
|
||||||
|
|
||||||
// Make sure that PluginManager hook is triggered
|
|
||||||
$this->container->pluginManager
|
|
||||||
->expects(static::atLeastOnce())
|
|
||||||
->method('executeHooks')
|
|
||||||
->withConsecutive(['save_link'])
|
|
||||||
->willReturnCallback(function (string $hook, array $data) use ($parameters, $id): array {
|
|
||||||
if ('save_link' === $hook) {
|
|
||||||
static::assertSame($id, $data['id']);
|
|
||||||
static::assertSame($parameters['lf_url'], $data['url']);
|
|
||||||
static::assertSame($parameters['lf_title'], $data['title']);
|
|
||||||
static::assertSame($parameters['lf_description'], $data['description']);
|
|
||||||
static::assertSame($parameters['lf_tags'], $data['tags']);
|
|
||||||
static::assertTrue($data['private']);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $data;
|
|
||||||
})
|
|
||||||
;
|
|
||||||
|
|
||||||
$result = $this->controller->save($request, $response);
|
|
||||||
|
|
||||||
static::assertSame(302, $result->getStatusCode());
|
|
||||||
static::assertRegExp('@/subfolder/#[\w\-]{6}@', $result->getHeader('location')[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test save an existing bookmark
|
|
||||||
*/
|
|
||||||
public function testSaveExistingBookmark(): void
|
|
||||||
{
|
|
||||||
$id = 21;
|
|
||||||
$parameters = [
|
|
||||||
'lf_id' => (string) $id,
|
|
||||||
'lf_url' => 'http://url.tld/other?part=3#hash',
|
|
||||||
'lf_title' => 'Provided Title',
|
|
||||||
'lf_description' => 'Provided description.',
|
|
||||||
'lf_tags' => 'abc def',
|
|
||||||
'lf_private' => '1',
|
|
||||||
'returnurl' => 'http://shaarli/subfolder/?page=2'
|
|
||||||
];
|
|
||||||
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$request
|
|
||||||
->method('getParam')
|
|
||||||
->willReturnCallback(function (string $key) use ($parameters): ?string {
|
|
||||||
return $parameters[$key] ?? null;
|
|
||||||
})
|
|
||||||
;
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
$checkBookmark = function (Bookmark $bookmark) use ($parameters, $id) {
|
|
||||||
static::assertSame($id, $bookmark->getId());
|
|
||||||
static::assertSame($parameters['lf_url'], $bookmark->getUrl());
|
|
||||||
static::assertSame($parameters['lf_title'], $bookmark->getTitle());
|
|
||||||
static::assertSame($parameters['lf_description'], $bookmark->getDescription());
|
|
||||||
static::assertSame($parameters['lf_tags'], $bookmark->getTagsString());
|
|
||||||
static::assertTrue($bookmark->isPrivate());
|
|
||||||
};
|
|
||||||
|
|
||||||
$this->container->bookmarkService->expects(static::atLeastOnce())->method('exists')->willReturn(true);
|
|
||||||
$this->container->bookmarkService
|
|
||||||
->expects(static::once())
|
|
||||||
->method('get')
|
|
||||||
->willReturn((new Bookmark())->setId($id)->setUrl('http://other.url'))
|
|
||||||
;
|
|
||||||
$this->container->bookmarkService
|
|
||||||
->expects(static::once())
|
|
||||||
->method('addOrSet')
|
|
||||||
->willReturnCallback(function (Bookmark $bookmark, bool $save) use ($checkBookmark, $id): Bookmark {
|
|
||||||
static::assertFalse($save);
|
|
||||||
|
|
||||||
$checkBookmark($bookmark);
|
|
||||||
|
|
||||||
return $bookmark;
|
|
||||||
})
|
|
||||||
;
|
|
||||||
$this->container->bookmarkService
|
|
||||||
->expects(static::once())
|
|
||||||
->method('set')
|
|
||||||
->willReturnCallback(function (Bookmark $bookmark, bool $save) use ($checkBookmark, $id): Bookmark {
|
|
||||||
static::assertTrue($save);
|
|
||||||
|
|
||||||
$checkBookmark($bookmark);
|
|
||||||
|
|
||||||
static::assertSame($id, $bookmark->getId());
|
|
||||||
|
|
||||||
return $bookmark;
|
|
||||||
})
|
|
||||||
;
|
|
||||||
|
|
||||||
// Make sure that PluginManager hook is triggered
|
|
||||||
$this->container->pluginManager
|
|
||||||
->expects(static::atLeastOnce())
|
|
||||||
->method('executeHooks')
|
|
||||||
->withConsecutive(['save_link'])
|
|
||||||
->willReturnCallback(function (string $hook, array $data) use ($parameters, $id): array {
|
|
||||||
if ('save_link' === $hook) {
|
|
||||||
static::assertSame($id, $data['id']);
|
|
||||||
static::assertSame($parameters['lf_url'], $data['url']);
|
|
||||||
static::assertSame($parameters['lf_title'], $data['title']);
|
|
||||||
static::assertSame($parameters['lf_description'], $data['description']);
|
|
||||||
static::assertSame($parameters['lf_tags'], $data['tags']);
|
|
||||||
static::assertTrue($data['private']);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $data;
|
|
||||||
})
|
|
||||||
;
|
|
||||||
|
|
||||||
$result = $this->controller->save($request, $response);
|
|
||||||
|
|
||||||
static::assertSame(302, $result->getStatusCode());
|
|
||||||
static::assertRegExp('@/subfolder/\?page=2#[\w\-]{6}@', $result->getHeader('location')[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test save a bookmark - try to retrieve the thumbnail
|
|
||||||
*/
|
|
||||||
public function testSaveBookmarkWithThumbnailSync(): void
|
|
||||||
{
|
|
||||||
$parameters = ['lf_url' => 'http://url.tld/other?part=3#hash'];
|
|
||||||
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$request
|
|
||||||
->method('getParam')
|
|
||||||
->willReturnCallback(function (string $key) use ($parameters): ?string {
|
|
||||||
return $parameters[$key] ?? null;
|
|
||||||
})
|
|
||||||
;
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
$this->container->conf = $this->createMock(ConfigManager::class);
|
|
||||||
$this->container->conf->method('get')->willReturnCallback(function (string $key, $default) {
|
|
||||||
if ($key === 'thumbnails.mode') {
|
|
||||||
return Thumbnailer::MODE_ALL;
|
|
||||||
} elseif ($key === 'general.enable_async_metadata') {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $default;
|
|
||||||
});
|
|
||||||
|
|
||||||
$this->container->thumbnailer = $this->createMock(Thumbnailer::class);
|
|
||||||
$this->container->thumbnailer
|
|
||||||
->expects(static::once())
|
|
||||||
->method('get')
|
|
||||||
->with($parameters['lf_url'])
|
|
||||||
->willReturn($thumb = 'http://thumb.url')
|
|
||||||
;
|
|
||||||
|
|
||||||
$this->container->bookmarkService
|
|
||||||
->expects(static::once())
|
|
||||||
->method('addOrSet')
|
|
||||||
->willReturnCallback(function (Bookmark $bookmark, bool $save) use ($thumb): Bookmark {
|
|
||||||
static::assertSame($thumb, $bookmark->getThumbnail());
|
|
||||||
|
|
||||||
return $bookmark;
|
|
||||||
})
|
|
||||||
;
|
|
||||||
|
|
||||||
$result = $this->controller->save($request, $response);
|
|
||||||
|
|
||||||
static::assertSame(302, $result->getStatusCode());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test save a bookmark - with ID #0
|
|
||||||
*/
|
|
||||||
public function testSaveBookmarkWithIdZero(): void
|
|
||||||
{
|
|
||||||
$parameters = ['lf_id' => '0'];
|
|
||||||
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$request
|
|
||||||
->method('getParam')
|
|
||||||
->willReturnCallback(function (string $key) use ($parameters): ?string {
|
|
||||||
return $parameters[$key] ?? null;
|
|
||||||
})
|
|
||||||
;
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
$this->container->bookmarkService->expects(static::once())->method('exists')->with(0)->willReturn(true);
|
|
||||||
$this->container->bookmarkService->expects(static::once())->method('get')->with(0)->willReturn(new Bookmark());
|
|
||||||
|
|
||||||
$result = $this->controller->save($request, $response);
|
|
||||||
|
|
||||||
static::assertSame(302, $result->getStatusCode());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test save a bookmark - do not attempt to retrieve thumbnails if async mode is enabled.
|
|
||||||
*/
|
|
||||||
public function testSaveBookmarkWithThumbnailAsync(): void
|
|
||||||
{
|
|
||||||
$parameters = ['lf_url' => 'http://url.tld/other?part=3#hash'];
|
|
||||||
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$request
|
|
||||||
->method('getParam')
|
|
||||||
->willReturnCallback(function (string $key) use ($parameters): ?string {
|
|
||||||
return $parameters[$key] ?? null;
|
|
||||||
})
|
|
||||||
;
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
$this->container->conf = $this->createMock(ConfigManager::class);
|
|
||||||
$this->container->conf->method('get')->willReturnCallback(function (string $key, $default) {
|
|
||||||
if ($key === 'thumbnails.mode') {
|
|
||||||
return Thumbnailer::MODE_ALL;
|
|
||||||
} elseif ($key === 'general.enable_async_metadata') {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $default;
|
|
||||||
});
|
|
||||||
|
|
||||||
$this->container->thumbnailer = $this->createMock(Thumbnailer::class);
|
|
||||||
$this->container->thumbnailer->expects(static::never())->method('get');
|
|
||||||
|
|
||||||
$this->container->bookmarkService
|
|
||||||
->expects(static::once())
|
|
||||||
->method('addOrSet')
|
|
||||||
->willReturnCallback(function (Bookmark $bookmark): Bookmark {
|
|
||||||
static::assertNull($bookmark->getThumbnail());
|
|
||||||
|
|
||||||
return $bookmark;
|
|
||||||
})
|
|
||||||
;
|
|
||||||
|
|
||||||
$result = $this->controller->save($request, $response);
|
|
||||||
|
|
||||||
static::assertSame(302, $result->getStatusCode());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Change the password with a wrong existing password
|
|
||||||
*/
|
|
||||||
public function testSaveBookmarkFromBookmarklet(): void
|
|
||||||
{
|
|
||||||
$parameters = ['source' => 'bookmarklet'];
|
|
||||||
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$request
|
|
||||||
->method('getParam')
|
|
||||||
->willReturnCallback(function (string $key) use ($parameters): ?string {
|
|
||||||
return $parameters[$key] ?? null;
|
|
||||||
})
|
|
||||||
;
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
$result = $this->controller->save($request, $response);
|
|
||||||
|
|
||||||
static::assertSame(200, $result->getStatusCode());
|
|
||||||
static::assertSame('<script>self.close();</script>', (string) $result->getBody());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Change the password with a wrong existing password
|
|
||||||
*/
|
|
||||||
public function testSaveBookmarkWrongToken(): void
|
|
||||||
{
|
|
||||||
$this->container->sessionManager = $this->createMock(SessionManager::class);
|
|
||||||
$this->container->sessionManager->method('checkToken')->willReturn(false);
|
|
||||||
|
|
||||||
$this->container->bookmarkService->expects(static::never())->method('addOrSet');
|
|
||||||
$this->container->bookmarkService->expects(static::never())->method('set');
|
|
||||||
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
$this->expectException(WrongTokenException::class);
|
|
||||||
|
|
||||||
$this->controller->save($request, $response);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,184 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace Shaarli\Front\Controller\Admin;
|
|
||||||
|
|
||||||
use Shaarli\Front\Exception\WrongTokenException;
|
|
||||||
use Shaarli\Security\SessionManager;
|
|
||||||
use Shaarli\TestCase;
|
|
||||||
use Slim\Http\Request;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Class ShaarliControllerTest
|
|
||||||
*
|
|
||||||
* This class is used to test default behavior of ShaarliAdminController abstract class.
|
|
||||||
* It uses a dummy non abstract controller.
|
|
||||||
*/
|
|
||||||
class ShaarliAdminControllerTest extends TestCase
|
|
||||||
{
|
|
||||||
use FrontAdminControllerMockHelper;
|
|
||||||
|
|
||||||
/** @var ShaarliAdminController */
|
|
||||||
protected $controller;
|
|
||||||
|
|
||||||
public function setUp(): void
|
|
||||||
{
|
|
||||||
$this->createContainer();
|
|
||||||
|
|
||||||
$this->controller = new class ($this->container) extends ShaarliAdminController
|
|
||||||
{
|
|
||||||
public function checkToken(Request $request): bool
|
|
||||||
{
|
|
||||||
return parent::checkToken($request);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function saveSuccessMessage(string $message): void
|
|
||||||
{
|
|
||||||
parent::saveSuccessMessage($message);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function saveWarningMessage(string $message): void
|
|
||||||
{
|
|
||||||
parent::saveWarningMessage($message);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function saveErrorMessage(string $message): void
|
|
||||||
{
|
|
||||||
parent::saveErrorMessage($message);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Trigger controller's checkToken with a valid token.
|
|
||||||
*/
|
|
||||||
public function testCheckTokenWithValidToken(): void
|
|
||||||
{
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$request->method('getParam')->with('token')->willReturn($token = '12345');
|
|
||||||
|
|
||||||
$this->container->sessionManager = $this->createMock(SessionManager::class);
|
|
||||||
$this->container->sessionManager->method('checkToken')->with($token)->willReturn(true);
|
|
||||||
|
|
||||||
static::assertTrue($this->controller->checkToken($request));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Trigger controller's checkToken with na valid token should raise an exception.
|
|
||||||
*/
|
|
||||||
public function testCheckTokenWithNotValidToken(): void
|
|
||||||
{
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$request->method('getParam')->with('token')->willReturn($token = '12345');
|
|
||||||
|
|
||||||
$this->container->sessionManager = $this->createMock(SessionManager::class);
|
|
||||||
$this->container->sessionManager->method('checkToken')->with($token)->willReturn(false);
|
|
||||||
|
|
||||||
$this->expectException(WrongTokenException::class);
|
|
||||||
|
|
||||||
$this->controller->checkToken($request);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test saveSuccessMessage() with a first message.
|
|
||||||
*/
|
|
||||||
public function testSaveSuccessMessage(): void
|
|
||||||
{
|
|
||||||
$this->container->sessionManager
|
|
||||||
->expects(static::once())
|
|
||||||
->method('setSessionParameter')
|
|
||||||
->with(SessionManager::KEY_SUCCESS_MESSAGES, [$message = 'bravo!'])
|
|
||||||
;
|
|
||||||
|
|
||||||
$this->controller->saveSuccessMessage($message);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test saveSuccessMessage() with existing messages.
|
|
||||||
*/
|
|
||||||
public function testSaveSuccessMessageWithExistingMessages(): void
|
|
||||||
{
|
|
||||||
$this->container->sessionManager
|
|
||||||
->expects(static::once())
|
|
||||||
->method('getSessionParameter')
|
|
||||||
->with(SessionManager::KEY_SUCCESS_MESSAGES)
|
|
||||||
->willReturn(['success1', 'success2'])
|
|
||||||
;
|
|
||||||
$this->container->sessionManager
|
|
||||||
->expects(static::once())
|
|
||||||
->method('setSessionParameter')
|
|
||||||
->with(SessionManager::KEY_SUCCESS_MESSAGES, ['success1', 'success2', $message = 'bravo!'])
|
|
||||||
;
|
|
||||||
|
|
||||||
$this->controller->saveSuccessMessage($message);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test saveWarningMessage() with a first message.
|
|
||||||
*/
|
|
||||||
public function testSaveWarningMessage(): void
|
|
||||||
{
|
|
||||||
$this->container->sessionManager
|
|
||||||
->expects(static::once())
|
|
||||||
->method('setSessionParameter')
|
|
||||||
->with(SessionManager::KEY_WARNING_MESSAGES, [$message = 'warning!'])
|
|
||||||
;
|
|
||||||
|
|
||||||
$this->controller->saveWarningMessage($message);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test saveWarningMessage() with existing messages.
|
|
||||||
*/
|
|
||||||
public function testSaveWarningMessageWithExistingMessages(): void
|
|
||||||
{
|
|
||||||
$this->container->sessionManager
|
|
||||||
->expects(static::once())
|
|
||||||
->method('getSessionParameter')
|
|
||||||
->with(SessionManager::KEY_WARNING_MESSAGES)
|
|
||||||
->willReturn(['warning1', 'warning2'])
|
|
||||||
;
|
|
||||||
$this->container->sessionManager
|
|
||||||
->expects(static::once())
|
|
||||||
->method('setSessionParameter')
|
|
||||||
->with(SessionManager::KEY_WARNING_MESSAGES, ['warning1', 'warning2', $message = 'warning!'])
|
|
||||||
;
|
|
||||||
|
|
||||||
$this->controller->saveWarningMessage($message);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test saveErrorMessage() with a first message.
|
|
||||||
*/
|
|
||||||
public function testSaveErrorMessage(): void
|
|
||||||
{
|
|
||||||
$this->container->sessionManager
|
|
||||||
->expects(static::once())
|
|
||||||
->method('setSessionParameter')
|
|
||||||
->with(SessionManager::KEY_ERROR_MESSAGES, [$message = 'error!'])
|
|
||||||
;
|
|
||||||
|
|
||||||
$this->controller->saveErrorMessage($message);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test saveErrorMessage() with existing messages.
|
|
||||||
*/
|
|
||||||
public function testSaveErrorMessageWithExistingMessages(): void
|
|
||||||
{
|
|
||||||
$this->container->sessionManager
|
|
||||||
->expects(static::once())
|
|
||||||
->method('getSessionParameter')
|
|
||||||
->with(SessionManager::KEY_ERROR_MESSAGES)
|
|
||||||
->willReturn(['error1', 'error2'])
|
|
||||||
;
|
|
||||||
$this->container->sessionManager
|
|
||||||
->expects(static::once())
|
|
||||||
->method('setSessionParameter')
|
|
||||||
->with(SessionManager::KEY_ERROR_MESSAGES, ['error1', 'error2', $message = 'error!'])
|
|
||||||
;
|
|
||||||
|
|
||||||
$this->controller->saveErrorMessage($message);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,157 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace Shaarli\Front\Controller\Admin;
|
|
||||||
|
|
||||||
use Shaarli\Bookmark\Bookmark;
|
|
||||||
use Shaarli\Bookmark\Exception\BookmarkNotFoundException;
|
|
||||||
use Shaarli\Bookmark\SearchResult;
|
|
||||||
use Shaarli\TestCase;
|
|
||||||
use Shaarli\Thumbnailer;
|
|
||||||
use Slim\Http\Request;
|
|
||||||
use Slim\Http\Response;
|
|
||||||
|
|
||||||
class ThumbnailsControllerTest extends TestCase
|
|
||||||
{
|
|
||||||
use FrontAdminControllerMockHelper;
|
|
||||||
|
|
||||||
/** @var ThumbnailsController */
|
|
||||||
protected $controller;
|
|
||||||
|
|
||||||
public function setUp(): void
|
|
||||||
{
|
|
||||||
$this->createContainer();
|
|
||||||
|
|
||||||
$this->controller = new ThumbnailsController($this->container);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test displaying the thumbnails update page
|
|
||||||
* Note that only non-note and HTTP bookmarks should be returned.
|
|
||||||
*/
|
|
||||||
public function testIndex(): void
|
|
||||||
{
|
|
||||||
$assignedVariables = [];
|
|
||||||
$this->assignTemplateVars($assignedVariables);
|
|
||||||
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
$this->container->bookmarkService
|
|
||||||
->expects(static::once())
|
|
||||||
->method('search')
|
|
||||||
->willReturn(SearchResult::getSearchResult([
|
|
||||||
(new Bookmark())->setId(1)->setUrl('http://url1.tld')->setTitle('Title 1'),
|
|
||||||
(new Bookmark())->setId(2)->setUrl('?abcdef')->setTitle('Note 1'),
|
|
||||||
(new Bookmark())->setId(3)->setUrl('http://url2.tld')->setTitle('Title 2'),
|
|
||||||
(new Bookmark())->setId(4)->setUrl('ftp://domain.tld', ['ftp'])->setTitle('FTP'),
|
|
||||||
]))
|
|
||||||
;
|
|
||||||
|
|
||||||
$result = $this->controller->index($request, $response);
|
|
||||||
|
|
||||||
static::assertSame(200, $result->getStatusCode());
|
|
||||||
static::assertSame('thumbnails', (string) $result->getBody());
|
|
||||||
|
|
||||||
static::assertSame('Thumbnails update - Shaarli', $assignedVariables['pagetitle']);
|
|
||||||
static::assertSame([1, 3], $assignedVariables['ids']);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test updating a bookmark thumbnail with valid parameters
|
|
||||||
*/
|
|
||||||
public function testAjaxUpdateValid(): void
|
|
||||||
{
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
$bookmark = (new Bookmark())
|
|
||||||
->setId($id = 123)
|
|
||||||
->setUrl($url = 'http://url1.tld')
|
|
||||||
->setTitle('Title 1')
|
|
||||||
->setThumbnail(false)
|
|
||||||
;
|
|
||||||
|
|
||||||
$this->container->thumbnailer = $this->createMock(Thumbnailer::class);
|
|
||||||
$this->container->thumbnailer
|
|
||||||
->expects(static::once())
|
|
||||||
->method('get')
|
|
||||||
->with($url)
|
|
||||||
->willReturn($thumb = 'http://img.tld/pic.png')
|
|
||||||
;
|
|
||||||
|
|
||||||
$this->container->bookmarkService
|
|
||||||
->expects(static::once())
|
|
||||||
->method('get')
|
|
||||||
->with($id)
|
|
||||||
->willReturn($bookmark)
|
|
||||||
;
|
|
||||||
$this->container->bookmarkService
|
|
||||||
->expects(static::once())
|
|
||||||
->method('set')
|
|
||||||
->willReturnCallback(function (Bookmark $bookmark) use ($thumb): Bookmark {
|
|
||||||
static::assertSame($thumb, $bookmark->getThumbnail());
|
|
||||||
|
|
||||||
return $bookmark;
|
|
||||||
})
|
|
||||||
;
|
|
||||||
|
|
||||||
$result = $this->controller->ajaxUpdate($request, $response, ['id' => (string) $id]);
|
|
||||||
|
|
||||||
static::assertSame(200, $result->getStatusCode());
|
|
||||||
|
|
||||||
$payload = json_decode((string) $result->getBody(), true);
|
|
||||||
|
|
||||||
static::assertSame($id, $payload['id']);
|
|
||||||
static::assertSame($url, $payload['url']);
|
|
||||||
static::assertSame($thumb, $payload['thumbnail']);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test updating a bookmark thumbnail - Invalid ID
|
|
||||||
*/
|
|
||||||
public function testAjaxUpdateInvalidId(): void
|
|
||||||
{
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
$result = $this->controller->ajaxUpdate($request, $response, ['id' => 'nope']);
|
|
||||||
|
|
||||||
static::assertSame(400, $result->getStatusCode());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test updating a bookmark thumbnail - No ID
|
|
||||||
*/
|
|
||||||
public function testAjaxUpdateNoId(): void
|
|
||||||
{
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
$result = $this->controller->ajaxUpdate($request, $response, []);
|
|
||||||
|
|
||||||
static::assertSame(400, $result->getStatusCode());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test updating a bookmark thumbnail with valid parameters
|
|
||||||
*/
|
|
||||||
public function testAjaxUpdateBookmarkNotFound(): void
|
|
||||||
{
|
|
||||||
$id = 123;
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
$this->container->bookmarkService
|
|
||||||
->expects(static::once())
|
|
||||||
->method('get')
|
|
||||||
->with($id)
|
|
||||||
->willThrowException(new BookmarkNotFoundException())
|
|
||||||
;
|
|
||||||
|
|
||||||
$result = $this->controller->ajaxUpdate($request, $response, ['id' => (string) $id]);
|
|
||||||
|
|
||||||
static::assertSame(404, $result->getStatusCode());
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,41 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace Shaarli\Front\Controller\Admin;
|
|
||||||
|
|
||||||
use Shaarli\TestCase;
|
|
||||||
use Slim\Http\Request;
|
|
||||||
use Slim\Http\Response;
|
|
||||||
|
|
||||||
class TokenControllerTest extends TestCase
|
|
||||||
{
|
|
||||||
use FrontAdminControllerMockHelper;
|
|
||||||
|
|
||||||
/** @var TokenController */
|
|
||||||
protected $controller;
|
|
||||||
|
|
||||||
public function setUp(): void
|
|
||||||
{
|
|
||||||
$this->createContainer();
|
|
||||||
|
|
||||||
$this->controller = new TokenController($this->container);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testGetToken(): void
|
|
||||||
{
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
$this->container->sessionManager
|
|
||||||
->expects(static::once())
|
|
||||||
->method('generateToken')
|
|
||||||
->willReturn($token = 'token1234')
|
|
||||||
;
|
|
||||||
|
|
||||||
$result = $this->controller->getToken($request, $response);
|
|
||||||
|
|
||||||
static::assertSame(200, $result->getStatusCode());
|
|
||||||
static::assertSame($token, (string) $result->getBody());
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,69 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace Shaarli\Front\Controller\Admin;
|
|
||||||
|
|
||||||
use Shaarli\TestCase;
|
|
||||||
use Slim\Http\Request;
|
|
||||||
use Slim\Http\Response;
|
|
||||||
|
|
||||||
class ToolsControllerTest extends TestCase
|
|
||||||
{
|
|
||||||
use FrontAdminControllerMockHelper;
|
|
||||||
|
|
||||||
/** @var ToolsController */
|
|
||||||
protected $controller;
|
|
||||||
|
|
||||||
public function setUp(): void
|
|
||||||
{
|
|
||||||
$this->createContainer();
|
|
||||||
|
|
||||||
$this->controller = new ToolsController($this->container);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testDefaultInvokeWithHttps(): void
|
|
||||||
{
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
$this->container->environment = [
|
|
||||||
'SERVER_NAME' => 'shaarli',
|
|
||||||
'SERVER_PORT' => 443,
|
|
||||||
'HTTPS' => 'on',
|
|
||||||
];
|
|
||||||
|
|
||||||
// Save RainTPL assigned variables
|
|
||||||
$assignedVariables = [];
|
|
||||||
$this->assignTemplateVars($assignedVariables);
|
|
||||||
|
|
||||||
$result = $this->controller->index($request, $response);
|
|
||||||
|
|
||||||
static::assertSame(200, $result->getStatusCode());
|
|
||||||
static::assertSame('tools', (string) $result->getBody());
|
|
||||||
static::assertSame('https://shaarli/', $assignedVariables['pageabsaddr']);
|
|
||||||
static::assertTrue($assignedVariables['sslenabled']);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testDefaultInvokeWithoutHttps(): void
|
|
||||||
{
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
$this->container->environment = [
|
|
||||||
'SERVER_NAME' => 'shaarli',
|
|
||||||
'SERVER_PORT' => 80,
|
|
||||||
];
|
|
||||||
|
|
||||||
// Save RainTPL assigned variables
|
|
||||||
$assignedVariables = [];
|
|
||||||
$this->assignTemplateVars($assignedVariables);
|
|
||||||
|
|
||||||
$result = $this->controller->index($request, $response);
|
|
||||||
|
|
||||||
static::assertSame(200, $result->getStatusCode());
|
|
||||||
static::assertSame('tools', (string) $result->getBody());
|
|
||||||
static::assertSame('http://shaarli/', $assignedVariables['pageabsaddr']);
|
|
||||||
static::assertFalse($assignedVariables['sslenabled']);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,538 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace Shaarli\Front\Controller\Visitor;
|
|
||||||
|
|
||||||
use Shaarli\Bookmark\Bookmark;
|
|
||||||
use Shaarli\Bookmark\Exception\BookmarkNotFoundException;
|
|
||||||
use Shaarli\Bookmark\SearchResult;
|
|
||||||
use Shaarli\Config\ConfigManager;
|
|
||||||
use Shaarli\Security\LoginManager;
|
|
||||||
use Shaarli\TestCase;
|
|
||||||
use Shaarli\Thumbnailer;
|
|
||||||
use Slim\Http\Request;
|
|
||||||
use Slim\Http\Response;
|
|
||||||
|
|
||||||
class BookmarkListControllerTest extends TestCase
|
|
||||||
{
|
|
||||||
use FrontControllerMockHelper;
|
|
||||||
|
|
||||||
/** @var BookmarkListController */
|
|
||||||
protected $controller;
|
|
||||||
|
|
||||||
public function setUp(): void
|
|
||||||
{
|
|
||||||
$this->createContainer();
|
|
||||||
|
|
||||||
$this->controller = new BookmarkListController($this->container);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test rendering list of bookmarks with default parameters (first page).
|
|
||||||
*/
|
|
||||||
public function testIndexDefaultFirstPage(): void
|
|
||||||
{
|
|
||||||
$assignedVariables = [];
|
|
||||||
$this->assignTemplateVars($assignedVariables);
|
|
||||||
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
$this->container->bookmarkService
|
|
||||||
->expects(static::once())
|
|
||||||
->method('search')
|
|
||||||
->with(
|
|
||||||
['searchtags' => '', 'searchterm' => ''],
|
|
||||||
null,
|
|
||||||
false,
|
|
||||||
false,
|
|
||||||
false,
|
|
||||||
['offset' => 0, 'limit' => 2]
|
|
||||||
)
|
|
||||||
->willReturn(SearchResult::getSearchResult([
|
|
||||||
(new Bookmark())->setId(1)->setUrl('http://url1.tld')->setTitle('Title 1'),
|
|
||||||
(new Bookmark())->setId(2)->setUrl('http://url2.tld')->setTitle('Title 2'),
|
|
||||||
(new Bookmark())->setId(3)->setUrl('http://url3.tld')->setTitle('Title 3'),
|
|
||||||
], 0, 2));
|
|
||||||
|
|
||||||
$this->container->sessionManager
|
|
||||||
->method('getSessionParameter')
|
|
||||||
->willReturnCallback(function (string $parameter, $default = null) {
|
|
||||||
if ('LINKS_PER_PAGE' === $parameter) {
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $default;
|
|
||||||
})
|
|
||||||
;
|
|
||||||
|
|
||||||
$result = $this->controller->index($request, $response);
|
|
||||||
|
|
||||||
static::assertSame(200, $result->getStatusCode());
|
|
||||||
static::assertSame('linklist', (string) $result->getBody());
|
|
||||||
|
|
||||||
static::assertSame('Shaarli', $assignedVariables['pagetitle']);
|
|
||||||
static::assertSame('?page=2', $assignedVariables['previous_page_url']);
|
|
||||||
static::assertSame('', $assignedVariables['next_page_url']);
|
|
||||||
static::assertSame(2, $assignedVariables['page_max']);
|
|
||||||
static::assertSame('', $assignedVariables['search_tags']);
|
|
||||||
static::assertSame(3, $assignedVariables['result_count']);
|
|
||||||
static::assertSame(1, $assignedVariables['page_current']);
|
|
||||||
static::assertSame('', $assignedVariables['search_term']);
|
|
||||||
static::assertNull($assignedVariables['visibility']);
|
|
||||||
static::assertCount(2, $assignedVariables['links']);
|
|
||||||
|
|
||||||
$link = $assignedVariables['links'][0];
|
|
||||||
|
|
||||||
static::assertSame(1, $link['id']);
|
|
||||||
static::assertSame('http://url1.tld', $link['url']);
|
|
||||||
static::assertSame('Title 1', $link['title']);
|
|
||||||
|
|
||||||
$link = $assignedVariables['links'][1];
|
|
||||||
|
|
||||||
static::assertSame(2, $link['id']);
|
|
||||||
static::assertSame('http://url2.tld', $link['url']);
|
|
||||||
static::assertSame('Title 2', $link['title']);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test rendering list of bookmarks with default parameters (second page).
|
|
||||||
*/
|
|
||||||
public function testIndexDefaultSecondPage(): void
|
|
||||||
{
|
|
||||||
$assignedVariables = [];
|
|
||||||
$this->assignTemplateVars($assignedVariables);
|
|
||||||
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$request->method('getParam')->willReturnCallback(function (string $key) {
|
|
||||||
if ('page' === $key) {
|
|
||||||
return '2';
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
});
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
$this->container->bookmarkService
|
|
||||||
->expects(static::once())
|
|
||||||
->method('search')
|
|
||||||
->with(
|
|
||||||
['searchtags' => '', 'searchterm' => ''],
|
|
||||||
null,
|
|
||||||
false,
|
|
||||||
false,
|
|
||||||
false,
|
|
||||||
['offset' => 2, 'limit' => 2]
|
|
||||||
)
|
|
||||||
->willReturn(SearchResult::getSearchResult([
|
|
||||||
(new Bookmark())->setId(1)->setUrl('http://url1.tld')->setTitle('Title 1'),
|
|
||||||
(new Bookmark())->setId(2)->setUrl('http://url2.tld')->setTitle('Title 2'),
|
|
||||||
(new Bookmark())->setId(3)->setUrl('http://url3.tld')->setTitle('Title 3'),
|
|
||||||
], 2, 2))
|
|
||||||
;
|
|
||||||
|
|
||||||
$this->container->sessionManager
|
|
||||||
->method('getSessionParameter')
|
|
||||||
->willReturnCallback(function (string $parameter, $default = null) {
|
|
||||||
if ('LINKS_PER_PAGE' === $parameter) {
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $default;
|
|
||||||
})
|
|
||||||
;
|
|
||||||
|
|
||||||
$result = $this->controller->index($request, $response);
|
|
||||||
|
|
||||||
static::assertSame(200, $result->getStatusCode());
|
|
||||||
static::assertSame('linklist', (string) $result->getBody());
|
|
||||||
|
|
||||||
static::assertSame('Shaarli', $assignedVariables['pagetitle']);
|
|
||||||
static::assertSame('', $assignedVariables['previous_page_url']);
|
|
||||||
static::assertSame('?page=1', $assignedVariables['next_page_url']);
|
|
||||||
static::assertSame(2, $assignedVariables['page_max']);
|
|
||||||
static::assertSame('', $assignedVariables['search_tags']);
|
|
||||||
static::assertSame(3, $assignedVariables['result_count']);
|
|
||||||
static::assertSame(2, $assignedVariables['page_current']);
|
|
||||||
static::assertSame('', $assignedVariables['search_term']);
|
|
||||||
static::assertNull($assignedVariables['visibility']);
|
|
||||||
static::assertCount(1, $assignedVariables['links']);
|
|
||||||
|
|
||||||
$link = $assignedVariables['links'][2];
|
|
||||||
|
|
||||||
static::assertSame(3, $link['id']);
|
|
||||||
static::assertSame('http://url3.tld', $link['url']);
|
|
||||||
static::assertSame('Title 3', $link['title']);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test rendering list of bookmarks with filters.
|
|
||||||
*/
|
|
||||||
public function testIndexDefaultWithFilters(): void
|
|
||||||
{
|
|
||||||
$assignedVariables = [];
|
|
||||||
$this->assignTemplateVars($assignedVariables);
|
|
||||||
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$request->method('getParam')->willReturnCallback(function (string $key) {
|
|
||||||
if ('searchtags' === $key) {
|
|
||||||
return 'abc@def';
|
|
||||||
}
|
|
||||||
if ('searchterm' === $key) {
|
|
||||||
return 'ghi jkl';
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
});
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
$this->container->sessionManager
|
|
||||||
->method('getSessionParameter')
|
|
||||||
->willReturnCallback(function (string $key, $default) {
|
|
||||||
if ('LINKS_PER_PAGE' === $key) {
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
if ('visibility' === $key) {
|
|
||||||
return 'private';
|
|
||||||
}
|
|
||||||
if ('untaggedonly' === $key) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $default;
|
|
||||||
})
|
|
||||||
;
|
|
||||||
|
|
||||||
$this->container->bookmarkService
|
|
||||||
->expects(static::once())
|
|
||||||
->method('search')
|
|
||||||
->with(
|
|
||||||
['searchtags' => 'abc@def', 'searchterm' => 'ghi jkl'],
|
|
||||||
'private',
|
|
||||||
false,
|
|
||||||
true,
|
|
||||||
false,
|
|
||||||
['offset' => 0, 'limit' => 2]
|
|
||||||
)
|
|
||||||
->willReturn(SearchResult::getSearchResult([
|
|
||||||
(new Bookmark())->setId(1)->setUrl('http://url1.tld')->setTitle('Title 1'),
|
|
||||||
(new Bookmark())->setId(2)->setUrl('http://url2.tld')->setTitle('Title 2'),
|
|
||||||
(new Bookmark())->setId(3)->setUrl('http://url3.tld')->setTitle('Title 3'),
|
|
||||||
], 0, 2))
|
|
||||||
;
|
|
||||||
|
|
||||||
$result = $this->controller->index($request, $response);
|
|
||||||
|
|
||||||
static::assertSame(200, $result->getStatusCode());
|
|
||||||
static::assertSame('linklist', (string) $result->getBody());
|
|
||||||
|
|
||||||
static::assertSame('Search: ghi jkl [abc] [def] - Shaarli', $assignedVariables['pagetitle']);
|
|
||||||
static::assertSame('?page=2&searchterm=ghi+jkl&searchtags=abc%40def', $assignedVariables['previous_page_url']);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test displaying a permalink with valid parameters
|
|
||||||
*/
|
|
||||||
public function testPermalinkValid(): void
|
|
||||||
{
|
|
||||||
$hash = 'abcdef';
|
|
||||||
|
|
||||||
$assignedVariables = [];
|
|
||||||
$this->assignTemplateVars($assignedVariables);
|
|
||||||
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
$this->container->bookmarkService
|
|
||||||
->expects(static::once())
|
|
||||||
->method('findByHash')
|
|
||||||
->with($hash)
|
|
||||||
->willReturn((new Bookmark())->setId(123)->setTitle('Title 1')->setUrl('http://url1.tld'))
|
|
||||||
;
|
|
||||||
|
|
||||||
$result = $this->controller->permalink($request, $response, ['hash' => $hash]);
|
|
||||||
|
|
||||||
static::assertSame(200, $result->getStatusCode());
|
|
||||||
static::assertSame('linklist', (string) $result->getBody());
|
|
||||||
|
|
||||||
static::assertSame('Title 1 - Shaarli', $assignedVariables['pagetitle']);
|
|
||||||
static::assertCount(1, $assignedVariables['links']);
|
|
||||||
|
|
||||||
$link = $assignedVariables['links'][0];
|
|
||||||
|
|
||||||
static::assertSame(123, $link['id']);
|
|
||||||
static::assertSame('http://url1.tld', $link['url']);
|
|
||||||
static::assertSame('Title 1', $link['title']);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test displaying a permalink with an unknown small hash : renders a 404 template error
|
|
||||||
*/
|
|
||||||
public function testPermalinkNotFound(): void
|
|
||||||
{
|
|
||||||
$hash = 'abcdef';
|
|
||||||
|
|
||||||
$assignedVariables = [];
|
|
||||||
$this->assignTemplateVars($assignedVariables);
|
|
||||||
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
$this->container->bookmarkService
|
|
||||||
->expects(static::once())
|
|
||||||
->method('findByHash')
|
|
||||||
->with($hash)
|
|
||||||
->willThrowException(new BookmarkNotFoundException())
|
|
||||||
;
|
|
||||||
|
|
||||||
$result = $this->controller->permalink($request, $response, ['hash' => $hash]);
|
|
||||||
|
|
||||||
static::assertSame(200, $result->getStatusCode());
|
|
||||||
static::assertSame('404', (string) $result->getBody());
|
|
||||||
|
|
||||||
static::assertSame(
|
|
||||||
'The link you are trying to reach does not exist or has been deleted.',
|
|
||||||
$assignedVariables['error_message']
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test GET /shaare/{hash}?key={key} - Find a link by hash using a private link.
|
|
||||||
*/
|
|
||||||
public function testPermalinkWithPrivateKey(): void
|
|
||||||
{
|
|
||||||
$hash = 'abcdef';
|
|
||||||
$privateKey = 'this is a private key';
|
|
||||||
|
|
||||||
$assignedVariables = [];
|
|
||||||
$this->assignTemplateVars($assignedVariables);
|
|
||||||
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$request->method('getParam')->willReturnCallback(function (string $key, $default = null) use ($privateKey) {
|
|
||||||
return $key === 'key' ? $privateKey : $default;
|
|
||||||
});
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
$this->container->bookmarkService
|
|
||||||
->expects(static::once())
|
|
||||||
->method('findByHash')
|
|
||||||
->with($hash, $privateKey)
|
|
||||||
->willReturn((new Bookmark())->setId(123)->setTitle('Title 1')->setUrl('http://url1.tld'))
|
|
||||||
;
|
|
||||||
|
|
||||||
$result = $this->controller->permalink($request, $response, ['hash' => $hash]);
|
|
||||||
|
|
||||||
static::assertSame(200, $result->getStatusCode());
|
|
||||||
static::assertSame('linklist', (string) $result->getBody());
|
|
||||||
static::assertCount(1, $assignedVariables['links']);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test getting link list with thumbnail updates.
|
|
||||||
* -> 2 thumbnails update, only 1 datastore write
|
|
||||||
*/
|
|
||||||
public function testThumbnailUpdateFromLinkList(): void
|
|
||||||
{
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
$this->container->loginManager = $this->createMock(LoginManager::class);
|
|
||||||
$this->container->loginManager->method('isLoggedIn')->willReturn(true);
|
|
||||||
|
|
||||||
$this->container->conf = $this->createMock(ConfigManager::class);
|
|
||||||
$this->container->conf
|
|
||||||
->method('get')
|
|
||||||
->willReturnCallback(function (string $key, $default) {
|
|
||||||
if ($key === 'thumbnails.mode') {
|
|
||||||
return Thumbnailer::MODE_ALL;
|
|
||||||
} elseif ($key === 'general.enable_async_metadata') {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $default;
|
|
||||||
})
|
|
||||||
;
|
|
||||||
|
|
||||||
$this->container->thumbnailer = $this->createMock(Thumbnailer::class);
|
|
||||||
$this->container->thumbnailer
|
|
||||||
->expects(static::exactly(2))
|
|
||||||
->method('get')
|
|
||||||
->withConsecutive(['https://url2.tld'], ['https://url4.tld'])
|
|
||||||
;
|
|
||||||
|
|
||||||
$this->container->bookmarkService
|
|
||||||
->expects(static::once())
|
|
||||||
->method('search')
|
|
||||||
->willReturn(SearchResult::getSearchResult([
|
|
||||||
(new Bookmark())->setId(1)->setUrl('https://url1.tld')->setTitle('Title 1')->setThumbnail(false),
|
|
||||||
$b1 = (new Bookmark())->setId(2)->setUrl('https://url2.tld')->setTitle('Title 2'),
|
|
||||||
(new Bookmark())->setId(3)->setUrl('https://url3.tld')->setTitle('Title 3')->setThumbnail(false),
|
|
||||||
$b2 = (new Bookmark())->setId(2)->setUrl('https://url4.tld')->setTitle('Title 4'),
|
|
||||||
(new Bookmark())->setId(2)->setUrl('ftp://url5.tld', ['ftp'])->setTitle('Title 5'),
|
|
||||||
]))
|
|
||||||
;
|
|
||||||
$this->container->bookmarkService
|
|
||||||
->expects(static::exactly(2))
|
|
||||||
->method('set')
|
|
||||||
->withConsecutive([$b1, false], [$b2, false])
|
|
||||||
;
|
|
||||||
$this->container->bookmarkService->expects(static::once())->method('save');
|
|
||||||
|
|
||||||
$result = $this->controller->index($request, $response);
|
|
||||||
|
|
||||||
static::assertSame(200, $result->getStatusCode());
|
|
||||||
static::assertSame('linklist', (string) $result->getBody());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test getting a permalink with thumbnail update.
|
|
||||||
*/
|
|
||||||
public function testThumbnailUpdateFromPermalink(): void
|
|
||||||
{
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
$this->container->loginManager = $this->createMock(LoginManager::class);
|
|
||||||
$this->container->loginManager->method('isLoggedIn')->willReturn(true);
|
|
||||||
|
|
||||||
$this->container->conf = $this->createMock(ConfigManager::class);
|
|
||||||
$this->container->conf
|
|
||||||
->method('get')
|
|
||||||
->willReturnCallback(function (string $key, $default) {
|
|
||||||
if ($key === 'thumbnails.mode') {
|
|
||||||
return Thumbnailer::MODE_ALL;
|
|
||||||
} elseif ($key === 'general.enable_async_metadata') {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $default;
|
|
||||||
})
|
|
||||||
;
|
|
||||||
|
|
||||||
$this->container->thumbnailer = $this->createMock(Thumbnailer::class);
|
|
||||||
$this->container->thumbnailer->expects(static::once())->method('get')->withConsecutive(['https://url.tld']);
|
|
||||||
|
|
||||||
$this->container->bookmarkService
|
|
||||||
->expects(static::once())
|
|
||||||
->method('findByHash')
|
|
||||||
->willReturn($bookmark = (new Bookmark())->setId(2)->setUrl('https://url.tld')->setTitle('Title 1'))
|
|
||||||
;
|
|
||||||
$this->container->bookmarkService->expects(static::once())->method('set')->with($bookmark, true);
|
|
||||||
$this->container->bookmarkService->expects(static::never())->method('save');
|
|
||||||
|
|
||||||
$result = $this->controller->permalink($request, $response, ['hash' => 'abc']);
|
|
||||||
|
|
||||||
static::assertSame(200, $result->getStatusCode());
|
|
||||||
static::assertSame('linklist', (string) $result->getBody());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test getting a permalink with thumbnail update with async setting: no update should run.
|
|
||||||
*/
|
|
||||||
public function testThumbnailUpdateFromPermalinkAsync(): void
|
|
||||||
{
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
$this->container->loginManager = $this->createMock(LoginManager::class);
|
|
||||||
$this->container->loginManager->method('isLoggedIn')->willReturn(true);
|
|
||||||
|
|
||||||
$this->container->conf = $this->createMock(ConfigManager::class);
|
|
||||||
$this->container->conf
|
|
||||||
->method('get')
|
|
||||||
->willReturnCallback(function (string $key, $default) {
|
|
||||||
if ($key === 'thumbnails.mode') {
|
|
||||||
return Thumbnailer::MODE_ALL;
|
|
||||||
} elseif ($key === 'general.enable_async_metadata') {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $default;
|
|
||||||
})
|
|
||||||
;
|
|
||||||
|
|
||||||
$this->container->thumbnailer = $this->createMock(Thumbnailer::class);
|
|
||||||
$this->container->thumbnailer->expects(static::never())->method('get');
|
|
||||||
|
|
||||||
$this->container->bookmarkService
|
|
||||||
->expects(static::once())
|
|
||||||
->method('findByHash')
|
|
||||||
->willReturn((new Bookmark())->setId(2)->setUrl('https://url.tld')->setTitle('Title 1'))
|
|
||||||
;
|
|
||||||
$this->container->bookmarkService->expects(static::never())->method('set');
|
|
||||||
$this->container->bookmarkService->expects(static::never())->method('save');
|
|
||||||
|
|
||||||
$result = $this->controller->permalink($request, $response, ['hash' => 'abc']);
|
|
||||||
|
|
||||||
static::assertSame(200, $result->getStatusCode());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Trigger legacy controller in link list controller: permalink
|
|
||||||
*/
|
|
||||||
public function testLegacyControllerPermalink(): void
|
|
||||||
{
|
|
||||||
$hash = 'abcdef';
|
|
||||||
$this->container->environment['QUERY_STRING'] = $hash;
|
|
||||||
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
$result = $this->controller->index($request, $response);
|
|
||||||
|
|
||||||
static::assertSame(302, $result->getStatusCode());
|
|
||||||
static::assertSame('/subfolder/shaare/' . $hash, $result->getHeader('location')[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Trigger legacy controller in link list controller: ?do= query parameter
|
|
||||||
*/
|
|
||||||
public function testLegacyControllerDoPage(): void
|
|
||||||
{
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$request->method('getQueryParam')->with('do')->willReturn('picwall');
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
$result = $this->controller->index($request, $response);
|
|
||||||
|
|
||||||
static::assertSame(302, $result->getStatusCode());
|
|
||||||
static::assertSame('/subfolder/picture-wall', $result->getHeader('location')[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Trigger legacy controller in link list controller: ?do= query parameter with unknown legacy route
|
|
||||||
*/
|
|
||||||
public function testLegacyControllerUnknownDoPage(): void
|
|
||||||
{
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$request->method('getQueryParam')->with('do')->willReturn('nope');
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
$result = $this->controller->index($request, $response);
|
|
||||||
|
|
||||||
static::assertSame(200, $result->getStatusCode());
|
|
||||||
static::assertSame('linklist', (string) $result->getBody());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Trigger legacy controller in link list controller: other GET route (e.g. ?post)
|
|
||||||
*/
|
|
||||||
public function testLegacyControllerGetParameter(): void
|
|
||||||
{
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$request->method('getQueryParams')->willReturn(['post' => $url = 'http://url.tld']);
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
$this->container->loginManager = $this->createMock(LoginManager::class);
|
|
||||||
$this->container->loginManager->method('isLoggedIn')->willReturn(true);
|
|
||||||
|
|
||||||
$result = $this->controller->index($request, $response);
|
|
||||||
|
|
||||||
static::assertSame(302, $result->getStatusCode());
|
|
||||||
static::assertSame(
|
|
||||||
'/subfolder/admin/shaare?post=' . urlencode($url),
|
|
||||||
$result->getHeader('location')[0]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,726 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace Shaarli\Front\Controller\Visitor;
|
|
||||||
|
|
||||||
use Shaarli\Bookmark\Bookmark;
|
|
||||||
use Shaarli\Bookmark\SearchResult;
|
|
||||||
use Shaarli\Feed\CachedPage;
|
|
||||||
use Shaarli\TestCase;
|
|
||||||
use Slim\Http\Request;
|
|
||||||
use Slim\Http\Response;
|
|
||||||
|
|
||||||
class DailyControllerTest extends TestCase
|
|
||||||
{
|
|
||||||
use FrontControllerMockHelper;
|
|
||||||
|
|
||||||
/** @var DailyController */
|
|
||||||
protected $controller;
|
|
||||||
|
|
||||||
public function setUp(): void
|
|
||||||
{
|
|
||||||
$this->createContainer();
|
|
||||||
|
|
||||||
$this->controller = new DailyController($this->container);
|
|
||||||
DailyController::$DAILY_RSS_NB_DAYS = 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testValidIndexControllerInvokeDefault(): void
|
|
||||||
{
|
|
||||||
$currentDay = new \DateTimeImmutable('2020-05-13');
|
|
||||||
$previousDate = new \DateTime('2 days ago 00:00:00');
|
|
||||||
$nextDate = new \DateTime('today 00:00:00');
|
|
||||||
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$request->method('getQueryParam')->willReturnCallback(function (string $key) use ($currentDay): ?string {
|
|
||||||
return $key === 'day' ? $currentDay->format('Ymd') : null;
|
|
||||||
});
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
// Save RainTPL assigned variables
|
|
||||||
$assignedVariables = [];
|
|
||||||
$this->assignTemplateVars($assignedVariables);
|
|
||||||
|
|
||||||
$this->container->bookmarkService
|
|
||||||
->expects(static::once())
|
|
||||||
->method('findByDate')
|
|
||||||
->willReturnCallback(
|
|
||||||
function ($from, $to, &$previous, &$next) use ($currentDay, $previousDate, $nextDate): array {
|
|
||||||
$previous = $previousDate;
|
|
||||||
$next = $nextDate;
|
|
||||||
|
|
||||||
return [
|
|
||||||
(new Bookmark())
|
|
||||||
->setId(1)
|
|
||||||
->setUrl('http://url.tld')
|
|
||||||
->setTitle(static::generateString(50))
|
|
||||||
->setDescription(static::generateString(500))
|
|
||||||
,
|
|
||||||
(new Bookmark())
|
|
||||||
->setId(2)
|
|
||||||
->setUrl('http://url2.tld')
|
|
||||||
->setTitle(static::generateString(50))
|
|
||||||
->setDescription(static::generateString(500))
|
|
||||||
,
|
|
||||||
(new Bookmark())
|
|
||||||
->setId(3)
|
|
||||||
->setUrl('http://url3.tld')
|
|
||||||
->setTitle(static::generateString(50))
|
|
||||||
->setDescription(static::generateString(500))
|
|
||||||
,
|
|
||||||
];
|
|
||||||
}
|
|
||||||
)
|
|
||||||
;
|
|
||||||
|
|
||||||
// Make sure that PluginManager hook is triggered
|
|
||||||
$this->container->pluginManager
|
|
||||||
->expects(static::atLeastOnce())
|
|
||||||
->method('executeHooks')
|
|
||||||
->withConsecutive(['render_daily'])
|
|
||||||
->willReturnCallback(
|
|
||||||
function (string $hook, array $data, array $param) use ($currentDay, $previousDate, $nextDate): array {
|
|
||||||
if ('render_daily' === $hook) {
|
|
||||||
static::assertArrayHasKey('linksToDisplay', $data);
|
|
||||||
static::assertCount(3, $data['linksToDisplay']);
|
|
||||||
static::assertSame(1, $data['linksToDisplay'][0]['id']);
|
|
||||||
static::assertSame($currentDay->getTimestamp(), $data['day']);
|
|
||||||
static::assertSame($previousDate->format('Ymd'), $data['previousday']);
|
|
||||||
static::assertSame($nextDate->format('Ymd'), $data['nextday']);
|
|
||||||
|
|
||||||
static::assertArrayHasKey('loggedin', $param);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $data;
|
|
||||||
}
|
|
||||||
)
|
|
||||||
;
|
|
||||||
|
|
||||||
$result = $this->controller->index($request, $response);
|
|
||||||
|
|
||||||
static::assertSame(200, $result->getStatusCode());
|
|
||||||
static::assertSame('daily', (string) $result->getBody());
|
|
||||||
static::assertSame(
|
|
||||||
'Daily - ' . format_date($currentDay, false, true) . ' - Shaarli',
|
|
||||||
$assignedVariables['pagetitle']
|
|
||||||
);
|
|
||||||
static::assertEquals($currentDay, $assignedVariables['dayDate']);
|
|
||||||
static::assertEquals($currentDay->getTimestamp(), $assignedVariables['day']);
|
|
||||||
static::assertSame($previousDate->format('Ymd'), $assignedVariables['previousday']);
|
|
||||||
static::assertSame($nextDate->format('Ymd'), $assignedVariables['nextday']);
|
|
||||||
static::assertSame('day', $assignedVariables['type']);
|
|
||||||
static::assertSame('May 13, 2020', $assignedVariables['dayDesc']);
|
|
||||||
static::assertSame('Daily', $assignedVariables['localizedType']);
|
|
||||||
static::assertCount(3, $assignedVariables['linksToDisplay']);
|
|
||||||
|
|
||||||
$link = $assignedVariables['linksToDisplay'][0];
|
|
||||||
|
|
||||||
static::assertSame(1, $link['id']);
|
|
||||||
static::assertSame('http://url.tld', $link['url']);
|
|
||||||
static::assertNotEmpty($link['title']);
|
|
||||||
static::assertNotEmpty($link['description']);
|
|
||||||
static::assertNotEmpty($link['formatedDescription']);
|
|
||||||
|
|
||||||
$link = $assignedVariables['linksToDisplay'][1];
|
|
||||||
|
|
||||||
static::assertSame(2, $link['id']);
|
|
||||||
static::assertSame('http://url2.tld', $link['url']);
|
|
||||||
static::assertNotEmpty($link['title']);
|
|
||||||
static::assertNotEmpty($link['description']);
|
|
||||||
static::assertNotEmpty($link['formatedDescription']);
|
|
||||||
|
|
||||||
$link = $assignedVariables['linksToDisplay'][2];
|
|
||||||
|
|
||||||
static::assertSame(3, $link['id']);
|
|
||||||
static::assertSame('http://url3.tld', $link['url']);
|
|
||||||
static::assertNotEmpty($link['title']);
|
|
||||||
static::assertNotEmpty($link['description']);
|
|
||||||
static::assertNotEmpty($link['formatedDescription']);
|
|
||||||
|
|
||||||
static::assertCount(3, $assignedVariables['cols']);
|
|
||||||
static::assertCount(1, $assignedVariables['cols'][0]);
|
|
||||||
static::assertCount(1, $assignedVariables['cols'][1]);
|
|
||||||
static::assertCount(1, $assignedVariables['cols'][2]);
|
|
||||||
|
|
||||||
$link = $assignedVariables['cols'][0][0];
|
|
||||||
|
|
||||||
static::assertSame(1, $link['id']);
|
|
||||||
static::assertSame('http://url.tld', $link['url']);
|
|
||||||
static::assertNotEmpty($link['title']);
|
|
||||||
static::assertNotEmpty($link['description']);
|
|
||||||
static::assertNotEmpty($link['formatedDescription']);
|
|
||||||
|
|
||||||
$link = $assignedVariables['cols'][1][0];
|
|
||||||
|
|
||||||
static::assertSame(2, $link['id']);
|
|
||||||
static::assertSame('http://url2.tld', $link['url']);
|
|
||||||
static::assertNotEmpty($link['title']);
|
|
||||||
static::assertNotEmpty($link['description']);
|
|
||||||
static::assertNotEmpty($link['formatedDescription']);
|
|
||||||
|
|
||||||
$link = $assignedVariables['cols'][2][0];
|
|
||||||
|
|
||||||
static::assertSame(3, $link['id']);
|
|
||||||
static::assertSame('http://url3.tld', $link['url']);
|
|
||||||
static::assertNotEmpty($link['title']);
|
|
||||||
static::assertNotEmpty($link['description']);
|
|
||||||
static::assertNotEmpty($link['formatedDescription']);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Daily page - test that everything goes fine with no future or past bookmarks
|
|
||||||
*/
|
|
||||||
public function testValidIndexControllerInvokeNoFutureOrPast(): void
|
|
||||||
{
|
|
||||||
$currentDay = new \DateTimeImmutable('2020-05-13');
|
|
||||||
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$request->method('getQueryParam')->willReturnCallback(function (string $key) use ($currentDay): ?string {
|
|
||||||
return $key === 'day' ? $currentDay->format('Ymd') : null;
|
|
||||||
});
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
// Save RainTPL assigned variables
|
|
||||||
$assignedVariables = [];
|
|
||||||
$this->assignTemplateVars($assignedVariables);
|
|
||||||
|
|
||||||
$this->container->bookmarkService
|
|
||||||
->expects(static::once())
|
|
||||||
->method('findByDate')
|
|
||||||
->willReturnCallback(function () use ($currentDay): array {
|
|
||||||
return [
|
|
||||||
(new Bookmark())
|
|
||||||
->setId(1)
|
|
||||||
->setUrl('http://url.tld')
|
|
||||||
->setTitle(static::generateString(50))
|
|
||||||
->setDescription(static::generateString(500))
|
|
||||||
,
|
|
||||||
];
|
|
||||||
})
|
|
||||||
;
|
|
||||||
|
|
||||||
// Make sure that PluginManager hook is triggered
|
|
||||||
$this->container->pluginManager
|
|
||||||
->expects(static::atLeastOnce())
|
|
||||||
->method('executeHooks')
|
|
||||||
->withConsecutive(['render_daily'])
|
|
||||||
->willReturnCallback(function (string $hook, array $data, array $param) use ($currentDay): array {
|
|
||||||
if ('render_daily' === $hook) {
|
|
||||||
static::assertArrayHasKey('linksToDisplay', $data);
|
|
||||||
static::assertCount(1, $data['linksToDisplay']);
|
|
||||||
static::assertSame(1, $data['linksToDisplay'][0]['id']);
|
|
||||||
static::assertSame($currentDay->getTimestamp(), $data['day']);
|
|
||||||
static::assertEmpty($data['previousday']);
|
|
||||||
static::assertEmpty($data['nextday']);
|
|
||||||
|
|
||||||
static::assertArrayHasKey('loggedin', $param);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $data;
|
|
||||||
});
|
|
||||||
|
|
||||||
$result = $this->controller->index($request, $response);
|
|
||||||
|
|
||||||
static::assertSame(200, $result->getStatusCode());
|
|
||||||
static::assertSame('daily', (string) $result->getBody());
|
|
||||||
static::assertSame(
|
|
||||||
'Daily - ' . format_date($currentDay, false, true) . ' - Shaarli',
|
|
||||||
$assignedVariables['pagetitle']
|
|
||||||
);
|
|
||||||
static::assertCount(1, $assignedVariables['linksToDisplay']);
|
|
||||||
|
|
||||||
$link = $assignedVariables['linksToDisplay'][0];
|
|
||||||
static::assertSame(1, $link['id']);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Daily page - test that height adjustment in columns is working
|
|
||||||
*/
|
|
||||||
public function testValidIndexControllerInvokeHeightAdjustment(): void
|
|
||||||
{
|
|
||||||
$currentDay = new \DateTimeImmutable('2020-05-13');
|
|
||||||
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
// Save RainTPL assigned variables
|
|
||||||
$assignedVariables = [];
|
|
||||||
$this->assignTemplateVars($assignedVariables);
|
|
||||||
|
|
||||||
$this->container->bookmarkService
|
|
||||||
->expects(static::once())
|
|
||||||
->method('findByDate')
|
|
||||||
->willReturnCallback(function () use ($currentDay): array {
|
|
||||||
return [
|
|
||||||
(new Bookmark())->setId(1)->setUrl('http://url.tld')->setTitle('title'),
|
|
||||||
(new Bookmark())
|
|
||||||
->setId(2)
|
|
||||||
->setUrl('http://url.tld')
|
|
||||||
->setTitle(static::generateString(50))
|
|
||||||
->setDescription(static::generateString(5000))
|
|
||||||
,
|
|
||||||
(new Bookmark())->setId(3)->setUrl('http://url.tld')->setTitle('title'),
|
|
||||||
(new Bookmark())->setId(4)->setUrl('http://url.tld')->setTitle('title'),
|
|
||||||
(new Bookmark())->setId(5)->setUrl('http://url.tld')->setTitle('title'),
|
|
||||||
(new Bookmark())->setId(6)->setUrl('http://url.tld')->setTitle('title'),
|
|
||||||
(new Bookmark())->setId(7)->setUrl('http://url.tld')->setTitle('title'),
|
|
||||||
];
|
|
||||||
})
|
|
||||||
;
|
|
||||||
|
|
||||||
// Make sure that PluginManager hook is triggered
|
|
||||||
$this->container->pluginManager
|
|
||||||
->expects(static::atLeastOnce())
|
|
||||||
->method('executeHooks')
|
|
||||||
->willReturnCallback(function (string $hook, array $data, array $param): array {
|
|
||||||
return $data;
|
|
||||||
})
|
|
||||||
;
|
|
||||||
|
|
||||||
$result = $this->controller->index($request, $response);
|
|
||||||
|
|
||||||
static::assertSame(200, $result->getStatusCode());
|
|
||||||
static::assertSame('daily', (string) $result->getBody());
|
|
||||||
static::assertCount(7, $assignedVariables['linksToDisplay']);
|
|
||||||
|
|
||||||
$columnIds = function (array $column): array {
|
|
||||||
return array_map(function (array $item): int {
|
|
||||||
return $item['id'];
|
|
||||||
}, $column);
|
|
||||||
};
|
|
||||||
|
|
||||||
static::assertSame([1, 4, 6], $columnIds($assignedVariables['cols'][0]));
|
|
||||||
static::assertSame([2], $columnIds($assignedVariables['cols'][1]));
|
|
||||||
static::assertSame([3, 5, 7], $columnIds($assignedVariables['cols'][2]));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Daily page - no bookmark
|
|
||||||
*/
|
|
||||||
public function testValidIndexControllerInvokeNoBookmark(): void
|
|
||||||
{
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
// Save RainTPL assigned variables
|
|
||||||
$assignedVariables = [];
|
|
||||||
$this->assignTemplateVars($assignedVariables);
|
|
||||||
|
|
||||||
// Links dataset: 2 links with thumbnails
|
|
||||||
$this->container->bookmarkService
|
|
||||||
->expects(static::once())
|
|
||||||
->method('findByDate')
|
|
||||||
->willReturnCallback(function (): array {
|
|
||||||
return [];
|
|
||||||
})
|
|
||||||
;
|
|
||||||
|
|
||||||
// Make sure that PluginManager hook is triggered
|
|
||||||
$this->container->pluginManager
|
|
||||||
->expects(static::atLeastOnce())
|
|
||||||
->method('executeHooks')
|
|
||||||
->willReturnCallback(function (string $hook, array $data, array $param): array {
|
|
||||||
return $data;
|
|
||||||
})
|
|
||||||
;
|
|
||||||
|
|
||||||
$result = $this->controller->index($request, $response);
|
|
||||||
|
|
||||||
static::assertSame(200, $result->getStatusCode());
|
|
||||||
static::assertSame('daily', (string) $result->getBody());
|
|
||||||
static::assertCount(0, $assignedVariables['linksToDisplay']);
|
|
||||||
static::assertSame('Today - ' . (new \DateTime())->format('F j, Y'), $assignedVariables['dayDesc']);
|
|
||||||
static::assertEquals((new \DateTime())->setTime(0, 0)->getTimestamp(), $assignedVariables['day']);
|
|
||||||
static::assertEquals((new \DateTime())->setTime(0, 0), $assignedVariables['dayDate']);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Daily RSS - default behaviour
|
|
||||||
*/
|
|
||||||
public function testValidRssControllerInvokeDefault(): void
|
|
||||||
{
|
|
||||||
$dates = [
|
|
||||||
new \DateTimeImmutable('2020-05-17'),
|
|
||||||
new \DateTimeImmutable('2020-05-15'),
|
|
||||||
new \DateTimeImmutable('2020-05-13'),
|
|
||||||
new \DateTimeImmutable('+1 month'),
|
|
||||||
];
|
|
||||||
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
$this->container->bookmarkService->expects(static::once())->method('search')->willReturn(
|
|
||||||
SearchResult::getSearchResult([
|
|
||||||
(new Bookmark())->setId(1)->setCreated($dates[0])->setUrl('http://domain.tld/1'),
|
|
||||||
(new Bookmark())->setId(2)->setCreated($dates[1])->setUrl('http://domain.tld/2'),
|
|
||||||
(new Bookmark())->setId(3)->setCreated($dates[1])->setUrl('http://domain.tld/3'),
|
|
||||||
(new Bookmark())->setId(4)->setCreated($dates[2])->setUrl('http://domain.tld/4'),
|
|
||||||
(new Bookmark())->setId(5)->setCreated($dates[3])->setUrl('http://domain.tld/5'),
|
|
||||||
])
|
|
||||||
);
|
|
||||||
|
|
||||||
$this->container->pageCacheManager
|
|
||||||
->expects(static::once())
|
|
||||||
->method('getCachePage')
|
|
||||||
->willReturnCallback(function (): CachedPage {
|
|
||||||
$cachedPage = $this->createMock(CachedPage::class);
|
|
||||||
$cachedPage->expects(static::once())->method('cache')->with('dailyrss');
|
|
||||||
|
|
||||||
return $cachedPage;
|
|
||||||
});
|
|
||||||
|
|
||||||
// Save RainTPL assigned variables
|
|
||||||
$assignedVariables = [];
|
|
||||||
$this->assignTemplateVars($assignedVariables);
|
|
||||||
|
|
||||||
$result = $this->controller->rss($request, $response);
|
|
||||||
|
|
||||||
static::assertSame(200, $result->getStatusCode());
|
|
||||||
static::assertStringContainsString('application/rss', $result->getHeader('Content-Type')[0]);
|
|
||||||
static::assertSame('dailyrss', (string) $result->getBody());
|
|
||||||
static::assertSame('Shaarli', $assignedVariables['title']);
|
|
||||||
static::assertSame('http://shaarli/subfolder/', $assignedVariables['index_url']);
|
|
||||||
static::assertSame('http://shaarli/subfolder/daily-rss', $assignedVariables['page_url']);
|
|
||||||
static::assertFalse($assignedVariables['hide_timestamps']);
|
|
||||||
static::assertCount(3, $assignedVariables['days']);
|
|
||||||
|
|
||||||
$day = $assignedVariables['days'][$dates[0]->format('Ymd')];
|
|
||||||
$date = $dates[0]->setTime(23, 59, 59);
|
|
||||||
|
|
||||||
static::assertEquals($date, $day['date']);
|
|
||||||
static::assertSame($date->format(\DateTime::RSS), $day['date_rss']);
|
|
||||||
static::assertSame(format_date($date, false), $day['date_human']);
|
|
||||||
static::assertSame('http://shaarli/subfolder/daily?day=' . $dates[0]->format('Ymd'), $day['absolute_url']);
|
|
||||||
static::assertCount(1, $day['links']);
|
|
||||||
static::assertSame(1, $day['links'][0]['id']);
|
|
||||||
static::assertSame('http://domain.tld/1', $day['links'][0]['url']);
|
|
||||||
static::assertEquals($dates[0], $day['links'][0]['created']);
|
|
||||||
|
|
||||||
$day = $assignedVariables['days'][$dates[1]->format('Ymd')];
|
|
||||||
$date = $dates[1]->setTime(23, 59, 59);
|
|
||||||
|
|
||||||
static::assertEquals($date, $day['date']);
|
|
||||||
static::assertSame($date->format(\DateTime::RSS), $day['date_rss']);
|
|
||||||
static::assertSame(format_date($date, false), $day['date_human']);
|
|
||||||
static::assertSame('http://shaarli/subfolder/daily?day=' . $dates[1]->format('Ymd'), $day['absolute_url']);
|
|
||||||
static::assertCount(2, $day['links']);
|
|
||||||
|
|
||||||
static::assertSame(2, $day['links'][0]['id']);
|
|
||||||
static::assertSame('http://domain.tld/2', $day['links'][0]['url']);
|
|
||||||
static::assertEquals($dates[1], $day['links'][0]['created']);
|
|
||||||
static::assertSame(3, $day['links'][1]['id']);
|
|
||||||
static::assertSame('http://domain.tld/3', $day['links'][1]['url']);
|
|
||||||
static::assertEquals($dates[1], $day['links'][1]['created']);
|
|
||||||
|
|
||||||
$day = $assignedVariables['days'][$dates[2]->format('Ymd')];
|
|
||||||
$date = $dates[2]->setTime(23, 59, 59);
|
|
||||||
|
|
||||||
static::assertEquals($date, $day['date']);
|
|
||||||
static::assertSame($date->format(\DateTime::RSS), $day['date_rss']);
|
|
||||||
static::assertSame(format_date($date, false), $day['date_human']);
|
|
||||||
static::assertSame('http://shaarli/subfolder/daily?day=' . $dates[2]->format('Ymd'), $day['absolute_url']);
|
|
||||||
static::assertCount(1, $day['links']);
|
|
||||||
static::assertSame(4, $day['links'][0]['id']);
|
|
||||||
static::assertSame('http://domain.tld/4', $day['links'][0]['url']);
|
|
||||||
static::assertEquals($dates[2], $day['links'][0]['created']);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Daily RSS - trigger cache rendering
|
|
||||||
*/
|
|
||||||
public function testValidRssControllerInvokeTriggerCache(): void
|
|
||||||
{
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
$this->container->pageCacheManager->method('getCachePage')->willReturnCallback(function (): CachedPage {
|
|
||||||
$cachedPage = $this->createMock(CachedPage::class);
|
|
||||||
$cachedPage->method('cachedVersion')->willReturn('this is cache!');
|
|
||||||
|
|
||||||
return $cachedPage;
|
|
||||||
});
|
|
||||||
|
|
||||||
$this->container->bookmarkService->expects(static::never())->method('search');
|
|
||||||
|
|
||||||
$result = $this->controller->rss($request, $response);
|
|
||||||
|
|
||||||
static::assertSame(200, $result->getStatusCode());
|
|
||||||
static::assertStringContainsString('application/rss', $result->getHeader('Content-Type')[0]);
|
|
||||||
static::assertSame('this is cache!', (string) $result->getBody());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Daily RSS - No bookmark
|
|
||||||
*/
|
|
||||||
public function testValidRssControllerInvokeNoBookmark(): void
|
|
||||||
{
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
$this->container->bookmarkService
|
|
||||||
->expects(static::once())->method('search')
|
|
||||||
->willReturn(SearchResult::getSearchResult([]));
|
|
||||||
|
|
||||||
// Save RainTPL assigned variables
|
|
||||||
$assignedVariables = [];
|
|
||||||
$this->assignTemplateVars($assignedVariables);
|
|
||||||
|
|
||||||
$result = $this->controller->rss($request, $response);
|
|
||||||
|
|
||||||
static::assertSame(200, $result->getStatusCode());
|
|
||||||
static::assertStringContainsString('application/rss', $result->getHeader('Content-Type')[0]);
|
|
||||||
static::assertSame('dailyrss', (string) $result->getBody());
|
|
||||||
static::assertSame('Shaarli', $assignedVariables['title']);
|
|
||||||
static::assertSame('http://shaarli/subfolder/', $assignedVariables['index_url']);
|
|
||||||
static::assertSame('http://shaarli/subfolder/daily-rss', $assignedVariables['page_url']);
|
|
||||||
static::assertFalse($assignedVariables['hide_timestamps']);
|
|
||||||
static::assertCount(0, $assignedVariables['days']);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test simple display index with week parameter
|
|
||||||
*/
|
|
||||||
public function testSimpleIndexWeekly(): void
|
|
||||||
{
|
|
||||||
$currentDay = new \DateTimeImmutable('2020-05-13');
|
|
||||||
$expectedDay = new \DateTimeImmutable('2020-05-11');
|
|
||||||
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$request->method('getQueryParam')->willReturnCallback(function (string $key) use ($currentDay): ?string {
|
|
||||||
return $key === 'week' ? $currentDay->format('YW') : null;
|
|
||||||
});
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
// Save RainTPL assigned variables
|
|
||||||
$assignedVariables = [];
|
|
||||||
$this->assignTemplateVars($assignedVariables);
|
|
||||||
|
|
||||||
$this->container->bookmarkService
|
|
||||||
->expects(static::once())
|
|
||||||
->method('findByDate')
|
|
||||||
->willReturnCallback(
|
|
||||||
function (): array {
|
|
||||||
return [
|
|
||||||
(new Bookmark())
|
|
||||||
->setId(1)
|
|
||||||
->setUrl('http://url.tld')
|
|
||||||
->setTitle(static::generateString(50))
|
|
||||||
->setDescription(static::generateString(500))
|
|
||||||
,
|
|
||||||
(new Bookmark())
|
|
||||||
->setId(2)
|
|
||||||
->setUrl('http://url2.tld')
|
|
||||||
->setTitle(static::generateString(50))
|
|
||||||
->setDescription(static::generateString(500))
|
|
||||||
,
|
|
||||||
];
|
|
||||||
}
|
|
||||||
)
|
|
||||||
;
|
|
||||||
|
|
||||||
$result = $this->controller->index($request, $response);
|
|
||||||
|
|
||||||
static::assertSame(200, $result->getStatusCode());
|
|
||||||
static::assertSame('daily', (string) $result->getBody());
|
|
||||||
static::assertSame(
|
|
||||||
'Weekly - Week 20 (May 11, 2020) - Shaarli',
|
|
||||||
$assignedVariables['pagetitle']
|
|
||||||
);
|
|
||||||
|
|
||||||
static::assertCount(2, $assignedVariables['linksToDisplay']);
|
|
||||||
static::assertEquals($expectedDay->setTime(0, 0), $assignedVariables['dayDate']);
|
|
||||||
static::assertSame($expectedDay->setTime(0, 0)->getTimestamp(), $assignedVariables['day']);
|
|
||||||
static::assertSame('', $assignedVariables['previousday']);
|
|
||||||
static::assertSame('', $assignedVariables['nextday']);
|
|
||||||
static::assertSame('Week 20 (May 11, 2020)', $assignedVariables['dayDesc']);
|
|
||||||
static::assertSame('week', $assignedVariables['type']);
|
|
||||||
static::assertSame('Weekly', $assignedVariables['localizedType']);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test simple display index with month parameter
|
|
||||||
*/
|
|
||||||
public function testSimpleIndexMonthly(): void
|
|
||||||
{
|
|
||||||
$currentDay = new \DateTimeImmutable('2020-05-13');
|
|
||||||
$expectedDay = new \DateTimeImmutable('2020-05-01');
|
|
||||||
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$request->method('getQueryParam')->willReturnCallback(function (string $key) use ($currentDay): ?string {
|
|
||||||
return $key === 'month' ? $currentDay->format('Ym') : null;
|
|
||||||
});
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
// Save RainTPL assigned variables
|
|
||||||
$assignedVariables = [];
|
|
||||||
$this->assignTemplateVars($assignedVariables);
|
|
||||||
|
|
||||||
$this->container->bookmarkService
|
|
||||||
->expects(static::once())
|
|
||||||
->method('findByDate')
|
|
||||||
->willReturnCallback(
|
|
||||||
function (): array {
|
|
||||||
return [
|
|
||||||
(new Bookmark())
|
|
||||||
->setId(1)
|
|
||||||
->setUrl('http://url.tld')
|
|
||||||
->setTitle(static::generateString(50))
|
|
||||||
->setDescription(static::generateString(500))
|
|
||||||
,
|
|
||||||
(new Bookmark())
|
|
||||||
->setId(2)
|
|
||||||
->setUrl('http://url2.tld')
|
|
||||||
->setTitle(static::generateString(50))
|
|
||||||
->setDescription(static::generateString(500))
|
|
||||||
,
|
|
||||||
];
|
|
||||||
}
|
|
||||||
)
|
|
||||||
;
|
|
||||||
|
|
||||||
$result = $this->controller->index($request, $response);
|
|
||||||
|
|
||||||
static::assertSame(200, $result->getStatusCode());
|
|
||||||
static::assertSame('daily', (string) $result->getBody());
|
|
||||||
static::assertSame(
|
|
||||||
'Monthly - May, 2020 - Shaarli',
|
|
||||||
$assignedVariables['pagetitle']
|
|
||||||
);
|
|
||||||
|
|
||||||
static::assertCount(2, $assignedVariables['linksToDisplay']);
|
|
||||||
static::assertEquals($expectedDay->setTime(0, 0), $assignedVariables['dayDate']);
|
|
||||||
static::assertSame($expectedDay->setTime(0, 0)->getTimestamp(), $assignedVariables['day']);
|
|
||||||
static::assertSame('', $assignedVariables['previousday']);
|
|
||||||
static::assertSame('', $assignedVariables['nextday']);
|
|
||||||
static::assertSame('May, 2020', $assignedVariables['dayDesc']);
|
|
||||||
static::assertSame('month', $assignedVariables['type']);
|
|
||||||
static::assertSame('Monthly', $assignedVariables['localizedType']);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test simple display RSS with week parameter
|
|
||||||
*/
|
|
||||||
public function testSimpleRssWeekly(): void
|
|
||||||
{
|
|
||||||
$dates = [
|
|
||||||
new \DateTimeImmutable('2020-05-19'),
|
|
||||||
new \DateTimeImmutable('2020-05-13'),
|
|
||||||
];
|
|
||||||
$expectedDates = [
|
|
||||||
new \DateTimeImmutable('2020-05-24 23:59:59'),
|
|
||||||
new \DateTimeImmutable('2020-05-17 23:59:59'),
|
|
||||||
];
|
|
||||||
|
|
||||||
$this->container->environment['QUERY_STRING'] = 'week';
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$request->method('getQueryParam')->willReturnCallback(function (string $key): ?string {
|
|
||||||
return $key === 'week' ? '' : null;
|
|
||||||
});
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
$this->container->bookmarkService->expects(static::once())->method('search')->willReturn(
|
|
||||||
SearchResult::getSearchResult([
|
|
||||||
(new Bookmark())->setId(1)->setCreated($dates[0])->setUrl('http://domain.tld/1'),
|
|
||||||
(new Bookmark())->setId(2)->setCreated($dates[1])->setUrl('http://domain.tld/2'),
|
|
||||||
(new Bookmark())->setId(3)->setCreated($dates[1])->setUrl('http://domain.tld/3'),
|
|
||||||
])
|
|
||||||
);
|
|
||||||
|
|
||||||
// Save RainTPL assigned variables
|
|
||||||
$assignedVariables = [];
|
|
||||||
$this->assignTemplateVars($assignedVariables);
|
|
||||||
|
|
||||||
$result = $this->controller->rss($request, $response);
|
|
||||||
|
|
||||||
static::assertSame(200, $result->getStatusCode());
|
|
||||||
static::assertStringContainsString('application/rss', $result->getHeader('Content-Type')[0]);
|
|
||||||
static::assertSame('dailyrss', (string) $result->getBody());
|
|
||||||
static::assertSame('Shaarli', $assignedVariables['title']);
|
|
||||||
static::assertSame('http://shaarli/subfolder/', $assignedVariables['index_url']);
|
|
||||||
static::assertSame('http://shaarli/subfolder/daily-rss?week', $assignedVariables['page_url']);
|
|
||||||
static::assertFalse($assignedVariables['hide_timestamps']);
|
|
||||||
static::assertCount(2, $assignedVariables['days']);
|
|
||||||
|
|
||||||
$day = $assignedVariables['days'][$dates[0]->format('YW')];
|
|
||||||
$date = $expectedDates[0];
|
|
||||||
|
|
||||||
static::assertEquals($date, $day['date']);
|
|
||||||
static::assertSame($date->format(\DateTime::RSS), $day['date_rss']);
|
|
||||||
static::assertSame('Week 21 (May 18, 2020)', $day['date_human']);
|
|
||||||
static::assertSame('http://shaarli/subfolder/daily?week=' . $dates[0]->format('YW'), $day['absolute_url']);
|
|
||||||
static::assertCount(1, $day['links']);
|
|
||||||
|
|
||||||
$day = $assignedVariables['days'][$dates[1]->format('YW')];
|
|
||||||
$date = $expectedDates[1];
|
|
||||||
|
|
||||||
static::assertEquals($date, $day['date']);
|
|
||||||
static::assertSame($date->format(\DateTime::RSS), $day['date_rss']);
|
|
||||||
static::assertSame('Week 20 (May 11, 2020)', $day['date_human']);
|
|
||||||
static::assertSame('http://shaarli/subfolder/daily?week=' . $dates[1]->format('YW'), $day['absolute_url']);
|
|
||||||
static::assertCount(2, $day['links']);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test simple display RSS with month parameter
|
|
||||||
*/
|
|
||||||
public function testSimpleRssMonthly(): void
|
|
||||||
{
|
|
||||||
$dates = [
|
|
||||||
new \DateTimeImmutable('2022-02-19'),
|
|
||||||
new \DateTimeImmutable('2020-04-13'),
|
|
||||||
];
|
|
||||||
$expectedDates = [
|
|
||||||
new \DateTimeImmutable('2022-02-28 23:59:59'),
|
|
||||||
new \DateTimeImmutable('2020-04-30 23:59:59'),
|
|
||||||
];
|
|
||||||
|
|
||||||
$this->container->environment['QUERY_STRING'] = 'month';
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$request->method('getQueryParam')->willReturnCallback(function (string $key): ?string {
|
|
||||||
return $key === 'month' ? '' : null;
|
|
||||||
});
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
$this->container->bookmarkService->expects(static::once())->method('search')->willReturn(
|
|
||||||
SearchResult::getSearchResult([
|
|
||||||
(new Bookmark())->setId(1)->setCreated($dates[0])->setUrl('http://domain.tld/1'),
|
|
||||||
(new Bookmark())->setId(2)->setCreated($dates[1])->setUrl('http://domain.tld/2'),
|
|
||||||
(new Bookmark())->setId(3)->setCreated($dates[1])->setUrl('http://domain.tld/3'),
|
|
||||||
])
|
|
||||||
);
|
|
||||||
|
|
||||||
// Save RainTPL assigned variables
|
|
||||||
$assignedVariables = [];
|
|
||||||
$this->assignTemplateVars($assignedVariables);
|
|
||||||
|
|
||||||
$result = $this->controller->rss($request, $response);
|
|
||||||
|
|
||||||
static::assertSame(200, $result->getStatusCode());
|
|
||||||
static::assertStringContainsString('application/rss', $result->getHeader('Content-Type')[0]);
|
|
||||||
static::assertSame('dailyrss', (string) $result->getBody());
|
|
||||||
static::assertSame('Shaarli', $assignedVariables['title']);
|
|
||||||
static::assertSame('http://shaarli/subfolder/', $assignedVariables['index_url']);
|
|
||||||
static::assertSame('http://shaarli/subfolder/daily-rss?month', $assignedVariables['page_url']);
|
|
||||||
static::assertFalse($assignedVariables['hide_timestamps']);
|
|
||||||
static::assertCount(2, $assignedVariables['days']);
|
|
||||||
|
|
||||||
$day = $assignedVariables['days'][$dates[0]->format('Ym')];
|
|
||||||
$date = $expectedDates[0];
|
|
||||||
|
|
||||||
static::assertEquals($date, $day['date']);
|
|
||||||
static::assertSame($date->format(\DateTime::RSS), $day['date_rss']);
|
|
||||||
static::assertSame('February, 2022', $day['date_human']);
|
|
||||||
static::assertSame('http://shaarli/subfolder/daily?month=' . $dates[0]->format('Ym'), $day['absolute_url']);
|
|
||||||
static::assertCount(1, $day['links']);
|
|
||||||
|
|
||||||
$day = $assignedVariables['days'][$dates[1]->format('Ym')];
|
|
||||||
$date = $expectedDates[1];
|
|
||||||
|
|
||||||
static::assertEquals($date, $day['date']);
|
|
||||||
static::assertSame($date->format(\DateTime::RSS), $day['date_rss']);
|
|
||||||
static::assertSame('April, 2020', $day['date_human']);
|
|
||||||
static::assertSame('http://shaarli/subfolder/daily?month=' . $dates[1]->format('Ym'), $day['absolute_url']);
|
|
||||||
static::assertCount(2, $day['links']);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,98 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace Shaarli\Front\Controller\Visitor;
|
|
||||||
|
|
||||||
use Shaarli\Front\Exception\ShaarliFrontException;
|
|
||||||
use Shaarli\TestCase;
|
|
||||||
use Slim\Http\Request;
|
|
||||||
use Slim\Http\Response;
|
|
||||||
|
|
||||||
class ErrorControllerTest extends TestCase
|
|
||||||
{
|
|
||||||
use FrontControllerMockHelper;
|
|
||||||
|
|
||||||
/** @var ErrorController */
|
|
||||||
protected $controller;
|
|
||||||
|
|
||||||
public function setUp(): void
|
|
||||||
{
|
|
||||||
$this->createContainer();
|
|
||||||
|
|
||||||
$this->controller = new ErrorController($this->container);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test displaying error with a ShaarliFrontException: display exception message and use its code for HTTTP code
|
|
||||||
*/
|
|
||||||
public function testDisplayFrontExceptionError(): void
|
|
||||||
{
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
$message = 'error message';
|
|
||||||
$errorCode = 418;
|
|
||||||
|
|
||||||
// Save RainTPL assigned variables
|
|
||||||
$assignedVariables = [];
|
|
||||||
$this->assignTemplateVars($assignedVariables);
|
|
||||||
|
|
||||||
$result = ($this->controller)(
|
|
||||||
$request,
|
|
||||||
$response,
|
|
||||||
new class ($message, $errorCode) extends ShaarliFrontException {
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
static::assertSame($errorCode, $result->getStatusCode());
|
|
||||||
static::assertSame($message, $assignedVariables['message']);
|
|
||||||
static::assertArrayNotHasKey('stacktrace', $assignedVariables);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test displaying error with any exception (no debug) while logged in:
|
|
||||||
* display full error details
|
|
||||||
*/
|
|
||||||
public function testDisplayAnyExceptionErrorNoDebugLoggedIn(): void
|
|
||||||
{
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
// Save RainTPL assigned variables
|
|
||||||
$assignedVariables = [];
|
|
||||||
$this->assignTemplateVars($assignedVariables);
|
|
||||||
|
|
||||||
$this->container->loginManager->method('isLoggedIn')->willReturn(true);
|
|
||||||
|
|
||||||
$result = ($this->controller)($request, $response, new \Exception('abc'));
|
|
||||||
|
|
||||||
static::assertSame(500, $result->getStatusCode());
|
|
||||||
static::assertSame('Error: abc', $assignedVariables['message']);
|
|
||||||
static::assertContainsPolyfill('Please report it on Github', $assignedVariables['text']);
|
|
||||||
static::assertArrayHasKey('stacktrace', $assignedVariables);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test displaying error with any exception (no debug) while logged out:
|
|
||||||
* display standard error without detail
|
|
||||||
*/
|
|
||||||
public function testDisplayAnyExceptionErrorNoDebug(): void
|
|
||||||
{
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
// Save RainTPL assigned variables
|
|
||||||
$assignedVariables = [];
|
|
||||||
$this->assignTemplateVars($assignedVariables);
|
|
||||||
|
|
||||||
$this->container->loginManager->method('isLoggedIn')->willReturn(false);
|
|
||||||
|
|
||||||
$result = ($this->controller)($request, $response, new \Exception('abc'));
|
|
||||||
|
|
||||||
static::assertSame(500, $result->getStatusCode());
|
|
||||||
static::assertSame('An unexpected error occurred.', $assignedVariables['message']);
|
|
||||||
static::assertArrayNotHasKey('text', $assignedVariables);
|
|
||||||
static::assertArrayNotHasKey('stacktrace', $assignedVariables);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,81 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace Shaarli\Front\Controller\Visitor;
|
|
||||||
|
|
||||||
use Shaarli\TestCase;
|
|
||||||
use Slim\Http\Request;
|
|
||||||
use Slim\Http\Response;
|
|
||||||
use Slim\Http\Uri;
|
|
||||||
|
|
||||||
class ErrorNotFoundControllerTest extends TestCase
|
|
||||||
{
|
|
||||||
use FrontControllerMockHelper;
|
|
||||||
|
|
||||||
/** @var ErrorNotFoundController */
|
|
||||||
protected $controller;
|
|
||||||
|
|
||||||
public function setUp(): void
|
|
||||||
{
|
|
||||||
$this->createContainer();
|
|
||||||
|
|
||||||
$this->controller = new ErrorNotFoundController($this->container);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test displaying 404 error
|
|
||||||
*/
|
|
||||||
public function testDisplayNotFoundError(): void
|
|
||||||
{
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$request->expects(static::once())->method('getRequestTarget')->willReturn('/');
|
|
||||||
$request->method('getUri')->willReturnCallback(function (): Uri {
|
|
||||||
$uri = $this->createMock(Uri::class);
|
|
||||||
$uri->method('getBasePath')->willReturn('/subfolder');
|
|
||||||
|
|
||||||
return $uri;
|
|
||||||
});
|
|
||||||
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
// Save RainTPL assigned variables
|
|
||||||
$assignedVariables = [];
|
|
||||||
$this->assignTemplateVars($assignedVariables);
|
|
||||||
|
|
||||||
$result = ($this->controller)(
|
|
||||||
$request,
|
|
||||||
$response
|
|
||||||
);
|
|
||||||
|
|
||||||
static::assertSame(404, $result->getStatusCode());
|
|
||||||
static::assertSame('404', (string) $result->getBody());
|
|
||||||
static::assertSame('Requested page could not be found.', $assignedVariables['error_message']);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test displaying 404 error from REST API
|
|
||||||
*/
|
|
||||||
public function testDisplayNotFoundErrorFromAPI(): void
|
|
||||||
{
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$request->expects(static::once())->method('getRequestTarget')->willReturn('/sufolder/api/v1/links');
|
|
||||||
$request->method('getUri')->willReturnCallback(function (): Uri {
|
|
||||||
$uri = $this->createMock(Uri::class);
|
|
||||||
$uri->method('getBasePath')->willReturn('/subfolder');
|
|
||||||
|
|
||||||
return $uri;
|
|
||||||
});
|
|
||||||
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
// Save RainTPL assigned variables
|
|
||||||
$assignedVariables = [];
|
|
||||||
$this->assignTemplateVars($assignedVariables);
|
|
||||||
|
|
||||||
$result = ($this->controller)($request, $response);
|
|
||||||
|
|
||||||
static::assertSame(404, $result->getStatusCode());
|
|
||||||
static::assertSame([], $assignedVariables);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,151 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace Shaarli\Front\Controller\Visitor;
|
|
||||||
|
|
||||||
use Shaarli\Feed\FeedBuilder;
|
|
||||||
use Shaarli\TestCase;
|
|
||||||
use Slim\Http\Request;
|
|
||||||
use Slim\Http\Response;
|
|
||||||
|
|
||||||
class FeedControllerTest extends TestCase
|
|
||||||
{
|
|
||||||
use FrontControllerMockHelper;
|
|
||||||
|
|
||||||
/** @var FeedController */
|
|
||||||
protected $controller;
|
|
||||||
|
|
||||||
public function setUp(): void
|
|
||||||
{
|
|
||||||
$this->createContainer();
|
|
||||||
|
|
||||||
$this->container->feedBuilder = $this->createMock(FeedBuilder::class);
|
|
||||||
|
|
||||||
$this->controller = new FeedController($this->container);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Feed Controller - RSS default behaviour
|
|
||||||
*/
|
|
||||||
public function testDefaultRssController(): void
|
|
||||||
{
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
$this->container->feedBuilder->expects(static::once())->method('setLocale');
|
|
||||||
$this->container->feedBuilder->expects(static::once())->method('setHideDates')->with(false);
|
|
||||||
$this->container->feedBuilder->expects(static::once())->method('setUsePermalinks')->with(true);
|
|
||||||
|
|
||||||
// Save RainTPL assigned variables
|
|
||||||
$assignedVariables = [];
|
|
||||||
$this->assignTemplateVars($assignedVariables);
|
|
||||||
|
|
||||||
$this->container->feedBuilder->method('buildData')->willReturn(['content' => 'data']);
|
|
||||||
|
|
||||||
// Make sure that PluginManager hook is triggered
|
|
||||||
$this->container->pluginManager
|
|
||||||
->expects(static::atLeastOnce())
|
|
||||||
->method('executeHooks')
|
|
||||||
->withConsecutive(['render_feed'])
|
|
||||||
->willReturnCallback(function (string $hook, array $data, array $param): void {
|
|
||||||
if ('render_feed' === $hook) {
|
|
||||||
static::assertSame('data', $data['content']);
|
|
||||||
|
|
||||||
static::assertArrayHasKey('loggedin', $param);
|
|
||||||
static::assertSame('feed.rss', $param['target']);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
;
|
|
||||||
|
|
||||||
$result = $this->controller->rss($request, $response);
|
|
||||||
|
|
||||||
static::assertSame(200, $result->getStatusCode());
|
|
||||||
static::assertStringContainsString('application/rss', $result->getHeader('Content-Type')[0]);
|
|
||||||
static::assertSame('feed.rss', (string) $result->getBody());
|
|
||||||
static::assertSame('data', $assignedVariables['content']);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Feed Controller - ATOM default behaviour
|
|
||||||
*/
|
|
||||||
public function testDefaultAtomController(): void
|
|
||||||
{
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
$this->container->feedBuilder->expects(static::once())->method('setLocale');
|
|
||||||
$this->container->feedBuilder->expects(static::once())->method('setHideDates')->with(false);
|
|
||||||
$this->container->feedBuilder->expects(static::once())->method('setUsePermalinks')->with(true);
|
|
||||||
|
|
||||||
// Save RainTPL assigned variables
|
|
||||||
$assignedVariables = [];
|
|
||||||
$this->assignTemplateVars($assignedVariables);
|
|
||||||
|
|
||||||
$this->container->feedBuilder->method('buildData')->willReturn(['content' => 'data']);
|
|
||||||
|
|
||||||
// Make sure that PluginManager hook is triggered
|
|
||||||
$this->container->pluginManager
|
|
||||||
->expects(static::atLeastOnce())
|
|
||||||
->method('executeHooks')
|
|
||||||
->withConsecutive(['render_feed'])
|
|
||||||
->willReturnCallback(function (string $hook, array $data, array $param): void {
|
|
||||||
if ('render_feed' === $hook) {
|
|
||||||
static::assertSame('data', $data['content']);
|
|
||||||
|
|
||||||
static::assertArrayHasKey('loggedin', $param);
|
|
||||||
static::assertSame('feed.atom', $param['target']);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
;
|
|
||||||
|
|
||||||
$result = $this->controller->atom($request, $response);
|
|
||||||
|
|
||||||
static::assertSame(200, $result->getStatusCode());
|
|
||||||
static::assertStringContainsString('application/atom', $result->getHeader('Content-Type')[0]);
|
|
||||||
static::assertSame('feed.atom', (string) $result->getBody());
|
|
||||||
static::assertSame('data', $assignedVariables['content']);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Feed Controller - ATOM with parameters
|
|
||||||
*/
|
|
||||||
public function testAtomControllerWithParameters(): void
|
|
||||||
{
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$request->method('getParams')->willReturn(['parameter' => 'value']);
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
// Save RainTPL assigned variables
|
|
||||||
$assignedVariables = [];
|
|
||||||
$this->assignTemplateVars($assignedVariables);
|
|
||||||
|
|
||||||
$this->container->feedBuilder
|
|
||||||
->method('buildData')
|
|
||||||
->with('atom', ['parameter' => 'value'])
|
|
||||||
->willReturn(['content' => 'data'])
|
|
||||||
;
|
|
||||||
|
|
||||||
// Make sure that PluginManager hook is triggered
|
|
||||||
$this->container->pluginManager
|
|
||||||
->expects(static::atLeastOnce())
|
|
||||||
->method('executeHooks')
|
|
||||||
->withConsecutive(['render_feed'])
|
|
||||||
->willReturnCallback(function (string $hook, array $data, array $param): void {
|
|
||||||
if ('render_feed' === $hook) {
|
|
||||||
static::assertSame('data', $data['content']);
|
|
||||||
|
|
||||||
static::assertArrayHasKey('loggedin', $param);
|
|
||||||
static::assertSame('feed.atom', $param['target']);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
;
|
|
||||||
|
|
||||||
$result = $this->controller->atom($request, $response);
|
|
||||||
|
|
||||||
static::assertSame(200, $result->getStatusCode());
|
|
||||||
static::assertStringContainsString('application/atom', $result->getHeader('Content-Type')[0]);
|
|
||||||
static::assertSame('feed.atom', (string) $result->getBody());
|
|
||||||
static::assertSame('data', $assignedVariables['content']);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,122 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace Shaarli\Front\Controller\Visitor;
|
|
||||||
|
|
||||||
use Shaarli\Bookmark\BookmarkServiceInterface;
|
|
||||||
use Shaarli\Config\ConfigManager;
|
|
||||||
use Shaarli\Container\ShaarliTestContainer;
|
|
||||||
use Shaarli\Formatter\BookmarkFormatter;
|
|
||||||
use Shaarli\Formatter\BookmarkRawFormatter;
|
|
||||||
use Shaarli\Formatter\FormatterFactory;
|
|
||||||
use Shaarli\Plugin\PluginManager;
|
|
||||||
use Shaarli\Render\PageBuilder;
|
|
||||||
use Shaarli\Render\PageCacheManager;
|
|
||||||
use Shaarli\Security\LoginManager;
|
|
||||||
use Shaarli\Security\SessionManager;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Trait FrontControllerMockHelper
|
|
||||||
*
|
|
||||||
* Helper trait used to initialize the ShaarliContainer and mock its services for controller tests.
|
|
||||||
*
|
|
||||||
* @property ShaarliTestContainer $container
|
|
||||||
* @package Shaarli\Front\Controller
|
|
||||||
*/
|
|
||||||
trait FrontControllerMockHelper
|
|
||||||
{
|
|
||||||
/** @var ShaarliTestContainer */
|
|
||||||
protected $container;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Mock the container instance and initialize container's services used by tests
|
|
||||||
*/
|
|
||||||
protected function createContainer(): void
|
|
||||||
{
|
|
||||||
$this->container = $this->createMock(ShaarliTestContainer::class);
|
|
||||||
|
|
||||||
$this->container->loginManager = $this->createMock(LoginManager::class);
|
|
||||||
|
|
||||||
// Config
|
|
||||||
$this->container->conf = $this->createMock(ConfigManager::class);
|
|
||||||
$this->container->conf->method('get')->willReturnCallback(function (string $parameter, $default) {
|
|
||||||
if ($parameter === 'general.tags_separator') {
|
|
||||||
return '@';
|
|
||||||
}
|
|
||||||
|
|
||||||
return $default === null ? $parameter : $default;
|
|
||||||
});
|
|
||||||
|
|
||||||
// PageBuilder
|
|
||||||
$this->container->pageBuilder = $this->createMock(PageBuilder::class);
|
|
||||||
$this->container->pageBuilder
|
|
||||||
->method('render')
|
|
||||||
->willReturnCallback(function (string $template): string {
|
|
||||||
return $template;
|
|
||||||
})
|
|
||||||
;
|
|
||||||
|
|
||||||
// Plugin Manager
|
|
||||||
$this->container->pluginManager = $this->createMock(PluginManager::class);
|
|
||||||
|
|
||||||
// BookmarkService
|
|
||||||
$this->container->bookmarkService = $this->createMock(BookmarkServiceInterface::class);
|
|
||||||
|
|
||||||
// Formatter
|
|
||||||
$this->container->formatterFactory = $this->createMock(FormatterFactory::class);
|
|
||||||
$this->container->formatterFactory
|
|
||||||
->method('getFormatter')
|
|
||||||
->willReturnCallback(function (): BookmarkFormatter {
|
|
||||||
return new BookmarkRawFormatter($this->container->conf, true);
|
|
||||||
})
|
|
||||||
;
|
|
||||||
|
|
||||||
// CacheManager
|
|
||||||
$this->container->pageCacheManager = $this->createMock(PageCacheManager::class);
|
|
||||||
|
|
||||||
// SessionManager
|
|
||||||
$this->container->sessionManager = $this->createMock(SessionManager::class);
|
|
||||||
|
|
||||||
// $_SERVER
|
|
||||||
$this->container->environment = [
|
|
||||||
'SERVER_NAME' => 'shaarli',
|
|
||||||
'SERVER_PORT' => '80',
|
|
||||||
'REQUEST_URI' => '/subfolder/daily-rss',
|
|
||||||
'REMOTE_ADDR' => '1.2.3.4',
|
|
||||||
'SCRIPT_NAME' => '/subfolder/index.php',
|
|
||||||
];
|
|
||||||
|
|
||||||
$this->container->basePath = '/subfolder';
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Pass a reference of an array which will be populated by `pageBuilder->assign` calls during execution.
|
|
||||||
*
|
|
||||||
* @param mixed $variables Array reference to populate.
|
|
||||||
*/
|
|
||||||
protected function assignTemplateVars(array &$variables): void
|
|
||||||
{
|
|
||||||
$this->container->pageBuilder
|
|
||||||
->method('assign')
|
|
||||||
->willReturnCallback(function ($key, $value) use (&$variables) {
|
|
||||||
$variables[$key] = $value;
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
})
|
|
||||||
;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected static function generateString(int $length): string
|
|
||||||
{
|
|
||||||
// bin2hex(random_bytes) generates string twice as long as given parameter
|
|
||||||
$length = (int) ceil($length / 2);
|
|
||||||
|
|
||||||
return bin2hex(random_bytes($length));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Force to be used in PHPUnit context.
|
|
||||||
*/
|
|
||||||
abstract protected function isInTestsContext(): bool;
|
|
||||||
}
|
|
|
@ -1,304 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace Shaarli\Front\Controller\Visitor;
|
|
||||||
|
|
||||||
use Shaarli\Config\ConfigManager;
|
|
||||||
use Shaarli\Front\Exception\AlreadyInstalledException;
|
|
||||||
use Shaarli\Security\SessionManager;
|
|
||||||
use Shaarli\TestCase;
|
|
||||||
use Slim\Http\Request;
|
|
||||||
use Slim\Http\Response;
|
|
||||||
|
|
||||||
class InstallControllerTest extends TestCase
|
|
||||||
{
|
|
||||||
use FrontControllerMockHelper;
|
|
||||||
|
|
||||||
protected const MOCK_FILE = '.tmp';
|
|
||||||
|
|
||||||
/** @var InstallController */
|
|
||||||
protected $controller;
|
|
||||||
|
|
||||||
public function setUp(): void
|
|
||||||
{
|
|
||||||
$this->createContainer();
|
|
||||||
|
|
||||||
$this->container->conf = $this->createMock(ConfigManager::class);
|
|
||||||
$this->container->conf->method('getConfigFileExt')->willReturn(static::MOCK_FILE);
|
|
||||||
$this->container->conf->method('get')->willReturnCallback(function (string $key, $default) {
|
|
||||||
if ($key === 'resource.raintpl_tpl') {
|
|
||||||
return '.';
|
|
||||||
}
|
|
||||||
|
|
||||||
return $default ?? $key;
|
|
||||||
});
|
|
||||||
|
|
||||||
$this->controller = new InstallController($this->container);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function tearDown(): void
|
|
||||||
{
|
|
||||||
if (file_exists(static::MOCK_FILE)) {
|
|
||||||
unlink(static::MOCK_FILE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test displaying install page with valid session.
|
|
||||||
*/
|
|
||||||
public function testInstallIndexWithValidSession(): void
|
|
||||||
{
|
|
||||||
$assignedVariables = [];
|
|
||||||
$this->assignTemplateVars($assignedVariables);
|
|
||||||
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
$this->container->sessionManager = $this->createMock(SessionManager::class);
|
|
||||||
$this->container->sessionManager
|
|
||||||
->method('getSessionParameter')
|
|
||||||
->willReturnCallback(function (string $key, $default) {
|
|
||||||
return $key === 'session_tested' ? 'Working' : $default;
|
|
||||||
})
|
|
||||||
;
|
|
||||||
|
|
||||||
$result = $this->controller->index($request, $response);
|
|
||||||
|
|
||||||
static::assertSame(200, $result->getStatusCode());
|
|
||||||
static::assertSame('install', (string) $result->getBody());
|
|
||||||
|
|
||||||
static::assertIsArray($assignedVariables['continents']);
|
|
||||||
static::assertSame('Africa', $assignedVariables['continents'][0]);
|
|
||||||
static::assertSame('UTC', $assignedVariables['continents']['selected']);
|
|
||||||
|
|
||||||
static::assertIsArray($assignedVariables['cities']);
|
|
||||||
static::assertSame(['continent' => 'Africa', 'city' => 'Abidjan'], $assignedVariables['cities'][0]);
|
|
||||||
static::assertSame('UTC', $assignedVariables['continents']['selected']);
|
|
||||||
|
|
||||||
static::assertIsArray($assignedVariables['languages']);
|
|
||||||
static::assertSame('Automatic', $assignedVariables['languages']['auto']);
|
|
||||||
static::assertSame('French', $assignedVariables['languages']['fr']);
|
|
||||||
|
|
||||||
static::assertSame(PHP_VERSION, $assignedVariables['php_version']);
|
|
||||||
static::assertArrayHasKey('php_has_reached_eol', $assignedVariables);
|
|
||||||
static::assertArrayHasKey('php_eol', $assignedVariables);
|
|
||||||
static::assertArrayHasKey('php_extensions', $assignedVariables);
|
|
||||||
static::assertArrayHasKey('permissions', $assignedVariables);
|
|
||||||
static::assertEmpty($assignedVariables['permissions']);
|
|
||||||
|
|
||||||
static::assertSame('Install Shaarli', $assignedVariables['pagetitle']);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Instantiate the install controller with an existing config file: exception.
|
|
||||||
*/
|
|
||||||
public function testInstallWithExistingConfigFile(): void
|
|
||||||
{
|
|
||||||
$this->expectException(AlreadyInstalledException::class);
|
|
||||||
|
|
||||||
touch(static::MOCK_FILE);
|
|
||||||
|
|
||||||
$this->controller = new InstallController($this->container);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Call controller without session yet defined, redirect to test session install page.
|
|
||||||
*/
|
|
||||||
public function testInstallRedirectToSessionTest(): void
|
|
||||||
{
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
$this->container->sessionManager = $this->createMock(SessionManager::class);
|
|
||||||
$this->container->sessionManager
|
|
||||||
->expects(static::once())
|
|
||||||
->method('setSessionParameter')
|
|
||||||
->with(InstallController::SESSION_TEST_KEY, InstallController::SESSION_TEST_VALUE)
|
|
||||||
;
|
|
||||||
|
|
||||||
$result = $this->controller->index($request, $response);
|
|
||||||
|
|
||||||
static::assertSame(302, $result->getStatusCode());
|
|
||||||
static::assertSame('/subfolder/install/session-test', $result->getHeader('location')[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Call controller in session test mode: valid session then redirect to install page.
|
|
||||||
*/
|
|
||||||
public function testInstallSessionTestValid(): void
|
|
||||||
{
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
$this->container->sessionManager = $this->createMock(SessionManager::class);
|
|
||||||
$this->container->sessionManager
|
|
||||||
->method('getSessionParameter')
|
|
||||||
->with(InstallController::SESSION_TEST_KEY)
|
|
||||||
->willReturn(InstallController::SESSION_TEST_VALUE)
|
|
||||||
;
|
|
||||||
|
|
||||||
$result = $this->controller->sessionTest($request, $response);
|
|
||||||
|
|
||||||
static::assertSame(302, $result->getStatusCode());
|
|
||||||
static::assertSame('/subfolder/install', $result->getHeader('location')[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Call controller in session test mode: invalid session then redirect to error page.
|
|
||||||
*/
|
|
||||||
public function testInstallSessionTestError(): void
|
|
||||||
{
|
|
||||||
$assignedVars = [];
|
|
||||||
$this->assignTemplateVars($assignedVars);
|
|
||||||
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
$this->container->sessionManager = $this->createMock(SessionManager::class);
|
|
||||||
$this->container->sessionManager
|
|
||||||
->method('getSessionParameter')
|
|
||||||
->with(InstallController::SESSION_TEST_KEY)
|
|
||||||
->willReturn('KO')
|
|
||||||
;
|
|
||||||
|
|
||||||
$result = $this->controller->sessionTest($request, $response);
|
|
||||||
|
|
||||||
static::assertSame(200, $result->getStatusCode());
|
|
||||||
static::assertSame('error', (string) $result->getBody());
|
|
||||||
static::assertStringStartsWith(
|
|
||||||
'<pre>Sessions do not seem to work correctly on your server',
|
|
||||||
$assignedVars['message']
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test saving valid data from install form. Also initialize datastore.
|
|
||||||
*/
|
|
||||||
public function testSaveInstallValid(): void
|
|
||||||
{
|
|
||||||
$providedParameters = [
|
|
||||||
'continent' => 'Europe',
|
|
||||||
'city' => 'Berlin',
|
|
||||||
'setlogin' => 'bob',
|
|
||||||
'setpassword' => 'password',
|
|
||||||
'title' => 'Shaarli',
|
|
||||||
'language' => 'fr',
|
|
||||||
'updateCheck' => true,
|
|
||||||
'enableApi' => true,
|
|
||||||
];
|
|
||||||
|
|
||||||
$expectedSettings = [
|
|
||||||
'general.timezone' => 'Europe/Berlin',
|
|
||||||
'credentials.login' => 'bob',
|
|
||||||
'credentials.salt' => '_NOT_EMPTY',
|
|
||||||
'credentials.hash' => '_NOT_EMPTY',
|
|
||||||
'general.title' => 'Shaarli',
|
|
||||||
'translation.language' => 'en',
|
|
||||||
'updates.check_updates' => true,
|
|
||||||
'api.enabled' => true,
|
|
||||||
'api.secret' => '_NOT_EMPTY',
|
|
||||||
'general.header_link' => '/subfolder',
|
|
||||||
];
|
|
||||||
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$request->method('getParam')->willReturnCallback(function (string $key) use ($providedParameters) {
|
|
||||||
return $providedParameters[$key] ?? null;
|
|
||||||
});
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
$this->container->conf = $this->createMock(ConfigManager::class);
|
|
||||||
$this->container->conf
|
|
||||||
->method('get')
|
|
||||||
->willReturnCallback(function (string $key, $value) {
|
|
||||||
if ($key === 'credentials.login') {
|
|
||||||
return 'bob';
|
|
||||||
} elseif ($key === 'credentials.salt') {
|
|
||||||
return 'salt';
|
|
||||||
}
|
|
||||||
|
|
||||||
return $value;
|
|
||||||
})
|
|
||||||
;
|
|
||||||
$this->container->conf
|
|
||||||
->expects(static::exactly(count($expectedSettings)))
|
|
||||||
->method('set')
|
|
||||||
->willReturnCallback(function (string $key, $value) use ($expectedSettings) {
|
|
||||||
if ($expectedSettings[$key] ?? null === '_NOT_EMPTY') {
|
|
||||||
static::assertNotEmpty($value);
|
|
||||||
} else {
|
|
||||||
static::assertSame($expectedSettings[$key], $value);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
;
|
|
||||||
$this->container->conf->expects(static::once())->method('write');
|
|
||||||
|
|
||||||
$this->container->sessionManager
|
|
||||||
->expects(static::once())
|
|
||||||
->method('setSessionParameter')
|
|
||||||
->with(SessionManager::KEY_SUCCESS_MESSAGES)
|
|
||||||
;
|
|
||||||
|
|
||||||
$result = $this->controller->save($request, $response);
|
|
||||||
|
|
||||||
static::assertSame(302, $result->getStatusCode());
|
|
||||||
static::assertSame('/subfolder/login', $result->getHeader('location')[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test default settings (timezone and title).
|
|
||||||
* Also check that bookmarks are not initialized if
|
|
||||||
*/
|
|
||||||
public function testSaveInstallDefaultValues(): void
|
|
||||||
{
|
|
||||||
$confSettings = [];
|
|
||||||
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
$this->container->conf->method('set')->willReturnCallback(function (string $key, $value) use (&$confSettings) {
|
|
||||||
$confSettings[$key] = $value;
|
|
||||||
});
|
|
||||||
|
|
||||||
$result = $this->controller->save($request, $response);
|
|
||||||
|
|
||||||
static::assertSame(302, $result->getStatusCode());
|
|
||||||
static::assertSame('/subfolder/login', $result->getHeader('location')[0]);
|
|
||||||
|
|
||||||
static::assertSame('UTC', $confSettings['general.timezone']);
|
|
||||||
static::assertSame('Shared Bookmarks', $confSettings['general.title']);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Same test as testSaveInstallDefaultValues() but for an instance install in root directory.
|
|
||||||
*/
|
|
||||||
public function testSaveInstallDefaultValuesWithoutSubfolder(): void
|
|
||||||
{
|
|
||||||
$confSettings = [];
|
|
||||||
|
|
||||||
$this->container->environment = [
|
|
||||||
'SERVER_NAME' => 'shaarli',
|
|
||||||
'SERVER_PORT' => '80',
|
|
||||||
'REQUEST_URI' => '/install',
|
|
||||||
'REMOTE_ADDR' => '1.2.3.4',
|
|
||||||
'SCRIPT_NAME' => '/index.php',
|
|
||||||
];
|
|
||||||
|
|
||||||
$this->container->basePath = '';
|
|
||||||
|
|
||||||
$request = $this->createMock(Request::class);
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
$this->container->conf->method('set')->willReturnCallback(function (string $key, $value) use (&$confSettings) {
|
|
||||||
$confSettings[$key] = $value;
|
|
||||||
});
|
|
||||||
|
|
||||||
$result = $this->controller->save($request, $response);
|
|
||||||
|
|
||||||
static::assertSame(302, $result->getStatusCode());
|
|
||||||
static::assertSame('/login', $result->getHeader('location')[0]);
|
|
||||||
|
|
||||||
static::assertSame('UTC', $confSettings['general.timezone']);
|
|
||||||
static::assertSame('Shared Bookmarks', $confSettings['general.title']);
|
|
||||||
}
|
|
||||||
}
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue