From 663f81a2b1eba75883fbab6577a386351b86f623 Mon Sep 17 00:00:00 2001
From: Dan Brown <ssddanbrown@googlemail.com>
Date: Sun, 19 Jun 2022 16:57:33 +0100
Subject: [PATCH] Added tests to cover convert functionality

Also updated cloner class with typed properties.
---
 app/Entities/Tools/Cloner.php |  23 ++------
 tests/Entity/ConvertTest.php  | 105 ++++++++++++++++++++++++++++++++++
 2 files changed, 109 insertions(+), 19 deletions(-)
 create mode 100644 tests/Entity/ConvertTest.php

diff --git a/app/Entities/Tools/Cloner.php b/app/Entities/Tools/Cloner.php
index 91e10b9be..c76f224b4 100644
--- a/app/Entities/Tools/Cloner.php
+++ b/app/Entities/Tools/Cloner.php
@@ -16,25 +16,10 @@ use Illuminate\Http\UploadedFile;
 
 class Cloner
 {
-    /**
-     * @var PageRepo
-     */
-    protected $pageRepo;
-
-    /**
-     * @var ChapterRepo
-     */
-    protected $chapterRepo;
-
-    /**
-     * @var BookRepo
-     */
-    protected $bookRepo;
-
-    /**
-     * @var ImageService
-     */
-    protected $imageService;
+    protected PageRepo $pageRepo;
+    protected ChapterRepo $chapterRepo;
+    protected BookRepo $bookRepo;
+    protected ImageService $imageService;
 
     public function __construct(PageRepo $pageRepo, ChapterRepo $chapterRepo, BookRepo $bookRepo, ImageService $imageService)
     {
diff --git a/tests/Entity/ConvertTest.php b/tests/Entity/ConvertTest.php
new file mode 100644
index 000000000..4a949e76f
--- /dev/null
+++ b/tests/Entity/ConvertTest.php
@@ -0,0 +1,105 @@
+<?php
+
+namespace Tests\Entity;
+
+use BookStack\Actions\ActivityType;
+use BookStack\Actions\Tag;
+use BookStack\Entities\Models\Book;
+use BookStack\Entities\Models\Bookshelf;
+use BookStack\Entities\Models\Chapter;
+use BookStack\Entities\Models\Page;
+use Tests\TestCase;
+
+class ConvertTest extends TestCase
+{
+
+    public function test_chapter_edit_view_shows_convert_option()
+    {
+        /** @var Chapter $chapter */
+        $chapter = Chapter::query()->first();
+
+        $resp = $this->asEditor()->get($chapter->getUrl('/edit'));
+        $resp->assertSee('Convert to Book');
+        $resp->assertSee('Convert Chapter');
+        $resp->assertElementExists('form[action$="/convert-to-book"] button');
+    }
+
+    public function test_convert_chapter_to_book()
+    {
+        /** @var Chapter $chapter */
+        $chapter = Chapter::query()->whereHas('pages')->first();
+        $chapter->tags()->save(new Tag(['name' => 'Category', 'value' => 'Penguins']));
+        /** @var Page $childPage */
+        $childPage = $chapter->pages()->first();
+
+        $resp = $this->asEditor()->post($chapter->getUrl('/convert-to-book'));
+        $resp->assertRedirectContains('/books/');
+
+        /** @var Book $newBook */
+        $newBook = Book::query()->orderBy('id', 'desc')->first();
+
+        $this->assertDatabaseMissing('chapters', ['id' => $chapter->id]);
+        $this->assertDatabaseHas('pages', ['id' => $childPage->id, 'book_id' => $newBook->id, 'chapter_id' => 0]);
+        $this->assertCount(1, $newBook->tags);
+        $this->assertEquals('Category', $newBook->tags->first()->name);
+        $this->assertEquals('Penguins', $newBook->tags->first()->value);
+        $this->assertEquals($chapter->name, $newBook->name);
+        $this->assertEquals($chapter->description, $newBook->description);
+
+        $this->assertActivityExists(ActivityType::BOOK_CREATE_FROM_CHAPTER, $newBook);
+    }
+
+    public function test_book_edit_view_shows_convert_option()
+    {
+        $book = Book::query()->first();
+
+        $resp = $this->asEditor()->get($book->getUrl('/edit'));
+        $resp->assertSee('Convert to Shelf');
+        $resp->assertSee('Convert Book');
+        $resp->assertSee('Note that permissions on shelves do not auto-cascade to content');
+        $resp->assertElementExists('form[action$="/convert-to-shelf"] button');
+    }
+
+    public function test_book_convert_to_shelf()
+    {
+        /** @var Book $book */
+        $book = Book::query()->whereHas('directPages')->whereHas('chapters')->firstOrFail();
+        $book->tags()->save(new Tag(['name' => 'Category', 'value' => 'Ducks']));
+        /** @var Page $childPage */
+        $childPage = $book->directPages()->first();
+        /** @var Chapter $childChapter */
+        $childChapter = $book->chapters()->whereHas('pages')->firstOrFail();
+        /** @var Page $chapterChildPage */
+        $chapterChildPage = $childChapter->pages()->firstOrFail();
+        $bookChapterCount = $book->chapters()->count();
+        $systemBookCount = Book::query()->count();
+
+        // Run conversion
+        $resp = $this->asEditor()->post($book->getUrl('/convert-to-shelf'));
+
+        /** @var Bookshelf $newShelf */
+        $newShelf = Bookshelf::query()->orderBy('id', 'desc')->first();
+
+        // Checks for new shelf
+        $resp->assertRedirectContains('/shelves/');
+        $this->assertDatabaseMissing('chapters', ['id' => $childChapter->id]);
+        $this->assertCount(1, $newShelf->tags);
+        $this->assertEquals('Category', $newShelf->tags->first()->name);
+        $this->assertEquals('Ducks', $newShelf->tags->first()->value);
+        $this->assertEquals($book->name, $newShelf->name);
+        $this->assertEquals($book->description, $newShelf->description);
+        $this->assertEquals($newShelf->books()->count(), $bookChapterCount + 1);
+        $this->assertEquals($systemBookCount + $bookChapterCount, Book::query()->count());
+        $this->assertActivityExists(ActivityType::BOOKSHELF_CREATE_FROM_BOOK, $newShelf);
+
+        // Checks for old book to contain child pages
+        $this->assertDatabaseHas('books', ['id' => $book->id, 'name' => $book->name . ' Pages']);
+        $this->assertDatabaseHas('pages', ['id' => $childPage->id, 'book_id' => $book->id, 'chapter_id' => 0]);
+
+        // Checks for nested page
+        $chapterChildPage->refresh();
+        $this->assertEquals(0, $chapterChildPage->chapter_id);
+        $this->assertEquals($childChapter->name, $chapterChildPage->book->name);
+    }
+
+}
\ No newline at end of file