tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

doc_test.js (11353B)


      1 (function() {
      2  // A minilanguage for instantiating linked CodeMirror instances and Docs
      3  function instantiateSpec(spec, place, opts) {
      4    var names = {}, pos = 0, l = spec.length, editors = [];
      5    while (spec) {
      6      var m = spec.match(/^(\w+)(\*?)(?:='([^\']*)'|<(~?)(\w+)(?:\/(\d+)-(\d+))?)\s*/);
      7      var name = m[1], isDoc = m[2], cur;
      8      if (m[3]) {
      9        cur = isDoc ? CodeMirror.Doc(m[3]) : CodeMirror(place, clone(opts, {value: m[3]}));
     10      } else {
     11        var other = m[5];
     12        if (!names.hasOwnProperty(other)) {
     13          names[other] = editors.length;
     14          editors.push(CodeMirror(place, opts));
     15        }
     16        var doc = editors[names[other]].linkedDoc({
     17          sharedHist: !m[4],
     18          from: m[6] ? Number(m[6]) : null,
     19          to: m[7] ? Number(m[7]) : null
     20        });
     21        cur = isDoc ? doc : CodeMirror(place, clone(opts, {value: doc}));
     22      }
     23      names[name] = editors.length;
     24      editors.push(cur);
     25      spec = spec.slice(m[0].length);
     26    }
     27    return editors;
     28  }
     29 
     30  function clone(obj, props) {
     31    if (!obj) return;
     32    clone.prototype = obj;
     33    var inst = new clone();
     34    if (props) for (var n in props) if (props.hasOwnProperty(n))
     35      inst[n] = props[n];
     36    return inst;
     37  }
     38 
     39  function eqAll(val) {
     40    var end = arguments.length, msg = null;
     41    if (typeof arguments[end-1] == "string")
     42      msg = arguments[--end];
     43    if (i == end) throw new Error("No editors provided to eqAll");
     44    for (var i = 1; i < end; ++i)
     45      eq(arguments[i].getValue(), val, msg)
     46  }
     47 
     48  function testDoc(name, spec, run, opts, expectFail) {
     49    if (!opts) opts = {};
     50 
     51    return test("doc_" + name, function() {
     52      var place = document.getElementById("testground");
     53      var editors = instantiateSpec(spec, place, opts);
     54      var successful = false;
     55 
     56      try {
     57        run.apply(null, editors);
     58        successful = true;
     59      } finally {
     60        if (!successful || verbose) {
     61          place.style.visibility = "visible";
     62        } else {
     63          for (var i = 0; i < editors.length; ++i)
     64            if (editors[i] instanceof CodeMirror)
     65              place.removeChild(editors[i].getWrapperElement());
     66        }
     67      }
     68    }, expectFail);
     69  }
     70 
     71  var ie_lt8 = /MSIE [1-7]\b/.test(navigator.userAgent);
     72 
     73  function testBasic(a, b) {
     74    eqAll("x", a, b);
     75    a.setValue("hey");
     76    eqAll("hey", a, b);
     77    b.setValue("wow");
     78    eqAll("wow", a, b);
     79    a.replaceRange("u\nv\nw", Pos(0, 3));
     80    b.replaceRange("i", Pos(0, 4));
     81    b.replaceRange("j", Pos(2, 1));
     82    eqAll("wowui\nv\nwj", a, b);
     83  }
     84 
     85  testDoc("basic", "A='x' B<A", testBasic);
     86  testDoc("basicSeparate", "A='x' B<~A", testBasic);
     87 
     88  testDoc("sharedHist", "A='ab\ncd\nef' B<A", function(a, b) {
     89    a.replaceRange("x", Pos(0));
     90    b.replaceRange("y", Pos(1));
     91    a.replaceRange("z", Pos(2));
     92    eqAll("abx\ncdy\nefz", a, b);
     93    a.undo();
     94    a.undo();
     95    eqAll("abx\ncd\nef", a, b);
     96    a.redo();
     97    eqAll("abx\ncdy\nef", a, b);
     98    b.redo();
     99    eqAll("abx\ncdy\nefz", a, b);
    100    a.undo(); b.undo(); a.undo(); a.undo();
    101    eqAll("ab\ncd\nef", a, b);
    102  }, null, ie_lt8);
    103 
    104  testDoc("undoIntact", "A='ab\ncd\nef' B<~A", function(a, b) {
    105    a.replaceRange("x", Pos(0));
    106    b.replaceRange("y", Pos(1));
    107    a.replaceRange("z", Pos(2));
    108    a.replaceRange("q", Pos(0));
    109    eqAll("abxq\ncdy\nefz", a, b);
    110    a.undo();
    111    a.undo();
    112    eqAll("abx\ncdy\nef", a, b);
    113    b.undo();
    114    eqAll("abx\ncd\nef", a, b);
    115    a.redo();
    116    eqAll("abx\ncd\nefz", a, b);
    117    a.redo();
    118    eqAll("abxq\ncd\nefz", a, b);
    119    a.undo(); a.undo(); a.undo(); a.undo();
    120    eqAll("ab\ncd\nef", a, b);
    121    b.redo();
    122    eqAll("ab\ncdy\nef", a, b);
    123  });
    124 
    125  testDoc("undoConflict", "A='ab\ncd\nef' B<~A", function(a, b) {
    126    a.replaceRange("x", Pos(0));
    127    a.replaceRange("z", Pos(2));
    128    // This should clear the first undo event in a, but not the second
    129    b.replaceRange("y", Pos(0));
    130    a.undo(); a.undo();
    131    eqAll("abxy\ncd\nef", a, b);
    132    a.replaceRange("u", Pos(2));
    133    a.replaceRange("v", Pos(0));
    134    // This should clear both events in a
    135    b.replaceRange("w", Pos(0));
    136    a.undo(); a.undo();
    137    eqAll("abxyvw\ncd\nefu", a, b);
    138  });
    139 
    140  testDoc("doubleRebase", "A='ab\ncd\nef\ng' B<~A C<B", function(a, b, c) {
    141    c.replaceRange("u", Pos(3));
    142    a.replaceRange("", Pos(0, 0), Pos(1, 0));
    143    c.undo();
    144    eqAll("cd\nef\ng", a, b, c);
    145  });
    146 
    147  testDoc("undoUpdate", "A='ab\ncd\nef' B<~A", function(a, b) {
    148    a.replaceRange("x", Pos(2));
    149    b.replaceRange("u\nv\nw\n", Pos(0, 0));
    150    a.undo();
    151    eqAll("u\nv\nw\nab\ncd\nef", a, b);
    152    a.redo();
    153    eqAll("u\nv\nw\nab\ncd\nefx", a, b);
    154    a.undo();
    155    eqAll("u\nv\nw\nab\ncd\nef", a, b);
    156    b.undo();
    157    a.redo();
    158    eqAll("ab\ncd\nefx", a, b);
    159    a.undo();
    160    eqAll("ab\ncd\nef", a, b);
    161  });
    162 
    163  testDoc("undoKeepRanges", "A='abcdefg' B<A", function(a, b) {
    164    var m = a.markText(Pos(0, 1), Pos(0, 3), {className: "foo"});
    165    b.replaceRange("x", Pos(0, 0));
    166    eqCharPos(m.find().from, Pos(0, 2));
    167    b.replaceRange("yzzy", Pos(0, 1), Pos(0));
    168    eq(m.find(), null);
    169    b.undo();
    170    eqCharPos(m.find().from, Pos(0, 2));
    171    b.undo();
    172    eqCharPos(m.find().from, Pos(0, 1));
    173  });
    174 
    175  testDoc("longChain", "A='uv' B<A C<B D<C", function(a, b, c, d) {
    176    a.replaceSelection("X");
    177    eqAll("Xuv", a, b, c, d);
    178    d.replaceRange("Y", Pos(0));
    179    eqAll("XuvY", a, b, c, d);
    180  });
    181 
    182  testDoc("broadCast", "B<A C<A D<A E<A", function(a, b, c, d, e) {
    183    b.setValue("uu");
    184    eqAll("uu", a, b, c, d, e);
    185    a.replaceRange("v", Pos(0, 1));
    186    eqAll("uvu", a, b, c, d, e);
    187  });
    188 
    189  // A and B share a history, C and D share a separate one
    190  testDoc("islands", "A='x\ny\nz' B<A C<~A D<C", function(a, b, c, d) {
    191    a.replaceRange("u", Pos(0));
    192    d.replaceRange("v", Pos(2));
    193    b.undo();
    194    eqAll("x\ny\nzv", a, b, c, d);
    195    c.undo();
    196    eqAll("x\ny\nz", a, b, c, d);
    197    a.redo();
    198    eqAll("xu\ny\nz", a, b, c, d);
    199    d.redo();
    200    eqAll("xu\ny\nzv", a, b, c, d);
    201  });
    202 
    203  testDoc("unlink", "B<A C<A D<B", function(a, b, c, d) {
    204    a.setValue("hi");
    205    b.unlinkDoc(a);
    206    d.setValue("aye");
    207    eqAll("hi", a, c);
    208    eqAll("aye", b, d);
    209    a.setValue("oo");
    210    eqAll("oo", a, c);
    211    eqAll("aye", b, d);
    212  });
    213 
    214  testDoc("bareDoc", "A*='foo' B*<A C<B", function(a, b, c) {
    215    is(a instanceof CodeMirror.Doc);
    216    is(b instanceof CodeMirror.Doc);
    217    is(c instanceof CodeMirror);
    218    eqAll("foo", a, b, c);
    219    a.replaceRange("hey", Pos(0, 0), Pos(0));
    220    c.replaceRange("!", Pos(0));
    221    eqAll("hey!", a, b, c);
    222    b.unlinkDoc(a);
    223    b.setValue("x");
    224    eqAll("x", b, c);
    225    eqAll("hey!", a);
    226  });
    227 
    228  testDoc("swapDoc", "A='a' B*='b' C<A", function(a, b, c) {
    229    var d = a.swapDoc(b);
    230    d.setValue("x");
    231    eqAll("x", c, d);
    232    eqAll("b", a, b);
    233  });
    234 
    235  testDoc("docKeepsScroll", "A='x' B*='y'", function(a, b) {
    236    addDoc(a, 200, 200);
    237    a.scrollIntoView(Pos(199, 200));
    238    var c = a.swapDoc(b);
    239    a.swapDoc(c);
    240    var pos = a.getScrollInfo();
    241    is(pos.left > 0, "not at left");
    242    is(pos.top > 0, "not at top");
    243  });
    244 
    245  testDoc("copyDoc", "A='u'", function(a) {
    246    var copy = a.getDoc().copy(true);
    247    a.setValue("foo");
    248    copy.setValue("bar");
    249    var old = a.swapDoc(copy);
    250    eq(a.getValue(), "bar");
    251    a.undo();
    252    eq(a.getValue(), "u");
    253    a.swapDoc(old);
    254    eq(a.getValue(), "foo");
    255    eq(old.historySize().undo, 1);
    256    eq(old.copy(false).historySize().undo, 0);
    257  });
    258 
    259  testDoc("docKeepsMode", "A='1+1'", function(a) {
    260    var other = CodeMirror.Doc("hi", "text/x-markdown");
    261    a.setOption("mode", "text/javascript");
    262    var old = a.swapDoc(other);
    263    eq(a.getOption("mode"), "text/x-markdown");
    264    eq(a.getMode().name, "markdown");
    265    a.swapDoc(old);
    266    eq(a.getOption("mode"), "text/javascript");
    267    eq(a.getMode().name, "javascript");
    268  });
    269 
    270  testDoc("subview", "A='1\n2\n3\n4\n5' B<~A/1-3", function(a, b) {
    271    eq(b.getValue(), "2\n3");
    272    eq(b.firstLine(), 1);
    273    b.setCursor(Pos(4));
    274    eqCharPos(b.getCursor(), Pos(2, 1));
    275    a.replaceRange("-1\n0\n", Pos(0, 0));
    276    eq(b.firstLine(), 3);
    277    eqCharPos(b.getCursor(), Pos(4, 1));
    278    a.undo();
    279    eqCharPos(b.getCursor(), Pos(2, 1));
    280    b.replaceRange("oyoy\n", Pos(2, 0));
    281    eq(a.getValue(), "1\n2\noyoy\n3\n4\n5");
    282    b.undo();
    283    eq(a.getValue(), "1\n2\n3\n4\n5");
    284  });
    285 
    286  testDoc("subviewEditOnBoundary", "A='11\n22\n33\n44\n55' B<~A/1-4", function(a, b) {
    287    a.replaceRange("x\nyy\nz", Pos(0, 1), Pos(2, 1));
    288    eq(b.firstLine(), 2);
    289    eq(b.lineCount(), 2);
    290    eq(b.getValue(), "z3\n44");
    291    a.replaceRange("q\nrr\ns", Pos(3, 1), Pos(4, 1));
    292    eq(b.firstLine(), 2);
    293    eq(b.getValue(), "z3\n4q");
    294    eq(a.getValue(), "1x\nyy\nz3\n4q\nrr\ns5");
    295    a.execCommand("selectAll");
    296    a.replaceSelection("!");
    297    eqAll("!", a, b);
    298  });
    299 
    300 
    301  testDoc("sharedMarker", "A='ab\ncd\nef\ngh' B<A C<~A/1-2", function(a, b, c) {
    302    var mark = b.markText(Pos(0, 1), Pos(3, 1),
    303                          {className: "cm-searching", shared: true});
    304    var found = a.findMarksAt(Pos(0, 2));
    305    eq(found.length, 1);
    306    eq(found[0], mark);
    307    eq(c.findMarksAt(Pos(1, 1)).length, 1);
    308    eqCharPos(mark.find().from, Pos(0, 1));
    309    eqCharPos(mark.find().to, Pos(3, 1));
    310    b.replaceRange("x\ny\n", Pos(0, 0));
    311    eqCharPos(mark.find().from, Pos(2, 1));
    312    eqCharPos(mark.find().to, Pos(5, 1));
    313    var cleared = 0;
    314    CodeMirror.on(mark, "clear", function() {++cleared;});
    315    b.operation(function(){mark.clear();});
    316    eq(a.findMarksAt(Pos(3, 1)).length, 0);
    317    eq(b.findMarksAt(Pos(3, 1)).length, 0);
    318    eq(c.findMarksAt(Pos(3, 1)).length, 0);
    319    eq(mark.find(), null);
    320    eq(cleared, 1);
    321  });
    322 
    323  testDoc("sharedMarkerCopy", "A='abcde'", function(a) {
    324    var shared = a.markText(Pos(0, 1), Pos(0, 3), {shared: true});
    325    var b = a.linkedDoc();
    326    var found = b.findMarksAt(Pos(0, 2));
    327    eq(found.length, 1);
    328    eq(found[0], shared);
    329    shared.clear();
    330    eq(b.findMarksAt(Pos(0, 2)), 0);
    331  });
    332 
    333  testDoc("sharedMarkerDetach", "A='abcde' B<A C<B", function(a, b, c) {
    334    var shared = a.markText(Pos(0, 1), Pos(0, 3), {shared: true});
    335    a.unlinkDoc(b);
    336    var inB = b.findMarksAt(Pos(0, 2));
    337    eq(inB.length, 1);
    338    is(inB[0] != shared);
    339    var inC = c.findMarksAt(Pos(0, 2));
    340    eq(inC.length, 1);
    341    is(inC[0] != shared);
    342    inC[0].clear();
    343    is(shared.find());
    344  });
    345 
    346  testDoc("sharedBookmark", "A='ab\ncd\nef\ngh' B<A C<~A/1-2", function(a, b, c) {
    347    var mark = b.setBookmark(Pos(1, 1), {shared: true});
    348    var found = a.findMarksAt(Pos(1, 1));
    349    eq(found.length, 1);
    350    eq(found[0], mark);
    351    eq(c.findMarksAt(Pos(1, 1)).length, 1);
    352    eqCharPos(mark.find(), Pos(1, 1));
    353    b.replaceRange("x\ny\n", Pos(0, 0));
    354    eqCharPos(mark.find(), Pos(3, 1));
    355    var cleared = 0;
    356    CodeMirror.on(mark, "clear", function() {++cleared;});
    357    b.operation(function() {mark.clear();});
    358    eq(a.findMarks(Pos(0, 0), Pos(5)).length, 0);
    359    eq(b.findMarks(Pos(0, 0), Pos(5)).length, 0);
    360    eq(c.findMarks(Pos(0, 0), Pos(5)).length, 0);
    361    eq(mark.find(), null);
    362    eq(cleared, 1);
    363  });
    364 
    365  testDoc("undoInSubview", "A='line 0\nline 1\nline 2\nline 3\nline 4' B<A/1-4", function(a, b) {
    366    b.replaceRange("x", Pos(2, 0));
    367    a.undo();
    368    eq(a.getValue(), "line 0\nline 1\nline 2\nline 3\nline 4");
    369    eq(b.getValue(), "line 1\nline 2\nline 3");
    370  });
    371 })();