1f30298a1SAndreas Gohr<?php 2f30298a1SAndreas Gohr 3f30298a1SAndreas Gohr/** 4f30298a1SAndreas Gohr * Check some page output for validity 50af8c6fbSAndreas Gohr * 60af8c6fbSAndreas Gohr * @group internet 7f30298a1SAndreas Gohr */ 8f30298a1SAndreas Gohrclass general_html_test extends DokuWikiTest 9f30298a1SAndreas Gohr{ 10*fc21b37bSAndreas Gohr /** @var string[] we consider these hits shortcomings in the validator and not errors */ 11*fc21b37bSAndreas Gohr protected $allowedErrors = [ 12*fc21b37bSAndreas Gohr 'The string “ugc” is not a registered keyword.', 13*fc21b37bSAndreas Gohr ]; 14f30298a1SAndreas Gohr 15f30298a1SAndreas Gohr /** 16f30298a1SAndreas Gohr * List of requests to check for validity 17f30298a1SAndreas Gohr * 18f30298a1SAndreas Gohr * @return array 19f30298a1SAndreas Gohr */ 20f30298a1SAndreas Gohr public function requestProvider() 21f30298a1SAndreas Gohr { 22f30298a1SAndreas Gohr return [ 23f30298a1SAndreas Gohr ['/doku.php', 'GET', []], 24f30298a1SAndreas Gohr ['/doku.php', 'GET', ['do' => 'recent']], 25f30298a1SAndreas Gohr ['/doku.php', 'GET', ['do' => 'index']], 26f30298a1SAndreas Gohr ['/doku.php', 'GET', ['do' => 'login']], 27f30298a1SAndreas Gohr ['/doku.php', 'GET', ['do' => 'search', 'q' => 'wiki']], 28f30298a1SAndreas Gohr ['/doku.php', 'GET', ['id' => 'wiki:syntax']], 29f30298a1SAndreas Gohr ['/doku.php', 'GET', ['id' => 'wiki:syntax', 'ns' => 'wiki', 'image' => 'wiki:dokuwiki-128.png', 'do' => 'media']], 30f30298a1SAndreas Gohr ['/lib/exe/detail.php', 'GET', ['id' => 'wiki:syntax', 'media' => 'wiki:dokuwiki-128.png']], 31f30298a1SAndreas Gohr ]; 32f30298a1SAndreas Gohr } 33f30298a1SAndreas Gohr 34f30298a1SAndreas Gohr /** 35f30298a1SAndreas Gohr * Sends the given HTML to the validator and returns the result 36f30298a1SAndreas Gohr * 37f30298a1SAndreas Gohr * @param string $html 38f30298a1SAndreas Gohr * @return array 39f30298a1SAndreas Gohr * @throws Exception when communication failed 40f30298a1SAndreas Gohr */ 41f30298a1SAndreas Gohr protected function validate($html) 42f30298a1SAndreas Gohr { 43*fc21b37bSAndreas Gohr $http = new \dokuwiki\HTTP\DokuHTTPClient(); 44f30298a1SAndreas Gohr $http->headers['Content-Type'] = 'text/html; charset=utf-8'; 45f30298a1SAndreas Gohr $result = $http->post('https://validator.w3.org/nu/?out=json&level=error', $html); 46f30298a1SAndreas Gohr 47f30298a1SAndreas Gohr if ($result === false) { 48f30298a1SAndreas Gohr throw new \Exception($http->error); 49f30298a1SAndreas Gohr } 50f30298a1SAndreas Gohr 51f30298a1SAndreas Gohr $result = json_decode($result, true); 52f30298a1SAndreas Gohr if ($result === null) { 53f30298a1SAndreas Gohr throw new \Exception('could not decode JSON'); 54f30298a1SAndreas Gohr } 55f30298a1SAndreas Gohr 56f30298a1SAndreas Gohr return $result; 57f30298a1SAndreas Gohr } 58f30298a1SAndreas Gohr 59f30298a1SAndreas Gohr /** 60f30298a1SAndreas Gohr * Reformat the errors for nicer display in output 61f30298a1SAndreas Gohr * 62f30298a1SAndreas Gohr * @param array $result 63f30298a1SAndreas Gohr * @return string[] 64f30298a1SAndreas Gohr */ 65f30298a1SAndreas Gohr protected function listErrors($result) 66f30298a1SAndreas Gohr { 67f30298a1SAndreas Gohr $errors = []; 68f30298a1SAndreas Gohr foreach ($result['messages'] as $msg) { 69*fc21b37bSAndreas Gohr if ($this->isAllowedError($msg['message'])) continue; 70f30298a1SAndreas Gohr $errors[] = "☛ " . $msg['message'] . "\n" . $msg['extract'] . "\n"; 71f30298a1SAndreas Gohr } 72f30298a1SAndreas Gohr return $errors; 73f30298a1SAndreas Gohr } 74f30298a1SAndreas Gohr 75*fc21b37bSAndreas Gohr /** 76*fc21b37bSAndreas Gohr * Is the given string an allowed error that should be skipped? 77*fc21b37bSAndreas Gohr * 78*fc21b37bSAndreas Gohr * @param string $string 79*fc21b37bSAndreas Gohr * @return bool 80*fc21b37bSAndreas Gohr */ 81*fc21b37bSAndreas Gohr protected function isAllowedError($string) 82*fc21b37bSAndreas Gohr { 83*fc21b37bSAndreas Gohr $re = join('|', array_map('preg_quote_cb', $this->allowedErrors)); 84*fc21b37bSAndreas Gohr return (bool)preg_match("/$re/", $string); 85*fc21b37bSAndreas Gohr } 86f30298a1SAndreas Gohr 87f30298a1SAndreas Gohr /** 88f30298a1SAndreas Gohr * @dataProvider requestProvider 89f30298a1SAndreas Gohr * @param string $url 90f30298a1SAndreas Gohr * @param string $method 91f30298a1SAndreas Gohr * @param array $data 92f30298a1SAndreas Gohr * @group internet 93f30298a1SAndreas Gohr */ 94f30298a1SAndreas Gohr public function test_Validity($url, $method, $data) 95f30298a1SAndreas Gohr { 96f30298a1SAndreas Gohr $request = new TestRequest(); 97f30298a1SAndreas Gohr if ($method == 'GET') { 98f30298a1SAndreas Gohr $response = $request->get($data, $url); 99f30298a1SAndreas Gohr } elseif ($method == 'POST') { 100f30298a1SAndreas Gohr $response = $request->post($data, $url); 101f30298a1SAndreas Gohr } else { 102f30298a1SAndreas Gohr throw new \RuntimeException("unknown method given: $method"); 103f30298a1SAndreas Gohr } 104f30298a1SAndreas Gohr 105f30298a1SAndreas Gohr $html = $response->getContent(); 106f30298a1SAndreas Gohr try { 107f30298a1SAndreas Gohr $result = $this->validate($html); 108f30298a1SAndreas Gohr } catch (\Exception $e) { 109f30298a1SAndreas Gohr $this->markTestSkipped($e->getMessage()); 110f30298a1SAndreas Gohr return; 111f30298a1SAndreas Gohr } 112f30298a1SAndreas Gohr 113f30298a1SAndreas Gohr $errors = $this->listErrors($result); 114f30298a1SAndreas Gohr $info = "Invalid HTML found:\n" . join("\n", $errors); 115f30298a1SAndreas Gohr 116f30298a1SAndreas Gohr $this->assertEquals(0, count($errors), $info); 117f30298a1SAndreas Gohr } 118f30298a1SAndreas Gohr} 119