@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.) hq.recaptime.dev/wiki/Phorge
phorge phabricator
at upstream/main 223 lines 5.9 kB view raw
1<?php 2 3final class PhutilMarkupTestCase extends PhutilTestCase { 4 5 public function testTagDefaults() { 6 $this->assertEqual( 7 (string)phutil_tag('br'), 8 (string)phutil_tag('br', array())); 9 10 $this->assertEqual( 11 (string)phutil_tag('br', array()), 12 (string)phutil_tag('br', array(), null)); 13 } 14 15 public function testTagEmpty() { 16 $this->assertEqual( 17 '<br />', 18 (string)phutil_tag('br', array(), null)); 19 20 $this->assertEqual( 21 '<div></div>', 22 (string)phutil_tag('div', array(), null)); 23 24 $this->assertEqual( 25 '<div></div>', 26 (string)phutil_tag('div', array(), '')); 27 } 28 29 public function testTagBasics() { 30 $this->assertEqual( 31 '<br />', 32 (string)phutil_tag('br')); 33 34 $this->assertEqual( 35 '<div>y</div>', 36 (string)phutil_tag('div', array(), 'y')); 37 } 38 39 public function testTagAttributes() { 40 $this->assertEqual( 41 '<div u="v">y</div>', 42 (string)phutil_tag('div', array('u' => 'v'), 'y')); 43 44 $this->assertEqual( 45 '<br u="v" />', 46 (string)phutil_tag('br', array('u' => 'v'))); 47 } 48 49 public function testTagEscapes() { 50 $this->assertEqual( 51 '<br u="&lt;" />', 52 (string)phutil_tag('br', array('u' => '<'))); 53 54 $this->assertEqual( 55 '<div><br /></div>', 56 (string)phutil_tag('div', array(), phutil_tag('br'))); 57 } 58 59 public function testTagNullAttribute() { 60 $this->assertEqual( 61 '<br />', 62 (string)phutil_tag('br', array('y' => null))); 63 } 64 65 public function testTagJavascriptProtocolRejection() { 66 $hrefs = array( 67 'javascript:alert(1)' => true, 68 'JAVASCRIPT:alert(2)' => true, 69 70 // NOTE: When interpreted as a URI, this is dropped because of leading 71 // whitespace. 72 ' javascript:alert(3)' => array(true, false), 73 '/' => false, 74 '/path/to/stuff/' => false, 75 '' => false, 76 'http://example.com/' => false, 77 '#' => false, 78 'javascript://anything' => true, 79 80 // Chrome 33 and IE11, at a minimum, treat this as Javascript. 81 "javascript\n:alert(4)" => true, 82 83 // Opera currently accepts a variety of unicode spaces. This test case 84 // has a smattering of them. 85 "\xE2\x80\x89javascript:" => true, 86 "javascript\xE2\x80\x89:" => true, 87 "\xE2\x80\x84javascript:" => true, 88 "javascript\xE2\x80\x84:" => true, 89 90 // Because we're aggressive, all of unicode should trigger detection 91 // by default. 92 "\xE2\x98\x83javascript:" => true, 93 "javascript\xE2\x98\x83:" => true, 94 "\xE2\x98\x83javascript\xE2\x98\x83:" => true, 95 96 // We're aggressive about this, so we'll intentionally raise false 97 // positives in these cases. 98 'javascript~:alert(5)' => true, 99 '!!!javascript!!!!:alert(6)' => true, 100 101 // However, we should raise true negatives in these slightly more 102 // reasonable cases. 103 'javascript/:docs.html' => false, 104 'javascripts:x.png' => false, 105 'COOLjavascript:page' => false, 106 '/javascript:alert(1)' => false, 107 ); 108 109 foreach (array(true, false) as $use_uri) { 110 foreach ($hrefs as $href => $expect) { 111 if (is_array($expect)) { 112 $expect = ($use_uri ? $expect[1] : $expect[0]); 113 } 114 115 if ($use_uri) { 116 $href_value = new PhutilURI($href); 117 } else { 118 $href_value = $href; 119 } 120 121 $caught = null; 122 try { 123 phutil_tag('a', array('href' => $href_value), 'click for candy'); 124 } catch (Exception $ex) { 125 $caught = $ex; 126 } 127 128 $desc = pht( 129 'Unexpected result for "%s". <uri = %s, expect exception = %s>', 130 $href, 131 $use_uri ? pht('Yes') : pht('No'), 132 $expect ? pht('Yes') : pht('No')); 133 134 $this->assertEqual( 135 $expect, 136 $caught instanceof Exception, 137 $desc); 138 } 139 } 140 } 141 142 public function testURIEscape() { 143 $this->assertEqual( 144 '%2B/%20%3F%23%26%3A%21xyz%25', 145 phutil_escape_uri('+/ ?#&:!xyz%')); 146 } 147 148 public function testURIPathComponentEscape() { 149 $this->assertEqual( 150 'a%252Fb', 151 phutil_escape_uri_path_component('a/b')); 152 153 $str = ''; 154 for ($ii = 0; $ii <= 255; $ii++) { 155 $str .= chr($ii); 156 } 157 158 $this->assertEqual( 159 $str, 160 phutil_unescape_uri_path_component( 161 rawurldecode( // Simulates webserver. 162 phutil_escape_uri_path_component($str)))); 163 } 164 165 public function testHsprintf() { 166 $this->assertEqual( 167 '<div>&lt;3</div>', 168 (string)hsprintf('<div>%s</div>', '<3')); 169 } 170 171 public function testAppendHTML() { 172 $html = phutil_tag('hr'); 173 $html->appendHTML(phutil_tag('br'), '<evil>'); 174 $this->assertEqual('<hr /><br />&lt;evil&gt;', $html->getHTMLContent()); 175 } 176 177 public function testArrayEscaping() { 178 $this->assertEqual( 179 '<div>&lt;div&gt;</div>', 180 phutil_escape_html( 181 array( 182 hsprintf('<div>'), 183 array( 184 array( 185 '<', 186 array( 187 'd', 188 array( 189 array( 190 hsprintf('i'), 191 ), 192 'v', 193 ), 194 ), 195 array( 196 array( 197 '>', 198 ), 199 ), 200 ), 201 ), 202 hsprintf('</div>'), 203 ))); 204 205 $this->assertEqual( 206 '<div><br /><hr /><wbr /></div>', 207 phutil_tag( 208 'div', 209 array(), 210 array( 211 array( 212 array( 213 phutil_tag('br'), 214 array( 215 phutil_tag('hr'), 216 ), 217 phutil_tag('wbr'), 218 ), 219 ), 220 ))->getHTMLContent()); 221 } 222 223}