browser_css_statemachine.js (13542B)
1 /* Any copyright is dedicated to the Public Domain. 2 http://creativecommons.org/publicdomain/zero/1.0/ */ 3 4 "use strict"; 5 6 const CSSCompleter = require("resource://devtools/client/shared/sourceeditor/css-autocompleter.js"); 7 const { 8 cssTokenizerWithLineColumn, 9 } = require("resource://devtools/shared/css/parsing-utils.js"); 10 11 const CSS_URI = 12 "http://mochi.test:8888/browser/devtools/client/shared/sourceeditor" + 13 "/test/css_statemachine_testcases.css"; 14 15 const source = read(CSS_URI); 16 17 // Test states to be tested for css state machine in css-autocompleter.js file.", 18 // Test cases are of the following format:", 19 // [ 20 // [ 21 // line, // The line location of the cursor 22 // ch // The column locaiton of the cursor 23 // ], 24 // [ 25 // state, // one of CSSCompleter.CSS_STATE_* 26 // selectorState, // one of CSSCompleter.CSS_SELECTOR_STATE_* 27 // completing, // what is being completed 28 // propertyName, // what property is being completed in case of value state 29 // // or the current selector that is being completed 30 // ] 31 // ] 32 const tests = [ 33 [ 34 [0, 10], 35 [CSSCompleter.CSS_STATE_NULL, "", "", ""], 36 ], 37 [ 38 [4, 3], 39 [ 40 CSSCompleter.CSS_STATE_SELECTOR, 41 CSSCompleter.CSS_SELECTOR_STATE_CLASS, 42 "de", 43 ".de", 44 ], 45 ], 46 [ 47 [5, 8], 48 [ 49 CSSCompleter.CSS_STATE_PROPERTY, 50 CSSCompleter.CSS_SELECTOR_STATE_NULL, 51 "-moz-a", 52 ], 53 ], 54 [ 55 [5, 21], 56 [ 57 CSSCompleter.CSS_STATE_VALUE, 58 CSSCompleter.CSS_SELECTOR_STATE_NULL, 59 "no", 60 "-moz-appearance", 61 ], 62 ], 63 [ 64 [6, 18], 65 [ 66 CSSCompleter.CSS_STATE_PROPERTY, 67 CSSCompleter.CSS_SELECTOR_STATE_NULL, 68 "padding", 69 ], 70 ], 71 [ 72 [6, 24], 73 [ 74 CSSCompleter.CSS_STATE_VALUE, 75 CSSCompleter.CSS_SELECTOR_STATE_NULL, 76 "3", 77 "padding", 78 ], 79 ], 80 [ 81 [6, 29], 82 [ 83 CSSCompleter.CSS_STATE_PROPERTY, 84 CSSCompleter.CSS_SELECTOR_STATE_NULL, 85 "bo", 86 ], 87 ], 88 [ 89 [6, 50], 90 [ 91 CSSCompleter.CSS_STATE_VALUE, 92 CSSCompleter.CSS_SELECTOR_STATE_NULL, 93 "1p", 94 "border-bottom-width", 95 ], 96 ], 97 [ 98 [7, 24], 99 [ 100 CSSCompleter.CSS_STATE_VALUE, 101 CSSCompleter.CSS_SELECTOR_STATE_NULL, 102 "s", 103 "border-bottom-style", 104 ], 105 ], 106 [ 107 [9, 0], 108 [CSSCompleter.CSS_STATE_NULL, CSSCompleter.CSS_SELECTOR_STATE_NULL, "", ""], 109 ], 110 [ 111 [10, 6], 112 [ 113 CSSCompleter.CSS_STATE_SELECTOR, 114 CSSCompleter.CSS_SELECTOR_STATE_ID, 115 "devto", 116 "#devto", 117 ], 118 ], 119 [ 120 [10, 17], 121 [ 122 CSSCompleter.CSS_STATE_SELECTOR, 123 CSSCompleter.CSS_SELECTOR_STATE_CLASS, 124 "de", 125 "#devtools-menu.de", 126 ], 127 ], 128 [ 129 [11, 5], 130 [ 131 CSSCompleter.CSS_STATE_SELECTOR, 132 CSSCompleter.CSS_SELECTOR_STATE_CLASS, 133 "devt", 134 ".devt", 135 ], 136 ], 137 [ 138 [11, 30], 139 [ 140 CSSCompleter.CSS_STATE_SELECTOR, 141 CSSCompleter.CSS_SELECTOR_STATE_ID, 142 "devtoo", 143 ".devtools-toolbarbutton#devtoo", 144 ], 145 ], 146 [ 147 [12, 10], 148 [ 149 CSSCompleter.CSS_STATE_PROPERTY, 150 CSSCompleter.CSS_SELECTOR_STATE_NULL, 151 "-moz-app", 152 ], 153 ], 154 [ 155 [16, 27], 156 [ 157 CSSCompleter.CSS_STATE_VALUE, 158 CSSCompleter.CSS_SELECTOR_STATE_NULL, 159 "hsl", 160 "text-shadow", 161 ], 162 ], 163 [ 164 [19, 24], 165 [ 166 CSSCompleter.CSS_STATE_VALUE, 167 CSSCompleter.CSS_SELECTOR_STATE_NULL, 168 "linear-gra", 169 "background", 170 ], 171 ], 172 [ 173 [19, 55], 174 [ 175 CSSCompleter.CSS_STATE_VALUE, 176 CSSCompleter.CSS_SELECTOR_STATE_NULL, 177 "hsl", 178 "background", 179 ], 180 ], 181 [ 182 [19, 79], 183 [ 184 CSSCompleter.CSS_STATE_VALUE, 185 CSSCompleter.CSS_SELECTOR_STATE_NULL, 186 "paddin", 187 "background", 188 ], 189 ], 190 [ 191 [20, 47], 192 [ 193 CSSCompleter.CSS_STATE_VALUE, 194 CSSCompleter.CSS_SELECTOR_STATE_NULL, 195 "ins", 196 "box-shadow", 197 ], 198 ], 199 [ 200 [22, 15], 201 [ 202 CSSCompleter.CSS_STATE_VALUE, 203 CSSCompleter.CSS_SELECTOR_STATE_NULL, 204 "inheri", 205 "color", 206 ], 207 ], 208 [ 209 [25, 26], 210 [ 211 CSSCompleter.CSS_STATE_SELECTOR, 212 CSSCompleter.CSS_SELECTOR_STATE_NULL, 213 "", 214 ".devtools-toolbarbutton > ", 215 ], 216 ], 217 [ 218 [25, 28], 219 [ 220 CSSCompleter.CSS_STATE_SELECTOR, 221 CSSCompleter.CSS_SELECTOR_STATE_TAG, 222 "hb", 223 ".devtools-toolbarbutton > hb", 224 ], 225 ], 226 [ 227 [25, 41], 228 [ 229 CSSCompleter.CSS_STATE_SELECTOR, 230 CSSCompleter.CSS_SELECTOR_STATE_CLASS, 231 "toolbarbut", 232 ".devtools-toolbarbutton > hbox.toolbarbut", 233 ], 234 ], 235 [ 236 [29, 21], 237 [ 238 CSSCompleter.CSS_STATE_SELECTOR, 239 CSSCompleter.CSS_SELECTOR_STATE_PSEUDO, 240 "ac", 241 ".devtools-menulist:ac", 242 ], 243 ], 244 [ 245 [30, 27], 246 [ 247 CSSCompleter.CSS_STATE_SELECTOR, 248 CSSCompleter.CSS_SELECTOR_STATE_PSEUDO, 249 "foc", 250 "#devtools-toolbarbutton:foc", 251 ], 252 ], 253 [ 254 [31, 18], 255 [ 256 CSSCompleter.CSS_STATE_VALUE, 257 CSSCompleter.CSS_SELECTOR_STATE_NULL, 258 "dot", 259 "outline", 260 ], 261 ], 262 [ 263 [32, 25], 264 [ 265 CSSCompleter.CSS_STATE_VALUE, 266 CSSCompleter.CSS_SELECTOR_STATE_NULL, 267 "-4p", 268 "outline-offset", 269 ], 270 ], 271 [ 272 [35, 26], 273 [ 274 CSSCompleter.CSS_STATE_SELECTOR, 275 CSSCompleter.CSS_SELECTOR_STATE_PSEUDO, 276 "no", 277 ".devtools-toolbarbutton:no", 278 ], 279 ], 280 [ 281 [35, 28], 282 [ 283 CSSCompleter.CSS_STATE_SELECTOR, 284 CSSCompleter.CSS_SELECTOR_STATE_NULL, 285 "not", 286 "", 287 ], 288 ], 289 [ 290 [35, 30], 291 [ 292 CSSCompleter.CSS_STATE_SELECTOR, 293 CSSCompleter.CSS_SELECTOR_STATE_ATTRIBUTE, 294 "l", 295 "[l", 296 ], 297 ], 298 [ 299 [39, 46], 300 [ 301 CSSCompleter.CSS_STATE_SELECTOR, 302 CSSCompleter.CSS_SELECTOR_STATE_CLASS, 303 "toolba", 304 ".devtools-toolbarbutton:not([label]) > .toolba", 305 ], 306 ], 307 [ 308 [43, 39], 309 [ 310 CSSCompleter.CSS_STATE_SELECTOR, 311 CSSCompleter.CSS_SELECTOR_STATE_VALUE, 312 "tr", 313 "[checked=tr", 314 ], 315 ], 316 [ 317 [43, 47], 318 [ 319 CSSCompleter.CSS_STATE_SELECTOR, 320 CSSCompleter.CSS_SELECTOR_STATE_PSEUDO, 321 "hov", 322 ".devtools-toolbarbutton:not([checked=true]):hov", 323 ], 324 ], 325 [ 326 [43, 53], 327 [ 328 CSSCompleter.CSS_STATE_SELECTOR, 329 CSSCompleter.CSS_SELECTOR_STATE_PSEUDO, 330 "act", 331 ".devtools-toolbarbutton:not([checked=true]):hover:act", 332 ], 333 ], 334 [ 335 [47, 22], 336 [ 337 CSSCompleter.CSS_STATE_SELECTOR, 338 CSSCompleter.CSS_SELECTOR_STATE_ATTRIBUTE, 339 "op", 340 ".devtools-menulist[op", 341 ], 342 ], 343 [ 344 [47, 33], 345 [ 346 CSSCompleter.CSS_STATE_SELECTOR, 347 CSSCompleter.CSS_SELECTOR_STATE_VALUE, 348 "tr", 349 ".devtools-menulist[open =tr", 350 ], 351 ], 352 [ 353 [48, 38], 354 [ 355 CSSCompleter.CSS_STATE_SELECTOR, 356 CSSCompleter.CSS_SELECTOR_STATE_VALUE, 357 "tr", 358 ".devtools-toolbarbutton[open = tr", 359 ], 360 ], 361 [ 362 [49, 40], 363 [ 364 CSSCompleter.CSS_STATE_SELECTOR, 365 CSSCompleter.CSS_SELECTOR_STATE_VALUE, 366 "true", 367 ".devtools-toolbarbutton[checked= true", 368 ], 369 ], 370 [ 371 [53, 34], 372 [ 373 CSSCompleter.CSS_STATE_SELECTOR, 374 CSSCompleter.CSS_SELECTOR_STATE_VALUE, 375 "=", 376 ".devtools-toolbarbutton[checked=", 377 ], 378 ], 379 [ 380 [58, 38], 381 [ 382 CSSCompleter.CSS_STATE_VALUE, 383 CSSCompleter.CSS_SELECTOR_STATE_NULL, 384 "!impor", 385 "background-color", 386 ], 387 ], 388 [ 389 [61, 41], 390 [ 391 CSSCompleter.CSS_STATE_SELECTOR, 392 CSSCompleter.CSS_SELECTOR_STATE_PSEUDO, 393 "hov", 394 ".devtools-toolbarbutton[checked=true]:hov", 395 ], 396 ], 397 [ 398 [65, 47], 399 [ 400 CSSCompleter.CSS_STATE_SELECTOR, 401 CSSCompleter.CSS_SELECTOR_STATE_CLASS, 402 "to", 403 ".devtools-toolbarbutton[type=menu-button] > .to", 404 ], 405 ], 406 [ 407 [69, 44], 408 [ 409 CSSCompleter.CSS_STATE_SELECTOR, 410 CSSCompleter.CSS_SELECTOR_STATE_PSEUDO, 411 "first-of", 412 ".devtools-sidebar-tabs > tabs > tab:first-of", 413 ], 414 ], 415 [ 416 [73, 45], 417 [ 418 CSSCompleter.CSS_STATE_SELECTOR, 419 CSSCompleter.CSS_SELECTOR_STATE_PSEUDO, 420 "last", 421 ":last", 422 ], 423 ], 424 [ 425 [77, 27], 426 [ 427 CSSCompleter.CSS_STATE_SELECTOR, 428 CSSCompleter.CSS_SELECTOR_STATE_CLASS, 429 "vis", 430 ".vis", 431 ], 432 ], 433 [ 434 [78, 34], 435 [ 436 CSSCompleter.CSS_STATE_SELECTOR, 437 CSSCompleter.CSS_SELECTOR_STATE_CLASS, 438 "hidd", 439 ".hidden-labels-box.visible ~ .hidd", 440 ], 441 ], 442 [ 443 [83, 5], 444 [ 445 CSSCompleter.CSS_STATE_MEDIA, 446 CSSCompleter.CSS_SELECTOR_STATE_NULL, 447 "medi", 448 ], 449 ], 450 [ 451 [83, 22], 452 [CSSCompleter.CSS_STATE_MEDIA, CSSCompleter.CSS_SELECTOR_STATE_NULL, "800"], 453 ], 454 [ 455 [84, 9], 456 [ 457 CSSCompleter.CSS_STATE_SELECTOR, 458 CSSCompleter.CSS_SELECTOR_STATE_CLASS, 459 "catego", 460 ".catego", 461 ], 462 ], 463 [ 464 [89, 9], 465 [CSSCompleter.CSS_STATE_MEDIA, CSSCompleter.CSS_SELECTOR_STATE_NULL, "al"], 466 ], 467 [ 468 [90, 6], 469 [ 470 CSSCompleter.CSS_STATE_SELECTOR, 471 CSSCompleter.CSS_SELECTOR_STATE_ID, 472 "err", 473 "#err", 474 ], 475 ], 476 [ 477 [93, 11], 478 [ 479 CSSCompleter.CSS_STATE_PROPERTY, 480 CSSCompleter.CSS_SELECTOR_STATE_NULL, 481 "backgro", 482 ], 483 ], 484 [ 485 [98, 6], 486 [ 487 CSSCompleter.CSS_STATE_SELECTOR, 488 CSSCompleter.CSS_SELECTOR_STATE_TAG, 489 "butt", 490 "butt", 491 ], 492 ], 493 [ 494 [99, 22], 495 [ 496 CSSCompleter.CSS_STATE_VALUE, 497 CSSCompleter.CSS_SELECTOR_STATE_NULL, 498 "!impor", 499 "width", 500 ], 501 ], 502 [ 503 [103, 5], 504 [ 505 CSSCompleter.CSS_STATE_KEYFRAMES, 506 CSSCompleter.CSS_SELECTOR_STATE_NULL, 507 "ke", 508 ], 509 ], 510 [ 511 [104, 7], 512 [CSSCompleter.CSS_STATE_FRAME, CSSCompleter.CSS_SELECTOR_STATE_NULL, "fro"], 513 ], 514 [ 515 [104, 15], 516 [ 517 CSSCompleter.CSS_STATE_PROPERTY, 518 CSSCompleter.CSS_SELECTOR_STATE_NULL, 519 "opac", 520 ], 521 ], 522 [ 523 [104, 29], 524 [ 525 CSSCompleter.CSS_STATE_PROPERTY, 526 CSSCompleter.CSS_SELECTOR_STATE_NULL, 527 "transf", 528 ], 529 ], 530 [ 531 [104, 38], 532 [ 533 CSSCompleter.CSS_STATE_VALUE, 534 CSSCompleter.CSS_SELECTOR_STATE_NULL, 535 "scal", 536 "transform", 537 ], 538 ], 539 [ 540 [105, 8], 541 [CSSCompleter.CSS_STATE_FRAME, CSSCompleter.CSS_SELECTOR_STATE_NULL, ""], 542 ], 543 [ 544 [113, 6], 545 [ 546 CSSCompleter.CSS_STATE_KEYFRAMES, 547 CSSCompleter.CSS_SELECTOR_STATE_NULL, 548 "keyfr", 549 ], 550 ], 551 [ 552 [114, 4], 553 [CSSCompleter.CSS_STATE_FRAME, CSSCompleter.CSS_SELECTOR_STATE_NULL, "fr"], 554 ], 555 [ 556 [115, 3], 557 [CSSCompleter.CSS_STATE_FRAME, CSSCompleter.CSS_SELECTOR_STATE_NULL, "2"], 558 ], 559 [ 560 [117, 8], 561 [ 562 CSSCompleter.CSS_STATE_PROPERTY, 563 CSSCompleter.CSS_SELECTOR_STATE_NULL, 564 "opac", 565 ], 566 ], 567 [ 568 [117, 16], 569 [ 570 CSSCompleter.CSS_STATE_VALUE, 571 CSSCompleter.CSS_SELECTOR_STATE_NULL, 572 "0", 573 "opacity", 574 ], 575 ], 576 [ 577 [121, 0], 578 [CSSCompleter.CSS_STATE_NULL, "", ""], 579 ], 580 ]; 581 582 const TEST_URI = 583 "data:text/html;charset=UTF-8," + 584 encodeURIComponent(` 585 <!DOCTYPE html> 586 <html> 587 <head><title>CSS State machine tests.</title></head> 588 <body> 589 <h2>State machine tests for CSS autocompleter.</h2> 590 </body> 591 </html> 592 `); 593 594 add_task(async function test() { 595 await addTab(TEST_URI); 596 597 const completer = new CSSCompleter({ 598 cssProperties: getClientCssProperties(), 599 }); 600 601 let i = 0; 602 for (const testcase of tests) { 603 ++i; 604 // if (i !== 2) continue; 605 const [[line, column], expected] = testcase; 606 const limitedSource = limit(source, [line, column]); 607 608 info(`Test case ${i} from source`); 609 completer.resolveState({ 610 source: limitedSource, 611 line, 612 column, 613 }); 614 assertState(completer, expected, i + " (from_source)"); 615 616 info(`Test case ${i} from tokens`); 617 completer.resolveState({ 618 sourceTokens: cssTokenizerWithLineColumn(limitedSource), 619 }); 620 assertState(completer, expected, i + " (from tokens)"); 621 } 622 gBrowser.removeCurrentTab(); 623 }); 624 625 function assertState(completer, expected, testCaseName) { 626 if (checkState(completer, expected)) { 627 ok(true, `Test ${testCaseName} passed. `); 628 } else { 629 ok( 630 false, 631 `Test ${testCaseName} failed. Expected state : ${JSON.stringify([ 632 expected[0]?.toString(), 633 expected[1]?.toString(), 634 expected[2], 635 expected[3], 636 ])} but found ${JSON.stringify([ 637 completer.state?.toString(), 638 completer.selectorState?.toString(), 639 completer.completing, 640 completer.propertyName || completer.selector, 641 ])}.` 642 ); 643 } 644 } 645 646 function checkState(completer, expected) { 647 if ( 648 expected[0] == CSSCompleter.CSS_STATE_NULL && 649 (!completer.state || completer.state == CSSCompleter.CSS_STATE_NULL) 650 ) { 651 return true; 652 } else if ( 653 expected[0] == completer.state && 654 expected[0] == CSSCompleter.CSS_STATE_SELECTOR && 655 expected[1] == completer.selectorState && 656 expected[2] == completer.completing && 657 expected[3] == completer.selector 658 ) { 659 return true; 660 } else if ( 661 expected[0] == completer.state && 662 expected[0] == CSSCompleter.CSS_STATE_VALUE && 663 expected[2] == completer.completing && 664 expected[3] == completer.propertyName 665 ) { 666 return true; 667 } else if ( 668 expected[0] == completer.state && 669 expected[2] == completer.completing && 670 expected[0] != CSSCompleter.CSS_STATE_SELECTOR && 671 expected[0] != CSSCompleter.CSS_STATE_VALUE 672 ) { 673 return true; 674 } 675 return false; 676 }