| 1 | #!/usr/bin/env python2
|
| 2 | from __future__ import print_function
|
| 3 |
|
| 4 | import cmark # Oils dev dependency
|
| 5 |
|
| 6 | import unittest
|
| 7 |
|
| 8 | from data_lang import htm8
|
| 9 | from doctools import ul_table
|
| 10 |
|
| 11 | # <ulcol> is a special annotation
|
| 12 | TEST1 = """\
|
| 13 | <table id="foo">
|
| 14 |
|
| 15 | - thead
|
| 16 | - <cell-attrs class="foo" /> name
|
| 17 | - <cell-attrs class="bar" /> [age](https://example.com/)
|
| 18 | - tr
|
| 19 | - alice *italic*
|
| 20 | - 30
|
| 21 | - tr
|
| 22 | - bob
|
| 23 | - 42
|
| 24 |
|
| 25 | </table>""" # no extra
|
| 26 |
|
| 27 | TD_ATTRS = """\
|
| 28 | <table>
|
| 29 |
|
| 30 | - thead
|
| 31 | - <cell-attrs class=unquoted /> name
|
| 32 | - <cell-attrs class=quoted /> age
|
| 33 | - role
|
| 34 | - tr <!-- comment --> <!-- comment 2 -->
|
| 35 | - <cell-attrs class="cool" /> alice
|
| 36 | - 30
|
| 37 | - parent
|
| 38 | - tr
|
| 39 | - bob
|
| 40 | - 42
|
| 41 | - <cell-attrs class=child /> child
|
| 42 |
|
| 43 | </table>
|
| 44 | """
|
| 45 |
|
| 46 | TD_ATTRS_HTML = """\
|
| 47 | <table>
|
| 48 | <thead>
|
| 49 | <tr>
|
| 50 | <th> name</th>
|
| 51 | <th> age</th>
|
| 52 | <th>role</th>
|
| 53 | </tr>
|
| 54 | </thead>
|
| 55 | <tr>
|
| 56 | <td class="unquoted cool"> alice</td>
|
| 57 | <td class="quoted">30</td>
|
| 58 | <td>parent</td>
|
| 59 | </tr>
|
| 60 | <tr>
|
| 61 | <td class="unquoted">bob</td>
|
| 62 | <td class="quoted">42</td>
|
| 63 | <td class="child"> child</td>
|
| 64 | </tr>
|
| 65 | </table>
|
| 66 | """
|
| 67 |
|
| 68 | TRAILING_ATTRS = """\
|
| 69 | <table>
|
| 70 |
|
| 71 | - thead
|
| 72 | - OSH
|
| 73 | - YSH
|
| 74 | - tr
|
| 75 | - ```
|
| 76 | echo osh
|
| 77 | ```
|
| 78 | <cell-attrs class=osh-code />
|
| 79 | - ```
|
| 80 | echo ysh
|
| 81 | ```
|
| 82 | <cell-attrs class=ysh-code />
|
| 83 |
|
| 84 | </table>
|
| 85 | """
|
| 86 |
|
| 87 | TRAILING_ATTRS_HTML = """\
|
| 88 | <table>
|
| 89 | <thead>
|
| 90 | <tr>
|
| 91 | <th>OSH</th>
|
| 92 | <th>YSH</th>
|
| 93 | </tr>
|
| 94 | </thead>
|
| 95 | <tr>
|
| 96 | <td class="osh-code">
|
| 97 | <pre><code>echo osh
|
| 98 | </code></pre>
|
| 99 |
|
| 100 | </td>
|
| 101 | <td class="ysh-code">
|
| 102 | <pre><code>echo ysh
|
| 103 | </code></pre>
|
| 104 |
|
| 105 | </td>
|
| 106 | </tr>
|
| 107 | </table>
|
| 108 | """
|
| 109 |
|
| 110 | TR_ATTRS = """\
|
| 111 | <table>
|
| 112 |
|
| 113 | - thead
|
| 114 | - <cell-attrs class=unquoted /> name
|
| 115 | - <cell-attrs class=quoted /> age
|
| 116 | - role
|
| 117 | - tr <row-attrs class=totals />
|
| 118 | - alice
|
| 119 | - 30
|
| 120 | - parent
|
| 121 | - tr
|
| 122 | - bob
|
| 123 | - 42
|
| 124 | - <cell-attrs class=child /> child
|
| 125 |
|
| 126 | </table>
|
| 127 | """
|
| 128 |
|
| 129 | TR_ATTRS_HTML = """\
|
| 130 | <table>
|
| 131 | <thead>
|
| 132 | <tr>
|
| 133 | <th> name</th>
|
| 134 | <th> age</th>
|
| 135 | <th>role</th>
|
| 136 | </tr>
|
| 137 | </thead>
|
| 138 | <tr class="totals">
|
| 139 | <td class="unquoted">alice</td>
|
| 140 | <td class="quoted">30</td>
|
| 141 | <td>parent</td>
|
| 142 | </tr>
|
| 143 | <tr>
|
| 144 | <td class="unquoted">bob</td>
|
| 145 | <td class="quoted">42</td>
|
| 146 | <td class="child"> child</td>
|
| 147 | </tr>
|
| 148 | </table>
|
| 149 | """
|
| 150 |
|
| 151 | # Note CSS Grid can express colspan
|
| 152 | # https://developer.mozilla.org/en-US/docs/Web/CSS/grid-column
|
| 153 |
|
| 154 | COLSPAN = """\
|
| 155 | <!-- begin REPLACE -->
|
| 156 |
|
| 157 | <table>
|
| 158 |
|
| 159 | - thead
|
| 160 | - <cell-attrs class=foo /> name
|
| 161 | - age
|
| 162 | - tr
|
| 163 | - alice
|
| 164 | - 30
|
| 165 | - tr
|
| 166 | - <cell-attrs colspan=2 /> ... more ...
|
| 167 | - tr
|
| 168 | - bob
|
| 169 | - 42
|
| 170 |
|
| 171 | </table>
|
| 172 |
|
| 173 | <!-- end REPLACE -->
|
| 174 | """
|
| 175 |
|
| 176 | COLSPAN_HTML = """\
|
| 177 | <!-- begin REPLACE -->
|
| 178 | <table>
|
| 179 | <thead>
|
| 180 | <tr>
|
| 181 | <th> name</th>
|
| 182 | <th>age</th>
|
| 183 | </tr>
|
| 184 | </thead>
|
| 185 | <tr>
|
| 186 | <td class="foo">alice</td>
|
| 187 | <td>30</td>
|
| 188 | </tr>
|
| 189 | <tr>
|
| 190 | <td class="foo" colspan="2"> ... more ...</td>
|
| 191 | </tr>
|
| 192 | <tr>
|
| 193 | <td class="foo">bob</td>
|
| 194 | <td>42</td>
|
| 195 | </tr>
|
| 196 | </table>
|
| 197 | <!-- end REPLACE -->
|
| 198 | """
|
| 199 |
|
| 200 | # UNUSED - not worth it now
|
| 201 | MIXED_TR = """\
|
| 202 | <table>
|
| 203 |
|
| 204 | - thead
|
| 205 | - name
|
| 206 | - age
|
| 207 | - tr
|
| 208 | - 30
|
| 209 | - parent
|
| 210 |
|
| 211 | <tr>
|
| 212 | <td colspan=2> - </td>
|
| 213 | </tr>
|
| 214 |
|
| 215 | - tr
|
| 216 | - bob
|
| 217 | - 42
|
| 218 | - <cell-attrs class=child /> child
|
| 219 |
|
| 220 | </table>
|
| 221 | """
|
| 222 |
|
| 223 |
|
| 224 | def MarkdownToTable(md):
|
| 225 | # type: (str) -> str
|
| 226 | # markdown -> HTML
|
| 227 |
|
| 228 | h = cmark.md2html(md)
|
| 229 | # Markdown adds a newline
|
| 230 | if h.endswith('\n'):
|
| 231 | print('ENDS WITH NEWLINE %r' % h[-10:])
|
| 232 |
|
| 233 | if 1:
|
| 234 | print('---')
|
| 235 | print('ORIGINAL')
|
| 236 | print(h)
|
| 237 | print('')
|
| 238 |
|
| 239 | h = ul_table.RemoveComments(h)
|
| 240 | h = ul_table.ReplaceTables(h)
|
| 241 |
|
| 242 | if 1:
|
| 243 | print('---')
|
| 244 | print('REPLACED')
|
| 245 | print(h)
|
| 246 | print('')
|
| 247 |
|
| 248 | return h
|
| 249 |
|
| 250 |
|
| 251 | class UlTableTest(unittest.TestCase):
|
| 252 |
|
| 253 | def testOne(self):
|
| 254 | # type: () -> None
|
| 255 | h = MarkdownToTable('hi\n' + TEST1 + '\n\n bye \n')
|
| 256 |
|
| 257 | def testNoHeader(self):
|
| 258 | # type: () -> None
|
| 259 | # HTML looks like:
|
| 260 | #
|
| 261 | # <table>
|
| 262 | # <ul> # problem: we need to lookahead SPACE <li> (tr or thead)
|
| 263 | # <li>tr
|
| 264 | # <ul>
|
| 265 | # <li>one</li>
|
| 266 | # </ul>
|
| 267 | # </li>
|
| 268 | # </ul>
|
| 269 | # </table>
|
| 270 |
|
| 271 | h = MarkdownToTable('''\
|
| 272 | <table>
|
| 273 |
|
| 274 | - tr
|
| 275 | - one
|
| 276 | - two
|
| 277 |
|
| 278 | </table>
|
| 279 | ''')
|
| 280 | print(h)
|
| 281 |
|
| 282 | def testSimple(self):
|
| 283 | # type: () -> None
|
| 284 | h = MarkdownToTable("""\
|
| 285 | <table>
|
| 286 |
|
| 287 | - thead
|
| 288 | - *name*
|
| 289 | - *age*
|
| 290 | - tr
|
| 291 | - alice
|
| 292 | - 30
|
| 293 | - tr
|
| 294 | - bob
|
| 295 | - 40
|
| 296 |
|
| 297 | <table>
|
| 298 | """)
|
| 299 | self.assertMultiLineEqual(
|
| 300 | """\
|
| 301 | <table>
|
| 302 | <thead>
|
| 303 | <tr>
|
| 304 | <th><em>name</em></th>
|
| 305 | <th><em>age</em></th>
|
| 306 | </tr>
|
| 307 | </thead>
|
| 308 | <tr>
|
| 309 | <td>alice</td>
|
| 310 | <td>30</td>
|
| 311 | </tr>
|
| 312 | <tr>
|
| 313 | <td>bob</td>
|
| 314 | <td>40</td>
|
| 315 | </tr>
|
| 316 | <table>
|
| 317 | """, h)
|
| 318 |
|
| 319 | def testMultipleTables(self):
|
| 320 | # type: () -> None
|
| 321 | # They can be right next to each other
|
| 322 | html_one = MarkdownToTable(TEST1)
|
| 323 |
|
| 324 | self.assert_(not TEST1.endswith('\n'))
|
| 325 | # CommonMark added a newline
|
| 326 | self.assert_(html_one.endswith('\n'))
|
| 327 | html_one = html_one[:-1]
|
| 328 |
|
| 329 | html_two = MarkdownToTable(TEST1 + TEST1)
|
| 330 |
|
| 331 | # The output is just concatenated
|
| 332 | self.assertMultiLineEqual(html_one + html_one + '\n', html_two)
|
| 333 |
|
| 334 | def testMultipleTablesWithSpace(self):
|
| 335 | # type: () -> None
|
| 336 | h = MarkdownToTable(TEST1 + '\n\n hi \n' + TEST1)
|
| 337 |
|
| 338 | def testTdAttrs(self):
|
| 339 | # type: () -> None
|
| 340 | h = MarkdownToTable(TD_ATTRS)
|
| 341 | self.assertMultiLineEqual(TD_ATTRS_HTML, h)
|
| 342 |
|
| 343 | def testTdAttrsTrailing(self):
|
| 344 | # type: () -> None
|
| 345 | self.maxDiff = 2000
|
| 346 | h = MarkdownToTable(TRAILING_ATTRS)
|
| 347 | if 1:
|
| 348 | print('expect', repr(TRAILING_ATTRS_HTML))
|
| 349 | print('actual', repr(h))
|
| 350 | self.assertMultiLineEqual(TRAILING_ATTRS_HTML, h)
|
| 351 |
|
| 352 | def testColspan(self):
|
| 353 | # type: () -> None
|
| 354 | h = MarkdownToTable(COLSPAN)
|
| 355 | self.assertMultiLineEqual(COLSPAN_HTML, h)
|
| 356 |
|
| 357 | def testTrAttrs(self):
|
| 358 | # type: () -> None
|
| 359 | h = MarkdownToTable(TR_ATTRS)
|
| 360 | self.assertMultiLineEqual(TR_ATTRS_HTML, h)
|
| 361 |
|
| 362 | def testMixedTr(self):
|
| 363 | # type: () -> None
|
| 364 | # Not worth it
|
| 365 | return
|
| 366 | h = MarkdownToTable(MIXED_TR)
|
| 367 | #self.assertMultiLineEqual(MIXED_TR, h)
|
| 368 |
|
| 369 | def testSyntaxErrors(self):
|
| 370 | # type: () -> None
|
| 371 | # Once we get <table><ul>, then we TAKE OVER, and start being STRICT
|
| 372 |
|
| 373 | try:
|
| 374 | h = MarkdownToTable("""
|
| 375 | <table>
|
| 376 |
|
| 377 | - should be thead
|
| 378 | - one
|
| 379 | - two
|
| 380 | """)
|
| 381 | except htm8.ParseError as e:
|
| 382 | print(e)
|
| 383 | else:
|
| 384 | self.fail('Expected parse error')
|
| 385 |
|
| 386 | try:
|
| 387 | h = MarkdownToTable("""
|
| 388 | <table>
|
| 389 |
|
| 390 | - thead
|
| 391 | - one
|
| 392 | - two
|
| 393 | - tr <bad-attrs />
|
| 394 | - 1
|
| 395 | - 2
|
| 396 | """)
|
| 397 | except htm8.ParseError as e:
|
| 398 | print(e)
|
| 399 | else:
|
| 400 | self.fail('Expected parse error')
|
| 401 |
|
| 402 | def testColumnCheck(self):
|
| 403 | # type: () -> None
|
| 404 | # Disabled because of colspan
|
| 405 | return
|
| 406 |
|
| 407 | try:
|
| 408 | h = MarkdownToTable("""
|
| 409 | <table>
|
| 410 |
|
| 411 | - thead
|
| 412 | - one
|
| 413 | - two
|
| 414 | - tr
|
| 415 | - 1
|
| 416 | - 2
|
| 417 | - tr
|
| 418 | - wrong number of cells
|
| 419 | - tr
|
| 420 | - 3
|
| 421 | - 4
|
| 422 |
|
| 423 | </table>
|
| 424 | """)
|
| 425 | except htm8.ParseError as e:
|
| 426 | print(e)
|
| 427 | else:
|
| 428 | self.fail('Expected parse error')
|
| 429 |
|
| 430 |
|
| 431 | if __name__ == '__main__':
|
| 432 | unittest.main()
|