* * @author Jonas Rittershofer * * @license AGPL-3.0-or-later * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . * */ namespace OCA\Forms\Tests\Integration\Api; use OCA\Forms\Db\Form; use OCA\Forms\Db\FormMapper; use OCP\DB\QueryBuilder\IQueryBuilder; use GuzzleHttp\Client; use GuzzleHttp\Exception\ClientException; use Test\TestCase; class ApiV2Test extends TestCase { /** @var GuzzleHttp\Client */ private $http; /** @var FormMapper */ private $formMapper; /** @var Array */ private $testForms = [ [ 'hash' => 'abcdefg', 'title' => 'Title of a Form', 'description' => 'Just a simple form.', 'owner_id' => 'test', 'access_json' => [ 'permitAllUsers' => false, 'showToAllUsers' => false ], 'created' => 12345, 'expires' => 0, 'is_anonymous' => false, 'submit_multiple' => false, 'questions' => [ [ 'type' => 'short', 'text' => 'First Question?', 'isRequired' => true, 'order' => 1, 'options' => [] ], [ 'type' => 'multiple_unique', 'text' => 'Second Question?', 'isRequired' => false, 'order' => 2, 'options' => [ [ 'text' => 'Option 1' ], [ 'text' => 'Option 2' ] ] ] ], 'shares' => [ [ 'shareType' => 0, 'shareWith' => 'user1', ], [ 'shareType' => 3, 'shareWith' => 'shareHash', ], ], 'submissions' => [ [ 'userId' => 'user1', 'timestamp' => 123456, 'answers' => [ [ 'questionIndex' => 0, 'text' => 'This is a short answer.' ], [ 'questionIndex' => 1, 'text' => 'Option 1' ] ] ], [ 'userId' => 'user2', 'timestamp' => 12345, 'answers' => [ [ 'questionIndex' => 0, 'text' => 'This is another short answer.' ], [ 'questionIndex' => 1, 'text' => 'Option 2' ] ] ] ] ], [ 'hash' => 'abcdefghij', 'title' => 'Title of a second Form', 'description' => '', 'owner_id' => 'someUser', 'access_json' => [ 'permitAllUsers' => true, 'showToAllUsers' => true ], 'created' => 12345, 'expires' => 0, 'is_anonymous' => false, 'submit_multiple' => false, 'questions' => [ [ 'type' => 'short', 'text' => 'Third Question?', 'isRequired' => false, 'order' => 1, 'options' => [] ], ], 'shares' => [ [ 'shareType' => 0, 'shareWith' => 'user2', ], ], 'submissions' => [] ] ]; /** * Set up test environment. * Writing testforms into db, preparing http request */ public function setUp(): void { parent::setUp(); $qb = TestCase::$realDatabase->getQueryBuilder(); // Write our test forms into db foreach ($this->testForms as $index => $form) { $qb->insert('forms_v2_forms') ->values([ 'hash' => $qb->createNamedParameter($form['hash'], IQueryBuilder::PARAM_STR), 'title' => $qb->createNamedParameter($form['title'], IQueryBuilder::PARAM_STR), 'description' => $qb->createNamedParameter($form['description'], IQueryBuilder::PARAM_STR), 'owner_id' => $qb->createNamedParameter($form['owner_id'], IQueryBuilder::PARAM_STR), 'access_json' => $qb->createNamedParameter(json_encode($form['access_json']), IQueryBuilder::PARAM_STR), 'created' => $qb->createNamedParameter($form['created'], IQueryBuilder::PARAM_INT), 'expires' => $qb->createNamedParameter($form['expires'], IQueryBuilder::PARAM_INT), 'is_anonymous' => $qb->createNamedParameter($form['is_anonymous'], IQueryBuilder::PARAM_BOOL), 'submit_multiple' => $qb->createNamedParameter($form['submit_multiple'], IQueryBuilder::PARAM_BOOL) ]); $qb->execute(); $formId = $qb->getLastInsertId(); $this->testForms[$index]['id'] = $formId; // Insert Questions into DB foreach ($form['questions'] as $qIndex => $question) { $qb->insert('forms_v2_questions') ->values([ 'form_id' => $qb->createNamedParameter($formId, IQueryBuilder::PARAM_INT), 'order' => $qb->createNamedParameter($question['order'], IQueryBuilder::PARAM_INT), 'type' => $qb->createNamedParameter($question['type'], IQueryBuilder::PARAM_STR), 'is_required' => $qb->createNamedParameter($question['isRequired'], IQueryBuilder::PARAM_BOOL), 'text' => $qb->createNamedParameter($question['text'], IQueryBuilder::PARAM_STR) ]); $qb->execute(); $questionId = $qb->getLastInsertId(); $this->testForms[$index]['questions'][$qIndex]['id'] = $questionId; // Insert Options into DB foreach ($question['options'] as $oIndex => $option) { $qb->insert('forms_v2_options') ->values([ 'question_id' => $qb->createNamedParameter($questionId, IQueryBuilder::PARAM_INT), 'text' => $qb->createNamedParameter($option['text'], IQueryBuilder::PARAM_STR) ]); $qb->execute(); $this->testForms[$index]['questions'][$qIndex]['options'][$oIndex]['id'] = $qb->getLastInsertId(); } } // Insert Shares into DB foreach ($form['shares'] as $sIndex => $share) { $qb->insert('forms_v2_shares') ->values([ 'form_id' => $qb->createNamedParameter($formId, IQueryBuilder::PARAM_INT), 'share_type' => $qb->createNamedParameter($share['shareType'], IQueryBuilder::PARAM_STR), 'share_with' => $qb->createNamedParameter($share['shareWith'], IQueryBuilder::PARAM_STR) ]); $qb->execute(); $this->testForms[$index]['shares'][$sIndex]['id'] = $qb->getLastInsertId(); } // Insert Submissions into DB foreach ($form['submissions'] as $suIndex => $submission) { $qb->insert('forms_v2_submissions') ->values([ 'form_id' => $qb->createNamedParameter($formId, IQueryBuilder::PARAM_INT), 'user_id' => $qb->createNamedParameter($submission['userId'], IQueryBuilder::PARAM_STR), 'timestamp' => $qb->createNamedParameter($submission['timestamp'], IQueryBuilder::PARAM_INT) ]); $qb->execute(); $submissionId = $qb->getLastInsertId(); $this->testForms[$index]['submissions'][$suIndex]['id'] = $submissionId; foreach ($submission['answers'] as $aIndex => $answer) { $qb->insert('forms_v2_answers') ->values([ 'submission_id' => $qb->createNamedParameter($submissionId, IQueryBuilder::PARAM_INT), 'question_id' => $qb->createNamedParameter($this->testForms[$index]['questions'][$answer['questionIndex']]['id'], IQueryBuilder::PARAM_INT), 'text' => $qb->createNamedParameter($answer['text'], IQueryBuilder::PARAM_STR) ]); $qb->execute(); $this->testForms[$index]['submissions'][$suIndex]['answers'][$aIndex]['id'] = $qb->getLastInsertId(); } } } // Set up http Client $this->http = new Client([ 'base_uri' => 'http://localhost:8080/ocs/v2.php/apps/forms/', 'auth' => ['test', 'test'], 'headers' => [ 'OCS-ApiRequest' => 'true', 'Accept' => 'application/json' ], ]); } /** Clean up database from testforms */ public function tearDown(): void { $qb = TestCase::$realDatabase->getQueryBuilder(); foreach ($this->testForms as $form) { $qb->delete('forms_v2_forms') ->where($qb->expr()->eq('id', $qb->createNamedParameter($form['id'], IQueryBuilder::PARAM_INT))); $qb->execute(); foreach ($form['questions'] as $question) { $qb->delete('forms_v2_questions') ->where($qb->expr()->eq('id', $qb->createNamedParameter($question['id'], IQueryBuilder::PARAM_INT))); $qb->execute(); foreach ($question['options'] as $option) { $qb->delete('forms_v2_options') ->where($qb->expr()->eq('id', $qb->createNamedParameter($option['id'], IQueryBuilder::PARAM_INT))); $qb->execute(); } } foreach ($form['shares'] as $share) { $qb->delete('forms_v2_shares') ->where($qb->expr()->eq('id', $qb->createNamedParameter($share['id'], IQueryBuilder::PARAM_INT))); $qb->execute(); } if (isset($form['submissions'])) { foreach ($form['submissions'] as $submission) { $qb->delete('forms_v2_submissions') ->where($qb->expr()->eq('id', $qb->createNamedParameter($submission['id'], IQueryBuilder::PARAM_INT))); $qb->execute(); foreach ($submission['answers'] as $answer) { $qb->delete('forms_v2_answers') ->where($qb->expr()->eq('id', $qb->createNamedParameter($answer['id'], IQueryBuilder::PARAM_INT))); $qb->execute(); } } } } parent::tearDown(); } // Small Wrapper for OCS-Response private function OcsResponse2Data($resp) { $arr = json_decode($resp->getBody()->getContents(), true); return $arr['ocs']['data']; } // Unset Id, as we can not control it on the tests. private function arrayUnsetId(array $arr): array { foreach ($arr as $index => $elem) { unset($arr[$index]['id']); } return $arr; } public function dataGetForms() { return [ 'getTestforms' => [ 'expected' => [[ 'hash' => 'abcdefg', 'title' => 'Title of a Form', 'expires' => 0, 'permissions' => [ 'edit', 'results', 'submit' ], 'partial' => true ]] ] ]; } /** * @dataProvider dataGetForms * * @param array $expected */ public function testGetForms(array $expected): void { $resp = $this->http->request('GET', 'api/v2/forms'); $data = $this->OcsResponse2Data($resp); $data = $this->arrayUnsetId($data); $this->assertEquals(200, $resp->getStatusCode()); $this->assertEquals($expected, $data); } public function dataGetSharedForms() { return [ 'getTestforms' => [ 'expected' => [[ 'hash' => 'abcdefghij', 'title' => 'Title of a second Form', 'expires' => 0, 'permissions' => [ 'submit' ], 'partial' => true ]] ] ]; } /** * @dataProvider dataGetSharedForms * * @param array $expected */ public function testGetSharedForms(array $expected): void { $resp = $this->http->request('GET', 'api/v2/shared_forms'); $data = $this->OcsResponse2Data($resp); $data = $this->arrayUnsetId($data); $this->assertEquals(200, $resp->getStatusCode()); $this->assertEquals($expected, $data); } public function dataGetPartialForm() { return [ 'getPartialForm' => [ 'expected' => [ 'hash' => 'abcdefghij', 'title' => 'Title of a second Form', 'expires' => 0, 'permissions' => [ 'submit' ], 'partial' => true ] ] ]; } /** * @dataProvider dataGetPartialForm * * @param array $expected */ public function testGetPartialForm(array $expected): void { $resp = $this->http->request('GET', "api/v2/partial_form/{$this->testForms[1]['hash']}"); $data = $this->OcsResponse2Data($resp); unset($data['id']); $this->assertEquals(200, $resp->getStatusCode()); $this->assertEquals($expected, $data); } public function dataGetNewForm() { return [ 'getNewForm' => [ 'expected' => [ // 'hash' => Some random, cannot be checked. 'title' => '', 'description' => '', 'ownerId' => 'test', // 'created' => Hard to check exactly. 'access' => [ 'permitAllUsers' => false, 'showToAllUsers' => false ], 'expires' => 0, 'isAnonymous' => false, 'submitMultiple' => false, 'canSubmit' => true, 'permissions' => [ 'edit', 'results', 'submit' ], 'questions' => [], 'shares' => [], ] ] ]; } /** * @dataProvider dataGetNewForm * * @param array $expected */ public function testGetNewForm(array $expected): void { $resp = $this->http->request('POST', 'api/v2/form'); $data = $this->OcsResponse2Data($resp); // Store for deletion on tearDown $this->testForms[] = $data; // Cannot control id unset($data['id']); // Check general behaviour of hash $this->assertMatchesRegularExpression('/^[a-zA-Z0-9]{16}$/', $data['hash']); unset($data['hash']); // Check general behaviour of created (Created in the last 10 seconds) $this->assertTrue(time() - $data['created'] < 10); unset($data['created']); $this->assertEquals(200, $resp->getStatusCode()); $this->assertEquals($expected, $data); } public function dataGetFullForm() { return [ 'getFullForm' => [ 'expected' => [ 'hash' => 'abcdefg', 'title' => 'Title of a Form', 'description' => 'Just a simple form.', 'ownerId' => 'test', 'created' => 12345, 'access' => [ 'permitAllUsers' => false, 'showToAllUsers' => false ], 'expires' => 0, 'isAnonymous' => false, 'submitMultiple' => false, 'canSubmit' => true, 'permissions' => [ 'edit', 'results', 'submit' ], 'questions' => [ [ 'type' => 'short', 'text' => 'First Question?', 'isRequired' => true, 'order' => 1, 'options' => [] ], [ 'type' => 'multiple_unique', 'text' => 'Second Question?', 'isRequired' => false, 'order' => 2, 'options' => [ [ 'text' => 'Option 1' ], [ 'text' => 'Option 2' ] ] ] ], 'shares' => [ [ 'shareType' => 0, 'shareWith' => 'user1', 'displayName' => '' ], [ 'shareType' => 3, 'shareWith' => 'shareHash', 'displayName' => '' ], ], ] ] ]; } /** * @dataProvider dataGetFullForm * * @param array $expected */ public function testGetFullForm(array $expected): void { $resp = $this->http->request('GET', "api/v2/form/{$this->testForms[0]['id']}"); $data = $this->OcsResponse2Data($resp); // Cannot control ids, but check general consistency. foreach ($data['questions'] as $qIndex => $question) { $this->assertEquals($data['id'], $question['formId']); unset($data['questions'][$qIndex]['formId']); foreach ($question['options'] as $oIndex => $option) { $this->assertEquals($question['id'], $option['questionId']); unset($data['questions'][$qIndex]['options'][$oIndex]['questionId']); unset($data['questions'][$qIndex]['options'][$oIndex]['id']); } unset($data['questions'][$qIndex]['id']); } foreach ($data['shares'] as $sIndex => $share) { $this->assertEquals($data['id'], $share['formId']); unset($data['shares'][$sIndex]['formId']); unset($data['shares'][$sIndex]['id']); } unset($data['id']); $this->assertEquals(200, $resp->getStatusCode()); $this->assertEquals($expected, $data); } public function dataCloneForm() { $fullFormExpected = $this->dataGetFullForm()['getFullForm']['expected']; // Compared to full form expected, update changed properties $fullFormExpected['title'] = 'Title of a Form - Copy'; $fullFormExpected['shares'] = []; // Compared to full form expected, unset unpredictable properties. These will be checked logically. unset($fullFormExpected['id']); unset($fullFormExpected['hash']); unset($fullFormExpected['created']); foreach ($fullFormExpected['questions'] as $qIndex => $question) { unset($fullFormExpected['questions'][$qIndex]['formId']); } return [ 'updateFormProps' => [ 'expected' => $fullFormExpected ] ]; } /** * @dataProvider dataCloneForm * * @param array $expected */ public function testCloneForm(array $expected): void { $resp = $this->http->request('POST', "api/v2/form/clone/{$this->testForms[0]['id']}"); $data = $this->OcsResponse2Data($resp); // Store for deletion on tearDown $this->testForms[] = $data; // Cannot control ids, but check general consistency. foreach ($data['questions'] as $qIndex => $question) { $this->assertEquals($data['id'], $question['formId']); unset($data['questions'][$qIndex]['formId']); foreach ($question['options'] as $oIndex => $option) { $this->assertEquals($question['id'], $option['questionId']); unset($data['questions'][$qIndex]['options'][$oIndex]['questionId']); unset($data['questions'][$qIndex]['options'][$oIndex]['id']); } unset($data['questions'][$qIndex]['id']); } foreach ($data['shares'] as $sIndex => $share) { $this->assertEquals($data['id'], $share['formId']); unset($data['shares'][$sIndex]['formId']); unset($data['shares'][$sIndex]['id']); } // Check not just returning source-form (id must differ). $this->assertGreaterThan($this->testForms[0]['id'], $data['id']); unset($data['id']); // Check general behaviour of hash $this->assertMatchesRegularExpression('/^[a-zA-Z0-9]{16}$/', $data['hash']); unset($data['hash']); // Check general behaviour of created (Created in the last 10 seconds) $this->assertTrue(time() - $data['created'] < 10); unset($data['created']); $this->assertEquals(200, $resp->getStatusCode()); $this->assertEquals($expected, $data); } public function dataUpdateFormProperties() { $fullFormExpected = $this->dataGetFullForm()['getFullForm']['expected']; $fullFormExpected['title'] = 'This is my NEW Title!'; $fullFormExpected['access'] = [ 'permitAllUsers' => true, 'showToAllUsers' => true ]; return [ 'updateFormProps' => [ 'expected' => $fullFormExpected ] ]; } /** * @dataProvider dataUpdateFormProperties * * @param array $expected */ public function testUpdateFormProperties(array $expected): void { $resp = $this->http->request('POST', 'api/v2/form/update', [ 'json' => [ 'id' => $this->testForms[0]['id'], 'keyValuePairs' => [ 'title' => 'This is my NEW Title!', 'access' => [ 'permitAllUsers' => true, 'showToAllUsers' => true ] ] ] ]); $data = $this->OcsResponse2Data($resp); $this->assertEquals(200, $resp->getStatusCode()); $this->assertEquals($this->testForms[0]['id'], $data); // Check if form equals updated form. $this->testGetFullForm($expected); } public function testDeleteForm() { $resp = $this->http->request('DELETE', "api/v2/form/{$this->testForms[0]['id']}"); $data = $this->OcsResponse2Data($resp); $this->assertEquals(200, $resp->getStatusCode()); $this->assertEquals($this->testForms[0]['id'], $data); // Check if not existent anymore. try { $this->http->request('GET', "api/v2/form/{$this->testForms[0]['id']}"); } catch (ClientException $e) { $resp = $e->getResponse(); } $this->assertEquals(400, $resp->getStatusCode()); } public function dataCreateNewQuestion() { return [ 'newQuestion' => [ 'expected' => [ // 'formId' => 3, // Checked during test // 'order' => 3, // Checked during test 'type' => 'short', 'isRequired' => false, 'text' => 'Already some Question?', 'options' => [] ] ] ]; } /** * @dataProvider dataCreateNewQuestion * * @param array $expected */ public function testCreateNewQuestion(array $expected): void { $resp = $this->http->request('POST', 'api/v2/question', [ 'json' => [ 'formId' => $this->testForms[0]['id'], 'type' => 'short', 'text' => 'Already some Question?' ] ]); $data = $this->OcsResponse2Data($resp); // Store for deletion on tearDown $this->testForms[0]['questions'][] = $data; // Check formId & order $this->assertEquals($this->testForms[0]['id'], $data['formId']); unset($data['formId']); $this->assertEquals(sizeof($this->testForms[0]['questions']), $data['order']); unset($data['order']); unset($data['id']); $this->assertEquals(200, $resp->getStatusCode()); $this->assertEquals($expected, $data); } public function dataUpdateQuestionProperties() { $fullFormExpected = $this->dataGetFullForm()['getFullForm']['expected']; $fullFormExpected['questions'][0]['text'] = 'Still first Question!'; $fullFormExpected['questions'][0]['isRequired'] = false; return [ 'updateQuestionProps' => [ 'fullFormExpected' => $fullFormExpected ] ]; } /** * @dataProvider dataUpdateQuestionProperties * * @param array $fullFormExpected */ public function testUpdateQuestionProperties(array $fullFormExpected): void { $resp = $this->http->request('POST', 'api/v2/question/update', [ 'json' => [ 'id' => $this->testForms[0]['questions'][0]['id'], 'keyValuePairs' => [ 'isRequired' => false, 'text' => 'Still first Question!' ] ] ]); $data = $this->OcsResponse2Data($resp); $this->assertEquals(200, $resp->getStatusCode()); $this->assertEquals($this->testForms[0]['questions'][0]['id'], $data); // Check if form equals updated form. $this->testGetFullForm($fullFormExpected); } public function dataReorderQuestions() { $fullFormExpected = $this->dataGetFullForm()['getFullForm']['expected']; $fullFormExpected['questions'][0]['order'] = 2; $fullFormExpected['questions'][1]['order'] = 1; // Exchange questions, as they will be returned in new order. $tmp = $fullFormExpected['questions'][0]; $fullFormExpected['questions'][0] = $fullFormExpected['questions'][1]; $fullFormExpected['questions'][1] = $tmp; return [ 'updateQuestionProps' => [ 'fullFormExpected' => $fullFormExpected ] ]; } /** * @dataProvider dataReorderQuestions * * @param array $fullFormExpected */ public function testReorderQuestions(array $fullFormExpected): void { $resp = $this->http->request('POST', 'api/v2/question/reorder', [ 'json' => [ 'formId' => $this->testForms[0]['id'], 'newOrder' => [ $this->testForms[0]['questions'][1]['id'], $this->testForms[0]['questions'][0]['id'] ] ] ]); $data = $this->OcsResponse2Data($resp); $this->assertEquals(200, $resp->getStatusCode()); $this->assertEquals([ $this->testForms[0]['questions'][0]['id'] => [ 'order' => 2 ], $this->testForms[0]['questions'][1]['id'] => [ 'order' => 1 ] ], $data); // Check if form equals updated form. $this->testGetFullForm($fullFormExpected); } public function dataDeleteQuestion() { $fullFormExpected = $this->dataGetFullForm()['getFullForm']['expected']; array_splice($fullFormExpected['questions'], 0, 1); $fullFormExpected['questions'][0]['order'] = 1; return [ 'deleteQuestion' => [ 'fullFormExpected' => $fullFormExpected ] ]; } /** * @dataProvider dataDeleteQuestion * * @param array $fullFormExpected */ public function testDeleteQuestion(array $fullFormExpected) { $resp = $this->http->request('DELETE', "api/v2/question/{$this->testForms[0]['questions'][0]['id']}"); $data = $this->OcsResponse2Data($resp); $this->assertEquals(200, $resp->getStatusCode()); $this->assertEquals($this->testForms[0]['questions'][0]['id'], $data); $this->testGetFullForm($fullFormExpected); } public function dataCreateNewOption() { return [ 'newOption' => [ 'expected' => [ // 'questionId' => Done dynamically below. 'text' => 'A new Option.' ] ] ]; } /** * @dataProvider dataCreateNewOption * * @param array $expected */ public function testCreateNewOption(array $expected): void { $resp = $this->http->request('POST', 'api/v2/option', [ 'json' => [ 'questionId' => $this->testForms[0]['questions'][1]['id'], 'text' => 'A new Option.' ] ]); $data = $this->OcsResponse2Data($resp); // Store for deletion on tearDown $this->testForms[0]['questions'][1]['options'][] = $data; // Check questionId $this->assertEquals($this->testForms[0]['questions'][1]['id'], $data['questionId']); unset($data['questionId']); unset($data['id']); $this->assertEquals(200, $resp->getStatusCode()); $this->assertEquals($expected, $data); } public function dataUpdateOptionProperties() { $fullFormExpected = $this->dataGetFullForm()['getFullForm']['expected']; $fullFormExpected['questions'][1]['options'][0]['text'] = 'New option Text.'; return [ 'updateOptionProps' => [ 'fullFormExpected' => $fullFormExpected ] ]; } /** * @dataProvider dataUpdateOptionProperties * * @param array $fullFormExpected */ public function testUpdateOptionProperties(array $fullFormExpected): void { $resp = $this->http->request('POST', 'api/v2/option/update', [ 'json' => [ 'id' => $this->testForms[0]['questions'][1]['options'][0]['id'], 'keyValuePairs' => [ 'text' => 'New option Text.' ] ] ]); $data = $this->OcsResponse2Data($resp); $this->assertEquals(200, $resp->getStatusCode()); $this->assertEquals($this->testForms[0]['questions'][1]['options'][0]['id'], $data); // Check if form equals updated form. $this->testGetFullForm($fullFormExpected); } public function dataDeleteOption() { $fullFormExpected = $this->dataGetFullForm()['getFullForm']['expected']; array_splice($fullFormExpected['questions'][1]['options'], 0, 1); return [ 'deleteOption' => [ 'fullFormExpected' => $fullFormExpected ] ]; } /** * @dataProvider dataDeleteOption * * @param array $fullFormExpected */ public function testDeleteOption(array $fullFormExpected) { $resp = $this->http->request('DELETE', "api/v2/option/{$this->testForms[0]['questions'][1]['options'][0]['id']}"); $data = $this->OcsResponse2Data($resp); $this->assertEquals(200, $resp->getStatusCode()); $this->assertEquals($this->testForms[0]['questions'][1]['options'][0]['id'], $data); $this->testGetFullForm($fullFormExpected); } public function dataAddShare() { return [ 'addAShare' => [ 'expected' => [ // 'formId' => Checked dynamically 'shareType' => 0, 'shareWith' => 'test', 'displayName' => 'Test Displayname' ] ] ]; } /** * @dataProvider dataAddShare * * @param array $expected */ public function testAddShare(array $expected) { $resp = $this->http->request('POST', 'api/v2/share', [ 'json' => [ 'formId' => $this->testForms[0]['id'], 'shareType' => 0, 'shareWith' => 'test' ] ]); $data = $this->OcsResponse2Data($resp); // Store for cleanup $this->testForms[0]['shares'][] = $data; $this->assertEquals(200, $resp->getStatusCode()); $this->assertEquals($this->testForms[0]['id'], $data['formId']); unset($data['formId']); unset($data['id']); $this->assertEquals($expected, $data); } public function dataDeleteShare() { $fullFormExpected = $this->dataGetFullForm()['getFullForm']['expected']; array_splice($fullFormExpected['shares'], 0, 1); return [ 'deleteShare' => [ 'fullFormExpected' => $fullFormExpected ] ]; } /** * @dataProvider dataDeleteShare * * @param array $fullFormExpected */ public function testDeleteShare(array $fullFormExpected) { $resp = $this->http->request('DELETE', "api/v2/share/{$this->testForms[0]['shares'][0]['id']}"); $data = $this->OcsResponse2Data($resp); $this->assertEquals(200, $resp->getStatusCode()); $this->assertEquals($this->testForms[0]['shares'][0]['id'], $data); $this->testGetFullForm($fullFormExpected); } public function dataGetSubmissions() { return [ 'getSubmissions' => [ 'expected' => [ 'submissions' => [ [ // 'formId' => Checked dynamically 'userId' => 'user1', 'userDisplayName' => 'user1', 'timestamp' => 123456, 'answers' => [ [ // 'submissionId' => Checked dynamically // 'questionId' => Checked dynamically 'text' => 'This is a short answer.' ], [ // 'submissionId' => Checked dynamically // 'questionId' => Checked dynamically 'text' => 'Option 1' ] ] ], [ // 'formId' => Checked dynamically 'userId' => 'user2', 'userDisplayName' => 'user2', 'timestamp' => 12345, 'answers' => [ [ // 'submissionId' => Checked dynamically // 'questionId' => Checked dynamically 'text' => 'This is another short answer.' ], [ // 'submissionId' => Checked dynamically // 'questionId' => Checked dynamically 'text' => 'Option 2' ] ] ] ], 'questions' => $this->dataGetFullForm()['getFullForm']['expected']['questions'] ] ] ]; } /** * @dataProvider dataGetSubmissions * * @param array $expected */ public function testGetSubmissions(array $expected) { $resp = $this->http->request('GET', "api/v2/submissions/{$this->testForms[0]['hash']}"); $data = $this->OcsResponse2Data($resp); // Cannot control ids, but check general consistency. foreach ($data['submissions'] as $sIndex => $submission) { $this->assertEquals($this->testForms[0]['id'], $submission['formId']); unset($data['submissions'][$sIndex]['formId']); foreach ($submission['answers'] as $aIndex => $answer) { $this->assertEquals($submission['id'], $answer['submissionId']); $this->assertEquals($this->testForms[0]['questions'][ $this->testForms[0]['submissions'][$sIndex]['answers'][$aIndex]['questionIndex'] ]['id'], $answer['questionId']); unset($data['submissions'][$sIndex]['answers'][$aIndex]['submissionId']); unset($data['submissions'][$sIndex]['answers'][$aIndex]['questionId']); unset($data['submissions'][$sIndex]['answers'][$aIndex]['id']); } unset($data['submissions'][$sIndex]['id']); } foreach ($data['questions'] as $qIndex => $question) { $this->assertEquals($this->testForms[0]['id'], $question['formId']); unset($data['questions'][$qIndex]['formId']); foreach ($question['options'] as $oIndex => $option) { $this->assertEquals($question['id'], $option['questionId']); unset($data['questions'][$qIndex]['options'][$oIndex]['questionId']); unset($data['questions'][$qIndex]['options'][$oIndex]['id']); } unset($data['questions'][$qIndex]['id']); } $this->assertEquals(200, $resp->getStatusCode()); $this->assertEquals($expected, $data); } public function dataExportSubmissions() { return [ 'exportSubmissions' => [ 'expected' => ' "User display name","Timestamp","First Question?","Second Question?" "user1","Friday, January 2, 1970 at 10:17:36 AM GMT+0:00","This is a short answer.","Option 1" "user2","Thursday, January 1, 1970 at 3:25:45 AM GMT+0:00","This is another short answer.","Option 2"' ] ]; } /** * @dataProvider dataExportSubmissions * * @param array $expected */ public function testExportSubmissions(string $expected) { $resp = $this->http->request('GET', "api/v2/submissions/export/{$this->testForms[0]['hash']}"); $data = substr($resp->getBody()->getContents(), 3); // Some strange Character removed at the beginning $this->assertEquals(200, $resp->getStatusCode()); $this->assertEquals('attachment; filename="Title of a Form (responses).csv"', $resp->getHeaders()['Content-Disposition'][0]); $this->assertEquals('text/csv;charset=UTF-8', $resp->getHeaders()['Content-type'][0]); $arr_txt_expected = preg_split('/,/', str_replace(["\t", "\n"], '', $expected)); $arr_txt_data = preg_split('/,/', str_replace(["\t", "\n"], '', $data)); $this->assertEquals($arr_txt_expected, $arr_txt_data); } public function testExportToCloud() { $resp = $this->http->request('POST', 'api/v2/submissions/export', [ 'json' => [ 'hash' => $this->testForms[0]['hash'], 'path' => '' ]] ); $data = $this->OcsResponse2Data($resp); $this->assertEquals(200, $resp->getStatusCode()); $this->assertEquals('Title of a Form (responses).csv', $data); } public function dataDeleteSubmissions() { $submissionsExpected = $this->dataGetSubmissions()['getSubmissions']['expected']; $submissionsExpected['submissions'] = []; return [ 'deleteSubmissions' => [ 'submissionsExpected' => $submissionsExpected ] ]; } /** * @dataProvider dataDeleteSubmissions * * @param array $submissionsExpected */ public function testDeleteSubmissions(array $submissionsExpected) { $resp = $this->http->request('DELETE', "api/v2/submissions/{$this->testForms[0]['id']}"); $data = $this->OcsResponse2Data($resp); $this->assertEquals(200, $resp->getStatusCode()); $this->assertEquals($this->testForms[0]['id'], $data); $this->testGetSubmissions($submissionsExpected); } public function dataInsertSubmission() { $submissionsExpected = $this->dataGetSubmissions()['getSubmissions']['expected']; $submissionsExpected['submissions'][] = [ 'userId' => 'test' ]; return [ 'insertSubmission' => [ 'submissionsExpected' => $submissionsExpected ] ]; } /** * @dataProvider dataInsertSubmission * * @param array $submissionsExpected */ public function testInsertSubmission(array $submissionsExpected) { $resp = $this->http->request('POST', 'api/v2/submission/insert', [ 'json' => [ 'formId' => $this->testForms[0]['id'], 'answers' => [ $this->testForms[0]['questions'][0]['id'] => ['ShortAnswer!'], $this->testForms[0]['questions'][1]['id'] => [ $this->testForms[0]['questions'][1]['options'][0]['id'] ] ] ] ]); $data = $this->OcsResponse2Data($resp); $this->assertEquals(200, $resp->getStatusCode()); // Check stored submissions $resp = $this->http->request('GET', "api/v2/submissions/{$this->testForms[0]['hash']}"); $data = $this->OcsResponse2Data($resp); // Store for deletion $this->testForms[0]['submissions'][] = $data['submissions'][0]; // Check Ids foreach ($data['submissions'][0]['answers'] as $aIndex => $answer) { $this->assertEquals($data['submissions'][0]['id'], $answer['submissionId']); unset($data['submissions'][0]['answers'][$aIndex]['id']); unset($data['submissions'][0]['answers'][$aIndex]['submissionId']); } unset($data['submissions'][0]['id']); // Check general behaviour of timestamp (Insert in the last 10 seconds) $this->assertTrue(time() - $data['submissions'][0]['timestamp'] < 10); unset($data['submissions'][0]['timestamp']); $this->assertEquals([ 'userId' => 'test', 'userDisplayName' => 'Test Displayname', 'formId' => $this->testForms[0]['id'], 'answers' => [ [ 'questionId' => $this->testForms[0]['questions'][0]['id'], 'text' => 'ShortAnswer!' ], [ 'questionId' => $this->testForms[0]['questions'][1]['id'], 'text' => 'Option 1' ] ] ], $data['submissions'][0]); } public function dataDeleteSingleSubmission() { $submissionsExpected = $this->dataGetSubmissions()['getSubmissions']['expected']; array_splice($submissionsExpected['submissions'], 0, 1); return [ 'deleteSingleSubmission' => [ 'submissionsExpected' => $submissionsExpected ] ]; } /** * @dataProvider dataDeleteSingleSubmission * * @param array $submissionsExpected */ public function testDeleteSingleSubmission(array $submissionsExpected) { $resp = $this->http->request('DELETE', "api/v2/submission/{$this->testForms[0]['submissions'][0]['id']}"); $data = $this->OcsResponse2Data($resp); $this->assertEquals(200, $resp->getStatusCode()); $this->assertEquals($this->testForms[0]['submissions'][0]['id'], $data); $this->testGetSubmissions($submissionsExpected); } };