#@+leo-ver=5-thin
#@+node:edward.20160314170027.56: * @file activeUnitTests.txt
# All the following should pass when run locally (Alt-4).
#@@language python
#@+all
#@+node:ekr.20111112092813.4060: ** @mark-for-unit-tests
@nocolor-node

All support code should be placed as a child of this @mark-for-unit-test node
so that it will be copied to dynamicUnitTest.leo when running tests externally.
#@+node:ekr.20111113102936.4600: *3* Test headline abc
#@+node:ekr.20120212130242.3980: *3* newHeadline
#@+node:ekr.20090529141856.4700: *3* importTests
@language plain
#@+node:ekr.20090529141856.4710: *4* importCWEBFiles
#@+node:ekr.20090529141856.4711: *5* dialog
openFileDialog
test\\unittest\\input\\cweave.w
#@+node:ekr.20090529141856.4704: *4* importDerivedFile
#@+node:ekr.20090529141856.4705: *5* dialog
openFileDialog
core\\runLeo.py
#@+node:ekr.20090529141856.4708: *4* importFlattenedOutline
#@+node:ekr.20090529141856.4709: *5* dialog
openFileDialog
test\\unittest\\input\\flat.txt
#@+node:ekr.20161006155420.1: *4* importMOREFiles
#@+node:ekr.20161006155420.2: *5* dialog
openFileDialog
test\\unittest\\perfectImport\\MORE_file_test.txt
#@+node:ekr.20090529141856.4706: *4* importNowebFiles
#@+node:ekr.20090529141856.4707: *5* dialog
openFileDialog
test\\unittest\\input\\noweave.nw.txt
#@+node:ekr.20161006154740.1: *4* importTabFiles
#@+node:ekr.20161006154802.1: *5* dialog
openFileDialog
test\\unittest\\perfectImport\\tab_file_test.txt
#@+node:ekr.20090529141856.4712: *4* removeSentinels
#@+node:ekr.20090529141856.4713: *5* dialog
openFileDialog
test\\unittest\\input\\testLeoAtFile.py
#@+node:ekr.20090529141856.4701: *4* tempNode
#@+node:ekr.20090529141856.4686: *3* exportTests
@language plain
#@+node:ekr.20111115105448.3880: *4* tempNode
#@+node:ekr.20090529141856.4688: *4* exportHeadlines
#@+node:ekr.20090529141856.4689: *5* dialog
saveFileDialog
test\\unittest\\output\\exportHeadlines.txt
#@+node:ekr.20090529141856.4690: *4* flattenOutline
#@+node:ekr.20090529141856.4691: *5* dialog
saveFileDialog
test\\unittest\\output\\flattenOutline.txt
#@+node:ekr.20090529141856.4692: *4* weave
#@+node:ekr.20090529141856.4693: *5* dialog
saveFileDialog
test\\unittest\\output\\weave.txt
#@+node:ekr.20090529141856.4694: *4* outlineToNoweb
#@+node:ekr.20090529141856.4695: *5* dialog
saveFileDialog
test\\unittest\\output\\outlineToNoweb.txt
#@+node:ekr.20090529141856.4696: *4* outlineToCWEB
#@+node:ekr.20090529141856.4697: *5* dialog
saveFileDialog
test\\unittest\\output\\outlineToCweb.txt
#@+node:ekr.20100830114008.5967: *3* @common leoEditCommands test code
@others
#@+node:ekr.20100830114008.5968: *4* runEditCommandTest
@
This is an updated version of c.testManager.runEditCommandTest,
moved here to take advantage of EKR's new common-test-code-sharing
mechanism. It should be okay to delete the old code and replace
all uses with:

    exec(g.findTestScript(c,'@common leoEditCommands test code'))
    runEditCommandTest(c,p)
@c

def runEditCommandTest (c,p,inHeadline=False):
    '''
    This is a helper for testing edit commands. It takes the name of the
    command from the title of the test and the before and after conditions
    from child nodes.

    :param inHeadline: if True, tests the command in the headline; if False,
    tests the command in the body.
    '''

    tm = c.testManager
    atTest = p.copy()

    h = atTest.h
    assert h.startswith('@test '),'expected head: %s, got: %s' % ('@test',h)
    commandName = h[6:].strip()
    # Ignore everything after the actual command name.
    i = g.skip_id(commandName, 0, chars='-')
    commandName = commandName[:i]
    assert commandName, 'empty command name'
    command = c.commandsDict.get(commandName)
    assert command, 'no command: %s' % (commandName)

    work,before,after = tm.findChildrenOf(atTest)
    before_h = 'before sel='
    after_h = 'after sel='
    for node,h in ((work,'work'),(before,before_h),(after,after_h)):
        h2 = node.h
        assert h2.startswith(h),'expected head: %s, got: %s' % (h,h2)

    sels = []
    for node,h in ((before,before_h),(after,after_h)):
        sel = node.h[len(h):].strip()
        aList = [str(z) for z in sel.split(',')]
        sels.append(tuple(aList))
    sel1,sel2 = sels
    #g.trace(repr(sels))

    c.selectPosition(work)

    if inHeadline:
        c.setHeadString(work,before.b)
        # To make the node visible, and edit the label
        c.redrawAndEdit(work)
        w = c.edit_widget(work)
        g.app.gui.set_focus(c,w)
    else:
        w = c.frame.body.wrapper
        c.setBodyString(work,before.b)

    try:
        #g.trace(repr(sel1[0]),repr(sel1[1]))
        w.setSelectionRange(sel1[0],sel1[1],insert=sel1[1])
        if inHeadline:
            # simulateCommand doesn't seem to work when editing a headline
            c.k.manufactureKeyPressForCommandName(w,commandName)
        else:
            c.k.simulateCommand(commandName)

        # Exit headline-editing mode
        if inHeadline:
            g.app.gui.event_generate(c,'\n','Return',w)

        location = 'headline' if inHeadline else 'body'
        s1 = work.h if inHeadline else work.b
        s2 = after.b
        
        # Strip '\n' from 'before' headline, as is now done in Leo.
        if inHeadline and s2.endswith('\n'):
            s2 = s2[:-1]

        assert s1 == s2, 'mismatch in %s\nexpected: %s\n     got: %s' % (location,repr(s2),repr(s1))
        sel3 = w.getSelectionRange()
        ins = w.toPythonIndex(w.getInsertPoint())
        #g.trace('ins',ins,'s1[j:...]',repr(s1[j:j+10]))
        # Convert both selection ranges to gui indices.
        sel2_orig = sel2
        # g.trace(w)
        assert len(sel2) == 2,'Bad headline index.  Expected index,index.  got: %s' % sel2
        i,j = sel2 ; sel2 = w.toPythonIndex(i),w.toPythonIndex(j)
        assert len(sel3) == 2,'Bad headline index.  Expected index,index.  got: %s' % sel3
        i,j = sel3 ; sel3 = w.toPythonIndex(i),w.toPythonIndex(j)
        assert sel2 == sel3, 'mismatch in sel\nexpected: %s = %s, got: %s' % (sel2_orig,sel2,sel3)
        c.selectPosition(atTest)
        atTest.contract()
        # Don't redraw.
    finally:
        # Make sure to restore the headline so it can be used for future tests
        if inHeadline:
            c.setHeadString(work,'work')
#@+node:ekr.20111006072734.3640: *3* @common x-marked-nodes test code
@others
#@+node:ekr.20111006072734.3641: *4* setup_test
def setup_test(target):
    
    c.unmarkAll() # Make sure we move only the test nodes!
    
    common = g.findNodeAnywhere(c,'@common x-marked-nodes test code')
    assert common,'no common'
    data = g.findNodeInTree(c,common,'data')
    assert data,'no data'
    
    delete_children(target)

    # Copy the nodes.
    c.selectPosition(data)
    c.copyOutline()
    c.selectPosition(target)
    c.pasteOutline()
    c.moveOutlineRight()
    c.promote()
    c.deleteOutline()
    c.redraw()
        
    for h in ('a','b','c'):
        p2 = g.findNodeInTree(c,target,h)
        assert p2,'not found: %s' % (h)
        p2.setMarked()
        
    for child in target.children():
        if child.h == 'a':
            assert child.isCloned(),'not cloned!: %s' % (child)
        else:
            assert not child.isCloned(),'cloned!: %s' % (child)
        
    # g.trace('setup complete')
    
#@+node:ekr.20111006115024.3613: *4* tear_down
def tear_down(p,h=None):
    
    delete_children(p)
    
    if h:
        node = g.findNodeAnywhere(c,h)
        if node:
            node.doDelete()
            # g.trace('deleted',node.h)

    common = g.findNodeAnywhere(c,'@common x-marked-nodes test code')
    common.contract()

    c.selectPosition(p)
    c.redraw()
#@+node:ekr.20111006105711.3734: *4* delete_children
def delete_children(p):

    while p.hasChildren():
        p.firstChild().doDelete()
#@+node:ekr.20111006072734.3642: *4* test_children
def test_children(p):
    
    n = p.numberOfChildren()
    assert n == 3 ,'children: %s' % (n)
    
    child = p.firstChild()
    assert child.h == 'a','child1: %s' % (child)
    
    child = child.next()
    assert child.h == 'c','child2: %s' % (child)
    
    child = child.next()
    assert child.h == 'a','child3: %s' % (child)
#@+node:ekr.20111211094602.3972: *4* data
#@+node:ekr.20111211094602.3978: *5* a
#@+node:ekr.20111211094602.3979: *6* b
#@+node:ekr.20111211094602.3975: *5* c
#@+node:ekr.20111211094602.3976: *5* d
#@+node:ekr.20111211094602.3977: *5* e
#@+node:ekr.20111211094602.3978: *6* a
#@+node:ekr.20111211094602.3979: *7* b
#@+node:ekr.20100812172232.5800: *3* @common leoRst test code
@others
#@+node:ekr.20100812182942.5804: *4* class rst3Test
@first # -*- coding: utf-8 -*-

class rst3Test:
    '''A class to run rst-related unit tests.'''
    
    def __init__ (self,c,p):
        '''Ctor for rst3Test class.'''
        self.c = c
        self.p = p.copy()
        self.run()

    @others
#@+node:ekr.20100827194549.5963: *5* report
def report (self,expected,got):
    '''Report errors in an rst test.'''
    verbose = True
    expected_lines = g.splitLines(expected.b)
    got_lines = g.splitLines(got.b)
    for i in range(min(len(expected_lines),len(got_lines))):
        match = expected_lines[i]==got_lines[i]
        if verbose or not match:
            tag = g.choose(match,'  ','**')
            print ('%3d%s %s' % (i,tag,repr(expected_lines[i])))
            print ('%3d%s %s' % (i,tag,repr(got_lines[i])))
        if not verbose and not match:
            break
#@+node:ekr.20100827183358.5957: *5* run
def run(self):
    '''run an rst test.'''
    import sys
    # import leo.core.leoRst as leoRst
    if not sys.platform.startswith('win') and g.isPython3: return
    try:
        import docutils
    except ImportError:
        return

    def clean(s):
        s = s.replace('\r','')
        s = g.toUnicode(s,'utf-8')
        return s

    c,p = self.c,self.p
    rc = c.rstCommands
    expected,got,source = self.setup()
    root = source.firstChild()
    rc.preprocessTree(root)
    rc.processTree(p=root,ext='.html',toString=True,justOneFile=True)
    rst = clean(rc.source)
    html = clean(rc.stringOutput)
    assert rst,'rst'
    assert html,'html'
    # Kludge: disregard version of docutils.
    if 1:
        import re
        html = re.sub('Docutils [\.0-9]*:','Docutils VER:',html)
    else:
        html = html.replace('Docutils 0.8.1:','Docutils VER:')
        html = html.replace('Docutils 0.6:','Docutils VER:')
        html = html.replace('Docutils 0.7:','Docutils VER:')
        html = html.replace('Docutils 0.8:','Docutils VER:')
        html = html.replace('Docutils 0.10:','Docutils VER:')
    if expected.hasChildren():
        child1 = expected.firstChild()
        child2 = expected.firstChild().next()
        child1_b = clean(child1.b)
        child2_b = clean(child2.b)
        ok = rst == child1_b and html == child2_b
        if not ok:
            got_html,got_rst = self.set_got(expected,got)
            got_html.b = html
            got_rst.b = rst
        if rst != child1_b:
            self.report(child1,got_rst)
        if html != child2_b:
            self.report(child2,got_html)
        assert rst == child1_b,'rst mismatch'
        assert html == child2_b,'html mismatch'
    else:
        child = expected.insertAsNthChild(0)
        child.h,child.b = 'rst',rst
        child = expected.insertAsNthChild(1)
        child.h,child.b = ' html',html
#@+node:ekr.20100827183358.5958: *5* setup
def setup (self):
    
    c,p = self.c, self.p
    expected = g.findNodeInTree(c,p,'expected')
    got = g.findNodeInTree(c,p,'got')
    source = g.findNodeInTree(c,p,'source')
    assert source,'source'
    assert expected,'expected'
    return expected,got,source
#@+node:ekr.20100827183358.5959: *5* set_got
def set_got (self,expected,got):

    c,p = self.c, self.p
    if got:
        got_rst = g.findNodeInTree(c,got,'rst')
        got_html = g.findNodeInTree(c,got,'html')
        assert got_rst
        assert got_html
    else:
        got = p.insertAsLastChild()
        got.h = 'got'
        got_rst = got.insertAsNthChild(0)
        got_rst.h = 'rst'
        got_html = got.insertAsNthChild(1)
        got_html.h = 'html'
    return got_html,got_rst
#@+node:ekr.20090703080553.5000: ** @suite run all doctests
tm = c.testManager

if g.isPython3:
    # Some tests now fail on Python 2.x.
    path = g.os_path_join(g.app.loadDir,"..","core")
    
    if 0:
        << define exclude >>
    else:
        exclude = ['leoIPython.py',]
            # leoIPython.py will give an annoying error if IPython can't be imported.

    modules = tm.importAllModulesInPath(path,exclude=exclude)
    suite   = tm.createUnitTestsFromDoctests(modules)
else:
    # Create a dummy suite.
    suite = tm.generalTestCase(p)
    
# if suite: g.app.scriptDict['suite'] = suite
    
#@+node:ekr.20090703093925.5003: *3* << define exclude >>
exclude = [
    # Gives an error if IPython can't be imported.
    'leoIPython.py',
    # These cause no problems, but will not have unit tests.
    'leo_Debugger.py',
    'leo_FileList.py',
    'leo_RemoteDebugger.py',
    'leo_run.py',
    'leo_Shell.py',
    'leoDynamicTest.py',
    'leoBridge.py',
    'leoBridgeTest.py',
]
#@+node:ekr.20100210222021.5388: ** @test save new file
import os
import sys
if g.isPython3 and sys.platform.startswith('linux'):
    # There is a PyQt issue: https://bugreports.qt.io/browse/QTBUG-35600
    # The crash causes several other unit tests to fail.
    pass
else:
    c1 = c
    fn = g.os_path_finalize_join(g.app.loadDir,'..','test','save-new-test.py')
    # print(fn)
    if g.os_path_exists(fn):
        os.remove(fn)
    assert not g.os_path_exists(fn)
    try:
        c = c1.new()
        assert not c.cacher.db
        # Not a perfect unit test, but it similar to c.save.
        c.mFileName = fn
        c.openDirectory = c.frame.openDirectory = g.os_path_dirname(fn)
        # print(c.mFileName)
        c.fileCommands.save(c.mFileName)
        c.close()
        assert g.os_path_exists(fn)
    finally:
        if g.os_path_exists(fn):
            os.remove(fn)
#@+node:ekr.20100131171342.5471: ** General
#@+node:ekr.20100131171342.5486: *3* @@test that all @test nodes in derived files start with if g.unitTesting
# print('-' * 30)

@others

# This can't be run externally,
# And it is no longer an effective test.

p = c.rootPosition()
ok = True
while p and ok:
    if p.isAnyAtFileNode():
        h = p.h
        if h.endswith('.py'):
            ok = checkFile(p)
        p.moveToNodeAfterTree()
    else:
        p.moveToThreadNext()
assert ok
#@+node:ekr.20100131171342.5487: *4* checkFile
def checkFile(p):

    print('checking',p.h)
    # Check all the descendant nodes.
    ok = True
    for p2 in p.subtree_iter():
        h = p2.h
        for tag in ('@test','@suite'):
            if h.startswith(tag):
                s = p2.b
                lines = g.splitLines(s)
                for line in lines:
                    # print('line',line)
                    if not line.strip() or line.startswith('#'):
                        continue
                    elif line.startswith('if g.unitTesting:'):
                        break
                    else:
                        print('in %s' % p.h)
                        print('missing "if g.unitTesting:" %s' % h)
                        ok = False
    return ok
#@+node:ekr.20100131171342.5485: *3* @test all commands have an event arg
import inspect

d = c.commandsDict
keys = sorted(d.keys())
for key in keys:
    if key.startswith('bookmark'):
        continue # bookmarks commands are their own signatures.
    f = d.get(key)
    # Test true __call__ methods if they exist.
    name = getattr(f,'__name__',None) or repr(f)
    if hasattr(f,'__call__') and inspect.ismethod(f.__call__):
        f = getattr(f,'__call__')
    args, varargs, varkw, defaults = data = inspect.getargspec(f)
    arg0 = len(args) > 0 and args[0]
    arg1 = len(args) > 1 and args[1]
    expected = ('event',)
    message = '\nno event arg for command %s, func: %s\nargs: %s' % (key,name,data)
    assert arg0 in expected or arg1 in expected,message
#@+node:ekr.20110613143220.3314: *3* @test All menus execute the proper command
@ We want to ensure that when masterMenuHandler does::
    
    event = g.app.gui.create_key_event(c,None,stroke,w)
    return k.masterKeyHandler(event)
    
that the effect will be to call commandName, where commandName
is the arg passed to masterMenuHandler.

createMenuEntries creates the association of stroke to commandName.
@c

trace = False # False: the unit test can fail.
k = c.k
d = g.app.unitTestMenusDict
d2 = k.bindingsDict ### c.k.masterGuiBindingsDict
d2name = 'k.bindingsDict'
commandNames = list(d.keys())
commandNames.sort()
exclude_strokes = ('Alt+F4','Ctrl+q','Ctrl+Shift+Tab',)

for name in commandNames:
    assert name in c.commandsDict,'unexpected command name: %s' % (
        repr(name))
    aSet = d.get(name)
    aList = list(aSet)
    aList.sort()
    for z in exclude_strokes:
        if z in aList:
            aList.remove(z)
    for stroke in aList:
        aList2 = d2.get(stroke)
        assert aList2,'stroke %s not in %s' % (
            repr(stroke),d2name)
        for b in aList2:
            if b.commandName == name:
                break
        else:
            if trace:
                inverseBindingDict = k.computeInverseBindingDict()
                print('%s: stroke %s not bound to %s in %s' % (
                    p.h,repr(stroke),repr(name),d2name))
                print('%s: inverseBindingDict.get(%s): %s' % (
                    p.h,name,inverseBindingDict.get(name)))
            else:
                assert False,'stroke %s not bound to %s in %s' % (
                    repr(stroke),repr(name),d2name)
#@+node:ekr.20111221062755.3909: *3* @test all top-level read/write commands give proper read/write error dialogs
child = p.firstChild()
assert child
assert child.h == 'child',child.h
c.selectPosition(child)

table = (
    'import-file',
    'open-outline',
    'read-at-auto-nodes',
    'read-at-file-nodes',
    'read-at-shadow-nodes',
   # 'read-file-into-node',
   # 'read-outline-only',
   'save-file',
   'save-file-as',
   'save-file-to',
    'write-at-auto-nodes',
    'write-at-file-nodes',
    'write-at-shadow-nodes',
    'write-dirty-at-auto-nodes',
    'write-dirty-at-file-nodes',
    'write-dirty-at-shadow-nodes',
    #'write-file-from-node',
    'write-missing-at-file-nodes',
    #'write-outline-only',
)

tags = (('init_error_dialogs',2), ('raise_error_dialogs',1))

d = g.app.unitTestDict
for commandName in table:
    for tag,n in tags:
        d[tag] = 0
    c.k.simulateCommand(commandName)
    for tag,n in tags:
        assert d.get(tag) == n,'commandName: %s,tag: %s, n: %s' % (commandName,tag,d.get(tag))
#@+node:ekr.20111221062755.3910: *4* child
#@+node:ekr.20100131171342.5483: *3* @test batch mode
import os
import sys

trace = False

python_interp = sys.executable
test_path = g.os_path_join(g.app.loadDir,"..","test","unittest")
src_path  = g.os_path_join(g.app.loadDir,"..","..")

leo_file   = g.os_path_join(src_path,"launchLeo.py")
batch_file = g.os_path_join(test_path,"batchTest.py")
test_file  = g.os_path_join(test_path,"createdFile.txt")

# Execute this command: python launchLeo.py --script test\unittest\batchTest.py

if 1:
    command = r"%s %s --silent --script %s" % (python_interp,leo_file,batch_file)
else:
    command = r"%s %s --script %s" % (python_interp,leo_file,batch_file)

@others

if trace:
    print('@test batch mode: loadDir: %s' % g.app.loadDir)

removeFile(test_file)
os.system(command)

assert(g.os_path_exists(test_file))
#@+node:ekr.20100131171342.5484: *4* removeFile
def removeFile(path):

    trace = False

    if os.path.exists(test_file):
        if trace:
            print("@test batch mode: removeFile: deleting",test_file)
        os.remove(test_file)
    else:
        if trace:
            print("@test batch mode: removeFile: not found:",test_file)
#@+node:ekr.20160419061017.1: *3* @test event classes
import leo.core.leoGui as leoGui # LeoKeyEvent
import leo.core.leoVim as leoVim # VimEvent.
import leo.plugins.qt_frame as qt_frame # EventWrapper
event = func = next_w = parent = None
char = shortcut = stroke = w = x = y = None
x_root = y_root = None
# The EventWrapper class is buried too deep to test easily.
# I'll try harder if it ever become a problem ;-)
    # dw = qt_frame.DynamicWindow(c, parent)
    # event_wrapper = dw.EventWrapper(c, w, next_w, func)
key_event = leoGui.LeoKeyEvent(
    c, char, event, shortcut,
    w, x, y, x_root, y_root)
vim_event = leoVim.VimEvent(c, char, stroke, w)
# assert hasattr(event_wrapper, 'c')
assert hasattr(key_event, 'c')
assert hasattr(vim_event, 'c')
#@+node:ekr.20140904060337.4476: *3* @test interfaces using API classes
if g.in_bridge or g.app.isExternalUnitTest:
    self.skipTest('Can not be run externally')
else:
    import leo.core.leoFrame as leoFrame
    import leo.plugins.qt_text as qt_text
    from leo.core.leoQt import Qsci,QtWidgets
    if Qsci:
        w = Qsci.QsciScintilla()
        q = qt_text.QScintillaWrapper(widget=w,c=c,name='test')
        q_list = [z for z in sorted(dir(q)) if not z.startswith('__')]
    # Check the text wrappers.
    W = leoFrame.WrapperAPI(c)
    tw = QtWidgets.QTextBrowser()
    t = qt_text.QTextEditWrapper(widget=tw,name='test2')
    W_list = [z for z in sorted(dir(W)) if not z.startswith('__')]
    t_list = [z for z in sorted(dir(t)) if not z.startswith('__')]
    ignore = [
        'set_focus', # synonym for setFocus
        'mutable_methods', # maybe for unit test, not actually used.
    ]
    for z in W_list:
        if z not in t_list and z not in ignore:
            assert False,'In WrapperAPI but not in QTextEditWrapper: %s' % z
    if Qsci:
        for z in W_list:
            if z not in q_list and z not in ignore:
                assert False,'In WrapperAPI but not in QScintillaWrapper: %s' % z
    # Check Null classes that are not subclasses of a base type:
    table = (
        ('NullIconBarClass',leoFrame.NullIconBarClass(c,None),
         # 'c.frame.iconBar',c.frame.iconBar,
         'IconBarAPI',leoFrame.IconBarAPI(c,None),
        ),
        ('NullStatusLineClass',leoFrame.NullStatusLineClass(c,None),
         # 'c.frame.statusLine',c.frame.statusLine,
         'StatusLineAPI',leoFrame.StatusLineAPI(c,None)
        )
    )
    for name1,L,name2,W in table:
        W_list = [z for z in sorted(dir(W)) if not z.startswith('__')]
        L_list = [z for z in sorted(dir(L)) if not z.startswith('__')]
        for z in W_list:
            assert z in L_list,'In %s but not in %s: %s' % (name2,name1,z)
#@+node:ekr.20100131171342.5472: *3* Check base classes & ivars
#@+node:ekr.20111118125141.3879: *4* @@@test bodyCtrl property
# Test that changing c.frame.body.bodyCtrl also changes c.frame.body.wrapper.
if 0:
    # A very dangerous test.
    # A failure here will destroy all following tests!
    # Furthermore, it is not needed.  bodyCtrl exists nowhere in Leo.
    body = c.frame.body
    old_w = body.wrapper
    try:
        assert old_w is not None
        body.bodyCtrl = None
        assert body.wrapper is None
    finally:
        body.wrapper = old_w
    assert hasattr(c.frame.body,'bodyCtrl')
    assert hasattr(c.frame.log,'logCtrl')
#@+node:ekr.20120227152633.3934: *4* @test c.config.initIvar sets *commander* ivars
# for key in sorted(list(g.app.config.ivarsDict.keys())):
    
for ivar,setting_type,default in g.app.config.ivarsData:
    
    assert hasattr(c,ivar),ivar
    assert hasattr(c.config,ivar),ivar
    val = getattr(c.config,ivar)
    val2 = c.config.get(ivar,setting_type)
    assert val == val2,"%s %s" % (val,val2)
    # print(ivar,val)
#@+node:ekr.20120227143454.3932: *4* @test k.settings ivars match settings
k = c.k
getBool  = c.config.getBool
getColor = c.config.getColor

bg = getColor('body_text_background_color') or 'white'
fg = getColor('body_text_foreground_color') or 'black'

table = (
    ('command_mode_bg_color',           getColor('command_mode_bg_color') or bg),
    ('command_mode_fg_color',           getColor('command_mode_fg_color') or fg),
    ('enable_alt_ctrl_bindings',        getBool('enable_alt_ctrl_bindings')),
    ('enable_autocompleter',            getBool('enable_autocompleter_initially')),
    ('enable_calltips',                 getBool('enable_calltips_initially')),
    ('ignore_caps_lock',                getBool('ignore_caps_lock')),
    ('ignore_unbound_non_ascii_keys',   getBool('ignore_unbound_non_ascii_keys')),
    ('insert_mode_bg_color',            getColor('insert_mode_bg_color') or bg),
    ('insert_mode_fg_color',            getColor('insert_mode_fg_color') or fg),
    ('minibuffer_background_color',     getColor('minibuffer_background_color') or 'lightblue'),
    ('minibuffer_error_color',          getColor('minibuffer_error_color') or 'red'),
    ('minibuffer_warning_color',        getColor('minibuffer_warning_color') or 'lightgrey'),
    ('overwrite_mode_bg_color',         getColor('overwrite_mode_bg_color') or bg),
    ('overwrite_mode_fg_color',         getColor('overwrite_mode_fg_color') or fg),
    ('swap_mac_keys',                   getBool('swap_mac_keys')),
    ('unselected_body_bg_color',        getColor('unselected_body_bg_color') or bg),
    ('unselected_body_fg_color',        getColor('unselected_body_fg_color') or bg),
    ('warn_about_redefined_shortcuts',  getBool('warn_about_redefined_shortcuts')),
)

for ivar,setting in table:
    assert hasattr(k,ivar),ivar
    val = getattr(k,ivar)
    assert val == setting,'%s k.%s setting: %s' % (
        ivar,ivar,val)
#@+node:ekr.20100131171342.5479: *4* @test official commander ivars
f = c.frame
assert(f.c==c)
assert(c.frame==f)

ivars = (
    # Subcommanders...
    'atFileCommands','fileCommands','importCommands','tangleCommands','undoer',
    # Positions...
    '_currentPosition', # '_topPosition',
    # '_rootPosition'
    # Data structures...
    'hoistStack',
        # 'recentFiles',
    # Args...
    'output_doc_flag','page_width','tab_width',
    # 'tangle_directory',
    'tangle_errors','tangle_batch_flag','target_language',
    'untangle_batch_flag','use_header_flag',
    # Others...
    'mFileName',
)

for ivar in ivars:
    assert hasattr(c,ivar), 'missing commander ivar: %s' % ivar
    val = getattr(c,ivar)
    assert val is not None,'null commander ivar: %s'% ivar
#@+node:ekr.20100131171342.5480: *4* @test official frame ivars
f = c.frame
assert(f.c==c)
assert(c.frame==f)

if g.app.gui.guiName() == 'tkinter':
    ivars = (
        'bar1','bar2',
        'body',
        #'bodyBar','bodyXBar', # 2007: 10/31: There are now injected in c.frame.body.wrapper.
        'canvas',
        'f1','f2',
        'iconBar','iconFrame',
        'log','outerFrame',
        'statusLine','statusFrame','statusLabel','statusText',
        'title','top','tree',
        #'treeBar', # leo_treeBar is now injected into frame.canvas.
    )
else: ivars = ()
for ivar in ivars:
    assert hasattr(f,ivar), 'missing frame ivar: %s' % ivar
    val = getattr(f,ivar)
    assert val is not None,'null frame ivar: %s'% ivar

# These do not have to be initied.
for ivar in ('findPanel',):
    assert hasattr(f,ivar), 'missing frame ivar: %s' % ivar
#@+node:ekr.20100131171342.5481: *4* @test official g.app directories
ivars = ('extensionsDir','globalConfigDir','loadDir','testDir')

for ivar in ivars:
    assert hasattr(g.app,ivar), 'missing g.app directory: %s' % ivar
    val = getattr(g.app,ivar)
    assert val is not None, 'null g.app directory: %s'% ivar
    assert g.os_path_exists(g.os_path_abspath(val)), 'non-existent g.app directory: %s' % ivar

assert hasattr(g.app,'homeDir') # May well be None.
#@+node:ekr.20100131171342.5482: *4* @test official g.app ivars

ivars = (
    # Global managers.
    'config','externalFilesController',
    'loadManager','pluginsController','recentFilesManager',
    # Official ivars.
    'gui',
    'initing','killed','quitting',
    'leoID','log','logIsLocked','logWaiting',
    'nodeIndices',
    'unitTesting','unitTestDict',
    'windowList',
    # Less-official and might be removed...
    'batchMode',
    'debugSwitch','disableSave',
    'hookError','hookFunction',
    'numberOfUntitledWindows',
    'realMenuNameDict',
    'searchDict','scriptDict',
    'use_psyco',
)

if g.app.isExternalUnitTest:
    mayBeNone = ('hookFunction','idleTimeHook','log','openWithInstance')
else:
    mayBeNone = ('hookFunction','openWithInstance')

for ivar in ivars:
    assert hasattr(g.app,ivar), 'missing app ivar: %s %r' % (ivar,g.app)
    if ivar not in mayBeNone:
        val = getattr(g.app,ivar)
        assert val is not None, 'null app ivar: %s %r'% (ivar,g.app)
#@+node:ekr.20100205223124.5377: ** Syntax checking
#@+node:ekr.20040712101813: *3* @@test c.checkAllPythonCode
result = c.checkAllPythonCode(unittest=True,ignoreAtIgnore=True)

assert result=="ok", "checkPythonCode returns: %s" % result
#@+node:ekr.20100205231441.5386: *3* @test at.checkPythonSyntax
at = c.atFileCommands

s = '''
# no error
def spam():
    pass
'''

assert at.checkPythonSyntax(p,s),'fail 1'

s2 = '''
# syntax error
def spam:
    pass
'''

assert not at.checkPythonSyntax(p,s2,supress=True),'fail2'

if not g.unitTesting: # A hand test of at.syntaxError
    at.checkPythonSyntax(p,s2)
#@+node:ekr.20100205233116.5387: *3* @test at.tabNannyNode
@tabwidth -4

at = c.atFileCommands

s = '''
# no error
def spam():
    pass
'''

at.tabNannyNode (p,body=s,suppress=True)

s2 = '''
# syntax error
def spam:
    pass
  a = 2
'''

try:
    at.tabNannyNode(p,body=s2,suppress=True)
except IndentationError:
    pass
#@+node:ekr.20100205235740.5391: *3* @test c.checkPythonCode
c.checkPythonCode(event=None,
    unittest=True,ignoreAtIgnore=False,
    suppressErrors=True,checkOnSave=False)
#@+node:ekr.20100205223124.5378: *3* @test c.checkPythonNode
table = (
    ('syntax-error','error'),
)

for h,expected in table:
    p2 = g.findNodeInTree(c,p,h)
    assert p2,'node not found: %s' % h
    result = c.checkPythonCode(event=None,
        unittest=True,ignoreAtIgnore=True,
        suppressErrors=True,checkOnSave=False)
    assert result==expected, 'expected %s got %s' % (
        expected,result)
#@+node:ekr.20100205223124.5379: *4* syntax-error
def abc
    pass
#@+node:ekr.20100205234837.5390: *3* @test c.tabNannyNode
@tabwidth -4

s = '''
# no error
def spam():
    pass
'''

c.tabNannyNode(p,headline=p.h,body=s,unittest=True,suppressErrors=True)

s2 = '''
# syntax error
def spam:
    pass
  a = 2
'''

try:
    c.tabNannyNode(p,headline=p.h,body=s2,unittest=True,suppressErrors=True)
except IndentationError:
    pass
#@+node:ekr.20100206002004.5397: *3* @test g.es_exception
# This is just a hand test.
if not g.unitTesting:
    try:
        assert False
    except AssertionError:
        g.es_exception(full=True,c=None,color='red')
#@+node:ekr.20071113145804.20: *3* @@test g.es_exception (heroic)
if c.config.redirect_execute_script_output_to_log_pane:
    pass # Test doesn't work when redirection is on.
else:
    try:
        import sys
        # Catch the output of g.es_exception.
        # We catch the AssertionError, so nothing gets written to stderr.
        sys.stdout = fo = g.fileLikeObject()
        try: # Create an exception to catch.
            assert False, 'Assert False in test_g_es_exception'
        except AssertionError:
            g.es_exception(color='suppress')
            result = fo.get()
            s1 = 'Traceback (most recent call last):'
            s2 = 'AssertionError: Assert False in test_g_es_exception'
            assert result.find(s1) > -1, 'No traceback line: %s' % repr(result)
            assert result.find(s2) > -1, 'No AssertionError line: %s' % repr(result)
    finally:
        # Not needed unless we execute this script as selected text.
        sys.stdout = sys.__stdout__
#@+node:ekr.20100206001203.5395: *3* @test g.getLastTracebackFileAndLineNumber
try:
    assert False
except AssertionError:
    fn,n = g.getLastTracebackFileAndLineNumber()
    
if g.app.isExternalUnitTest:
    writeScriptFile = True
else:
    writeScriptFile = c.config.getBool('write_script_file')

if writeScriptFile:
    assert fn != '<string>',repr(fn)
else:
    assert fn == '<string>',repr(fn)

assert n == 4,repr(n)
#@+node:ekr.20100205230621.5383: *3* @test leoTest.checkFileSyntax
s = '''
# syntax error
def spam:
    pass
'''

try:
    c.testManager.checkFileSyntax('<fileName>',s,suppress=True)
    assert False
except SyntaxError:
    pass
#@+node:ekr.20100205235740.5392: *3* @test syntax of all files
import glob
trace = False
failed,n = [],0
skip_tuples3 = (
    ('extensions','asciidoc.py'),
)
skip_tuples2 = (
    ('test', 'python3_test.py'),
)
join = g.os_path_finalize_join
skip_tuples = skip_tuples3 if g.isPython3 else skip_tuples2
skip_list = [join(g.app.loadDir,'..',a,b) for a,b in skip_tuples]
for theDir in ('core','external','extensions','plugins','scripts','test'):
    if trace: print(theDir)
    path = g.os_path_finalize_join(g.app.loadDir,'..',theDir)
    assert g.os_path_exists(path),path
    aList = glob.glob(g.os_path_join(path,'*.py'))
    for z in aList:
        if z in skip_list:
            pass # print('%s: skipped: %s' % (p.h,z))
        else:
            n += 1
            fn = g.shortFileName(z)
            # if trace: print('%8s %s' % (theDir,fn))
            s,e = g.readFileIntoString(z)
            if not c.testManager.checkFileSyntax(fn,s,reraise=False,suppress=False):
                failed.append(z)
if trace: print('tested %s files' % n)
assert not failed,'failed %s\n' % g.listToString(failed,sort=True)
#@+node:ekr.20110612071416.3311: *3* @test syntax of setup.py
fn = g.os_path_finalize_join(g.app.loadDir,'..','..','setup.py')

# Only run this test if setup.py exists: it may not in the actual distribution.
if g.os_path_exists(fn):
    s,e = g.readFileIntoString(fn)
    c.testManager.checkFileSyntax(fn,s,reraise=True,suppress=False)
#@+node:ekr.20050208051418: ** Unicode tests
#@+node:ekr.20050206201145: *3* @test % operator with unicode
@first # -*- coding: utf-8 -*-

s = "testᾹ(U+1FB9: Greek Capital Letter Alpha With Macron)"

s2 = 'test: %s' % s
#@+node:ekr.20050208051854: *3* @test atFile.printError
@first # -*- coding: utf-8 -*-

at = c.atFileCommands
at.errors = 0

if g.isPython3:
    # Do not call g.ue: it will crash.
    s = 'La Peña'
else:
    s = g.ue('La Peña','utf-8')

at.printError('test of at.printError:',s)

# important: this test will fail if sitecustomize.py
# does not contain sys.setdefaultencoding('utf-8')
#@+node:ekr.20050208051418.1: *3* @test can't open message in g.openWithFileName
@first # -*- coding: utf-8 -*-

import sys
# g.openWithFileName *always* opens the file.
if g.isPython3 and sys.platform.startswith('linux'):
    # There is a PyQt issue: https://bugreports.qt.io/browse/QTBUG-35600
    # The crash causes several other unit tests to fail.
    pass
elif not g.app.isExternalUnitTest:

    old_c = c
    filename = "testᾹ(U+1FB9: Greek Capital Letter Alpha With Macron)"
    try:
        c2 = None
        c2 = g.openWithFileName(filename,old_c=old_c)
    finally:
        if c2:
            g.app.destroyWindow(c2.frame)
        c.setLog()
        c.bodyWantsFocus()
#@+node:ekr.20050208111037: *3* @test failure to convert unicode characters to ascii
@first # -*- coding: utf-8 -*-

encoding = 'ascii'

if g.isPython3:
    s = '炰' # This is already unicode.
    s2,ok = g.toUnicodeWithErrorCode(s,encoding)
    assert ok, 'toUnicodeWithErrorCode returns False for %s with ascii encoding' % s

    s3,ok = g.toEncodedStringWithErrorCode(s,encoding)
    assert not ok, 'toEncodedStringWithErrorCode returns True for %s with ascii encoding' % s
else:
    s = '炰' # An encoded string.
    s2,ok = g.toUnicodeWithErrorCode(s,encoding)
    assert not ok, 'toUnicodeWithErrorCode returns True for %s with ascii encoding' % s

    s = g.ue('炰','utf-8') # Must use utf-8 encoding *here*
    s3,ok = g.toEncodedStringWithErrorCode(s,encoding)
    assert not ok, 'toEncodedStringWithErrorCode returns True for %s with ascii encoding' % s
#@+node:ekr.20071113143844.6: *3* @test failure with ascii encodings
@first # -*- coding: utf-8 -*-

encoding = 'ascii'

if g.isPython3:
    s = '炰'
    s2,ok = g.toUnicodeWithErrorCode(s,encoding)
    assert ok, 'toUnicodeWithErrorCode returns True for %s with ascii encoding' % s

    s3,ok = g.toEncodedStringWithErrorCode(s,encoding)
    assert not ok, 'toEncodedStringWithErrorCode returns True for %s with ascii encoding' % s
else:
    s = '炰'
    s2,ok = g.toUnicodeWithErrorCode(s,encoding)
    assert not ok, 'toUnicodeWithErrorCode returns True for %s with ascii encoding' % s

    s = g.ue('炰','utf-8')
    s3,ok = g.toEncodedStringWithErrorCode(s,encoding)
    assert not ok, 'toEncodedStringWithErrorCode returns True for %s with ascii encoding' % s
#@+node:ekr.20071113145804.23: *3* @@test g.reportBadChars
@first # -*- coding: utf-8 -*-

# g.reportBadChars no longer exists.

table = (
    ('aĂbĂ',                    'ascii'),
    (g.ue('aĂbĂ','utf-8'),      'ascii'),
    ('炰',                       'ascii'),
    (g.ue('炰','utf-8'),         'ascii'),
    ('aĂbĂ',                     'utf-8'),
    (g.ue('aĂbĂ','utf-8'),       'utf-8'),
    ('炰',                       'utf-8'),
    (g.ue('炰','utf-8'),         'utf-8'),
)
for s,encoding in table:
    g.reportBadChars(s,encoding)
#@+node:ekr.20100204053330.5367: *3* @test koi8-r encoding
root = p.copy()
while p.hasChildren():
    p.firstChild().doDelete(newNode = None)
try:
    p1 = p.insertAsLastChild()
    s = '\xd4\xc5\xd3\xd4' # the word 'test' in Russian, koi8-r
    if g.isPython3:
        assert g.isUnicode(s)
    else:
        s = unicode(s,'koi8-r')
    p1.setBodyString(s)
    c.selectPosition(p1)
    c.copyOutline()
    c.pasteOutline()
    p2 = p1.next()
    # self.assertEqual(p1.b, p2.b) # 'self' defined only when unit-testing.
    assert p1.b == p2.b
finally:
    if 1:
         while root.hasChildren():
              root.firstChild().doDelete(newNode = None)
    c.redraw_now(p)
#@+node:ekr.20050208104202: *3* @test of round-tripping toUnicode & toEncodedString
@first # -*- coding: utf-8 -*-

if not g.isPython3: # Does not work with Python 3.x

    for s,encoding in (
        ('a',    'utf-8'),
        ('a',    'ascii'),
        ('äöü',  'utf-8'),
        ('äöü',  'mbcs'),
        ('炰',    'utf-8'),
        ('炰',    'mbcs'),
    ):
        if g.isValidEncoding(encoding):
            s2,ok = g.toUnicodeWithErrorCode(s,encoding)
            assert ok, 'toUnicodeWithErrorCode fails for %s' %s
            s3,ok = g.toEncodedStringWithErrorCode(s2,encoding)
            assert ok, 'toEncodedStringWithErrorCode fails for %s' % s2
            assert s3 == s, 'Round-trip one fails for %s' %s

            s2 = g.toUnicode(s,encoding)
            s3 = g.toEncodedString(s2,encoding)
            assert s3 == s, 'Round-trip two fails for %s' %s
#@+node:ekr.20050206090416: *3* @test open non-existent non-ascii directory
@first # -*- coding: utf-8 -*-

# g.openWithFileName *always* opens the file.

if not g.app.isExternalUnitTest:

    if g.isPython3:
        # Do not call g.ue: it will crash.
        theFile = 'Ỗ'
    else:
        theFile = g.ue('Ỗ','utf-8')
    
    path = g.os_path_join('Ỗ','Ỗ')
    # print(g.toEncodedString(theFile,'utf-8'))
    
    try:
        c2 = g.openWithFileName(path,old_c=c)
    finally:
        if c2:
            g.app.destroyWindow(c2.frame)
        c.setLog()
        c.bodyWantsFocus()
#@+node:ekr.20071113145804.24: *3* @test round trip toUnicode toEncodedString
@first # -*- coding: utf-8 -*-

if not g.isPython3: # Does not work with Python 3.x

    table = [
        ('a',    'utf-8'),
        ('a',    'ascii'),
        ('äöü',  'utf-8'),
        ('äöü',  'mbcs'),
        ('炰',   'utf-8'),
    ]

    # __pychecker__ = '--no-reimport'
    import sys

    if sys.platform.startswith('win'):
        data = '炰','mbcs'
        table.append(data)

    for s,encoding in table:
        if g.isValidEncoding(encoding):
            s2,ok = g.toUnicodeWithErrorCode(s,encoding)
            assert ok, 'toUnicodeWithErrorCode fails for %s' %s
            s3,ok = g.toEncodedStringWithErrorCode(s2,encoding)
            assert ok, 'toEncodedStringWithErrorCode fails for %s' % s2
            assert s3 == s, 'Round-trip one failed for %s' %s

            s2 = g.toUnicode(s,encoding)
            s3 = g.toEncodedString(s2,encoding)
            assert s3 == s, 'Round-trip two failed for %s' %s
#@+node:ekr.20100421102506.6282: *3* @test rst.write with unicode character
@first # -*- coding: utf-8 -*-

try:
    import docutils
except ImportError:
    docutils = False
    # print('docutils not present')
    
if docutils:
    rst = c.rstCommands
    name = g.os_path_finalize_join(g.app.loadDir,'..','test','unittest','rst_write_test.txt')
    s = "testᾹ(U+1FB9: Greek Capital Letter Alpha With Macron)"
    
    if g.isPython3:
        f = open(name,'w',encoding='utf-8')
    else:
        f = open(name,'w')
        s = rst.encode(s)
    
    f.write(s)
    f.close()
    
    assert g.os_path_exists(name)
#@+node:ekr.20071113194858: ** Organized by file
# All the following files have problems when run with Alt-5.
#@+node:ekr.20100223123103.5382: *3* @test expand/contract-pane
import leo.core.leoFrame as leoFrame

# Do nothing when run externally.
if g.app.isExternalUnitTest:
    self.skipTest('Can not be run externally')
else:
    assert not isinstance(c.frame,leoFrame.NullFrame)
    def closeEnough(f1,f2):
        return abs(f1-f2) < 0.01
    f = c.frame
    ratio,ratio2 = f.ratio,f.secondary_ratio
    table = (
        c.bodyWantsFocusNow,
        c.logWantsFocusNow,
        c.treeWantsFocusNow,
    )
    for func in table:
        name = func.__name__
        func()
        f.contractPane()
        if func == c.logWantsFocusNow:
            assert ratio2 != f.secondary_ratio,'fail 1'
        else:
            assert ratio != f.ratio,'fail 2: %s, %s: %s' % (ratio,f.ratio,name)
        func()
        f.expandPane()
        assert closeEnough(ratio,f.ratio),'fail 3 %s != %s: %s' % (
            ratio,f.ratio,name)
        assert closeEnough(ratio2,f.secondary_ratio),'fail 4 %s != %s: %s' % (
            ratio2,f.secondary_ratio,name)
#@+node:ekr.20100131171342.5506: *3* leoApp
#@+node:ekr.20100131171342.5507: *4* @test consistency of leoApp tables
@
language_delims_dict 
    # Keys are languages, values are 1,2 or 3-tuples of delims. 
language_extension_dict
    # Keys are languages, values are extensions.
extension_dict = {
    # Keys are extensions, values are languages.
@c

delims_d    = g.app.language_delims_dict
lang_d      = g.app.language_extension_dict
ext_d       = g.app.extension_dict

for lang in lang_d:
    ext = lang_d.get(lang)
    assert lang in delims_d,'fail 1: %s' % lang
    assert ext in ext_d,'fail 2: %s' % ext
for ext in ext_d:
    lang = ext_d.get(ext)
    assert lang in lang_d,'fail 3: %s' % lang
#@+node:ekr.20100131180007.5417: *4* @test lm.openLeoOrZipFile
import zipfile
lm = g.app.loadManager

# Create a zip file for testing.
s = 'this is a test file'
testDir = g.os_path_join(g.app.loadDir,'..','test')
assert g.os_path_exists(testDir)
path = g.os_path_finalize_join(testDir,'testzip.zip')
theFile = zipfile.ZipFile(path,'w')
theFile.writestr('leo-zip-file',s)
theFile.close()

# Open the file, and use read (with no args) to get the contents.
theFile = lm.openLeoOrZipFile(path)
assert theFile
s2 = theFile.read()
assert s == s2,'s:  %s\ns2: %s' % (repr(s),repr(s2))
#@+node:ekr.20100211110729.5389: *4* @test rfm.writeRecentFilesFileHelper
@first # -*- coding: utf-8 -*-

# On Windows, this works with or without the following line in sitecustomize.py
# sys.setdefaultencoding('utf-8')

import os

if g.isPython3:
    fn ='ффф.leo'
else:
    fn = g.toUnicode('ффф.leo')

g.app.recentFilesManager.writeRecentFilesFileHelper(fn)
assert g.os_path_exists(fn),'fail 1'
os.remove(fn)
assert not g.os_path_exists(fn),'fail 1'
#@+node:ekr.20130503061820.4186: *4* @test consistency of leoApp tables
@
language_delims_dict 
    # Keys are languages, values are 1,2 or 3-tuples of delims. 
language_extension_dict
    # Keys are languages, values are extensions.
extension_dict = {
    # Keys are extensions, values are languages.
@c

delims_d    = g.app.language_delims_dict
lang_d      = g.app.language_extension_dict
ext_d       = g.app.extension_dict

for lang in lang_d:
    ext = lang_d.get(lang)
    assert lang in delims_d,'fail 1: %s' % lang
    assert ext in ext_d,'fail 2: %s' % ext
for ext in ext_d:
    lang = ext_d.get(ext)
    assert lang in lang_d,'fail 3: %s' % lang
#@+node:ekr.20160318094003.1: *3* leoAst
#@+node:ekr.20160318094009.1: *4* @test Python3 features
if not g.isPython3:
    self.skipTest('python 3 test')
else:
    import leo.core.leoAst as leoAst
    import leo.external.make_stub_files as msf
    import leo.external.py2cs as py2cs
    import ast, tokenize
    path = g.os_path_finalize_join(g.app.loadDir,
        '..', 'test', 'unittest', 'python3_test.py')
    assert g.os_path_exists(path), path
    fn = g.shortFileName(path)
    source = open(path, 'r').read()
    node = ast.parse(source, filename=fn, mode='exec')
    src = open(path, 'r').read()
    readlines = g.ReadLinesClass(src).next
    tokens = list(tokenize.generate_tokens(readlines))
    leoAst.AstFullTraverser().visit(node)
    s = leoAst.HTMLReportTraverser(debug=True).main(fn, node)
    assert s
    s = leoAst.AstFormatter().format(node)
    assert s
    s = py2cs.CoffeeScriptTraverser(controller=g.NullObject()).format(node, src, tokens)
    assert s
    controller = msf.StandAloneMakeStubFile()
    msf.StubTraverser(controller).visit(node)
#@+node:ekr.20160523094102.1: *4* @test leoAst traverser classes
# Great ast docs: http://greentreesnakes.readthedocs.io/en/latest/nodes.html

import leo.core.leoAst as leoAst
leoAst.unit_test(raise_on_fail=True)

import leo.external.make_stub_files as msf
msf.unit_test(raise_on_fail=True)

import leo.external.py2cs as py2cs
py2cs.unit_test(raise_on_fail=True)

#@+node:ekr.20050112095306.1: *3* leoAtFile
#@+node:ekr.20041021065844: *4* @test @asis
c.testManager.runAtFileTest(p)
#@+node:ekr.20041021065903: *5* #@asis
# Test that @nosent generates no sentinels

<< section >>

@others

last line
#@+node:ekr.20041021065903.1: *6* << section >>
section line 1
#@+node:ekr.20041021065903.2: *6* unnamed node
unnamed node line 1
#@+node:ekr.20041021065844.1: *5* Output
# Test that @nosent generates no sentinels

<< section >>

@others

last line
section line 1
unnamed node line 1
#@+node:ekr.20090627070131.4971: *4* @test @auto (newlines at end of nodes)
c.testManager.runAtFileTest(p)
#@+node:ekr.20090627070131.4975: *5* #@auto
@language python
@tabwidth -4
@others
#end
#@+node:ekr.20090627070131.4976: *6* spam
def spam(cheese):

    print(cheese)
#@+node:ekr.20090627070131.4977: *6* cheese
def cheese():

    pass
#@+node:ekr.20090627070131.4978: *5* Output
def spam(cheese):

    print(cheese)
def cheese():

    pass
#end
#@+node:ekr.20100801125533.5787: *4* @test @auto (no newline at end of nodes)
c.testManager.runAtFileTest(p)
#@+node:ekr.20100801125533.5788: *5* #@auto
@language python
@tabwidth -4
@others
#end
#@+node:ekr.20100801125533.5789: *6* spam
def spam(cheese):

    print(cheese)
#@+node:ekr.20100801125533.5790: *6* cheese
def cheese():

    pass
#@+node:ekr.20100801125533.5791: *5* Output
def spam(cheese):

    print(cheese)
def cheese():

    pass
#end
#@+node:ekr.20090225102051.2: *4* @test @edit
c.testManager.runAtFileTest(p)
#@+node:ekr.20090225102051.3: *5* #@edit
Line 1

Last line: no newline
#@+node:ekr.20090225102051.4: *5* Output
Line 1

Last line: no newline
#@+node:ekr.20110524120515.3489: *4* @test @raw
c.testManager.runAtFileTest(p)
#@+node:ekr.20110524120515.3490: *5* #@file
# before

@raw

@c

<< ref >>

@end_raw

#after
#@+node:ekr.20110524120515.3491: *5* Output
#@verbatim
#@+leo-ver=5
#@verbatim
#@+node:#@file
# before

#@verbatim
#@@raw

@c

<< ref >>

#@verbatim
#@@end_raw

#after
#@verbatim
#@-leo
#@+node:ekr.20071113145804.8: *4* @test at.directiveKind4
at=c.atFileCommands
table = [
    ('@=',0,at.noDirective),
    ('@',0,at.atDirective),
    ('@ ',0,at.atDirective),
    ('@\t',0,at.atDirective),
    ('@\n',0,at.atDirective),
    ('@all',0,at.allDirective),
    ('    @all',4,at.allDirective),
    ("@c",0,at.cDirective),
    ("@code",0,at.codeDirective),
    ("@doc",0,at.docDirective),
    ("@end_raw",0,at.endRawDirective),
    ('@others',0,at.othersDirective),
    ('    @others',4,at.othersDirective),
    ("@raw",0,at.rawDirective),
]
for name in g.globalDirectiveList:
    # Note: entries in g.globalDirectiveList do not start with '@'
    if name not in ('all','c','code','doc','end_raw','others','raw',):
        table.append(('@' + name,0,at.miscDirective),)

for s,i,expected in table:
    result = at.directiveKind4(s,i)
    assert result == expected, '%d %s result: %s expected: %s' % (
        i,repr(s),at.sentinelName(result),at.sentinelName(expected))
#@+node:ekr.20170123035753.1: *4* @test at.directiveKind4 (new)
at = c.atFileCommands
table = (
    (at.othersDirective, '@others'),
    (at.othersDirective, '@others\n'),
    (at.othersDirective, '    @others'),
    (at.miscDirective,   '@tabwidth -4'),
    (at.miscDirective,   '@tabwidth -4\n'),
    (at.miscDirective,   '@encoding'),
    (at.noDirective,     '@encoding.setter'),
    (at.noDirective,     '@encoding("abc")'),
    (at.noDirective,     'encoding = "abc"'),
    (at.noDirective,     '@directive'), # A crucial new test.
)
for expected, s in table:
    result = at.directiveKind4(s, 0)
    assert expected == result, (expected, result, repr(s))
#@+node:ekr.20100225094004.5385: *4* @test at.isFileLike
s1 = '''
#@verbatim
#@+leo-ver=4
#@verbatim
#@+node:#@file
Line 1
#@verbatim
#@-node:#@file
#@verbatim
#@-leo
'''

s2 = '''
#@verbatim
#@+leo-ver=4-thin
#@verbatim
#@+node:ekr.20040707141957.13:#@thin
#@verbatim
#@-node:ekr.20040707141957.13:#@thin
#@verbatim
#@-leo
'''

at = c.atFileCommands
assert at.isFileLike(s1),'fail1'
assert not at.isFileLike(s2),'fail2'
#@+node:ekr.20071113143844.5: *4* @test at.isSignificantTree
assert c.atFileCommands.isSignificantTree(p)

#@+node:ekr.20110524091618.3488: *4* @test at.massageDocPart
at = c.atFileCommands

# A mininimal test.

at.startSentinelComment = '<!--'
at.endSentinelComment = '-->'

s1 = '<!--\nline 2.\n-->\n'
s2 = at.massageAtDocPart(s1)

assert s2 == 'line 2.\n',repr(s2)
#@+node:ekr.20090529115704.4562: *4* @test at.open/closeStringFile
at = c.atFileCommands

# at.toString is set by the execute-script command.
# at.outputFile = f = g.fileLikeObject() # Re-allocate for the test.
f = at.openStringFile('abc')
assert isinstance(f,g.fileLikeObject)
s = 'abc'
f.write(s)
s2 = at.closeStringFile(f)
assert s == s2,s2
# assert at.toString
#@+node:ekr.20090529115704.4563: *4* @test at.openForWrite: not a shadow file
at = c.atFileCommands
x = c.shadowController

filename = x.pathName('xyzzy')
assert not g.os_path_exists(filename)

try:
    kind,theFile = at.openForWrite(filename)
    assert kind == 'check'
    # print(repr(theFile))
    if theFile: theFile.close()

finally:
    if g.os_path_exists(filename):
        x.unlink(filename)
        assert not g.os_path_exists(filename)
#@+node:ekr.20071113145804.7: *4* @test at.parseLeoSentinel
s1 = '#@+leo-ver=4-thin-encoding=utf-8,.'  # 4.2 format.
s2 = '#@+leo-ver=4-thin-encoding=utf-8.' # pre-4.2 format.

at=c.atFileCommands # Self is a dummy argument.

for s in (s1,s2):
    valid,new_df,start,end,isThinDerivedFile = at.parseLeoSentinel(s)
    # g.trace('start',start,'end',repr(end),'len(s)',len(s))
    assert valid, 'not valid'
    assert new_df, 'not new_df'
    assert isThinDerivedFile, 'not thin'
    assert end == '', 'invalid end: %s' % repr(end)
    assert at.encoding == 'utf-8', 'bad encoding: %s' % repr(at.encoding)
#@+node:ekr.20090529115704.4564: *4* @test at.readOneAtShadowNode
at = c.atFileCommands
x = c.shadowController

changed = c.changed
child = p.firstChild()
s = child.b

try:
    fn = 'unittest/read_test.py'
    child.setHeadString('@shadow %s' % fn)
    at.writeOneAtShadowNode(child,toString=False,force=True)
    at.readOneAtShadowNode(fn,child)
finally:
    child.setHeadString('@@shadow %s' % fn)
    c.setChanged(changed)
#@+node:ekr.20090529115704.4565: *5* @@shadow unittest/read_test.py
@language python
@tabwidth -4
@others
#@+node:ekr.20120228174052.3929: *4* Node 1
# node 1 text A.
#@+node:ekr.20050105093136: *4* @test at.remove
import os

at = c.atFileCommands
exists = g.os_path_exists

path = g.os_path_join(g.app.testDir,'xyzzy')
if exists(path):
    os.remove(path)

assert not exists(path)
assert not at.remove(path,verbose=False)

f = open(path,'w')
f.write('test')
f.close()

assert exists(path)
assert at.remove(path)
assert not exists(path)
#@+node:ekr.20050105093524: *4* @test at.rename
import os

at = c.atFileCommands
exists = g.os_path_exists
path = g.os_path_join(g.app.testDir,'xyzzy')
path2 = g.os_path_join(g.app.testDir,'xyzzy2')

# Create both paths.
for p in (path,path2):
    if exists(p):
        os.remove(p)
    assert not exists(p)
    f = open(p,'w')
    f.write('test %s' % p)
    f.close()
    assert exists(p)

assert at.rename(path,path2,verbose=True)
assert exists(path2)
f = open(path2)
s = f.read()
f.close()
# print('Contents of %s: %s' % (path2,s))
assert s == 'test %s' % path
os.remove(path2)
assert not exists(path)
#@+node:ekr.20090529115704.4566: *4* @test at.replaceFileWithString
import os
s = 'abc'
fn = 'unitTestFile.py'
path = g.os_path_abspath(g.os_path_join(g.app.loadDir,'..','test','unittest',fn))
try:
    c.atFileCommands.replaceFileWithString(path,s)
    f = open(path)
    s2 = f.read()
    f.close()
    assert s == s2
finally:
    if g.os_path_exists(path):
        os.unlink(path)
#@+node:ekr.20050105094311: *4* @test at.replaceTargetFileIfDifferent (different)
import os
import leo.core.leoAtFile as leoAtFile
at = c.atFileCommands
exists = g.os_path_exists
at.outputFileName = None
at.targetFileName = g.os_path_join(g.app.testDir,'xyzzy2')
try:
    # Create both paths (different contents)
    table = (at.targetFileName,)
    at.outputContents = contents = g.toUnicode('test contents')
    for fn in table:
        if fn and exists(fn):
            os.remove(fn)
        assert not exists(fn)
        f = open(fn,'w')
        s = 'test %s' % fn
        f.write(s)
        f.close()
        assert exists(fn),fn
    at.toString = False # Set by execute script stuff.
    at.shortFileName = at.targetFileName
    val = at.replaceTargetFileIfDifferent(at.root)
    assert val
    if 0:
        print('%s exists %s' % (at.outputFileName,exists(at.outputFileName)))
        print('%s exists %s' % (at.targetFileName,exists(at.targetFileName)))
    assert not exists(at.outputFileName), 'oops, output file exists'
    assert exists(at.targetFileName), 'oops, target file does not exist'
    f = open(at.targetFileName)
    s = f.read()
    f.close()
    assert s == contents,s
finally:
    if 1:
        for fn in (at.outputFileName,at.targetFileName):
            if fn and exists(fn):
                os.remove(fn)
#@+node:ekr.20050105095743: *4* @test at.replaceTargetFileIfDifferent (identical)
import os
import leo.core.leoAtFile as leoAtFile
at = c.atFileCommands
exists = g.os_path_exists
at.outputFileName = None
at.targetFileName = g.os_path_join(g.app.testDir,'xyzzy2')
# Create both paths (identical contents)
contents = g.toUnicode('test contents')
try:
    table = (at.targetFileName,)
    at.outputContents = contents
    for fn in table:
        if fn and exists(fn):
            os.remove(fn)
        assert not exists(fn)
        f = open(fn,'w')
        f.write(contents)
        f.close()
        assert exists(fn)
    at.toString = False # Set by execute script stuff.
    at.shortFileName = at.targetFileName
    assert not at.replaceTargetFileIfDifferent(at.root)
    if 0:
        print('%s exists %s' % (at.outputFileName,exists(at.outputFileName)))
        print('%s exists %s' % (at.targetFileName,exists(at.targetFileName)))
    assert not exists(at.outputFileName)
    assert exists(at.targetFileName)
    f = open(at.targetFileName)
    s = f.read()
    f.close()
    assert s == contents,contents
finally:
    if 1:
        for fn in (at.outputFileName,at.targetFileName):
            if fn and exists(fn):
                os.remove(fn)
#@+node:ekr.20050105100227: *4* @test at.replaceTargetFileIfDifferent (no target file)
import os
import leo.core.leoAtFile as leoAtFile
at = c.atFileCommands
exists = g.os_path_exists
at.outputFileName = None ### g.os_path_join(g.app.testDir,'xyzzy1.txt')
at.targetFileName = g.os_path_join(g.app.testDir,'xyzzy2.txt')
# Remove both files.
for fn in (at.outputFileName,at.targetFileName):
    if fn and exists(fn):
        os.remove(fn)
try:
    # Create the output file or contents.
    at.outputContents = contents = g.toUnicode('test output')
    at.toString = False # Set by execute script stuff.
    at.shortFileName = at.targetFileName
    val = at.replaceTargetFileIfDifferent(at.root)
    assert not val
    if 0:
        print('%s exists %s' % (at.outputFileName,exists(at.outputFileName)))
        print('%s exists %s' % (at.targetFileName,exists(at.targetFileName)))
    assert not exists(at.outputFileName),at.outputFileName
    assert exists(at.targetFileName),at.targetFileName
    f = open(at.targetFileName)
    s = f.read()
    f.close()
    assert s == contents,'%s len(%s)' % (fn,len(s))
finally:
    if 1:
        for fn in (at.outputFileName,at.targetFileName):
            if fn and exists(fn):
                os.remove(fn)
#@+node:ekr.20060602195313: *4* @test at.write using @comment
at = c.atFileCommands
child = p.firstChild()
child2 = child.next()
result = str(child2.b)
at.write(child,nosentinels=False,thinFile=False,scriptWrite=False,toString=True)
s = str(at.stringOutput)

if s != result:
    print('-' * 30)
    print(s)
    print('-' * 30)
    print(result)

assert s == result
#@+node:ekr.20060602195313.2: *5* root
@language c
#ifdef COMMENT
@comment /* */ 
#endif
@tabwidth 4
@lineending crlf

@others

<< Get LRR Task >>
<< Start LRR >>
#@+node:ekr.20060602195313.3: *6* << Get LRR Task >>
#@+node:ekr.20060602195313.4: *6* << Start LRR >>
#@+node:ekr.20060602195914: *5* Result
/*@+leo-ver=5*/
/*@+node:root*/
/*@@language c*/
#ifdef COMMENT
/*@@comment /* */ */
#endif
/*@@tabwidth 4*/
/*@@lineending crlf*/

/*@+others*/
/*@-others*/

/*@+<< Get LRR Task >>*/
/*@+node:<< Get LRR Task >>*/
/*@-<< Get LRR Task >>*/
/*@+<< Start LRR >>*/
/*@+node:<< Start LRR >>*/
/*@-<< Start LRR >>*/
/*@-leo*/
#@+node:ekr.20090529115704.4567: *4* @test at.writeOneAtShadowNode
at = c.atFileCommands
x = c.shadowController
changed = c.changed
child = p.firstChild()
s = child.b

try:
    child.setHeadString('@shadow unittest/test_1.py')
    fn = 'unittest/test_1.py'
    shadow_fn = x.shadowPathName(fn)
    shadow_dir = x.shadowDirName(fn)
    x.makeShadowDirectory(shadow_dir)
    if g.os_path_exists(shadow_fn):
        g.utils_remove(shadow_fn,verbose=True)
    at.writeOneAtShadowNode(child,toString=True,force=True)
    assert at.startSentinelComment == '#','startSentinelComment: %s' % (
        repr(at.startSentinelComment))
    assert at.endSentinelComment == '','endSentinelComment: %s' % (
        repr(at.endSentinelComment))
    if 0:
        print('public...\n',at.public_s)
        print('private...\n',at.private_s)
    at.writeOneAtShadowNode(child,toString=False,force=True)
    assert g.os_path_exists(shadow_fn),'not found: %s' % shadow_fn
    # No need to remove this: it's in the unittest directory.
    # g.utils_remove(shadow_fn,verbose=True)
finally:

    child.setHeadString('@@shadow unittest/test_1.py')
    c.setChanged(changed)
    # c.redraw_now()
#@+node:ekr.20090529115704.4568: *5* @@shadow unittest/test_1.py
# body of @shadow test node
# The last line.
#@+node:ekr.20130912092638.4151: *4* @test utf-16 encoding
import sys
if g.app.isExternalUnitTest:
    if sys.platform.startswith('linux'):
        self.skipTest('external linux test')
    else:
        path = g.os_path_finalize_join(g.app.loadDir,'..','test','unittest','utf-16-test.txt')
        assert g.os_path_exists(path)
        f = open(path,'r')
        s = f.read()
        f.close()
        s = g.toUnicode(s,encoding='utf-16')
        assert s.find('Test of utf-16.') > -1,s
else:
    h = '@file unittest/utf-16-test.txt'
    p = g.findNodeAnywhere(c,h)
    s = 'Test of utf-16.'
    assert p,h
    # It's hard to test the utf-16 text directly.
    assert p.b
    assert p.b.find(s) > -1
    assert len(p.b)==66,len(p.b)
#@+node:ekr.20100131180007.5462: *4* @test verbatim sentinel
# Here is something that should generate a verbtim sentinel::

#@verbatim
#@+leo-encoding=iso-8859-1.

# The length of this node should remain constant.

assert len(p.b) == 175,len(p.b)
#@+node:ekr.20071113201736: *4* @test zz end of leoAtFile tests
# This is **not** a real unit test.
# It simply restores the screen to a more convenient state.

# c.contractParent()
# g.app.unitTestDict['restoreSelectedNode']=False

print('\nEnd of leoAtFile tests')
#@+node:ekr.20101021205258.6011: *4* at.Directives & directories
#@+node:ekr.20100131180007.5454: *5* @test at.get/setPathUa
at = c.atFileCommands

at.setPathUa(p,'abc')
d = p.v.tempAttributes
d2 = d.get('read-path')
val1 = d2.get('path')
val2 = at.getPathUa(p)

table = (
    ('d2.get',val1),
    ('at.getPathUa',val2),
)
for kind,val in table:
    assert val == 'abc','kind %s expected %s got %s' % (
        kind,'abc',val)
#@+node:ekr.20100131180007.5461: *5* @test at.replaceFileWithString
at = c.atFileCommands

fn = 'does/not/exist'
assert not g.os_path_exists(fn)
assert not at.replaceFileWithString (fn,'abc')
#@+node:ekr.20100131180007.5458: *5* @test at.scanAllDirectives (minimal)
at = c.atFileCommands
d = at.scanAllDirectives(p)
#@+node:ekr.20071113090055.4: *5* @test at.scanAllDirectives
# This will work regardless of where this method is.
@language python
@tabwidth -4
# @path xyzzy # Creates folder called xyzzy: interferes with other unit tests.
@pagewidth 120

d = c.atFileCommands.scanAllDirectives(p)

assert d.get('language') == 'python'
assert d.get('tabwidth') == -4
# assert d.get('path').endswith('xyzzy')
assert d.get('pagewidth') == 120
#@+node:ekr.20111113091935.4786: *4* Not valid when run externally
@nocolor-node

These all call g.findNodeAnywhere for an @<file> node.
We don't want to copy such nodes to dynamicUnitTest.leo
#@+node:ekr.20090704085350.5044: *5* @test @asis: shape of tree
# Not valid for external tests: uses @<file> node.
if not g.app.isExternalUnitTest:

    h = '@asis unittest/at-asis-test.py'
    p = g.findNodeAnywhere(c,h)
    assert p
    
    table = (
        (p.firstChild(),'spam'),
        (p.firstChild().next(),'eggs')
    )
    
    assert not p.isDirty(),p.h # Do not ignore this failure!
    
    for p2,h2 in table:
        assert p2.h == h2
        assert len(p2.b) > 10
#@+node:ekr.20090704085350.5052: *5* @test @auto: shape of tree
# Not valid for external tests: uses @<file> node.
if not g.app.isExternalUnitTest:

    h = '@auto unittest/at-auto-test.py'
    p = g.findNodeAnywhere(c,h)
    assert p
    
    table = (
        (p.firstChild(),'spam'),
        (p.firstChild().next(),'eggs')
    )
    
    assert not p.isDirty(),p.h # Do not ignore this failure!
    
    for p2,h2 in table:
        assert p2.h == h2
        assert len(p2.b) > 10
#@+node:ekr.20090704085350.5018: *5* @@test @shadow: shape of tree
# Not valid for external tests: uses @<file> node.
if not g.app.isExternalUnitTest:

    h = '@shadow ../test/unittest/at-shadow-test.py'
    p = g.findNodeAnywhere(c,h)
    assert p
    
    table = (
        (p.firstChild(),'spam'),
        (p.firstChild().next(),'eggs')
    )
    
    assert not p.isDirty(),p.h # Do not ignore this failure!
    
    for p2,h2 in table:
        assert len(p2.h) == len(h2)
#@+node:ekr.20100731163237.5778: *5* @test @thin: html section references
@language python

# Not valid for external tests: uses @<file> node.
if not g.app.isExternalUnitTest:
    
    # html uses block comments.  This is an important test.
    
    h = '@thin unittest/at-thin-html-test.html'
    p = g.findNodeAnywhere(c,h)
    assert p
    
    s = (
    '@language html\n\n<< ' +
    'a section reference >>\n\n' +
    'after.\n')
    
    # print(repr(p.b)) ; print(repr(s))
    
    assert p.b == s,'body failure'
#@+node:ekr.20090704085350.5046: *5* @test @thin: shape of tree
# Not valid for external tests: uses @<file> node.
if not g.app.isExternalUnitTest:

    h = '@thin unittest/at-thin-test.py'
    p = g.findNodeAnywhere(c,h)
    assert p
    
    table = (
        (p.firstChild(),'spam'),
        (p.firstChild().next(),'eggs')
    )
    
    assert not p.isDirty(),p.h # Do not ignore this failure!
    
    for p2,h2 in table:
        assert p2.h == h2
        assert len(p2.b) > 10
#@+node:ekr.20111021115306.3696: *5* @test @file: tex bug
# Not valid for external tests: uses @<file> node.
if not g.app.isExternalUnitTest:
    
    p = g.findNodeAnywhere(c,"@file unittest/tex-error.tex")
    assert(p)
    
    s1 = r"""\begin{document}
<< Document """
    
    s2 = r""">>
% hidden comment
\end{document}
"""
    
    s = s1 + s2
    s = g.adjustTripleString(s,c.tab_width)
    
    # print(repr(s))
    # print(repr(p.b))
    assert p.b == s
#@+node:ekr.20100802220019.5795: *5* @test at.deleteUnvistedNodes
def clone (p,parent,n):
    p2 = p.clone()
    p2.moveToNthChildOf(parent,n)
    return p2

def make (parent,n,h):
    child = parent.insertAsNthChild(n)
    child.h = h
    return child

def delete_r():
    '''Delete all 'Resurrected Nodes' nodes.'''
    while True:
        r = g.findNodeAnywhere(c,'Resurrected Nodes')
        if r: r.doDelete(newNode=p)
        else: break

def delete_children():
    # Delete all children of p.
    while p.hasChildren():
        p.firstChild().doDelete(newNode=p)

def test(p,h,tag):
    assert p,'p'
    assert p.h == 'From root','p.h %s' % tag
    assert p.numberOfChildren() == 1,'number of children %s' % tag
    assert p.firstChild().h == h,'child.h %s' % tag

delete_r()
delete_children()

# Create some children.
root = make(p,0,'root')
child1 = make(root,0,'child1')
child2 = make(root,1,'child2')
child3 = make(root,2,'child3')
child11 = make(child1,0,'child11')
child21 = make(child2,0,'child21')
child31 = make(child3,0,'child31')
# Create some clones.
if 0:
    child4 = clone(child31,root,3)
# Set all bits except for child2 & child31.
for z in root.self_and_subtree():
    z.setVisited()
for z in child2,child31: # These should be moved.
    z.clearVisited()
if 1:
    c.atFileCommands.deleteUnvisitedNodes(root)
    c.redraw()
if 1:
    r = g.findNodeAnywhere(c,'Resurrected Nodes')
    assert r,'r'
    r1 = r.firstChild()
    r2 = r1.next()
    # r3 = r2.next()
    test(r1,'child31','r1')
    test(r2,'child2','r2')
    # assert root.numberOfChildren() == 3,'root.n'
if 1:
    delete_r()
if 1:
    delete_children()
c.redraw()
#@+node:ekr.20040707141957.12: *5* @test @thin: @last
# Doesn't work when run externally because the copy operation changes the gnx.
if g.app.isExternalUnitTest:
    self.skipTest('Can not be run externally')
else:
    c.testManager.runAtFileTest(p)
#@+node:ekr.20040707141957.13: *6* #@thin
Line 1

@last last line 1: no newline
#@+node:ekr.20040707141957.14: *6* Output
#@verbatim
#@+leo-ver=5-thin
#@verbatim
#@+node:ekr.20040707141957.13: * #@thin
Line 1

#@verbatim
#@@last
#@verbatim
#@-leo
last line 1: no newline
#@+node:ekr.20101021210253.6018: *4* Unused
#@+node:ekr.20040712101754.103: *5* @@test @file no newline
c.testManager.runAtFileTest(p)
#@+node:ekr.20040712101754.104: *6* #@file
Line 1

@last last line 1: no newline
#@+node:ekr.20040712101754.105: *6* Output
#@verbatim
#@+leo-ver=4
#@verbatim
#@+node:#@file
Line 1

#@verbatim
#@@last
#@verbatim
#@nonl
#@verbatim
#@-node:#@file
#@verbatim
#@-leo
last line 1: no newline
#@+node:ekr.20040712101754.106: *5* @@test @file one newline
c.testManager.runAtFileTest(p)
#@+node:ekr.20040712101754.107: *6* #@file
Line 1

@last last line 1: newline
#@+node:ekr.20040712101754.108: *6* Output
#@verbatim
#@+leo-ver=4
#@verbatim
#@+node:#@file
Line 1

#@verbatim
#@@last
#@verbatim
#@-node:#@file
#@verbatim
#@-leo
last line 1: newline
#@+node:ekr.20040712101754.109: *5* @@test @file two newlines
c.testManager.runAtFileTest(p)
#@+node:ekr.20040712101754.110: *6* #@file
Line 1

@last last line 1: two trailing newlines
#@+node:ekr.20040712101754.111: *6* Output
#@verbatim
#@+leo-ver=4
#@verbatim
#@+node:#@file
Line 1

#@verbatim
#@@last
#@verbatim
#@-node:#@file
#@verbatim
#@-leo
last line 1: two trailing newlines
#@+node:ekr.20090704085350.5010: *5* @@test @file: shape of tree
h = '@file ../test/unittest/at-file-test.py'
p = g.findNodeAnywhere(c,h)
assert p
assert not p.isDirty(),p.h # Do not ignore this failure!

table = (
    (p.firstChild(),'spam'),
    (p.firstChild().next(),'eggs')
)

for p2,h2 in table:
    assert p2.h == h2
    assert len(p2.b) > 10
#@+node:ekr.20150521123343.1: *3* leoBeautify
#@+node:ekr.20111104171708.3843: *4* @test leoBeautify.CPrettyPrinter
import leo.core.leoBeautify as leoBeautify
cpp = leoBeautify.CPrettyPrinter(c)
fn = 'c tokenize test'
p2 = g.findNodeInTree(c,p,fn)
assert p2,'not found: %s' % (fn)

if 1: # test of indent.
    # import os ; os.system('cls')
    cpp.indent(p2)

if 0: # test of tokenize.
    aList = cpp.tokenize(p2.b)
    assert(p2.b == ''.join(aList))
    if 0:
        import os ; os.system('cls')
        print('*' * 40)
        # print(''.join(aList))
        for z in aList:
            print(repr(z))
#@+node:ekr.20111104171708.3844: *5* c tokenize test
@language c

static exit_values_ty indent_main_loop(void)
{
    codes_ty         hd_type         = code_eof;
    char           * t_ptr           = NULL;
    codes_ty         type_code       = start_token;
    exit_values_ty   file_exit_value = total_success;
    int              dec_ind         = 0; /* current indentation for declarations */

    BOOLEAN          scase           = false; /* true when we've just see a "case";
                                               * determines what to do with the
                                               * following colon */
    BOOLEAN          flushed_nl;              /* Used when buffering up comments to remember that
                                               * a newline was passed over */
    BOOLEAN          sp_sw           = false; /* true when in the expression part of if(...),
                                               * while(...), etc. */
    BOOLEAN          force_nl        = false;

    /* last_token_ends_sp: True if we have just encountered the end of an if (...),
     * etc. (i.e. the ')' of the if (...) was the last token).  The variable is
     * set to 2 in the middle of the main token reading loop and is decremented
     * at the beginning of the loop, so it will reach zero when the second token
     * after the ')' is read.
     */

    BOOLEAN          last_token_ends_sp = false;

    BOOLEAN          last_else = false; /* true if last keyword was an else */

    for (;;)
    {
        /* this is the main loop.  it will go until
         * we reach eof */

        BOOLEAN is_procname_definition;
        bb_code_ty can_break;

        if (type_code != newline)
        {
            can_break = parser_state_tos->can_break;
        }

        parser_state_tos->last_saw_nl = false;
        parser_state_tos->can_break = bb_none;

        type_code = lexi ();    /* lexi reads one token.  "token" points to
                                 * the actual characters. lexi returns a code
                                 * indicating the type of token */

        /* If the last time around we output an identifier or
         * a paren, then consider breaking the line here if it's
         * too long.
         *
         * A similar check is performed at the end of the loop, after
         * we've put the token on the line. */

        if ((settings.max_col > 0) &&
            (buf_break != NULL) &&
            ( ( (parser_state_tos->last_token == ident) &&
                (type_code != comma) &&
                (type_code != semicolon) &&
                (type_code != newline) &&
                (type_code != form_feed) &&
                (type_code != rparen) &&
                (type_code != struct_delim)) ||
              ( (parser_state_tos->last_token == rparen) &&
                (type_code != comma) &&
                (type_code != rparen) ) ) &&
            (output_line_length () > settings.max_col))
        {
            break_line = 1;
        }

        if (last_token_ends_sp > 0)
        {
            last_token_ends_sp--;
        }

        is_procname_definition =
                (((parser_state_tos->procname[0] != '\0') &&
                  parser_state_tos->in_parameter_declaration) ||
                 (parser_state_tos->classname[0] != '\0'));

        /* The following code moves everything following an if (), while (),
         * else, etc. up to the start of the following stmt to a buffer. This
         * allows proper handling of both kinds of brace placement.
         */

        flushed_nl = false;

        if (!search_brace(&type_code, &force_nl, &flushed_nl, &last_else, &is_procname_definition))
        {
            /* Hit EOF unexpectedly in comment. */
            return indent_punt;
        }
        
        if (type_code == code_eof)
        {
            /* we got eof */
            if (s_lab != e_lab || s_code != e_code || s_com != e_com)   /* must dump end of line */
            {
                dump_line(true, &paren_target);
            }

            if (parser_state_tos->tos > 1)      /* check for balanced braces */
            {
                ERROR (_("Unexpected end of file"), 0, 0);
                file_exit_value = indent_error;
            }

            if (settings.verbose)
            {
                printf (_("There were %d non-blank output lines and %d comments\n"),
                        (int) out_lines, (int) com_lines);
                if (com_lines > 0 && code_lines > 0)
                {
                    printf (_("(Lines with comments)/(Lines with code): %6.3f\n"),
                            (1.0 * com_lines) / code_lines);
                }
            }
            flush_output ();

            return file_exit_value;                                              /* RETURN */
        }

        if ((type_code != comment) &&
            (type_code != cplus_comment) &&
            (type_code != newline) &&
            (type_code != preesc) &&
            (type_code != form_feed))
        {
            if (force_nl &&
                (type_code != semicolon) &&
                ( (type_code != lbrace) ||
                  (!parser_state_tos->in_decl && !settings.btype_2) ||
                  (parser_state_tos->in_decl && !settings.braces_on_struct_decl_line) ||
                  (parser_state_tos->last_token == rbrace)))
            {
                if (settings.verbose && !flushed_nl)
                {
                    WARNING (_("Line broken 2"), 0, 0);
                }

                flushed_nl = false;
                dump_line(true, &paren_target);
                parser_state_tos->want_blank = false;
                force_nl = false;
            }

            parser_state_tos->in_stmt = true;   /* turn on flag which causes
                                                 * an extra level of
                                                 * indentation. this is
                                                 * turned off by a ; or } */
            if (s_com != e_com)
            {
                /* the code has an embedded comment in the
                 * line. Move it from the com buffer to the
                 * code buffer.
                 *
                 * Do not add a space before the comment if it is the first
                 * thing on the line.
                 */

                if (e_code != s_code)
                {
                    set_buf_break (bb_embedded_comment_start, paren_target);
                    *e_code++ = ' ';
                    embedded_comment_on_line = 2;
                }
                else
                {
                    embedded_comment_on_line = 1;
                }

                for (t_ptr = s_com; *t_ptr; ++t_ptr)
                {
                    check_code_size();
                    *e_code++ = *t_ptr;
                }

                set_buf_break (bb_embedded_comment_end, paren_target);
                *e_code++ = ' ';
                *e_code = '\0'; /* null terminate code sect */
                parser_state_tos->want_blank = false;
                e_com = s_com;
            }
        }
        else if ((type_code != comment) &&
                 (type_code != cplus_comment) &&
                 !(settings.break_function_decl_args &&
                   (parser_state_tos->last_token == comma)) &&
                 !( (parser_state_tos->last_token == comma) &&
                    !settings.leave_comma))
        {
            /* preserve force_nl thru a comment but
             * cancel forced newline after newline, form feed, etc.
             * however, don't cancel if last thing seen was comma-newline
             * and -bc flag is on. */

            force_nl = false;
        }

        /* Main switch on type of token scanned */

        check_code_size();
        
        /* now, decide what to do with the token */

        handle_the_token(type_code, &scase, &force_nl, &sp_sw, &flushed_nl,
                         &hd_type, &dec_ind, &last_token_ends_sp, &file_exit_value,
                         can_break, &last_else, is_procname_definition);
        
        *e_code = '\0';         /* make sure code section is null terminated */

        if ((type_code != comment) &&
            (type_code != cplus_comment) &&
            (type_code != newline) &&
            (type_code != preesc) &&
            (type_code != form_feed))
        {
            parser_state_tos->last_token = type_code;
        }

        /* Now that we've put the token on the line (in most cases),
         * consider breaking the line because it's too long.
         *
         * Don't consider the cases of `unary_op', newlines,
         * declaration types (int, etc.), if, while, for,
         * identifiers (handled at the beginning of the loop),
         * periods, or preprocessor commands. */

        if ((settings.max_col > 0) && (buf_break != NULL))
        {
            if ( ( (type_code == binary_op) ||
                   (type_code == postop) ||
                   (type_code == question) ||
                   ((type_code == colon) && (scase || (squest <= 0))) ||
                   (type_code == semicolon) ||
                   (type_code == sp_nparen) ||
                   (type_code == sp_else) ||
                   ((type_code == ident) && (*token == '\"')) ||
                   (type_code == struct_delim) ||
                   (type_code == comma)) &&
                 (output_line_length () > settings.max_col))
            {
                break_line = 1;
            }
        }
    }                           /* end of main infinite loop */
}
#@+node:ekr.20150610064911.1: *4* @test beautifier
# This tests only recent bugs.
p1 = p.firstChild()
s = p1.b
p2 = p1.next()
try:
    c.selectPosition(p1)
    c.k.simulateCommand('beautify-tree')
    assert p1.b == p2.b
finally:
    p1.b = s
    c.setChanged(False)

#@+node:ekr.20150610064930.1: *5* before
def spam():
    if - 1 < 2:
        pass
#@+node:ekr.20150610065241.1: *5* after
def spam():
    if -1 < 2:
        pass
#@+node:ekr.20100131171342.5508: *3* leoBridge
#@+node:ekr.20100131171342.5509: *4* @test leoBridge init logic
import leo.core.leoBridge as leoBridge

if g.app.isExternalUnitTest:
    print('running @test leoBridge init logic')
    # This can not be run locally!
    b = leoBridge.controller(gui='nullGui',
        loadPlugins=True,
        readSettings=True,
        silent=False,
        tracePlugins=True,
        verbose=True)
    g = b.globals()
    path = g.os_path_finalize_join(g.app.loadDir,'..','doc','LeoDocs.leo')
    assert g.os_path_exists(path)
    c = b.openLeoFile(path)
    assert c
    assert c.rootPosition()
else:
    self.skipTest('Can not be run locally')
#@+node:ekr.20110608135658.3377: *3* leoChapters
#@+node:ekr.20110608162543.3363: *4* @test chapter-create/remove & undo
# cc will be None when unit tests run dynamically.
import leo.core.leoChapters as leoChapters
new_code = getattr(leoChapters, 'new_code', True)
cc = c.chapterController
if new_code:
    self.skipTest('create/remove commands no longer exist.')
elif cc and not g.app.isExternalUnitTest:
    chaptersNode = cc.findChaptersNode()
    assert chaptersNode
    chapterNode = (
        cc.findChapterNode('aaa') or
        cc.createChapterByName('aaa',p=None))
    cc.selectChapterByName('aaa',chaptersNode)
    cc.removeChapterByName('aaa')
    c.undoer.undo()
    assert cc.findChapterNode('aaa')
    cc.selectChapterByName('main',collapse=True)
else:
    self.skipTest('Can not be run locally')
#@+node:ekr.20110608162543.3365: *4* @test chapter-rename & undo
# cc will be None when unit tests run dynamically.
import leo.core.leoChapters as leoChapters
new_code = getattr(leoChapters, 'new_code', True)
cc = c.chapterController
if new_code:
    self.skipTest('create/remove commands no longer exist.')
elif cc and not g.app.isExternalUnitTest:
    chaptersNode = cc.findChaptersNode()
    assert chaptersNode
    chapterNode = (
        cc.findChapterNode('aaa') or
        cc.createChapterByName('aaa',p=None))
    try:
        cc.selectChapterByName('aaa',chaptersNode)
        cc.renameChapterByName('bbb')
        cc.selectChapterByName('bbb',chaptersNode)
        cc.renameChapterByName('aaa')
        assert cc.findChapterNode('aaa'),'after undo'
    finally:
        cc.selectChapterByName('main',collapse=True)
else:
    self.skipTest('Can not be run locally')
#@+node:ekr.20110608181936.3368: *4* @test chapter-move/clone/copy-node-to
# cc will be None when unit tests run dynamically.
import leo.core.leoChapters as leoChapters
new_code = getattr(leoChapters, 'new_code', True)
cc = c.chapterController
if new_code:
    self.skipTest('move/clone/copy commands no longer exist.')
elif cc and not g.app.isExternalUnitTest:
    chaptersNode = cc.findChaptersNode()
    assert chaptersNode,'fail 0'
    chapterNode = (
        cc.findChapterNode('aaa') or
        cc.createChapterByName('aaa',p=None))
    table = (
        ('node a',cc.moveNodeToChapterHelper),
        ('node b',cc.copyNodeToChapterHelper),
        ('node c',cc.cloneNodeToChapterHelper),
    )
    # Initialze 
    while p.hasChildren():
        p.firstChild().doDelete(newNode=None)
    for h,unused_f in table:
        p2 = p.insertAsLastChild()
        p2.h = h
        p2.b = '# %s' % h
    try:
        cc.selectChapterByName('aaa')
        for h,f in table:
            p2 = g.findNodeInTree(c,p,h)
            assert p2,'fail 1'
            c.selectPosition(p2) # All helpers work on c.p.
            f('aaa')
            assert g.findNodeInTree(c,chapterNode,h),(
                'fail 2', chapterNode.h, h, f.__name__)
        assert not g.findNodeInTree(c,p,'node a')
        assert g.findNodeInTree(c,p,'node b')
        assert g.findNodeInTree(c,p,'node c')
    finally:
        if 1: # Restore the tree so activeUnitTests.txt does not change.
            while p.hasChildren():
                p.firstChild().doDelete(newNode=None)
            for h,f in table:
                p3 = g.findNodeInTree(c,chapterNode,h)
                if p3: p3.doDelete()
        cc.selectChapterByName('main',collapse=True)
        c.redraw()
else:
    self.skipTest('Can not be run locally')
#@+node:ekr.20160402043006.1: *5* node a
# node a
#@+node:ekr.20160402043006.2: *5* node b
# node b
#@+node:ekr.20160402043006.3: *5* node c
# node c
#@+node:ekr.20080503132221.1: *4* @test chapter-create-from-node
# cc will be None when unit tests run dynamically.
import leo.core.leoChapters as leoChapters
new_code = getattr(leoChapters, 'new_code', True)
cc = c.chapterController
if new_code:
    self.skipTest('create-from-node no longer exist.')
elif cc and not g.app.isExternalUnitTest:
    root = p.copy()
    # Init the children
    while p.hasChildren():
        p.firstChild().doDelete(newNode=None)
    child = p.insertAsNthChild(0)
    # c.setHeadString(child,'child') # Force the headline to update.
    child.h = 'child'
    child.b = '# child'
    # Kill the chapter so the test will not fail if run twice.
    chapter = cc.chaptersDict.get('new-chapter')
    if chapter:
        cc.removeChapterByName('new-chapter')
    try:
        c.selectPosition(child)
        c.chapterController.createChapterByName(
            'new-chapter',child,'Create Chapter From Node')
        if 0:
            c.undoer.undo()
            c.undoer.redo()
            c.undoer.undo()
            c.undoer.redo()
            c.undoer.undo() # Don't pollute future unit tests.
        else:
            c.redraw_now() # Required.
            chapterNode = cc.findChapterNode('new-chapter')
            assert chapterNode,'fail 1: %s' % (undoType)
            chapterNode.doDelete()
            c.redraw_now()
    finally:
        cc.selectChapterByName('main',collapse=True)
        if 1: # Do this so the activeUnitTests.txt does not change.
            while root.hasChildren():
                root.firstChild().doDelete(newNode=None)
        c.redraw_now()
else:
    self.skipTest('Can not be run locally')

#@+node:ekr.20090615053403.4876: *3* leoColorizer
#@+node:ekr.20090615053403.4877: *4* @test @comment after @language plain
p = c.p.firstChild()
c.selectPosition(p) # Sets body text.
# val = c.frame.body.colorizer.colorize(p,incremental=False)
# assert val=="ok", "colorizer test failed: %s" % p.h
#@+node:ekr.20090615053403.4878: *5* plain code
@language plain
@comment # /* */

This is plain text.

# This is a comment.

More plain text.

/* A block comment
continues */

More plain text.
#@+node:ekr.20170201143435.1: *4* @test bc.scanLanguageDirectives
@language python
import leo.core.leoColorizer as leoColorizer
# import imp
# imp.reload(leoColorizer)
wrapper = c.frame.body.wrapper
widget = c.frame.body.widget
x = leoColorizer.JEditColorizer(c, widget, wrapper)
tables = p.firstChild()
tables_s = tables.b
child = p.firstChild().next()
assert child.h == 'test-child'
grand = child.firstChild()
<< scanLanguageDirectives test tables >>
try:
    for i, data in enumerate(language_table):
        language, child_s, grand_s = data
        child.b = child_s
        grand.b = grand_s
        got = x.scanLanguageDirectives(grand)
        assert got == language, '%s expected %r, got %r child.b %r' % (
            i, language, got, child.b)
finally:
    tables.b = tables_s
    
#@+node:ekr.20170201143435.2: *5* << scanLanguageDirectives test tables >>
language_table = [
    ('python', '@language rest\n@language python\n', ''),
    ('rest', '@language rest', ''),
    ('python', '@language rest\n@language python\n', ''),
]
#@+node:ekr.20170201143435.3: *5* test-child
@language rest
@language python
#@+node:ekr.20170201143435.4: *6* test-grandchild
#@+node:ekr.20170201175441.1: *4* @test bc.useSyntaxColoring
@language python
import leo.core.leoColorizer as leoColorizer
# import imp
# imp.reload(leoColorizer)
wrapper = c.frame.body.wrapper
widget = c.frame.body.widget
x = leoColorizer.JEditColorizer(c, widget, wrapper)
tables = p.firstChild()
tables_s = tables.b
child = p.firstChild().next()
assert child.h == 'test-child'
grand = child.firstChild()
<< useSyntaxColoring test tables >>
try:
    for i, data in enumerate(language_table):
        expected, child_s, grand_s = data
        child.b = child_s
        grand.b = grand_s
        got = x.useSyntaxColoring(grand)
        assert got == expected, '%s expected %r, got %r child.b %r' % (
            i, expected, got, child.b)
finally:
    tables.b = tables_s
    
#@+node:ekr.20170201175441.2: *5* << useSyntaxColoring test tables >>
language_table = [
    (True, '', ''),
    # Ambiguous parent.
    (True, '@color \n@nocolor\n', ''),
    (True, '@nocolor \n@color\n', ''),
    # Unambiguous parent.
    (True, '@nocolor-node', ''), # Does not apply to descendants.
    (False, '@nocolor', ''),
    (False, '@killcolor', ''),
    #
    # Note: the following tests don't matter because
    # jedit.recolor ignores the self.enabled flag.
    # As a result, *all* color directives, including @nocolor-node,
    # Apply from the directive to the next color directive.
    #
    # Unambiguous child.
    (False, '', '@killcolor\n'),
    (True, '', '@color\n'),
    # @nocolor-node rules node.
    (False, '', '@nocolor-node\n'),
    (False, '', '@color\n@nocolor-node\n'),
    # Ambiguous node: defer to ancestors.
    (True, '', '@color\n@nocolor'),
    (True, '', '@nocolor\n@color'),
]
#@+node:ekr.20170201175441.3: *5* test-child
#@+node:ekr.20170201175441.4: *6* test-grandchild
@nocolor
@color
#@+node:ekr.20090615053403.4879: *4* @test colorizer Actionscript
p = c.p.firstChild()
c.selectPosition(p) # Sets body text.
# val = c.frame.body.colorizer.colorize(p,incremental=False)
# assert val=="ok", "colorizer test failed: %s" % p.h
#@+node:ekr.20090615053403.4880: *5* actionscript test
@language actionscript

break
call, continue
delete, do
else
false, for, function
goto
if, in
new, null
return
true, typeof
undefined
var, void, while, with
#include
catch, constructor
prototype
this, try
_parent, _root, __proto__
// Jeeze hasn't anyone ever heard of namespaces??
ASnative, abs, acos, appendChild, asfunction, asin, atan, atan2, attachMovie, attachSound, attributes
BACKSPACE
CAPSLOCK, CONTROL, ceil, charAt, charCodeAt, childNodes, chr, cloneNode, close, concat, connect, cos, createElement, createTextNode
DELETEKEY, DOWN, docTypeDecl, duplicateMovieClip
END, ENTER, ESCAPE, enterFrame, entry, equal, eval, evaluate, exp
firstChild, floor, fromCharCode, fscommand, getAscii
getBeginIndex, getBounds, getBytesLoaded, getBytesTotal, getCaretIndex, getCode, getDate, getDay, getEndIndex, getFocus, getFullYear, getHours, getMilliseconds, getMinutes, getMonth, getPan, getProperty, getRGB, getSeconds, getTime, getTimer, getTimezoneOffset, getTransform, getURL, getUTCDate, getUTCDay, getUTCFullYear, getUTCHours, getUTCMilliseconds, getUTCMinutes, getUTCMonth, getUTCSeconds, getVersion, getVolume, getYear, globalToLocal, gotoAndPlay, gotoAndStop
HOME, haschildNodes, hide, hitTest
INSERT, Infinity, ifFrameLoaded, ignoreWhite, indexOf, insertBefore, int, isDown, isFinite, isNaN, isToggled
join
keycode, keyDown, keyUp
LEFT, LN10, LN2, LOG10E, LOG2E, lastChild, lastIndexOf, length, load, loaded, loadMovie, loadMovieNum, loadVariables, loadVariablesNum, localToGlobal, log
MAX_VALUE, MIN_VALUE, max, maxscroll, mbchr, mblength, mbord, mbsubstring, min, 
NEGATIVE_INFINITY, NaN, newline, nextFrame, nextScene, nextSibling, nodeName, nodeType, nodeValue
on, onClipEvent, onClose, onConnect, onData, onLoad, onXML, ord
PGDN, PGUP, PI, POSITIVE_INFINITY, parentNode, parseFloat, parseInt, parseXML, play, pop, pow, press, prevFrame, previousSibling, prevScene, print, printAsBitmap, printAsBitmapNum, printNum, push
RIGHT, random, release, removeMovieClip, removeNode, reverse, round
SPACE, SQRT1_2, SQRT2, scroll, send, sendAndLoad, set, setDate, setFocus, setFullYear, setHours, setMilliseconds, setMinutes, setMonth, setPan, setProperty, setRGB, setSeconds, setSelection, setTime, setTransform, setUTCDate, setUTCFullYear, setUTCHours, setUTCMilliseconds, setUTCMinutes, setUTCMonth, setUTCSeconds, setVolume, setYear, shift, show, sin, slice, sort, start, startDrag, status, stop, stopAllSounds, stopDrag, substr, substring, swapDepths, splice, split, sqrt
TAB, tan, targetPath, tellTarget, toggleHighQuality, toLowerCase, toString, toUpperCase, trace
UP, UTC, unescape, unloadMovie, unLoadMovieNum, unshift, updateAfterEvent
valueOf
xmlDecl, _alpha
_currentframe
_droptarget
_focusrect, _framesloaded
_height, _highquality
_name
_quality
_rotation
_soundbuftime
_target, _totalframes
_url
_visible
_width
_x, _xmouse, _xscale
_y, _ymouse, _yscale
and, add, eq, ge, gt, le, lt, ne, not, or, Array, Boolean, Color, Date, Key, Math, MovieClip, Mouse, Number, Object, Selection, Sound, String, XML, XMLSocket
#@+node:ekr.20090615053403.4881: *4* @test colorizer C
p = c.p.firstChild()
c.selectPosition(p) # Sets body text.
# val = c.frame.body.colorizer.colorize(p,incremental=False)
# assert val=="ok", "colorizer test failed: %s" % p.h
#@+node:ekr.20090615053403.4882: *5* c code
@language c
@comment /* */

@
@c

#define WIPEOUT 0 /* 
                   * Causes database card number & flags to be set to zero. 
                   * This is so I don't need an infinite supply of cards!
                   */
// Not colored (because of @language /* */)
#include "equ.h"
#include "cmn.h"
#include "ramdef.h"
#include "eeprom.h"
#include <hpc_ram.h>
#include <rlydef.h>
#@+node:ekr.20090615053403.4883: *4* @test colorizer C#
p = c.p.firstChild()
c.selectPosition(p) # Sets body text.
# val = c.frame.body.colorizer.colorize(p,incremental=False)
# assert val=="ok", "colorizer test failed: %s" % p.h
#@+node:ekr.20090615053403.4884: *5* c# code
@language csharp
@ comment
@c

/* block
comment */

// test

id // not a keyword

abstract as 
base bool break byte 
case catch char checked class const continue 
decimal default delegate do double 
else enum event explicit extern 
false finally fixed float for foreach 
get goto 
if implicit in int interface internal is 
lock long 
namespace new null 
object operator out override 
params partial private protected public 
readonly ref return 
sbyte sealed set short sizeof stackalloc 
static string struct switch 
this throw true try typeof 
uint ulong unchecked unsafe ushort using 
value virtual void volatile 
where while
yield
#@+node:ekr.20090615053403.4885: *4* @test colorizer css
p = c.p.firstChild()
c.selectPosition(p) # Sets body text.
# val = c.frame.body.colorizer.colorize(p,incremental=False)
# assert val=="ok", "colorizer test failed: %s" % p.h
#@+node:ekr.20090615053403.4886: *5* css
@language css
/* New in 4.2. */

/*html tags*/
address, applet, area, a, base, basefont,
big, blockquote, body, br, b, caption, center,
cite, code, dd, dfn, dir, div, dl, dt, em, font,
form, h1, h2, h3, h4, h5, h6, head, hr, html, img,
input, isindex, i, kbd, link, li, link, map, menu,
meta, ol, option, param, pre, p, samp,
select, small, span, strike, strong, style, sub, sup,
table, td, textarea, th, title, tr, tt, ul, u, var,
/*units*/
mm, cm, in, pt, pc, em, ex, px,
/*colors*/
aqua, black, blue, fuchsia, gray, green, lime, maroon, navy, olive, purple, red, silver, teal, yellow, white,
/*important directive*/
!important,
/*font rules*/
font, font-family, font-style, font-variant, font-weight, font-size,
/*font values*/
cursive, fantasy, monospace, normal, italic, oblique, small-caps,
bold, bolder, lighter, medium, larger, smaller,
serif, sans-serif,
/*background rules*/
background, background-color, background-image, background-repeat, background-attachment, background-position,
/*background values*/
contained, none, top, center, bottom, left, right, scroll, fixed,
repeat, repeat-x, repeat-y, no-repeat,
/*text rules*/
word-spacing, letter-spacing, text-decoration, vertical-align, text-transform, text-align, text-indent, text-transform, text-shadow, unicode-bidi, line-height,
/*text values*/
normal, none, underline, overline, blink, sub, super, middle, top, text-top, text-bottom,
capitalize, uppercase, lowercase, none, left, right, center, justify,
line-through,
/*box rules*/
margin, margin-top, margin-bottom, margin-left, margin-right,
margin, padding-top, padding-bottom, padding-left, padding-right,
border, border-width, border-style, border-top, border-top-width, border-top-style, border-bottom, border-bottom-width, border-bottom-style, border-left, border-left-width, border-left-style, border-right, border-right-width, border-right-style, border-color,
/*box values*/
width, height, float, clear,
auto, thin, medium, thick, left, right, none, both,
none, dotted, dashed, solid, double, groove, ridge, inset, outset,
/*display rules*/
display, white-space, 
min-width, max-width, min-height, max-height,
outline-color, outline-style, outline-width,
/*display values*/
run-in, inline-block, list-item, block, inline, none, normal, pre, nowrap, table-cell, table-row, table-row-group, table-header-group, inline-table, table-column, table-column-group, table-cell, table-caption
/*list rules*/
list-style, list-style-type, list-style-image, list-style-position,
/*list values*/
disc, circle, square, decimal, decimal-leading-zero, none,
lower-roman, upper-roman, lower-alpha, upper-alpha, lower-latin, upper-latin,
/*table rules*/
border-collapse, caption-side,
/*table-values*/
empty-cells, table-layout,
/*misc values/rules*/
counter-increment, counter-reset,
marker-offset, z-index,
cursor, direction, marks, quotes,
clip, content, orphans, overflow, visibility,
/*aural rules*/
pitch, range, pitch-during, cue-after, pause-after, cue-before, pause-before, speak-header, speak-numeral, speak-punctuation, speed-rate, play-during, voice-family,
/*aural values*/
stress, azimuth, elevation, pitch, richness, volume,
page-break, page-after, page-inside
#@+node:ekr.20090615053403.4887: *4* @test colorizer CWEB
p = c.p.firstChild()
c.selectPosition(p) # Sets body text.
# val = c.frame.body.colorizer.colorize(p,incremental=False)
# assert val=="ok", "colorizer test failed: %s" % p.h
#@+node:ekr.20090615053403.4888: *5* CWEB
@language cweb

% This is limbo in cweb mode... It should be in \LaTeX mode, not \c mode.
% The following should not be colorized: class,if,else.

@* this is a _cweb_ comment.  Code is written in \c.
"strings" should not be colorized.
It should be colored in \LaTeX mode.
The following are not keywords in latex mode: if, else, etc.
Noweb section references are _valid_ in cweb comments!
<< section ref >>
<< missing ref >>
@c

and this is C code. // It is colored in \LaTeX mode by default.
/* This is a C block comment.  It may also be colored in restricted \LaTeX mode. */

// Section refs are valid in code too, of course.
<< section ref >>
<< missing ref >>

\LaTeX and \c should not be colored.
if else, while, do // C keywords.
#@+node:ekr.20090615053403.4889: *6* << section ref >>
<< section def >>=

    my \c code goes here // This is \LaTeX text
    /* This is also \LaTeX text */
#@+node:ekr.20110521073115.3486: *4* @test colorizer cython
@language python

p = c.p.firstChild()
c.selectPosition(p) # Sets body text.
# val = c.frame.body.colorizer.colorize(p,incremental=False)
# assert val=="ok", "colorizer test failed: %s" % p.h
#@+node:ekr.20110521073115.3490: *5* cython
@language cython

by cdef cimport cpdef ctypedef enum except?
extern gil include nogil property public
readonly struct union DEF IF ELIF ELSE
                    
NULL bint char dict double float int list
long object Py_ssize_t short size_t void

try:
    pass
except Exception:
    pass

#@+node:ekr.20090615053403.4890: *4* @test colorizer elisp
p = c.p.firstChild()
c.selectPosition(p) # Sets body text.
# val = c.frame.body.colorizer.colorize(p,incremental=False)
# assert val=="ok", "colorizer test failed: %s" % p.h
#@+node:ekr.20090615053403.4891: *5* elisp
@language elisp

; Maybe...
error princ 

; More typical of other lisps...
and apply
car cdr cons cond
defconst defun defvar 
eq equal eval
gt ge
if 
let le lt
mapcar 
ne nil 
or not 
prog progn 
set setq 
t type-of 
unless 
when while
#@+node:ekr.20090615053403.4892: *4* @test colorizer erlang
p = c.p.firstChild()
c.selectPosition(p) # Sets body text.
# val = c.frame.body.colorizer.colorize(p,incremental=False)
# assert val=="ok", "colorizer test failed: %s" % p.h
#@+node:ekr.20090615053403.4893: *5* erlang
@language erlang

halt()

-module()
#@+node:ekr.20090615053403.4894: *4* @test colorizer forth
p = c.p.firstChild()
c.selectPosition(p) # Sets body text.
# val = c.frame.body.colorizer.colorize(p,incremental=False)
# assert val=="ok", "colorizer test failed: %s" % p.h
#@+node:ekr.20090615053403.4895: *5* forth
@language forth

\ tiny demo of Leo forth syntax colouring

: some-forth-word ( x1 x2 -- x3 ) \ blue :, black/bold some-forth-word
   label: y  \ blue label:
   asm[ s" some string" type ]asm cr
   asm[ abc ]asm
   a
   s" abc "
   s" abc"
   a
   tty" abc "
   lcd2" abc "
   until

@ test
@c

{ abc }

a b @ c

asm[ abc ]asm

.( ab ) \ a string

: foo [ .s ] ;

   [ a b c
   x y z]
;
#@+node:ekr.20090615053403.4896: *4* @test colorizer HTML string bug
p = c.p.firstChild()
c.selectPosition(p) # Sets body text.
# val = c.frame.body.colorizer.colorize(p,incremental=False)
# assert val=="ok", "colorizer test failed: %s" % p.h
#@+node:ekr.20090615053403.4897: *5* html
@language html

b = "cd"
d
#@+node:ekr.20090615053403.4898: *4* @test colorizer HTML1
p = c.p.firstChild()
c.selectPosition(p) # Sets body text.
# val = c.frame.body.colorizer.colorize(p,incremental=False)
# assert val=="ok", "colorizer test failed: %s" % p.h
#@+node:ekr.20090615053403.4899: *5* html
@language html

<HTML>
<!-- Author: Edward K. Ream, edream@tds.net -->
<HEAD>
  <META NAME="GENERATOR" CONTENT="Microsoft FrontPage 4.0">
  <TITLE> Leo's Home Page </TITLE>
  <META NAME="description" CONTENT="This page describes Leo.
Leo adds powerful outlines to the noweb and CWEB literate programming languages.">
  <META NAME="keywords" CONTENT="LEO, LITERATE PROGRAMMING, OUTLINES, CWEB,
NOWEB, OUTLINES, EDWARD K. REAM, DONALD E. KNUTH, SILVIO LEVY, OPEN SOFTWARE">
</HEAD>
<!-- Last Modified: May 12, 2002 -->
<BODY BGCOLOR="#fffbdc">

<H1 ALIGN=CENTER><a NAME="top"></a><IMG SRC="Blank.gif" width=
"32" height="32" ALIGN="BOTTOM" NATURALSIZEFLAG="3"><IMG SRC="leo.gif" 
WIDTH="32" HEIGHT="32" ALIGN="BOTTOM" NATURALSIZEFLAG="3"><a href="leo_TOC.html#top"><IMG SRC=
"arrow_rt.gif" WIDTH="32" HEIGHT="32" ALIGN="BOTTOM" NATURALSIZEFLAG="3"></a> &nbsp;</H1>

<H1 ALIGN=CENTER> Leo's Home Page</H1>

<p align="center"><a href="http://www.python.org/"><img border="0" src="PythonPowered.gif" width="110" height="44"> </a> <A HREF="http://sourceforge.net/"><IMG SRC="http://sourceforge.net/sflogo.php?group_id=3458&type=1" NATURALSIZEFLAG="0" ALT="SourceForge Logo"></A>&nbsp;&nbsp;&nbsp;
<A HREF="http://sourceforge.net/project/?group_id=3458">Leo at SourceForge</A>&nbsp;&nbsp;
<a href="icons.html"><img border="0" src="LeoCodeGray.gif" width="77" height="42"></a>&nbsp;&nbsp;
<a href="icons.html"><img border="0" src="LeoProse.gif" width="81" height="42"></a>&nbsp;&nbsp;&nbsp;&nbsp;

<H3><A NAME="anchor127554"></A>Summary</H3>

<UL>
  <LI>Leo is a <i> programmer's editor</i>  and a flexible <i>browser</i> for
    projects, programs, classes or data. Leo clarifies design, coding, debugging, testing
  and maintenance.
  <LI>Leo is an <i>outlining editor</i>. Outlines clarify the big picture while
    providing unlimited space for details.
  <LI>Leo
    is a <a HREF="http://www.literateprogramming.com/"><i>literate
    programming</i></a> tool, compatible with <A HREF="http://www.eecs.harvard.edu/~nr/noweb/">noweb</A>
    and <a HREF="http://www-cs-faculty.stanford.edu/~knuth/cweb.html">CWEB</a>.
    Leo enhances any text-based
programming language, from assembly language and C to Java, Python and XML.
  <LI>Leo is also a <i>data organizer</i>. A single Leo outline can generate complex
    data spanning many different files.&nbsp; Leo has been used to manage web sites.
  <LI>Leo is a <i> project manager</i>. Leo provides multiple views
of a project within a single outline. Leo naturally represents tasks that remain
    up-to-date.
  <LI>Leo is fully <i> scriptable</i> using <A HREF="http://www.python.org/">Python</A>
  and saves its files in <A HREF="http://www.w3.org/XML/">XML</A> format.
  <LI>Leo is <i>portable</i>.&nbsp; Leo.py is 100% pure Python and will run on
    any platform supporting <A HREF="http://www.python.org/">Python</A>
    and <a href="http://tcl.activestate.com/">Tk/tcl</a>, including Windows,
    Linux and MacOS X.&nbsp; Leo.exe runs on any Windows platform.
  <LI>Leo is <a href="http://www.opensource.org/"> <i> Open Software</i></a>, distributed under
    the <a href="http://www.python.org/doc/Copyright.html"> Python License</a>.
</UL>

<H3>More Information and downloads</H3>

<ul>
  <LI>An excellent <a href="http://www.3dtree.com/ev/e/sbooks/leo/sbframetoc_ie.htm">online
    tutorial</a> and <A HREF="http://www.jserv.com/jk_orr/xml/leo.htm">Leo resource
  page</A>, both written by <a href="http://www.jserv.com/jk_orr">Joe Orr</a>.
  <LI>My brother's <a href="SpeedReam.html">slashdot
    article about Leo</a>, the best description about why Leo is special.
  <LI><A HREF="testimonials.html#anchor104391">What people are saying about Leo</A>
  <LI><A HREF="leo_TOC.html#anchor964914">Complete users guide</A>
    and
    <A HREF="intro.html#anchor887874">tutorial introduction</A>  with
  screen shots.
  <li><a href="FAQ.html">FAQ</a> and <a href="http://sourceforge.net/forum/?group_id=3458">help and discussion
    forums</a>, preferable to <A HREF="mailto:edream@tds.net">email</A> so others may join
    in.</li>
  <li><a href="icons.html">Icons</a> for bragging about Leo.</li>
</ul>

<a href="http://sourceforge.net/project/showfiles.php?group_id=3458">Download
    Leo</a> from <A HREF="http://sourceforge.net/project/?group_id=3458">Leo's SourceForge
site</A>.

<P ALIGN=left>Leo's author is <A HREF="http://personalpages.tds.net/~edream/index.html">Edward
  K. Ream</A> email: <A HREF="mailto:edream@tds.net">edream@tds.net</A> voice: (608) 231-0766

<HR ALIGN=LEFT>

<p align="center">

<IMG SRC="Blank.gif" ALIGN="left" NATURALSIZEFLAG=
"3" width="34" height="34"><IMG SRC="leo.gif" ALIGN="left" NATURALSIZEFLAG=
"3" width="32" height="32"><a HREF="leo_TOC.html"><IMG SRC="arrow_rt.gif" WIDTH="32"
HEIGHT="32" ALIGN="left" NATURALSIZEFLAG="3">

</BODY>
</HTML>
#@+node:ekr.20090615053403.4900: *4* @test colorizer HTML2
p = c.p.firstChild()
c.selectPosition(p) # Sets body text.
# val = c.frame.body.colorizer.colorize(p,incremental=False)
# assert val=="ok", "colorizer test failed: %s" % p.h
#@+node:ekr.20090615053403.4901: *5* html
@language html

<? xml version="1.0">
<!-- test -->
<project name="Converter" default="dist">
</project>"""
#@+node:ekr.20090615053403.4902: *4* @test colorizer Java
p = c.p.firstChild()
c.selectPosition(p) # Sets body text.
# val = c.frame.body.colorizer.colorize(p,incremental=False)
# assert val=="ok", "colorizer test failed: %s" % p.h
#@+node:ekr.20090615053403.4903: *5* html
@ doc part
@c

@language java /* Colored by match_leo_keyword: tag = leoKeyword. */

@whatever /* Colored by java match_following rule: tag = keyword4. */

/** A javadoc: tag = comment3 */

/** <!-- comment --> tag = comment1. */

/** @see tag = label */
#@+node:ekr.20090615053403.4904: *4* @test colorizer LaTex
p = c.p.firstChild()
c.selectPosition(p) # Sets body text.
# val = c.frame.body.colorizer.colorize(p,incremental=False)
# assert val=="ok", "colorizer test failed: %s" % p.h
#@+node:ekr.20090615053403.4905: *5* LaTex
@language latex

% This is a \LaTeX mode comment.

This is a test of \LaTeX mode.

@ blah blah blah
@c

\c and \LaTeX are latex keywords.

This is a keyword \% not the start of a comment.

More keywords: \@ and \( and \) and \{ and \}

The following should be colored:

\documentclass{report}

The following 2-letter words should be colored, regardless of what follows:

\(\)\{\}\@
\(abc\)abc\{abc\}abc\@abc
#@+node:ekr.20090615053403.4906: *4* @test colorizer lisp
p = c.p.firstChild()
c.selectPosition(p) # Sets body text.
# val = c.frame.body.colorizer.colorize(p,incremental=False)
# assert val=="ok", "colorizer test failed: %s" % p.h
#@+node:ekr.20090615053403.4907: *5* lisp
@language lisp

; Maybe...
error princ 

; More typical of other lisps...
and apply
car cdr cons cond
defconst defun defvar 
eq equal eval
gt ge
if 
let le lt
mapcar 
ne nil 
or not 
prog progn 
set setq 
t type-of 
unless 
when while
#@+node:ekr.20101020123501.6005: *4* @test colorizer objective-c
p = c.p.firstChild()
c.selectPosition(p) # Sets body text.
# val = c.frame.body.colorizer.colorize(p,incremental=False)
# assert val=="ok", "colorizer test failed: %s" % p.h
#@+node:ekr.20101020123501.6006: *5* objective-c
@language objective_c

@interface Application
    -(void) init;
    -(void) showMessage;
@end

@implementation Application 
    -(id) init {
        if (self = [super init]) {
            NSLog(@"Init ok");
            return self;
        }
        return nil;
    }
    -(void) showMessage {
        NSLog(@"Hello there");
    }
@end

@"Hello there"

,@interface
, @interface
the @interface

// By the way, I have noticed that such kind of words in doxygen block
// are highlighted properly, but they are labels here, not keywords1 as in my case.
/**
@var test
@todo
*/
#@+node:ekr.20090615053403.4908: *4* @test colorizer perl
p = c.p.firstChild()
c.selectPosition(p) # Sets body text.
# val = c.frame.body.colorizer.colorize(p,incremental=False)
# assert val=="ok", "colorizer test failed: %s" % p.h
#@+node:ekr.20090615053403.4909: *5* perl
@language perl

# From a perl tutorial.

print 'Hello world.';		# Print a message

$a = $b;	# Assign $b to $a

@food  = ("apples", "pears", "eels");

$grub = pop(@food);	# Now $grub = "eels"

$#food

@lines = <INFO>;

#!/usr/local/bin/perl
print "Password? ";		# Ask for input
$a = <STDIN>;			# Get input
chop $a;			# Remove the newline at end
while ($a ne "fred")		# While input is wrong...
{
    print "sorry. Again? ";	# Ask again
    $a = <STDIN>;		# Get input again
    chop $a;			# Chop off newline again
}

if ($sentence =~ /under/)
{
	print "We're talking about rugby\\n";
}

$sentence =~ s/london/London/

$_ = "Capes:Geoff::Shot putter:::Big Avenue";
@personal = split(/:/);

foreach $age (values %ages)
{
	print "Somebody is $age\\n";
}

&mysubroutine;		# Call the subroutine
&mysubroutine($_);	# Call it with a parameter
&mysubroutine(1+2, $_);	# Call it with two parameters

sub inside
{
	local($a, $b);			# Make local variables
	($a, $b) = ($_[0], $_[1]);	# Assign values
	$a =~ s/ //g;			# Strip spaces from
	$b =~ s/ //g;			#   local variables
	($a =~ /$b/ || $b =~ /$a/);	# Is $b inside $a
					#   or $a inside $b?
}
#@+node:ekr.20090615053403.4910: *4* @test colorizer PHP
p = c.p.firstChild()
c.selectPosition(p) # Sets body text.
# val = c.frame.body.colorizer.colorize(p,incremental=False)
# assert val=="ok", "colorizer test failed: %s" % p.h
#@+node:ekr.20090615053403.4911: *5* PHP
@language php
@ doc
This is a doc part.
@c

and or
array
array()
/* Multi-line comment
*/
this is a test.
__CLASS__
<?php and or array() ?>
<?PHP and or array() ?>
#@+node:ekr.20090615053403.4912: *4* @test colorizer plsql
p = c.p.firstChild()
c.selectPosition(p) # Sets body text.
# val = c.frame.body.colorizer.colorize(p,incremental=False)
# assert val=="ok", "colorizer test failed: %s" % p.h
#@+node:ekr.20090615053403.4913: *5* plsql
@language plsql

"a string"
-- reserved keywords
ABORT,
abort,
ACceSS,
access,
add,
all,
allocate,
alter,
analyze,
and,
any,
archive,
archivelog,
array,
arraylen,
as,
asc,
assert,
assign,
at,
audit,
authorization,
avg,
backup,
base_table,
become,
before,
begin,
between,
binary_integer,
block,
body,
boolean,
by,
cache,
cancel,
cascade,
case,
change,
char,
char_base,
character,
check,
checkpoint,
close,
cluster,
clusters,
cobol,
colauth,
column,
columns,
comment,
commit,
compile,
compress,
connect,
constant,
constraint,
constraints,
contents,
continue,
controlfile,
count,
crash,
create,
current,
currval,
cursor,
cycle,
data_base,
database,
datafile,
date,
dba,
debugoff,
debugon,
dec,
decimal,
declare,
default,
definition,
delay,
delete,
delta,
desc,
digits,
disable,
dismount,
dispose,
distinct,
distinct,
do,
double,
drop,
drop,
dump,
each,
else,
else,
elsif,
enable,
end,
end,
entry,
escape,
events,
except,
exception,
exception_init,
exceptions,
exclusive,
exec,
execute,
exists,
exists,
exit,
explain,
extent,
externally,
false,
fetch,
fetch,
file,
float,
float,
flush,
for,
for,
force,
foreign,
form,
fortran,
found,
freelist,
freelists,
from,
from,
function,
generic,
go,
goto,
grant,
group,
groups,
having,
identified,
if,
immediate,
in,
including,
increment,
index,
indexes,
indicator,
initial,
initrans,
insert,
instance,
int,
integer,
intersect,
into,
is,
key,
language,
layer,
level,
like,
limited,
link,
lists,
lock,
logfile,
long,
loop,
manage,
manual,
max,
maxdatafiles,
maxextents,
maxinstances,
maxlogfiles,
maxloghistory,
maxlogmembers,
maxtrans,
maxvalue,
min,
minextents,
minus,
minvalue,
mlslabel,
mod,
mode,
modify,
module,
mount,
natural,
new,
new,
next,
nextval,
noarchivelog,
noaudit,
nocache,
nocompress,
nocycle,
nomaxvalue,
nominvalue,
none,
noorder,
noresetlogs,
normal,
nosort,
not,
notfound,
nowait,
null,
number,
number_base,
numeric,
of,
off,
offline,
old,
on,
online,
only,
open,
open,
optimal,
option,
or,
order,
others,
out,
own,
package,
package,
parallel,
partition,
pctfree,
pctincrease,
pctused,
plan,
pli,
positive,
pragma,
precision,
primary,
prior,
private,
private,
privileges,
procedure,
procedure,
profile,
public,
quota,
raise,
range,
raw,
read,
real,
record,
recover,
references,
referencing,
release,
remr,
rename,
resetlogs,
resource,
restricted,
return,
reuse,
reverse,
revoke,
role,
roles,
rollback,
row,
rowid,
rowlabel,
rownum,
rows,
rowtype,
run,
savepoint,
schema,
scn,
section,
segment,
select,
select,
separate,
sequence,
session,
set,
set,
share,
shared,
size,
size,
smallint,
smallint,
snapshot,
some,
sort,
space,
sql,
sqlbuf,
sqlcode,
sqlerrm,
sqlerror,
sqlstate,
start,
start,
statement,
statement_id,
statistics,
stddev,
stop,
storage,
subtype,
successful,
sum,
sum,
switch,
synonym,
sysdate,
system,
tabauth,
table,
tables,
tables,
tablespace,
task,
temporary,
terminate,
then,
thread,
time,
to,
tracing,
transaction,
trigger,
triggers,
true,
truncate,
type,
uid,
under,
union,
unique,
unlimited,
until,
update,
use,
user,
using,
validate,
values,
varchar,
varchar2,
variance,
view,
views,
when,
whenever,
where,
while,
with,
work,
write,
xor
#@+node:ekr.20090615053403.4914: *4* @test colorizer python.xml (jEdit)
p = c.p.firstChild()
c.selectPosition(p) # Sets body text.
# val = c.frame.body.colorizer.colorize(p,incremental=False)
# assert val=="ok", "colorizer test failed: %s" % p.h
#@+node:ekr.20090615053403.4915: *5* python.xml
@language html

<?xml version="1.0"?>

<!DOCTYPE MODE SYSTEM "xmode.dtd">
<< remarks >>

<MODE>
    <PROPS>
        <PROPERTY NAME="indentPrevLine" VALUE="\s*.{3,}:\s*(#.*)?" />
        <PROPERTY NAME="lineComment" VALUE="#" />
    </PROPS>
    <RULES ESCAPE="\" IGNORE_CASE="FALSE" HIGHLIGHT_DIGITS="TRUE">
        << comments >>
        << literals >>
        << operators >>
        <MARK_PREVIOUS TYPE="FUNCTION" EXCLUDE_MATCH="TRUE">(</MARK_PREVIOUS>
        << keywords >>
    </RULES>
</MODE>
#@+node:ekr.20090615053403.4916: *6* << remarks >>
<!-- Python mode, by Slava Pestov. Based on PythonTokenMarker by -->
<!-- Jonathan Revusky -->

<!-- Modified 19-Jul-00 by Ivan Frohne to: -->
<!--  (a) implement 'indentOnEnter'; -->
<!--  (b) indent next line automatically after control structures followed -->
<!--	  by ':'; -->
<!--  (c) make """ or ''' multiline quotes TYPE LITERAL2; -->
<!--  (d) add TYPE FUNCTION identified by a following '(' -->
<!--  (e) eliminate the '?' SEQ TYPE ('?' has no meaning in Python); -->
<!--  (f) change the TYPE of 'and', 'or', and 'not' to KEYWORD1; and -->
<!--  (g) add all builtin functions, builtin exceptions, -->
<!--	  builtin type methods, File object methods, and special type -->
<!--	  attributes as TYPE KEYWORD3. -->
#@+node:ekr.20090615053403.4917: *6* << comments >>
<!-- Comment -->
<EOL_SPAN TYPE="COMMENT1">#</EOL_SPAN>

<!-- Triple-quotes -->
<SPAN TYPE="LITERAL2">
    <BEGIN>"""</BEGIN>
    <END>"""</END>
</SPAN>

<SPAN TYPE="LITERAL2">
    <BEGIN>'''</BEGIN>
    <END>'''</END>
</SPAN>
#@+node:ekr.20090615053403.4918: *6* << literals >>
<!-- Standard literals -->
<SPAN TYPE="LITERAL1">
    <BEGIN>"</BEGIN>
    <END>"</END>
</SPAN>

<SPAN TYPE="LITERAL1">
    <BEGIN>'</BEGIN>
    <END>'</END>
</SPAN>
#@+node:ekr.20090615053403.4919: *6* << operators >>
<SEQ TYPE="OPERATOR">=</SEQ>
<SEQ TYPE="OPERATOR">!</SEQ>
<SEQ TYPE="OPERATOR">&gt;=</SEQ>
<SEQ TYPE="OPERATOR">&lt;=</SEQ>
<SEQ TYPE="OPERATOR">+</SEQ>
<SEQ TYPE="OPERATOR">-</SEQ>
<SEQ TYPE="OPERATOR">/</SEQ>
<SEQ TYPE="OPERATOR">*</SEQ>
<SEQ TYPE="OPERATOR">&gt;</SEQ>
<SEQ TYPE="OPERATOR">&lt;</SEQ>
<SEQ TYPE="OPERATOR">%</SEQ>
<SEQ TYPE="OPERATOR">&amp;</SEQ>
<SEQ TYPE="OPERATOR">|</SEQ>
<SEQ TYPE="OPERATOR">^</SEQ>
<SEQ TYPE="OPERATOR">~</SEQ>
#@+node:ekr.20090615053403.4920: *6* << keywords >>
<KEYWORDS>
    << reserved words >>
    << builtins >>
    << exceptions >>
    << types >>
</KEYWORDS>
#@+node:ekr.20090615053403.4921: *7* << reserved words >>
<!--  Reserved Words  -->
<KEYWORD1>and</KEYWORD1>
<KEYWORD1>as</KEYWORD1>
<KEYWORD1>assert</KEYWORD1>
<KEYWORD1>break</KEYWORD1>
<KEYWORD1>class</KEYWORD1>
<KEYWORD1>continue</KEYWORD1>
<KEYWORD1>def</KEYWORD1>
<KEYWORD1>del</KEYWORD1>
<KEYWORD1>elif</KEYWORD1>
<KEYWORD1>else</KEYWORD1>
<KEYWORD1>except</KEYWORD1>
<KEYWORD1>exec</KEYWORD1>
<KEYWORD1>finally</KEYWORD1>
<KEYWORD1>for</KEYWORD1>
<KEYWORD1>from</KEYWORD1>
<KEYWORD1>global</KEYWORD1>
<KEYWORD1>if</KEYWORD1>
<KEYWORD1>import</KEYWORD1>
<KEYWORD1>in</KEYWORD1>
<KEYWORD1>is</KEYWORD1>
<KEYWORD1>lambda</KEYWORD1>
<KEYWORD1>not</KEYWORD1>
<KEYWORD1>or</KEYWORD1>
<KEYWORD1>pass</KEYWORD1>
<KEYWORD1>print</KEYWORD1>
<KEYWORD1>raise</KEYWORD1>
<KEYWORD1>return</KEYWORD1>
<KEYWORD1>try</KEYWORD1>
<KEYWORD1>while</KEYWORD1>
<KEYWORD1>yield</KEYWORD1>
#@+node:ekr.20090615053403.4922: *7* << builtins >>
<!-- builtins -->
<KEYWORD2>abs</KEYWORD2>
<KEYWORD2>apply</KEYWORD2>
<KEYWORD2>bool</KEYWORD2>
<KEYWORD2>buffer</KEYWORD2>
<KEYWORD2>callable</KEYWORD2>
<KEYWORD2>chr</KEYWORD2>
<KEYWORD2>classmethod</KEYWORD2>
<KEYWORD2>cmp</KEYWORD2>
<KEYWORD2>coerce</KEYWORD2>
<KEYWORD2>compile</KEYWORD2>
<KEYWORD2>complex</KEYWORD2>
<KEYWORD2>delattr</KEYWORD2>
<KEYWORD2>dict</KEYWORD2>
<KEYWORD2>dir</KEYWORD2>
<KEYWORD2>divmod</KEYWORD2>
<KEYWORD2>eval</KEYWORD2>
<KEYWORD2>execfile</KEYWORD2>
<KEYWORD2>file</KEYWORD2>
<KEYWORD2>filter</KEYWORD2>
<KEYWORD2>float</KEYWORD2>
<KEYWORD2>getattr</KEYWORD2>
<KEYWORD2>globals</KEYWORD2>
<KEYWORD2>hasattr</KEYWORD2>
<KEYWORD2>hash</KEYWORD2>
<KEYWORD2>hex</KEYWORD2>
<KEYWORD2>id</KEYWORD2>
<KEYWORD2>input</KEYWORD2>
<KEYWORD2>int</KEYWORD2>
<KEYWORD2>intern</KEYWORD2>
<KEYWORD2>isinstance</KEYWORD2>
<KEYWORD2>issubclass</KEYWORD2>
<KEYWORD2>iter</KEYWORD2>
<KEYWORD2>len</KEYWORD2>
<KEYWORD2>list</KEYWORD2>
<KEYWORD2>locals</KEYWORD2>
<KEYWORD2>long</KEYWORD2>
<KEYWORD2>map</KEYWORD2>
<KEYWORD2>max</KEYWORD2>
<KEYWORD2>min</KEYWORD2>
<KEYWORD2>object</KEYWORD2>
<KEYWORD2>oct</KEYWORD2>
<KEYWORD2>open</KEYWORD2>
<KEYWORD2>ord</KEYWORD2>
<KEYWORD2>pow</KEYWORD2>
<KEYWORD2>property</KEYWORD2>
<KEYWORD2>range</KEYWORD2>
<KEYWORD2>raw_input</KEYWORD2>
<KEYWORD2>reduce</KEYWORD2>
<KEYWORD2>reload</KEYWORD2>
<KEYWORD2>repr</KEYWORD2>
<KEYWORD2>round</KEYWORD2>
<KEYWORD2>setattr</KEYWORD2>
<KEYWORD2>slice</KEYWORD2>
<KEYWORD2>staticmethod</KEYWORD2>
<KEYWORD2>str</KEYWORD2>
<KEYWORD2>super</KEYWORD2>
<KEYWORD2>tuple</KEYWORD2>
<KEYWORD2>type</KEYWORD2>
<KEYWORD2>unichr</KEYWORD2>
<KEYWORD2>unicode</KEYWORD2>
<KEYWORD2>vars</KEYWORD2>
<KEYWORD2>xrange</KEYWORD2>
<KEYWORD2>zip</KEYWORD2>
#@+node:ekr.20090615053403.4923: *7* << exceptions >>
<!-- exceptions -->
<KEYWORD3>ArithmeticError</KEYWORD3>
<KEYWORD3>AssertionError</KEYWORD3>
<KEYWORD3>AttributeError</KEYWORD3>
<KEYWORD3>DeprecationWarning</KEYWORD3>
<KEYWORD3>EOFError</KEYWORD3>
<KEYWORD3>EnvironmentError</KEYWORD3>
<KEYWORD3>Exception</KEYWORD3>
<KEYWORD3>FloatingPointError</KEYWORD3>
<KEYWORD3>IOError</KEYWORD3>
<KEYWORD3>ImportError</KEYWORD3>
<KEYWORD3>IndentationError</KEYWORD3>
<KEYWORD3>IndexError</KEYWORD3>
<KEYWORD3>KeyError</KEYWORD3>
<KEYWORD3>KeyboardInterrupt</KEYWORD3>
<KEYWORD3>LookupError</KEYWORD3>
<KEYWORD3>MemoryError</KEYWORD3>
<KEYWORD3>NameError</KEYWORD3>
<KEYWORD3>NotImplemented</KEYWORD3>
<KEYWORD3>NotImplementedError</KEYWORD3>
<KEYWORD3>OSError</KEYWORD3>
<KEYWORD3>OverflowError</KEYWORD3>
<KEYWORD3>OverflowWarning</KEYWORD3>
<KEYWORD3>ReferenceError</KEYWORD3>
<KEYWORD3>RuntimeError</KEYWORD3>
<KEYWORD3>RuntimeWarning</KEYWORD3>
<KEYWORD3>StandardError</KEYWORD3>
<KEYWORD3>StopIteration</KEYWORD3>
<KEYWORD3>SyntaxError</KEYWORD3>
<KEYWORD3>SyntaxWarning</KEYWORD3>
<KEYWORD3>SystemError</KEYWORD3>
<KEYWORD3>SystemExit</KEYWORD3>
<KEYWORD3>TabError</KEYWORD3>
<KEYWORD3>TypeError</KEYWORD3>
<KEYWORD3>UnboundLocalError</KEYWORD3>
<KEYWORD3>UnicodeError</KEYWORD3>
<KEYWORD3>UserWarning</KEYWORD3>
<KEYWORD3>ValueError</KEYWORD3>
<KEYWORD3>Warning</KEYWORD3>
<KEYWORD3>WindowsError</KEYWORD3>
<KEYWORD3>ZeroDivisionError</KEYWORD3>
#@+node:ekr.20090615053403.4924: *7* << types >>
<!-- types (from types module) -->
<KEYWORD3>BufferType</KEYWORD3>
<KEYWORD3>BuiltinFunctionType</KEYWORD3>
<KEYWORD3>BuiltinMethodType</KEYWORD3>
<KEYWORD3>ClassType</KEYWORD3>
<KEYWORD3>CodeType</KEYWORD3>
<KEYWORD3>ComplexType</KEYWORD3>
<KEYWORD3>DictProxyType</KEYWORD3>
<KEYWORD3>DictType</KEYWORD3>
<KEYWORD3>DictionaryType</KEYWORD3>
<KEYWORD3>EllipsisType</KEYWORD3>
<KEYWORD3>FileType</KEYWORD3>
<KEYWORD3>FloatType</KEYWORD3>
<KEYWORD3>FrameType</KEYWORD3>
<KEYWORD3>FunctionType</KEYWORD3>
<KEYWORD3>GeneratorType</KEYWORD3>
<KEYWORD3>InstanceType</KEYWORD3>
<KEYWORD3>IntType</KEYWORD3>
<KEYWORD3>LambdaType</KEYWORD3>
<KEYWORD3>ListType</KEYWORD3>
<KEYWORD3>LongType</KEYWORD3>
<KEYWORD3>MethodType</KEYWORD3>
<KEYWORD3>ModuleType</KEYWORD3>
<KEYWORD3>NoneType</KEYWORD3>
<KEYWORD3>ObjectType</KEYWORD3>
<KEYWORD3>SliceType</KEYWORD3>
<KEYWORD3>StringType</KEYWORD3>
<KEYWORD3>StringTypes</KEYWORD3>
<KEYWORD3>TracebackType</KEYWORD3>
<KEYWORD3>TupleType</KEYWORD3>
<KEYWORD3>TypeType</KEYWORD3>
<KEYWORD3>UnboundMethodType</KEYWORD3>
<KEYWORD3>UnicodeType</KEYWORD3>
<KEYWORD3>XRangeType</KEYWORD3>

<KEYWORD3>False</KEYWORD3>
<KEYWORD3>None</KEYWORD3>
<KEYWORD3>True</KEYWORD3>

<KEYWORD3>__abs__</KEYWORD3>
<KEYWORD3>__add__</KEYWORD3>
<KEYWORD3>__all__</KEYWORD3>
<KEYWORD3>__author__</KEYWORD3>
<KEYWORD3>__bases__</KEYWORD3>
<KEYWORD3>__builtins__</KEYWORD3>
<KEYWORD3>__call__</KEYWORD3>
<KEYWORD3>__class__</KEYWORD3>
<KEYWORD3>__cmp__</KEYWORD3>
<KEYWORD3>__coerce__</KEYWORD3>
<KEYWORD3>__contains__</KEYWORD3>
<KEYWORD3>__debug__</KEYWORD3>
<KEYWORD3>__del__</KEYWORD3>
<KEYWORD3>__delattr__</KEYWORD3>
<KEYWORD3>__delitem__</KEYWORD3>
<KEYWORD3>__delslice__</KEYWORD3>
<KEYWORD3>__dict__</KEYWORD3>
<KEYWORD3>__div__</KEYWORD3>
<KEYWORD3>__divmod__</KEYWORD3>
<KEYWORD3>__doc__</KEYWORD3>
<KEYWORD3>__eq__</KEYWORD3>
<KEYWORD3>__file__</KEYWORD3>
<KEYWORD3>__float__</KEYWORD3>
<KEYWORD3>__floordiv__</KEYWORD3>
<KEYWORD3>__future__</KEYWORD3>
<KEYWORD3>__ge__</KEYWORD3>
<KEYWORD3>__getattr__</KEYWORD3>
<KEYWORD3>__getattribute__</KEYWORD3>
<KEYWORD3>__getitem__</KEYWORD3>
<KEYWORD3>__getslice__</KEYWORD3>
<KEYWORD3>__gt__</KEYWORD3>
<KEYWORD3>__hash__</KEYWORD3>
<KEYWORD3>__hex__</KEYWORD3>
<KEYWORD3>__iadd__</KEYWORD3>
<KEYWORD3>__import__</KEYWORD3>
<KEYWORD3>__imul__</KEYWORD3>
<KEYWORD3>__init__</KEYWORD3>
<KEYWORD3>__int__</KEYWORD3>
<KEYWORD3>__invert__</KEYWORD3>
<KEYWORD3>__iter__</KEYWORD3>
<KEYWORD3>__le__</KEYWORD3>
<KEYWORD3>__len__</KEYWORD3>
<KEYWORD3>__long__</KEYWORD3>
<KEYWORD3>__lshift__</KEYWORD3>
<KEYWORD3>__lt__</KEYWORD3>
<KEYWORD3>__members__</KEYWORD3>
<KEYWORD3>__metaclass__</KEYWORD3>
<KEYWORD3>__mod__</KEYWORD3>
<KEYWORD3>__mro__</KEYWORD3>
<KEYWORD3>__mul__</KEYWORD3>
<KEYWORD3>__name__</KEYWORD3>
<KEYWORD3>__ne__</KEYWORD3>
<KEYWORD3>__neg__</KEYWORD3>
<KEYWORD3>__new__</KEYWORD3>
<KEYWORD3>__nonzero__</KEYWORD3>
<KEYWORD3>__oct__</KEYWORD3>
<KEYWORD3>__or__</KEYWORD3>
<KEYWORD3>__path__</KEYWORD3>
<KEYWORD3>__pos__</KEYWORD3>
<KEYWORD3>__pow__</KEYWORD3>
<KEYWORD3>__radd__</KEYWORD3>
<KEYWORD3>__rdiv__</KEYWORD3>
<KEYWORD3>__rdivmod__</KEYWORD3>
<KEYWORD3>__reduce__</KEYWORD3>
<KEYWORD3>__repr__</KEYWORD3>
<KEYWORD3>__rfloordiv__</KEYWORD3>
<KEYWORD3>__rlshift__</KEYWORD3>
<KEYWORD3>__rmod__</KEYWORD3>
<KEYWORD3>__rmul__</KEYWORD3>
<KEYWORD3>__ror__</KEYWORD3>
<KEYWORD3>__rpow__</KEYWORD3>
<KEYWORD3>__rrshift__</KEYWORD3>
<KEYWORD3>__rsub__</KEYWORD3>
<KEYWORD3>__rtruediv__</KEYWORD3>
<KEYWORD3>__rxor__</KEYWORD3>
<KEYWORD3>__setattr__</KEYWORD3>
<KEYWORD3>__setitem__</KEYWORD3>
<KEYWORD3>__setslice__</KEYWORD3>
<KEYWORD3>__self__</KEYWORD3>
<KEYWORD3>__slots__</KEYWORD3>
<KEYWORD3>__str__</KEYWORD3>
<KEYWORD3>__sub__</KEYWORD3>
<KEYWORD3>__truediv__</KEYWORD3>
<KEYWORD3>__version__</KEYWORD3>
<KEYWORD3>__xor__</KEYWORD3>
#@+node:ekr.20090615053403.4925: *4* @test colorizer Python1
p = c.p.firstChild()
c.selectPosition(p) # Sets body text.
# val = c.frame.body.colorizer.colorize(p,incremental=False)
# assert val=="ok", "colorizer test failed: %s" % p.h
#@+node:ekr.20090615053403.4926: *5* python
@language python

int
float
dict
#@+node:ekr.20090615053403.4927: *4* @test colorizer Python2
p = c.p.firstChild()
c.selectPosition(p) # Sets body text.
# val = c.frame.body.colorizer.colorize(p,incremental=False)
# assert val=="ok", "colorizer test failed: %s" % p.h
#@+node:ekr.20090615053403.4928: *5* python
"""This creates a free-floating copy of v's tree for undo.
The copied trees must use different tnodes than the original."""

def copyTree(self,root):

    c = self
    # Create the root VNode.
    result = v = leoNodes.VNode(c)
    # Copy the headline and icon values v.copyNode(root,v)
    # Copy the rest of tree.
    v.copyTree(root,v)
    # Replace all tnodes in v by copies.
    assert(v.nodeAfterTree() == None)
    while v:
        v = leoNodes.VNode(c)
        v = v.threadNext()
    return result
#@+node:ekr.20090615053403.4929: *4* @test colorizer r
p = c.p.firstChild()
c.selectPosition(p) # Sets body text.
# val = c.frame.body.colorizer.colorize(p,incremental=False)
# assert val=="ok", "colorizer test failed: %s" % p.h
#@+node:ekr.20090615053403.4930: *5* r
@language r

x <- rnorm(10) 

vv <- function(z) return(z) 

def python_funct(uu): 
return uu
#@+node:ekr.20090615053403.4931: *4* @test colorizer rapidq
p = c.p.firstChild()
c.selectPosition(p) # Sets body text.
# val = c.frame.body.colorizer.colorize(p,incremental=False)
# assert val=="ok", "colorizer test failed: %s" % p.h
#@+node:ekr.20090615053403.4932: *5* rapidq
' New in 4.2.
@language rapidq
' a comment.

$APPTYPE,$DEFINE,$ELSE,$ENDIF,$ESCAPECHARS,$IFDEF,$IFNDEF,
$INCLUDE,$MACRO,$OPTIMIZE,$OPTION,$RESOURCE,$TYPECHECK,$UNDEF,
ABS,ACOS,ALIAS,AND,AS,ASC,ASIN,ATAN,ATN,BIN$,BIND,BYTE,
CALL,CALLBACK,CALLFUNC,CASE,CEIL,CHDIR,CHDRIVE,CHR$,CINT,
CLNG,CLS,CODEPTR,COMMAND$,COMMANDCOUNT,CONSOLE,CONST,CONSTRUCTOR,
CONVBASE$,COS,CREATE,CSRLIN,CURDIR$,DATA,DATE$,DEC,DECLARE,
DEFBYTE,DEFDBL,DEFDWORD,DEFINT,DEFLNG,DEFSHORT,DEFSNG,DEFSTR,
DEFWORD,DELETE$,DIM,DIR$,DIREXISTS,DO,DOEVENTS,DOUBLE,DWORD,
ELSE,ELSEIF,END,ENVIRON,ENVIRON$,EVENT,EXIT,EXP,EXTENDS,
EXTRACTRESOURCE,FIELD$,FILEEXISTS,FIX,FLOOR,FOR,FORMAT$,FRAC,
FUNCTION,FUNCTIONI,GET$,GOSUB,GOTO,HEX$,IF,INC,INITARRAY,
INKEY$,INP,INPUT,INPUT$,INPUTHANDLE,INSERT$,INSTR,INT,INTEGER,
INV,IS,ISCONSOLE,KILL,KILLMESSAGE,LBOUND,LCASE$,LEFT$,LEN,
LFLUSH,LIB,LIBRARYINST,LOCATE,LOG,LONG,LOOP,LPRINT,LTRIM$,
MEMCMP,MESSAGEBOX,MESSAGEDLG,MID$,MKDIR,MOD,MOUSEX,MOUSEY,
NEXT,NOT,OFF,ON,OR,OUT,OUTPUTHANDLE,PARAMSTR$,PARAMSTRCOUNT,
PARAMVAL,PARAMVALCOUNT,PCOPY,PEEK,PLAYWAV,POKE,POS,POSTMESSAGE,
PRINT,PROPERTY,QUICKSORT,RANDOMIZE,REDIM,RENAME,REPLACE$,
REPLACESUBSTR$,RESOURCE,RESOURCECOUNT,RESTORE,RESULT,RETURN,
REVERSE$,RGB,RIGHT$,RINSTR,RMDIR,RND,ROUND,RTRIM$,RUN,
SCREEN,SELECT,SENDER,SENDMESSAGE,SETCONSOLETITLE,SGN,SHELL,
SHL,SHORT,SHOWMESSAGE,SHR,SIN,SINGLE,SIZEOF,SLEEP,SOUND,
SPACE$,SQR,STACK,STATIC,STEP,STR$,STRF$,STRING,STRING$,
SUB,SUBI,SWAP,TALLY,TAN,THEN,TIME$,TIMER,TO,TYPE,UBOUND,
UCASE$,UNLOADLIBRARY,UNTIL,VAL,VARIANT,VARPTR,VARPTR$,VARTYPE,
WEND,WHILE,WITH,WORD,XOR
#@+node:ekr.20090615053403.4933: *4* @test colorizer Rebol
p = c.p.firstChild()
c.selectPosition(p) # Sets body text.
# val = c.frame.body.colorizer.colorize(p,incremental=False)
# assert val=="ok", "colorizer test failed: %s" % p.h
#@+node:ekr.20090615053403.4934: *5* Rebol
@language rebol

; a comment
about abs absolute add alert alias all alter and and~ any append arccosine arcsine arctangent array ask at  
back bind boot-prefs break browse build-port build-tag  
call caret-to-offset catch center-face change change-dir charset checksum choose clean-path clear clear-fields close comment complement compose compress confirm continue-post context copy cosine create-request crypt cvs-date cvs-version  
debase decode-cgi decode-url decompress deflag-face dehex delete demo desktop detab dh-compute-key dh-generate-key dh-make-key difference dirize disarm dispatch divide do do-boot do-events do-face do-face-alt does dsa-generate-key dsa-make-key dsa-make-signature dsa-verify-signature  
echo editor either else emailer enbase entab exclude exit exp extract 
fifth find find-key-face find-window flag-face first flash focus for forall foreach forever form forskip fourth free func function  
get get-modes get-net-info get-style  
halt has head help hide hide-popup  
if import-email in inform input insert insert-event-func intersect 
join 
last launch launch-thru layout license list-dir load load-image load-prefs load-thru log-10 log-2 log-e loop lowercase  
make make-dir make-face max maximum maximum-of min minimum minimum-of mold multiply  
negate net-error next not now  
offset-to-caret open open-events or or~ 
parse parse-email-addrs parse-header parse-header-date parse-xml path-thru pick poke power prin print probe protect protect-system  
q query quit  
random read read-io read-net read-thru reboot recycle reduce reform rejoin remainder remold remove remove-event-func rename repeat repend replace request request-color request-date request-download request-file request-list request-pass request-text resend return reverse rsa-encrypt rsa-generate-key rsa-make-key 
save save-prefs save-user scroll-para second secure select send send-and-check set set-modes set-font set-net set-para set-style set-user set-user-name show show-popup sine size-text skip sort source split-path square-root stylize subtract switch  
tail tangent textinfo third throw throw-on-error to to-binary to-bitset to-block to-char to-date to-decimal to-email to-event to-file to-get-word to-hash to-hex to-idate to-image to-integer to-issue to-list to-lit-path to-lit-word to-local-file to-logic to-money to-none to-pair to-paren to-path to-rebol-file to-refinement to-set-path to-set-word to-string to-tag to-time to-tuple to-url to-word trace trim try  
unfocus union unique uninstall unprotect unset until unview update upgrade uppercase usage use  
vbug view view-install view-prefs  
wait what what-dir while write write-io  
xor xor~  
action! any-block! any-function! any-string! any-type! any-word!  
binary! bitset! block!  
char!  
datatype! date! decimal! 
email! error! event!  
file! function!  
get-word!  
hash!  
image! integer! issue!  
library! list! lit-path! lit-word! logic!  
money!  
native! none! number!  
object! op!  
pair! paren! path! port!  
refinement! routine!  
series! set-path! set-word! string! struct! symbol!  
tag! time! tuple!  
unset! url!  
word!  
any-block? any-function? any-string? any-type? any-word?  
binary? bitset? block?  
char? connected? crypt-strength? 
datatype? date? decimal? dir?  
email? empty? equal? error? even? event? exists? exists-key?
file? flag-face? found? function?  
get-word? greater-or-equal? greater?  
hash? head?  
image? in-window? index? info? input? inside? integer? issue?  
length? lesser-or-equal? lesser? library? link-app? link? list? lit-path? lit-word? logic?  
modified? money?  
native? negative? none? not-equal? number?  
object? odd? offset? op? outside?  
pair? paren? path? port? positive?  
refinement? routine?  
same? screen-offset? script? series? set-path? set-word? size? span? strict-equal? strict-not-equal? string? struct?  
tag? tail? time? tuple? type?  
unset? url?  
value? view? 
within? word?  
zero?
#@+node:ekr.20090615053403.4935: *4* @test colorizer rest
p = c.p.firstChild()
c.selectPosition(p) # Sets body text.
# val = c.frame.body.colorizer.colorize(p,incremental=False)
# assert val=="ok", "colorizer test failed: %s" % p.h
#@+node:ekr.20090615053403.4936: *5* rest
@language rest

@ @rst-options
code_mode=False
generate_rst=True
http_server_support = False
show_organizer_nodes=True
show_headlines=True
show_leo_directives=True
stylesheet_path=..\doc
write_intermediate_file = False
verbose=True
@c

. Links used in this document...

.. _`Pmw`:                  http://pmw.sourceforge.net/
.. _run:                    `Running Leo`_

.. WARNING: image targets may not have upper case letters!

.. |back| image:: arrow_lt.gif
    :target: FAQ.html

.. |leo| image:: leo.gif
    :target: front.html

.. |next| image:: arrow_rt.gif
    :target: intro.html

|back| |leo| |next|

###########################
Chapter 1: Installing Leo
###########################

This chapter tells how to install and run Leo.

**Important**:

If you have *any* problems installing Leo,
please ask for help on Leo's help forum:

.. contents::

**Windows**
    If you have `associated .leo files with Leo`_ you may run Leo by double-clicking any .leo file.
    You can also use a batch file.
    Put the following .bat file in c:\\Windows::

        cd c:\prog\LeoCVS\leo
        c:\python22\python c:\prog\LeoCVS\leo\leo.py %1

-   Download the latest version of Leo from `Leo's download page`_.

-   In Windows 2K or XP, go to ``Start->Settings->Control panel``, open the ``Folder Options`` tab.

    **Warning**: When building Tcl on Linux, do **not** specify
    "--enable-threads".
    Only use Tcl with the default "threads not enabled" case.

-------------

|back| |leo| |next|
#@+node:ekr.20110529215703.3494: *4* @test colorizer scala
p = c.p.firstChild()
c.selectPosition(p) # Sets body text.
# val = c.frame.body.colorizer.colorize(p,incremental=False)
# assert val=="ok", "colorizer test failed: %s" % p.h
#@+node:ekr.20110529215703.3495: *5* scala
@language scala

/* A comment */

object HelloWorld {
    def main(args: Array[String]) {
      println("Hello, world!")
    }
  }
#@+node:ekr.20090615053403.4937: *4* @test colorizer shell
p = c.p.firstChild()
c.selectPosition(p) # Sets body text.
# val = c.frame.body.colorizer.colorize(p,incremental=False)
# assert val=="ok", "colorizer test failed: %s" % p.h
#@+node:ekr.20090615053403.4938: *5* shell
# New in 4.2.

@language shell

# comment
$# not a comment
break
case,continue,
do,done
elif,else,esac
fi,for
if,in
return,
then
until
while,

cd,chdir,eval,exec,
exit,kill,newgrp,pwd,read,readonly,
shift,test,trap,ulimit,
umask,wait
#@+node:ekr.20090615053403.4939: *4* @test colorizer shellscript
p = c.p.firstChild()
c.selectPosition(p) # Sets body text.
# val = c.frame.body.colorizer.colorize(p,incremental=False)
# assert val=="ok", "colorizer test failed: %s" % p.h
#@+node:ekr.20090615053403.4940: *5* shellscript
@language shellscript

# comment
$# not a comment
break
case,continue,
do,done
elif,else,esac
fi,for
if,in
return,
then
until
while,

cd,chdir,eval,exec,
exit,kill,newgrp,pwd,read,readonly,
shift,test,trap,ulimit,
umask,wait
#@+node:ekr.20090615053403.4941: *4* @test colorizer tex.xml (jEdit)
p = c.p.firstChild()
c.selectPosition(p) # Sets body text.
# val = c.frame.body.colorizer.colorize(p,incremental=False)
# assert val=="ok", "colorizer test failed: %s" % p.h
#@+node:ekr.20090615053403.4942: *5* tex.xml
@language html

<!-- ekr uses the MARK_FOLLOWING to mark _anything_ after \ -->

<?xml version="1.0"?>

<!DOCTYPE MODE SYSTEM "xmode.dtd">

<MODE>
    <PROPS>
        <PROPERTY NAME="lineComment" VALUE="%" />
    </PROPS>

    <RULES>
        << general rules >>
    </RULES>

    <RULES SET="MATH" DEFAULT="MARKUP">
        << math rules >>
    </RULES>
</MODE>
#@+node:ekr.20090615053403.4943: *6* << general rules >>
<!-- $$...$$ -->
<SPAN TYPE="MARKUP" DELEGATE="MATH">
    <BEGIN>$$</BEGIN>
    <END>$$</END>
</SPAN>

<!-- $...$ -->
<SPAN TYPE="MARKUP" DELEGATE="MATH">
    <BEGIN>$</BEGIN>
    <END>$</END>
</SPAN>

<!-- \[...\] (LaTeX math mode) -->
<SPAN TYPE="MARKUP" DELEGATE="MATH">
    <BEGIN>\[</BEGIN>
    <END>\]</END>
</SPAN>

<!-- some commands must be handled specially -->
<SEQ TYPE="KEYWORD1">\$</SEQ>
<SEQ TYPE="KEYWORD1">\\</SEQ>
<SEQ TYPE="KEYWORD1">\%</SEQ>

<!-- \... commands -->
<MARK_FOLLOWING TYPE="KEYWORD1">\</MARK_FOLLOWING>

<!-- comments -->
<EOL_SPAN TYPE="COMMENT1">%</EOL_SPAN>

<!-- word separators -->
<SEQ TYPE="OPERATOR">{</SEQ>
<SEQ TYPE="OPERATOR">}</SEQ>
<SEQ TYPE="OPERATOR">[</SEQ>
<SEQ TYPE="OPERATOR">]</SEQ>
#@+node:ekr.20090615053403.4944: *6* << math rules >>
<!-- some commands must be handled specially -->
<SEQ TYPE="KEYWORD3">\$</SEQ>
<SEQ TYPE="KEYWORD3">\\</SEQ>
<SEQ TYPE="KEYWORD3">\%</SEQ>

<!-- \... commands -->
<MARK_FOLLOWING TYPE="KEYWORD3">\</MARK_FOLLOWING>

<!-- word separators -->
<SEQ TYPE="KEYWORD2">)</SEQ>
<SEQ TYPE="KEYWORD2">(</SEQ>
<SEQ TYPE="KEYWORD2">{</SEQ>
<SEQ TYPE="KEYWORD2">}</SEQ>
<SEQ TYPE="KEYWORD2">[</SEQ>
<SEQ TYPE="KEYWORD2">]</SEQ>
<SEQ TYPE="KEYWORD2">=</SEQ>
<SEQ TYPE="KEYWORD2">!</SEQ>
<SEQ TYPE="KEYWORD2">+</SEQ>
<SEQ TYPE="KEYWORD2">-</SEQ>
<SEQ TYPE="KEYWORD2">/</SEQ>
<SEQ TYPE="KEYWORD2">*</SEQ>
<SEQ TYPE="KEYWORD2">&gt;</SEQ>
<SEQ TYPE="KEYWORD2">&lt;</SEQ>
<SEQ TYPE="KEYWORD2">&amp;</SEQ>
<SEQ TYPE="KEYWORD2">|</SEQ>
<SEQ TYPE="KEYWORD2">^</SEQ>
<SEQ TYPE="KEYWORD2">~</SEQ>
<SEQ TYPE="KEYWORD2">.</SEQ>
<SEQ TYPE="KEYWORD2">,</SEQ>
<SEQ TYPE="KEYWORD2">;</SEQ>
<SEQ TYPE="KEYWORD2">?</SEQ>
<SEQ TYPE="KEYWORD2">:</SEQ>
<SEQ TYPE="KEYWORD2">'</SEQ>
<SEQ TYPE="KEYWORD2">"</SEQ>
<SEQ TYPE="KEYWORD2">`</SEQ>

<!-- comments -->
<EOL_SPAN TYPE="COMMENT1">%</EOL_SPAN>
#@+node:ekr.20090615053403.4945: *4* @test colorizer wikiTest1
p = c.p.firstChild()
c.selectPosition(p) # Sets body text.
# val = c.frame.body.colorizer.colorize(p,incremental=False)
# assert val=="ok", "colorizer test failed: %s" % p.h
#@+node:ekr.20090615053403.4946: *5* wiki
# both color_markup & add_directives plugins must be enabled.

@markup wiki
@language python

""" {picture file=../Icons/Leoapp.GIF}this """ # Problems with correct indexing following a graphic.

""" {picture file=../Icons/Leoapp.GIF}this """ # two copies work.

abc

""" {picture file=../Icons/Leodoc.GIF} """ # xyz

""" continued
string"""

@ ''ab'' __xxx__ ''wx'' __xyz__
@c

# /* ''ab'' __xxx__ ''wx'' __xyz__ */

# Test

""" ''' """ ''' """'''  # Leo handles the common cases correctly.

''' ''ab'' __xxx__ ''wx'' __xyz__ ''' # No wiki markup in ''' strings.

""" ''ab'' __xxx__ ''wx'' __xyz__ """

# ''ab'' __xxx__ ''wx'' __xyz__

""" ''y'' """

""" text~~#ff00ff:some text~~more text"""

if 1 and 2:
    pass

print(g.app().loadDir)
#@+node:ekr.20090615053403.4947: *4* @test colorizer wikiTest2
p = c.p.firstChild()
c.selectPosition(p) # Sets body text.
# val = c.frame.body.colorizer.colorize(p,incremental=False)
# assert val=="ok", "colorizer test failed: %s" % p.h
#@+node:ekr.20090615053403.4948: *5* wiki
# both color_markup & add_directives plugins must be enabled.
@markup wiki

""" continued
string"""

@ ''ab'' __xxx__ ''wx'' __xyz__  __''bolditalic''__ and ''__italicbold__''
@c

# /* ''ab'' __xxx__ ''wx'' __xyz__ */

__abc__ 

# Test

""" ''' """ ''' """'''  # Leo handles the __b__ common cases correctly.

''' ''ab'' __xxx__ ''wx'' __xyz__ ''' # No wiki markup in ''' strings.

""" ''ab'' __xxx__ ''wx'' __xyz__ """

# ''ab'' __xxx__ ''wx'' __xyz__

""" ''y'' """

""" text~~#ee00ff:some text~~more text"""


if 1 and 2:
    pass

print(g.app().loadDir)
#@+node:ekr.20090615053403.4949: *4* @test colorizer wikiTest3
p = c.p.firstChild()
c.selectPosition(p) # Sets body text.
# val = c.frame.body.colorizer.colorize(p,incremental=False)
# assert val=="ok", "colorizer test failed: %s" % p.h
#@+node:ekr.20090615053403.4950: *5* wiki
# both color_markup & add_directives plugins must be enabled.

@markup wiki

""" text~~red:some text~~more text"""

""" text~~#ee0ff:some text~~more text"""

if 1 and 2:
    pass
#@+node:ekr.20090615053403.4951: *4* @test leoColor.doNowebSecRef
<< test defined >>
#@+node:ekr.20090615053403.4952: *5* << test defined >>
pass
#@+node:ekr.20090615053403.4953: *4* @test python keywords (new colorizer)
try:
    mode = c.frame.body.colorizer.modes.get('python')
    mode.keywords['as'] = 1 # append the keyword, colorize with 'keyword1' tag.
except AttributeError:
    pass # modes only exists for new colorizer.
#@+node:ekr.20090615053403.4954: *4* @test scanColorDirectives
# This will work regardless of where this method is.
@language python

language = g.findLanguageDirectives(c,p)
assert language == 'python','got:%s' % language
#@+node:ekr.20090615053403.4955: *4* @test vbscript
p = c.p.firstChild()
c.selectPosition(p) # Sets body text.
# val = c.frame.body.colorizer.colorize(p,incremental=False)
# assert val=="ok", "colorizer test failed: %s" % p.h
#@+node:ekr.20090615053403.4956: *5* vbscript
@language vbscript

if
IF
#@+node:ekr.20090615053403.4957: *4* @test zz end of leoColor tests
# This is **not** a real unit test.
# It simply restores the screen to a more convenient state.

# c.contractParent()
# g.app.unitTestDict['restoreSelectedNode']=False

print('\nEnd of leoColor tests')
#@+node:ekr.20071113193624: *3* leoCommands
# 7 failures with Alt-5
#@+node:ekr.20090104053806.1: *4* @@@test c.checkFileTimeStamp & c.setFileTimeStamp
# Disabled because modifying errorTest.py creates annoying bzr conflicts.

import os

path = g.os_path_finalize_join(g.app.testDir,'unittest','errorTest.py')
assert g.os_path_exists(path),path
timeStamp = c.timeStampDict.get(path)
val = c.checkFileTimeStamp(path)
assert val == True

f = open(path)
s = f.read()
lines = g.splitLines(s)
result = [] ; found = False
tag = '# timestamp:'
for line in lines:
    if line.startswith(tag):
        timeStamp = os.path.getmtime(path)
        result.append('%s %s\n' % (tag,timeStamp))
        found = True
    else:
        result.append(line)
f.close()

assert found,' no line starts with "%s"' % tag

f = open(path,'w')
f.write(''.join(result))
f.close()

timeStamp2 = os.path.getmtime(path)
assert timeStamp != timeStamp2
val = c.checkFileTimeStamp(path)
assert not val,repr(val)
c.setFileTimeStamp(path)
val = c.checkFileTimeStamp(path)
assert val,repr(val)
#@+node:ekr.20100203103015.5356: *4* @@@test c.openTempFileInExternalEditor
arg = ''
arg0 = 'one'
fn = '<fn>'
filename = '' # g.os.path.basename(arg)
vtuple = [arg0,fn]

table = (
    #('os.system',       'os.system(%s)' % (arg+fn)),
    #('os.startfile',    'os.startfile(%s)' % (arg+fn)),
    #('exec',            'exec(%s)' % (arg+fn)),
    #('os.spawnl',       'os.spawnl(%s,%s,%s)' % (arg,filename,fn)),
    #('os.spawnv',       'os.spawnv(%s,%s)' % (arg0,vtuple)),
    ('subprocess.Popen','subprocess.Popen(%s)' % vtuple),
    ('huh?',            'bad command:'+'huh?'),
)

for openType,result in table:
    if openType in ('os.spawnv','subprocess.Popen'):
        arg2 = ['one']
    else:
        arg2 = None
    result2 = c.openTempFileInExternalEditor(
        arg2,fn,openType,testing=True)
    assert result==result2,'expected %s, got %s' % (
        repr(result),repr(result2))
#@+node:ekr.20100209155559.5386: *4* @@@test efc.create_temp_file
efc = g.app.externalFilesController
d = {'ext':'.py',}
fn = efc.create_temp_file(c,d,p)
assert g.os_path_exists(fn),fn
efc.shut_down()
assert not g.os_path_exists(fn),fn
#@+node:ekr.20120309155126.3949: *4* @test add/delete comments with multiple @language directives
# Can't be run externally.
w = c.frame.body.wrapper
p = g.findNodeInTree(c,p,'rest and python')
assert p,'no test node'
s = p.b
indent = c.config.getBool('indent_added_comments',default=True)

try:
    i = p.b.find('pass')
    assert i > -1,'fail1: %s' % (repr(p.b))
    c.selectPosition(p)
    w.setSelectionRange(i,i+4)
    c.addComments()
    if indent:
        i = p.b.find('# pass')
    else:
        i = p.b.find('#     pass')
    assert i > -1,'fail2: %s' % (repr(p.b))
    c.deleteComments()
    assert p.b == s,'fail3: %s' % (repr(p.b))
    # Add a comment delim without a blank.
    c.addComments()
    p.b = p.b.replace('# pass','#pass')
    i = p.b.find('#')
    w.setSelectionRange(i,i+4)
    c.deleteComments()
    assert p.b == s,'fail5: s\n%s\nresult\n%s' % (repr(s),repr(p.b))
finally:
    # print('\n'.join([repr(z) for z in g.splitLines(p.b)]))
    p.b = s
#@+node:ekr.20120309155126.3950: *5* rest and python
@language rest

This is rest text.

@language python

def spam():
    pass

# after
#@+node:ekr.20111112171235.3854: *4* @test add/delete html comments
w = c.frame.body.wrapper
p = g.findNodeInTree(c,p,'html')
assert p,'no test node'
s = p.b
indent = c.config.getBool('indent_added_comments',default=True)
try:
    i = p.b.find('text')
    assert i > -1,'fail1: %s' % (repr(p.b))
    c.selectPosition(p)
    w.setSelectionRange(i,i+4)
    c.addComments()
    if indent:
        i = p.b.find('<!-- text')
    else:
        i = p.b.find('<!--     text')
    assert i > -1,'fail2: %s' % (repr(p.b))
    c.deleteComments()
    assert p.b == s,'fail3: s\n%s\nresult\n%s' % (repr(s),repr(p.b))
    # Add a comment delim without a blank.
    c.addComments()
    p.b = p.b.replace('<!-- ','<!--')
    i = p.b.find('<!--')
    w.setSelectionRange(i,i+4)
    c.deleteComments()
    assert p.b == s,'fail5: s\n%s\nresult\n%s' % (repr(s),repr(p.b))
finally:
    # print('\n'.join([repr(z) for z in g.splitLines(p.b)]))
    p.b = s
#@+node:ekr.20170128023431.1: *5* @language html
@language html
#@+node:ekr.20111112171235.3855: *6* html
@language html
<html>
    text 
</html>
#@+node:ekr.20111112171235.3858: *4* @test add/delete python comments
# Can't be run externally.
w = c.frame.body.wrapper
p = g.findNodeInTree(c,p,'python')
assert p,'no test node'
s = p.b
indent = c.config.getBool('indent_added_comments',default=True)

try:
    i = p.b.find('pass')
    assert i > -1,'fail1: %s' % (repr(p.b))
    c.selectPosition(p)
    w.setSelectionRange(i,i+4)
    c.addComments()
    if indent:
        i = p.b.find('# pass')
    else:
        i = p.b.find('#     pass')
    assert i > -1,'fail2: %s' % (repr(p.b))
    c.deleteComments()
    assert p.b == s,'fail3: %s' % (repr(p.b))
    # Add a comment delim without a blank.
    c.addComments()
    p.b = p.b.replace('# pass','#pass')
    i = p.b.find('#')
    w.setSelectionRange(i,i+4)
    c.deleteComments()
    assert p.b == s,'fail5: s\n%s\nresult\n%s' % (repr(s),repr(p.b))
finally:
    # print('\n'.join([repr(z) for z in g.splitLines(p.b)]))
    p.b = s
#@+node:ekr.20111112171235.3859: *5* python
@language python

def spam():
    pass

# after
#@+node:ekr.20110510054817.3475: *4* @test c.alert
c.alert('test of c.alert')
#@+node:ekr.20050512084850: *4* @test c.checkOutline
errors = c.checkOutline()
assert errors == 0, "Check Outline reported %d errors" % errors
#@+node:ekr.20040713070526: *5* Scripts
@language python 

dump = False 
all = False 

tm = c.testManager

if all:
    c.prettyPrintAllPythonCode(dump=dump)
else:
    # Warning: at present the before and after text is unprotected:
    # Running Pretty Print on these nodes will negate the value of the test.
    temp = tm.findNodeInTree(p,"tempNode")
    c.setBodyString(temp,"")
    before = tm.findNodeInTree(p,"before")
    after = tm.findNodeInTree(p,"after")
    temp.scriptSetBodyString(before.b)
    c.prettyPrintPythonCode(p=temp,dump=dump)
    assert temp.b == after.b,"Pretty Print Test failed"
#@+node:ekr.20040713123617: *6* tempNode
@ This is a test of stuff.in doc parts.

         I wonder what will happen.
@c

def spam (self):

    """ This is a ' triple'   quoted string:
        It should remain untouched."""

    if a == 3:
        g.pr("Ä á Û")

    ''' Another ' triple'   quoted string:
        It should remain untouched.'''

    "yet another\
    multi-line string"

class eggs:

    """ A typical doc string """

    @others
#@+node:ekr.20050726141158: *6* before
@ This is    a test of stuff.in doc parts.

         I wonder           what will happen.
@c

def        spam (self         )  :   

    """ This is a ' triple'   quoted string:
        It should remain untouched."""

    if a==3:
        g.pr("Ä á Û")

    ''' Another ' triple'   quoted string:
        It should remain untouched.'''

    "yet another\
    multi-line string"

class eggs:

    """ A typical doc string """

    @others
#@+node:ekr.20040713123828.1: *6* after
@ This is a test of stuff.in doc parts.

         I wonder what will happen.
@c

def spam (self):

    """ This is a ' triple'   quoted string:
        It should remain untouched."""

    if a == 3:
        g.pr("Ä á Û")

    ''' Another ' triple'   quoted string:
        It should remain untouched.'''

    "yet another\
    multi-line string"

class eggs:

    """ A typical doc string """

    @others
#@+node:ekr.20071113145804.10: *4* @test c.contractAllHeadlines
c.contractAllHeadlines()
p = c.rootPosition()
while p.hasNext():
    p.moveToNext()
c.selectPosition(p)
#@+node:ekr.20070611105423.1: *4* @test c.contractAllHeadlines
c.contractAllHeadlines()
#@+node:ekr.20070611105728: *4* @test c.demote: illegal clone demote
# Remove any previous children.
while p.hasChildren():
    p.firstChild().doDelete()
# Create two cloned children.
c.selectPosition(p)
c.insertHeadline()
p2 = c.p
p2.moveToFirstChildOf(p)
p2.setHeadString('aClone')
c.selectPosition(p2)
c.clone()
assert 2 == p.numberOfChildren()

# Select the first clone and demote (it should be illegal)
c.selectPosition(p2)
c.demote() # This should do nothing.
assert g.app.unitTestDict.get('checkMoveWithParentWithWarning'),'fail 1'
assert 0 == c.checkOutline(), 'fail 2'
assert 2 == p.numberOfChildren(), 'fail 3'
# Delete the children, but only if there are no errors.
while p.hasChildren():
    p.firstChild().doDelete()
#@+node:ekr.20111121140833.3916: *4* @test c.findMatchingBracket
w = c.frame.body.wrapper
s = w.getAllText()
i = s.find('(')
w.setInsertPoint(i)
c.findMatchingBracket(event=None)
i,j = w.getSelectionRange()
assert i < j,'i: %s j: %s' % (i,j)
#@+node:ekr.20141016101308.4747: *4* @test c.hiddenRootNode.fileIndex
assert c.hiddenRootNode.fileIndex.startswith('hidden-root-vnode-gnx'), c.hiddenRootNode.fileIndex
#@+node:ekr.20120310121839.3949: *4* @test c.hoist @chapter node
# Not valid when run externally: the chapter node will not exist.
if not g.app.isExternalUnitTest:

    p1 = g.findNodeAnywhere(c,'@chapter aaa')
    assert p1
    p2 = g.findNodeAnywhere(c,'aaa node 1')
    assert p2
    try:
        # g.es_print('**1**', c.hoistStack)
        assert not c.hoistStack, ('fail1', c.hoistStack)
        c.selectPosition(p1)
        assert c.p == p1, ('fail2', c.p, p1)
        c.hoist()
            # New in Leo 5.3: should do nothing
        assert c.p == p1, ('fail3', c.p, p1)
        # assert c.p == p2, ('fail3', c.p, p2)
        c.dehoist()
            # New in Leo 5.3: should do nothing:
        assert c.p == p1, ('fail3', c.p, p1)
        # assert c.p == p2, 'fail4\n%s\n%s' % (c.p, p2)
        assert c.hoistStack == [], ('fail5', c.hoistStack)
    finally:
        c.hoistStack = []
        c.selectPosition(p)
        c.redraw()
else:
    self.skipTest('Can not be run locally')
#@+node:ekr.20120311124038.3951: *4* @test c.hoist followed by goto-first-node
p1 = p.copy()
try:
    assert not c.hoistStack
    c.selectPosition(p1)
    assert c.p == p1
    c.hoist()
    c.goToFirstNode()
    assert not c.hoistStack
        # The hoist stack must be cleared to show the first node.
    assert c.p == c.rootPosition()
    assert c.p.isVisible(c)
finally:
    c.selectPosition(p1)
    c.redraw()
#@+node:ekr.20071113105654.1: *4* @test c.hoist with no children
c.hoist()
c.dehoist()
#@+node:ekr.20061106112522: *4* @test c.insertBodyTime
w = c.frame.body.wrapper
s = w.getAllText()

try:
    w.setInsertPoint(len(s))
    c.insertBodyTime()
finally:
    w.setAllText(s)
    p.setBodyString(s)
    # c.recolor()

# end:
#@+node:ekr.20050512083807.1: *4* @test c.markAllAtFileNodesDirty
marks = [p.v for p in c.all_positions() if p.isMarked()]
try:
    ok = True
    try:
        c.markAllAtFileNodesDirty()
    except Exception:
        ok = False
finally:
    for p in c.all_positions():
        if p.v in marks:
            if not p.isMarked():
                c.setMarked(p)
        else:
            if p.isMarked():
                c.clearMarked(p)

if not ok: raise
#@+node:ekr.20050512083822.1: *4* @test c.markSubheads
marks = [p.v for p in c.all_positions() if p.isMarked()]
try:
    ok = True
    try:
        c.markSubheads()
    except Exception:
        ok = False
finally:
    for p in c.all_positions():
        if p.v in marks:
            if not p.isMarked():
                c.setMarked(p)
        else:
            if p.isMarked():
                c.clearMarked(p)

if not ok: raise
#@+node:ekr.20050512084850.1: *5* child 1
pass
#@+node:ekr.20050512084850.2: *5* child 2
pass
#@+node:ekr.20111212142649.3971: *4* @test c.pasteOutline does not clone top node
import sys
# g.openWithFileName *always* opens the file.
if g.isPython3 and sys.platform.startswith('linux'):
    # There is a PyQt issue: https://bugreports.qt.io/browse/QTBUG-35600
    # The crash causes several other unit tests to fail.
    pass
else:
    c.selectPosition(p)
    c.copyOutline()
    try:
        p2 = c.pasteOutline()
        assert p2
        assert not p2.isCloned()
    finally:
        if p2: p2.doDelete()
        c.redraw(p)
#@+node:ekr.20111212142649.3972: *5* child
# child text.
#@+node:ekr.20080917151620.9: *4* @test c.scanAllDirectives
@language python
@comment a b c
    # @comment must follow @language
@tabwidth -4
@pagewidth 72
@encoding utf-8
@lineending crlf

d = c.scanAllDirectives(p)
# print(g.dictToString(d))

table = (
    ('delims', ('a','b','c'),),
    ('encoding','utf-8'),
    ('language','python'),
    ('lineending','\r\n'),
    ('pagewidth',72),
    ('tabwidth',-4),
)

for kind,expected in table:
    got = d.get(kind)
    assert got == expected, 'kind: %s, expected %s, got %s' % (
        kind,repr(expected),repr(got))
#@+node:ekr.20100131180007.5466: *4* @test c.scanAtPathDirectives
p2 = p.firstChild().firstChild().firstChild()

aList = g.get_directives_dict_list(p2)
path = c.scanAtPathDirectives(aList)
# print (path,p2.h)
endpath = g.os_path_normpath('one/two')
assert path and path.endswith(endpath),'expected ending %s got %s' % (
    endpath,path)
#@+node:ekr.20100131180007.5467: *5* @path one
#@+node:ekr.20100131180007.5468: *6* @path two
#@+node:ekr.20100131180007.5469: *7* xyz
#@+node:sps.20100531034136.20110: *4* @test c.scanAtPathDirectives same name subdirs
p2 = p.firstChild().firstChild().firstChild()

aList = g.get_directives_dict_list(p2)
path = c.scanAtPathDirectives(aList)
# print (path,p2.h)
endpath = g.os_path_normpath('again/again')
assert path and path.endswith(endpath),'expected ending %s got %s' % (
    endpath,path)
#@+node:sps.20100531034136.20111: *5* @path again
#@+node:sps.20100531034136.20112: *6* @path again
#@+node:sps.20100531034136.20113: *7* xyz
#@+node:ekr.20040802065214: *4* @test c.setHeadString marks descendent @thin nodes dirty
# Make sure that changing this headline marks descendant @thin nodes dirty.
h = p.h

try:
    child = p.firstChild()
    child.initHeadString("@thin bogus")
    assert child.h == "@thin bogus", "setting headline failed"
    child.clearDirty()
    assert not child.isDirty(), "clearing dirty failed"
    c.setHeadString(p,"changed")
    assert child.isDirty(), "setting descendant @thin nodes dirty failed."
finally:
    try:
        c.setHeadString(p,h)
        c.setHeadString(child,"bogus")
        p.clearDirty()
        child.clearDirty()
    finally: pass

#### c.redraw()
#@+node:ekr.20040802065214.1: *5* bogus
test
#@+node:ekr.20050512083822.2: *4* @test c.unmarkAll
marks = [p.v for p in c.all_positions() if p.isMarked()]
try:
    ok = True
    try:
        c.unmarkAll()
    except Exception:
        ok = False
finally:
    for p in c.all_positions():
        if p.v in marks:
            if not p.isMarked():
                c.setMarked(p)
        else:
            if p.isMarked():
                c.clearMarked(p)

if not ok: raise
#@+node:ekr.20100131180007.5465: *4* @test class StubConfig
class StubConfig(g.nullObject):
    pass

x = StubConfig()
assert not x.getBool(c,'mySetting')
assert not x.enabledPluginsFileName
#@+node:ekr.20100203103015.5353: *4* @test efc.ask
# Not a perfect test, but stil significant.
efc = g.app.externalFilesController
result = efc.ask(c,p.h)
assert result in (True, False),result
#@+node:ekr.20100203103015.5355: *4* @test efc.get_ext
@language python

efc = g.app.externalFilesController

table = (
    # (None,'.py'),
    # ('','.py'),
    ('txt','.txt'),
    ('.txt','.txt'),
)

for ext,result in table:
    result2 = efc.get_ext(c,p,ext)
    assert result==result2,'ext: %s, expected %s, got %s' % (
        repr(ext),repr(result),repr(result2))
#@+node:ekr.20100203103015.5354: *4* @test efc.temp_file_path
efc = g.app.externalFilesController
s = efc.temp_file_path(c,p,'.py')
assert s.endswith('.py')
#@+node:ville.20090602190735.4770: *4* @test g.command decorator
_foo = 0

@g.command('my-test-command')
def mytestcommand(event):
    global _foo
    _foo = 1

try:
    c.k.simulateCommand('my-test-command')
    assert _foo == 1
    
    # bonus test: c.app.commanders()
    assert c in g.app.commanders()

except AttributeError:
    # Raised only for unit testing.
    pass
#@+node:ekr.20100203103015.5357: *4* @test g.isCallable
def spam(): pass
lam = lambda a: None
class aCallable:
    def __call__ (self):
        pass
c = aCallable()

table = (
    ('abc',False),
    (spam,True),
    (lam,True),
    (c,True)
)

for obj,val in table:
    val2 = g.isCallable(obj)
    assert val == val2,'%s, expected %s, got %s' % (
        repr(obj),val,val2)
#@+node:ekr.20071113201833: *4* @test zz end of leoCommands tests
# This is **not** a real unit test.
# It simply restores the screen to a more convenient state.

# c.contractParent()
# g.app.unitTestDict['restoreSelectedNode']=False

print('\nEnd of leoCommands tests')
#@+node:ekr.20071113194216: *3* leoConfig
# 3 failurs with Alt-5
#@+node:ekr.20120201125738.3958: *4* @@@test g.app.config.getShortcuts works when no local shortcuts
# This tests is valid only if not g.new_config.

sd = g.app.config.localShortcutsDict
d = sd.get(c.hash(),{})
try:
    sd[c.hash()] = {}
    key,aList = c.config.getShortcut('new')
    # print(key,aList)
    assert aList,'key: %s' % (key)
finally:
    sd[c.hash()] = d
#@+node:ekr.20060325071703.2: *4* @@@test ifgui
guiname = g.app.gui.guiName()

tkinter = c.config.getBool('test_tkinter_setting')
wx      = c.config.getBool('test_wxWindows_setting')

print(guiname)

if guiname == 'tkinter':
    assert(tkinter)
    assert(not wx)

if guiname == 'wxWindows':
    assert(not tkinter)
    assert(wx)
#@+node:ekr.20111115071700.3870: *4* @test c.config.printSettings
c.config.printSettings()

#@+node:ekr.20120201101804.3907: *4* @test c.config.updateSetting with no @settings node
import leo.core.leoConfig as leoConfig
    
p = c.config.settingsRoot()
assert c
if p:
    # p will not exist when run externally.
    h = p.h
    p.h = '@@' + h
try:
    parser = leoConfig.SettingsTreeParser(c,localFlag=True)
    d1,d2 = parser.traverse()
    assert isinstance(d1,g.TypedDictOfLists),d1
    assert isinstance(d2,g.TypedDict),d2
finally:
    if p:
        p.h = h
        c.redraw()
#@+node:ekr.20111124090010.3939: *4* @test g.app.config @buttons and @commands logic
'''Test that the config parser visits @buttons and @commands nodes for
leoSettings.leo and unitTest.leo.

If strict is True, also test that the config parser vists the nodes in
myLeoSettings.leo. This may fail on machines without @buttons and @commands
nodes in myLeoSettings.leo.
'''

if g.app.isExternalUnitTest:
    self.skipTest('Can not be run externally')
else:
    strict = True # Set to False if you are not EKR.
    
    table = ['leoSettings.leo','unitTest.leo']
    if strict:
        table.append('myLeoSettings.leo')
    
    keys = ('config.doButtons-file-names','config.doCommands-file-names')
    d = g.app.config.unitTestDict # Always created for this unit test.
    
    for key in keys:
        aList = d.get(key,[])
        for fn in table:
            # print(fn)
            # print(repr(aList))
            assert fn in aList,'%s not in unitTestDict[%s]' % (fn,key)
#@+node:ekr.20050203084930.1: *4* @test g.app.config.get
w = g.app.config.get('global_setting_for_unit_tests','int')

assert w in (None,132) # Will be None when tests run dynamically.
#@+node:ekr.20111105124216.3840: *4* @test g.app.config.set
setting = 'import_html_tags'
html_tags = ('body','head','html','table','xxx')

# When run externally, c.config.getData will return None.
existing_tags = c.config.getData(setting)
if not existing_tags:
    g.app.config.set(None,setting,'data',html_tags)
    tags = c.config.getData(setting)
    assert c.config.getData(setting) == html_tags
#@+node:ekr.20060325071703.1: *4* @test ifplatform
import sys

win32  = c.config.getBool('test_win32_setting')
darwin = c.config.getBool('test_darwin_setting')

if sys.platform == 'win32':
    assert(win32)
    assert(not darwin)

elif sys.platform== 'darwin':
    assert(not win32)
    assert(darwin)

#@+node:ekr.20050203001146: *4* @test local settings (c.page_width)
assert c.page_width == c.config.getInt('page_width'),c.page_width
#@+node:ekr.20071113201854: *4* @test zz end of leoConfig tests
# This is **not** a real unit test.
# It simply restores the screen to a more convenient state.

# c.contractParent()
# g.app.unitTestDict['restoreSelectedNode']=False

print('\nEnd of leoConfig tests')
#@+node:ekr.20100131171342.5592: *3* leoDialogs
#@+node:ekr.20100131171342.5593: *4* @test ctors for all dialogs
# For some reason these don't select the dialog properly when run as a script.
# However, the main reason for the tests is to make sure the ctors don't crash.
# Also, for unit testing the value of c doesn't matter.

oldGui = g.app.gui ; guis = [g.app.gui]

import leo.core.leoGui as leoGui
guis.append(leoGui.UnitTestGui())

for gui in guis:
    gui.runAboutLeoDialog(c,'version','copyright','url','email')
    gui.runAskLeoIDDialog()
    gui.runAskOkDialog(c,'title','message')
    gui.runAskOkCancelNumberDialog(c,'title','message')
    gui.runAskOkCancelStringDialog(c,'title','message')
    gui.runAskYesNoDialog(c,'title','message')
    gui.runAskYesNoCancelDialog(c,'title','message')
    # gui.runCompareDialog(c) # Removed.

g.app.gui = oldGui
#@+node:ekr.20071113192611: *3* leoEditCommands
#@+node:ekr.20070131175538: *4*  Commands A-B
#@+node:ekr.20061101121602.78: *5* @test add-space-to-lines
c.testManager.runEditCommandTest(p)
#@+node:ekr.20061101121602.79: *6* work
first line
 line 1
     line a
 line b
last line
#@+node:ekr.20061101121602.80: *6* before sel=2.0,4.6
first line
line 1
    line a
line b
last line
#@+node:ekr.20061101121602.81: *6* after sel=2.0,4.7
first line
 line 1
     line a
 line b
last line
#@+node:ekr.20061101121602.82: *5* @test add-tab-to-lines
c.testManager.runEditCommandTest(p)
#@+node:ekr.20061101121602.83: *6* work
first line
    line 1
        line a
            line b
    line c
last line
#@+node:ekr.20061101121602.84: *6* before sel=2.0,5.6
first line
line 1
    line a
        line b
line c
last line
#@+node:ekr.20061101121602.85: *6* after sel=2.0,5.10
first line
    line 1
        line a
            line b
    line c
last line
#@+node:ekr.20071113145804.16: *5* @test helpForbindings
# vr plugin not loaded externally.
if g.app.isExternalUnitTest:
    self.skipTest('Can not be run externally')
else:
    c.helpCommands.helpForBindings()
#@+node:ekr.20071113145804.17: *5* @test helpForFindCommands
# vr plugin not loaded externally.
if g.app.isExternalUnitTest:
    self.skipTest('Can not be run externally')
else:
    c.helpCommands.helpForFindCommands()
#@+node:ekr.20061101121602.86: *5* @test back-char
c.testManager.runEditCommandTest(p)
#@+node:ekr.20061101121602.87: *6* work
first line
line 1
    line a
        line b
line c
last line
#@+node:ekr.20061101121602.88: *6* before sel=3.8,3.8
first line
line 1
    line a
        line b
line c
last line
#@+node:ekr.20061101121602.89: *6* after sel=3.7,3.7
first line
line 1
    line a
        line b
line c
last line
#@+node:ekr.20061101121602.90: *5* @test back-char-extend-selection
c.testManager.runEditCommandTest(p)
#@+node:ekr.20061101121602.91: *6* work
first line
line 1
    line a
        line b
line c
last line
#@+node:ekr.20061101121602.92: *6* before sel=4.12,4.12
first line
line 1
    line a
        line b
line c
last line
#@+node:ekr.20061101121602.93: *6* after sel=4.11,4.12
first line
line 1
    line a
        line b
line c
last line
#@+node:ekr.20061101121602.94: *5* @test back-paragraph
c.testManager.runEditCommandTest(p)
#@+node:ekr.20061101121602.95: *6* work
Americans live in the most severe weather-prone country on Earth. Each year,
Americans cope with an average of 10,000 thunderstorms, 2,500 floods, 1,000
tornadoes, as well as an average of 6 deadly hurricanes. Potentially deadly
weather impacts every American. Communities can now rely on the National Weather
Service’s StormReady program to help them guard against the ravages of Mother
Nature.

Some 90% of all presidentially declared disasters are weather related, leading
to around 500 deaths per year and nearly $14 billion in damage. StormReady, a
program started in 1999 in Tulsa, OK, helps arm America's communities with the
communication and safety skills needed to save lives and property– before and
during the event. StormReady helps community leaders and emergency managers
strengthen local safety programs.

StormReady communities are better prepared to save lives from the onslaught of
severe weather through better planning, education, and awareness. No community
is storm proof, but StormReady can help communities save lives. Does StormReady
make a difference?
#@+node:ekr.20061101121602.96: *6* before sel=9.0,9.0
Americans live in the most severe weather-prone country on Earth. Each year,
Americans cope with an average of 10,000 thunderstorms, 2,500 floods, 1,000
tornadoes, as well as an average of 6 deadly hurricanes. Potentially deadly
weather impacts every American. Communities can now rely on the National Weather
Service’s StormReady program to help them guard against the ravages of Mother
Nature.

Some 90% of all presidentially declared disasters are weather related, leading
to around 500 deaths per year and nearly $14 billion in damage. StormReady, a
program started in 1999 in Tulsa, OK, helps arm America's communities with the
communication and safety skills needed to save lives and property– before and
during the event. StormReady helps community leaders and emergency managers
strengthen local safety programs.

StormReady communities are better prepared to save lives from the onslaught of
severe weather through better planning, education, and awareness. No community
is storm proof, but StormReady can help communities save lives. Does StormReady
make a difference?
#@+node:ekr.20061101121602.97: *6* after sel=6.7,6.7
Americans live in the most severe weather-prone country on Earth. Each year,
Americans cope with an average of 10,000 thunderstorms, 2,500 floods, 1,000
tornadoes, as well as an average of 6 deadly hurricanes. Potentially deadly
weather impacts every American. Communities can now rely on the National Weather
Service’s StormReady program to help them guard against the ravages of Mother
Nature.

Some 90% of all presidentially declared disasters are weather related, leading
to around 500 deaths per year and nearly $14 billion in damage. StormReady, a
program started in 1999 in Tulsa, OK, helps arm America's communities with the
communication and safety skills needed to save lives and property– before and
during the event. StormReady helps community leaders and emergency managers
strengthen local safety programs.

StormReady communities are better prepared to save lives from the onslaught of
severe weather through better planning, education, and awareness. No community
is storm proof, but StormReady can help communities save lives. Does StormReady
make a difference?
#@+node:ekr.20061101121602.98: *5* @test back-paragraph-extend-selection
c.testManager.runEditCommandTest(p)
#@+node:ekr.20061101121602.99: *6* work
Americans live in the most severe weather-prone country on Earth. Each year,
Americans cope with an average of 10,000 thunderstorms, 2,500 floods, 1,000
tornadoes, as well as an average of 6 deadly hurricanes. Potentially deadly
weather impacts every American. Communities can now rely on the National Weather
Service’s StormReady program to help them guard against the ravages of Mother
Nature.

Some 90% of all presidentially declared disasters are weather related, leading
to around 500 deaths per year and nearly $14 billion in damage. StormReady, a
program started in 1999 in Tulsa, OK, helps arm America's communities with the
communication and safety skills needed to save lives and property– before and
during the event. StormReady helps community leaders and emergency managers
strengthen local safety programs.

StormReady communities are better prepared to save lives from the onslaught of
severe weather through better planning, education, and awareness. No community
is storm proof, but StormReady can help communities save lives. Does StormReady
make a difference?
#@+node:ekr.20061101121602.100: *6* before sel=9.0,9.5
Americans live in the most severe weather-prone country on Earth. Each year,
Americans cope with an average of 10,000 thunderstorms, 2,500 floods, 1,000
tornadoes, as well as an average of 6 deadly hurricanes. Potentially deadly
weather impacts every American. Communities can now rely on the National Weather
Service’s StormReady program to help them guard against the ravages of Mother
Nature.

Some 90% of all presidentially declared disasters are weather related, leading
to around 500 deaths per year and nearly $14 billion in damage. StormReady, a
program started in 1999 in Tulsa, OK, helps arm America's communities with the
communication and safety skills needed to save lives and property– before and
during the event. StormReady helps community leaders and emergency managers
strengthen local safety programs.

StormReady communities are better prepared to save lives from the onslaught of
severe weather through better planning, education, and awareness. No community
is storm proof, but StormReady can help communities save lives. Does StormReady
make a difference?
#@+node:ekr.20061101121602.101: *6* after sel=6.7,9.5
Americans live in the most severe weather-prone country on Earth. Each year,
Americans cope with an average of 10,000 thunderstorms, 2,500 floods, 1,000
tornadoes, as well as an average of 6 deadly hurricanes. Potentially deadly
weather impacts every American. Communities can now rely on the National Weather
Service’s StormReady program to help them guard against the ravages of Mother
Nature.

Some 90% of all presidentially declared disasters are weather related, leading
to around 500 deaths per year and nearly $14 billion in damage. StormReady, a
program started in 1999 in Tulsa, OK, helps arm America's communities with the
communication and safety skills needed to save lives and property– before and
during the event. StormReady helps community leaders and emergency managers
strengthen local safety programs.

StormReady communities are better prepared to save lives from the onslaught of
severe weather through better planning, education, and awareness. No community
is storm proof, but StormReady can help communities save lives. Does StormReady
make a difference?
#@+node:ekr.20061101121602.102: *5* @test back-sentence
c.testManager.runEditCommandTest(p)
#@+node:ekr.20061101121602.103: *6* work
Americans live in the most severe weather-prone country on Earth. Each year, Americans cope with an average of 10,000 thunderstorms, 2,500 floods, 1,000 tornadoes, as well as an average of 6 deadly hurricanes. Potentially deadly weather impacts every American. Communities can now rely on the National Weather Service’s StormReady program to help them guard against the ravages of Mother Nature.

Some 90% of all presidentially declared disasters are weather related, leading to around 500 deaths per year and nearly $14 billion in damage. StormReady, a program started in 1999 in Tulsa, OK, helps arm America's communities with the communication and safety skills needed to save lives and property– before and during the event. StormReady helps community leaders and emergency managers strengthen local safety programs.

StormReady communities are better prepared to save lives from the onslaught of severe weather through better planning, education, and awareness. No community is storm proof, but StormReady can help communities save lives. Does StormReady make a difference?
#@+node:ekr.20061101121602.104: *6* before sel=3.169,3.169
Americans live in the most severe weather-prone country on Earth. Each year, Americans cope with an average of 10,000 thunderstorms, 2,500 floods, 1,000 tornadoes, as well as an average of 6 deadly hurricanes. Potentially deadly weather impacts every American. Communities can now rely on the National Weather Service’s StormReady program to help them guard against the ravages of Mother Nature.

Some 90% of all presidentially declared disasters are weather related, leading to around 500 deaths per year and nearly $14 billion in damage. StormReady, a program started in 1999 in Tulsa, OK, helps arm America's communities with the communication and safety skills needed to save lives and property– before and during the event. StormReady helps community leaders and emergency managers strengthen local safety programs.

StormReady communities are better prepared to save lives from the onslaught of severe weather through better planning, education, and awareness. No community is storm proof, but StormReady can help communities save lives. Does StormReady make a difference?
#@+node:ekr.20061101121602.105: *6* after sel=3.143,3.143
Americans live in the most severe weather-prone country on Earth. Each year, Americans cope with an average of 10,000 thunderstorms, 2,500 floods, 1,000 tornadoes, as well as an average of 6 deadly hurricanes. Potentially deadly weather impacts every American. Communities can now rely on the National Weather Service’s StormReady program to help them guard against the ravages of Mother Nature.

Some 90% of all presidentially declared disasters are weather related, leading to around 500 deaths per year and nearly $14 billion in damage. StormReady, a program started in 1999 in Tulsa, OK, helps arm America's communities with the communication and safety skills needed to save lives and property– before and during the event. StormReady helps community leaders and emergency managers strengthen local safety programs.

StormReady communities are better prepared to save lives from the onslaught of severe weather through better planning, education, and awareness. No community is storm proof, but StormReady can help communities save lives. Does StormReady make a difference?
#@+node:ekr.20061101121602.106: *5* @test back-sentence-extend-selection
c.testManager.runEditCommandTest(p)
#@+node:ekr.20061101121602.107: *6* work
Americans live in the most severe weather-prone country on Earth. Each year, Americans cope with an average of 10,000 thunderstorms, 2,500 floods, 1,000 tornadoes, as well as an average of 6 deadly hurricanes. Potentially deadly weather impacts every American. Communities can now rely on the National Weather Service’s StormReady program to help them guard against the ravages of Mother Nature.

Some 90% of all presidentially declared disasters are weather related, leading to around 500 deaths per year and nearly $14 billion in damage. StormReady, a program started in 1999 in Tulsa, OK, helps arm America's communities with the communication and safety skills needed to save lives and property– before and during the event. StormReady helps community leaders and emergency managers strengthen local safety programs.

StormReady communities are better prepared to save lives from the onslaught of severe weather through better planning, education, and awareness. No community is storm proof, but StormReady can help communities save lives. Does StormReady make a difference?
#@+node:ekr.20061101121602.108: *6* before sel=3.208,3.208
Americans live in the most severe weather-prone country on Earth. Each year, Americans cope with an average of 10,000 thunderstorms, 2,500 floods, 1,000 tornadoes, as well as an average of 6 deadly hurricanes. Potentially deadly weather impacts every American. Communities can now rely on the National Weather Service’s StormReady program to help them guard against the ravages of Mother Nature.

Some 90% of all presidentially declared disasters are weather related, leading to around 500 deaths per year and nearly $14 billion in damage. StormReady, a program started in 1999 in Tulsa, OK, helps arm America's communities with the communication and safety skills needed to save lives and property– before and during the event. StormReady helps community leaders and emergency managers strengthen local safety programs.

StormReady communities are better prepared to save lives from the onslaught of severe weather through better planning, education, and awareness. No community is storm proof, but StormReady can help communities save lives. Does StormReady make a difference?
#@+node:ekr.20061101121602.109: *6* after sel=3.143,3.208
Americans live in the most severe weather-prone country on Earth. Each year, Americans cope with an average of 10,000 thunderstorms, 2,500 floods, 1,000 tornadoes, as well as an average of 6 deadly hurricanes. Potentially deadly weather impacts every American. Communities can now rely on the National Weather Service’s StormReady program to help them guard against the ravages of Mother Nature.

Some 90% of all presidentially declared disasters are weather related, leading to around 500 deaths per year and nearly $14 billion in damage. StormReady, a program started in 1999 in Tulsa, OK, helps arm America's communities with the communication and safety skills needed to save lives and property– before and during the event. StormReady helps community leaders and emergency managers strengthen local safety programs.

StormReady communities are better prepared to save lives from the onslaught of severe weather through better planning, education, and awareness. No community is storm proof, but StormReady can help communities save lives. Does StormReady make a difference?
#@+node:ekr.20061101121602.110: *5* @test back-to-indentation
c.testManager.runEditCommandTest(p)
#@+node:ekr.20061101121602.111: *6* work
first line
line 1
    line a
        line b
line c
last line
#@+node:ekr.20061101121602.112: *6* before sel=4.13,4.13
first line
line 1
    line a
        line b
line c
last line
#@+node:ekr.20061101121602.113: *6* after sel=4.8,4.8
first line
line 1
    line a
        line b
line c
last line
#@+node:ekr.20090427104851.7: *5* @test back-to-home (at start of line)
c.testManager.runEditCommandTest(p)
#@+node:ekr.20090427104851.8: *6* work
if a:
    b = 'xyz'
#@+node:ekr.20090427104851.9: *6* before sel=2.0,2.0
if a:
    b = 'xyz'
#@+node:ekr.20090427104851.10: *6* after sel=2.4,2.4
if a:
    b = 'xyz'
#@+node:ekr.20090427104851.15: *5* @test back-to-home (at indentation
c.testManager.runEditCommandTest(p)
#@+node:ekr.20090427104851.16: *6* work
if a:
    b = 'xyz'
#@+node:ekr.20090427104851.17: *6* before sel=2.4,2.4
if a:
    b = 'xyz'
#@+node:ekr.20090427104851.18: *6* after sel=2.0,2.0
if a:
    b = 'xyz'
#@+node:ekr.20090427104851.11: *5* @test back-to-home (at end of line)
c.testManager.runEditCommandTest(p)
#@+node:ekr.20090427104851.12: *6* work
if a:
    b = 'xyz'
#@+node:ekr.20090427104851.13: *6* before sel=2.12,2.12
if a:
    b = 'xyz'
#@+node:ekr.20090427104851.14: *6* after sel=2.4,2.4
if a:
    b = 'xyz'
#@+node:ekr.20061101121602.114: *5* @test back-word
c.testManager.runEditCommandTest(p)
#@+node:ekr.20061101121602.115: *6* work
Americans live in the most severe weather-prone country on Earth. Each year, Americans cope with an average of 10,000 thunderstorms, 2,500 floods, 1,000 tornadoes, as well as an average of 6 deadly hurricanes. Potentially deadly weather impacts every American. Communities can now rely on the National Weather Service’s StormReady program to help them guard against the ravages of Mother Nature.

Some 90% of all presidentially declared disasters are weather related, leading to around 500 deaths per year and nearly $14 billion in damage. StormReady, a program started in 1999 in Tulsa, OK, helps arm America's communities with the communication and safety skills needed to save lives and property– before and during the event. StormReady helps community leaders and emergency managers strengthen local safety programs.

StormReady communities are better prepared to save lives from the onslaught of severe weather through better planning, education, and awareness. No community is storm proof, but StormReady can help communities save lives. Does StormReady make a difference?
#@+node:ekr.20061101121602.116: *6* before sel=1.183,1.183
Americans live in the most severe weather-prone country on Earth. Each year, Americans cope with an average of 10,000 thunderstorms, 2,500 floods, 1,000 tornadoes, as well as an average of 6 deadly hurricanes. Potentially deadly weather impacts every American. Communities can now rely on the National Weather Service’s StormReady program to help them guard against the ravages of Mother Nature.

Some 90% of all presidentially declared disasters are weather related, leading to around 500 deaths per year and nearly $14 billion in damage. StormReady, a program started in 1999 in Tulsa, OK, helps arm America's communities with the communication and safety skills needed to save lives and property– before and during the event. StormReady helps community leaders and emergency managers strengthen local safety programs.

StormReady communities are better prepared to save lives from the onslaught of severe weather through better planning, education, and awareness. No community is storm proof, but StormReady can help communities save lives. Does StormReady make a difference?
#@+node:ekr.20061101121602.117: *6* after sel=1.178,1.178
Americans live in the most severe weather-prone country on Earth. Each year, Americans cope with an average of 10,000 thunderstorms, 2,500 floods, 1,000 tornadoes, as well as an average of 6 deadly hurricanes. Potentially deadly weather impacts every American. Communities can now rely on the National Weather Service’s StormReady program to help them guard against the ravages of Mother Nature.

Some 90% of all presidentially declared disasters are weather related, leading to around 500 deaths per year and nearly $14 billion in damage. StormReady, a program started in 1999 in Tulsa, OK, helps arm America's communities with the communication and safety skills needed to save lives and property– before and during the event. StormReady helps community leaders and emergency managers strengthen local safety programs.

StormReady communities are better prepared to save lives from the onslaught of severe weather through better planning, education, and awareness. No community is storm proof, but StormReady can help communities save lives. Does StormReady make a difference?
#@+node:ekr.20061101121602.118: *5* @test back-word-extend-selection
c.testManager.runEditCommandTest(p)
#@+node:ekr.20061101121602.119: *6* work
Americans live in the most severe weather-prone country on Earth. Each year, Americans cope with an average of 10,000 thunderstorms, 2,500 floods, 1,000 tornadoes, as well as an average of 6 deadly hurricanes. Potentially deadly weather impacts every American. Communities can now rely on the National Weather Service’s StormReady program to help them guard against the ravages of Mother Nature.

Some 90% of all presidentially declared disasters are weather related, leading to around 500 deaths per year and nearly $14 billion in damage. StormReady, a program started in 1999 in Tulsa, OK, helps arm America's communities with the communication and safety skills needed to save lives and property– before and during the event. StormReady helps community leaders and emergency managers strengthen local safety programs.

StormReady communities are better prepared to save lives from the onslaught of severe weather through better planning, education, and awareness. No community is storm proof, but StormReady can help communities save lives. Does StormReady make a difference?
#@+node:ekr.20061101121602.120: *6* before sel=3.342,3.342
Americans live in the most severe weather-prone country on Earth. Each year, Americans cope with an average of 10,000 thunderstorms, 2,500 floods, 1,000 tornadoes, as well as an average of 6 deadly hurricanes. Potentially deadly weather impacts every American. Communities can now rely on the National Weather Service’s StormReady program to help them guard against the ravages of Mother Nature.

Some 90% of all presidentially declared disasters are weather related, leading to around 500 deaths per year and nearly $14 billion in damage. StormReady, a program started in 1999 in Tulsa, OK, helps arm America's communities with the communication and safety skills needed to save lives and property– before and during the event. StormReady helps community leaders and emergency managers strengthen local safety programs.

StormReady communities are better prepared to save lives from the onslaught of severe weather through better planning, education, and awareness. No community is storm proof, but StormReady can help communities save lives. Does StormReady make a difference?
#@+node:ekr.20061101121602.121: *6* after sel=3.332,3.342
Americans live in the most severe weather-prone country on Earth. Each year, Americans cope with an average of 10,000 thunderstorms, 2,500 floods, 1,000 tornadoes, as well as an average of 6 deadly hurricanes. Potentially deadly weather impacts every American. Communities can now rely on the National Weather Service’s StormReady program to help them guard against the ravages of Mother Nature.

Some 90% of all presidentially declared disasters are weather related, leading to around 500 deaths per year and nearly $14 billion in damage. StormReady, a program started in 1999 in Tulsa, OK, helps arm America's communities with the communication and safety skills needed to save lives and property– before and during the event. StormReady helps community leaders and emergency managers strengthen local safety programs.

StormReady communities are better prepared to save lives from the onslaught of severe weather through better planning, education, and awareness. No community is storm proof, but StormReady can help communities save lives. Does StormReady make a difference?
#@+node:ekr.20061101121602.122: *5* @test backward-delete-char
c.testManager.runEditCommandTest(p)
#@+node:ekr.20061101121602.123: *6* work
first lie
line 1
    line a
        line b
line c
last line
#@+node:ekr.20061101121602.124: *6* before sel=1.9,1.9
first line
line 1
    line a
        line b
line c
last line
#@+node:ekr.20061101121602.125: *6* after sel=1.8,1.8
first lie
line 1
    line a
        line b
line c
last line
#@+node:ekr.20071007121529: *5* @test backward-delete-char  (middle of line)
c.testManager.runEditCommandTest(p)
#@+node:ekr.20071007121529.1: *6* work
firstline
last line
#@+node:ekr.20071007121529.2: *6* before sel=1.6,1.6
first line
last line
#@+node:ekr.20071007121529.3: *6* after sel=1.5,1.5
firstline
last line
#@+node:ekr.20071007120947: *5* @test backward-delete-char (last char)
c.testManager.runEditCommandTest(p)
#@+node:ekr.20071007120947.6: *6* work
first line
last lin
#@+node:ekr.20071007120947.7: *6* before sel=2.9,2.9
first line
last line
#@+node:ekr.20071007120947.8: *6* after sel=2.8,2.8
first line
last lin
#@+node:ekr.20100817131738.5886: *5* @test backward-delete-word (no selection)
c.testManager.runEditCommandTest(p)
#@+node:ekr.20100817131738.5887: *6* work
aaaa cccc dddd
#@+node:ekr.20100817131738.5888: *6* before sel=1.10,1.10
aaaa bbbb cccc dddd
#@+node:ekr.20100817131738.5889: *6* after sel=1.5,1.5
aaaa cccc dddd
#@+node:ekr.20100817131738.5894: *5* @test backward-delete-word (selection)
c.testManager.runEditCommandTest(p)
#@+node:ekr.20100817131738.5895: *6* work
aaaa bbcc dddd
#@+node:ekr.20100817131738.5896: *6* before sel=1.7,1.12
aaaa bbbb cccc dddd
#@+node:ekr.20100817131738.5897: *6* after sel=1.7,1.7
aaaa bbcc dddd
#@+node:ekr.20061101121602.126: *5* @test backward-kill-paragraph
c.testManager.runEditCommandTest(p)
#@+node:ekr.20061101121602.127: *6* work
Americans live in the most severe weather-prone country on Earth. Each year,
Americans cope with an average of 10,000 thunderstorms, 2,500 floods, 1,000
tornadoes, as well as an average of 6 deadly hurricanes. Potentially deadly
weather impacts every American. Communities can now rely on the National Weather
Service’s StormReady program to help them guard against the ravages of Mother
Nature.
to around 500 deaths per year and nearly $14 billion in damage. StormReady, a
program started in 1999 in Tulsa, OK, helps arm America's communities with the
communication and safety skills needed to save lives and property– before and
during the event. StormReady helps community leaders and emergency managers
strengthen local safety programs.

StormReady communities are better prepared to save lives from the onslaught of
severe weather through better planning, education, and awareness. No community
is storm proof, but StormReady can help communities save lives. Does StormReady
make a difference?
#@+node:ekr.20061101121602.128: *6* before sel=9.0,9.0
Americans live in the most severe weather-prone country on Earth. Each year,
Americans cope with an average of 10,000 thunderstorms, 2,500 floods, 1,000
tornadoes, as well as an average of 6 deadly hurricanes. Potentially deadly
weather impacts every American. Communities can now rely on the National Weather
Service’s StormReady program to help them guard against the ravages of Mother
Nature.

Some 90% of all presidentially declared disasters are weather related, leading
to around 500 deaths per year and nearly $14 billion in damage. StormReady, a
program started in 1999 in Tulsa, OK, helps arm America's communities with the
communication and safety skills needed to save lives and property– before and
during the event. StormReady helps community leaders and emergency managers
strengthen local safety programs.

StormReady communities are better prepared to save lives from the onslaught of
severe weather through better planning, education, and awareness. No community
is storm proof, but StormReady can help communities save lives. Does StormReady
make a difference?
#@+node:ekr.20061101121602.129: *6* after sel=7.0,7.0
Americans live in the most severe weather-prone country on Earth. Each year,
Americans cope with an average of 10,000 thunderstorms, 2,500 floods, 1,000
tornadoes, as well as an average of 6 deadly hurricanes. Potentially deadly
weather impacts every American. Communities can now rely on the National Weather
Service’s StormReady program to help them guard against the ravages of Mother
Nature.
to around 500 deaths per year and nearly $14 billion in damage. StormReady, a
program started in 1999 in Tulsa, OK, helps arm America's communities with the
communication and safety skills needed to save lives and property– before and
during the event. StormReady helps community leaders and emergency managers
strengthen local safety programs.

StormReady communities are better prepared to save lives from the onslaught of
severe weather through better planning, education, and awareness. No community
is storm proof, but StormReady can help communities save lives. Does StormReady
make a difference?
#@+node:ekr.20070131173932: *5* @test backward-kill-sentence
c.testManager.runEditCommandTest(p)
#@+node:ekr.20070131173932.1: *6* work
This is the first sentence.  This
is the second sentence.
#@+node:ekr.20070131173932.2: *6* before sel=3.2,3.2
This is the first sentence.  This
is the second sentence.  And
this is the last sentence.
#@+node:ekr.20070131173932.3: *6* after sel=2.23,2.23
This is the first sentence.  This
is the second sentence.
#@+node:ekr.20081215084144.2: *5* @test backward-kill-word
c.testManager.runEditCommandTest(p)
#@+node:ekr.20081215084144.3: *6* work
This is the first sentence.  This
is the second sentence.  And
this  the last sentence.
#@+node:ekr.20081215084144.4: *6* before sel=3.7,3.7
This is the first sentence.  This
is the second sentence.  And
this is the last sentence.
#@+node:ekr.20081215084144.5: *6* after sel=3.5,3.5
This is the first sentence.  This
is the second sentence.  And
this  the last sentence.
#@+node:ekr.20061101121602.130: *5* @test beginning-of-buffer
c.testManager.runEditCommandTest(p)
#@+node:ekr.20061101121602.131: *6* work
Americans live in the most severe weather-prone country on Earth. Each year, Americans cope with an average of 10,000 thunderstorms, 2,500 floods, 1,000 tornadoes, as well as an average of 6 deadly hurricanes. Potentially deadly weather impacts every American. Communities can now rely on the National Weather Service’s StormReady program to help them guard against the ravages of Mother Nature.

Some 90% of all presidentially declared disasters are weather related, leading to around 500 deaths per year and nearly $14 billion in damage. StormReady, a program started in 1999 in Tulsa, OK, helps arm America's communities with the communication and safety skills needed to save lives and property– before and during the event. StormReady helps community leaders and emergency managers strengthen local safety programs.

StormReady communities are better prepared to save lives from the onslaught of severe weather through better planning, education, and awareness. No community is storm proof, but StormReady can help communities save lives. Does StormReady make a difference?
#@+node:ekr.20061101121602.132: *6* before sel=5.56,5.56
Americans live in the most severe weather-prone country on Earth. Each year, Americans cope with an average of 10,000 thunderstorms, 2,500 floods, 1,000 tornadoes, as well as an average of 6 deadly hurricanes. Potentially deadly weather impacts every American. Communities can now rely on the National Weather Service’s StormReady program to help them guard against the ravages of Mother Nature.

Some 90% of all presidentially declared disasters are weather related, leading to around 500 deaths per year and nearly $14 billion in damage. StormReady, a program started in 1999 in Tulsa, OK, helps arm America's communities with the communication and safety skills needed to save lives and property– before and during the event. StormReady helps community leaders and emergency managers strengthen local safety programs.

StormReady communities are better prepared to save lives from the onslaught of severe weather through better planning, education, and awareness. No community is storm proof, but StormReady can help communities save lives. Does StormReady make a difference?
#@+node:ekr.20061101121602.133: *6* after sel=1.0,1.0
Americans live in the most severe weather-prone country on Earth. Each year, Americans cope with an average of 10,000 thunderstorms, 2,500 floods, 1,000 tornadoes, as well as an average of 6 deadly hurricanes. Potentially deadly weather impacts every American. Communities can now rely on the National Weather Service’s StormReady program to help them guard against the ravages of Mother Nature.

Some 90% of all presidentially declared disasters are weather related, leading to around 500 deaths per year and nearly $14 billion in damage. StormReady, a program started in 1999 in Tulsa, OK, helps arm America's communities with the communication and safety skills needed to save lives and property– before and during the event. StormReady helps community leaders and emergency managers strengthen local safety programs.

StormReady communities are better prepared to save lives from the onslaught of severe weather through better planning, education, and awareness. No community is storm proof, but StormReady can help communities save lives. Does StormReady make a difference?
#@+node:ekr.20061101121602.134: *5* @test beginning-of-buffer-extend-selection
c.testManager.runEditCommandTest(p)
#@+node:ekr.20061101121602.135: *6* work
Americans live in the most severe weather-prone country on Earth. Each year, Americans cope with an average of 10,000 thunderstorms, 2,500 floods, 1,000 tornadoes, as well as an average of 6 deadly hurricanes. Potentially deadly weather impacts every American. Communities can now rely on the National Weather Service’s StormReady program to help them guard against the ravages of Mother Nature.

Some 90% of all presidentially declared disasters are weather related, leading to around 500 deaths per year and nearly $14 billion in damage. StormReady, a program started in 1999 in Tulsa, OK, helps arm America's communities with the communication and safety skills needed to save lives and property– before and during the event. StormReady helps community leaders and emergency managers strengthen local safety programs.

StormReady communities are better prepared to save lives from the onslaught of severe weather through better planning, education, and awareness. No community is storm proof, but StormReady can help communities save lives. Does StormReady make a difference?
#@+node:ekr.20061101121602.136: *6* before sel=3.423,3.423
Americans live in the most severe weather-prone country on Earth. Each year, Americans cope with an average of 10,000 thunderstorms, 2,500 floods, 1,000 tornadoes, as well as an average of 6 deadly hurricanes. Potentially deadly weather impacts every American. Communities can now rely on the National Weather Service’s StormReady program to help them guard against the ravages of Mother Nature.

Some 90% of all presidentially declared disasters are weather related, leading to around 500 deaths per year and nearly $14 billion in damage. StormReady, a program started in 1999 in Tulsa, OK, helps arm America's communities with the communication and safety skills needed to save lives and property– before and during the event. StormReady helps community leaders and emergency managers strengthen local safety programs.

StormReady communities are better prepared to save lives from the onslaught of severe weather through better planning, education, and awareness. No community is storm proof, but StormReady can help communities save lives. Does StormReady make a difference?
#@+node:ekr.20061101121602.137: *6* after sel=1.0,3.423
Americans live in the most severe weather-prone country on Earth. Each year, Americans cope with an average of 10,000 thunderstorms, 2,500 floods, 1,000 tornadoes, as well as an average of 6 deadly hurricanes. Potentially deadly weather impacts every American. Communities can now rely on the National Weather Service’s StormReady program to help them guard against the ravages of Mother Nature.

Some 90% of all presidentially declared disasters are weather related, leading to around 500 deaths per year and nearly $14 billion in damage. StormReady, a program started in 1999 in Tulsa, OK, helps arm America's communities with the communication and safety skills needed to save lives and property– before and during the event. StormReady helps community leaders and emergency managers strengthen local safety programs.

StormReady communities are better prepared to save lives from the onslaught of severe weather through better planning, education, and awareness. No community is storm proof, but StormReady can help communities save lives. Does StormReady make a difference?
#@+node:ekr.20061101121602.138: *5* @test beginning-of-line
c.testManager.runEditCommandTest(p)
#@+node:ekr.20061101121602.139: *6* work
first line
line 1
    line a
        line b
line c
last line
#@+node:ekr.20061101121602.140: *6* before sel=3.10,3.10
first line
line 1
    line a
        line b
line c
last line
#@+node:ekr.20061101121602.141: *6* after sel=3.0,3.0
first line
line 1
    line a
        line b
line c
last line
#@+node:ekr.20061101121602.142: *5* @test beginning-of-line-extend-selection
c.testManager.runEditCommandTest(p)
#@+node:ekr.20061101121602.143: *6* work
first line
line 1
    line a
        line b
line c
last line
#@+node:ekr.20061101121602.144: *6* before sel=4.10,4.10
first line
line 1
    line a
        line b
line c
last line
#@+node:ekr.20061101121602.145: *6* after sel=4.0,4.10
first line
line 1
    line a
        line b
line c
last line
#@+node:ekr.20081111084046.2: *4*  Commands C-E
#@+node:ekr.20111104171708.3847: *5* @test c-to-python
import leo.core.leoBeautify as leoBeautify
import leo.commands.convertCommands as convertCommands
cpp = leoBeautify.CPrettyPrinter(c)
# c2p = convertCommands.C_To_Python(c)
fn = 'c tokenize test'
p2 = g.findNodeInTree(c,p,fn)
assert p2,'not found: %s' % (fn)
aList = cpp.tokenize(p2.b)
assert aList
# c2p.convertCodeList(aList)
# s = ''.join(aList)
#@+node:ekr.20111104171708.3848: *6* c tokenize test
@language c

static exit_values_ty indent_main_loop(void)
{
    codes_ty         hd_type         = code_eof;
    char           * t_ptr           = NULL;
    codes_ty         type_code       = start_token;
    exit_values_ty   file_exit_value = total_success;
    int              dec_ind         = 0; /* current indentation for declarations */

    BOOLEAN          scase           = false; /* true when we've just see a "case";
                                               * determines what to do with the
                                               * following colon */
    BOOLEAN          flushed_nl;              /* Used when buffering up comments to remember that
                                               * a newline was passed over */
    BOOLEAN          sp_sw           = false; /* true when in the expression part of if(...),
                                               * while(...), etc. */
    BOOLEAN          force_nl        = false;

    /* last_token_ends_sp: True if we have just encountered the end of an if (...),
     * etc. (i.e. the ')' of the if (...) was the last token).  The variable is
     * set to 2 in the middle of the main token reading loop and is decremented
     * at the beginning of the loop, so it will reach zero when the second token
     * after the ')' is read.
     */

    BOOLEAN          last_token_ends_sp = false;

    BOOLEAN          last_else = false; /* true if last keyword was an else */

    for (;;)
    {
        /* this is the main loop.  it will go until
         * we reach eof */

        BOOLEAN is_procname_definition;
        bb_code_ty can_break;

        if (type_code != newline)
        {
            can_break = parser_state_tos->can_break;
        }

        parser_state_tos->last_saw_nl = false;
        parser_state_tos->can_break = bb_none;

        type_code = lexi ();    /* lexi reads one token.  "token" points to
                                 * the actual characters. lexi returns a code
                                 * indicating the type of token */

        /* If the last time around we output an identifier or
         * a paren, then consider breaking the line here if it's
         * too long.
         *
         * A similar check is performed at the end of the loop, after
         * we've put the token on the line. */

        if ((settings.max_col > 0) &&
            (buf_break != NULL) &&
            ( ( (parser_state_tos->last_token == ident) &&
                (type_code != comma) &&
                (type_code != semicolon) &&
                (type_code != newline) &&
                (type_code != form_feed) &&
                (type_code != rparen) &&
                (type_code != struct_delim)) ||
              ( (parser_state_tos->last_token == rparen) &&
                (type_code != comma) &&
                (type_code != rparen) ) ) &&
            (output_line_length () > settings.max_col))
        {
            break_line = 1;
        }

        if (last_token_ends_sp > 0)
        {
            last_token_ends_sp--;
        }

        is_procname_definition =
                (((parser_state_tos->procname[0] != '\0') &&
                  parser_state_tos->in_parameter_declaration) ||
                 (parser_state_tos->classname[0] != '\0'));

        /* The following code moves everything following an if (), while (),
         * else, etc. up to the start of the following stmt to a buffer. This
         * allows proper handling of both kinds of brace placement.
         */

        flushed_nl = false;

        if (!search_brace(&type_code, &force_nl, &flushed_nl, &last_else, &is_procname_definition))
        {
            /* Hit EOF unexpectedly in comment. */
            return indent_punt;
        }
        
        if (type_code == code_eof)
        {
            /* we got eof */
            if (s_lab != e_lab || s_code != e_code || s_com != e_com)   /* must dump end of line */
            {
                dump_line(true, &paren_target);
            }

            if (parser_state_tos->tos > 1)      /* check for balanced braces */
            {
                ERROR (_("Unexpected end of file"), 0, 0);
                file_exit_value = indent_error;
            }

            if (settings.verbose)
            {
                printf (_("There were %d non-blank output lines and %d comments\n"),
                        (int) out_lines, (int) com_lines);
                if (com_lines > 0 && code_lines > 0)
                {
                    printf (_("(Lines with comments)/(Lines with code): %6.3f\n"),
                            (1.0 * com_lines) / code_lines);
                }
            }
            flush_output ();

            return file_exit_value;                                              /* RETURN */
        }

        if ((type_code != comment) &&
            (type_code != cplus_comment) &&
            (type_code != newline) &&
            (type_code != preesc) &&
            (type_code != form_feed))
        {
            if (force_nl &&
                (type_code != semicolon) &&
                ( (type_code != lbrace) ||
                  (!parser_state_tos->in_decl && !settings.btype_2) ||
                  (parser_state_tos->in_decl && !settings.braces_on_struct_decl_line) ||
                  (parser_state_tos->last_token == rbrace)))
            {
                if (settings.verbose && !flushed_nl)
                {
                    WARNING (_("Line broken 2"), 0, 0);
                }

                flushed_nl = false;
                dump_line(true, &paren_target);
                parser_state_tos->want_blank = false;
                force_nl = false;
            }

            parser_state_tos->in_stmt = true;   /* turn on flag which causes
                                                 * an extra level of
                                                 * indentation. this is
                                                 * turned off by a ; or } */
            if (s_com != e_com)
            {
                /* the code has an embedded comment in the
                 * line. Move it from the com buffer to the
                 * code buffer.
                 *
                 * Do not add a space before the comment if it is the first
                 * thing on the line.
                 */

                if (e_code != s_code)
                {
                    set_buf_break (bb_embedded_comment_start, paren_target);
                    *e_code++ = ' ';
                    embedded_comment_on_line = 2;
                }
                else
                {
                    embedded_comment_on_line = 1;
                }

                for (t_ptr = s_com; *t_ptr; ++t_ptr)
                {
                    check_code_size();
                    *e_code++ = *t_ptr;
                }

                set_buf_break (bb_embedded_comment_end, paren_target);
                *e_code++ = ' ';
                *e_code = '\0'; /* null terminate code sect */
                parser_state_tos->want_blank = false;
                e_com = s_com;
            }
        }
        else if ((type_code != comment) &&
                 (type_code != cplus_comment) &&
                 !(settings.break_function_decl_args &&
                   (parser_state_tos->last_token == comma)) &&
                 !( (parser_state_tos->last_token == comma) &&
                    !settings.leave_comma))
        {
            /* preserve force_nl thru a comment but
             * cancel forced newline after newline, form feed, etc.
             * however, don't cancel if last thing seen was comma-newline
             * and -bc flag is on. */

            force_nl = false;
        }

        /* Main switch on type of token scanned */

        check_code_size();
        
        /* now, decide what to do with the token */

        handle_the_token(type_code, &scase, &force_nl, &sp_sw, &flushed_nl,
                         &hd_type, &dec_ind, &last_token_ends_sp, &file_exit_value,
                         can_break, &last_else, is_procname_definition);
        
        *e_code = '\0';         /* make sure code section is null terminated */

        if ((type_code != comment) &&
            (type_code != cplus_comment) &&
            (type_code != newline) &&
            (type_code != preesc) &&
            (type_code != form_feed))
        {
            parser_state_tos->last_token = type_code;
        }

        /* Now that we've put the token on the line (in most cases),
         * consider breaking the line because it's too long.
         *
         * Don't consider the cases of `unary_op', newlines,
         * declaration types (int, etc.), if, while, for,
         * identifiers (handled at the beginning of the loop),
         * periods, or preprocessor commands. */

        if ((settings.max_col > 0) && (buf_break != NULL))
        {
            if ( ( (type_code == binary_op) ||
                   (type_code == postop) ||
                   (type_code == question) ||
                   ((type_code == colon) && (scase || (squest <= 0))) ||
                   (type_code == semicolon) ||
                   (type_code == sp_nparen) ||
                   (type_code == sp_else) ||
                   ((type_code == ident) && (*token == '\"')) ||
                   (type_code == struct_delim) ||
                   (type_code == comma)) &&
                 (output_line_length () > settings.max_col))
            {
                break_line = 1;
            }
        }
    }                           /* end of main infinite loop */
}
#@+node:ekr.20061101121602.146: *5* @test capitalize-word
c.testManager.runEditCommandTest(p)
#@+node:ekr.20061101121602.147: *6* work
first line
line 1
    Line a
        line b
line c
last line
#@+node:ekr.20061101121602.148: *6* before sel=3.6,3.6
first line
line 1
    line a
        line b
line c
last line
#@+node:ekr.20061101121602.149: *6* after sel=3.6,3.6
first line
line 1
    Line a
        line b
line c
last line
#@+node:ekr.20061101121602.150: *5* @test center-line
@pagewidth 70 # Required for unit test.

c.testManager.runEditCommandTest(p)
#@+node:ekr.20061101121602.151: *6* work
Americans live in the most severe weather-prone country on Earth. Each year, Americans cope with an average of 10,000 thunderstorms, 2,500 floods, 1,000 tornadoes, as well as an average of 6 deadly hurricanes. Potentially deadly weather impacts every American. Communities can now rely on the National Weather Service’s StormReady program to help them guard against the ravages of Mother Nature.

Some 90% of all presidentially declared disasters are weather related,
leading to around 500 deaths per year and nearly $14 billion in damage.
StormReady, a program started in 1999 in Tulsa, OK,
helps arm America's communities with the communication and safety
skills needed to save lives and property– before and during the event.
StormReady helps community leaders and emergency managers strengthen local safety programs.

StormReady communities are better prepared to save lives from the onslaught of severe weather through better planning, education, and awareness. No community is storm proof, but StormReady can help communities save lives. Does StormReady make a difference?
#@+node:ekr.20061101121602.152: *6* before sel=3.0,9.0
Americans live in the most severe weather-prone country on Earth. Each year, Americans cope with an average of 10,000 thunderstorms, 2,500 floods, 1,000 tornadoes, as well as an average of 6 deadly hurricanes. Potentially deadly weather impacts every American. Communities can now rely on the National Weather Service’s StormReady program to help them guard against the ravages of Mother Nature.

Some 90% of all presidentially declared disasters are weather related,
leading to around 500 deaths per year and nearly $14 billion in damage.
StormReady, a program started in 1999 in Tulsa, OK,
helps arm America's communities with the communication and safety
skills needed to save lives and property– before and during the event.
StormReady helps community leaders and emergency managers strengthen local safety programs.

StormReady communities are better prepared to save lives from the onslaught of severe weather through better planning, education, and awareness. No community is storm proof, but StormReady can help communities save lives. Does StormReady make a difference?
#@+node:ekr.20061101121602.153: *6* after sel=3.0,9.0
Americans live in the most severe weather-prone country on Earth. Each year, Americans cope with an average of 10,000 thunderstorms, 2,500 floods, 1,000 tornadoes, as well as an average of 6 deadly hurricanes. Potentially deadly weather impacts every American. Communities can now rely on the National Weather Service’s StormReady program to help them guard against the ravages of Mother Nature.

Some 90% of all presidentially declared disasters are weather related,
leading to around 500 deaths per year and nearly $14 billion in damage.
StormReady, a program started in 1999 in Tulsa, OK,
helps arm America's communities with the communication and safety
skills needed to save lives and property– before and during the event.
StormReady helps community leaders and emergency managers strengthen local safety programs.

StormReady communities are better prepared to save lives from the onslaught of severe weather through better planning, education, and awareness. No community is storm proof, but StormReady can help communities save lives. Does StormReady make a difference?
#@+node:ekr.20061101121602.154: *5* @test center-region
@pagewidth 70 # Required for unit test.

c.testManager.runEditCommandTest(p)
#@+node:ekr.20061101121602.155: *6* work
Some 90% of all presidentially declared disasters are weather related,
leading to around 500 deaths per year and nearly $14 billion in damage.
         StormReady, a program started in 1999 in Tulsa, OK,
  helps arm America's communities with the communication and safety
skills needed to save lives and property– before and during the event.
StormReady helps community leaders and emergency managers strengthen local safety programs.
#@+node:ekr.20061101121602.156: *6* before sel=1.0,7.0
Some 90% of all presidentially declared disasters are weather related,
leading to around 500 deaths per year and nearly $14 billion in damage.
StormReady, a program started in 1999 in Tulsa, OK,
helps arm America's communities with the communication and safety
skills needed to save lives and property– before and during the event.
StormReady helps community leaders and emergency managers strengthen local safety programs.
#@+node:ekr.20061101121602.157: *6* after sel=1.0,7.0
Some 90% of all presidentially declared disasters are weather related,
leading to around 500 deaths per year and nearly $14 billion in damage.
         StormReady, a program started in 1999 in Tulsa, OK,
  helps arm America's communities with the communication and safety
skills needed to save lives and property– before and during the event.
StormReady helps community leaders and emergency managers strengthen local safety programs.
#@+node:ekr.20120525072421.3889: *5* @test clean-lines
c.testManager.runEditCommandTest(p)
#@+node:ekr.20120525072421.3890: *6* work
# Should remove all trailing whitespace.

a = 2

    b = 3
    c  = 4
d = 5
e = 6
x
#@+node:ekr.20120525072421.3891: *6* before sel=1.0,1.0
# Should remove all trailing whitespace.

a = 2   
    
    b = 3
    c  = 4  
d = 5
e = 6  
x
#@+node:ekr.20120525072421.3892: *6* after sel=1.0,1.0
# Should remove all trailing whitespace.

a = 2

    b = 3
    c  = 4
d = 5
e = 6
x
#@+node:ekr.20061101121602.158: *5* @test clear-selected-text
c.testManager.runEditCommandTest(p)
#@+node:ekr.20061101121602.159: *6* work
first line
line    line b
line c
last line
#@+node:ekr.20061101121602.160: *6* before sel=2.4,4.4
first line
line 1
    line a
        line b
line c
last line
#@+node:ekr.20061101121602.161: *6* after sel=2.4,2.4
first line
line    line b
line c
last line
#@+node:ekr.20111006105711.3544: *5* @test clone-marked-nodes
if g.app.isExternalUnitTest:
    self.skipTest('Can not be run externally')
else:

    exec(g.findTestScript(c,'@common x-marked-nodes test code'))
    
    def test(p):
        setup_test(p)
        c.cloneMarked()
        h = 'Clones of marked nodes'
        assert c.p.h == h,c.p.h
        c.undoer.undo()
        assert not g.findNodeAnywhere(c,h)
        c.undoer.redo()
        assert c.p.h == h,c.p.h
    try:
        test(p)
    finally:
        tear_down(p,'Clones of marked nodes')
#@+node:ekr.20061101121602.162: *5* @test count-region
c.testManager.runEditCommandTest(p)
#@+node:ekr.20061101121602.163: *6* work
first line
line 1
    line a
        line b
line c
last line
#@+node:ekr.20061101121602.164: *6* before sel=2.4,4.8
first line
line 1
    line a
        line b
line c
last line
#@+node:ekr.20061101121602.165: *6* after sel=2.4,4.8
first line
line 1
    line a
        line b
line c
last line
#@+node:ekr.20111120124051.3994: *5* @test cycle-all-focus
'''Test that cycle-all-focus cycles through all tabs.'''

import sys
if g.app.isExternalUnitTest:
    self.skipTest('Can not be run externally')
elif sys.platform.startswith('linux'):
    self.skipTest('skip cycle-all-focus')
else:
    log = c.frame.log
    c.bodyWantsFocusNow()
    w_name = g.app.gui.widget_name
    w = c.frame.body
    seen = []
    while w:
        event = g.bunch(widget=w)
        c.editCommands.cycleAllFocus(event=event)
        w = g.app.gui.get_focus()
        if w in seen: break
        seen.append(w)
        # print(id(w),w_name(w))
    assert len(seen) >2, "expected >2, got %s" % len(seen)
#@+node:ekr.20111121164644.3928: *5* @test cycle-tab-focus
'''Test that cycle-all-focus cycles through all tabs.'''

if g.app.isExternalUnitTest:
    self.skipTest('Can not be run externally')
else:
    log = c.frame.log
    tabs = log.orderedTabNames()[1:]
    tabs.append('Log')
    
    # Set up the initial state.
    c.k.keyboardQuit()
    c.bodyWantsFocusNow()
    
    for tab in tabs:
        log.cycleTabFocus(event=None)
        assert log.tabName == tab,'expected %s, got %s' % (
            tab,log.tabName)
        # print('pass',tab)
#@+node:ekr.20150414144103.1: *5* @test dabbrev-completion
# main after
# mainto

ac = c.abbrevCommands
w = c.frame.body.wrapper
s = w.getAllText()
w.setInsertPoint(4)
# i,j = g.getWord(s,4)
# word = s[i:j]
event = g.bunch(widget=w)
ac.dynamicCompletion(event)
try:
    i = s.find('main')
    assert i == 2,i
finally:
    if 1:
        c.undoer.undo(event=event)

#@+node:ekr.20150414144038.1: *5* @test dabbrev-expand
# main after
# mainto

ac = c.abbrevCommands
w = c.frame.body.wrapper
s = w.getAllText()
w.setInsertPoint(4)
i,j = g.getWord(s,4)
word = s[i:j]
aList = ac.getDynamicList(w,word)
c.k.arg = aList[1]
event = g.bunch(char=None, stroke=None, widget=w)
ac.dynamicExpandHelper(event)
    # This *does* support undo.
s = w.getAllText()
try:
    i = s.find('main')
    assert i == 2,i
finally:
    if 0: ####################
        c.undoer.undo()
#@+node:ekr.20061101121602.166: *5* @test delete-char
c.testManager.runEditCommandTest(p)
#@+node:ekr.20061101121602.167: *6* work
firstline
line 1
    line a
        line b
line c
last line
#@+node:ekr.20061101121602.168: *6* before sel=1.5,1.5
first line
line 1
    line a
        line b
line c
last line
#@+node:ekr.20061101121602.169: *6* after sel=1.5,1.5
firstline
line 1
    line a
        line b
line c
last line
#@+node:ekr.20071007120750.3: *5* @test delete-indentation
c.testManager.runEditCommandTest(p)
#@+node:ekr.20071007121115.1: *6* work
first line
line 1
last line
#@+node:ekr.20071007121115.2: *6* before sel=2.8,2.8
first line
    line 1
last line
#@+node:ekr.20071007121115.3: *6* after sel=2.4,2.4
first line
line 1
last line
#@+node:ekr.20111006064419.3491: *5* @test delete-marked-nodes
if g.app.isExternalUnitTest:
    self.skipTest('Can not be run externally')
else:

    exec(g.findTestScript(c,'@common x-marked-nodes test code'))
    
    def test(p):
        setup_test(p)
        c.deleteMarked()
        n = p.numberOfChildren()
        assert n == 2 ,'delete: children: %s' % (n)
        c.undoer.undo()
        n = p.numberOfChildren()
        assert n == 4,'undo: children: %s' % (n)
        c.undoer.redo()
        n = p.numberOfChildren()
        assert n == 2 ,'delete: children: %s' % (n)
    try:
        test(p)
    finally:
        tear_down(p)
#@+node:ekr.20070131162935: *5* @test delete-spaces
c.testManager.runEditCommandTest(p)
#@+node:ekr.20070131162935.1: *6* work
first line
line 1
line a
        line b
line c
last line
#@+node:ekr.20070131162935.2: *6* before sel=3.2,3.2
first line
line 1
    line a
        line b
line c
last line
#@+node:ekr.20070131162935.3: *6* after sel=3.0,3.0
first line
line 1
line a
        line b
line c
last line
#@+node:ekr.20100830113702.5969: *5* @test delete-word (no selection)
import sys
if g.app.gui.guiName() == 'qt':
    if sys.platform.startswith('linux'):
        self.skipTest('skip headline test')
    else:
        exec(g.findTestScript(c,'@common leoEditCommands test code'))
        runEditCommandTest(c,p,inHeadline=False)
        runEditCommandTest(c,p,inHeadline=True)
else:
    self.skipTest('skip qt test')
#@+node:ekr.20100830113702.5970: *6* work
aaaa bbbb dddd
#@+node:ekr.20100830113702.5971: *6* before sel=1.10,1.10
aaaa bbbb cccc dddd
#@+node:ekr.20100830113702.5972: *6* after sel=1.10,1.10
aaaa bbbb dddd
#@+node:ekr.20100830113702.5977: *5* @test delete-word (selection)
import sys
if g.app.gui.guiName() == 'qt':
    if sys.platform.startswith('linux'):
        self.skipTest('skip headline test')
    else:
        exec(g.findTestScript(c,'@common leoEditCommands test code'))
        runEditCommandTest(c,p,inHeadline=False)
        runEditCommandTest(c,p,inHeadline=True)
else:
    self.skipTest('skip qt test')
#@+node:ekr.20100830113702.5978: *6* work
aaaa bbcc dddd
#@+node:ekr.20100830113702.5979: *6* before sel=1.7,1.12
aaaa bbbb cccc dddd
#@+node:ekr.20100830113702.5980: *6* after sel=1.7,1.7
aaaa bbcc dddd
#@+node:ekr.20061101121602.170: *5* @test do-nothing
c.testManager.runEditCommandTest(p)
#@+node:ekr.20061101121602.171: *6* work
first line
line 1
    line a
        line b
line c
last line
#@+node:ekr.20061101121602.172: *6* before sel=1.0,1.0
first line
line 1
    line a
        line b
line c
last line
#@+node:ekr.20061101121602.173: *6* after sel=1.0,1.0
first line
line 1
    line a
        line b
line c
last line
#@+node:ekr.20061101121602.174: *5* @test downcase-region
c.testManager.runEditCommandTest(p)
assert g.app.unitTestDict.get('colorized')
#@+node:ekr.20061101121602.175: *6* work
Americans live in the most severe weather-prone country on Earth. Each year, Americans cope with an average of 10,000 thunderstorms, 2,500 floods, 1,000 tornadoes, as well as an average of 6 deadly hurricanes. Potentially deadly weather impacts every American. Communities can now rely on the National Weather Service’s StormReady program to help them guard against the ravages of Mother Nature.

some 90% of all presidentially declared disasters are weather related, leading to around 500 deaths per year and nearly $14 billion in damage. stormready, a program started in 1999 in tulsa, ok, helps arm america's communities with the communication and safety skills needed to save lives and property– before and during the event. stormready helps community leaders and emergency managers strengthen local safety programs.

StormReady communities are better prepared to save lives from the onslaught of severe weather through better planning, education, and awareness. No community is storm proof, but StormReady can help communities save lives. Does StormReady make a difference?
#@+node:ekr.20061101121602.176: *6* before sel=3.0,4.0
Americans live in the most severe weather-prone country on Earth. Each year, Americans cope with an average of 10,000 thunderstorms, 2,500 floods, 1,000 tornadoes, as well as an average of 6 deadly hurricanes. Potentially deadly weather impacts every American. Communities can now rely on the National Weather Service’s StormReady program to help them guard against the ravages of Mother Nature.

Some 90% of all presidentially declared disasters are weather related, leading to around 500 deaths per year and nearly $14 billion in damage. StormReady, a program started in 1999 in Tulsa, OK, helps arm America's communities with the communication and safety skills needed to save lives and property– before and during the event. StormReady helps community leaders and emergency managers strengthen local safety programs.

StormReady communities are better prepared to save lives from the onslaught of severe weather through better planning, education, and awareness. No community is storm proof, but StormReady can help communities save lives. Does StormReady make a difference?
#@+node:ekr.20061101121602.177: *6* after sel=3.0,4.0
Americans live in the most severe weather-prone country on Earth. Each year, Americans cope with an average of 10,000 thunderstorms, 2,500 floods, 1,000 tornadoes, as well as an average of 6 deadly hurricanes. Potentially deadly weather impacts every American. Communities can now rely on the National Weather Service’s StormReady program to help them guard against the ravages of Mother Nature.

some 90% of all presidentially declared disasters are weather related, leading to around 500 deaths per year and nearly $14 billion in damage. stormready, a program started in 1999 in tulsa, ok, helps arm america's communities with the communication and safety skills needed to save lives and property– before and during the event. stormready helps community leaders and emergency managers strengthen local safety programs.

StormReady communities are better prepared to save lives from the onslaught of severe weather through better planning, education, and awareness. No community is storm proof, but StormReady can help communities save lives. Does StormReady make a difference?
#@+node:ekr.20061101121602.178: *5* @test downcase-word
c.testManager.runEditCommandTest(p)
assert g.app.unitTestDict.get('colorized')
#@+node:ekr.20061101121602.179: *6* work
xyzzy line
line 1
    line a
        line b
line c
last line
#@+node:ekr.20061101121602.180: *6* before sel=1.4,1.4
XYZZY line
line 1
    line a
        line b
line c
last line
#@+node:ekr.20061101121602.181: *6* after sel=1.4,1.4
xyzzy line
line 1
    line a
        line b
line c
last line
#@+node:ekr.20061101121602.182: *5* @test end-of-buffer
c.testManager.runEditCommandTest(p)
#@+node:ekr.20061101121602.183: *6* work
first line
line 1
    line a
        line b
line c
last line
#@+node:ekr.20061101121602.184: *6* before sel=1.3,1.3
first line
line 1
    line a
        line b
line c
last line
#@+node:ekr.20061101121602.185: *6* after sel=7.0,7.0
first line
line 1
    line a
        line b
line c
last line
#@+node:ekr.20061101121602.186: *5* @test end-of-buffer-extend-selection
c.testManager.runEditCommandTest(p)
#@+node:ekr.20061101121602.187: *6* work
first line
line 1
    line a
        line b
line c
last line
#@+node:ekr.20061101121602.188: *6* before sel=1.0,1.0
first line
line 1
    line a
        line b
line c
last line
#@+node:ekr.20061101121602.189: *6* after sel=1.0,7.0
first line
line 1
    line a
        line b
line c
last line
#@+node:ekr.20061101121602.190: *5* @test end-of-line
c.testManager.runEditCommandTest(p)
#@+node:ekr.20061101121602.191: *6* work
first line
line 1
    line a
        line b
line c
last line
#@+node:ekr.20061101121602.192: *6* before sel=1.0,1.0
first line
line 1
    line a
        line b
line c
last line
#@+node:ekr.20061101121602.193: *6* after sel=1.10,1.10
first line
line 1
    line a
        line b
line c
last line
#@+node:ekr.20061128082002: *5* @test end-of-line 2
c.testManager.runEditCommandTest(p)
#@+node:ekr.20061128082002.1: *6* work
first line
line 1
    line a
        line b
line c
last line
#@+node:ekr.20061128082002.2: *6* before sel=6.0,6.0
first line
line 1
    line a
        line b
line c
last line
#@+node:ekr.20061128082002.3: *6* after sel=6.9,6.9
first line
line 1
    line a
        line b
line c
last line
#@+node:ekr.20061101121602.194: *5* @test end-of-line-extend-selection
c.testManager.runEditCommandTest(p)
#@+node:ekr.20061101121602.195: *6* work
first line
line 1
    line a
        line b
line c
last line
#@+node:ekr.20061101121602.196: *6* before sel=3.0,3.0
first line
line 1
    line a
        line b
line c
last line
#@+node:ekr.20061101121602.197: *6* after sel=3.0,3.10
first line
line 1
    line a
        line b
line c
last line
#@+node:ekr.20061101121602.198: *5* @test exchange-point-mark
c.testManager.runEditCommandTest(p)
#@+node:ekr.20061101121602.199: *6* work
first line
line 1
    line a
        line b
line c
last line
#@+node:ekr.20061101121602.200: *6* before sel=1.0,1.10
first line
line 1
    line a
        line b
line c
last line
#@+node:ekr.20061101121602.201: *6* after sel=1.0,1.10
first line
line 1
    line a
        line b
line c
last line
#@+node:ekr.20120303054735.3931: *5* @test expand-and-go-right
# Test of bug 930726: expandNodeAndGoToFirstChild only expands or only goes to first child .

p.contract()
c.expandNodeAndGoToFirstChild()
assert c.p == p.firstChild()
#@+node:ekr.20120303054735.3932: *6* child
#@+node:ekr.20061101121602.202: *5* @test extend-to-line
c.testManager.runEditCommandTest(p)
#@+node:ekr.20061101121602.203: *6* work
first line
line 1
    line a
        line b
line c
last line
#@+node:ekr.20061101121602.204: *6* before sel=3.3,3.3
first line
line 1
    line a
        line b
line c
last line
#@+node:ekr.20061101121602.205: *6* after sel=3.0,3.10
first line
line 1
    line a
        line b
line c
last line
#@+node:ekr.20061101121602.206: *5* @test extend-to-paragraph
c.testManager.runEditCommandTest(p)
#@+node:ekr.20061101121602.207: *6* work
Americans live in the most severe weather-prone country on Earth. Each year,
Americans cope with an average of 10,000 thunderstorms, 2,500 floods, 1,000
tornadoes, as well as an average of 6 deadly hurricanes. Potentially deadly
weather impacts every American. Communities can now rely on the National Weather
Service’s StormReady program to help them guard against the ravages of Mother
Nature.

Some 90% of all presidentially declared disasters are weather related, leading
to around 500 deaths per year and nearly $14 billion in damage. StormReady, a
program started in 1999 in Tulsa, OK, helps arm America's communities with the
communication and safety skills needed to save lives and property– before and
during the event. StormReady helps community leaders and emergency managers
strengthen local safety programs.

StormReady communities are better prepared to save lives from the onslaught of
severe weather through better planning, education, and awareness. No community
is storm proof, but StormReady can help communities save lives. Does StormReady
make a difference?
#@+node:ekr.20061101121602.208: *6* before sel=9.0,9.0
Americans live in the most severe weather-prone country on Earth. Each year,
Americans cope with an average of 10,000 thunderstorms, 2,500 floods, 1,000
tornadoes, as well as an average of 6 deadly hurricanes. Potentially deadly
weather impacts every American. Communities can now rely on the National Weather
Service’s StormReady program to help them guard against the ravages of Mother
Nature.

Some 90% of all presidentially declared disasters are weather related, leading
to around 500 deaths per year and nearly $14 billion in damage. StormReady, a
program started in 1999 in Tulsa, OK, helps arm America's communities with the
communication and safety skills needed to save lives and property– before and
during the event. StormReady helps community leaders and emergency managers
strengthen local safety programs.

StormReady communities are better prepared to save lives from the onslaught of
severe weather through better planning, education, and awareness. No community
is storm proof, but StormReady can help communities save lives. Does StormReady
make a difference?
#@+node:ekr.20061101121602.209: *6* after sel=8.0,13.33
Americans live in the most severe weather-prone country on Earth. Each year,
Americans cope with an average of 10,000 thunderstorms, 2,500 floods, 1,000
tornadoes, as well as an average of 6 deadly hurricanes. Potentially deadly
weather impacts every American. Communities can now rely on the National Weather
Service’s StormReady program to help them guard against the ravages of Mother
Nature.

Some 90% of all presidentially declared disasters are weather related, leading
to around 500 deaths per year and nearly $14 billion in damage. StormReady, a
program started in 1999 in Tulsa, OK, helps arm America's communities with the
communication and safety skills needed to save lives and property– before and
during the event. StormReady helps community leaders and emergency managers
strengthen local safety programs.

StormReady communities are better prepared to save lives from the onslaught of
severe weather through better planning, education, and awareness. No community
is storm proof, but StormReady can help communities save lives. Does StormReady
make a difference?
#@+node:ekr.20061101121602.210: *5* @test extend-to-sentence
c.testManager.runEditCommandTest(p)
#@+node:ekr.20061101121602.211: *6* work
Americans live in the most severe weather-prone country on Earth. Each year, Americans cope with an average of 10,000 thunderstorms, 2,500 floods, 1,000 tornadoes, as well as an average of 6 deadly hurricanes. Potentially deadly weather impacts every American. Communities can now rely on the National Weather Service’s StormReady program to help them guard against the ravages of Mother Nature.

Some 90% of all presidentially declared disasters are weather related, leading to around 500 deaths per year and nearly $14 billion in damage. StormReady, a program started in 1999 in Tulsa, OK, helps arm America's communities with the communication and safety skills needed to save lives and property– before and during the event. StormReady helps community leaders and emergency managers strengthen local safety programs.

StormReady communities are better prepared to save lives from the onslaught of severe weather through better planning, education, and awareness. No community is storm proof, but StormReady can help communities save lives. Does StormReady make a difference?
#@+node:ekr.20061101121602.212: *6* before sel=3.5,3.5
Americans live in the most severe weather-prone country on Earth. Each year, Americans cope with an average of 10,000 thunderstorms, 2,500 floods, 1,000 tornadoes, as well as an average of 6 deadly hurricanes. Potentially deadly weather impacts every American. Communities can now rely on the National Weather Service’s StormReady program to help them guard against the ravages of Mother Nature.

Some 90% of all presidentially declared disasters are weather related, leading to around 500 deaths per year and nearly $14 billion in damage. StormReady, a program started in 1999 in Tulsa, OK, helps arm America's communities with the communication and safety skills needed to save lives and property– before and during the event. StormReady helps community leaders and emergency managers strengthen local safety programs.

StormReady communities are better prepared to save lives from the onslaught of severe weather through better planning, education, and awareness. No community is storm proof, but StormReady can help communities save lives. Does StormReady make a difference?
#@+node:ekr.20061101121602.213: *6* after sel=1.395,3.142
Americans live in the most severe weather-prone country on Earth. Each year, Americans cope with an average of 10,000 thunderstorms, 2,500 floods, 1,000 tornadoes, as well as an average of 6 deadly hurricanes. Potentially deadly weather impacts every American. Communities can now rely on the National Weather Service’s StormReady program to help them guard against the ravages of Mother Nature.

Some 90% of all presidentially declared disasters are weather related, leading to around 500 deaths per year and nearly $14 billion in damage. StormReady, a program started in 1999 in Tulsa, OK, helps arm America's communities with the communication and safety skills needed to save lives and property– before and during the event. StormReady helps community leaders and emergency managers strengthen local safety programs.

StormReady communities are better prepared to save lives from the onslaught of severe weather through better planning, education, and awareness. No community is storm proof, but StormReady can help communities save lives. Does StormReady make a difference?
#@+node:ekr.20061101121602.214: *5* @test extend-to-word
c.testManager.runEditCommandTest(p)
#@+node:ekr.20061101121602.215: *6* work
first line
line 1
    line_24a a
        line b
line c
last line
#@+node:ekr.20061101121602.216: *6* before sel=3.10,3.10
first line
line 1
    line_24a a
        line b
line c
last line
#@+node:ekr.20061101121602.217: *6* after sel=3.4,3.12
first line
line 1
    line_24a a
        line b
line c
last line
#@+node:ekr.20120212130242.3942: *5* data
#@+node:ekr.20120212130242.3948: *6* a
#@+node:ekr.20120212130242.3949: *7* b
#@+node:ekr.20120212130242.3945: *6* c
#@+node:ekr.20120212130242.3946: *6* d
#@+node:ekr.20120212130242.3947: *6* e
#@+node:ekr.20120212130242.3948: *7* a
#@+node:ekr.20120212130242.3949: *8* b
#@+node:ekr.20070131175538.1: *4*  Commands F-L
#@+node:ekr.20071007120750.4: *5* @@test fill-region (one paragraph)
@pagewidth 80
    # Required for external unit test.

c.testManager.runEditCommandTest(p)
#@+node:ekr.20071007121312.1: *6* work
Americans live in the most severe weather-prone country on Earth. Each year,
Americans cope with an average of 10,000 thunderstorms, 2,500 floods, 1,000
tornadoes, as well as an average of 6 deadly hurricanes. Potentially deadly
weather impacts every American. Communities can now rely on the National Weather
Service’s StormReady program to help them guard against the ravages of Mother
Nature.

Some 90% of all presidentially declared disasters are weather related,
leading to around 500 deaths per year and nearly
$14 billion in damage.
StormReady, a program started in 1999 in Tulsa,
OK, helps arm America's communities with the communication
and safety skills needed to save lives and property– before and during the event.
StormReady helps community leaders
and emergency managers strengthen local safety programs.

StormReady communities are better prepared
to save lives from the onslaught of severe
weather through better planning, education, and awareness.
No community is storm proof,
but
StormReady can help communities save lives. Does StormReady make a difference?
#@+node:ekr.20071007121312.2: *6* before sel=1.0,9.7
Americans live in the most severe weather-prone country on Earth. Each year,
Americans cope with an average of 10,000 thunderstorms,
2,500 floods, 1,000
tornadoes, as well as an average of 6 deadly hurricanes.
Potentially deadly
weather impacts every American.
Communities can now rely on the National Weather
Service’s StormReady program to help them guard against the ravages of Mother
Nature.

Some 90% of all presidentially declared disasters are weather related,
leading to around 500 deaths per year and nearly
$14 billion in damage.
StormReady, a program started in 1999 in Tulsa,
OK, helps arm America's communities with the communication
and safety skills needed to save lives and property– before and during the event.
StormReady helps community leaders
and emergency managers strengthen local safety programs.

StormReady communities are better prepared
to save lives from the onslaught of severe
weather through better planning, education, and awareness.
No community is storm proof,
but
StormReady can help communities save lives. Does StormReady make a difference?
#@+node:ekr.20071007121312.3: *6* after sel=6.7,6.7
Americans live in the most severe weather-prone country on Earth. Each year,
Americans cope with an average of 10,000 thunderstorms, 2,500 floods, 1,000
tornadoes, as well as an average of 6 deadly hurricanes. Potentially deadly
weather impacts every American. Communities can now rely on the National Weather
Service’s StormReady program to help them guard against the ravages of Mother
Nature.

Some 90% of all presidentially declared disasters are weather related,
leading to around 500 deaths per year and nearly
$14 billion in damage.
StormReady, a program started in 1999 in Tulsa,
OK, helps arm America's communities with the communication
and safety skills needed to save lives and property– before and during the event.
StormReady helps community leaders
and emergency managers strengthen local safety programs.

StormReady communities are better prepared
to save lives from the onslaught of severe
weather through better planning, education, and awareness.
No community is storm proof,
but
StormReady can help communities save lives. Does StormReady make a difference?
#@+node:ekr.20071007124202: *5* @@test fill-region (three paragraphs)
@pagewidth 80
    # Required for external unit test.

c.testManager.runEditCommandTest(p)
#@+node:ekr.20071007124202.1: *6* work
Americans live in the most severe weather-prone country on Earth. Each year,
Americans cope with an average of 10,000 thunderstorms, 2,500 floods, 1,000
tornadoes, as well as an average of 6 deadly hurricanes. Potentially deadly
weather impacts every American. Communities can now rely on the National Weather
Service’s StormReady program to help them guard against the ravages of Mother
Nature.

Some 90% of all presidentially declared disasters are weather related, leading
to around 500 deaths per year and nearly $14 billion in damage. StormReady, a
program started in 1999 in Tulsa, OK, helps arm America's communities with the
communication and safety skills needed to save lives and property– before and
during the event. StormReady helps community leaders and emergency managers
strengthen local safety programs.

StormReady communities are better prepared to save lives from the onslaught of
severe weather through better planning, education, and awareness. No community
is storm proof, but StormReady can help communities save lives. Does StormReady
make a difference?
#@+node:ekr.20071007124202.2: *6* before sel=1.0,24.78
Americans live in the most severe weather-prone country on Earth. Each year,
Americans cope with an average of 10,000 thunderstorms,
2,500 floods, 1,000
tornadoes, as well as an average of 6 deadly hurricanes.
Potentially deadly
weather impacts every American.
Communities can now rely on the National Weather
Service’s StormReady program to help them guard against the ravages of Mother
Nature.

Some 90% of all presidentially declared disasters are weather related,
leading to around 500 deaths per year and nearly
$14 billion in damage.
StormReady, a program started in 1999 in Tulsa,
OK, helps arm America's communities with the communication
and safety skills needed to save lives and property– before and during the event.
StormReady helps community leaders
and emergency managers strengthen local safety programs.

StormReady communities are better prepared
to save lives from the onslaught of severe
weather through better planning, education, and awareness.
No community is storm proof,
but
StormReady can help communities save lives. Does StormReady make a difference?
#@+node:ekr.20071007124202.3: *6* after sel=18.19,18.19
Americans live in the most severe weather-prone country on Earth. Each year,
Americans cope with an average of 10,000 thunderstorms, 2,500 floods, 1,000
tornadoes, as well as an average of 6 deadly hurricanes. Potentially deadly
weather impacts every American. Communities can now rely on the National Weather
Service’s StormReady program to help them guard against the ravages of Mother
Nature.

Some 90% of all presidentially declared disasters are weather related, leading
to around 500 deaths per year and nearly $14 billion in damage. StormReady, a
program started in 1999 in Tulsa, OK, helps arm America's communities with the
communication and safety skills needed to save lives and property– before and
during the event. StormReady helps community leaders and emergency managers
strengthen local safety programs.

StormReady communities are better prepared to save lives from the onslaught of
severe weather through better planning, education, and awareness. No community
is storm proof, but StormReady can help communities save lives. Does StormReady
make a difference?
#@+node:ekr.20061101121602.218: *5* @test fill-paragraph
@pagewidth 80
    # Required for external unit test.

c.testManager.runEditCommandTest(p)
#@+node:ekr.20061101121602.219: *6* work
Americans live in the most severe weather-prone country on Earth. Each year, Americans cope with an average of 10,000 thunderstorms, 2,500 floods, 1,000 tornadoes, as well as an average of 6 deadly hurricanes. Potentially deadly weather impacts every American. Communities can now rely on the National Weather Services StormReady program to help them guard against the ravages of Mother Nature.

Some 90% of all presidentially declared disasters are weather related, leading
to around 500 deaths per year and nearly $14 billion in damage. StormReady, a
program started in 1999 in Tulsa, OK, helps arm America's communities with the
communication and safety skills needed to save lives and property--before and
during the event. StormReady helps community leaders and emergency managers
strengthen local safety programs.

StormReady communities are better prepared to save lives from the onslaught of severe weather through better planning, education, and awareness. No community is storm proof, but StormReady can help communities save lives. Does StormReady make a difference?
#@+node:ekr.20061101121602.220: *6* before sel=3.0,3.7
Americans live in the most severe weather-prone country on Earth. Each year, Americans cope with an average of 10,000 thunderstorms, 2,500 floods, 1,000 tornadoes, as well as an average of 6 deadly hurricanes. Potentially deadly weather impacts every American. Communities can now rely on the National Weather Services StormReady program to help them guard against the ravages of Mother Nature.

Some 90% of all presidentially
declared disasters are weather related,
leading to around 500 deaths per year
and nearly $14 billion in damage.
StormReady, a program
started in 1999 in Tulsa, OK,
helps arm America's
communities with the communication and
safety skills needed to save lives and
property--before and during the event.
StormReady helps community leaders and
emergency managers strengthen local safety programs.

StormReady communities are better prepared to save lives from the onslaught of severe weather through better planning, education, and awareness. No community is storm proof, but StormReady can help communities save lives. Does StormReady make a difference?
#@+node:ekr.20061101121602.221: *6* after sel=8.33,8.33
Americans live in the most severe weather-prone country on Earth. Each year, Americans cope with an average of 10,000 thunderstorms, 2,500 floods, 1,000 tornadoes, as well as an average of 6 deadly hurricanes. Potentially deadly weather impacts every American. Communities can now rely on the National Weather Services StormReady program to help them guard against the ravages of Mother Nature.

Some 90% of all presidentially declared disasters are weather related, leading
to around 500 deaths per year and nearly $14 billion in damage. StormReady, a
program started in 1999 in Tulsa, OK, helps arm America's communities with the
communication and safety skills needed to save lives and property--before and
during the event. StormReady helps community leaders and emergency managers
strengthen local safety programs.

StormReady communities are better prepared to save lives from the onslaught of severe weather through better planning, education, and awareness. No community is storm proof, but StormReady can help communities save lives. Does StormReady make a difference?
#@+node:ekr.20061101121602.222: *5* @test forward-char
c.testManager.runEditCommandTest(p)
#@+node:ekr.20061101121602.223: *6* work
first line
line 1
    line a
        line b
line c
last line
#@+node:ekr.20061101121602.224: *6* before sel=1.2,1.2
first line
line 1
    line a
        line b
line c
last line
#@+node:ekr.20061101121602.225: *6* after sel=1.3,1.3
first line
line 1
    line a
        line b
line c
last line
#@+node:ekr.20061101121602.226: *5* @test forward-char-extend-selection
c.testManager.runEditCommandTest(p)
#@+node:ekr.20061101121602.227: *6* work
first line
line 1
    line a
        line b
line c
last line
#@+node:ekr.20061101121602.228: *6* before sel=1.1,1.1
first line
line 1
    line a
        line b
line c
last line
#@+node:ekr.20061101121602.229: *6* after sel=1.1,1.2
first line
line 1
    line a
        line b
line c
last line
#@+node:ekr.20061101121602.230: *5* @test forward-end-word (end of line)
c.testManager.runEditCommandTest(p)
#@+node:ekr.20061101121602.231: *6* work
Americans live in the most severe weather-prone country on Earth. Each year, Americans cope with an average of 10,000 thunderstorms, 2,500 floods, 1,000 tornadoes, as well as an average of 6 deadly hurricanes. Potentially deadly weather impacts every American. Communities can now rely on the National Weather Service’s StormReady program to help them guard against the ravages of Mother Nature.

Some 90% of all presidentially declared disasters are weather related, leading to around 500 deaths per year and nearly $14 billion in damage. StormReady, a program started in 1999 in Tulsa, OK, helps arm America's communities with the communication and safety skills needed to save lives and property– before and during the event. StormReady helps community leaders and emergency managers strengthen local safety programs.

StormReady communities are better prepared to save lives from the onslaught of severe weather through better planning, education, and awareness. No community is storm proof, but StormReady can help communities save lives. Does StormReady make a difference?
#@+node:ekr.20061101121602.232: *6* before sel=1.395,1.395
Americans live in the most severe weather-prone country on Earth. Each year, Americans cope with an average of 10,000 thunderstorms, 2,500 floods, 1,000 tornadoes, as well as an average of 6 deadly hurricanes. Potentially deadly weather impacts every American. Communities can now rely on the National Weather Service’s StormReady program to help them guard against the ravages of Mother Nature.

Some 90% of all presidentially declared disasters are weather related, leading to around 500 deaths per year and nearly $14 billion in damage. StormReady, a program started in 1999 in Tulsa, OK, helps arm America's communities with the communication and safety skills needed to save lives and property– before and during the event. StormReady helps community leaders and emergency managers strengthen local safety programs.

StormReady communities are better prepared to save lives from the onslaught of severe weather through better planning, education, and awareness. No community is storm proof, but StormReady can help communities save lives. Does StormReady make a difference?
#@+node:ekr.20061101121602.233: *6* after sel=3.4,3.4
Americans live in the most severe weather-prone country on Earth. Each year, Americans cope with an average of 10,000 thunderstorms, 2,500 floods, 1,000 tornadoes, as well as an average of 6 deadly hurricanes. Potentially deadly weather impacts every American. Communities can now rely on the National Weather Service’s StormReady program to help them guard against the ravages of Mother Nature.

Some 90% of all presidentially declared disasters are weather related, leading to around 500 deaths per year and nearly $14 billion in damage. StormReady, a program started in 1999 in Tulsa, OK, helps arm America's communities with the communication and safety skills needed to save lives and property– before and during the event. StormReady helps community leaders and emergency managers strengthen local safety programs.

StormReady communities are better prepared to save lives from the onslaught of severe weather through better planning, education, and awareness. No community is storm proof, but StormReady can help communities save lives. Does StormReady make a difference?
#@+node:ekr.20061101121602.234: *5* @test forward-end-word (start of word)
c.testManager.runEditCommandTest(p)
#@+node:ekr.20061101121602.235: *6* work
Americans live in the most severe weather-prone country on Earth. Each year, Americans cope with an average of 10,000 thunderstorms, 2,500 floods, 1,000 tornadoes, as well as an average of 6 deadly hurricanes. Potentially deadly weather impacts every American. Communities can now rely on the National Weather Service’s StormReady program to help them guard against the ravages of Mother Nature.

Some 90% of all presidentially declared disasters are weather related, leading to around 500 deaths per year and nearly $14 billion in damage. StormReady, a program started in 1999 in Tulsa, OK, helps arm America's communities with the communication and safety skills needed to save lives and property– before and during the event. StormReady helps community leaders and emergency managers strengthen local safety programs.

StormReady communities are better prepared to save lives from the onslaught of severe weather through better planning, education, and awareness. No community is storm proof, but StormReady can help communities save lives. Does StormReady make a difference?
#@+node:ekr.20061101121602.236: *6* before sel=1.310,1.310
Americans live in the most severe weather-prone country on Earth. Each year, Americans cope with an average of 10,000 thunderstorms, 2,500 floods, 1,000 tornadoes, as well as an average of 6 deadly hurricanes. Potentially deadly weather impacts every American. Communities can now rely on the National Weather Service’s StormReady program to help them guard against the ravages of Mother Nature.

Some 90% of all presidentially declared disasters are weather related, leading to around 500 deaths per year and nearly $14 billion in damage. StormReady, a program started in 1999 in Tulsa, OK, helps arm America's communities with the communication and safety skills needed to save lives and property– before and during the event. StormReady helps community leaders and emergency managers strengthen local safety programs.

StormReady communities are better prepared to save lives from the onslaught of severe weather through better planning, education, and awareness. No community is storm proof, but StormReady can help communities save lives. Does StormReady make a difference?
#@+node:ekr.20061101121602.237: *6* after sel=1.317,1.317
Americans live in the most severe weather-prone country on Earth. Each year, Americans cope with an average of 10,000 thunderstorms, 2,500 floods, 1,000 tornadoes, as well as an average of 6 deadly hurricanes. Potentially deadly weather impacts every American. Communities can now rely on the National Weather Service’s StormReady program to help them guard against the ravages of Mother Nature.

Some 90% of all presidentially declared disasters are weather related, leading to around 500 deaths per year and nearly $14 billion in damage. StormReady, a program started in 1999 in Tulsa, OK, helps arm America's communities with the communication and safety skills needed to save lives and property– before and during the event. StormReady helps community leaders and emergency managers strengthen local safety programs.

StormReady communities are better prepared to save lives from the onslaught of severe weather through better planning, education, and awareness. No community is storm proof, but StormReady can help communities save lives. Does StormReady make a difference?
#@+node:ekr.20061101121602.238: *5* @test forward-end-word-extend-selection
c.testManager.runEditCommandTest(p)
#@+node:ekr.20061101121602.239: *6* work
Americans live in the most severe weather-prone country on Earth. Each year, Americans cope with an average of 10,000 thunderstorms, 2,500 floods, 1,000 tornadoes, as well as an average of 6 deadly hurricanes. Potentially deadly weather impacts every American. Communities can now rely on the National Weather Service’s StormReady program to help them guard against the ravages of Mother Nature.

Some 90% of all presidentially declared disasters are weather related, leading to around 500 deaths per year and nearly $14 billion in damage. StormReady, a program started in 1999 in Tulsa, OK, helps arm America's communities with the communication and safety skills needed to save lives and property– before and during the event. StormReady helps community leaders and emergency managers strengthen local safety programs.

StormReady communities are better prepared to save lives from the onslaught of severe weather through better planning, education, and awareness. No community is storm proof, but StormReady can help communities save lives. Does StormReady make a difference?
#@+node:ekr.20061101121602.240: *6* before sel=3.20,3.20
Americans live in the most severe weather-prone country on Earth. Each year, Americans cope with an average of 10,000 thunderstorms, 2,500 floods, 1,000 tornadoes, as well as an average of 6 deadly hurricanes. Potentially deadly weather impacts every American. Communities can now rely on the National Weather Service’s StormReady program to help them guard against the ravages of Mother Nature.

Some 90% of all presidentially declared disasters are weather related, leading to around 500 deaths per year and nearly $14 billion in damage. StormReady, a program started in 1999 in Tulsa, OK, helps arm America's communities with the communication and safety skills needed to save lives and property– before and during the event. StormReady helps community leaders and emergency managers strengthen local safety programs.

StormReady communities are better prepared to save lives from the onslaught of severe weather through better planning, education, and awareness. No community is storm proof, but StormReady can help communities save lives. Does StormReady make a difference?
#@+node:ekr.20061101121602.241: *6* after sel=3.20,3.30
Americans live in the most severe weather-prone country on Earth. Each year, Americans cope with an average of 10,000 thunderstorms, 2,500 floods, 1,000 tornadoes, as well as an average of 6 deadly hurricanes. Potentially deadly weather impacts every American. Communities can now rely on the National Weather Service’s StormReady program to help them guard against the ravages of Mother Nature.

Some 90% of all presidentially declared disasters are weather related, leading to around 500 deaths per year and nearly $14 billion in damage. StormReady, a program started in 1999 in Tulsa, OK, helps arm America's communities with the communication and safety skills needed to save lives and property– before and during the event. StormReady helps community leaders and emergency managers strengthen local safety programs.

StormReady communities are better prepared to save lives from the onslaught of severe weather through better planning, education, and awareness. No community is storm proof, but StormReady can help communities save lives. Does StormReady make a difference?
#@+node:ekr.20061101121602.242: *5* @test forward-paragraph
c.testManager.runEditCommandTest(p)
#@+node:ekr.20061101121602.243: *6* work
Americans live in the most severe weather-prone country on Earth. Each year,
Americans cope with an average of 10,000 thunderstorms, 2,500 floods, 1,000
tornadoes, as well as an average of 6 deadly hurricanes. Potentially deadly
weather impacts every American. Communities can now rely on the National Weather
Service’s StormReady program to help them guard against the ravages of Mother
Nature.

Some 90% of all presidentially declared disasters are weather related, leading
to around 500 deaths per year and nearly $14 billion in damage. StormReady, a
program started in 1999 in Tulsa, OK, helps arm America's communities with the
communication and safety skills needed to save lives and property– before and
during the event. StormReady helps community leaders and emergency managers
strengthen local safety programs.

StormReady communities are better prepared to save lives from the onslaught of
severe weather through better planning, education, and awareness. No community
is storm proof, but StormReady can help communities save lives. Does StormReady
make a difference?
#@+node:ekr.20061101121602.244: *6* before sel=9.0,9.0
Americans live in the most severe weather-prone country on Earth. Each year,
Americans cope with an average of 10,000 thunderstorms, 2,500 floods, 1,000
tornadoes, as well as an average of 6 deadly hurricanes. Potentially deadly
weather impacts every American. Communities can now rely on the National Weather
Service’s StormReady program to help them guard against the ravages of Mother
Nature.

Some 90% of all presidentially declared disasters are weather related, leading
to around 500 deaths per year and nearly $14 billion in damage. StormReady, a
program started in 1999 in Tulsa, OK, helps arm America's communities with the
communication and safety skills needed to save lives and property– before and
during the event. StormReady helps community leaders and emergency managers
strengthen local safety programs.

StormReady communities are better prepared to save lives from the onslaught of
severe weather through better planning, education, and awareness. No community
is storm proof, but StormReady can help communities save lives. Does StormReady
make a difference?
#@+node:ekr.20061101121602.245: *6* after sel=15.0,15.0
Americans live in the most severe weather-prone country on Earth. Each year,
Americans cope with an average of 10,000 thunderstorms, 2,500 floods, 1,000
tornadoes, as well as an average of 6 deadly hurricanes. Potentially deadly
weather impacts every American. Communities can now rely on the National Weather
Service’s StormReady program to help them guard against the ravages of Mother
Nature.

Some 90% of all presidentially declared disasters are weather related, leading
to around 500 deaths per year and nearly $14 billion in damage. StormReady, a
program started in 1999 in Tulsa, OK, helps arm America's communities with the
communication and safety skills needed to save lives and property– before and
during the event. StormReady helps community leaders and emergency managers
strengthen local safety programs.

StormReady communities are better prepared to save lives from the onslaught of
severe weather through better planning, education, and awareness. No community
is storm proof, but StormReady can help communities save lives. Does StormReady
make a difference?
#@+node:ekr.20061101121602.246: *5* @test forward-paragraph-extend-selection
c.testManager.runEditCommandTest(p)
#@+node:ekr.20061101121602.247: *6* work
Americans live in the most severe weather-prone country on Earth. Each year,
Americans cope with an average of 10,000 thunderstorms, 2,500 floods, 1,000
tornadoes, as well as an average of 6 deadly hurricanes. Potentially deadly
weather impacts every American. Communities can now rely on the National Weather
Service’s StormReady program to help them guard against the ravages of Mother
Nature.

Some 90% of all presidentially declared disasters are weather related, leading
to around 500 deaths per year and nearly $14 billion in damage. StormReady, a
program started in 1999 in Tulsa, OK, helps arm America's communities with the
communication and safety skills needed to save lives and property– before and
during the event. StormReady helps community leaders and emergency managers
strengthen local safety programs.

StormReady communities are better prepared to save lives from the onslaught of
severe weather through better planning, education, and awareness. No community
is storm proof, but StormReady can help communities save lives. Does StormReady
make a difference?
#@+node:ekr.20061101121602.248: *6* before sel=10.0,10.0
Americans live in the most severe weather-prone country on Earth. Each year,
Americans cope with an average of 10,000 thunderstorms, 2,500 floods, 1,000
tornadoes, as well as an average of 6 deadly hurricanes. Potentially deadly
weather impacts every American. Communities can now rely on the National Weather
Service’s StormReady program to help them guard against the ravages of Mother
Nature.

Some 90% of all presidentially declared disasters are weather related, leading
to around 500 deaths per year and nearly $14 billion in damage. StormReady, a
program started in 1999 in Tulsa, OK, helps arm America's communities with the
communication and safety skills needed to save lives and property– before and
during the event. StormReady helps community leaders and emergency managers
strengthen local safety programs.

StormReady communities are better prepared to save lives from the onslaught of
severe weather through better planning, education, and awareness. No community
is storm proof, but StormReady can help communities save lives. Does StormReady
make a difference?
#@+node:ekr.20061101121602.249: *6* after sel=10.0,15.0
Americans live in the most severe weather-prone country on Earth. Each year,
Americans cope with an average of 10,000 thunderstorms, 2,500 floods, 1,000
tornadoes, as well as an average of 6 deadly hurricanes. Potentially deadly
weather impacts every American. Communities can now rely on the National Weather
Service’s StormReady program to help them guard against the ravages of Mother
Nature.

Some 90% of all presidentially declared disasters are weather related, leading
to around 500 deaths per year and nearly $14 billion in damage. StormReady, a
program started in 1999 in Tulsa, OK, helps arm America's communities with the
communication and safety skills needed to save lives and property– before and
during the event. StormReady helps community leaders and emergency managers
strengthen local safety programs.

StormReady communities are better prepared to save lives from the onslaught of
severe weather through better planning, education, and awareness. No community
is storm proof, but StormReady can help communities save lives. Does StormReady
make a difference?
#@+node:ekr.20061101121602.250: *5* @test forward-sentence
c.testManager.runEditCommandTest(p)
#@+node:ekr.20061101121602.251: *6* work
Americans live in the most severe weather-prone country on Earth. Each year, Americans cope with an average of 10,000 thunderstorms, 2,500 floods, 1,000 tornadoes, as well as an average of 6 deadly hurricanes. Potentially deadly weather impacts every American. Communities can now rely on the National Weather Service’s StormReady program to help them guard against the ravages of Mother Nature.

Some 90% of all presidentially declared disasters are weather related, leading to around 500 deaths per year and nearly $14 billion in damage. StormReady, a program started in 1999 in Tulsa, OK, helps arm America's communities with the communication and safety skills needed to save lives and property– before and during the event. StormReady helps community leaders and emergency managers strengthen local safety programs.

StormReady communities are better prepared to save lives from the onslaught of severe weather through better planning, education, and awareness. No community is storm proof, but StormReady can help communities save lives. Does StormReady make a difference?
#@+node:ekr.20061101121602.252: *6* before sel=3.17,3.17
Americans live in the most severe weather-prone country on Earth. Each year, Americans cope with an average of 10,000 thunderstorms, 2,500 floods, 1,000 tornadoes, as well as an average of 6 deadly hurricanes. Potentially deadly weather impacts every American. Communities can now rely on the National Weather Service’s StormReady program to help them guard against the ravages of Mother Nature.

Some 90% of all presidentially declared disasters are weather related, leading to around 500 deaths per year and nearly $14 billion in damage. StormReady, a program started in 1999 in Tulsa, OK, helps arm America's communities with the communication and safety skills needed to save lives and property– before and during the event. StormReady helps community leaders and emergency managers strengthen local safety programs.

StormReady communities are better prepared to save lives from the onslaught of severe weather through better planning, education, and awareness. No community is storm proof, but StormReady can help communities save lives. Does StormReady make a difference?
#@+node:ekr.20061101121602.253: *6* after sel=3.142,3.142
Americans live in the most severe weather-prone country on Earth. Each year, Americans cope with an average of 10,000 thunderstorms, 2,500 floods, 1,000 tornadoes, as well as an average of 6 deadly hurricanes. Potentially deadly weather impacts every American. Communities can now rely on the National Weather Service’s StormReady program to help them guard against the ravages of Mother Nature.

Some 90% of all presidentially declared disasters are weather related, leading to around 500 deaths per year and nearly $14 billion in damage. StormReady, a program started in 1999 in Tulsa, OK, helps arm America's communities with the communication and safety skills needed to save lives and property– before and during the event. StormReady helps community leaders and emergency managers strengthen local safety programs.

StormReady communities are better prepared to save lives from the onslaught of severe weather through better planning, education, and awareness. No community is storm proof, but StormReady can help communities save lives. Does StormReady make a difference?
#@+node:ekr.20061101121602.254: *5* @test forward-sentence-extend-selection
c.testManager.runEditCommandTest(p)
#@+node:ekr.20061101121602.255: *6* work
Americans live in the most severe weather-prone country on Earth. Each year, Americans cope with an average of 10,000 thunderstorms, 2,500 floods, 1,000 tornadoes, as well as an average of 6 deadly hurricanes. Potentially deadly weather impacts every American. Communities can now rely on the National Weather Service’s StormReady program to help them guard against the ravages of Mother Nature.

Some 90% of all presidentially declared disasters are weather related, leading to around 500 deaths per year and nearly $14 billion in damage. StormReady, a program started in 1999 in Tulsa, OK, helps arm America's communities with the communication and safety skills needed to save lives and property– before and during the event. StormReady helps community leaders and emergency managers strengthen local safety programs.

StormReady communities are better prepared to save lives from the onslaught of severe weather through better planning, education, and awareness. No community is storm proof, but StormReady can help communities save lives. Does StormReady make a difference?
#@+node:ekr.20061101121602.256: *6* before sel=1.264,1.264
Americans live in the most severe weather-prone country on Earth. Each year, Americans cope with an average of 10,000 thunderstorms, 2,500 floods, 1,000 tornadoes, as well as an average of 6 deadly hurricanes. Potentially deadly weather impacts every American. Communities can now rely on the National Weather Service’s StormReady program to help them guard against the ravages of Mother Nature.

Some 90% of all presidentially declared disasters are weather related, leading to around 500 deaths per year and nearly $14 billion in damage. StormReady, a program started in 1999 in Tulsa, OK, helps arm America's communities with the communication and safety skills needed to save lives and property– before and during the event. StormReady helps community leaders and emergency managers strengthen local safety programs.

StormReady communities are better prepared to save lives from the onslaught of severe weather through better planning, education, and awareness. No community is storm proof, but StormReady can help communities save lives. Does StormReady make a difference?
#@+node:ekr.20061101121602.257: *6* after sel=1.264,1.395
Americans live in the most severe weather-prone country on Earth. Each year, Americans cope with an average of 10,000 thunderstorms, 2,500 floods, 1,000 tornadoes, as well as an average of 6 deadly hurricanes. Potentially deadly weather impacts every American. Communities can now rely on the National Weather Service’s StormReady program to help them guard against the ravages of Mother Nature.

Some 90% of all presidentially declared disasters are weather related, leading to around 500 deaths per year and nearly $14 billion in damage. StormReady, a program started in 1999 in Tulsa, OK, helps arm America's communities with the communication and safety skills needed to save lives and property– before and during the event. StormReady helps community leaders and emergency managers strengthen local safety programs.

StormReady communities are better prepared to save lives from the onslaught of severe weather through better planning, education, and awareness. No community is storm proof, but StormReady can help communities save lives. Does StormReady make a difference?
#@+node:ekr.20061101121602.258: *5* @test forward-word
c.testManager.runEditCommandTest(p)
#@+node:ekr.20061101121602.259: *6* work
Americans live in the most severe weather-prone country on Earth. Each year, Americans cope with an average of 10,000 thunderstorms, 2,500 floods, 1,000 tornadoes, as well as an average of 6 deadly hurricanes. Potentially deadly weather impacts every American. Communities can now rely on the National Weather Service’s StormReady program to help them guard against the ravages of Mother Nature.

Some 90% of all presidentially declared disasters are weather related, leading to around 500 deaths per year and nearly $14 billion in damage. StormReady, a program started in 1999 in Tulsa, OK, helps arm America's communities with the communication and safety skills needed to save lives and property– before and during the event. StormReady helps community leaders and emergency managers strengthen local safety programs.

StormReady communities are better prepared to save lives from the onslaught of severe weather through better planning, education, and awareness. No community is storm proof, but StormReady can help communities save lives. Does StormReady make a difference?
#@+node:ekr.20061101121602.260: *6* before sel=1.261,1.261
Americans live in the most severe weather-prone country on Earth. Each year, Americans cope with an average of 10,000 thunderstorms, 2,500 floods, 1,000 tornadoes, as well as an average of 6 deadly hurricanes. Potentially deadly weather impacts every American. Communities can now rely on the National Weather Service’s StormReady program to help them guard against the ravages of Mother Nature.

Some 90% of all presidentially declared disasters are weather related, leading to around 500 deaths per year and nearly $14 billion in damage. StormReady, a program started in 1999 in Tulsa, OK, helps arm America's communities with the communication and safety skills needed to save lives and property– before and during the event. StormReady helps community leaders and emergency managers strengthen local safety programs.

StormReady communities are better prepared to save lives from the onslaught of severe weather through better planning, education, and awareness. No community is storm proof, but StormReady can help communities save lives. Does StormReady make a difference?
#@+node:ekr.20061101121602.261: *6* after sel=1.273,1.273
Americans live in the most severe weather-prone country on Earth. Each year, Americans cope with an average of 10,000 thunderstorms, 2,500 floods, 1,000 tornadoes, as well as an average of 6 deadly hurricanes. Potentially deadly weather impacts every American. Communities can now rely on the National Weather Service’s StormReady program to help them guard against the ravages of Mother Nature.

Some 90% of all presidentially declared disasters are weather related, leading to around 500 deaths per year and nearly $14 billion in damage. StormReady, a program started in 1999 in Tulsa, OK, helps arm America's communities with the communication and safety skills needed to save lives and property– before and during the event. StormReady helps community leaders and emergency managers strengthen local safety programs.

StormReady communities are better prepared to save lives from the onslaught of severe weather through better planning, education, and awareness. No community is storm proof, but StormReady can help communities save lives. Does StormReady make a difference?
#@+node:ekr.20061101121602.262: *5* @test forward-word-extend-selection
c.testManager.runEditCommandTest(p)
#@+node:ekr.20061101121602.263: *6* work
Americans live in the most severe weather-prone country on Earth. Each year, Americans cope with an average of 10,000 thunderstorms, 2,500 floods, 1,000 tornadoes, as well as an average of 6 deadly hurricanes. Potentially deadly weather impacts every American. Communities can now rely on the National Weather Service’s StormReady program to help them guard against the ravages of Mother Nature.

Some 90% of all presidentially declared disasters are weather related, leading to around 500 deaths per year and nearly $14 billion in damage. StormReady, a program started in 1999 in Tulsa, OK, helps arm America's communities with the communication and safety skills needed to save lives and property– before and during the event. StormReady helps community leaders and emergency managers strengthen local safety programs.

StormReady communities are better prepared to save lives from the onslaught of severe weather through better planning, education, and awareness. No community is storm proof, but StormReady can help communities save lives. Does StormReady make a difference?
#@+node:ekr.20061101121602.264: *6* before sel=1.395,1.395
Americans live in the most severe weather-prone country on Earth. Each year, Americans cope with an average of 10,000 thunderstorms, 2,500 floods, 1,000 tornadoes, as well as an average of 6 deadly hurricanes. Potentially deadly weather impacts every American. Communities can now rely on the National Weather Service’s StormReady program to help them guard against the ravages of Mother Nature.

Some 90% of all presidentially declared disasters are weather related, leading to around 500 deaths per year and nearly $14 billion in damage. StormReady, a program started in 1999 in Tulsa, OK, helps arm America's communities with the communication and safety skills needed to save lives and property– before and during the event. StormReady helps community leaders and emergency managers strengthen local safety programs.

StormReady communities are better prepared to save lives from the onslaught of severe weather through better planning, education, and awareness. No community is storm proof, but StormReady can help communities save lives. Does StormReady make a difference?
#@+node:ekr.20061101121602.265: *6* after sel=1.395,3.0
Americans live in the most severe weather-prone country on Earth. Each year, Americans cope with an average of 10,000 thunderstorms, 2,500 floods, 1,000 tornadoes, as well as an average of 6 deadly hurricanes. Potentially deadly weather impacts every American. Communities can now rely on the National Weather Service’s StormReady program to help them guard against the ravages of Mother Nature.

Some 90% of all presidentially declared disasters are weather related, leading to around 500 deaths per year and nearly $14 billion in damage. StormReady, a program started in 1999 in Tulsa, OK, helps arm America's communities with the communication and safety skills needed to save lives and property– before and during the event. StormReady helps community leaders and emergency managers strengthen local safety programs.

StormReady communities are better prepared to save lives from the onslaught of severe weather through better planning, education, and awareness. No community is storm proof, but StormReady can help communities save lives. Does StormReady make a difference?
#@+node:ekr.20070305095401: *5* @test goNext/PrevVisitedNode
p = c.p.copy()
c.selectPosition(p.threadBack())
p1 = c.p
# print(p1)
c.goPrevVisitedNode()
p2 = c.p
# print(p2)
c.goNextVisitedNode()
p3 = c.p
# print(p3)
# assert p == p3
#@+node:ekr.20100212104817.5351: *5* @test help-for-command
result = c.helpCommands.getBindingsForCommand('help')
assert result.strip().lower()=='f1'
#@+node:ekr.20061101121602.266: *5* @test indent-relative
c.testManager.runEditCommandTest(p)
#@+node:ekr.20061101121602.267: *6* work
first line
line 1
    line a
        line b
        line c
last line
#@+node:ekr.20061101121602.268: *6* before sel=5.0,5.0
first line
line 1
    line a
        line b
line c
last line
#@+node:ekr.20061101121602.269: *6* after sel=5.8,5.8
first line
line 1
    line a
        line b
        line c
last line
#@+node:ekr.20061101121602.270: *5* @test indent-rigidly
c.testManager.runEditCommandTest(p)
#@+node:ekr.20061101121602.271: *6* work
first line
	line 1
	    line a
	        line b
	line c
last line
#@+node:ekr.20061101121602.272: *6* before sel=2.0,5.0
first line
line 1
    line a
        line b
line c
last line
#@+node:ekr.20061101121602.273: *6* after sel=2.0,5.1
first line
	line 1
	    line a
	        line b
	line c
last line
#@+node:ekr.20071007120750.5: *5* @test indent-to-comment-column
c.editCommands.ccolumn = 4 # Set the comment column
c.testManager.runEditCommandTest(p)
#@+node:ekr.20071007121312.5: *6* work
first line
    line b
last line
#@+node:ekr.20071007121312.6: *6* before sel=2.0,2.0
first line
line b
last line
#@+node:ekr.20071007121312.7: *6* after sel=2.4,2.4
first line
    line b
last line
#@+node:ekr.20061101121602.274: *5* @test insert-newline
c.testManager.runEditCommandTest(p)
#@+node:ekr.20061101121602.275: *6* work
first li
ne
line 1
    line a
        line b
line c
last line
#@+node:ekr.20061101121602.276: *6* before sel=1.8,1.8
first line
line 1
    line a
        line b
line c
last line
#@+node:ekr.20061101121602.277: *6* after sel=2.0,2.0
first li
ne
line 1
    line a
        line b
line c
last line
#@+node:ekr.20061101121602.278: *5* @test insert-parentheses
c.testManager.runEditCommandTest(p)
#@+node:ekr.20061101121602.279: *6* work
first() line
line 1
    line a
        line b
line c
last line
#@+node:ekr.20061101121602.280: *6* before sel=1.5,1.5
first line
line 1
    line a
        line b
line c
last line
#@+node:ekr.20061101121602.281: *6* after sel=1.6,1.6
first() line
line 1
    line a
        line b
line c
last line
#@+node:ekr.20061101121602.282: *5* @test kill-paragraph
c.testManager.runEditCommandTest(p)
#@+node:ekr.20061101121602.283: *6* work
Americans live in the most severe weather-prone country on Earth. Each year,
Americans cope with an average of 10,000 thunderstorms, 2,500 floods, 1,000
tornadoes, as well as an average of 6 deadly hurricanes. Potentially deadly
weather impacts every American. Communities can now rely on the National Weather
Service’s StormReady program to help them guard against the ravages of Mother
Nature.



StormReady communities are better prepared to save lives from the onslaught of
severe weather through better planning, education, and awareness. No community
is storm proof, but StormReady can help communities save lives. Does StormReady
make a difference?
#@+node:ekr.20061101121602.285: *6* before sel=9.0,9.0
Americans live in the most severe weather-prone country on Earth. Each year,
Americans cope with an average of 10,000 thunderstorms, 2,500 floods, 1,000
tornadoes, as well as an average of 6 deadly hurricanes. Potentially deadly
weather impacts every American. Communities can now rely on the National Weather
Service’s StormReady program to help them guard against the ravages of Mother
Nature.

Some 90% of all presidentially declared disasters are weather related, leading
to around 500 deaths per year and nearly $14 billion in damage. StormReady, a
program started in 1999 in Tulsa, OK, helps arm America's communities with the
communication and safety skills needed to save lives and property– before and
during the event. StormReady helps community leaders and emergency managers
strengthen local safety programs.

StormReady communities are better prepared to save lives from the onslaught of
severe weather through better planning, education, and awareness. No community
is storm proof, but StormReady can help communities save lives. Does StormReady
make a difference?
#@+node:ekr.20061101121602.284: *6* after sel=8.0,8.0
Americans live in the most severe weather-prone country on Earth. Each year,
Americans cope with an average of 10,000 thunderstorms, 2,500 floods, 1,000
tornadoes, as well as an average of 6 deadly hurricanes. Potentially deadly
weather impacts every American. Communities can now rely on the National Weather
Service’s StormReady program to help them guard against the ravages of Mother
Nature.



StormReady communities are better prepared to save lives from the onslaught of
severe weather through better planning, education, and awareness. No community
is storm proof, but StormReady can help communities save lives. Does StormReady
make a difference?
#@+node:ekr.20070131172706: *5* @test kill-sentence
c.testManager.runEditCommandTest(p)
#@+node:ekr.20070131172706.1: *6* work
This is the first sentence.  And
this is the last sentence.
#@+node:ekr.20070131172706.2: *6* before sel=2.2,2.2
This is the first sentence.  This
is the second sentence.  And
this is the last sentence.
#@+node:ekr.20070131172706.3: *6* after sel=1.27,1.27
This is the first sentence.  And
this is the last sentence.
#@+node:ekr.20081215084144.7: *5* @test kill-word
c.testManager.runEditCommandTest(p)
#@+node:ekr.20081215084144.8: *6* work
This is the first sentence.  This
is the  sentence.  And
this is the last sentence.
#@+node:ekr.20081215084144.9: *6* before sel=2.6,2.6
This is the first sentence.  This
is the second sentence.  And
this is the last sentence.
#@+node:ekr.20081215084144.10: *6* after sel=2.7,2.7
This is the first sentence.  This
is the  sentence.  And
this is the last sentence.
#@+node:ekr.20110610122533.3369: *5* goto-global-line tests
#@+node:ekr.20100212072149.5341: *6* @test c.goToScriptLineNumber
child = g.findNodeInChildren(c, p, 'syntax-error')
assert child, 'no child'
try:
    c.goToScriptLineNumber(1, child)
finally:
    p.contract()
    c.selectPosition(p)
    c.redraw()
#@+node:ekr.20100212072149.5342: *7* syntax-error
@language python
def spam:
    pass
#@+node:ekr.20150626101920.1: *6* @test find_file_line: @auto-md
import sys
# Not valid for external tests: uses @<file> node.
if g.app.isExternalUnitTest:
    self.skipTest('Can not be run externally')
elif sys.platform.startswith('win'):
    trace = False
    h = '@auto unittest/at-auto-md-line-number-test.md'
    root = g.findNodeAnywhere(c, h)
    assert root
    s = c.gotoCommands.get_external_file_with_sentinels(root)
    if trace:
        g.cls()
        print(''.join(['%3s %s' % (i, s) for i, s in enumerate(g.splitLines(s))]))
    for n in range(20):
        p, offset, found = c.gotoCommands.find_file_line(n, p=root)
        if found:
            if trace: print('found: %2s %2s %s' % (n, offset, p and p.h))
        else:
            if trace: print('not found: %s' % n)
            assert n == 7, n
            break
else:
    self.skipTest('Skip on Linux')
#@+node:ekr.20150626101643.1: *6* @test find_file_line: @auto-org
# Not valid for external tests: uses @<file> node.
if g.app.isExternalUnitTest:
    self.skipTest('Can not be run externally')
else:
    trace = False
    h = '@auto-org unittest/at-auto-org-line-number-test.py'
    root = g.findNodeAnywhere(c, h)
    assert root
    s = c.gotoCommands.get_external_file_with_sentinels(root)
    if trace:
        g.cls()
        print(''.join(['%3s %s' % (i, s) for i, s in enumerate(g.splitLines(s))]))
    for n in range(20):
        p, offset, found = c.gotoCommands.find_file_line(n, p=root)
        if found:
            if trace: print('found: %2s %2s %s' % (n, offset, p and p.h))
        else:
            if trace: print('not found: %s' % n)
            assert n == 5, n
            break
#@+node:ekr.20150626100652.1: *6* @test find_file_line: @auto-otl
# Not valid for external tests: uses @<file> node.
if g.app.isExternalUnitTest:
    self.skipTest('Can not be run externally')
else:
    trace = False
    h = '@auto-otl unittest/at-auto-otl-line-number-test.py'
    root = g.findNodeAnywhere(c, h)
    assert root
    s = c.gotoCommands.get_external_file_with_sentinels(root)
    if trace:
        g.cls()
        print(''.join(['%3s %s' % (i, s) for i, s in enumerate(g.splitLines(s))]))
    for n in range(20):
        p, offset, found = c.gotoCommands.find_file_line(n, p=root)
        if found:
            if trace: print('found: %2s %2s %s' % (n, offset, p and p.h))
        else:
            if trace: print('not found: %s' % n)
            assert n == 5, n
            break
#@+node:ekr.20150625101047.1: *6* @test find_file_line: @auto-py
import sys
# Not valid for external tests: uses @<file> node.
if g.app.isExternalUnitTest:
    self.skipTest('Can not be run externally')
elif sys.platform.startswith('win'):
    trace = False
    root = p.parent().parent()
    # h = '@auto unittest/at-auto-line-number-test.py'
    h = '@auto unittest/at-auto-unit-test.py'
    target = g.findNodeAnywhere(c, h)
    assert target, 'no target'
    s = c.gotoCommands.get_external_file_with_sentinels(target)
    if trace:
        g.cls()
        print(''.join(['%3s %s' % (i, s) for i, s in enumerate(g.splitLines(s))]))
    for n in range(25):
        p, offset, found = c.gotoCommands.find_file_line(n, p=target)
        if found:
            if trace: print('found %2s %2s %s' % (n, offset, p and p.h))
        else:
            assert n == 13, n
            if trace: print('not found: %s' % n)
            break
else:
    self.skipTest('Skip on Linux')
#@+node:ekr.20150626093653.1: *6* @@test find_file_line: @auto-rst
# Not valid for external tests: uses @<file> node.
if g.app.isExternalUnitTest:
    self.skipTest('Can not be run externally')
else:
    trace = True
    h = '@auto-rst unittest/at-auto-rst-line-number-test.py'
    root = g.findNodeAnywhere(c, h)
    assert root
    assert root.isAtAutoRstNode(), root
    s = c.gotoCommands.get_external_file_with_sentinels(root)
    if trace:
        g.cls()
        print('get_external_file_with_sentinels returns...')
        # print(''.join(['%3s %r' % (i, s) for i, s in enumerate(g.splitLines(s))]))
        g.printList(g.splitLines(s))
    for n in range(20):
        p, offset, found = c.gotoCommands.find_file_line(n, p=root)
        if found:
            if trace: print('found: %2s %2s %s' % (n, offset, p and p.h))
        else:
            if trace: print('not found: %s' % n)
            assert n == 9, n
            break
#@+node:ekr.20160403143643.1: *6* @@test find_file_line: @clean-c
# Not valid for external tests: uses @<file> node.
if g.app.isExternalUnitTest:
    self.skipTest('Can not be run externally')
else:
    trace = False
    root = p.parent().parent()
    h = '@clean unittest/at-clean-line-number-test.c'
    target = g.findNodeAnywhere(c, h)
    assert target, 'no target'
    s = c.gotoCommands.get_external_file_with_sentinels(target)
    lines = g.splitLines(s)
    g.printList(lines)
    stripped_lines = [z for z in lines if not z.startswith('//@')]
    g.printList(stripped_lines)
    if trace:
        g.cls()
        print(''.join(['%3s %s' % (i, s) for i, s in enumerate(lines)]))
    table = (
        # n is the 1-based offset
        (3, 4,  '// before @others // line 1'),
        (2, 8,  'def spam(): // line 2'),
        (3, 9,  '    pass'),
        (1, 11, 'def eggs(): // line 4'),
        (2, 12, '    pass'),
        (5, 14, '// last line: line 6'),
    )
    for i, data in enumerate(table):
        expected_offset, target_offset, expected_line = data
        p, offset, found = c.gotoCommands.find_file_line(i+1, p=target)
        assert expected_offset == offset, (
            'i: %s expected offset %s, got %s' % (i, expected_offset, offset))
        expected_line = expected_line.rstrip()
        got_line = stripped_lines[i].rstrip()
        assert expected_line == got_line, 'i: %s expected line:\n%s\ngot line:\n%s' % (
            i, expected_line, got_line)
        got_line2 = lines[target_offset].rstrip()
        assert expected_line == got_line2, 'i: %s expected line:\n%s\ngot line2:\n%s' % (
            i, expected_line, got_line)
    i = len(table)
    p, offset, found = c.gotoCommands.find_file_line(i+1, p=target)
    assert not found
#@+node:ekr.20160403143655.1: *6* @@test find_file_line: @clean-python
# Not valid for external tests: uses @<file> node.
if g.app.isExternalUnitTest:
    self.skipTest('Can not be run externally')
else:
    trace = False
    root = p.parent().parent()
    h = '@clean unittest/at-clean-line-number-test.py'
    target = g.findNodeAnywhere(c, h)
    assert target, 'no target'
    s = c.gotoCommands.get_external_file_with_sentinels(target)
    lines = g.splitLines(s)
    stripped_lines = [z for z in lines if not z.startswith('#@')]
    if trace:
        print(''.join(['%3s %s' % (i, s) for i, s in enumerate(lines)]))
        # print('')
        # print(''.join(['%3s %s' % (i, s) for i, s in enumerate(stripped_lines)]))
    table = (
        # n is the 1-based offset
        (3, 4,  '# Before @others: line 1'),
        (2, 8,  'def spam(): # line 2'),
        (3, 9,  '    pass'),
        (1, 11, 'def eggs(): # line 4'),
        (2, 12, '    pass'),
        (5, 14, '# Last line: line 6'),
    )
    for i, data in enumerate(table):
        expected_offset, target_offset, expected_line = data
        p, offset, found = c.gotoCommands.find_file_line(i+1, p=target)
        assert expected_offset == offset, (
            'i: %s expected offset %s, got %s' % (i, expected_offset, offset))
        expected_line = expected_line.rstrip()
        got_line = stripped_lines[i].rstrip()
        assert expected_line == got_line, 'i: %s expected line:\n%s\ngot line:\n%s' % (
            i, expected_line, got_line)
        got_line2 = lines[target_offset].rstrip()
        assert expected_line == got_line2, 'i: %s expected line:\n%s\ngot line2:\n%s' % (
            i, expected_line, got_line)
    i = len(table)
    p, offset, found = c.gotoCommands.find_file_line(i+1, p=target)
    assert not found
#@+node:ekr.20160403123650.1: *6* @test find_file_line: @file-c
# Not valid for external tests: uses @<file> node.
if g.app.isExternalUnitTest:
    self.skipTest('Can not be run externally')
else:
    trace = False
    root = p.parent().parent()
    h = '@file unittest/at-file-line-number-test.c'
    target = g.findNodeAnywhere(c, h)
    assert target, 'no target'
    s = c.gotoCommands.get_external_file_with_sentinels(target)
    if trace:
        g.cls()
        print(''.join(['%3s %s' % (i, s) for i, s in enumerate(g.splitLines(s))]))
    for n in range(20):
        p, offset, found = c.gotoCommands.find_file_line(n, p=target)
        if found:
            if trace: print('found %2s %2s %s' % (n, offset, p and p.h))
        else:
            assert n == 10, n
            if trace: print('not found: %s' % n)
            break
#@+node:ekr.20110610122533.3395: *6* @test find_file_line: @file-python
# Not valid for external tests: uses @<file> node.
if g.app.isExternalUnitTest:
    self.skipTest('Can not be run externally')
else:
    trace = False
    root = p.parent().parent()
    h = '@file unittest/at-file-line-number-test.py'
    target = g.findNodeAnywhere(c, h)
    assert target, 'no target'
    s = c.gotoCommands.get_external_file_with_sentinels(target)
    if trace:
        g.cls()
        print(''.join(['%3s %s' % (i, s) for i, s in enumerate(g.splitLines(s))]))
    for n in range(20):
        p, offset, found = c.gotoCommands.find_file_line(n, p=target)
        if found:
            if trace: print('found %2s %2s %s' % (n, offset, p and p.h))
        else:
            assert n == 10, n
            if trace: print('not found: %s' % n)
            break
#@+node:ekr.20110610122533.3399: *6* @test find_file_line: @nosent-python
# Not valid for external tests: uses @<file> node.
if g.app.isExternalUnitTest:
    self.skipTest('Can not be run externally')
else:
    trace = False
    h = '@nosent unittest/at-nosent-line-number-test.py'
    root = g.findNodeAnywhere(c, h)
    assert root
    assert root.isAtNoSentFileNode(), root
    s = c.gotoCommands.get_external_file_with_sentinels(root)
    if trace:
        g.cls()
        print(''.join(['%3s %s' % (i, s) for i, s in enumerate(g.splitLines(s))]))
    for n in range(20):
        p, offset, found = c.gotoCommands.find_file_line(n, p=root)
        if found:
            if trace: print('found: %2s %2s %s' % (n, offset, p and p.h))
        else:
            if trace: print('not found: %s' % n)
            assert n == 7, n
            break
#@+node:ekr.20110610122533.3394: *6* @test find_gnx @file
# Not valid for external tests: uses @<file> node.
if g.app.isExternalUnitTest:
    self.skipTest('Can not be run externally')
else:
    root = p.parent().parent()
    h = '@file unittest/at-file-line-number-test.py'
    target = g.findNodeAnywhere(c, h)
    assert target, 'no target'
    gnx = target.v.fileIndex
    assert gnx
    found = c.gotoCommands.find_gnx(root, gnx, h)
    assert found, 'not found'
#@+node:ekr.20110610122533.3404: *6* @test goto_show_results not found
c.gotoCommands.success(lines=['a', 'b'], n=3, n2=3, p=p)
c.gotoCommands.fail(lines=['a', 'b'], n=3, root=p)

#@+node:ekr.20130918043621.4172: *5* kill-line tests
#@+node:ekr.20130918051958.4176: *6* @test kill-line end-body-text
# First, we must remove the trailing newline from the 'after' line.
h = 'after sel=3.6,3.6'
p2 = g.findNodeInTree(c,p,h)
assert p2,h
s = p2.b
if s.endswith('\n'):
    p2.b = p2.b[:-1]
c.testManager.runEditCommandTest(p)
#@+node:ekr.20130918051958.4177: *7* work
line 1
line 2
line 3
#@+node:ekr.20130918051958.4178: *7* before sel=4.1,4.1
line 1
line 2
line 3
#@+node:ekr.20130918051958.4179: *7* after sel=3.6,3.6
line 1
line 2
line 3
#@+node:ekr.20061128090338: *6* @test kill-line end-line-text
c.testManager.runEditCommandTest(p)
#@+node:ekr.20061128090338.1: *7* work
line 1
line 2

#@+node:ekr.20061128090338.2: *7* before sel=3.5,3.5
line 1
line 2
line 3
#@+node:ekr.20061128090338.3: *7* after sel=3.0,3.0
line 1
line 2

#@+node:ekr.20061128090021: *6* @test kill-line start-line
c.testManager.runEditCommandTest(p)
#@+node:ekr.20061128090021.1: *7* work
line 1
line 2

line 4
#@+node:ekr.20061128090021.2: *7* before sel=3.0,3.0
line 1
line 2
line 3
line 4
#@+node:ekr.20061128090021.3: *7* after sel=3.0,3.0
line 1
line 2

line 4
#@+node:ekr.20061128090147: *6* @test kill-line start-blank-line
c.testManager.runEditCommandTest(p)
#@+node:ekr.20061128090147.1: *7* work
line 1
line 2
line 4
#@+node:ekr.20061128090147.2: *7* before sel=3.0,3.0
line 1
line 2

line 4
#@+node:ekr.20061128090147.3: *7* after sel=3.0,3.0
line 1
line 2
line 4
#@+node:ekr.20130918043621.4190: *5* kill-to-end-of-line tests
#@+node:ekr.20130918043621.4195: *6* @test kill-to-end-of-line end-body-text
# First, we must remove the trailing newline from the 'after' line.
h = 'after sel=3.6,3.6'
p2 = g.findNodeInTree(c,p,h)
assert p2,h
s = p2.b
if s.endswith('\n'):
    p2.b = p2.b[:-1]
c.testManager.runEditCommandTest(p)
#@+node:ekr.20130918043621.4196: *7* work
line 1
line 2
line 3
#@+node:ekr.20130918043621.4197: *7* before sel=4.1,4.1
line 1
line 2
line 3
#@+node:ekr.20130918043621.4198: *7* after sel=3.6,3.6
line 1
line 2
line 3
#@+node:ekr.20130918050446.4202: *6* @test kill-to-end-of-line end-line
c.testManager.runEditCommandTest(p)
#@+node:ekr.20130918050446.4203: *7* work
line 1
line 2line 3
#@+node:ekr.20130918050446.4204: *7* before sel=2.6,2.6
line 1
line 2
line 3
#@+node:ekr.20130918050446.4205: *7* after sel=2.6,2.6
line 1
line 2line 3
#@+node:ekr.20130918052416.4180: *6* @test kill-to-end-of-line after last visible char
c.testManager.runEditCommandTest(p)
#@+node:ekr.20130918052416.4181: *7* work
line 1
# The next line contains two trailing blanks.
line 3line 4
#@+node:ekr.20130918052416.4182: *7* before sel=3.6,3.6
line 1
# The next line contains two trailing blanks.
line 3  
line 4
#@+node:ekr.20130918052416.4183: *7* after sel=3.6,3.6
line 1
# The next line contains two trailing blanks.
line 3line 4
#@+node:ekr.20130918043621.4199: *6* @test kill-to-end-of-line start-line
c.testManager.runEditCommandTest(p)
#@+node:ekr.20130918043621.4200: *7* work
line 1
line 2

line 4
#@+node:ekr.20130918043621.4201: *7* before sel=3.0,3.0
line 1
line 2
line 3
line 4
#@+node:ekr.20130918043621.4202: *7* after sel=3.0,3.0
line 1
line 2

line 4
#@+node:ekr.20130918050446.4210: *6* @test kill-to-end-of-line start-blank-line
c.testManager.runEditCommandTest(p)
#@+node:ekr.20130918050446.4211: *7* work
line 1
line 2
line 4
#@+node:ekr.20130918050446.4212: *7* before sel=3.0,3.0
line 1
line 2

line 4
#@+node:ekr.20130918050446.4213: *7* after sel=3.0,3.0
line 1
line 2
line 4
#@+node:ekr.20130918043621.4203: *6* @test kill-to-end-of-line middle-line
c.testManager.runEditCommandTest(p)
#@+node:ekr.20130918043621.4204: *7* work
line 1
li
line 3
#@+node:ekr.20130918043621.4205: *7* before sel=2.2,2.2
line 1
line 2
line 3
#@+node:ekr.20130918043621.4206: *7* after sel=2.2,2.2
line 1
li
line 3
#@+node:ekr.20070131175646: *4*  Commands M-Z
#@+node:ekr.20070131171218.1: *5* @@test zap-to-chararacter
#@+node:ekr.20070131171218.2: *6* work
first line
line 1
    line a
        line b
line c
last line
#@+node:ekr.20061101121602.286: *5* @test move-lines-down
c.testManager.runEditCommandTest(p)
#@+node:ekr.20061101121602.287: *6* work
first line
line 1
line c
    line a
        line b
last line
#@+node:ekr.20061101121602.288: *6* before sel=3.3,4.3
first line
line 1
    line a
        line b
line c
last line
#@+node:ekr.20061101121602.289: *6* after sel=4.3,5.3
first line
line 1
line c
    line a
        line b
last line
#@+node:ekr.20061101121602.290: *5* @test move-lines-up
c.testManager.runEditCommandTest(p)
#@+node:ekr.20061101121602.291: *6* work
line 1
first line
    line a
        line b
line c
last line
#@+node:ekr.20061101121602.292: *6* before sel=2.2,2.2
first line
line 1
    line a
        line b
line c
last line
#@+node:ekr.20061101121602.293: *6* after sel=1.2,1.2
line 1
first line
    line a
        line b
line c
last line
#@+node:ekr.20120306201833.3942: *5* @test move-lines-up (into docstring)
# Test of bug 799695: colorizer bug after move-lines-up into a docstring

# import os ; os.system('cls')

n = c.frame.body.colorizer.full_recolor_count

c.testManager.runEditCommandTest(p)

# Not an effective test, even though the bug fix was to call
# c.recolor_now(incremental=False)

# g.trace(n,c.frame.body.colorizer.full_recolor_count)

# assert c.frame.body.colorizer.full_recolor_count > n
#@+node:ekr.20120306201833.3943: *6* work
@language python
def test():
    """ a
    b
    c
    print 1
    """
    
    print 2
#@+node:ekr.20120306201833.3944: *6* before sel=7.1,7.1
@language python
def test():
    """ a
    b
    c
    """
    print 1
    
    print 2
#@+node:ekr.20120306201833.3945: *6* after sel=6.1,6.1
@language python
def test():
    """ a
    b
    c
    print 1
    """
    
    print 2
#@+node:ekr.20111006064419.3493: *5* @test move-marked-nodes
if g.app.isExternalUnitTest:
    self.skipTest('Can not be run externally')
else:

    exec(g.findTestScript(c,'@common x-marked-nodes test code'))
    
    def test(p):
        setup_test(p)
        n = p.numberOfChildren()
        assert n == 4 ,'delete: children: %s' % (n)
        c.moveMarked()
        assert c.p.h == 'Moved marked nodes'
        n = p.numberOfChildren()
        assert n == 2 ,'delete: children: %s' % (n)
        if 0:
            # The new move-marked-nodes command doesn't
            # leave the result in the root node.
            root = c.rootPosition()
            assert root.h == 'Moved marked nodes',root.h
        if 0: # The move-marked-nodes command is no longer undoable.
            c.undoer.undo()
            n = p.numberOfChildren()
            assert n == 4,'undo: children: %s' % (n)
            c.undoer.redo()
            n = p.numberOfChildren()
            assert n == 2 ,'delete: children: %s' % (n)
    try:
        test(p)
    finally:
        tear_down(p,'Moved marked nodes')
#@+node:ekr.20061101121602.294: *5* @test move-past-close
c.testManager.runEditCommandTest(p)
#@+node:ekr.20061101121602.295: *6* work
first (line)
line 1
    line a
        line b
line c
last line
#@+node:ekr.20061101121602.296: *6* before sel=1.10,1.10
first (line)
line 1
    line a
        line b
line c
last line
#@+node:ekr.20061101121602.297: *6* after sel=1.12,1.12
first (line)
line 1
    line a
        line b
line c
last line
#@+node:ekr.20061101121602.298: *5* @test move-past-close-extend-selection
c.testManager.runEditCommandTest(p)
#@+node:ekr.20061101121602.299: *6* work
first line
line 1
    (line )a
        line b
line c
last line
#@+node:ekr.20061101121602.300: *6* before sel=3.7,3.7
first line
line 1
    (line )a
        line b
line c
last line
#@+node:ekr.20061101121602.301: *6* after sel=3.7,3.11
first line
line 1
    (line )a
        line b
line c
last line
#@+node:ekr.20061101121602.302: *5* @test newline-and-indent
c.testManager.runEditCommandTest(p)
#@+node:ekr.20061101121602.303: *6* work
first line
line 1
    
    line a
        line b
line c
last line
#@+node:ekr.20061101121602.304: *6* before sel=2.6,2.6
first line
line 1
    line a
        line b
line c
last line
#@+node:ekr.20061101121602.305: *6* after sel=3.4,3.4
first line
line 1
    
    line a
        line b
line c
last line
#@+node:ekr.20070315065720: *5* @test next-line
c.testManager.runEditCommandTest(p)
#@+node:ekr.20070315065720.1: *6* work
a

b
#@+node:ekr.20070315065720.2: *6* before sel=1.1,1.1
a

b
#@+node:ekr.20070315065720.3: *6* after sel=2.0,2.0
a

b
#@+node:ekr.20070315065849: *5* @test previous-line
c.testManager.runEditCommandTest(p)
#@+node:ekr.20070315065849.1: *6* work
a

b
#@+node:ekr.20070315065849.2: *6* before sel=3.0,3.0
a

b
#@+node:ekr.20070315065849.3: *6* after sel=2.0,2.0
a

b
#@+node:ekr.20070217071121.1: *5* @test rectangle-clear
c.testManager.runEditCommandTest(p)
#@+node:ekr.20070217071121.2: *6* work
before
aaa   bbb
aaa   bbb
aaa   bbb
aaa   bbb
after
#@+node:ekr.20070217071121.3: *6* before sel=2.3,5.6
before
aaaxxxbbb
aaaxxxbbb
aaaxxxbbb
aaaxxxbbb
after
#@+node:ekr.20070217071121.4: *6* after sel=2.3,5.6
before
aaa   bbb
aaa   bbb
aaa   bbb
aaa   bbb
after
#@+node:ekr.20070217071121.5: *5* @test rectangle-close
c.testManager.runEditCommandTest(p)
#@+node:ekr.20070217071121.6: *6* work
before
aaabbb
aaabbb
aaabbb
aaabbb
after
#@+node:ekr.20070217071121.7: *6* before sel=2.3,5.6
before
aaa   bbb
aaa   bbb
aaa   bbb
aaa   bbb
after
#@+node:ekr.20070217071121.8: *6* after sel=2.3,5.3
before
aaabbb
aaabbb
aaabbb
aaabbb
after
#@+node:ekr.20070217071121.9: *5* @test rectangle-delete
c.testManager.runEditCommandTest(p)
#@+node:ekr.20070217071121.10: *6* work
before
aaabbb
aaabbb
aaabbb
aaabbb
after
#@+node:ekr.20070217071121.11: *6* before sel=2.3,5.6
before
aaaxxxbbb
aaaxxxbbb
aaaxxxbbb
aaaxxxbbb
after
#@+node:ekr.20070217071121.12: *6* after sel=2.3,5.3
before
aaabbb
aaabbb
aaabbb
aaabbb
after
#@+node:ekr.20070217071121.17: *5* @test rectangle-kill
c.testManager.runEditCommandTest(p)
#@+node:ekr.20070217071121.18: *6* work
before
aaabbb
aaabbb
aaabbb
aaabbb
after
#@+node:ekr.20070217071121.19: *6* before sel=2.3,5.6
before
aaaxxxbbb
aaaxxxbbb
aaaxxxbbb
aaaxxxbbb
after
#@+node:ekr.20070217071121.20: *6* after sel=5.3,5.3
before
aaabbb
aaabbb
aaabbb
aaabbb
after
#@+node:ekr.20070217071121.13: *5* @test rectangle-open
c.testManager.runEditCommandTest(p)
#@+node:ekr.20070217071121.14: *6* work
before
aaa   xxxbbb
aaa   xxxbbb
aaa   xxxbbb
aaa   xxxbbb
after
#@+node:ekr.20070217071121.15: *6* before sel=2.3,5.6
before
aaaxxxbbb
aaaxxxbbb
aaaxxxbbb
aaaxxxbbb
after
#@+node:ekr.20070217071121.16: *6* after sel=2.3,5.6
before
aaa   xxxbbb
aaa   xxxbbb
aaa   xxxbbb
aaa   xxxbbb
after
#@+node:ekr.20070217071121.21: *5* @test rectangle-string
c.testManager.runEditCommandTest(p)
#@+node:ekr.20070217071121.22: *6* work
before
aaas...sbbb
aaas...sbbb
aaas...sbbb
aaas...sbbb
after
#@+node:ekr.20070217071121.23: *6* before sel=2.3,5.6
before
aaaxxxbbb
aaaxxxbbb
aaaxxxbbb
aaaxxxbbb
after
#@+node:ekr.20070217071121.24: *6* after sel=2.3,5.8
before
aaas...sbbb
aaas...sbbb
aaas...sbbb
aaas...sbbb
after
#@+node:ekr.20070217071121.25: *5* @test rectangle-yank
c.testManager.runEditCommandTest(p)
#@+node:ekr.20070217071121.26: *6* work
before
aaaY1Ybbb
aaaY2Ybbb
aaaY3Ybbb
aaaY4Ybbb
after
#@+node:ekr.20070217071121.28: *6* before sel=2.3,5.6
before
aaaxxxbbb
aaaxxxbbb
aaaxxxbbb
aaaxxxbbb
after
#@+node:ekr.20070217071121.27: *6* after sel=2.3,5.6
before
aaaY1Ybbb
aaaY2Ybbb
aaaY3Ybbb
aaaY4Ybbb
after
#@+node:ekr.20061101121602.306: *5* @test remove-blank-lines
c.testManager.runEditCommandTest(p)
#@+node:ekr.20061101121602.307: *6* work
first line
line 1
    line a
        line b
line c
last line
#@+node:ekr.20061101121602.308: *6* before sel=1.0,9.0
first line

line 1
    line a
        line b

line c
last line
#@+node:ekr.20061101121602.309: *6* after sel=1.0,6.9
first line
line 1
    line a
        line b
line c
last line
#@+node:ekr.20061101121602.310: *5* @test remove-space-from-lines
c.testManager.runEditCommandTest(p)
#@+node:ekr.20061101121602.311: *6* work
first line

line 1
   line a
       line b

line c
last line
#@+node:ekr.20061101121602.312: *6* before sel=1.0,9.0
first line

line 1
    line a
        line b

line c
last line
#@+node:ekr.20061101121602.313: *6* after sel=1.0,9.0
first line

line 1
   line a
       line b

line c
last line
#@+node:ekr.20061101121602.314: *5* @test remove-tab-from-lines
c.testManager.runEditCommandTest(p)
#@+node:ekr.20061101121602.315: *6* work
first line
line 1
line a
    line b
line c
last line
#@+node:ekr.20061101121602.316: *6* before sel=1.0,7.0
first line
line 1
    line a
        line b
line c
last line
#@+node:ekr.20061101121602.317: *6* after sel=1.0,7.0
first line
line 1
line a
    line b
line c
last line
#@+node:ekr.20061101121602.318: *5* @test reverse-region
c.testManager.runEditCommandTest(p)
#@+node:ekr.20061101121602.319: *6* work

last line
line c
        line b
    line a
line 1
first line
#@+node:ekr.20061101121602.320: *6* before sel=1.0,7.0
first line
line 1
    line a
        line b
line c
last line
#@+node:ekr.20061101121602.321: *6* after sel=7.10,7.10

last line
line c
        line b
    line a
line 1
first line
#@+node:ekr.20071113081247: *5* @test reverse-sort-lines
c.testManager.runEditCommandTest(p)
#@+node:ekr.20071113081247.1: *6* work
z
x
e
d
a
#@+node:ekr.20071113081247.2: *6* before sel=1.0,5.1
a
d
e
z
x
#@+node:ekr.20071113081247.3: *6* after sel=1.0,5.1
z
x
e
d
a
#@+node:ekr.20071113082531: *5* @test reverse-sort-lines-ignoring-case
c.testManager.runEditCommandTest(p)
#@+node:ekr.20071113082531.1: *6* work
z
Y
X
c
b
A
#@+node:ekr.20071113082531.2: *6* before sel=1.0,6.1
c
A
z
X
Y
b
#@+node:ekr.20071113082531.3: *6* after sel=1.0,6.1
z
Y
X
c
b
A
#@+node:ekr.20071113145804.4: *5* @test selfInsertCommand-1
@first # -*- coding: utf-8 -*-
@language python

try:
    ec = c.editCommands ; w = c.frame.body.wrapper
    s = w.getAllText()

    # This strings tests unicode, paren matching, and auto-indentation.
    u = g.u('(a\u00c9\u03a9B\u3045\u4e7cz):\n') # '(aÉ©BE|cz):\n'
    u = g.u('(pdq):\n')
    w.setInsertPoint(len(s))
    for char in u:
        stroke = g.choose(char=='\n','Return',char)
        event = g.app.gui.create_key_event(c,char,stroke,w)
        ec.selfInsertCommand(event)
    result = w.getAllText()
    #g.trace('result',repr(result))
    assert result.endswith('    '),'result:\n%s' % result
    # Test of autocompleter.
finally:
    if 1:
        w.setAllText(s)
        p.setBodyString(s)
        # g.trace(repr(s))
        c.recolor()

# end:
#@+node:ekr.20071113145804.5: *5* @test selfInsertCommand-2 (replacing tabs)
@language python
@tabwidth -4

try:
    ec = c.editCommands ; w = c.frame.body.wrapper
    s = w.getAllText()
    w.setSelectionRange(len(s)-9,len(s)-6)
    event = g.app.gui.create_key_event(c,'\t','Tab',w)
    ec.selfInsertCommand(event)
    result = w.getAllText()
    # print('result %s' % result)
    assert result.endswith('\n    ###abcdef\n'),'result\n%s' % (repr(result))
finally:
    w.setAllText(s)
    p.setBodyString(s)
    c.recolor_now()
    
###abcdef
#@+node:ekr.20071007120750.6: *5* @test set-fill-prefix
# xxxx.yyyy

s = p.b
w = c.frame.body.wrapper
w.setSelectionRange(2,11)
c.editCommands.setFillPrefix(event=None)
prefix = c.editCommands.fillPrefix
assert prefix == 'xxxx.yyyy',repr(prefix)
#@+node:ekr.20061101121602.322: *5* @test sort-columns
c.testManager.runEditCommandTest(p)
#@+node:ekr.20061101121602.323: *6* work
        line b
    line a
first line
last line
line 1
line c
#@+node:ekr.20061101121602.324: *6* before sel=1.0,6.2
first line
line 1
    line a
        line b
line c
last line
#@+node:ekr.20061101121602.325: *6* after sel=1.0,7.0
        line b
    line a
first line
last line
line 1
line c
#@+node:ekr.20061101121602.326: *5* @test sort-lines
c.testManager.runEditCommandTest(p)
#@+node:ekr.20061101121602.327: *6* work
first line
        line b
    line a
line 1
line c
last line
#@+node:ekr.20061101121602.328: *6* before sel=2.0,5.6
first line
line 1
    line a
        line b
line c
last line
#@+node:ekr.20061101121602.329: *6* after sel=2.0,5.6
first line
        line b
    line a
line 1
line c
last line
#@+node:ekr.20071113081247.8: *5* @test sort-lines-ignoring-case
c.testManager.runEditCommandTest(p)
#@+node:ekr.20071113081247.9: *6* work
A
B
c
x
z
#@+node:ekr.20071113081247.10: *6* before sel=1.0,5.1
x
z
A
c
B
#@+node:ekr.20071113081247.11: *6* after sel=1.0,5.1
A
B
c
x
z
#@+node:ekr.20100212104817.5346: *5* @test sort-recent-files (new)
c.sortRecentFiles()
#@+node:ekr.20100212104817.5347: *5* @test sort-siblings (new)
child = p.firstChild()
assert child.h == 'b','fail 1'
try:
    c.selectPosition(child)
    c.sortSiblings()
    c.redraw_now()
    child = p.firstChild()
    assert child.h == 'a'
    child = child.next()
    assert child.h == 'b'
    child = child.next()
    assert child.h == 'c'
    assert not child.next()
finally:
    c.undoer.undo()
    p.contract()
    c.redraw(p)
#@+node:ekr.20100212104817.5348: *6* b
#@+node:ekr.20100212104817.5349: *6* a
#@+node:ekr.20100212104817.5350: *6* c
#@+node:ekr.20061101121602.330: *5* @test split-line
c.testManager.runEditCommandTest(p)
#@+node:ekr.20061101121602.331: *6* work
first
 line
line 1
    line a
        line b
line c
last line
#@+node:ekr.20061101121602.332: *6* before sel=1.5,1.5
first line
line 1
    line a
        line b
line c
last line
#@+node:ekr.20061101121602.333: *6* after sel=2.0,2.0
first
 line
line 1
    line a
        line b
line c
last line
#@+node:ekr.20061101121602.334: *5* @test tabify
c.testManager.runEditCommandTest(p)
#@+node:ekr.20061101121602.335: *6* work
first line
line 1
	line a
		line b
line c
last line
#@+node:ekr.20061101121602.336: *6* before sel=1.0,7.0
first line
line 1
    line a
        line b
line c
last line
#@+node:ekr.20061101121602.337: *6* after sel=7.0,7.0
first line
line 1
	line a
		line b
line c
last line
#@+node:ekr.20061101121602.338: *5* @test transpose-chars
c.testManager.runEditCommandTest(p)
#@+node:ekr.20061101121602.339: *6* work
frist line
line 1
    line a
        line b
line c
last line
#@+node:ekr.20061101121602.340: *6* before sel=1.2,1.2
first line
line 1
    line a
        line b
line c
last line
#@+node:ekr.20061101121602.341: *6* after sel=1.2,1.2
frist line
line 1
    line a
        line b
line c
last line
#@+node:ekr.20061101121602.342: *5* @test transpose-lines
c.testManager.runEditCommandTest(p)
#@+node:ekr.20061101121602.343: *6* work
line 1
first line
    line a
        line b
line c
last line
#@+node:ekr.20061101121602.344: *6* before sel=2.2,2.2
first line
line 1
    line a
        line b
line c
last line
#@+node:ekr.20061101121602.345: *6* after sel=2.10,2.10
line 1
first line
    line a
        line b
line c
last line
#@+node:ekr.20160314133351.1: *5* @test transpose-words
c.testManager.runEditCommandTest(p)
#@+node:ekr.20160314133351.2: *6* work
first line
before foo += bar2 after
last line
#@+node:ekr.20160314133351.3: *6* before sel=2.9,2.9
first line
before bar2 += foo after
last line
#@+node:ekr.20160314133351.4: *6* after sel=2.11,2.11
first line
before foo += bar2 after
last line
#@+node:ekr.20121016134831.3906: *5* @test typescript-to-python
import leo.core.leoBeautify as leoBeautify
cpp = leoBeautify.CPrettyPrinter(c)
# ts2p = c.convertCommands.TS_To_Python(c)
fn = 'typescript tokenize test'
p2 = g.findNodeInTree(c,p,fn)
assert p2,'not found: %s' % (fn)
aList = cpp.tokenize(p2.b)
assert aList
# bts2p.convertCodeList(aList)
# s = ''.join(aList)
#@+node:ekr.20121016134831.3907: *6* typescript tokenize test
@language javascript

public attemptIncrementalUpdateUnit(previousScript: Script,scriptId: string,newSourceText: ISourceText,editRange: ScriptEditRange): UpdateUnitResult
    self.logger.log("attemptIncrementalUpdateUnit(\"" + scriptId + "\")")
    if editRange === None:
        throw Error("editRange should be valid")
    var scope1 = self.getEnclosingScopeContextIfSingleScopeEdit(previousScript,scriptId,newSourceText,editRange)
    if scope1 === None:
        return None
    var newScopeLength = scope1.scopeStartAST.limChar - scope1.scopeStartAST.minChar + editRange.delta
    # Heuristic: if the range to reparse is too big,bail out.
    # This is because a full parse will be faster than an incremental parse followed by all the necessary fix-ups
    if newScopeLength >= newSourceText.getLength()/ 2:
        self.logger.log("  Bailing out because range of scope to reparse(" + newScopeLength + " characters)is greater than half the size of the source text")
        return None
    # Capture parsing errors so that they are part of "updateResult"
    var parseErrors: TypeScript.ErrorEntry:[] = []
    var errorCapture = function(minChar: number,charLen: number,message: string,unitIndex: number): void
        parseErrors.push(TypeScript.ErrorEntry:(unitIndex,minChar,minChar + charLen,message))
    var quickParseResult = TypeScript.quickParse(self.logger,scope1.scopeStartAST,newSourceText,scope1.scopeStartAST.minChar,scope1.scopeStartAST.minChar + newScopeLength,errorCapture)
    if quickParseResult.endLexState != TypeScript.LexState.Start:
        self.logger.log("  Bailing out because scope contains unterminated comment")
        return None
    var scriptFragment = quickParseResult.Script
    if scriptFragment.vars.members.length !== 0:
        self.logger.log("  Bailing out because new source text defines variables")
        return None
    #if(scriptFragment.scopes.members.length !== 1)
    #    logger.log("  Bailing out because new source text defines more than one scope(or none)");
    #    return null;
    #
    # This detects adding close curlies,since they have the side effect of having the parser
    # parse more members in the scope range.
    if scriptFragment.bod.members.length !== 1:
        self.logger.log("  Bailing out because new source text defines more than one scope(or none)")
        return None
    var oldScope = scope1.scopeStartAST
    var newScope = scriptFragment.bod.members[0]
    if oldScope.nodeType != newScope.nodeType:
        self.logger.log("  Bailing out because new source text does not define the same scope type as the existing scope")
        return None
    if not (<any>oldScope).leftCurlyCount or not (<any>oldScope).rightCurlyCount:
        self.logger.log("  Bailing out because sopce doesn't have left/right curly count")
        return None
    if(<any>oldScope).leftCurlyCount !==(<any>newScope).leftCurlyCount:
        self.logger.log("  Bailing out because new source text contains more(or fewer)left curly braces")
        return None
    if(<any>oldScope).rightCurlyCount !==(<any>newScope).rightCurlyCount:
        self.logger.log("  Bailing out because new source text contains more(or fewer)right curly braces")
        return None
    if newScope.minChar !== 0:
        self.logger.log("  Bailing out because new function declaration does not start at position 0")
        return None
    if newScope.limChar !== newScopeLength:
        self.logger.log("  Bailing out because new function declaration does not end at the new end position")
        return None
    return TypeScript.UpdateUnitResult.singleScopeEdits(previousScript,scriptFragment,oldScope,newScope,editRange,parseErrors)
#@+node:ekr.20061101121602.346: *5* @test untabify
c.testManager.runEditCommandTest(p)
#@+node:ekr.20061101121602.347: *6* work
first line
line 1
    line a
        line b
line c
last line
#@+node:ekr.20061101121602.348: *6* before sel=1.0,7.0
first line
line 1
	line a
		line b
line c
last line
#@+node:ekr.20061101121602.349: *6* after sel=7.0,7.0
first line
line 1
    line a
        line b
line c
last line
#@+node:ekr.20061101121602.350: *5* @test upcase-region
c.testManager.runEditCommandTest(p)
assert g.app.unitTestDict.get('colorized')
#@+node:ekr.20061101121602.351: *6* work
Americans live in the most severe weather-prone country on Earth. Each year, Americans cope with an average of 10,000 thunderstorms, 2,500 floods, 1,000 tornadoes, as well as an average of 6 deadly hurricanes. Potentially deadly weather impacts every American. Communities can now rely on the National Weather Service’s StormReady program to help them guard against the ravages of Mother Nature.

SOME 90% OF ALL PRESIDENTIALLY DECLARED DISASTERS ARE WEATHER RELATED, LEADING TO AROUND 500 DEATHS PER YEAR AND NEARLY $14 BILLION IN DAMAGE. STORMREADY, A PROGRAM STARTED IN 1999 IN TULSA, OK, HELPS ARM AMERICA'S COMMUNITIES WITH THE COMMUNICATION AND SAFETY SKILLS NEEDED TO SAVE LIVES AND PROPERTY– BEFORE AND DURING THE EVENT. STORMREADY HELPS COMMUNITY LEADERS AND EMERGENCY MANAGERS STRENGTHEN LOCAL SAFETY PROGRAMS.

StormReady communities are better prepared to save lives from the onslaught of severe weather through better planning, education, and awareness. No community is storm proof, but StormReady can help communities save lives. Does StormReady make a difference?
#@+node:ekr.20061101121602.352: *6* before sel=3.0,4.0
Americans live in the most severe weather-prone country on Earth. Each year, Americans cope with an average of 10,000 thunderstorms, 2,500 floods, 1,000 tornadoes, as well as an average of 6 deadly hurricanes. Potentially deadly weather impacts every American. Communities can now rely on the National Weather Service’s StormReady program to help them guard against the ravages of Mother Nature.

Some 90% of all presidentially declared disasters are weather related, leading to around 500 deaths per year and nearly $14 billion in damage. StormReady, a program started in 1999 in Tulsa, OK, helps arm America's communities with the communication and safety skills needed to save lives and property– before and during the event. StormReady helps community leaders and emergency managers strengthen local safety programs.

StormReady communities are better prepared to save lives from the onslaught of severe weather through better planning, education, and awareness. No community is storm proof, but StormReady can help communities save lives. Does StormReady make a difference?
#@+node:ekr.20061101121602.353: *6* after sel=3.0,4.0
Americans live in the most severe weather-prone country on Earth. Each year, Americans cope with an average of 10,000 thunderstorms, 2,500 floods, 1,000 tornadoes, as well as an average of 6 deadly hurricanes. Potentially deadly weather impacts every American. Communities can now rely on the National Weather Service’s StormReady program to help them guard against the ravages of Mother Nature.

SOME 90% OF ALL PRESIDENTIALLY DECLARED DISASTERS ARE WEATHER RELATED, LEADING TO AROUND 500 DEATHS PER YEAR AND NEARLY $14 BILLION IN DAMAGE. STORMREADY, A PROGRAM STARTED IN 1999 IN TULSA, OK, HELPS ARM AMERICA'S COMMUNITIES WITH THE COMMUNICATION AND SAFETY SKILLS NEEDED TO SAVE LIVES AND PROPERTY– BEFORE AND DURING THE EVENT. STORMREADY HELPS COMMUNITY LEADERS AND EMERGENCY MANAGERS STRENGTHEN LOCAL SAFETY PROGRAMS.

StormReady communities are better prepared to save lives from the onslaught of severe weather through better planning, education, and awareness. No community is storm proof, but StormReady can help communities save lives. Does StormReady make a difference?
#@+node:ekr.20061101121602.354: *5* @test upcase-word
c.testManager.runEditCommandTest(p)
assert g.app.unitTestDict.get('colorized')
#@+node:ekr.20061101121602.355: *6* work
first line
line 1
    LINE a
        line b
line c
last line
#@+node:ekr.20061101121602.356: *6* before sel=3.7,3.7
first line
line 1
    line a
        line b
line c
last line
#@+node:ekr.20061101121602.357: *6* after sel=3.7,3.7
first line
line 1
    LINE a
        line b
line c
last line
#@+node:ekr.20110118082508.3729: *5* reformat-paragraph tests
#@+node:ekr.20110118082508.3793: *6* @test reformat-paragraph list 1 of 5
# Required when running tests externally
@language plain
@pagewidth 40
@tabwidth 8

c.testManager.runEditCommandTest(p)
#@+node:ekr.20110118082508.3799: *7* work
This paragraph leads of this test. It is
the "lead" paragraph.

  1. This is item 
     number 1.  It is the first item in the list.

  2. This is item 
     number 2.  It is the second item in the list.

  3. This is item 
     number 3.  It is the third item in the list.

This paragraph ends the test.  It is the "final"
paragraph.
#@+node:ekr.20110118082508.3800: *7* before sel=1.0,1.0
This paragraph leads of this test.  It is the "lead"
paragraph.

  1. This is item 
     number 1.  It is the first item in the list.

  2. This is item 
     number 2.  It is the second item in the list.

  3. This is item 
     number 3.  It is the third item in the list.

This paragraph ends the test.  It is the "final"
paragraph.
#@+node:ekr.20110118082508.3803: *7* after sel=2.21,2.21
This paragraph leads of this test. It is
the "lead" paragraph.

  1. This is item 
     number 1.  It is the first item in the list.

  2. This is item 
     number 2.  It is the second item in the list.

  3. This is item 
     number 3.  It is the third item in the list.

This paragraph ends the test.  It is the "final"
paragraph.
#@+node:ekr.20110118082508.3808: *6* @test reformat-paragraph list 2 of 5
# Required when running tests externally
@language plain
@pagewidth 40
@tabwidth 8

c.testManager.runEditCommandTest(p)
#@+node:ekr.20110118082508.3809: *7* work
This paragraph leads of this test. It is
the "lead" paragraph.

  1. This is item number 1. It is the
     first item in the list.

  2. This is item 
     number 2.  It is the second item in the list.

  3. This is item 
     number 3.  It is the third item in the list.

This paragraph ends the test.  It is the "final"
paragraph.
#@+node:ekr.20110118082508.3810: *7* before sel=4.0,4.0
This paragraph leads of this test. It is
the "lead" paragraph.

  1. This is item number 1. It is the
     first item in the list.

  2. This is item 
     number 2.  It is the second item in the list.

  3. This is item 
     number 3.  It is the third item in the list.

This paragraph ends the test.  It is the "final"
paragraph.
#@+node:ekr.20110118082508.3811: *7* after sel=7.0,7.0
This paragraph leads of this test. It is
the "lead" paragraph.

  1. This is item number 1. It is the
     first item in the list.

  2. This is item 
     number 2.  It is the second item in the list.

  3. This is item 
     number 3.  It is the third item in the list.

This paragraph ends the test.  It is the "final"
paragraph.
#@+node:ekr.20110118082508.3816: *6* @test reformat-paragraph list 3 of 5
# Required when running tests externally
@language plain
@pagewidth 40
@tabwidth 8

c.testManager.runEditCommandTest(p)
#@+node:ekr.20110118082508.3817: *7* work
This paragraph leads of this test. It is
the "lead" paragraph.

  1. This is item number 1. It is the
     first item in the list.

  2. This is item number 2. It is the
     second item in the list.

  3. This is item 
     number 3.  It is the third item in the list.

This paragraph ends the test.  It is the "final"
paragraph.
#@+node:ekr.20110118082508.3818: *7* before sel=7.0,7.0
This paragraph leads of this test. It is
the "lead" paragraph.

  1. This is item number 1. It is the
     first item in the list.

  2. This is item 
     number 2.  It is the second item in the list.

  3. This is item 
     number 3.  It is the third item in the list.

This paragraph ends the test.  It is the "final"
paragraph.
#@+node:ekr.20110118082508.3819: *7* after sel=8.29,8.29
This paragraph leads of this test. It is
the "lead" paragraph.

  1. This is item number 1. It is the
     first item in the list.

  2. This is item number 2. It is the
     second item in the list.

  3. This is item 
     number 3.  It is the third item in the list.

This paragraph ends the test.  It is the "final"
paragraph.
#@+node:ekr.20110118082508.3824: *6* @test reformat-paragraph list 4 of 5
# Required when running tests externally
@language plain
@pagewidth 40
@tabwidth 8

c.testManager.runEditCommandTest(p)
#@+node:ekr.20110118082508.3825: *7* work
This paragraph leads of this test. It is
the "lead" paragraph.

  1. This is item number 1. It is the
     first item in the list.

  2. This is item number 2. It is the
     second item in the list.

  3. This is item number 3. It is the
     third item in the list.

This paragraph ends the test.  It is the "final"
paragraph.
#@+node:ekr.20110118082508.3826: *7* before sel=10.0,10.0
This paragraph leads of this test. It is
the "lead" paragraph.

  1. This is item number 1. It is the
     first item in the list.

  2. This is item number 2. It is the
     second item in the list.

  3. This is item 
     number 3.  It is the third item in the list.

This paragraph ends the test.  It is the "final"
paragraph.
#@+node:ekr.20110118082508.3827: *7* after sel=11.28,11.28
This paragraph leads of this test. It is
the "lead" paragraph.

  1. This is item number 1. It is the
     first item in the list.

  2. This is item number 2. It is the
     second item in the list.

  3. This is item number 3. It is the
     third item in the list.

This paragraph ends the test.  It is the "final"
paragraph.
#@+node:ekr.20110118082508.3832: *6* @test reformat-paragraph list 5 of 5
# Required when running tests externally
@language plain
@pagewidth 40
@tabwidth 8

c.testManager.runEditCommandTest(p)
#@+node:ekr.20110118082508.3833: *7* work
This paragraph leads of this test. It is
the "lead" paragraph.

  1. This is item number 1. It is the
     first item in the list.

  2. This is item number 2. It is the
     second item in the list.

  3. This is item number 3. It is the
     third item in the list.

This paragraph ends the test. It is the
"final" paragraph.
#@+node:ekr.20110118082508.3834: *7* before sel=13.0,13.0
This paragraph leads of this test. It is
the "lead" paragraph.

  1. This is item number 1. It is the
     first item in the list.

  2. This is item number 2. It is the
     second item in the list.

  3. This is item number 3. It is the
     third item in the list.

This paragraph ends the test.  It is the "final"
paragraph.
#@+node:ekr.20110118082508.3835: *7* after sel=14.19,14.19
This paragraph leads of this test. It is
the "lead" paragraph.

  1. This is item number 1. It is the
     first item in the list.

  2. This is item number 2. It is the
     second item in the list.

  3. This is item number 3. It is the
     third item in the list.

This paragraph ends the test. It is the
"final" paragraph.
#@+node:ekr.20131103084038.4274: *6* @test reformat-paragraph new code 1 of 8
# Required when running tests externally
@language plain
@pagewidth 40
@tabwidth 8

c.testManager.runEditCommandTest(p)
#@+node:ekr.20131103084038.4275: *7* work
@pagewidth 40
'''
docstring.
'''
#@+node:ekr.20131103084038.4276: *7* before sel=1.0,1.0
@pagewidth 40
'''
docstring.
'''
#@+node:ekr.20131103084038.4277: *7* after sel=2.0,2.0
@pagewidth 40
'''
docstring.
'''
#@+node:ekr.20131103084038.4282: *6* @test reformat-paragraph new code 2 of 8
# Required when running tests externally
@language plain
@pagewidth 40
@tabwidth 8

c.testManager.runEditCommandTest(p)
#@+node:ekr.20131103084038.4283: *7* work
@pagewidth 40
'''
docstring.
'''
#@+node:ekr.20131103084038.4284: *7* before sel=2.0,2.0
@pagewidth 40
'''
docstring.
'''
#@+node:ekr.20131103084038.4285: *7* after sel=3.0,3.0
@pagewidth 40
'''
docstring.
'''
#@+node:ekr.20131103084038.4290: *6* @test reformat-paragraph new code 3 of 8
# Required when running tests externally
@language plain
@pagewidth 40
@tabwidth 8

c.testManager.runEditCommandTest(p)
#@+node:ekr.20131103084038.4291: *7* work
@pagewidth 40
'''
docstring. more docstring.
'''
#@+node:ekr.20131103084038.4292: *7* before sel=3.1,4.1
@pagewidth 40
'''
docstring.
more docstring.
'''
#@+node:ekr.20131103084038.4293: *7* after sel=3.26,3.26
@pagewidth 40
'''
docstring. more docstring.
'''
#@+node:ekr.20131103084038.4298: *6* @test reformat-paragraph new code 4 of 8
# Required when running tests externally
@language plain
@pagewidth 40
@tabwidth 8

c.testManager.runEditCommandTest(p)
#@+node:ekr.20131103084038.4299: *7* work
- Point 1. xxxxxxxxxxxxxxxxxxxxxxxxxxxx
  Line 11.
A. Point 2. xxxxxxxxxxxxxxxxxxxxxxxxxxx
#@+node:ekr.20131103084038.4300: *7* before sel=1.0,1.0
- Point 1. xxxxxxxxxxxxxxxxxxxxxxxxxxxx
Line 11.
A. Point 2. xxxxxxxxxxxxxxxxxxxxxxxxxxx
#@+node:ekr.20131103084038.4301: *7* after sel=2.10,2.10
- Point 1. xxxxxxxxxxxxxxxxxxxxxxxxxxxx
  Line 11.
A. Point 2. xxxxxxxxxxxxxxxxxxxxxxxxxxx
#@+node:ekr.20131103084038.4306: *6* @test reformat-paragraph new code 5 of 8
# Required when running tests externally
@language plain
@pagewidth 40
@tabwidth 8

c.testManager.runEditCommandTest(p)
#@+node:ekr.20131103084038.4307: *7* work
A. Point 2. xxxxxxxxxxxxxxxxxxxxxxxxxxx
   Line 22.
1. Point 3. xxxxxxxxxxxxxxxxxxxxxxxxxxx
#@+node:ekr.20131103084038.4308: *7* before sel=1.0,2.0
A. Point 2. xxxxxxxxxxxxxxxxxxxxxxxxxxx
  Line 22.
1. Point 3. xxxxxxxxxxxxxxxxxxxxxxxxxxx
#@+node:ekr.20131103084038.4309: *7* after sel=2.11,2.11
A. Point 2. xxxxxxxxxxxxxxxxxxxxxxxxxxx
   Line 22.
1. Point 3. xxxxxxxxxxxxxxxxxxxxxxxxxxx
#@+node:ekr.20131103084038.4314: *6* @test reformat-paragraph new code 6 of 8
# Required when running tests externally
@language plain
@pagewidth 40
@tabwidth 8

c.testManager.runEditCommandTest(p)
#@+node:ekr.20131103084038.4315: *7* work
1. Point 3. xxxxxxxxxxxxxxxxxxxxxxxxxxx
   Line 32.

2. Point 4  xxxxxxxxxxxxxxxxxxxxxxxxxxx
#@+node:ekr.20131103084038.4316: *7* before sel=1.0,1.0
1. Point 3. xxxxxxxxxxxxxxxxxxxxxxxxxxx
Line 32.

2. Point 4  xxxxxxxxxxxxxxxxxxxxxxxxxxx
#@+node:ekr.20131103084038.4317: *7* after sel=2.11,2.11
1. Point 3. xxxxxxxxxxxxxxxxxxxxxxxxxxx
   Line 32.

2. Point 4  xxxxxxxxxxxxxxxxxxxxxxxxxxx
#@+node:ekr.20131103084038.4322: *6* @test reformat-paragraph new code 7 of 8
# Required when running tests externally
@language plain
@pagewidth 40
@tabwidth 8

c.testManager.runEditCommandTest(p)
#@+node:ekr.20131103084038.4323: *7* work
1. Point 3. xxxxxxxxxxxxxxxxxxxxxxxxxxx
   Line 32.

2. Point 4 xxxxxxxxxxxxxxxxxxxxxxxxxxx
        Line 41.
#@+node:ekr.20131103084038.4324: *7* before sel=2.11,2.11
1. Point 3. xxxxxxxxxxxxxxxxxxxxxxxxxxx
   Line 32.

2. Point 4 xxxxxxxxxxxxxxxxxxxxxxxxxxx
        Line 41.
#@+node:ekr.20131103084038.4325: *7* after sel=3.1,3.1
1. Point 3. xxxxxxxxxxxxxxxxxxxxxxxxxxx
   Line 32.

2. Point 4 xxxxxxxxxxxxxxxxxxxxxxxxxxx
        Line 41.
#@+node:ekr.20131103084038.4330: *6* @test reformat-paragraph new code 8 of 8
# Required when running tests externally
@language plain
@pagewidth 40
@tabwidth 8

c.testManager.runEditCommandTest(p)
#@+node:ekr.20131103084038.4331: *7* work
2. Point 4 xxxxxxxxxxxxxxxxxxxxxxxxxxx
        Line 41.
#@+node:ekr.20131103084038.4332: *7* before sel=1.0,1.0
2. Point 4 xxxxxxxxxxxxxxxxxxxxxxxxxxx
        Line 41.
#@+node:ekr.20131103084038.4333: *7* after sel=3.0,3.0
2. Point 4 xxxxxxxxxxxxxxxxxxxxxxxxxxx
        Line 41.
#@+node:ekr.20110118082508.3766: *6* @test reformat-paragraph paragraph 1 of 3
# Required when running tests externally
@language plain
@pagewidth 40
@tabwidth 8

c.testManager.runEditCommandTest(p)
#@+node:ekr.20110118082508.3772: *7* work
Americans live in the most severe
weather-prone country on Earth. Each
year, Americans cope with an average of
10,000 thunderstorms, 2,500 floods,
1,000 tornadoes, as well as an average
of 6 deadly hurricanes. Potentially
deadly weather impacts every American.
Communities can now rely on the National
Weather Service’s StormReady program to
help them guard against the ravages of
Mother Nature.

Some 90% of all presidentially declared disasters are weather related, leading to around 500 deaths per year and nearly $14 billion in damage. StormReady, a program started in 1999 in Tulsa, OK, helps arm America's communities with the communication and safety skills needed to save lives and property– before and during the event. StormReady helps community leaders and emergency managers strengthen local safety programs.

StormReady communities are better prepared to save lives from the onslaught of severe weather through better planning, education, and awareness. No community is storm proof, but StormReady can help communities save lives. Does StormReady make a difference?

Last paragraph.
#@+node:ekr.20110118082508.3773: *7* before sel=1.0,1.0
Americans live in the most severe weather-prone country on Earth. Each year, Americans cope with an average of 10,000 thunderstorms, 2,500 floods, 1,000 tornadoes, as well as an average of 6 deadly hurricanes. Potentially deadly weather impacts every American. Communities can now rely on the National Weather Service’s StormReady program to help them guard against the ravages of Mother Nature.

Some 90% of all presidentially declared disasters are weather related, leading to around 500 deaths per year and nearly $14 billion in damage. StormReady, a program started in 1999 in Tulsa, OK, helps arm America's communities with the communication and safety skills needed to save lives and property– before and during the event. StormReady helps community leaders and emergency managers strengthen local safety programs.

StormReady communities are better prepared to save lives from the onslaught of severe weather through better planning, education, and awareness. No community is storm proof, but StormReady can help communities save lives. Does StormReady make a difference?

Last paragraph.
#@+node:ekr.20110118082508.3792: *7* after sel=11.14,11.14
Americans live in the most severe
weather-prone country on Earth. Each
year, Americans cope with an average of
10,000 thunderstorms, 2,500 floods,
1,000 tornadoes, as well as an average
of 6 deadly hurricanes. Potentially
deadly weather impacts every American.
Communities can now rely on the National
Weather Service’s StormReady program to
help them guard against the ravages of
Mother Nature.

Some 90% of all presidentially declared disasters are weather related, leading to around 500 deaths per year and nearly $14 billion in damage. StormReady, a program started in 1999 in Tulsa, OK, helps arm America's communities with the communication and safety skills needed to save lives and property– before and during the event. StormReady helps community leaders and emergency managers strengthen local safety programs.

StormReady communities are better prepared to save lives from the onslaught of severe weather through better planning, education, and awareness. No community is storm proof, but StormReady can help communities save lives. Does StormReady make a difference?

Last paragraph.
#@+node:ekr.20110118082508.3779: *6* @test reformat-paragraph paragraph 2 of 3
# Required when running tests externally
@language plain
@pagewidth 40
@tabwidth 8

c.testManager.runEditCommandTest(p)
#@+node:ekr.20110118082508.3780: *7* work
Americans live in the most severe
weather-prone country on Earth. Each
year, Americans cope with an average of
10,000 thunderstorms, 2,500 floods,
1,000 tornadoes, as well as an average
of 6 deadly hurricanes. Potentially
deadly weather impacts every American.
Communities can now rely on the National
Weather Service’s StormReady program to
help them guard against the ravages of
Mother Nature.

Some 90% of all presidentially declared
disasters are weather related, leading
to around 500 deaths per year and nearly
$14 billion in damage. StormReady, a
program started in 1999 in Tulsa, OK,
helps arm America's communities with the
communication and safety skills needed
to save lives and property– before and
during the event. StormReady helps
community leaders and emergency managers
strengthen local safety programs.

StormReady communities are better prepared to save lives from the onslaught of severe weather through better planning, education, and awareness. No community is storm proof, but StormReady can help communities save lives. Does StormReady make a difference?

Last paragraph.
#@+node:ekr.20110118082508.3781: *7* before sel=13.0,13.0
Americans live in the most severe
weather-prone country on Earth. Each
year, Americans cope with an average of
10,000 thunderstorms, 2,500 floods,
1,000 tornadoes, as well as an average
of 6 deadly hurricanes. Potentially
deadly weather impacts every American.
Communities can now rely on the National
Weather Service’s StormReady program to
help them guard against the ravages of
Mother Nature.

Some 90% of all presidentially declared disasters are weather related, leading to around 500 deaths per year and nearly $14 billion in damage. StormReady, a program started in 1999 in Tulsa, OK, helps arm America's communities with the communication and safety skills needed to save lives and property– before and during the event. StormReady helps community leaders and emergency managers strengthen local safety programs.

StormReady communities are better prepared to save lives from the onslaught of severe weather through better planning, education, and awareness. No community is storm proof, but StormReady can help communities save lives. Does StormReady make a difference?

Last paragraph.
#@+node:ekr.20110118082508.3782: *7* after sel=23.33,23.33
Americans live in the most severe
weather-prone country on Earth. Each
year, Americans cope with an average of
10,000 thunderstorms, 2,500 floods,
1,000 tornadoes, as well as an average
of 6 deadly hurricanes. Potentially
deadly weather impacts every American.
Communities can now rely on the National
Weather Service’s StormReady program to
help them guard against the ravages of
Mother Nature.

Some 90% of all presidentially declared
disasters are weather related, leading
to around 500 deaths per year and nearly
$14 billion in damage. StormReady, a
program started in 1999 in Tulsa, OK,
helps arm America's communities with the
communication and safety skills needed
to save lives and property– before and
during the event. StormReady helps
community leaders and emergency managers
strengthen local safety programs.

StormReady communities are better prepared to save lives from the onslaught of severe weather through better planning, education, and awareness. No community is storm proof, but StormReady can help communities save lives. Does StormReady make a difference?

Last paragraph.
#@+node:ekr.20110118082508.3787: *6* @test reformat-paragraph paragraph 3 of 3
# Required when running tests externally
@language plain
@pagewidth 40
@tabwidth 8

c.testManager.runEditCommandTest(p)
#@+node:ekr.20110118082508.3788: *7* work
Americans live in the most severe
weather-prone country on Earth. Each
year, Americans cope with an average of
10,000 thunderstorms, 2,500 floods,
1,000 tornadoes, as well as an average
of 6 deadly hurricanes. Potentially
deadly weather impacts every American.
Communities can now rely on the National
Weather Service’s StormReady program to
help them guard against the ravages of
Mother Nature.

Some 90% of all presidentially declared
disasters are weather related, leading
to around 500 deaths per year and nearly
$14 billion in damage. StormReady, a
program started in 1999 in Tulsa, OK,
helps arm America's communities with the
communication and safety skills needed
to save lives and property– before and
during the event. StormReady helps
community leaders and emergency managers
strengthen local safety programs.

StormReady communities are better
prepared to save lives from the
onslaught of severe weather through
better planning, education, and
awareness. No community is storm proof,
but StormReady can help communities save
lives. Does StormReady make a
difference?

Last paragraph.
#@+node:ekr.20110118082508.3789: *7* before sel=25.10,25.10
Americans live in the most severe
weather-prone country on Earth. Each
year, Americans cope with an average of
10,000 thunderstorms, 2,500 floods,
1,000 tornadoes, as well as an average
of 6 deadly hurricanes. Potentially
deadly weather impacts every American.
Communities can now rely on the National
Weather Service’s StormReady program to
help them guard against the ravages of
Mother Nature.

Some 90% of all presidentially declared
disasters are weather related, leading
to around 500 deaths per year and nearly
$14 billion in damage. StormReady, a
program started in 1999 in Tulsa, OK,
helps arm America's communities with the
communication and safety skills needed
to save lives and property– before and
during the event. StormReady helps
community leaders and emergency managers
strengthen local safety programs.

StormReady communities are better prepared to save lives from the onslaught of severe weather through better planning, education, and awareness. No community is storm proof, but StormReady can help communities save lives. Does StormReady make a difference?

Last paragraph.
#@+node:ekr.20110118082508.3790: *7* after sel=32.11,32.11
Americans live in the most severe
weather-prone country on Earth. Each
year, Americans cope with an average of
10,000 thunderstorms, 2,500 floods,
1,000 tornadoes, as well as an average
of 6 deadly hurricanes. Potentially
deadly weather impacts every American.
Communities can now rely on the National
Weather Service’s StormReady program to
help them guard against the ravages of
Mother Nature.

Some 90% of all presidentially declared
disasters are weather related, leading
to around 500 deaths per year and nearly
$14 billion in damage. StormReady, a
program started in 1999 in Tulsa, OK,
helps arm America's communities with the
communication and safety skills needed
to save lives and property– before and
during the event. StormReady helps
community leaders and emergency managers
strengthen local safety programs.

StormReady communities are better
prepared to save lives from the
onslaught of severe weather through
better planning, education, and
awareness. No community is storm proof,
but StormReady can help communities save
lives. Does StormReady make a
difference?

Last paragraph.
#@+node:ekr.20110118082508.3730: *6* @test reformat-paragraph simple hanging indent
# Required when running tests externally
@language plain
@pagewidth 40
@tabwidth 8

c.testManager.runEditCommandTest(p)
#@+node:ekr.20110118082508.3745: *7* work
Honor this line that has a hanging
  indentation, please. Hanging
  indentation is valuable for lists of
  all kinds. But it is tricky to get
  right.

Next paragraph.
#@+node:ekr.20110118082508.3746: *7* before sel= 1.0,1.0
Honor this line that has a hanging indentation, please.  Hanging
  indentation is valuable for lists of all kinds.  But it is tricky to get right.

Next paragraph.
#@+node:ekr.20110118082508.3747: *7* after sel= 5.8,5.8
Honor this line that has a hanging
  indentation, please. Hanging
  indentation is valuable for lists of
  all kinds. But it is tricky to get
  right.

Next paragraph.
#@+node:ekr.20110118082508.3748: *6* @test reformat-paragraph simple hanging indent 2
# Required when running tests externally
@language plain
@pagewidth 40
@tabwidth 8

c.testManager.runEditCommandTest(p)
#@+node:ekr.20110118082508.3754: *7* work
Honor this line that has a hanging
  indentation, please. Hanging
  indentation is valuable for lists of
  all kinds. But it is tricky to get
  right.

Next paragraph.
#@+node:ekr.20110118082508.3755: *7* before sel=2.0,2.0
Honor this line that has
  a hanging indentation, please.  Hanging
    indentation is valuable for lists of all kinds.  But it is tricky to get right.

Next paragraph.
#@+node:ekr.20110118082508.3756: *7* after sel=5.8,5.8
Honor this line that has a hanging
  indentation, please. Hanging
  indentation is valuable for lists of
  all kinds. But it is tricky to get
  right.

Next paragraph.
#@+node:ekr.20110118082508.3757: *6* @test reformat-paragraph simple hanging indent 3
# Required when running tests externally
@language plain
@pagewidth 40
@tabwidth 8

c.testManager.runEditCommandTest(p)
#@+node:ekr.20110118082508.3763: *7* work
Honor this line that has a hanging
  indentation, please. Hanging
  indentation is valuable for lists of
  all kinds. But it is tricky to get
  right.

Next Paragraph.
#@+node:ekr.20110118082508.3764: *7* before sel=1.0,1.0
Honor this line that 
  has a hanging indentation, 
  please.  Hanging
   indentation is valuable
    for lists of all kinds.  But 
    it is tricky to get right.

Next Paragraph.
#@+node:ekr.20110118082508.3765: *7* after sel=5.8,5.8
Honor this line that has a hanging
  indentation, please. Hanging
  indentation is valuable for lists of
  all kinds. But it is tricky to get
  right.

Next Paragraph.
#@+node:ekr.20061104172236.1: *4*  Function tests
#@+node:ekr.20150430053825.1: *5* @test abbrevCommands.next_place
ac = c.abbrevCommands
assert ac
child = g.findNodeInTree(c,p,'child')
assert child
old_b = child.b
try:
    i,j,val = 0,0,child.b
    # ac.make_script_substitutions(i,j,val)
    # ac.find_place_holder(child,True)
    # print(ac.save_ins,ac.save_sel)
    new_s,i,j = ac.next_place(child.b,offset=0)
    assert i == 34 and j == 40,(i,j)
    new_s2,i,j = ac.next_place(new_s,offset=40)
    assert i == 54 and j == 58,(i,j)
finally:
    child.b = old_b
#@+node:ekr.20150430061225.1: *6* child
def spam ():
    """None - Return <|return|>
    """

    <|code|>
#@+node:ekr.20100902074747.5970: *5* @test addAbbrevHelper
f = c.abbrevCommands.addAbbrevHelper
d = c.abbrevCommands.abbrevs

# New in Leo 4.10: whitespace (blank,tab,newline) *is* significant in definitions.
table = (
    ('ut1','ut1=aa','aa'),
    # ('ut2','ut2 =bb','bb'),
    ('ut3','ut3=cc=dd','cc=dd'),
    ('ut4','ut4= ee',' ee'),
    ('ut5','ut5= ff = gg',' ff = gg'),
    ('ut6','ut6= hh==ii',' hh==ii'),
    ('ut7','ut7=j=k','j=k'),
    ('ut8','ut8=l==m','l==m'),
    ('@ut1','@ut1=@a','@a'),
)

for name,s,expected in table:
    for s2,kind in ((s,'(no nl)'),(s+'\n','(nl)')):
        f(s2,tag='unit-test')
        result,tag = d.get(name,(None,None),)
        assert result==expected, '%s <%s> expected <%s>, got <%s>' % (
            kind,s,expected,result)
#@+node:ekr.20061104172236.3: *5* @test capitalizeHelper
# TARGETWORD

w = c.frame.body.wrapper

for (which,result) in (('cap','Targetword'),('low','targetword'),('up','TARGETWORD')):
    w.setInsertPoint(5)
    c.editCommands.capitalizeHelper(event=None,which=which,undoType=None)
    s = w.getAllText()
    word = s[2:12]
    assert word == result, 'Expected %s, got: %s' % (result,repr(word))
    i = w.getInsertPoint()
    assert i == 5, 'Expected 5, got: %d' % i
#@+node:ekr.20100131180007.5453: *5* @test dynamicExpandHelper
# A totally wimpy test.
# And it somehow prints a newline to the console.
if 0:
    c.abbrevCommands.dynamicExpandHelper(event=None,prefix='',aList=[],w=None)
#@+node:ekr.20061104172236.5: *5* @test extendHelper
ec = c.editCommands ; w = c.frame.body.wrapper

for i,j,python in (
    # ('1.0','4.5',False),
    (5,50,True),
):
    extend = True
    ec.moveSpot = None # It's hard to init this properly.
    ec.extendHelper(w,extend,j)
    i2,j2 = w.getSelectionRange()
    # print(i2,j2)
    #assert 0==i2, 'Expected i=%s, got %s' % (repr(i),repr(i2))
    #assert j==j2, 'Expected j=%s, got %s' % (repr(j),repr(j2))
#@+node:ekr.20080408094623.1: *5* @test findWord
# start
# targetWord

e = c.editCommands
k = c.k
w = c.frame.body.wrapper
w.setInsertPoint(0)
k.arg = 't' # 'targetWord'
e.w = w
e.oneLineFlag = False
e.findWord1(event=None)
i,j = w.getSelectionRange()
assert i == 10, 'expected 10, got %s' % (i)
#@+node:ekr.20061104172236.2: *5* @test findWordInLine
# targetWord
e = c.editCommands
k = c.k
w = c.frame.body.wrapper
for val in (True,False):
    k.arg = 't' # 'targetWord'
    w.setInsertPoint(0)
    e.w = w
    e.oneLineFlag = val
    f = e.findWord1(event=None)
    i,j = w.getSelectionRange()
    assert i == 2, 'expected 2, got %s' % (i)
    # s = w.getAllText()
    # ch = s[i]
    # assert word == 'targetWord', 'got: %s' % word

#@+node:ekr.20071113145804.15: *5* @test helpForMinibuffer
if g.app.isExternalUnitTest:
    self.skipTest('Can not be run externally')
else:
    c.helpCommands.helpForMinibuffer()
#@+node:ekr.20061104172236.6: *5* @test moveToHelper
ec = c.editCommands ; w = c.frame.body.wrapper

for i,j,python in (
    #('1.0','4.5',False),
    (5,50,True),
):
    event = None ; extend = True ; ec.moveSpot = None
    w.setInsertPoint(i)
    ec.moveToHelper (event,j,extend)
    i2,j2 = w.getSelectionRange()
    assert i==i2, 'Expected %s, got %s' % (repr(i),repr(i2))
    assert j==j2, 'Expected %s, got %s' % (repr(j),repr(j2))
    w.setSelectionRange(0,0,insert=None)
#@+node:ekr.20061110094226: *5* @test moveUpOrDownHelper
ec = c.editCommands ; w = c.frame.body.wrapper

for i,result,direction in (('5.8','4.8','up'),('5.8','6.8','down')):
    event = None ; extend = False; ec.moveSpot = None
    w.setInsertPoint(i)
    ec.moveUpOrDownHelper (event,direction,extend)
    i2,j2 = w.getSelectionRange()
    if 1:
        break
    else:
        assert i==i2, 'Expected %s, got %s' % (repr(i),repr(i2))
        assert j==j2, 'Expected %s, got %s' % (repr(j),repr(j2))
        w.setSelectionRange(0,0,insert=None)
#@+node:ekr.20061104172236.7: *5* @test scrollHelper
ec = c.editCommands
w = c.frame.body.wrapper

for direction in ('up','down'):
    for distance in ('line','page','half-page'):
        event = g.app.gui.create_key_event(c,None,None,w)
        ec.scrollHelper(event,direction,distance)
#@+node:ekr.20061104172236.4: *5* @test setMoveCol
w = c.frame.body.wrapper
ec = c.editCommands

for spot,result in (('1.0',0),(5,5)):
    ec.setMoveCol(w,spot)
    assert ec.moveSpot == result
    assert ec.moveCol == result
#@+node:ekr.20100204165850.5371: *4* Toggle commands
# These tests will be important when revising config code.
#@+node:ekr.20100119102849.5108: *5* @test toggle-extend-mode
# backward-find-character and find-character
# can't be tested this way because they require k.getarg.
# They pass hand tests.

<< define table >>

w = c.frame.body.wrapper
child = g.findNodeInChildren(c,p,'work')
assert child
c.selectPosition(child)

for commandName in table:
    # Put the cursor in the middle of the middle line
    # so all cursor moves will actually do something.
    w.setInsertPoint(15) # for move-past-close
    try:
        c.editCommands.extendMode = True
        c.keyHandler.simulateCommand(commandName)
        i,j = w.getSelectionRange()
        assert i != j,'i == j: %s %s' % (i,commandName)
    finally:
        c.editCommands.extendMode = False

#@+node:ekr.20100119102849.5109: *6* << define table >>
# Cursor movement commands affected by extend mode.
# The x-extend-selection commands are not so affected.
table = (
    'back-to-indentation',
    'back-to-home',
    'back-char',
    'back-page',
    'back-paragraph',
    'back-sentence',
    'back-word',
    'beginning-of-buffer',
    'beginning-of-line',
    'end-of-buffer',
    'end-of-line',
    'forward-char',
    'forward-page',
    'forward-paragraph',
    'forward-sentence',
    'forward-end-word',
    'forward-word',
    'move-past-close',
    'next-line',
    'previous-line',
)
#@+node:ekr.20100119102849.5110: *6* work
line 1.
line 2(xxx).
line 3.
#@+node:ekr.20100204165850.5373: *5* @test most toggle commands
k = c.k
colorizer = c.frame.body.getColorizer()
ed = c.editCommands

# These don't set ivars
    # 'toggle-active-pane'),
    # 'toggle-angle-brackets',
    # 'toggle-input-state'),
    # 'toggle-mini-buffer'),
    # 'toggle-split-direction'),

table = [
    (k,'abbrevOn','toggle-abbrev-mode'),
    (ed,'extendMode','toggle-extend-mode'),
]

# Not valid for external tests.
table2 = [
    (k,'enable_autocompleter','toggle-autocompleter'),
    (k,'enable_calltips','toggle-calltips'),
    (c,'sparse_find','toggle-find-collapses-nodes'),
    (colorizer,'showInvisibles','toggle-invisibles'),
    (c,'sparse_move','toggle-sparse-move'),
]

if not g.app.isExternalUnitTest:
    table.extend(table2)

for obj,ivar,command in table:
    val1 = getattr(obj,ivar)
    try:
        k.simulateCommand(command)
        val2 = getattr(obj,ivar)
        assert val2 == (not val1),'failed 1 %s' % command
        k.simulateCommand(command)
        val3 = getattr(obj,ivar)
        assert val3 == val1,'failed 2 %s' % command
        # print('pass',command)
    finally:
        setattr(obj,ivar,val1)
#@+node:ekr.20100204173354.5375: *5* @test toggle-find-x
if g.app.isExternalUnitTest:
    self.skipTest('Can not be run externally')
else:
    table = (
        # ('ignore_case','toggle-find-ignore-case-option'),
            # This option now can be set automagically.
        ('search_body','toggle-find-in-body-option'),
        ('search_headline','toggle-find-in-headline-option'),
        ('mark_changes','toggle-find-mark-changes-option'),
        ('mark_finds','toggle-find-mark-finds-option'),
        ('pattern_match','toggle-find-regex-option'),
        # ('reverse','toggle-find-reverse-option'),
        ('whole_word','toggle-find-word-option'),
        ('wrap','toggle-find-wrap-around-option'),
    )
    fc = c.findCommands
    for ivar,command in table:
        val1 = getattr(fc,ivar)
        try:
            c.k.simulateCommand(command)
            val2 = getattr(fc,ivar)
            assert val2 == (not val1),'failed 1 %s' % command
            c.k.simulateCommand(command)
            val3 = getattr(fc,ivar)
            assert val3 == val1,'failed 2 %s' % command
        finally:
            setattr(fc,ivar,val1)
#@+node:ekr.20051107115231: *4*  Typing
# These are mysteriously fragile tests, so they go first
#@+node:ekr.20060208072415: *5* @test Delete key sticks in body
h = 'Test headline abc'
p = c.testManager.findNodeAnywhere(h)
assert p,'node not found: %s' % h
c.selectPosition(p)
s = 'ABC'
c.setBodyString(p,s)
try:
    c.bodyWantsFocus()
    w = c.frame.body.wrapper
    w.setInsertPoint(2)
    c.outerUpdate() # This fixed the problem.
    if 1:
        c.k.simulateCommand('delete-char')
    else:
        # This fails unless Delete is bound to delete-char
        g.app.gui.event_generate(c,'Delete','Delete',w) # Calls c.outerUpdate()
    assert p.b == s[:-1],'oops1: expected "AB", got %s' % p.b
    c.selectPosition(p.threadBack())
    c.selectPosition(p)
    assert p.b == s[:-1],'oops2: expected "AB", got %s' % p.b
finally:
    if 0:
        c.setBodyString(p,'')
        c.redraw(p)
#@+node:ekr.20051125170139: *5* @test Delete key sticks in headline
h = 'Test headline abc'
p = c.testManager.findNodeAnywhere(h)
assert p,'node not found: %s' % h
c.redraw(p) # To make node visible
c.frame.tree.editLabel(p)
w = c.edit_widget(p)
try:
    assert w
    w.setSelectionRange('end','end')
finally:
    if 1:
        c.setHeadString(p,h) # Essential
        c.redraw(p)
#@+node:ekr.20051109091333: *5* @test deleting the last body character text redraws the screen (and icon)
h = 'Test headline abc'
p = c.testManager.findNodeAnywhere(h)
assert p,'node not found: %s' % h
c.selectPosition(p)
c.setBodyString(p,'a')
c.redraw_now() # To make node visible and to set the icon.
try:
    c.bodyWantsFocus()
    n = c.frame.tree.redrawCount
    w = c.frame.body.wrapper
    w.setInsertPoint('end')
    g.app.gui.event_generate(c,'\b','BackSpace',w)
    n2 = c.frame.tree.redrawCount
    if not g.app.isExternalUnitTest:
        # This test is meaningless with a nullGui.
        assert n2 == n + 1,'too many or too few redraws: %d' % (n2-n)
finally:
    if 1:
        c.setBodyString(p,'')
        c.redraw_now()
#@+node:ekr.20051107115231.15: *5* @test editLabel selects entire headline
k = c.keyHandler
frame = c.frame ; tree = frame.tree ; canvas = tree.canvas
h = '@test editLabel selects entire headline'
p = c.testManager.findNodeAnywhere(h)
assert p,'node not found: %s' % h
c.redraw(p) # To make node visible
tree.editLabel(p)
w = c.edit_widget(p)
assert w
s = w.getAllText()
selectAll = c.config.getBool('select_all_text_when_editing_headlines')
# g.trace('editLabel selects entire headline',selectAll)
i,j = w.getSelectionRange()
if selectAll:
    assert i == 0 and j == len(s),'oops1: i: %d, j: %d' % (i,j)
else:
    assert i == len(s) and j == len(s),'oops2: i: %d, j: %d' % (i,j)
#@+node:ekr.20051120110335: *5* @test insert-node can be undone and redone
u = c.undoer
assert u
c.insertHeadline()
assert u.undoMenuLabel == 'Undo Insert Node',repr(u.undoMenuLabel)
c.undoer.undo()
assert u.redoMenuLabel == 'Redo Insert Node',repr(u.undoMenuLabel)
#@+node:ekr.20130923090601.4178: *5* @test insert-node-before node can be undone and redone
u = c.undoer
assert u
c.insertHeadlineBefore()
assert u.undoMenuLabel == 'Undo Insert Node Before',repr(u.undoMenuLabel)
c.undoer.undo()
assert u.redoMenuLabel == 'Redo Insert Node Before',repr(u.undoMenuLabel)
#@+node:ekr.20051125155134: *5* @test inserting a new node draws the screen exactly once
n = c.frame.tree.redrawCount
# print('before')
c.insertHeadline()
c.outerUpdate() # Not actually needed, but should not matter.
# print('after')

try:
    n2 = c.frame.tree.redrawCount
    if g.app.isExternalUnitTest:
        self.skipTest('Can not be run externally')
    else:
        assert n2 == n + 1,'redraws: %d' % (n2 - n)
finally:
    c.undoer.undo()
#@+node:ekr.20051107115231.18: *5* @test paste and undo in headline - at end
import sys
if sys.platform.startswith('linux'):
    self.skipTest('skip headline test')
else:
    k = c.keyHandler
    h = 'Test headline abc'
    p = c.testManager.findNodeAnywhere(h)
    assert p,'node not found: %s' % h
    frame = c.frame
    tree = frame.tree
    canvas = tree.canvas
    c.redrawAndEdit(p) # To make node visible
    w = c.edit_widget(p)
    try:
        assert w,'oops1'
        w.setSelectionRange('end','end')
        paste = 'ABC'
        g.app.gui.replaceClipboardWith(paste)
        w.setSelectionRange('end','end')
        k.manufactureKeyPressForCommandName(w,'paste-text')
        g.app.gui.event_generate(c,'\n','Return',w)
        assert p.h == h + paste,'oops2 got: %s' % p.h
        k.manufactureKeyPressForCommandName(w,'undo')
        assert p.h == h,'oops3 got: %s' % p.h
    finally:
        if 1:
            c.setHeadString(p,h) # Essential
            c.redraw(p)
#@+node:ekr.20051107115231.20: *5* @test paste and undo in headline - with selection
import sys
if sys.platform.startswith('linux'):
    self.skipTest('skip headline test')
else:
    k = c.keyHandler
    frame = c.frame ; tree = frame.tree ; canvas = tree.canvas
    h = 'Test headline abc'
    p = c.testManager.findNodeAnywhere(h)
    assert p,'node not found: %s' % h
    c.redraw(p) # To make node visible
    tree.editLabel(p)
    w = c.edit_widget(p)
    try:
        assert w, 'Null w'
        paste = 'ABC'
        g.app.gui.replaceClipboardWith(paste)
        w.setSelectionRange('1.1','1.2')
        k.manufactureKeyPressForCommandName(w,'paste-text')
        g.app.gui.event_generate(c,'\n','Return',w)
        assert p.h == h[0] + paste + h[2:]
        k.manufactureKeyPressForCommandName(w,'undo')
        assert p.h == h, 'head mismatch'
    finally:
        if 1:
            c.setHeadString(p,h) # Essential
            c.redraw(p)
#@+node:ekr.20051107115231.16: *5* @test paste at end of headline
import sys
if sys.platform.startswith('linux'):
    self.skipTest('skip headline test')
else:
    k = c.keyHandler
    frame = c.frame ; tree = frame.tree ; canvas = tree.canvas
    h = 'Test headline abc'
    p = c.testManager.findNodeAnywhere(h)
    assert p,'node not found: %s' % h
    c.redrawAndEdit(p) # To make node visible
    w = c.edit_widget(p)
    g.app.gui.set_focus(c,w)
    w2 = g.app.gui.get_focus(c)
    
    try:
        assert w
        paste = 'ABC'
        g.app.gui.replaceClipboardWith(paste)
        g.app.gui.set_focus(c,w)
        w2 = g.app.gui.get_focus(c)
        w.setSelectionRange('end','end')
        k.manufactureKeyPressForCommandName(w,'paste-text')
        g.app.gui.event_generate(c,'\n','Return',w)
        assert p.h == h + paste,'Expected: %s, got %s' % (
            h + paste,p.h)
    finally:
        if 1:
            c.setHeadString(p,h) # Essential
            c.redraw(p)
#@+node:ekr.20060208072307: *5* @test paste from menu into body sticks
if c.k.defaultUnboundKeyAction == 'insert':
    h = 'Test headline abc'
    p = c.testManager.findNodeAnywhere(h)
    assert p,'node not found: %s' % h
    c.redraw(p)
    c.bodyWantsFocus()
    paste = 'ABC'
    g.app.gui.replaceClipboardWith(paste)
    event = g.app.gui.create_key_event(c,None,None,c.frame.body.wrapper)
    c.frame.pasteText(event)
    
    # Move around and and make sure it doesn't change.
    try:
        assert p.b == paste, 'paste1 failed'
        c.selectPosition(p.threadBack())
        assert p.b == paste, 'stick failed'
        c.selectPosition(p)
        assert p.b == paste, 'revisit failed'
    finally:
        if 1:
            c.setBodyString(p,'')
            c.redraw(p)
#@+node:ekr.20060208072331: *5* @test paste from menu into headline sticks
h = 'Test headline abc'
p = c.testManager.findNodeAnywhere(h)
assert p,'node not found: %s' % h
c.selectPosition(p)
c.frame.tree.editLabel(p)
w = c.edit_widget(p)
w.setSelectionRange('end','end',insert='end')
paste = 'ABC'
g.app.gui.replaceClipboardWith(paste)
event = g.app.gui.create_key_event(c,None,None,w)
c.frame.pasteText(event)
# Move around and and make sure it doesn't change.
try:
    # g.trace('before select',w,w.getAllText())
    c.selectPosition(p.threadBack())
    assert p.h == h + paste,'oops1: expected: %s, got %s' % (h + paste,p.h)
    c.selectPosition(p)
    assert p.h == h + paste,'oops2: expected: %s, got %s' % (h + paste,p.h)
finally:
    if 1:
        c.setHeadString(p,h) # Essential
        c.redraw(p)
#@+node:ekr.20051107115231.24: *5* @test paste from menu to body recolors the body
# Should be a comment
h = 'Test headline abc'
p = c.testManager.findNodeAnywhere(h)
w = c.frame.body.wrapper
n = c.frame.body.colorizer.recolorCount
assert p,'node not found: %s' % h
c.selectPosition(p)
c.bodyWantsFocus()
paste = '# Should be a comment'
g.app.gui.replaceClipboardWith(paste)
c.outerUpdate()
event = g.app.gui.create_key_event(c,None,None,c.frame.body.wrapper)
c.frame.pasteText(event)
try:
    assert c.frame.body.colorizer.recolorCount > n
finally:
    if 1:
        c.setBodyString(p,'')
        c.redraw(p)
#@+node:ekr.20051107115231.14: *5* @test return ends editing of headline
h = '@test return ends editing of headline'
p = c.testManager.findNodeAnywhere(h)
assert p,'node not found: %s' % h
c.redraw(p) # To make node visible
c.frame.tree.editLabel(p)
w = c.edit_widget(p)
guiName = g.app.gui.guiName()
wName = g.app.gui.widget_name(w)
assert wName.startswith('head'),'w.name:%s' % wName
g.app.gui.event_generate(c,'\n','Return',w)
c.outerUpdate()
assert w != c.get_focus(),'oops2: focus in headline'
#@+node:ekr.20051107115231.28: *5* @test selecting new node retains paste in headline
import sys
if sys.platform.startswith('linux'):
    self.skipTest('skip headline test')
else:
    k = c.keyHandler
    frame = c.frame ; tree = frame.tree ; canvas = tree.canvas
    h = 'Test headline abc'
    p = c.testManager.findNodeAnywhere(h)
    assert p,'node not found: %s' % h
    c.redraw(p) # To make node visible
    tree.editLabel(p)
    w = c.edit_widget(p)
    try:
        assert w,'oops1'
        w.setSelectionRange('end','end')
        paste = 'ABC'
        g.app.gui.replaceClipboardWith(paste)
        w.setSelectionRange('end','end')
        k.manufactureKeyPressForCommandName(w,'paste-text')
        c.selectPosition(p.visBack(c))
        assert p.h == h + paste
        k.manufactureKeyPressForCommandName(w,'undo')
        assert p.h == h,'expected: %s, got: %s' % (
            h,p.h)
    finally:
        if 1:
            c.setHeadString(p,h) # Essential
            c.redraw(p)
#@+node:ekr.20051107115231.21: *5* @test selecting new node retains typing in headline
import sys
if sys.platform.startswith('linux'):
    self.skipTest('skip headline test')
else:
    k = c.k
    if k.defaultUnboundKeyAction == 'insert':
        frame = c.frame ; tree = frame.tree ; canvas = tree.canvas
        h = 'Test headline abc'
        p = c.testManager.findNodeAnywhere(h)
        assert p,'node not found: %s' % h
        c.redraw(p) # To make node visible
        tree.editLabel(p)
        w = c.edit_widget(p)
        try:
            assert w
            w.setSelectionRange('end','end')
            g.app.gui.event_generate(c,'X','Shift+X',w)
            g.app.gui.event_generate(c,'Y','Shift+Y',w)
            g.app.gui.event_generate(c,'Z','Shift+Z',w)
            g.app.gui.event_generate(c,'\n','Return',w)
            assert p.h == h + 'XYZ'
            k.manufactureKeyPressForCommandName(w,'undo')
            assert p.h == h
        finally:
            if 1:
                c.setHeadString(p,h) # Essential
                c.redraw(p)
#@+node:ekr.20051107115231.17: *5* @test typing and undo in headline - at end
import sys
if sys.platform.startswith('linux'):
    self.skipTest('skip headline test')
else:
    k = c.k
    if k.defaultUnboundKeyAction == 'insert':
        frame = c.frame ; tree = frame.tree ; canvas = tree.canvas
        h = 'Test headline abc'
        p = c.testManager.findNodeAnywhere(h)
        assert p,'node not found: %s' % h
        c.redrawAndEdit(p) # To make the node visible.
        w = c.edit_widget(p)
        # print('guiName',g.app.gui.guiName())
        try:
            assert w, 'oops1'
            wName = g.app.gui.widget_name(w)
            assert wName.startswith('head'),'w.name:%s' % wName
            w.setSelectionRange('end','end')
            g.app.gui.event_generate(c,'X','Shift+X',w)
            g.app.gui.event_generate(c,'Y','Shift+Y',w)
            g.app.gui.event_generate(c,'Z','Shift+Z',w)
            g.app.gui.event_generate(c,'\n','Return',w)
            assert p.h == h + 'XYZ',(
                'oops2: expected: %s, got: %s' % (
                    h + 'XYZ',p.h))
            if g.app.gui.guiName() != 'nullGui':
                assert c.undoer.undoMenuLabel == 'Undo Typing','oops3: %s' % (
                    c.undoer.undoMenuLabel)
            k.manufactureKeyPressForCommandName(w,'undo')
            if g.app.gui.guiName() != 'nullGui':
                assert c.undoer.redoMenuLabel == 'Redo Typing','oops4'
            assert p.h == h,'oops5 got: %s, expected: %s' % (
                p.h,h)
        finally:
            if 1:
                c.setHeadString(p,h) # Essential
                c.redraw(p)
#@+node:ekr.20060208072358: *5* @test typing in empty body text redraws the screen (and icon)
# This test is too flaky for Tk.
import sys
if False and sys.platform.startswith('linux'):
    # Fails for strange reasons.
    self.skipTest('linux')
else:
    h = 'Test headline abc'
    p = c.testManager.findNodeAnywhere(h)
    assert p,'node not found: %s' % h
    c.selectPosition(p)
    c.bodyWantsFocus()
    c.redraw(p) # To make node visible
    n = c.frame.tree.redrawCount
    assert not p.b, 'oops1'
    try:
        # print('before insert a',c.p)
        assert p == c.p,'position has changed!'
        w = c.frame.body.wrapper
        if c.vim_mode and c.vimCommands:
            if c.vimCommands.state == 'normal':
                # Enter insert mode ;-)
                g.app.gui.event_generate(c,'i','i',w)
        g.app.gui.event_generate(c,'a','a',w)
        assert p.b == 'a', 'expected "a", got: %s' % repr(p.b)
        if g.app.gui.guiName() != 'nullGui':
            n2 = c.frame.tree.redrawCount
            c.outerUpdate() # Force the coloring before doing the test.
            assert n2 == n + 1,'too many or too few redraws: expected 1: got: %d' % (n2-n)
    finally:
        if 1:
            c.setBodyString(p,'')
            c.redraw(p)
#@+node:ekr.20051109091731: *5* @test typing in non-empty body text does not redraw the screen
h = 'Test headline abc'
p = c.testManager.findNodeAnywhere(h)
assert p,'node not found: %s' % h
c.setBodyString(p,'a')
c.redraw(p) # To make node visible
# print('after redraw_now')
c.bodyWantsFocus()
n = c.frame.tree.redrawCount
try:
    w = c.frame.body.wrapper
    g.app.gui.event_generate(c,'a','a',w)
    n2 = c.frame.tree.redrawCount
    assert n2 == n,'too many redraws: %d' % (n2-n)
finally:
    if 1:
        c.setBodyString(p,'')
        c.redraw(p)
#@+node:ekr.20051120115046: *5* @test undoing insert node restores previous node's body text
h = 'Test headline abc'
p = c.testManager.findNodeAnywhere(h)
assert p,'node not found: %s' % h
c.selectPosition(p)
body = 'This is a test'
c.setBodyString(p,body)

try:
    assert p.b == body
    c.insertHeadline()
    c.undoer.undo()
    assert p.b == body
finally:
    c.setBodyString(p,'')
#@+node:ekr.20060131102450: *5* @test zz print end of typing tests
print('\nEnd of typing tests')
#@+node:ekr.20070306091949: *4* @test zz end of leoEditCommands tests
# This is **not** a real unit test.
# It simply restores the screen to a more convenient state.

# c.contractParent()
# g.app.unitTestDict['restoreSelectedNode']=False

print('\nEnd of leoEditCommands tests.')
#@+node:ekr.20061001114637: *3* leoFileCommands
# 3 failures with Alt-5
#@+node:ekr.20100206165505.5386: *4* @@test fc.handleNodeConflicts
# More suitable as a hand test:
# it makes no effort to delete the 'Recovered Nodes' node.

c.nodeConflictList = []

for i in range(2):
    c.nodeConflictList.append(g.bunch(
        tag='(uncached)',
        gnx='gnx %s' % (i),
        fileName ='filename %s' % (i),
        b_old='old body %s' % (i),
        b_new='new body %s' % (i),
        h_old='head %s' % (i),
        h_new='head %s' % (i),
    ))

c.fileCommands.handleNodeConflicts()

c.nodeConflictList = []

c.redraw()
#@+node:ekr.20100131180007.5451: *4* @test fc.cleanSaxInputString
s = 'test%cthis' % 27

assert c.fileCommands.cleanSaxInputString(s) == 'test this'
#@+node:ekr.20071113145804.18: *4* @test fc.deleteFileWithMessage
fc=c.fileCommands
fc.deleteFileWithMessage('xyzzy','test')

if 0: # one-time test of es statements.
    fileName = 'fileName' ; kind = 'kind'
    g.es("read only",color="red")
    g.es("exception deleting %s file: %s" % (fileName,kind))
    g.es("exception deleting backup file:" + fileName)
#@+node:ekr.20100131180007.5450: *4* @test fc.getSaxUa
expectedIconDictList = [
{
    'on': 'tnode',
    'where': 'beforeHeadline',
    'yoffset': 0,
    # 'file': u'C:\\leo.repo\\trunk\\leo\\Icons\\Tango\\16x16\\actions\\add.png',
    'file': 'C:\\leo.repo\\trunk\\leo\\Icons\\Tango\\16x16\\actions\\add.png',
    'xpad': 1,
    'type': 'file',
    'xoffset': 2,
    # 'relPath': u'Tango\\16x16\\actions\\add.png',
    'relPath': 'Tango\\16x16\\actions\\add.png',
},
{
    'on': 'tnode',
    'where': 'beforeHeadline',
    'yoffset': 0,
    # 'file': u'C:\\leo.repo\\trunk\\leo\\Icons\\Tango\\16x16\\actions\\bottom.png',
    'file': 'C:\\leo.repo\\trunk\\leo\\Icons\\Tango\\16x16\\actions\\bottom.png',
    'xpad': 1,
    'type': 'file',
    'xoffset': 2,
    # 'relPath': u'Tango\\16x16\\actions\\bottom.png',
    'relPath': 'Tango\\16x16\\actions\\bottom.png',
}]
table = (
('tx','raw',None,"ekr.20090701133940.1767"),
('lineYOffset',None,3,"4b032e"),
# A real icon
('icons',None,expectedIconDictList,
"5d7100287d71012855026f6e71025505746e6f6465710355047479\
70657104550466696c6571055507796f666673657471064b006805583700000\
0433a5c6c656f2e7265706f5c7472756e6b5c6c656f5c49636f6e735c54616e\
676f5c31367831365c616374696f6e735c6164642e706e67710755047870616\
471084b01550577686572657109550e6265666f7265486561646c696e65710a\
5507786f6666736574710b4b02550772656c50617468710c581b00000054616\
e676f5c31367831365c616374696f6e735c6164642e706e67710d757d710e28\
55026f6e710f68035504747970657110550466696c6571115507796f6666736\
57471124b006811583a000000433a5c6c656f2e7265706f5c7472756e6b5c6c\
656f5c49636f6e735c54616e676f5c31367831365c616374696f6e735c626f7\
4746f6d2e706e67711355047870616471144b01550577686572657115550e62\
65666f7265486561646c696e6571165507786f666673657471174b025507726\
56c506174687118581e00000054616e676f5c31367831365c616374696f6e73\
5c626f74746f6d2e706e67711975652e"),
)
for attr,kind,expected,val in table:
    result = c.fileCommands.getSaxUa(attr,val,kind=kind)
    if expected is None: expected = val
    assert g.toEncodedString(expected)==result,'expected %s got %s' % (
        expected,result)
#@+node:ekr.20100131180007.5463: *4* @test fc.handleTnodeSaxAttributes
sax_node = g.bunch(
    tnodeAttributes={
# The 'tx' attribute is handled by contentHandler.tnodeAttributes.
# 'tx':"ekr.20090701133940.1767",
'lineYOffset':"4b032e",
# A real icon attribute, see the tests below for what we expect
'icons':"5d7100287d71012855026f6e71025505746e6f6465710355047479\
70657104550466696c6571055507796f666673657471064b006805583700000\
0433a5c6c656f2e7265706f5c7472756e6b5c6c656f5c49636f6e735c54616e\
676f5c31367831365c616374696f6e735c6164642e706e67710755047870616\
471084b01550577686572657109550e6265666f7265486561646c696e65710a\
5507786f6666736574710b4b02550772656c50617468710c581b00000054616\
e676f5c31367831365c616374696f6e735c6164642e706e67710d757d710e28\
55026f6e710f68035504747970657110550466696c6571115507796f6666736\
57471124b006811583a000000433a5c6c656f2e7265706f5c7472756e6b5c6c\
656f5c49636f6e735c54616e676f5c31367831365c616374696f6e735c626f7\
4746f6d2e706e67711355047870616471144b01550577686572657115550e62\
65666f7265486561646c696e6571165507786f666673657471174b025507726\
56c506174687118581e00000054616e676f5c31367831365c616374696f6e73\
5c626f74746f6d2e706e67711975652e"
})
try:
    p2 = p.insertAsLastChild()
    v = p2.v
    c.fileCommands.handleTnodeSaxAttributes(sax_node,v)
    # print v,v.u
    d = v.u
    for attr in ('lineYOffset','icons'):
        assert d.get(attr),attr
    for attr in ('tx','a'):
        assert d.get(attr) is None,attr # A known attribute.
finally:
    if 1:
        while p.hasChildren():
            # print('deleting',p.firstChild())
            p.firstChild().doDelete()
#@+node:ekr.20100131180007.5460: *4* @test fc.handleVnodeSaxAttributes
sax_node = g.bunch(
    attributes={
'a':'M',
'lineYOffset':"4b032e",
# A real icon attribute, see the tests below for what we expect
'icons':"5d7100287d71012855026f6e71025505746e6f6465710355047479\
70657104550466696c6571055507796f666673657471064b006805583700000\
0433a5c6c656f2e7265706f5c7472756e6b5c6c656f5c49636f6e735c54616e\
676f5c31367831365c616374696f6e735c6164642e706e67710755047870616\
471084b01550577686572657109550e6265666f7265486561646c696e65710a\
5507786f6666736574710b4b02550772656c50617468710c581b00000054616\
e676f5c31367831365c616374696f6e735c6164642e706e67710d757d710e28\
55026f6e710f68035504747970657110550466696c6571115507796f6666736\
57471124b006811583a000000433a5c6c656f2e7265706f5c7472756e6b5c6c\
656f5c49636f6e735c54616e676f5c31367831365c616374696f6e735c626f7\
4746f6d2e706e67711355047870616471144b01550577686572657115550e62\
65666f7265486561646c696e6571165507786f666673657471174b025507726\
56c506174687118581e00000054616e676f5c31367831365c616374696f6e73\
5c626f74746f6d2e706e67711975652e"
})
try:
    p2 = p.insertAsLastChild()
    v = p2.v
    c.fileCommands.handleVnodeSaxAttributes(sax_node,v)
    # print v,v.u
    d = v.u
    for attr in ('lineYOffset','icons'):
        assert d.get(attr) is not None,attr
    # The a:M attribute should mark the node.
    assert d.get('a') is None
    assert v.isMarked()
    aList = d.get('icons')
    assert aList
    assert len(aList) == 2
    for d2 in aList:
        for key in ('on','where','yoffset','file'):
            assert d2.get(key) is not None,key
finally:
    if 1:
        while p.hasChildren():
            # print('deleting',p.firstChild())
            p.firstChild().doDelete()
#@+node:ekr.20080806072412.1: *4* @test fc.resolveArchivedPosition
child1 = p.firstChild()
child2 = p.firstChild().next()
grandChild1 = child2.firstChild()
grandChild2 = grandChild1.next()
greatGrandChild11 = grandChild1.firstChild()
greatGrandChild12 = greatGrandChild11.next()
greatGrandChild21 = grandChild2.firstChild()
greatGrandChild22 = greatGrandChild21.next()
root_v = p.v

table = (
    # Errors.
    (None,'-1'),
    (None,'1'),
    (None,'0.2'),
    (None,'0.0.0'),
    (None,'0.1.2'),
    # Valid.
    (root_v,'0'),
    (child1.v,'0.0'),
    (child2.v,'0.1'),
    (grandChild1.v,'0.1.0'),
    (greatGrandChild11.v,'0.1.0.0'),
    (greatGrandChild12.v,'0.1.0.1'),
    (grandChild2.v,'0.1.1'),
    (greatGrandChild21.v,'0.1.1.0'),
    (greatGrandChild22.v,'0.1.1.1'),
)

for v,archivedPosition in table:
    v2 = c.fileCommands.resolveArchivedPosition(archivedPosition,root_v)
    assert v == v2,'got %s, expected %s' % (v2,v)
#@+node:ekr.20080806072412.2: *5* first child
#@+node:ekr.20080806072412.3: *5* second child
#@+node:ekr.20080806072412.4: *6* grandChild1
#@+node:ekr.20080806080425.1: *7* greatGrandChild11
#@+node:ekr.20080806080425.2: *7* greatGrandChild12
#@+node:ekr.20080806072412.5: *6* grandChild 2
#@+node:ekr.20080806080425.3: *7* greatGrandChild21
#@+node:ekr.20080806080425.4: *7* greatGrandChild22
#@+node:ekr.20080805105541.1: *4* @test p.archivedPosition
val = p.archivedPosition(root_p=p)
assert val == [0],'expected %s, got %s' % ([0],val)

i = 0
for z in p.parent().children_iter():
    val = z.archivedPosition(root_p=p.parent())
    assert val == [0,i],'expected %s, got %s'%([0,i],val)
    i += 1

i = 0
for z in p.children_iter():
    val = z.archivedPosition(root_p=p)
    assert val == [0,i],'expected %s, got %s'%([0,i],val)
    i += 1

i = 0
for z in p.firstChild().next().children_iter():
    val = z.archivedPosition(root_p=p)
    assert val == [0,1,i],'expected %s, got %s'%([0,1,i],val)
    i += 1
#@+node:ekr.20080805122315.1: *5* first child
#@+node:ekr.20080805122315.2: *5* second child
#@+node:ekr.20080805122315.3: *6* grandChild
#@+node:ekr.20080805122315.4: *6* grandChild 2
#@+node:ekr.20080805104144.1: *4* @test putDescendentVnodeUas
fc = c.fileCommands
child = p.firstChild()
grandChild = child.firstChild()
child.v.unknownAttributes = {'unit_test_child':'abcd'}
grandChild.v.unknownAttributes = {'unit_test_grandchild':'wxyz'}


try:
    s = fc.putDescendentVnodeUas (p)
    
    if 0: # This test is too flaky to be useful.
        if g.isPython3:
            expected = ' descendentVnodeUnknownAttributes=\
7d7100285803000000302e3071017d7102580f000000756e6974\
5f746573745f6368696c64710358040000006162636471047358\
05000000302e302e3071057d71065814000000756e69745f7465\
73745f6772616e646368696c64710758040000007778797a710873752e"'
        else:
            expected = ' descendentVnodeUnknownAttributes="\
7d7100285503302e3071017d7102550f756e69745f746573745f\
6368696c6471035504616263647104735505302e302e3071057d\
71065514756e69745f746573745f6772616e646368696c647107\
55047778797a710873752e"'
    
        assert s == expected, 'expected: %s, got: %s' % (repr(expected),repr(s))
finally:
    del child.v.unknownAttributes
    del grandChild.v.unknownAttributes
#@+node:ekr.20080805104144.2: *5* child
#@+node:ekr.20080805104144.3: *6* grandChild
#@+node:ekr.20061001114236: *4* @test putUa
fc = c.fileCommands # self is a dummy
p.v.unknownAttributes = {g.u('unit_test'):g.u('abcd')}
s = fc.putUnknownAttributes (p.v)
expected = g.u(' unit_test="58040000006162636471002e"')
assert s == expected, '\nexpected: %s\ngot:      %s' % (repr(expected),repr(s))
#@+node:ekr.20051107115231.9: *4* @test Select a node when file is first loaded
c.redraw(p) # To make node visible

c2 = c.new()
p2 = c2.p

try:
    # This fails, but it is possible to edit the headline.
    # assert c2.edit_widget(p2),'c2.edit_widget(p2) failed: %s' % repr(p2)
    assert p2,'p2 failed: %s' % repr(p2)
    # assert c.edit_widget(p),'c.edit_widget(p) failed: %s' % repr(p)
finally:
    c2.setChanged(False)
    c2.close()
#@+node:ekr.20090507084947.5152: *4* @test t.fileIndex remains the same
# print(p.v.fileIndex)

if g.app.isExternalUnitTest:
    self.skipTest('Can not be run externally')
else:
    # new_gnxs:
    assert p.v.fileIndex == 'ekr.20090507084947.5152',p.v.fileIndex
    # old gnxs:
    # assert p.v.fileIndex == ('ekr', '20090507084947', 5152)
#@+node:ekr.20071113202045: *4* @test zz end of leoFile tests
# This is **not** a real unit test.
# It simply restores the screen to a more convenient state.

# c.contractParent()
# g.app.unitTestDict['restoreSelectedNode']=False

print('\nEnd of leoFileCommands tests.')
#@+node:ekr.20071113193527: *3* leoFind
# 4 failures with Alt-5
#@+node:ekr.20051107115231.29: *4* @@test Find keeps focus in body & shows selected text
import leo.core.leoEditCommands as leoEditCommands
s = 'foo' ; wrapper = c.frame.body.wrapper
c.searchCommands.openFindTab()
h = c.searchCommands.findTabHandler
w = h.find_ctrl
w.setAllText(s)
c.bodyWantsFocus()
wrapper.setInsertPoint(0)
c.searchCommands.findTabFindNext()
w = c.get_focus()
wName = g.app.gui.widget_name(w)
assert 'body' in wName, 'focus: %s = %s, expected %s = %s' % (
    w,wName,wrapper,g.app.gui.widget_name(wrapper))
#@+node:ekr.20060130151716.3: *4* @test minibuffer find commands
if g.app.isExternalUnitTest:
    self.skipTest('Can not be run externally')
else:
    table = (
        're-search-forward',
        're-search-backward',
        'search-forward',
        'search-backward',
        'word-search-forward',
        'word-search-backward',
    )
    
    for command in table:
        # This is not a full test.  We must use keyboardQuit here!
        c.k.simulateCommand(command)
        c.k.keyboardQuit(None)
#@+node:ekr.20060130151716.2: *4* @test set find mode commands
if g.app.isExternalUnitTest:
    self.skipTest('Can not be run externally')
else:
    table = (
        'set-find-everywhere',
        'set-find-node-only',
        'set-find-suboutline-only',
    )
    # show-find-tab-options     = Ctrl-o
    # show-find-options         = o
    for command in table:
        c.k.simulateCommand(command)
#@+node:ekr.20060130151716.4: *4* @test show-find-options
c.k.simulateCommand('show-find-options')
#@+node:ekr.20060130151716.1: *4* @test toggle find options commands
if g.app.isExternalUnitTest:
    self.skipTest('Can not be run externally')
else:
    table = (
        # 'toggle-find-clone-find-all-option',
        'toggle-find-ignore-case-option',
        'toggle-find-in-body-option',
        'toggle-find-in-headline-option',
        'toggle-find-mark-changes-option',
        'toggle-find-mark-finds-option',
        'toggle-find-regex-option',
        # 'toggle-find-reverse-option',
        'toggle-find-word-option',
        'toggle-find-wrap-around-option',
    )
    for command in table:
        c.k.simulateCommand(command)
        c.k.simulateCommand(command)
#@+node:ekr.20071113202153: *4* @test zz end of leoFind tests
# This is **not** a real unit test.
# It simply restores the screen to a more convenient state.

# c.contractParent()
# g.app.unitTestDict['restoreSelectedNode']=False

print('\nEnd of leoFind tests.')
#@+node:ekr.20071113194424: *3* leoFrame
# 3 failures with Alt-5
#@+node:ekr.20060912091510.1: *4* @@test add-editor & delete-editor
import time

c.frame.body.addEditor()

time.sleep(0.5)

c.frame.body.deleteEditor()

time.sleep(0.5)
#@+node:ekr.20090608174319.4791: *4* @@test delete-editor
# This causes trouble if executed quickly after the add-editor command.
# Presumably this is a timing condition that will never happen in practice.

if 0:
    c.frame.body.deleteEditor()
#@+node:ekr.20061106201509.6: *4* @test c.frame.body.getInsertLines
# line 1
# line 2
# line 3

w = c.frame.body.wrapper
index = 11 # in the second line.
w.setInsertPoint(index)
before,ins,after = c.frame.body.getInsertLines()
assert before == '# line 1\n','Got %s' % repr(before)
assert ins    == '# line 2\n','Got %s' % repr(ins)
assert after.startswith('# line 3\n'),'line3'
assert after.endswith('# end.\n'),'end'

# end.
#@+node:ekr.20061106201509.7: *4* @test c.frame.body.getSelectionAreas
# line 1
# line 2
# line 3

w = c.frame.body.wrapper
s = w.getAllText()
start,end = 11,15
w.setSelectionRange(start,end)
before,ins,after = c.frame.body.getSelectionAreas()
assert before == s[0:start],'Got %s' % repr(before)
assert ins    == s[start:end],'Got %s' % repr(ins)
assert after == s[end:]

# end.
#@+node:ekr.20071113145804.32: *4* @test c.frame.body.getSelectionAreas & test
# line 1
# line 2
# line 3

w = c.frame.body.wrapper
s = w.getAllText()
start,end = 11,15
w.setSelectionRange(start,end)
before,ins,after = c.frame.body.getSelectionAreas()
assert before == s[0:start],'Got %s' % repr(before)
assert ins    == s[start:end],'Got %s' % repr(ins)
assert after == s[end:]

# end.
#@+node:ekr.20111121152019.3929: *4* @test c.frame.body.updateEditors
'''updateEditors was crashing due to calling setSelectionRange(ins=i).
The proper keyword argument is insert=i.
'''

c.frame.body.updateEditors()
#@+node:ekr.20111121142012.4030: *4* @test c.frame.log relationships
from leo.core.leoQt import QtGui,QtWidgets
log = c.frame.log
name = log.__class__.__name__

if g.app.isExternalUnitTest:
    assert name == 'NullLog',name
else:
    assert name == 'LeoQtLog',name
    assert log.logCtrl.__class__.__name__ == 'QTextEditWrapper',log.logCtrl
    assert not issubclass(log.logCtrl.__class__,QtWidgets.QWidget.__class__)
        # leoQTextEditWidget us a poor name: it is not a Qt widget.
    assert log.logCtrl.widget.__class__.__name__ == 'LeoQTextBrowser'
    assert hasattr(log.logCtrl,'widget') and log.logCtrl.widget
    assert hasattr(log.logCtrl.widget,'leo_log_wrapper')
    wrapper = log.logCtrl.widget.leo_log_wrapper
    assert wrapper == log.logCtrl

#@+node:ekr.20111121081052.3908: *4* @test c.frame.log.numberOfVisibleTabs
if g.app.isExternalUnitTest:
    self.skipTest('Can not be run externally')
else:
    log = c.frame.log
    d = log.contentsDict
    keys = list(d.keys())
    tabs = log.orderedTabNames()
    n = len(keys)
    n2 = log.numberOfVisibleTabs()
    n3 = len(tabs)
    assert n == n2,'n: %s n2: %s' % (n,n2)
    # The spell tab may not be in d.keys.
    assert n <= n3,'n: %s len(log.orederedTabNames() %s): %s' % (n,n3,tabs)
#@+node:ekr.20111121140833.3917: *4* @test c.frame.log.put & putNl
'''These were changed, then reverted, but a unit test is important.'''

if g.app.isExternalUnitTest:
    self.skipTest('Prints to console, which is annoying.')
else:
    log = c.frame.log
    log.put(p.h)
    log.putnl()
#@+node:ekr.20111107065245.3833: *4* @test c.frame.minimize-all
# The actual code contains the unit test.
# This test will have effect only when run locally.

if g.app.isExternalUnitTest:
    self.skipTest('Can not be run externally')
else:
    d = g.app.unitTestDict
    tag = 'minimize-all'
    assert not d.get(tag)
    c.frame.minimizeAll()
    assert d.get(tag) is True
#@+node:ekr.20061104172236.22: *4* @test c.frame.pasteText
# target.

try:
    w = c.frame.body.wrapper
    s = w.getAllText()
    w.setInsertPoint(len(s))
    c.k.previousSelection = 2,8
    event = g.app.gui.create_key_event(c,None,None,w)
    c.frame.pasteText(event=event,middleButton=True)
    s2 = w.getAllText()
    assert len(s2) == len(s) + len('target')
finally:
    w.setAllText(s)
    p.setBodyString(s)
    # g.trace(repr(s))
    c.recolor()

# end
#@+node:ekr.20071113145804.33: *4* @test c.frame.pasteText 2
# target

try:
    w = c.frame.body.wrapper
    # print((w))
    s2 = p.b
    s = w.getAllText()
    assert s == s2, 'w.getAllText() != p.b: len(w)=%d, len(p)=%d' % (len(s),len(s2))
    w.setInsertPoint(len(s))
    c.k.previousSelection = 2,8
    event = g.app.gui.create_key_event(c,None,None,w)
    c.frame.pasteText(event=event,middleButton=True)
    s2 = w.getAllText()
    assert len(s2) == len(s) + len('target')
finally:
    w.setAllText(s)
    p.setBodyString(s)
    c.recolor()

# end5target
#@+node:ekr.20111107065530.3833: *4* @test c.frame.resize-to-screen
# The actual code contains the unit test.
# This test will have effect only when run locally.

if g.app.isExternalUnitTest:
    self.skipTest('Can not be run externally')
else:
    d = g.app.unitTestDict
    tag = 'resize-to-screen'
    assert not d.get(tag)
    c.frame.resizeToScreen()
    assert d.get(tag) is True
#@+node:ekr.20100131180007.5359: *4* @test c.frame.tree.OnIconDoubleClick
c.frame.tree.OnIconDoubleClick(p)
#@+node:ekr.20071113202153.1: *4* @test zz end of leoFrame tests
# This is **not** a real unit test.
# It simply restores the screen to a more convenient state.

# c.contractParent()
# g.app.unitTestDict['restoreSelectedNode']=False

print('\nEnd of leoFrame tests.')
#@+node:ekr.20071113194033.3: *3* leoGlobals
# No failures with Alt-5 but warnings about no tnode lists.
#@+node:ekr.20100131180007.5398: *4* @test g.adjustTripleString
if 1: # The following must be indented.

    s = '''\
    a
      b

c
    d'''

    s2 = '    a\n      b\n\nc\n    d'

    result = g.adjustTripleString(s,c.tab_width)
    # print(c.tab_width)
    # print(result)
    # print('=====')
    # print(s2)
    assert result == s2,repr(result)


#@+node:ekr.20110510054817.3476: *4* @test g.alert
g.alert(c,'test of g.alert')
#@+node:ekr.20040917062206: *4* @test g.cantImport returns None
assert(g.cantImport("xyzzy","during unit testing") is None)
#@+node:ekr.20060921115303: *4* @test g.checkVersion
# for condition in ('<','<=','>','>='):

for v1,condition,v2 in (
    ('8.4.12','>','8.4.3'),
    ('1','==','1.0'),
    ('2','>','1'),
    ('1.2','>','1'),
    ('2','>','1.2.3'),
    ('1.2.3','<','2'),
    ('1','<','1.1'),
):
    assert g.CheckVersion(v1,v2,condition=condition,trace=False)
#@+node:ekr.20071113143844.9: *4* @test g.CheckVersionToInt
assert g.CheckVersionToInt('12') == 12,'fail 1'
assert g.CheckVersionToInt('2a5') == 2, 'fail 2'
assert g.CheckVersionToInt('b2') == 0, 'fail 3'
#@+node:ekr.20100131180007.5428: *4* @test g.comment_delims_from_extension
# New in Leo 4.6, set_delims_from_language returns '' instead of None.
table = (
    ('.c',      ('//','/*','*/')),
    ('.html',   ('', '<!--', '-->')),
    ('.py',     ('#','','')),
    ('.xxx',    ('','','')),
)

for ext, expected in table:
    result = g.comment_delims_from_extension(ext)
    assert result==expected,'ext %s expected %s, got %s' % (
        ext,expected,result)
#@+node:ekr.20160327132053.1: *4* @test g.compute_directives_re
# Mimic the code in g.get_directives_dict
import re
pat = g.compute_directives_re()
pat = re.compile(pat, re.MULTILINE)
table = (
    '@wrap', # The failure case.
    '@wrap ',
    '@wrap\n',
    '@wrap\t',
)
for s in table:
    m = pat.search(s)
    assert m, repr(s)
#@+node:ekr.20071113145804.26: *4* @test g.convertPythonIndexToRowCol
s1 = 'abc\n\np\nxy'
table1 = (
    (-1,(0,0)), # One too small.
    (0,(0,0)),
    (1,(0,1)),
    (2,(0,2)),
    (3,(0,3)), # The newline ends a row.
    (4,(1,0)),
    (5,(2,0)),
    (6,(2,1)),
    (7,(3,0)),
    (8,(3,1)),
    (9,(3,2)), # One too many.
    (10,(3,2)), # Two too many.
)
s2 = 'abc\n\np\nxy\n'
table2 = (
    (9,(3,2)),
    (10,(4,0)), # One too many.
    (11,(4,0)), # Two too many.
)
s3 = 'ab' # Test special case.  This was the cause of off-by-one problems.
table3 = (
    (-1,(0,0)), # One too small.
    (0,(0,0)),
    (1,(0,1)),
    (2,(0,2)), # One too many.
    (3,(0,3)), # Two too many.
)

for s,table in ((s1,table1),(s2,table2)):
    for i,result in table:
        row,col = g.convertPythonIndexToRowCol(s,i)
        assert row == result[0], 'i: %d, expected row %d, got %d' % (i,result[0],row)
        assert col == result[1], 'i: %d, expected col %d, got %d' % (i,result[1],col)
#@+node:ekr.20071113145804.27: *4* @test g.convertRowColToPythonIndex
s1 = 'abc\n\np\nxy'
s2 = 'abc\n\np\nxy\n'
table1 = (
    (0,(-1,0)), # One too small.
    (0,(0,0)),
    (1,(0,1)),
    (2,(0,2)),
    (3,(0,3)), # The newline ends a row.
    (4,(1,0)),
    (5,(2,0)),
    (6,(2,1)),
    (7,(3,0)),
    (8,(3,1)),
    (9,(3,2)), # One too large.
)
table2 = (
    (9,(3,2)),
    (10,(4,0)), # One two many.
)
for s,table in ((s1,table1),(s2,table2)):
    for i,data in table:
        row,col = data
        result = g.convertRowColToPythonIndex(s,row,col)
        assert i == result, 'row: %d, col: %d, expected: %d, got: %s' % (row,col,i,result)
#@+node:ekr.20071113145804.21: *4* @test g.create_temp_file
theFile,fn = g.create_temp_file()
assert theFile
assert g.isString(fn)
#@+node:ekr.20100131180007.5403: *4* @test g.ensureLeadingNewlines
s = ' \n \n\t\naa bc'
s2 = 'aa bc'

for i in range(3):
    result = g.ensureLeadingNewlines(s,i)
    val = ('\n' * i) + s2
    assert result == val, 'expected %s, got %s' % (
        repr(val),repr(result))
#@+node:ekr.20100131180007.5404: *4* @test g.ensureTrailingNewlines
s = 'aa bc \n \n\t\n'
s2 = 'aa bc'

for i in range(3):
    result = g.ensureTrailingNewlines(s,i)
    val = s2 + ('\n' * i)
    assert result == val, 'expected %s, got %s' % (
        repr(val),repr(result))
#@+node:ekr.20111110073834.3843: *4* @test g.es_print
'''Make sure that g.trace doesn't add an extra newline.'''

import sys

def test():
    g.es_print('a')
    g.es_print('b')

try:
    sys.stdout = g.fileLikeObject()
    test()
    result = sys.stdout.get()
    assert result == 'a\nb\n',repr(result)
finally:
    sys.stdout = sys.__stdout__
#@+node:ekr.20071113145804.22: *4* @test g.es_trace
@first # -*- coding: utf-8 -*-

import sys

s = 'test ɯ'

def test():
    g.es_trace(s,color='red')

try:
    # Don't worry about the exact output.
    # Just test that it doesn't throw an exception.
    sys.stdout = g.fileLikeObject()
    test()

finally:
    sys.stdout = sys.__stdout__
#@+node:ekr.20140702101937.4245: *4* @test g.find_word
table = (
    ('abc a bc x','bc',0,6),
    ('abc a bc x','bc',1,6),
    ('abc a x','bc',0,-1),
)
for s,word,i,expected in table:
    actual = g.find_word(s,word,i)
    assert actual == expected
#@+node:ekr.20100131180007.5455: *4* @test g.fullPath
p2 = p.firstChild().firstChild()
path = g.fullPath(c,p2,simulate=True)
end = g.os_path_normpath('abc/xyz')
assert path.endswith(end),repr(path)
#@+node:ekr.20100131180007.5456: *5* @path abc
#@+node:ekr.20100131180007.5457: *6* xyz
#@+node:ekr.20071113090055.5: *4* @test g.get_directives_dict
# This will work regardless of where this method is.
@language python
@tabwidth -4
# @path xyzzy # Creates folder called xyzzy: interferes with other unit tests.
@pagewidth 120

d = c.atFileCommands.scanAllDirectives(p)
# print(d)
assert d.get('language') == 'python'
assert d.get('tabwidth') == -4
# assert d.get('path').endswith('xyzzy')
assert d.get('pagewidth') == 120
#@+node:ekr.20100131180007.5434: *4* @test g.get_directives_dict 2
@language python
@comment a b c
    # @comment must follow @language.
@tabwidth -8
@pagewidth 72
@encoding utf-8
# @path: anError # @path ends with ':'.

# @path xyzzy # Creates folder called xyzzy: interferes with other unit tests.

d = g.get_directives_dict(p)

# assert d.get('_p') == p # Never used, and a bad idea.
assert d.get('language') == 'python'
assert d.get('tabwidth') == '-8'
assert d.get('pagewidth') == '72'
assert d.get('encoding') == 'utf-8'
assert d.get('comment') == 'a b c'
assert not d.get('path'),d.get('path')
# assert d.get('path').endswith('xyzzy')
#@+node:ekr.20111018163546.3690: *4* @test g.getDocString
s1 = 'no docstring'
s2 = '''
# comment
"""docstring2."""
'''
s3 = '''
"""docstring3."""
\'\'\'docstring2.\'\'\'
'''

table = (
    (s1,''),
    (s2,'docstring2.'),
    (s3,'docstring3.'),
)

for s,result in table:
    s2 = g.getDocString(s)
    assert s2 == result,'Expected %s, got %s' % (repr(result),repr(s2))
#@+node:ekr.20061104172236.18: *4* @test g.getLine
s = 'a\ncd\n\ne'

for i,result in (
    (-1,(0,2)), # One too few.
    (0,(0,2)),(1,(0,2)),
    (2,(2,5)),(3,(2,5)),(4,(2,5)),
    (5,(5,6)),
    (6,(6,7)),
    (7,(6,7)), # One too many.
):
    j,k = g.getLine(s,i)
    assert (j,k) == result, 'i: %d, expected %d,%d, got %d,%d' % (i,result[0],result[1],j,k)
#@+node:ekr.20071113145804.28: *4* @test g.getScript strips crlf
script = g.getScript(c,p) # This will get the text of this node.
assert script.find('\r\n') == -1, repr(script)
#@+node:ekr.20061104172236.11: *4* @test g.getWord
s = 'abc xy_z5 pdq'
i,j = g.getWord(s,5)
assert s[i:j] == 'xy_z5','got %s' % s[i:j]
#@+node:ekr.20110612064437.3310: *4* @test g.guessExternalEditor
val = g.guessExternalEditor(c)
assert val,'no val' # This can be different on different platforms.
#@+node:ekr.20120307133953.3947: *4* @test g.handleUrl
import sys
if sys.platform.startswith('win'):
    file_, http, unl1 = 'file://', 'http://', 'unl:' + '//'
    fn1 = 'LeoDocs.leo#'
    fn2 = 'doc/LeoDocs.leo#'
    unl2 = '@settings-->Plugins-->wikiview plugin'
    unl3 = '@settings-->Plugins-->wikiview%20plugin'
    table = (
        (http + 'writemonkey.com/index.php', ['browser']),
        (file_ + 'x.py',        ['os_startfile']),
        (file_ + fn1,           ['g.recursiveUNLSearch']),
        (file_ + fn2,           ['g.recursiveUNLSearch']),
        (unl1 + fn1 + unl2,     ['g.recursiveUNLSearch']),
        (unl1 + fn1 + unl3,     ['g.recursiveUNLSearch']),
        (unl1 + '#' + unl2,     ['g.recursiveUNLSearch']),
        (unl1 + '#' + unl3,     ['g.recursiveUNLSearch']),
        (unl1 + unl2,           ['g.recursiveUNLSearch']),
        (unl1 + unl3,           ['g.recursiveUNLSearch']),
    )
    d = g.app.unitTestDict
    for url,aList in table:
        d = g.app.unitTestDict = {}
        g.handleUrl(c=c,p=c.p,url=url)
        for kind in aList:
            assert d.get(kind), 'kind: %r\nurl: %r\n%s' % (
                kind,url,g.dictToString(d))
#@+node:ekr.20111103213154.3824: *4* @test g.importFromPath
'''Make sure that trying to import a non-existent file does not crash g.importFromPath.'''

path = g.os_path_finalize_join(g.app.loadDir,'does_not_exist')
assert not g.os_path_exists(path)
module = g.importFromPath ('xyz',path,verbose=False)
assert not module,repr(module)
#@+node:ekr.20141208130803.11: *4* @test g.importModule
assert g.importModule('codewise',verbose=False)
    # Top-level .py file.
assert g.importModule('rope',verbose=False)
    # In a folder.
#@+node:ekr.20170122164330.1: *4* @test g.isDirective
# Do not try to reload g.
table = (
    (True, '@language python\n'),
    (True, '@tabwidth -4 #test\n'),
    (True, '@others\n'),
    (True, '    @others\n'),
    (True, '@encoding\n'),
    (False, '@encoding.setter\n'),
    (False, '@encoding("abc")\n'),
    (False, 'encoding = "abc"\n'),
)
for expected, s in table:
    result = g.isDirective(s)
    assert expected == bool(result), (expected, bool(result), repr(s))
#@+node:ekr.20101021205258.6010: *4* @test g.makeAllNonExistentDirectories
#@+node:ekr.20111104112332.3953: *4* @test g.os_path_finalize_join with thumb drive
import os

path1 = r'C:\Python32\Lib\site-packages\leo-editor\leo\core'
path2 = r'\N:Home\PTC_Creo\Creo.wmv'
path3 = r'N:\Home\PTC_Creo\Creo.wmv'

path12 = os.path.join(path1,path2)
path13 = os.path.join(path1,path3)

if 0:

    print(path12,g.os.path.abspath(path12))
    print(path13,g.os.path.abspath(path13))
#@+node:ekr.20071113145804.19: *4* @test g.pdb
import sys

# Not a good unit test; it probably will never fail.
def aFunction(): pass
assert type(g.pdb)==type(aFunction), 'wrong type for g.pdb: %s' % type(g.pdb)

class myStdout:
    def write(self,s):
        pass # g.es('From pdb:',s)

class myStdin:
    def readline (self):
        return 'c' # Return 'c' (continue) for all requests for input.

def restore():
    sys.stdout,sys.stdin = sys.__stdout__,sys.__stdin__

try:
    sys.stdin = myStdin() # Essential
    sys.stdout=myStdout() # Optional
    g.pdb()
    restore()
    # assert False,'test of reraising'
except Exception:
    restore()
    raise
#@+node:ekr.20111110073528.3843: *4* @test g.pr
'''Make sure that g.trace doesn't add an extra newline.'''

import sys

def test():
    g.pr('a')
    g.pr('b')

try:
    sys.stdout = g.fileLikeObject()
    test()
    result = sys.stdout.get()
    assert result == 'a\nb\n',repr(result)
finally:
    sys.stdout = sys.__stdout__
#@+node:ekr.20100212112056.5361: *4* @test g.printGcAll
g.printGcAll()
#@+node:ekr.20100131180007.5396: *4* @test g.removeBlankLines
for s,expected in (
    ('a\nb', 'a\nb'),
    ('\n  \n\nb\n', 'b\n'),
    (' \t \n\n  \n c\n\t\n', ' c\n'),
):
    result = g.removeBlankLines(s)
    assert result == expected, '\ns: %s\nexpected: %s\nresult:   %s' % (
        repr(s),repr(expected),repr(result))
#@+node:ekr.20071113145804.29: *4* @test g.removeExtraLws
for s,expected in (
    (' a\n b\n c', 'a\nb\nc'),
    (' \n  A\n    B\n  C\n', '\nA\n  B\nC\n'),
):
    result = g.removeExtraLws(s,c.tab_width)
    assert result == expected, '\ns: %s\nexpected: %s\nresult:   %s' % (
        repr(s),repr(expected),repr(result))
#@+node:ekr.20100131180007.5395: *4* @test g.removeLeadingBlankLines
for s,expected in (
    ('a\nb', 'a\nb'),
    ('\n  \nb\n', 'b\n'),
    (' \t \n\n\n c', ' c'),
):
    result = g.removeLeadingBlankLines(s)
    assert result == expected, '\ns: %s\nexpected: %s\nresult:   %s' % (
        repr(s),repr(expected),repr(result))
#@+node:ekr.20100131180007.5402: *4* @test g.removeTrailing
s = 'aa bc \n \n\t\n'
table = (
    ('\t\n ','aa bc'),
    ('abc\t\n ',''),
    ('c\t\n ','aa b'),
)

for arg,val in table:
    result = g.removeTrailing(s,arg)
    assert result == val, 'expected %s, got %s' % (val,result)
#@+node:ekr.20150328120706.1: *4* @test g.sanitize_filename
table = (
    ('A25&()','A'),         # Non-alpha characters.
    ('B\tc','B c'),         # Tabs.
    ('"AB"',"'AB'"),        # Double quotes.
    ('\\/:|<>*:.','_'),     # Special characters.
    ('_____________','_'),  # Combining underscores.
    ('A' * 200,'A' * 128),  # Maximum length.
    ('abc.','abc_'),        # Trailing dots.
)
for s,expected in table:
    got = g.sanitize_filename(s)
    assert got==expected,'s: %r expected: %r got: %r' % (s,expected,got)
#@+node:ekr.20080917151620.13: *4* @test g.scanAtHeaderDirectives header
@header

aList = g.get_directives_dict_list(p)
g.scanAtHeaderDirectives(aList)
#@+node:ekr.20100131180007.5435: *4* @test g.scanAtHeaderDirectives header
@header

c,p = g.getTestVars()
aList = g.get_directives_dict_list(p)
g.scanAtHeaderDirectives(aList)
#@+node:ekr.20080917151620.14: *4* @test g.scanAtHeaderDirectives noheader
@noheader

aList = g.get_directives_dict_list(p)
g.scanAtHeaderDirectives(aList)
#@+node:ekr.20080917151620.15: *4* @test g.scanAtLineendingDirectives cr
@lineending cr

aList = g.get_directives_dict_list(p)
s = g.scanAtLineendingDirectives(aList)

assert s == '\r'
#@+node:ekr.20080917151620.16: *4* @test g.scanAtLineendingDirectives crlf
@lineending crlf

aList = g.get_directives_dict_list(p)
s = g.scanAtLineendingDirectives(aList)
# print('@lineending: %s'%repr(s))

assert s == '\r\n'
#@+node:ekr.20080917151620.17: *4* @test g.scanAtLineendingDirectives lf
@lineending lf

aList = g.get_directives_dict_list(p)
s = g.scanAtLineendingDirectives(aList)

assert s == '\n'
#@+node:ekr.20080917151620.18: *4* @test g.scanAtLineendingDirectives nl
@lineending nl

aList = g.get_directives_dict_list(p)
s = g.scanAtLineendingDirectives(aList)

assert s == '\n'
#@+node:ekr.20080917151620.19: *4* @test g.scanAtLineendingDirectives platform
@lineending platform

import sys

aList = g.get_directives_dict_list(p)
s = g.scanAtLineendingDirectives(aList)

if sys.platform.startswith('win'):
    assert s == '\r\n'
else:
    assert s == '\n'
#@+node:ekr.20100131180007.5442: *4* @test g.scanAtPagewidthDirectives -40
@pagewidth -40

aList = g.get_directives_dict_list(p)
n = g.scanAtPagewidthDirectives(aList)

# The @pagewidth directive in the parent should control.
# Depending on how this test is run, the result could be 80 or None.
assert n in (None,80),repr(n)
#@+node:ekr.20080917151620.21: *4* @test g.scanAtPagewidthDirectives 40
@pagewidth 40

aList = g.get_directives_dict_list(p)
n = g.scanAtPagewidthDirectives(aList)

assert n == 40
#@+node:ekr.20080917151620.22: *4* @test g.scanAtPathDirectives ../test/unittest/at-path-test1.py
aList = g.get_directives_dict_list(p.firstChild())
s = c.scanAtPathDirectives(aList)
end = g.os_path_normpath(r'leo/test')

assert s.endswith(end),repr(s)
#@+node:ekr.20120228145505.4834: *5* @thin ../test/unittest/at-path-test1.py
@language python
# unittest/at-path-test1.py 
#@+node:ekr.20080917151620.27: *4* @test g.scanAtPathDirectives @path ../test @path unittest @thin at-path-test3.py
greatGrandChild = p.firstChild().firstChild().firstChild()
aList = g.get_directives_dict_list(greatGrandChild)
s = c.scanAtPathDirectives(aList)
end = g.os_path_normpath(r'leo/test/unittest')

assert s.endswith(end),repr(s)
#@+node:ekr.20080917151620.28: *5* @path ../test
#@+node:ekr.20080917151620.29: *6* @path unittest
#@+node:ekr.20120228145505.4838: *7* @thin at-path-test3.py
@language python
# unittest/at-path-test3.py 
#@+node:ekr.20080917151620.24: *4* @test g.scanAtPathDirectives @path ../test/unittest @thin at-path-test2.py
grandChild = p.firstChild().firstChild()
aList = g.get_directives_dict_list(grandChild)
s = c.scanAtPathDirectives(aList)
end = g.os_path_normpath(r'leo/test/unittest')

assert s.endswith(end),repr(s)
#@+node:ekr.20080917151620.25: *5* @path ../test/unittest
#@+node:ekr.20120228145505.4841: *6* @thin at-path-test2.py
@language python
# unittest/at-path-test2.py
#@+node:ekr.20080917151620.31: *4* @test g.scanAtTabwidthDirectives +6
@tabwidth 6

aList = g.get_directives_dict_list(p)
n = g.scanAtTabwidthDirectives(aList)

assert n == 6,repr(n)
#@+node:ekr.20080917151620.32: *4* @test g.scanAtTabwidthDirectives -6
@tabwidth -6

aList = g.get_directives_dict_list(p)
n = g.scanAtTabwidthDirectives(aList)

assert n == -6
#@+node:ekr.20080917151620.33: *4* @test g.scanAtWrapDirectives nowrap
@nowrap

aList = g.get_directives_dict_list(p)
s = g.scanAtWrapDirectives(aList)

assert s is False,repr(s)
#@+node:ekr.20080917151620.34: *4* @test g.scanAtWrapDirectives wrap (with @wrap)
@wrap

aList = g.get_directives_dict_list(p)
s = g.scanAtWrapDirectives(aList)

assert s is True,repr(s)
#@+node:ekr.20080917151620.35: *4* @test g.scanAtWrapDirectives wrap (without @nowrap)
aList = g.get_directives_dict_list(p)
s = g.scanAtWrapDirectives(aList)

assert s is None,repr(s)
#@+node:ekr.20100131180007.5426: *4* @test g.set_delims_from_language
# New in Leo 4.6, set_delims_from_language returns '' instead of None.
table = (
    ('c',       ('//','/*','*/')),
    ('python',  ('#','','')),
    ('xxxyyy',  ('','','')),
)

for language, expected in table:
    result = g.set_delims_from_language(language)
    assert result==expected,'language %s expected %s, got %s' % (
        language,expected,result)
#@+node:ekr.20100131180007.5425: *4* @test g.set_delims_from_string
# New in Leo 4.6, set_delims_from_string returns '' instead of None.
table = (
    ('c','@comment // /* */',   ('//','/*','*/')),
    ('c','// /* */',            ('//','/*','*/')),
    ('python','@comment #',     ('#','','')),
    ('python','#',              ('#','','')),
    ('xxxyyy','@comment a b c', ('a','b','c')),
    ('xxxyyy','a b c',          ('a','b','c')),
)

for language,s,expected in table:
    result = g.set_delims_from_string(s)
    assert result==expected,'language %s expected %s, got %s' % (
        language,expected,result)
#@+node:ekr.20100131180007.5421: *4* @test g.setDefaultDirectory
c,p = g.getTestVars()

# result,error = g.setDefaultDirectory(c,p,importing=False)
# assert error == ''
# assert result == c.openDirectory,result

result = g.setDefaultDirectory(c,p,importing=False)
assert result == c.openDirectory,result
#@+node:sps.20100609234650.16094: *4* @test g.skip_blank_lines
end = g.skip_blank_lines("",0)
assert end == 0, "expected 0, got %d" % end
end = g.skip_blank_lines(" ",0)
assert end == 0, "expected 0, got %d" % end
end = g.skip_blank_lines("\n",0)
assert end == 1, "expected 1, got %d" % end
end = g.skip_blank_lines(" \n",0)
assert end == 2, "expected 1, got %d" % end
end = g.skip_blank_lines("\n\na\n",0)
assert end == 2, "expected 2, got %d" % end
end = g.skip_blank_lines("\n\n a\n",0)
assert end == 2, "expected 2, got %d" % end
#@+node:ekr.20061104172236.15: *4* @test g.skip_line
s = 'a\n\nc'

for i,result in (
    (-1,2), # One too few.
    (0,2),(1,2),
    (2,3),
    (3,4),
    (4,4), # One too many.
):
    j = g.skip_line(s,i)
    assert j == result, 'i: %d, expected %d, got %d' % (i,result,j)
#@+node:ekr.20061104172236.16: *4* @test g.skip_to_end_of_line
s = 'a\n\nc'

for i,result in (
    (-1,1), # One too few.
    (0,1),(1,1),
    (2,2),
    (3,4),
    (4,4), # One too many.
):
    j = g.skip_to_end_of_line(s,i)
    assert j == result, 'i: %d, expected %d, got %d' % (i,result,j)
#@+node:ekr.20061104172236.17: *4* @test g.skip_to_start_of_line
s1 = 'a\n\nc'
table1 = (
    (-1,0), # One too few.
    (0,0),(1,0),
    (2,2),
    (3,3),
    (4,4), # One too many.
)
s2 = 'a\n'
table2 = ((1,0),(2,2)) # A special case at end.

for s,table in ((s1,table1),(s2,table2)):
    for i,result in table:
        j = g.skip_to_start_of_line(s,i)
        assert j == result, 'i: %d, expected %d, got %d' % (i,result,j)
#@+node:ekr.20150610130646.1: *4* @test g.splitLongFileName
table = (
    r'abcd/xy\pdqabc/aaa.py',
)
for s in table:
    g.splitLongFileName(s,limit=3)
    
#@+node:ekr.20130910062920.4149: *4* @test g.stripBOM
import codecs

# The hack of computing s below is not valid in Python 3.
if not g.isPython3:

    table = (
        ('utf-8',  codecs.BOM_UTF8),
        ('utf-16', codecs.BOM_UTF16_BE),
        ('utf-16', codecs.BOM_UTF16_LE),
        ('utf-32', codecs.BOM_UTF32_BE),
        ('utf-32', codecs.BOM_UTF32_LE),
    )
    for e,bom in table:
        s1 = 'this is a test'
        s = bom + 'this is a test'
        # print('%6s bom: %18r s: %s' % (e,bom,repr(s)))
        e2,s2 = g.stripBOM(s)
        assert e2 == e,'%s,%s' % (e,e2)
        assert s2 == s1,repr(s2)
#@+node:ekr.20100131180007.5427: *4* @test g.stripPathCruft
table =  (
    (None,None), # Retain empty paths for warnings.
    ('',''),
    (g.app.loadDir,g.app.loadDir),
    ('<abc>','abc'),
    ('"abc"','abc'),
    ("'abc'",'abc'),
)

for path,expected in table:
    result = g.stripPathCruft(path)
    assert result == expected
#@+node:ekr.20141223125432.11: *4* @test g.toUnicode(QString)
if not g.isPython3:
    import leo.core.leoQt as leoQt
    QString = leoQt.QString
    s = g.toUnicode(QString('abc'))
    assert s == 'abc',repr(s)
#@+node:ekr.20111110072415.3841: *4* @test g.trace
'''Make sure that g.trace doesn't add an extra newline.'''

import sys

def test():
    g.trace('a')
    g.trace('b')

try:
    sys.stdout = g.fileLikeObject()
    test()
    result = sys.stdout.get()
    assert result == 'test a\ntest b\n',repr(result)
finally:
    sys.stdout = sys.__stdout__
#@+node:ekr.20050105084757.1: *4* @test g.utils_remove
import os

exists = g.os_path_exists

path = g.os_path_join(g.app.testDir,'xyzzy')
if exists(path):
    os.remove(path)

assert not exists(path)
assert not g.utils_remove(path,verbose=False)

f = open(path,'w')
f.write('test')
f.close()

assert exists(path)
assert g.utils_remove(path,verbose=True)
assert not exists(path)
#@+node:ekr.20050105091547: *4* @test g.utils_rename
import os

exists = g.os_path_exists
path = g.os_path_join(g.app.testDir,'xyzzy')
path2 = g.os_path_join(g.app.testDir,'xyzzy2')

# Create both paths.
for p in (path,path2):
    if exists(p):
        os.remove(p)
    assert not exists(p)
    f = open(p,'w')
    f.write('test %s' % p)
    f.close()
    assert exists(p)

assert g.utils_rename(c,path,path2) #,verbose=True)
assert exists(path2)
f = open(path2)
s = f.read()
f.close()
# print('Contents of %s: %s' % (path2,s))
assert s == 'test %s' % path
os.remove(path2)
assert not exists(path)
#@+node:ekr.20100131180007.5429: *4* @test g.warnOnReadOnlyFile
import os,stat

fc = c.fileCommands
path = g.os_path_finalize_join(g.app.loadDir,'..','test','test-read-only.txt')
if os.path.exists(path):
    os.chmod(path, stat.S_IREAD)
    fc.warnOnReadOnlyFiles(path)
    assert fc.read_only
else:
    fc.warnOnReadOnlyFiles(path)
#@+node:ekr.20050208135429: *4* @test pre-definition of g in scripts
# print(g.listToString(dir()))

for ivar in ('c','g','p'):
    assert ivar in dir()
#@+node:ekr.20071113202153.2: *4* @test zz end of leoGlobals tests
# This is **not** a real unit test.
# It simply restores the screen to a more convenient state.

# c.contractParent()
# g.app.unitTestDict['restoreSelectedNode']=False

print('\nEnd of leoGlobals tests.')
#@+node:ekr.20100131171342.5599: *3* leoGui & leoQtGui
#@+node:ekr.20111120124051.3992: *4* @test Ctrl-I inserts only one headline
from leo.core.leoQt import QtCore,QtGui,QtWidgets
import leo.plugins.qt_events as qt_events
import sys
if g.app.isExternalUnitTest:
    self.skipTest('Can not be run externally')
elif sys.platform.startswith('linux'):
    self.skipTest('linux test')
else:
    def setup(p):
        delete_children(p)
        p2 = p.insertAsLastChild()
        c.selectPosition(p2)
        p2.h = 'first-child'
    
    def delete_children(p):
        while p.hasChildren():
            p.firstChild().doDelete()
    
    app = g.app.gui.qtApp
    assert issubclass(app.__class__,QtWidgets.QApplication)
    wrapper = c.frame.body.wrapper
    w = wrapper.widget
    assert g.isTextWrapper(wrapper),wrapper
    assert g.isTextWidget(w),w
    # w_name = w.__class__.__name__
    # bassert w_name in('QsciScintilla','LeoQTextBrowser'),w_name
    p1 = p.copy()
    filter_obj = qt_events.LeoQtEventFilter(c,w=w)
    g.app.unitTestDict[p.h] = filter_obj # preserve a pointer to the filter.
    try:
        ev = QtCore.QEvent
        table = (
            ev.KeyPress,
            # ev.KeyRelease, # Ignored except in QLineEdit's.
            # ev.ShortcutOverride, # Ignored everywhere.
        )
        for theType in table:
            # Create the event.
            setup(p1)
            e = QtGui.QKeyEvent(theType,ord('i'),QtCore.Qt.ControlModifier)
            # Pass it to eventFilter.
            filter_obj.eventFilter(w,e)
            # Check the results.
            c.redraw()
            n = p1.numberOfChildren()
            assert n==2,'%s children' % (n)
            delete_children(p1)
    finally:
        delete_children(p1)
        c.redraw()
#@+node:ekr.20111003145300.3466: *4* @test illegal drag gives warning
'''Test that dragging this node onto the child node generates a warning.'''
import sys
if sys.platform.startswith('linux'):
    self.skipTest('linux test')
else:
    fn = '<file name>'
    p2 = p.firstChild()
    tree = c.frame.tree
    w = tree.treeWidget
    if hasattr(tree,'treeWidget'):
        for w.was_control_drag in (True,False):
            tree.treeWidget.intraFileDrop(fn,p,p2)
            assert True==g.app.unitTestDict['checkMoveWithParentWithWarning']
#@+node:ekr.20111003145300.3467: *5* a
#@+node:ekr.20111123214629.3941: *4* @test unbound Alt-9 key is completely ignored
from leo.core.leoQt import QtCore,QtGui,QtWidgets
import leo.plugins.qt_events as qt_events
import sys
if g.app.isExternalUnitTest:
    self.skipTest('Can not be run externally')
elif sys.platform.startswith('linux'):
    self.skipTest('linux test')
else:
    wrapper = c.frame.body.wrapper
    w = wrapper.widget
    assert g.isTextWrapper(wrapper),wrapper
    assert g.isTextWidget(w),w
    filter_obj = qt_events.LeoQtEventFilter(c,w=w)
    g.app.unitTestDict[p.h] = filter_obj
        # keep a pointer to the filter.
    for z in c.k.bindingsDict.keys():
        if z.s == 'Alt+Key-9':
            # print('Alt-9 is bound')
            break
    else:
        # Create an Alt-9 key event.
        ev = QtCore.QEvent
        e = QtGui.QKeyEvent(ev.KeyPress,ord('9'),QtCore.Qt.AltModifier)
        filter_obj.eventFilter(w,e)
        # Assert that handleUnboundChar actually ignored it.
        assert g.app.unitTestDict.get('handleUnboundChar-ignore-alt-or-ctrl')
#@+node:ekr.20100131171342.5603: *4* @test zz end of leoGui tests
# This is **not** a real unit test.
# It simply restores the screen to a more convenient state.

# c.contractParent()
# g.app.unitTestDict['restoreSelectedNode']=False

print('\nEnd of leoGui tests.')
#@+node:ekr.20090529141856.4682: *3* leoImport
#@+node:ekr.20090529141856.4684: *4* Export tests
@language python
@tabwidth -4
#@+node:ekr.20090529141856.4685: *5* @suite Export tests
# Create unit tests in g.app.scriptDict["suite"]

suite = c.testManager.makeImportExportSuite("exportTests",doImport=False)

# g.app.scriptDict['suite'] = suite
#@+node:ekr.20090529141856.4698: *4* Import tests
#@+node:ekr.20090529141856.4699: *5* @suite Import tests
# Create unit tests in g.app.scriptDict["suite"]

suite = c.testManager.makeImportExportSuite("importTests",doImport=True)

# g.app.scriptDict['suite'] = suite
#@+node:ekr.20090529141856.4716: *4* Tests of @auto
@tabwidth -4
@language python
#@+node:ekr.20090529141856.4783: *5* @test collapse-all
# Not a real unit test.
c.contractAllHeadlines()
#@+node:ekr.20090529141856.4717: *5* C tests
#@+node:ekr.20090529141856.4718: *6* @test c class 1
if 0: # Preamble
    # g.cls()
    if c.isChanged(): c.save()
    import leo.core.leoImport as leoImport
    import leo.plugins.importers.linescanner as linescanner
    import leo.plugins.importers.c
    import imp
    imp.reload(leo.plugins.importers.linescanner)
    imp.reload(leo.plugins.importers.c)
    imp.reload(leoImport)
    g.app.loadManager.createAllImporetersData()
    ic = leoImport.LeoImportCommands(c)
else:
    ic = c.importCommands  

s = '''\
class cTestClass1 {

    int foo (int a) {
        a = 2 ;
    }

    char bar (float c) {
        ;
    }
}
'''
table = (
    'class cTestClass1',
    'int foo',
    'char bar',
)
try:
    ic.cUnitTest(p,s=s,showTree=True)
    if 1: # Check structure
        root = c.p.lastChild()
        assert root.h.startswith('@@'), root.h
        p2 = root.firstChild()
        for h in table:
            assert p2.h == h, (p2.h, h)
            p2.moveToThreadNext()
        assert not root.isAncestorOf(p2), p2.h # Extra nodes
finally:
    if 1: # Delete children
        p.deleteAllChildren()
    c.redraw()
#@+node:ekr.20090529141856.4719: *6* @test c class--underindented line
if 0: # Preamble
    # g.cls()
    if c.isChanged(): c.save()
    import leo.core.leoImport as leoImport
    import leo.plugins.importers.linescanner as linescanner
    import leo.plugins.importers.c
    import imp
    imp.reload(leo.plugins.importers.linescanner)
    imp.reload(leo.plugins.importers.c)
    imp.reload(leoImport)
    g.app.loadManager.createAllImporetersData()
    ic = leoImport.LeoImportCommands(c)
else:
    ic = c.importCommands  
s = '''\
class cTestClass1 {

    int foo (int a) {
// an underindented line.
        a = 2 ;
    }

    // This should go with the next function.

    char bar (float c) {
        ;
    }
}
'''
table = (
    'class cTestClass1',
    'int foo',
    'char bar',
)
try:
    ic.cUnitTest(p,s=s,showTree=True)
    if 1: # Check structure
        root = c.p.lastChild()
        assert root.h.startswith('@@'), root.h
        p2 = root.firstChild()
        for h in table:
            assert p2.h == h, (p2.h, h)
            p2.moveToThreadNext()
        assert not root.isAncestorOf(p2), p2.h # Extra nodes
finally:
    if 1: # Delete children
        p.deleteAllChildren()
    c.redraw()
#@+node:ekr.20090529141856.4721: *6* @test c comment follows arg list
if 0: # Preamble
    # g.cls()
    if c.isChanged(): c.save()
    import leo.core.leoImport as leoImport
    import leo.plugins.importers.linescanner as linescanner
    import leo.plugins.importers.c
    import imp
    imp.reload(leo.plugins.importers.linescanner)
    imp.reload(leo.plugins.importers.c)
    imp.reload(leoImport)
    g.app.loadManager.createAllImporetersData()
    ic = leoImport.LeoImportCommands(c)
else:
    ic = c.importCommands
s = '''\
void
aaa::bbb::doit
    (
    awk* b
    )
{
    assert(false);
}

bool
aaa::bbb::dothat
    (
    xyz *b
    ) //  <---------------------problem
{
    return true;
}
'''
table = (
    'void aaa::bbb::doit',
    'bool aaa::bbb::dothat',
)
try:
    ic.cUnitTest(p,s=s,showTree=True)
    if 1: # Check structure
        root = c.p.lastChild()
        assert root.h.startswith('@@'), root.h
        p2 = root.firstChild()
        for h in table:
            assert p2.h == h, (p2.h, h)
            p2.moveToThreadNext()
        assert not root.isAncestorOf(p2), p2.h # Extra nodes
finally:
    if 1: # Delete children 
        p.deleteAllChildren()
    c.redraw()
#@+node:ekr.20090529141856.4722: *6* @test c comment follows block delim
if 0: # Preamble
    # g.cls()
    if c.isChanged(): c.save()
    import leo.core.leoImport as leoImport
    import leo.plugins.importers.linescanner as linescanner
    import leo.plugins.importers.c
    import imp
    imp.reload(leo.plugins.importers.linescanner)
    imp.reload(leo.plugins.importers.c)
    imp.reload(leoImport)
    g.app.loadManager.createAllImporetersData()
    ic = leoImport.LeoImportCommands(c)
else:
    ic = c.importCommands  
s = '''\
void
aaa::bbb::doit
    (
    awk* b
    )
{
    assert(false);
}

bool
aaa::bbb::dothat
    (
    xyz *b
    ) 
{
    return true;
} //  <---------------------problem
'''
table = (
    'void aaa::bbb::doit',
    'bool aaa::bbb::dothat',
)
try:
    ic.cUnitTest(p,s=s,showTree=True)
    if 1: # Check structure
        root = c.p.lastChild()
        assert root.h.startswith('@@'), root.h
        p2 = root.firstChild()
        for h in table:
            assert p2.h == h, (p2.h, h)
            p2.moveToThreadNext()
        assert not root.isAncestorOf(p2), p2.h # Extra nodes
finally:
    if 1: # Delete children
        p.deleteAllChildren()
    c.redraw()
#@+node:ekr.20090529141856.4723: *6* @test c intermixed blanks and tabs
if 0: # Preamble
    # g.cls()
    if c.isChanged(): c.save()
    import leo.core.leoImport as leoImport
    import leo.plugins.importers.linescanner as linescanner
    import leo.plugins.importers.c
    import imp
    imp.reload(leo.plugins.importers.linescanner)
    imp.reload(leo.plugins.importers.c)
    imp.reload(leoImport)
    g.app.loadManager.createAllImporetersData()
    ic = leoImport.LeoImportCommands(c)
else:
    ic = c.importCommands
s = '''
void
aaa::bbb::doit
    (
    awk* b  // leading blank
    )
{
	assert(false); // leading tab
}

'''
table = (
    'void aaa::bbb::doit',
)
try:
    ic.cUnitTest(p,s=s,showTree=True)
    if 1: # Check structure
        root = c.p.lastChild()
        assert root.h.startswith('@@'), root.h
        p2 = root.firstChild()
        for h in table:
            assert p2.h == h, (p2.h, h)
            p2.moveToThreadNext()
        assert not root.isAncestorOf(p2), p2.h # Extra nodes
finally:
    if 1: # Delete children
        p.deleteAllChildren()
    c.redraw()
#@+node:ekr.20090529141856.4724: *6* @test c old-style decl 1
if 0: # Preamble
    # g.cls()
    if c.isChanged(): c.save()
    import leo.core.leoImport as leoImport
    import leo.plugins.importers.linescanner as linescanner
    import leo.plugins.importers.c
    import imp
    imp.reload(leo.plugins.importers.linescanner)
    imp.reload(leo.plugins.importers.c)
    imp.reload(leoImport)
    g.app.loadManager.createAllImporetersData()
    ic = leoImport.LeoImportCommands(c)
else:
    ic = c.importCommands  
s = '''\
static void
ReleaseCharSet(cset)
    CharSet *cset;
{
    ckfree((char *)cset->chars);
    if (cset->ranges) {
    ckfree((char *)cset->ranges);
    }
}
'''
table = (
    'static void ReleaseCharSet',
)
try:
    ic.cUnitTest(p,s=s,showTree=True)
    if 1: # Check structure
        root = c.p.lastChild()
        assert root.h.startswith('@@'), root.h
        p2 = root.firstChild()
        for h in table:
            assert p2.h == h, (p2.h, h)
            p2.moveToThreadNext()
        assert not root.isAncestorOf(p2), p2.h # Extra nodes
finally:
    if 1: # Delete children
        p.deleteAllChildren()
    c.redraw()
#@+node:ekr.20090529141856.4725: *6* @test c old-style decl 2
if 0: # Preamble
    # g.cls()
    if c.isChanged(): c.save()
    import leo.core.leoImport as leoImport
    import leo.plugins.importers.linescanner as linescanner
    import leo.plugins.importers.c
    import imp
    imp.reload(leo.plugins.importers.linescanner)
    imp.reload(leo.plugins.importers.c)
    imp.reload(leoImport)
    g.app.loadManager.createAllImporetersData()
    ic = leoImport.LeoImportCommands(c)
else:
    ic = c.importCommands  
s = '''\
Tcl_Obj *
Tcl_NewLongObj(longValue)
    register long longValue;	/* Long integer used to initialize the
         * new object. */
{
    return Tcl_DbNewLongObj(longValue, "unknown", 0);
}
'''
table = (
    'Tcl_Obj * Tcl_NewLongObj',
)
try:
    ic.cUnitTest(p,s=s,showTree=True)
    if 1: # Check structure
        root = c.p.lastChild()
        assert root.h.startswith('@@'), root.h
        p2 = root.firstChild()
        for h in table:
            assert p2.h == h, (p2.h, h)
            p2.moveToThreadNext()
        assert not root.isAncestorOf(p2), p2.h # Extra nodes
finally:
    if 1: # Delete children
        p.deleteAllChildren()
    c.redraw()
#@+node:ekr.20090529141856.4726: *6* @test c extern
if 0: # Preamble
    # g.cls()
    if c.isChanged(): c.save()
    import leo.core.leoImport as leoImport
    import leo.plugins.importers.linescanner as linescanner
    import leo.plugins.importers.c
    import imp
    imp.reload(leo.plugins.importers.linescanner)
    imp.reload(leo.plugins.importers.c)
    imp.reload(leoImport)
    g.app.loadManager.createAllImporetersData()
    ic = leoImport.LeoImportCommands(c)
else:
    ic = c.importCommands  
s = '''\
extern "C"
{
#include "stuff.h"
void    init(void);
#include "that.h"
}
'''
table = (
    'extern "C"',
)
try:
    ic.cUnitTest(p,s=s,showTree=True)
    if 1:
        root = c.p.lastChild()
        assert root.h.startswith('@@'), root.h
        p2 = root.firstChild()
        for h in table:
            assert p2.h == h, (p2.h, h)
            p2.moveToThreadNext()
        assert not root.isAncestorOf(p2), p2.h # Extra nodes
finally:
    if 1: # Delete children
        p.deleteAllChildren()
    c.redraw()
#@+node:ekr.20090529141856.4727: *5* c# tests
#@+node:ekr.20090529141856.4728: *6* @test c# namespace indent
s = '''\
namespace {
    class cTestClass1 {
        ;
    }
}
'''
try:
    c.importCommands.cSharpUnitTest(p,s=s,showTree=True)
    table = [
        'namespace',
        'class cTestClass1',
    ]
    root = c.p.firstChild()
    assert root.h.endswith('c# namespace indent'), root.h
    p2 = root.firstChild()
    for i, h in enumerate(table):
        assert p2.h == h, (p2.h, h)
        p2.moveToThreadNext()
finally:
    if 1:
        p.deleteAllChildren()
        c.redraw()
#@+node:ekr.20090529141856.4729: *6* @test c# namespace no indent
s = '''\
namespace {
class cTestClass1 {
    ;
}
}
'''
try:
    c.importCommands.cSharpUnitTest(p,s=s,showTree=True)
    table = [
        'namespace',
        'class cTestClass1',
    ]
    root = c.p.firstChild()
    assert root.h.endswith('c# namespace no indent'), root.h
    p2 = root.firstChild()
    for i, h in enumerate(table):
        assert p2.h == h, (p2.h, h)
        p2.moveToThreadNext()
finally:
    if 1:
        p.deleteAllChildren()
        c.redraw()
#@+node:ekr.20090529141856.4730: *6* @@test c# ref card
import sys

if sys.platform.lower().startswith('win'):

    fileName = g.os_path_abspath(g.os_path_join(
        g.app.loadDir,'..','test','big-c#-test.c#'))
    f = open(fileName)
    s = f.read()
    f.close()
    c.importCommands.cSharpUnitTest(p,s=s,fileName=fileName,showTree=False)
#@+node:ekr.20161108034116.1: *5* coffeescript tests
#@+node:ekr.20161108034138.1: *6* @test coffeescript-1
@killcolor

s = r'''

# The JavaScript to CoffeeScript compiler.
# Common usage:
#
#
#     var src = "var square = function(n) { return n * n };"
#
#     js2coffee = require('js2coffee');
#     js2coffee.build(src);
#     //=> "square = (n) -> n * n"

# ## Requires
#
# Js2coffee relies on Narcissus's parser. (Narcissus is Mozilla's JavaScript
# engine written in JavaScript).

{parser} = @Narcissus or require('./narcissus_packed')

_ = @_ or require('underscore')

{Types, Typenames, Node} = @NodeExt or require('./node_ext')

{Code, p, strEscape, unreserve, unshift, isSingleLine, trim, blockTrim,
  ltrim, rtrim, strRepeat, paren, truthy} = @Js2coffeeHelpers or require('./helpers')

# ## Main entry point
# This is `require('js2coffee').build()`. It takes a JavaScript source
# string as an argument, and it returns the CoffeeScript version.
#
# 1. Ask Narcissus to break it down into Nodes (`parser.parse`). This
#    returns a `Node` object of type `script`.
#
# 2. This node is now passed onto `Builder#build()`.

buildCoffee = (str) ->
  str  = str.replace /\r/g, ''
  str += "\n"

  builder    = new Builder
  scriptNode = parser.parse str

  output = trim builder.build(scriptNode)
  (rtrim line for line in output.split('\n')).join('\n')
# ## Builder class
# This is the main class that proccesses the AST and spits out streng.
# See the `buildCoffee()` function above for info on how this is used.

class Builder
  constructor: ->
    @transformer = new Transformer
  # `build()`
  # The main entry point.

  # This finds the appropriate @builder function for `node` based on it's type,
  # the passes the node onto that function.
  #
  # For instance, for a `function` node, it calls `@builders.function(node)`.
  # It defaults to `@builders.other` if it can't find a function for it.

  build: (args...) ->
    node = args[0]
    @transform node

    name = 'other'
    name = node.typeName()  if node != undefined and node.typeName

    fn  = (@[name] or @other)
    out = fn.apply(this, args)

    if node.parenthesized then paren(out) else out
  # `transform()`
  # Perform a transformation on the node, if a transformation function is
  # available.

  transform: (args...) ->
    @transformer.transform.apply(@transformer, args)
  # `body()`
  # Works like `@build()`, and is used for code blocks. It cleans up the returned
  # code block by removing any extraneous spaces and such.

  body: (node, opts={}) ->
    str = @build(node, opts)
    str = blockTrim(str)
    str = unshift(str)

    if str.length > 0 then str else ""
  # ## The builders
  #
  # Each of these method are passed a Node, and is expected to return
  # a string representation of it CoffeeScript counterpart.
  #
  # These are invoked using the main entry point, `Builder#build()`.

  # `script`
  # This is the main entry point.

  'script': (n, opts={}) ->
    c = new Code

    # *Functions must always be declared first in a block.*
    _.each n.functions,    (item) => c.add @build(item)
    _.each n.nonfunctions, (item) => c.add @build(item)

    c.toString()
  # `property_identifier`
  # A key in an object literal.

  'property_identifier': (n) ->
    str = n.value.toString()

    # **Caveat:**
    # *In object literals like `{ '#foo click': b }`, ensure that the key is
    # quoted if need be.*

    if str.match(/^([_\$a-z][_\$a-z0-9]*)$/i) or str.match(/^[0-9]+$/i)
      str
    else
      strEscape str
  # `identifier`
  # Any object identifier like a variable name.

  'identifier': (n) ->
    if n.value is 'undefined'
      '`undefined`'
    else if n.property_accessor
      n.value.toString()
    else
      unreserve n.value.toString()
  'number': (n) ->
    "#{n.src()}"
  'id': (n) ->
    if n.property_accessor
      n
    else
      unreserve n
  # `id_param`
  # Function parameters. Belongs to `list`.

  'id_param': (n) ->
    if n.toString() in ['undefined']
      "#{n}_"
    else
      @id n
  # `return`
  # A return statement. Has `n.value` of type `id`.

  'return': (n) ->
    if not n.value?
      "return\n"

    else
      "return #{@build(n.value)}\n"
  # `;` (aka, statement)
  # A single statement.

  ';': (n) ->
    # **Caveat:**
    # Some statements can be blank as some people are silly enough to use `;;`
    # sometimes. They should be ignored.

    unless n.expression?
      ""

    else if n.expression.typeName() == 'object_init'
      src = @object_init(n.expression)
      if n.parenthesized
        src
      else
        "#{unshift(blockTrim(src))}\n"

    else
      @build(n.expression) + "\n"
  # `new` + `new_with_args`
  # For `new X` and `new X(y)` respctively.

  'new': (n) -> "new #{@build n.left()}"
  'new_with_args': (n) -> "new #{@build n.left()}(#{@build n.right()})"
  # ### Unary operators

  'unary_plus': (n) -> "+#{@build n.left()}"
  'unary_minus': (n) -> "-#{@build n.left()}"
  # ### Keywords

  'this': (n) -> 'this'
  'null': (n) -> 'null'
  'true': (n) -> 'true'
  'false': (n) -> 'false'
  'void': (n) -> 'undefined'
  'debugger': (n) -> "debugger\n"
  'break': (n) -> "break\n"
  'continue': (n) -> "continue\n"
  # ### Some simple operators

  '~': (n) -> "~#{@build n.left()}"
  'typeof': (n) -> "typeof #{@build n.left()}"
  'index': (n) ->
    right = @build n.right()
    if _.any(n.children, (child) -> child.typeName() == 'object_init' and child.children.length > 1)
      right = "{#{right}}"
    "#{@build n.left()}[#{right}]"
  'throw': (n) -> "throw #{@build n.exception}"
  '!': (n) ->
    target = n.left()
    negations = 1
    ++negations while (target.isA '!') and target = target.left()
    if (negations & 1) and target.isA '==', '!=', '===', '!==', 'in', 'instanceof' # invertible binary operators
      target.negated = not target.negated
      return @build target
    "#{if negations & 1 then 'not ' else '!!'}#{@build target}"
  # ### Binary operators
  # All of these are rerouted to the `binary_operator` @builder.

  # TODO: make a function that generates these functions, invoked like so:
  #   in: binop 'in', 'of'
  #   '+': binop '+'
  #   and so on...

  in: (n) ->    @binary_operator n, 'of'
  '+': (n) ->   @binary_operator n, '+'
  '-': (n) ->   @binary_operator n, '-'
  '*': (n) ->   @binary_operator n, '*'
  '/': (n) ->   @binary_operator n, '/'
  '%': (n) ->   @binary_operator n, '%'
  '>': (n) ->   @binary_operator n, '>'
  '<': (n) ->   @binary_operator n, '<'
  '&': (n) ->   @binary_operator n, '&'
  '|': (n) ->   @binary_operator n, '|'
  '^': (n) ->   @binary_operator n, '^'
  '&&': (n) ->  @binary_operator n, 'and'
  '||': (n) ->  @binary_operator n, 'or'
  '<<': (n) ->  @binary_operator n, '<<'
  '<=': (n) ->  @binary_operator n, '<='
  '>>': (n) ->  @binary_operator n, '>>'
  '>=': (n) ->  @binary_operator n, '>='
  '===': (n) -> @binary_operator n, 'is'
  '!==': (n) -> @binary_operator n, 'isnt'
  '>>>': (n) ->  @binary_operator n, '>>>'
  instanceof: (n) -> @binary_operator n, 'instanceof'
  '==': (n) ->
    # TODO: throw warning
    @binary_operator n, 'is'
  '!=': (n) ->
    # TODO: throw warning
    @binary_operator n, 'isnt'
  'binary_operator': do ->
    INVERSIONS =
      is: 'isnt'
      in: 'not in'
      of: 'not of'
      instanceof: 'not instanceof'
    INVERSIONS[v] = k for own k, v of INVERSIONS
    (n, sign) ->
      sign = INVERSIONS[sign] if n.negated
      "#{@build n.left()} #{sign} #{@build n.right()}"
  # ### Increments and decrements
  # For `a++` and `--b`.

  '--': (n) -> @increment_decrement n, '--'
  '++': (n) -> @increment_decrement n, '++'
  'increment_decrement': (n, sign) ->
    if n.postfix
      "#{@build n.left()}#{sign}"
    else
      "#{sign}#{@build n.left()}"
  # `=` (aka, assignment)
  # For `a = b` (but not `var a = b`: that's `var`).

  '=': (n) ->
    sign = if n.assignOp?
      Types[n.assignOp] + '='
    else
      '='

    "#{@build n.left()} #{sign} #{@build n.right()}"
  # `,` (aka, comma)
  # For `a = 1, b = 2'

  ',': (n) ->
    list = _.map n.children, (item) => @build(item) + "\n"
    list.join('')
  # `regexp`
  # Regular expressions.

  'regexp': (n) ->
    m     = n.value.toString().match(/^\/(.*)\/([a-z]?)/)
    value = m[1]
    flag  = m[2]

    # **Caveat:**
    # *If it begins with `=` or a space, the CoffeeScript parser will choke if
    # it's written as `/=/`. Hence, they are written as `new RegExp('=')`.*

    begins_with = value[0]

    if begins_with in [' ', '=']
      if flag.length > 0
        "RegExp(#{strEscape value}, \"#{flag}\")"
      else
        "RegExp(#{strEscape value})"
    else
      "/#{value}/#{flag}"
  'string': (n) ->
    strEscape n.value
  # `call`
  # A Function call.
  # `n.left` is an `id`, and `n.right` is a `list`.

  'call': (n) ->
    if n.right().children.length == 0
      "#{@build n.left()}()"
    else
      "#{@build n.left()}(#{@build n.right()})"
  # `call_statement`
  # A `call` that's on it's own line.

  'call_statement': (n) ->
    left = @build n.left()

    # **Caveat:**
    # *When calling in this way: `function () { ... }()`,
    # ensure that there are parenthesis around the anon function
    # (eg, `(-> ...)()`).*

    left = paren(left)  if n.left().isA('function')

    if n.right().children.length == 0
      "#{left}()"
    else
      "#{left} #{@build n.right()}"
  # `list`
  # A parameter list.

  'list': (n) ->
    list = _.map(n.children, (item) =>
      if n.children.length > 1
        item.is_list_element = true
      @build(item))

    list.join(", ")
  'delete': (n) ->
    ids = _.map(n.children, (el) => @build(el))
    ids = ids.join(', ')
    "delete #{ids}\n"
  # `.` (scope resolution?)
  # For instances such as `object.value`.

  '.': (n) ->
    # **Caveat:**
    # *If called as `this.xxx`, it should use the at sign (`n.xxx`).*

    # **Caveat:**
    # *If called as `x.prototype`, it should use double colons (`x::`).*

    left  = @build n.left()
    right_obj = n.right()
    right_obj.property_accessor = true
    right = @build right_obj

    if n.isThis and n.isPrototype
      "@::"
    else if n.isThis
      "@#{right}"
    else if n.isPrototype
      "#{left}::"
    else if n.left().isPrototype
      "#{left}#{right}"
    else
      "#{left}.#{right}"
  'try': (n) ->
    c = new Code
    c.add 'try'
    c.scope @body(n.tryBlock)

    _.each n.catchClauses, (clause) =>
      c.add @build(clause)

    if n.finallyBlock?
      c.add "finally"
      c.scope @body(n.finallyBlock)

    c
  'catch': (n) ->
    body_ = @body(n.block)
    return '' if trim(body_).length == 0

    c = new Code

    if n.varName?
      c.add "catch #{n.varName}"
    else
      c.add 'catch'

    c.scope @body(n.block)
    c
  # `?` (ternary operator)
  # For `a ? b : c`. Note that these will always be parenthesized, as (I
  # believe) the order of operations in JS is different in CS.

  '?': (n) ->
    "(if #{@build n.left()} then #{@build n.children[1]} else #{@build n.children[2]})"
  'for': (n) ->
    c = new Code

    if n.setup?
      c.add "#{@build n.setup}\n"

    if n.condition?
      c.add "while #{@build n.condition}\n"
    else
      c.add "loop"

    c.scope @body(n.body)
    c.scope @body(n.update)  if n.update?
    c
  'for_in': (n) ->
    c = new Code

    c.add "for #{@build n.iterator} of #{@build n.object}"
    c.scope @body(n.body)
    c
  'while': (n) ->
    c = new Code

    keyword   = if n.positive then "while" else "until"
    body_     = @body(n.body)

    # *Use `loop` whin something will go on forever (like `while (true)`).*
    if truthy(n.condition)
      statement = "loop"
    else
      statement = "#{keyword} #{@build n.condition}"

    if isSingleLine(body_) and statement isnt "loop"
      c.add "#{trim body_}  #{statement}\n"
    else
      c.add statement
      c.scope body_
    c
  'do': (n) ->
    c = new Code

    c.add "loop"
    c.scope @body(n.body)
    c.scope "break unless #{@build n.condition}"  if n.condition?

    c
  'if': (n) ->
    c = new Code

    keyword = if n.positive then "if" else "unless"
    body_   = @body(n.thenPart)
    n.condition.parenthesized = false

    # *Account for `if (xyz) {}`, which should be `xyz`. (#78)*
    # *Note that `!xyz` still compiles to `xyz` because the `!` will not change anything.*
    if n.thenPart.isA('block') and n.thenPart.children.length == 0 and !n.elsePart?
      console.log n.thenPart
      c.add "#{@build n.condition}\n"

    else if isSingleLine(body_) and !n.elsePart?
      c.add "#{trim body_}  #{keyword} #{@build n.condition}\n"

    else
      c.add "#{keyword} #{@build n.condition}"
      c.scope @body(n.thenPart)

      if n.elsePart?
        if n.elsePart.typeName() == 'if'
          c.add "else #{@build(n.elsePart).toString()}"
        else
          c.add "else\n"
          c.scope @body(n.elsePart)

    c
  'switch': (n) ->
    c = new Code

    c.add "switch #{@build n.discriminant}\n"

    fall_through = false
    _.each n.cases, (item) =>
      if item.value == 'default'
        c.scope "else"
      else
        if fall_through == true
          c.add ", #{@build item.caseLabel}\n"
        else
          c.add "  when #{@build item.caseLabel}"
          
      if @body(item.statements).length == 0
        fall_through = true
      else
        fall_through = false
        c.add "\n"
        c.scope @body(item.statements), 2

      first = false

    c
  'existence_check': (n) ->
    "#{@build n.left()}?"
  'array_init': (n) ->
    if n.children.length == 0
      "[]"
    else
      "[ #{@list n} ]"
  # `property_init`
  # Belongs to `object_init`;
  # left is a `identifier`, right can be anything.

  'property_init': (n) ->
    left = n.left()
    right = n.right()
    right.is_property_value = true
    "#{@property_identifier left}: #{@build right}"
  # `object_init`
  # An object initializer.
  # Has many `property_init`.

  'object_init': (n, options={}) ->
    if n.children.length == 0
      "{}"

    else if n.children.length == 1 and not (n.is_property_value or n.is_list_element)
      @build n.children[0]

    else
      list = _.map n.children, (item) => @build item

      c = new Code
      c.scope list.join("\n")
      c = "{#{c}}"  if options.brackets?
      c
  # `function`
  # A function. Can be an anonymous function (`function () { .. }`), or a named
  # function (`function name() { .. }`).

  'function': (n) ->
    c = new Code

    params = _.map n.params, (str) =>
      if str.constructor == String
        @id_param str
      else
        @build str

    if n.name
      c.add "#{n.name} = "

    if n.params.length > 0
      c.add "(#{params.join ', '}) ->"
    else
      c.add "->"

    body = @body(n.body)
    if trim(body).length > 0
      c.scope body
    else
      c.add "\n"

    c
  'var': (n) ->
    list = _.map n.children, (item) =>
      "#{unreserve item.value} = #{if item.initializer? then @build(item.initializer) else 'undefined'}"

    _.compact(list).join("\n") + "\n"
  # ### Unsupported things
  #
  # Due to CoffeeScript limitations, the following things are not supported:
  #
  #  * New getter/setter syntax (`x.prototype = { get name() { ... } };`)
  #  * Break labels (`my_label: ...`)
  #  * Constants

  'other': (n) ->   @unsupported n, "#{n.typeName()} is not supported yet"
  'getter': (n) ->  @unsupported n, "getter syntax is not supported; use __defineGetter__"
  'setter': (n) ->  @unsupported n, "setter syntax is not supported; use __defineSetter__"
  'label': (n) ->   @unsupported n, "labels are not supported by CoffeeScript"
  'const': (n) ->   @unsupported n, "consts are not supported by CoffeeScript"
  'block': (args...) ->
    @script.apply @, args
  # `unsupported()`
  # Throws an unsupported error.
  'unsupported': (node, message) ->
    throw new UnsupportedError("Unsupported: #{message}", node)
# ## AST manipulation
# Manipulation of the abstract syntax tree happens here. All these are done on
# the `build()` step, done just before a node is passed onto `Builders`.

class Transformer
  transform: (args...) ->
    node = args[0]
    return  if node.transformed?
    type = node.typeName()
    fn = @[type]

    if fn
      fn.apply(this, args)
      node.transformed = true
  'script': (n) ->
    n.functions    = []
    n.nonfunctions = []

    _.each n.children, (item) =>
      if item.isA('function')
        n.functions.push item
      else
        n.nonfunctions.push item

    last = null

    # *Statements don't need parens, unless they are consecutive object
    # literals.*
    _.each n.nonfunctions, (item) =>
      if item.expression?
        expr = item.expression

        if last?.isA('object_init') and expr.isA('object_init')
          item.parenthesized = true
        else
          item.parenthesized = false

        last = expr
  '.': (n) ->
    n.isThis      = n.left().isA('this')
    n.isPrototype = (n.right().isA('identifier') and n.right().value == 'prototype')
  ';': (n) ->
    if n.expression?
      # *Statements don't need parens.*
      n.expression.parenthesized = false

      # *If the statement only has one function call (eg, `alert(2);`), the
      # parentheses should be omitted (eg, `alert 2`).*
      if n.expression.isA('call')
        n.expression.type = Typenames['call_statement']
        @call_statement n
  'function': (n) ->
    # *Unwrap the `return`s.*
    n.body.walk last: true, (parent, node, list) ->
      if node.isA('return') and node.value
        # Hax
        lastNode = if list
          parent[list]
        else
          parent.children[parent.children.length-1]

        if lastNode
          lastNode.type = Typenames[';']
          lastNode.expression = lastNode.value
  'switch': (n) ->
    _.each n.cases, (item) =>
      block = item.statements
      ch    = block.children

      # *CoffeeScript does not need `break` statements on `switch` blocks.*
      delete ch[ch.length-1] if block.last()?.isA('break')
  'call_statement': (n) ->
    if n.children[1]
      _.each n.children[1].children, (child, i) ->
        if child.isA('function') and i != n.children[1].children.length-1
          child.parenthesized = true
  'return': (n) ->
    # *Doing "return {x:2, y:3}" should parenthesize the return value.*
    if n.value and n.value.isA('object_init') and n.value.children.length > 1
      n.value.parenthesized = true
  'block': (n) ->
    @script n
  'if': (n) ->
    # *Account for `if(x) {} else { something }` which should be `something unless x`.*
    if n.thenPart.children.length == 0 and n.elsePart?.children.length > 0
      n.positive = false
      n.thenPart = n.elsePart
      delete n.elsePart

    @inversible n
  'while': (n) ->
    # *A while with a blank body (`while(x){}`) should be accounted for.*
    # *You can't have empty blocks, so put a `continue` in there. (#78)*
    if n.body.children.length is 0
      n.body.children.push n.clone(type: Typenames['continue'], value: 'continue', children: [])

    @inversible n
  'inversible': (n) ->
    @transform n.condition
    positive = if n.positive? then n.positive else true

    # *Invert a '!='. (`if (x != y)` => `unless x is y`)*
    if n.condition.isA('!=')
      n.condition.type = Typenames['==']
      n.positive = not positive

    # *Invert a '!'. (`if (!x)` => `unless x`)*
    else if n.condition.isA('!')
      n.condition = n.condition.left()
      n.positive = not positive

    else
      n.positive = positive
  '==': (n) ->
    if n.right().isA('null', 'void')
      n.type     = Typenames['!']
      n.children = [n.clone(type: Typenames['existence_check'], children: [n.left()])]
  '!=': (n) ->
    if n.right().isA('null', 'void')
      n.type     = Typenames['existence_check']
      n.children = [n.left()]
class UnsupportedError
  constructor: (str, src) ->
    @message = str
    @cursor  = src.start
    @line    = src.lineno
    @source  = src.tokenizer.source
  toString: -> @message

# ## Exports

@Js2coffee = exports =
  version: '0.1.3'
  build: buildCoffee
  UnsupportedError: UnsupportedError

module.exports = exports  if module?
'''
@color

table = (
    "buildCoffee = (str) ->",
    "class Builder",
    "constructor: ->",
    "build: (args...) ->",
    "transform: (args...) ->",
    "body: (node, opts={}) ->",
    "'script': (n, opts={}) ->",
    "'property_identifier': (n) ->",
    "'identifier': (n) ->",
    "'number': (n) ->",
    "'id': (n) ->",
    "'id_param': (n) ->",
    "'return': (n) ->",
    "';': (n) ->",
    "'new': (n) -> \"new #{@build n.left()}\"",
    "'new_with_args': (n) -> \"new #{@build n.left()}(#{@build n.right()})\"",
    "'unary_plus': (n) -> \"+#{@build n.left()}\"",
    "'unary_minus': (n) -> \"-#{@build n.left()}\"",
    "'this': (n) -> 'this'",
    "'null': (n) -> 'null'",
    "'true': (n) -> 'true'",
    "'false': (n) -> 'false'",
    "'void': (n) -> 'undefined'",
    "'debugger': (n) -> \"debugger\\n\"",
    "'break': (n) -> \"break\\n\"",
    "'continue': (n) -> \"continue\\n\"",
    "'~': (n) -> \"~#{@build n.left()}\"",
    "'typeof': (n) -> \"typeof #{@build n.left()}\"",
    "'index': (n) ->",
    "'throw': (n) -> \"throw #{@build n.exception}\"",
    "'!': (n) ->",
    "in: (n) ->    @binary_operator n, 'of'",
    "'+': (n) ->   @binary_operator n, '+'",
    "'-': (n) ->   @binary_operator n, '-'",
    "'*': (n) ->   @binary_operator n, '*'",
    "'/': (n) ->   @binary_operator n, '/'",
    "'%': (n) ->   @binary_operator n, '%'",
    "'>': (n) ->   @binary_operator n, '>'",
    "'<': (n) ->   @binary_operator n, '<'",
    "'&': (n) ->   @binary_operator n, '&'",
    "'|': (n) ->   @binary_operator n, '|'",
    "'^': (n) ->   @binary_operator n, '^'",
    "'&&': (n) ->  @binary_operator n, 'and'",
    "'||': (n) ->  @binary_operator n, 'or'",
    "'<<': (n) ->  @binary_operator n, '<<'",
    "'<=': (n) ->  @binary_operator n, '<='",
    "'>>': (n) ->  @binary_operator n, '>>'",
    "'>=': (n) ->  @binary_operator n, '>='",
    "'===': (n) -> @binary_operator n, 'is'",
    "'!==': (n) -> @binary_operator n, 'isnt'",
    "'>>>': (n) ->  @binary_operator n, '>>>'",
    "instanceof: (n) -> @binary_operator n, 'instanceof'",
    "'==': (n) ->",
    "'!=': (n) ->",
    "'binary_operator': do ->",
    "'--': (n) -> @increment_decrement n, '--'",
    "'++': (n) -> @increment_decrement n, '++'",
    "'increment_decrement': (n, sign) ->",
    "'=': (n) ->",
    "',': (n) ->",
    "'regexp': (n) ->",
    "'string': (n) ->",
    "'call': (n) ->",
    "'call_statement': (n) ->",
    "'list': (n) ->",
    "'delete': (n) ->",
    "'.': (n) ->",
    "'try': (n) ->",
    "'catch': (n) ->",
    "'?': (n) ->",
    "'for': (n) ->",
    "'for_in': (n) ->",
    "'while': (n) ->",
    "'do': (n) ->",
    "'if': (n) ->",
    "'switch': (n) ->",
    "'existence_check': (n) ->",
    "'array_init': (n) ->",
    "'property_init': (n) ->",
    "'object_init': (n, options={}) ->",
    "'function': (n) ->",
    "'var': (n) ->",
    "'other': (n) ->   @unsupported n, \"#{n.typeName()} is not supported yet\"",
    "'getter': (n) ->  @unsupported n, \"getter syntax is not supported; use __defineGetter__\"",
    "'setter': (n) ->  @unsupported n, \"setter syntax is not supported; use __defineSetter__\"",
    "'label': (n) ->   @unsupported n, \"labels are not supported by CoffeeScript\"",
    "'const': (n) ->   @unsupported n, \"consts are not supported by CoffeeScript\"",
    "'block': (args...) ->",
    "'unsupported': (node, message) ->",
    "class Transformer",
    "transform: (args...) ->",
    "'script': (n) ->",
    "'.': (n) ->",
    "';': (n) ->",
    "'function': (n) ->",
    "n.body.walk last: true, (parent, node, list) ->",
    "'switch': (n) ->",
    "'call_statement': (n) ->",
    "'return': (n) ->",
    "'block': (n) ->",
    "'if': (n) ->",
    "'while': (n) ->",
    "'inversible': (n) ->",
    "'==': (n) ->",
    "'!=': (n) ->",
    "class UnsupportedError",
    "constructor: (str, src) ->",
    "toString: -> @message",
)

try:
    c.importCommands.coffeeScriptUnitTest(p,s=s,showTree=True)
    if 1:
      p2 = c.p.firstChild().firstChild()
      for h in table:
          assert p2.h == h, (p2.h, h)
          p2.moveToThreadNext()
finally:
    if 1:
        p.deleteAllChildren()
        c.redraw()
#@+node:ekr.20161109084732.1: *6* @test coffeescript-2
s = r'''

# Js2coffee relies on Narcissus's parser.

{parser} = @Narcissus or require('./narcissus_packed')

# Main entry point

buildCoffee = (str) ->
  str  = str.replace /\r/g, ''
  str += "\n"

  builder    = new Builder
  scriptNode = parser.parse str
'''
table = (
    'buildCoffee = (str) ->',
)
try:
    c.importCommands.coffeeScriptUnitTest(p,s=s,showTree=True)
    if 1:
      p2 = c.p.firstChild().firstChild()
      for h in table:
          assert p2.h == h, (p2.h, h)
          p2.moveToThreadNext()
finally:
    if 1:
        p.deleteAllChildren()
        c.redraw()
#@+node:ekr.20161118144658.1: *6* @test coffeescript-3
@tabwidth -2 # Required

s = r'''
class Builder
  constructor: ->
    @transformer = new Transformer
  # `build()`

  build: (args...) ->
    node = args[0]
    @transform node

    name = 'other'
    name = node.typeName()  if node != undefined and node.typeName

    fn  = (@[name] or @other)
    out = fn.apply(this, args)

    if node.parenthesized then paren(out) else out
  # `transform()`

  transform: (args...) ->
    @transformer.transform.apply(@transformer, args)

  # `body()`

  body: (node, opts={}) ->
    str = @build(node, opts)
    str = blockTrim(str)
    str = unshift(str)
    if str.length > 0 then str else ""
'''
table = (
  'class Builder',
  'constructor: ->',
  'build: (args...) ->',
  'transform: (args...) ->',
  'body: (node, opts={}) ->',
)
try:
    c.importCommands.coffeeScriptUnitTest(p,s=s,showTree=True)
    if 1:
      p2 = c.p.firstChild().firstChild()
      for h in table:
          assert p2.h == h, (p2.h, h)
          p2.moveToThreadNext()
finally:
    if 1:
        p.deleteAllChildren()
        c.redraw()
#@+node:ekr.20161123115047.1: *5* dart tests
#@+node:ekr.20161123120652.1: *6* @test dart hello world
s = r'''
var name = 'Bob';

hello() {
  print('Hello, World!');
}

// Define a function.
printNumber(num aNumber) {
  print('The number is $aNumber.'); // Print to console.
}

// This is where the app starts executing.
void main() {
  var number = 42; // Declare and initialize a variable.
  printNumber(number); // Call a function.
}
'''
table = (
    'hello',
    'printNumber',
    'void main',
)
try:
    c.importCommands.dartUnitTest(p,s=s,showTree=True)
    root = c.p.firstChild()
    p2 = root.firstChild()
    for h in table:
        assert p2.h == h, (p2.h, h)
        p2.moveToThreadNext()
    assert not root.isAncestorOf(p2), p2.h # Extra nodes
finally:
    if 1:
        p.deleteAllChildren()
        c.redraw()
#@+node:ekr.20090529141856.4731: *5* elisp tests
#@+node:ekr.20090529141856.4733: *6* @test elisp
if 0:
    # The preamble...
    g.cls()
    if c.isChanged(): c.save()
    # import leo
    import leo.core.leoImport as leoImport
    import leo.plugins.importers.linescanner as linescanner
    import leo.plugins.importers.elisp
    # Reload all.
    import imp
    imp.reload(leo.plugins.importers.linescanner)
    imp.reload(leo.plugins.importers.elisp)
    imp.reload(leoImport)
    g.app.loadManager.createAllImporetersData()
    ic = leoImport.LeoImportCommands(c)
else:
    ic = c.importCommands

s = '''\
;;; comment
;;; continue
;;;

(defun abc (a b)
   (+ 1 2 3))

; comm
(defun cde (a b)
   (+ 1 2 3))
'''

table = (
    'defun abc',
    'defun cde',
)
try:
    ic.elispUnitTest(p,s=s,showTree=True)
    if 1:
        root = c.p.lastChild()
        assert root.h.startswith('@@'), root.h
        p2 = root.firstChild()
        for h in table:
            assert p2.h == h, (p2.h, h)
            p2.moveToThreadNext()
        assert not root.isAncestorOf(p2), p2.h # Extra nodes
finally:
    if 1:
        p.deleteAllChildren()
        c.redraw()

#@+node:ekr.20111029112647.4099: *5* html tests
#@+node:ekr.20111107102431.3849: *6* @@test html whitespace bug
# A good test, but we don't want this large a file included in the distro.

# fn = r'c:\recent\data4.html'
fn = r'c:\recent\data.html'

root = p.copy()

# Fails with more tags: a newline gets inserted between tags.

html_tags = ('body','head','html','table','xxx',)
setting = 'import_html_tags'

# Settings now work when run externally.
c.config.set(setting,'data',html_tags)
tags = c.config.getData(setting)
assert tags == html_tags,len(tags)

try:
    c.importCommands.importFilesCommand(files=[fn],treeType='@file')
finally:
    if 1:
        while root.hasChildren():
            root.firstChild().doDelete()
        c.redraw()
    assert not root.hasChildren()

fail = g.app.unitTestDict.get('fail')
assert not fail
#@+node:ekr.20111029112647.4101: *6* @test html: lowercase tags
s = '''\
<html>
<head>
    <title>Bodystring</title>
</head>
<body class="bodystring">
<div id='bodydisplay'></div>
</body>
</html>
'''
table = [
    '<html>',
    '<head>',
    '<body class="bodystring">',
]
try:
    c.importCommands.htmlUnitTest(p,s=s,showTree=True)
    root = c.p.firstChild()
    assert root.h.endswith('lowercase tags'), root.h
    p2 = root.firstChild()
    for i, h in enumerate(table):
        assert p2.h == h, (p2.h, h)
        p2.moveToThreadNext()
finally:
    if 1:
        p.deleteAllChildren()
        c.redraw()
#@+node:ekr.20111109143012.3839: *6* @test html: multiple tags on a line
@language html
    # Essential for the unit test.
    
# This part of the test file caused lots of problems.

s = '''

<html>

<body>

<table id="0">
<tr valign="top">
<td width="619">
	<table id="2">	<tr valign="top">	<td width="377">
		<table id="3">
		<tr>
		<td width="368">
			<table id="4">

<tbody id="5">

<tr valign="top">
<td width="550">
<table id="6">

<tbody id="6">
<tr>

<td class="blutopgrabot"><a href="href1">Listing Standards</a> | <a href="href2">Fees</a> | <strong>Non-compliant Issuers</strong> | <a href="href3">Form 25 Filings</a> </td>
</tr>
</tbody>

</table>

</td>
</tr><tr>
<td width="100%" colspan="2">


<br />
</td>
</tr>
</tbody>
</table>	
							</td>
						</tr>
						</table>

	<!-- View First part -->	</td>	<td width="242">	<!-- View Second part -->

	<!-- View Second part -->	</td>	</tr></table>										


<DIV class="webonly">

<script src="/scripts/footer.js"></script>
	
</DIV>
</td>
</tr>
</table>

<script language="JavaScript1.1">var SA_ID="nyse;nyse";</script>
<script language="JavaScript1.1" src="/scripts/stats/track.js"></script>
<noscript><img src="/scripts/stats/track.js" height="1" width="1" alt="" border="0"></noscript>
</body>
</html>

'''

c.importCommands.htmlUnitTest(p,s=s,showTree=False)
#@+node:ekr.20140218122321.4349: *6* @test html: multple node starts on a line
@language html

s = '''
<!-- tags that start nodes: html,body,head,div,table,nodeA,nodeB -->
<html><head>headline</head><body>body</body></html>
'''


c.importCommands.htmlUnitTest(p,s=s,showTree=False)
#@+node:ekr.20111102164107.3975: *6* @test html: underindented comment
s = r'''
<td width="550">
<table cellspacing="0" cellpadding="0" width="600" border="0">
    <td class="blutopgrabot" height="28"></td>
    
    <!-- The indentation of this element causes the problem. -->
    <table>
    
<!--
<div align="center">
<iframe src="http://www.amex.com/atamex/regulation/listingStatus/index.jsp"</iframe>
</div>
-->

</table>
</table>

<p>Paragraph</p>
</td>

'''
table = (
    '<td width="550">',
    '<table cellspacing="0" cellpadding="0" width="600" border="0">',
    '<table>',
)
try:
    c.importCommands.htmlUnitTest(p,s=s,showTree=True)
    p2 = c.p.firstChild().firstChild()
    for i, h in enumerate(table):
        assert p2.h == h, (p2.h, h)
        p2.moveToThreadNext()
finally:
    if 1:
        p.deleteAllChildren()
        c.redraw()
#@+node:ekr.20111029120441.3982: *6* @test html: uppercase tags
s = '''\
<HTML>
<HEAD>
    <title>Bodystring</title>
</HEAD>
<BODY class='bodystring'>
<DIV id='bodydisplay'></DIV>
</BODY>
</HTML>
'''


c.importCommands.htmlUnitTest(p,s=s,showTree=False)
#@+node:ekr.20111112103320.3849: *6* @test html: improperly nested tags
s = '''\
<body>

<!-- OOPS: the div and p elements not properly nested.-->
<!-- OOPS: this table got generated twice. -->

<p id="P1">
<div id="D666">Paragraph</p> <!-- P1 -->
<p id="P2">

<TABLE id="T666"></TABLE></p> <!-- P2 -->
</div>
</p> <!-- orphan -->

</body>
'''


c.importCommands.htmlUnitTest(p,s=s,showTree=False)
#@+node:ekr.20111112103320.3887: *6* @test html: improperly terminated tags
s = r'''
<html>

<head>
    <!-- oops: link elements terminated two different ways -->
    <link id="L1">
    <link id="L2">
    <link id="L3" />
    <link id='L4' />
    
    <title>TITLE</title>
    
<!-- oops: missing tags. -->
'''
table = ('<html>', '<head>', '<link id="L1">')
try:
    c.importCommands.htmlUnitTest(p,s=s,showTree=True)
    p2 = c.p.firstChild().firstChild()
    for i, h in enumerate(table):
        assert p2.h == h, (p2.h, h)
        p2.moveToThreadNext()
finally:
    if 1:
        p.deleteAllChildren()
        c.redraw()
#@+node:ekr.20111112103320.3893: *6* @test html: improperly terminated tags2
s = '''
<html>
<head>
    <!-- oops: link elements terminated two different ways -->
    <link id="L1">
    <link id="L2">
    <link id="L3" />
    <link id='L4' />
    
    <title>TITLE</title>
    
</head>
</html>
'''
table = ('<html>', '<head>', '<link id="L1">')
try:
    c.importCommands.htmlUnitTest(p,s=s,showTree=True)
    p2 = c.p.firstChild().firstChild()
    for h in table:
        assert p2.h == h, (p2.h, h)
        p2.moveToThreadNext()
finally:
    if 1:
        p.deleteAllChildren()
        c.redraw()
#@+node:ekr.20100803234640.5804: *5* ini tests
#@+node:ekr.20100803234640.5805: *6* @test ini-test-1
s = r'''; last modified 1 April 2001 by John Doe
[owner]
name=John Doe
organization=Acme Widgets Inc.

; [ not a section ]

[database]
server=192.0.2.62
    ; use IP address
port=143
file = "payroll.dat"
'''
table = ('[owner]', '[database]')
try:
    c.importCommands.iniUnitTest(p,s=s,showTree=True)
    root = c.p.firstChild()
    p2 = root.firstChild()
    for h in table:
        assert p2.h == h, (p2.h, h)
        p2.moveToThreadNext()
    assert not root.isAncestorOf(p2), p2.h # Extra nodes
finally:
    if 1:
        p.deleteAllChildren()
        c.redraw()

#@+node:ekr.20090529141856.4766: *5* Java tests
#@+node:ekr.20090529141856.4771: *6* @@test AdminPermission.java
import sys

if sys.platform.lower().startswith('win'):


    fileName = g.os_path_abspath(g.os_path_join(g.app.loadDir,'..','test','AdminPermission.java'))

    f = open(fileName)
    s = f.read()
    f.close()

    c.importCommands.javaUnitTest(p,s=s,fileName=fileName,showTree=False)
#@+node:ekr.20090529141856.4769: *6* @@test constants.java
import sys

if sys.platform.lower().startswith('win'):

    fileName = g.os_path_abspath(g.os_path_join(g.app.loadDir,'..','test','constants.java'))

    f = open(fileName)
    s = f.read()
    f.close()

    c.importCommands.javaUnitTest(p,s=None,fileName=fileName,showTree=False)
#@+node:ekr.20090529141856.4770: *6* @test from AdminPermission.java
if 0: # Preamble...
    # g.cls()
    if c.isChanged(): c.save()
    # import leo
    import leo.core.leoImport as leoImport
    import leo.plugins.importers.linescanner as linescanner
    import leo.plugins.importers.java
    # Reload all.
    import imp
    imp.reload(leo.plugins.importers.linescanner)
    imp.reload(leo.plugins.importers.java)
    imp.reload(leoImport)
    g.app.loadManager.createAllImporetersData()
    ic = leoImport.LeoImportCommands(c)
else:
    ic = c.importCommands  

s = '''\
/**
 * Indicates the caller's authority to perform lifecycle operations on
 */

public final class AdminPermission extends BasicPermission
{
    /**
     * Creates a new <tt>AdminPermission</tt> object.
     */
    public AdminPermission()
    {
        super("AdminPermission");
    }
}
'''
table = (
    'public final class AdminPermission extends BasicPermission',
    'public AdminPermission',
)
try:
    ic.javaUnitTest(p,s=s,showTree=True)
    if 1: # Check structure
        root = c.p.lastChild()
        assert root.h.startswith('@@'), root.h
        p2 = root.firstChild()
        for i, h in enumerate(table):
            assert p2.h == h, (p2.h, h)
            p2.moveToThreadNext()
        assert not root.isAncestorOf(p2), p2.h # Extra nodes
finally:
    if 1: # Delete children
        p.deleteAllChildren()
    c.redraw()
#@+node:ekr.20090529141856.4773: *6* @test from BundleException.java
@language python
@tabwidth 8
    # Must be in this node when run externally.
    
if 0: # Preamble...
    # g.cls()
    if c.isChanged(): c.save()
    # import leo
    import leo.core.leoImport as leoImport
    import leo.plugins.importers.linescanner as linescanner
    import leo.plugins.importers.java
    # Reload all.
    import imp
    imp.reload(leo.plugins.importers.linescanner)
    imp.reload(leo.plugins.importers.java)
    imp.reload(leoImport)
    g.app.loadManager.createAllImporetersData()
    ic = leoImport.LeoImportCommands(c)
else:
    ic = c.importCommands  

s = '''\
/*
 * $Header: /cvs/leo/test/unitTest.leo,v 1.247 2008/02/14 14:59:04 edream Exp $
 * 
 * Copyright (c) OSGi Alliance (2000, 2005). All Rights Reserved.
 * 
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License v1.0 which accompanies this 
 * distribution, and is available at http://www.eclipse.org/legal/epl-v10.html.
 */

package org.osgi.framework;

/**
 * A Framework exception used to indicate that a bundle lifecycle problem
 * occurred.
 * 
 * <p>
 * <code>BundleException</code> object is created by the Framework to denote
 * an exception condition in the lifecycle of a bundle.
 * <code>BundleException</code>s should not be created by bundle developers.
 * 
 * <p>
 * This exception is updated to conform to the general purpose exception
 * chaining mechanism.
 * 
 * @version $Revision: 1.247 $
 */

public class BundleException extends Exception {
	static final long	serialVersionUID	= 3571095144220455665L;
	/**
	 * Nested exception.
	 */
	private Throwable	cause;

	/**
	 * Creates a <code>BundleException</code> that wraps another exception.
	 * 
	 * @param msg The associated message.
	 * @param cause The cause of this exception.
	 */
	public BundleException(String msg, Throwable cause) {
		super(msg);
		this.cause = cause;
	}
}

'''
table = (
    'public class BundleException extends Exception',
    'public BundleException',
)
try:
    ic.javaUnitTest(p,s=s,showTree=True)
    if 1: # Check structure
        root = c.p.lastChild()
        assert root.h.startswith('@@'), root.h
        p2 = root.firstChild()
        for i, h in enumerate(table):
            assert p2.h == h, (p2.h, h)
            p2.moveToThreadNext()
        assert not root.isAncestorOf(p2), p2.h # Extra nodes
finally:
    if 1: # Delete children
        p.deleteAllChildren()
    c.redraw()
#@+node:ekr.20090529141856.4767: *6* @test java interface test1
if 0: # Preamble...
    # g.cls()
    if c.isChanged(): c.save()
    # import leo
    import leo.core.leoImport as leoImport
    import leo.plugins.importers.linescanner as linescanner
    import leo.plugins.importers.java
    # Reload all.
    import imp
    imp.reload(leo.plugins.importers.linescanner)
    imp.reload(leo.plugins.importers.java)
    imp.reload(leoImport)
    g.app.loadManager.createAllImporetersData()
    ic = leoImport.LeoImportCommands(c)
else:
    ic = c.importCommands  

s = '''\
interface Bicycle {
    void changeCadence(int newValue);
    void changeGear(int newValue);
}
'''
table = (
    'interface Bicycle',
)
try:
    ic.javaUnitTest(p,s=s,showTree=True)
    if 1:
        root = c.p.lastChild()
        assert root.h.startswith('@@'), root.h
        p2 = root.firstChild()
        for i, h in enumerate(table):
            assert p2.h == h, (p2.h, h)
            p2.moveToThreadNext()
        assert not root.isAncestorOf(p2), p2.h # Extra nodes
finally:
    if 1:
        p.deleteAllChildren()
    c.redraw()
#@+node:ekr.20090529141856.4768: *6* @test java interface test2
if 0: # Preamble...
    # g.cls()
    if c.isChanged(): c.save()
    # import leo
    import leo.core.leoImport as leoImport
    import leo.plugins.importers.linescanner as linescanner
    import leo.plugins.importers.java
    # Reload all.
    import imp
    imp.reload(leo.plugins.importers.linescanner)
    imp.reload(leo.plugins.importers.java)
    imp.reload(leoImport)
    g.app.loadManager.createAllImporetersData()
    ic = leoImport.LeoImportCommands(c)
else:
    ic = c.importCommands  

s = '''\
interface Bicycle {
void changeCadence(int newValue);
void changeGear(int newValue);
}
'''
table = (
    'interface Bicycle',
)
try:
    ic.javaUnitTest(p,s=s,showTree=True)
    if 1:
        root = c.p.lastChild()
        assert root.h.startswith('@@'), root.h
        p2 = root.firstChild()
        for i, h in enumerate(table):
            assert p2.h == h, (p2.h, h)
            p2.moveToThreadNext()
        assert not root.isAncestorOf(p2), p2.h # Extra nodes
finally:
    if 1:
        p.deleteAllChildren()
    c.redraw()
#@+node:ekr.20090529141856.4774: *5* Javascript tests
@language python
#@+node:ekr.20090529141856.4775: *6* Problems
@language javascript

// regexps that look like section references.

{
	name: "macro",
	match: "<<",
	lookaheadRegExp: /<<([^>\s]+)(?:\s*)((?:[^>]|(?:>(?!>)))*)>>/mg,
	handler: function(w)
	{
		this.lookaheadRegExp.lastIndex = w.matchStart;
		var lookaheadMatch = this.lookaheadRegExp.exec(w.source);
		if(lookaheadMatch && lookaheadMatch.index == w.matchStart && lookaheadMatch[1]) {
			w.nextMatch = this.lookaheadRegExp.lastIndex;
			invokeMacro(w.output,lookaheadMatch[1],lookaheadMatch[2],w,w.tiddler);
		}
	}
},

// Comments that look like section references.

// <<gradient [[tiddler name]] vert|horiz rgb rgb rgb rgb... >>

config.macros.gradient.handler = function(place,macroName,params,wikifier)
{
	var panel = wikifier ? createTiddlyElement(place,"div",null,"gradient") : place;
	panel.style.position = "relative";
	panel.style.overflow = "hidden";
	panel.style.zIndex = "0";
	if(wikifier) {
		var styles = config.formatterHelpers.inlineCssHelper(wikifier);
		config.formatterHelpers.applyCssHelper(panel,styles);
	}
	var colours = [];
	for(var t=1; t<params.length; t++) {
		var c = new RGB(params[t]);
		if(c)
			colours.push(c);
	}
	drawGradient(panel,params[0] != "vert",colours);
	if(wikifier)
		wikifier.subWikify(panel,">>");
	if(document.all) {
		panel.style.height = "100%";
		panel.style.width = "100%";
	}
};

// @Deprecated: Use <br> or <br /> instead of <<br>>
config.macros.br = {};
config.macros.br.handler = function(place)
{
	createTiddlyElement(place,"br");
};
#@+node:ekr.20090529141856.4776: *6* @test Javascript-regex-1
s = '''\

String.prototype.toJSONString = function()
{
    if(/["\\\\\\x00-\\x1f]/.test(this))
		return '"' + this.replace(/([\\x00-\\x1f\\"])/g,replaceFn) + '"';

	return '"' + this + '"';
};

'''


c.importCommands.javaScriptUnitTest(p,s=s,showTree=False)
#@+node:ekr.20090529141856.4777: *6* @@test JSON
s = '''\

// Convert a string to it's JSON representation by encoding control characters, double quotes and backslash. See json.org
String.prototype.toJSONString = function()
{
	var m = {
		'\\b': '\\\\b',
		'\\f': '\\\\f',
		'\\n': '\\\\n',
		'\\r': '\\\\r',
		'\\t': '\\\\t',
		'"' : '\\\\"',
		'\\\\': '\\\\\\\\'
		};
	var replaceFn = function(a,b) {
		var c = m[b];
		if(c)
			return c;
		c = b.charCodeAt();
		return '\\u00' + Math.floor(c / 16).toString(16) + (c % 16).toString(16);
		};
    if(/["\\\\\\x00-\\x1f]/.test(this))
		return '"' + this.replace(/([\\x00-\\x1f\\"])/g,replaceFn) + '"';

	return '"' + this + '"';
};

'''


c.importCommands.javaScriptUnitTest(p,s=s,showTree=False)
#@+node:ekr.20090529141856.4778: *6* @test Javascript-3
s = '''\

// Restarting
function restart()
{
	invokeParamifier(params,"onstart");
	if(story.isEmpty()) {
		var tiddlers = store.filterTiddlers(store.getTiddlerText("DefaultTiddlers"));
		for(var t=0; t<tiddlers.length; t++) {
			story.displayTiddler("bottom",tiddlers[t].title);
		}
	}
	window.scrollTo(0,0);
}

'''


c.importCommands.javaScriptUnitTest(p,s=s,showTree=False)
#@+node:ekr.20140218042220.4347: *6* @test Javascript-4
s = '''\

var c3 = (function () {
    "use strict";

    // Globals
    var c3 = { version: "0.0.1"   };

    c3.someFunction = function () {
        console.log("Just a demo...");
    };

    return c3;
}());

'''

c.importCommands.javaScriptUnitTest(p,s=s,showTree=False)
#@+node:ekr.20140218151418.4353: *6* @test Javascript-5
s = '''\
var express = require('express');

var app = express.createServer(express.logger());

app.get('/', function(request, response) {
response.send('Hello World!');
});

var port = process.env.PORT || 5000;
app.listen(port, function() {
console.log("Listening on " + port);
});
'''

c.importCommands.javaScriptUnitTest(p,s=s,showTree=False)
#@+node:ekr.20161123202857.1: *5* org tests
#@+node:ekr.20161123202924.1: *6* @test org-1
s = '''\
* Section 1
Sec 1.
* Section 2
Sec 2.
** Section 2-1
Sec 2.1
*** Section 2-1-1
Sec 2.1.1
* Section 3
** Section 3.1
Sec 3.1
'''
table = (
    'Section 1',
    'Section 2', 'Section 2-1', 'Section 2-1-1',
    'Section 3', 'Section 3.1',
)
try:
    c.importCommands.orgUnitTest(p,s=s,showTree=True)
    if 1:
        root = c.p.firstChild()
        p2 = root.firstChild()
        for h in table:
            assert p2.h == h, (p2.h, h)
            p2.moveToThreadNext()
        assert not root.isAncestorOf(p2), p2.h # Extra nodes
finally:
    if 1:
        p.deleteAllChildren()
        c.redraw()

#@+node:ekr.20161124040933.1: *5* otl (vim-outline) tests
#@+node:ekr.20161124040933.2: *6* @test otl-1
@tabwidth 4 # Required
s = '''\
Section 1
: Sec 1.
Section 2
: Sec 2.
\tSection 2-1
: Sec 2-1
\t\tSection 2-1-1
: Sect 2-1-1
Section 3
: Sec 3
\tSection 3.1
: Sec 3.1
'''
table = (
    'Section 1',
    'Section 2', 'Section 2-1', 'Section 2-1-1',
    'Section 3', 'Section 3.1',
)
try:
    c.importCommands.otlUnitTest(p,s=s,showTree=True)
    if 0:
        root = c.p.firstChild()
        p2 = root.firstChild()
        for h in table:
            assert p2.h == h, (p2.h, h)
            p2.moveToThreadNext()
        assert not root.isAncestorOf(p2), p2.h # Extra nodes
finally:
    if 1:
        p.deleteAllChildren()
        c.redraw()
#@+node:ekr.20090529141856.4734: *5* Pascal tests
#@+node:ekr.20090529141856.4735: *6* @test pascal-to-delphi interface
if 0:
    # The preamble...
    g.cls()
    if c.isChanged(): c.save()
    # import leo
    import leo.core.leoImport as leoImport
    import leo.plugins.importers.linescanner as linescanner
    import leo.plugins.importers.pascal
    # Reload all.
    import imp
    imp.reload(leo.plugins.importers.linescanner)
    imp.reload(leo.plugins.importers.pascal)
    imp.reload(leoImport)
    g.app.loadManager.createAllImporetersData()
    ic = leoImport.LeoImportCommands(c)
else:
    ic = c.importCommands  
s = '''
unit Unit1;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls,
Forms,
Dialogs;

type
TForm1 = class(TForm)
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;

var
Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
var
x,y: double;
begin
x:= 4;
Y := x/2;
end;

end. // interface
'''
table = (
    'interface',
    'procedure FormCreate',
    'procedure TForm1.FormCreate',
)
try:
    ic.pascalUnitTest(p,s=s,showTree=True)
    if 1:
        root = c.p.lastChild()
        assert root.h.startswith('@@'), root.h
        p2 = root.firstChild()
        for i, h in enumerate(table):
            assert p2.h == h, (p2.h, h)
            p2.moveToThreadNext()
        assert not root.isAncestorOf(p2), p2.h # Extra nodes
finally:
    if 1:
        p.deleteAllChildren()
        c.redraw()
#@+node:ekr.20161103015908.1: *5* Perl tests
#@+node:ekr.20161103015940.1: *6* @test perl-1
s = '''\
#!/usr/bin/perl

# Function definition
sub Hello{
   print "Hello, World!\n";
}

sub Test{
   print "Test!\n";
}
"\N{LATIN SMALL LIGATURE FI}" =~ /fi/i;

$bar = "foo";
if ($bar =~ /foo/){
   print "Second time is matching\n";
}else{
   print "Second time is not matching\n";
}

# Function call
Hello();
'''
try:
    c.importCommands.perlUnitTest(p,s=s,showTree=True)
finally:
    if 1:
        p.deleteAllChildren()
        c.redraw()
#@+node:ekr.20161103021621.1: *6* @test perlpod comment
s = '''\
#!/usr/bin/perl
          
sub Test{
   print "Test!\n";
}

=begin comment
sub World {
    print "This is not a funtion!"
}
=cut

# Function definition
sub Hello{
   print "Hello, World!\n";
}
'''
try:
    c.importCommands.perlUnitTest(p,s=s,showTree=True)
finally:
    if 1:
        p.deleteAllChildren()
        c.redraw()
#@+node:ekr.20161103021420.1: *6* @test perl multi-line string
s = '''\
#!/usr/bin/perl

# This would print with a line break in the middle
print "Hello

sub World {
    print "This is not a funtion!"
}

world\n";
'''
try:
    c.importCommands.perlUnitTest(p,s=s,showTree=True)
finally:
    if 1:
        p.deleteAllChildren()
        c.redraw()
#@+node:ekr.20161119031833.1: *6* @test perl regex-1
# ('len',   'tr///', '/',       context,  0,       0,       0),
# ('len',   's///',  '/',       context,  0,       0,       0),
# ('len',   'm//',   '/',       context,  0,       0,       0),
# ('len',   '/',     '/',       '',       0,       0,       0),

s = '''\
#!/usr/bin/perl

sub test1 {
    s = /{/g;
}

sub test2 {
    s = m//{/;
}

sub test3 {
    s = s///{/;
}

sub test4 {
    s = tr///{/;
}
'''
try:
    c.importCommands.perlUnitTest(p,s=s,showTree=True)
finally:
    if 1:
        p.deleteAllChildren()
        c.redraw()
#@+node:ekr.20161119032623.1: *6* @test perl regex-2
if 0:
    # The preamble...
    g.cls()
    if c.isChanged(): c.save()
    # import leo
    import leo.core.leoImport as leoImport
    import leo.plugins.importers.linescanner as linescanner
    import leo.plugins.importers.perl
    # Reload all.
    import imp
    imp.reload(leo.plugins.importers.linescanner)
    imp.reload(leo.plugins.importers.perl)
    imp.reload(leoImport)
    g.app.loadManager.createAllImporetersData()
    ic = leoImport.LeoImportCommands(c)
else:
    ic = c.importCommands

s = '''\
#!/usr/bin/perl

sub test1 {
    s = /}/g;
}

sub test2 {
    s = m//}/;
}

sub test3 {
    s = s///}/;
}

sub test4 {
    s = tr///}/;
}
'''
table = (
    'sub test1',
    'sub test2',
    'sub test3',
    'sub test4'
)
try:
    ic.perlUnitTest(p,s=s,showTree=True)
    if 1:
        root = c.p.lastChild()
        assert root.h.startswith('@@'), root.h
        p2 = root.firstChild()
        for h in table:
            assert p2.h == h, (p2.h, h)
            p2.moveToThreadNext()
        assert not root.isAncestorOf(p2), p2.h # Extra nodes
finally:
    if 1:
        p.deleteAllChildren()
        c.redraw()
#@+node:ekr.20100219080213.5365: *5* PHP tests
#@+node:ekr.20100219080213.5366: *6* @test php import class
s = '''\
<?php

$type = 'cc';
$obj = new $type; // outputs "hi!"

class cc {
    function __construct() {
        echo 'hi!';
    }
}

?>

'''

c.importCommands.phpUnitTest(p,s=s,showTree=False)
#@+node:ekr.20100219080213.5367: *6* @test php import conditional class
s = '''\
<?php

if (expr) {
    class cc {
        // version 1
    }
} else {
    class cc {
        // version 2
    }
}

?>
'''

c.importCommands.phpUnitTest(p,s=s,showTree=False)
#@+node:ekr.20100219080213.5368: *6* @test php import classes & functions
s = '''\
<?php
class Enum {
    protected $self = array();
    public function __construct( /*...*/ ) {
        $args = func_get_args();
        for( $i=0, $n=count($args); $i<$n; $i++ )
            $this->add($args[$i]);
    }

    public function __get( /*string*/ $name = null ) {
        return $this->self[$name];
    }

    public function add( /*string*/ $name = null, /*int*/ $enum = null ) {
        if( isset($enum) )
            $this->self[$name] = $enum;
        else
            $this->self[$name] = end($this->self) + 1;
    }
}

class DefinedEnum extends Enum {
    public function __construct( /*array*/ $itms ) {
        foreach( $itms as $name => $enum )
            $this->add($name, $enum);
    }
}

class FlagsEnum extends Enum {
    public function __construct( /*...*/ ) {
        $args = func_get_args();
        for( $i=0, $n=count($args), $f=0x1; $i<$n; $i++, $f *= 0x2 )
            $this->add($args[$i], $f);
    }
}
?>

'''

c.importCommands.phpUnitTest(p,s=s,showTree=False)
#@+node:ekr.20161129222003.1: *6* @test php here doc
s = '''\
<?php
class foo {
    public $bar = <<<EOT
a test.
bar
EOT;
}
?>
'''

c.importCommands.phpUnitTest(p,s=s,showTree=True)
#@+node:ekr.20161130042452.50: *7* @@clean c:/leo.repo/leo-editor/leo/test/php here doc
<?php
@others
@language php
@tabwidth -4
#@+node:ekr.20161130042452.51: *8* class foo
class foo {
    public $bar = <<<EOT
a test.
bar
EOT;
}
?>
#@+node:ekr.20161130050706.29: *7* @@clean c:/leo.repo/leo-editor/leo/test/php here doc
<?php
@others
@language php
@tabwidth -4
#@+node:ekr.20161130050706.30: *8* class foo
class foo {
    public $bar = <<<EOT
a test.
bar
EOT;
}
?>
#@+node:ekr.20161202053644.21: *7* @@clean c:/leo.repo/leo-editor/leo/test/php here doc
<?php
@others
@language php
@tabwidth -4
#@+node:ekr.20161202053644.22: *8* class foo
class foo {
    public $bar = <<<EOT
a test.
bar
EOT;
}
?>
#@+node:ekr.20161202083956.10: *7* @@clean c:/leo.repo/leo-editor/leo/test/php here doc
<?php
@others
@language php
@tabwidth -4
#@+node:ekr.20161202083956.11: *8* class foo
class foo {
    public $bar = <<<EOT
a test.
bar
EOT;
}
?>
#@+node:ekr.20161202093505.10: *7* @@clean c:/leo.repo/leo-editor/leo/test/php here doc
<?php
@others
@language php
@tabwidth -4
#@+node:ekr.20161202093505.11: *8* class foo
class foo {
    public $bar = <<<EOT
a test.
bar
EOT;
}
?>
#@+node:ekr.20161204034138.15: *7* @@clean c:/leo.repo/leo-editor/leo/test/php here doc
<?php
@others
@language php
@tabwidth -4
#@+node:ekr.20161204034138.16: *8* class foo
class foo {
    public $bar = <<<EOT
a test.
bar
EOT;
}
?>
#@+node:ekr.20161204035447.20: *7* @@clean c:/leo.repo/leo-editor/leo/test/php here doc
<?php
@others
@language php
@tabwidth -4
#@+node:ekr.20161204035447.21: *8* class foo
class foo {
    public $bar = <<<EOT
a test.
bar
EOT;
}
?>
#@+node:ekr.20161204041306.21: *7* @@clean c:/leo.repo/leo-editor/leo/test/php here doc
<?php
@others
@language php
@tabwidth -4
#@+node:ekr.20161204041306.22: *8* class foo
class foo {
    public $bar = <<<EOT
a test.
bar
EOT;
}
?>
#@+node:ekr.20161204041354.25: *7* @@clean c:/leo.repo/leo-editor/leo/test/php here doc
<?php
@others
@language php
@tabwidth -4
#@+node:ekr.20161204041354.26: *8* class foo
class foo {
    public $bar = <<<EOT
a test.
bar
EOT;
}
?>
#@+node:ekr.20161204041426.33: *7* @@clean c:/leo.repo/leo-editor/leo/test/php here doc
<?php
@others
@language php
@tabwidth -4
#@+node:ekr.20161204041426.34: *8* class foo
class foo {
    public $bar = <<<EOT
a test.
bar
EOT;
}
?>
#@+node:ekr.20161204041641.25: *7* @@clean c:/leo.repo/leo-editor/leo/test/php here doc
<?php
@others
@language php
@tabwidth -4
#@+node:ekr.20161204041641.26: *8* class foo
class foo {
    public $bar = <<<EOT
a test.
bar
EOT;
}
?>
#@+node:ekr.20161204041720.21: *7* @@clean c:/leo.repo/leo-editor/leo/test/php here doc
<?php
@others
@language php
@tabwidth -4
#@+node:ekr.20161204041720.22: *8* class foo
class foo {
    public $bar = <<<EOT
a test.
bar
EOT;
}
?>
#@+node:ekr.20161204041755.29: *7* @@clean c:/leo.repo/leo-editor/leo/test/php here doc
<?php
@others
@language php
@tabwidth -4
#@+node:ekr.20161204041755.30: *8* class foo
class foo {
    public $bar = <<<EOT
a test.
bar
EOT;
}
?>
#@+node:ekr.20161204041842.20: *7* @@clean c:/leo.repo/leo-editor/leo/test/php here doc
<?php
@others
@language php
@tabwidth -4
#@+node:ekr.20161204041842.21: *8* class foo
class foo {
    public $bar = <<<EOT
a test.
bar
EOT;
}
?>
#@+node:ekr.20161204041902.25: *7* @@clean c:/leo.repo/leo-editor/leo/test/php here doc
<?php
@others
@language php
@tabwidth -4
#@+node:ekr.20161204041902.26: *8* class foo
class foo {
    public $bar = <<<EOT
a test.
bar
EOT;
}
?>
#@+node:ekr.20161204041920.33: *7* @@clean c:/leo.repo/leo-editor/leo/test/php here doc
<?php
@others
@language php
@tabwidth -4
#@+node:ekr.20161204041920.34: *8* class foo
class foo {
    public $bar = <<<EOT
a test.
bar
EOT;
}
?>
#@+node:ekr.20161204042116.25: *7* @@clean c:/leo.repo/leo-editor/leo/test/php here doc
<?php
@others
@language php
@tabwidth -4
#@+node:ekr.20161204042116.26: *8* class foo
class foo {
    public $bar = <<<EOT
a test.
bar
EOT;
}
?>
#@+node:ekr.20161204042155.7: *7* @@clean c:/leo.repo/leo-editor/leo/test/php here doc
<?php
@others
@language php
@tabwidth -4
#@+node:ekr.20161204042155.8: *8* class foo
class foo {
    public $bar = <<<EOT
a test.
bar
EOT;
}
?>
#@+node:ekr.20161204042301.25: *7* @@clean c:/leo.repo/leo-editor/leo/test/php here doc
<?php
@others
@language php
@tabwidth -4
#@+node:ekr.20161204042301.26: *8* class foo
class foo {
    public $bar = <<<EOT
a test.
bar
EOT;
}
?>
#@+node:ekr.20161204042714.33: *7* @@clean c:/leo.repo/leo-editor/leo/test/php here doc
<?php
@others
@language php
@tabwidth -4
#@+node:ekr.20161204042714.34: *8* class foo
class foo {
    public $bar = <<<EOT
a test.
bar
EOT;
}
?>
#@+node:ekr.20161204042739.15: *7* @@clean c:/leo.repo/leo-editor/leo/test/php here doc
<?php
@others
@language php
@tabwidth -4
#@+node:ekr.20161204042739.16: *8* class foo
class foo {
    public $bar = <<<EOT
a test.
bar
EOT;
}
?>
#@+node:ekr.20161204043013.1: *7* @@clean c:/leo.repo/leo-editor/leo/test/php here doc
<?php
@others
@language php
@tabwidth -4
#@+node:ekr.20161204043013.2: *8* class foo
class foo {
    public $bar = <<<EOT
a test.
bar
EOT;
}
?>
#@+node:ekr.20161204043028.10: *7* @@clean c:/leo.repo/leo-editor/leo/test/php here doc
<?php
@others
@language php
@tabwidth -4
#@+node:ekr.20161204043028.11: *8* class foo
class foo {
    public $bar = <<<EOT
a test.
bar
EOT;
}
?>
#@+node:ekr.20161204043342.40: *7* @@clean c:/leo.repo/leo-editor/leo/test/php here doc
<?php
@others
@language php
@tabwidth -4
#@+node:ekr.20161204043342.41: *8* class foo
class foo {
    public $bar = <<<EOT
a test.
bar
EOT;
}
?>
#@+node:ekr.20161204045827.15: *7* @@clean c:/leo.repo/leo-editor/leo/test/php here doc
<?php
@others
@language php
@tabwidth -4
#@+node:ekr.20161204045827.16: *8* class foo
class foo {
    public $bar = <<<EOT
a test.
bar
EOT;
}
?>
#@+node:ekr.20161204045955.21: *7* @@clean c:/leo.repo/leo-editor/leo/test/php here doc
<?php
@others
@language php
@tabwidth -4
#@+node:ekr.20161204045955.22: *8* class foo
class foo {
    public $bar = <<<EOT
a test.
bar
EOT;
}
?>
#@+node:ekr.20161204154852.10: *7* @@clean c:/leo.repo/leo-editor/leo/test/php here doc
<?php
@others
@language php
@tabwidth -4
#@+node:ekr.20161204154852.11: *8* class foo
class foo {
    public $bar = <<<EOT
a test.
bar
EOT;
}
?>
#@+node:ekr.20161204155218.25: *7* @@clean c:/leo.repo/leo-editor/leo/test/php here doc
<?php
@others
@language php
@tabwidth -4
#@+node:ekr.20161204155218.26: *8* class foo
class foo {
    public $bar = <<<EOT
a test.
bar
EOT;
}
?>
#@+node:ekr.20161206135449.10: *7* @@clean c:/leo.repo/leo-editor/leo/test/php here doc
<?php
@others
@language php
@tabwidth -4
#@+node:ekr.20161206135449.11: *8* class foo
class foo {
    public $bar = <<<EOT
a test.
bar
EOT;
}
?>
#@+node:ekr.20161206165824.10: *7* @@clean c:/leo.repo/leo-editor/leo/test/php here doc
<?php
@others
@language php
@tabwidth -4
#@+node:ekr.20161206165824.11: *8* class foo
class foo {
    public $bar = <<<EOT
a test.
bar
EOT;
}
?>
#@+node:ekr.20161216141227.1: *7* @@clean c:/leo.repo/leo-editor/leo/test/php here doc
<?php
@others
@language php
@tabwidth -4
#@+node:ekr.20161216141227.2: *8* class foo
class foo {
    public $bar = <<<EOT
a test.
bar
EOT;
}
?>
#@+node:ekr.20161218104646.1: *7* @@clean c:/leo.repo/leo-editor/leo/test/php here doc
<?php
@others
@language php
@tabwidth -4
#@+node:ekr.20161218104646.2: *8* class foo
class foo {
    public $bar = <<<EOT
a test.
bar
EOT;
}
?>
#@+node:ekr.20161220185154.21: *7* @@clean c:/leo.repo/leo-editor/leo/test/php here doc
<?php
@others
@language php
@tabwidth -4
#@+node:ekr.20161220185154.22: *8* class foo
class foo {
    public $bar = <<<EOT
a test.
bar
EOT;
}
?>
#@+node:ekr.20161221062411.1: *7* @@clean c:/leo.repo/leo-editor/leo/test/php here doc
<?php
@others
@language php
@tabwidth -4
#@+node:ekr.20161221062411.2: *8* class foo
class foo {
    public $bar = <<<EOT
a test.
bar
EOT;
}
?>
#@+node:ekr.20161221063734.10: *7* @@clean c:/leo.repo/leo-editor/leo/test/php here doc
<?php
@others
@language php
@tabwidth -4
#@+node:ekr.20161221063734.11: *8* class foo
class foo {
    public $bar = <<<EOT
a test.
bar
EOT;
}
?>
#@+node:ekr.20161221065216.7: *7* @@clean c:/leo.repo/leo-editor/leo/test/php here doc
<?php
@others
@language php
@tabwidth -4
#@+node:ekr.20161221065216.8: *8* class foo
class foo {
    public $bar = <<<EOT
a test.
bar
EOT;
}
?>
#@+node:ekr.20161221080848.25: *7* @@clean c:/leo.repo/leo-editor/leo/test/php here doc
<?php
@others
@language php
@tabwidth -4
#@+node:ekr.20161221080848.26: *8* class foo
class foo {
    public $bar = <<<EOT
a test.
bar
EOT;
}
?>
#@+node:ekr.20161221091453.20: *7* @@clean c:/leo.repo/leo-editor/leo/test/php here doc
<?php
@others
@language php
@tabwidth -4
#@+node:ekr.20161221091453.21: *8* class foo
class foo {
    public $bar = <<<EOT
a test.
bar
EOT;
}
?>
#@+node:ekr.20161221091950.20: *7* @@clean c:/leo.repo/leo-editor/leo/test/php here doc
<?php
@others
@language php
@tabwidth -4
#@+node:ekr.20161221091950.21: *8* class foo
class foo {
    public $bar = <<<EOT
a test.
bar
EOT;
}
?>
#@+node:ekr.20161221092230.10: *7* @@clean c:/leo.repo/leo-editor/leo/test/php here doc
<?php
@others
@language php
@tabwidth -4
#@+node:ekr.20161221092230.11: *8* class foo
class foo {
    public $bar = <<<EOT
a test.
bar
EOT;
}
?>
#@+node:ekr.20161222122038.3: *7* @@clean c:/leo.repo/leo-editor/leo/test/php here doc
<?php
@others
@language php
@tabwidth -4
#@+node:ekr.20161222122038.4: *8* class foo
class foo {
    public $bar = <<<EOT
a test.
bar
EOT;
}
?>
#@+node:ekr.20161222123534.3: *7* @@clean c:/leo.repo/leo-editor/leo/test/php here doc
<?php
@others
@language php
@tabwidth -4
#@+node:ekr.20161222123534.4: *8* class foo
class foo {
    public $bar = <<<EOT
a test.
bar
EOT;
}
?>
#@+node:ekr.20161222123751.3: *7* @@clean c:/leo.repo/leo-editor/leo/test/php here doc
<?php
@others
@language php
@tabwidth -4
#@+node:ekr.20161222123751.4: *8* class foo
class foo {
    public $bar = <<<EOT
a test.
bar
EOT;
}
?>
#@+node:ekr.20161223153848.1: *7* @@clean c:/leo.repo/leo-editor/leo/test/php here doc
<?php
@others
@language php
@tabwidth -4
#@+node:ekr.20161223153848.2: *8* class foo
class foo {
    public $bar = <<<EOT
a test.
bar
EOT;
}
?>
#@+node:ekr.20161231115630.10: *7* @@clean c:/leo.repo/leo-editor/leo/test/php here doc
<?php
@others
@language php
@tabwidth -4
#@+node:ekr.20161231115630.11: *8* class foo
class foo {
    public $bar = <<<EOT
a test.
bar
EOT;
}
?>
#@+node:ekr.20170101085120.25: *7* @@clean c:/leo.repo/leo-editor/leo/test/php here doc
<?php
@others
@language php
@tabwidth -4
#@+node:ekr.20170101085120.26: *8* class foo
class foo {
    public $bar = <<<EOT
a test.
bar
EOT;
}
?>
#@+node:ekr.20170101131839.10: *7* @@clean c:/leo.repo/leo-editor/leo/test/php here doc
<?php
@others
@language php
@tabwidth -4
#@+node:ekr.20170101131839.11: *8* class foo
class foo {
    public $bar = <<<EOT
a test.
bar
EOT;
}
?>
#@+node:ekr.20170101134221.7: *7* @@clean c:/leo.repo/leo-editor/leo/test/php here doc
<?php
@others
@language php
@tabwidth -4
#@+node:ekr.20170101134221.8: *8* class foo
class foo {
    public $bar = <<<EOT
a test.
bar
EOT;
}
?>
#@+node:ekr.20170105122516.10: *7* @@clean c:/leo.repo/leo-editor/leo/test/php here doc
<?php
@others
@language php
@tabwidth -4
#@+node:ekr.20170105122516.11: *8* class foo
class foo {
    public $bar = <<<EOT
a test.
bar
EOT;
}
?>
#@+node:ekr.20170112111339.7: *7* @@clean c:/leo.repo/leo-editor/leo/test/php here doc
<?php
@others
@language php
@tabwidth -4
#@+node:ekr.20170112111339.8: *8* class foo
class foo {
    public $bar = <<<EOT
a test.
bar
EOT;
}
?>
#@+node:ekr.20170112111900.10: *7* @@clean c:/leo.repo/leo-editor/leo/test/php here doc
<?php
@others
@language php
@tabwidth -4
#@+node:ekr.20170112111900.11: *8* class foo
class foo {
    public $bar = <<<EOT
a test.
bar
EOT;
}
?>
#@+node:ekr.20170113162613.7: *7* @@clean c:/leo.repo/leo-editor/leo/test/php here doc
<?php
@others
@language php
@tabwidth -4
#@+node:ekr.20170113162613.8: *8* class foo
class foo {
    public $bar = <<<EOT
a test.
bar
EOT;
}
?>
#@+node:ekr.20170114055256.3: *7* @@clean c:/leo.repo/leo-editor/leo/test/php here doc
<?php
@others
@language php
@tabwidth -4
#@+node:ekr.20170114055256.4: *8* class foo
class foo {
    public $bar = <<<EOT
a test.
bar
EOT;
}
?>
#@+node:ekr.20170114080041.1: *7* @@clean c:/leo.repo/leo-editor/leo/test/php here doc
<?php
@others
@language php
@tabwidth -4
#@+node:ekr.20170114080041.2: *8* class foo
class foo {
    public $bar = <<<EOT
a test.
bar
EOT;
}
?>
#@+node:ekr.20170114200550.3: *7* @@clean c:/leo.repo/leo-editor/leo/test/php here doc
<?php
@others
@language php
@tabwidth -4
#@+node:ekr.20170114200550.4: *8* class foo
class foo {
    public $bar = <<<EOT
a test.
bar
EOT;
}
?>
#@+node:ekr.20170115052901.10: *7* @@clean c:/leo.repo/leo-editor/leo/test/php here doc
<?php
@others
@language php
@tabwidth -4
#@+node:ekr.20170115052901.11: *8* class foo
class foo {
    public $bar = <<<EOT
a test.
bar
EOT;
}
?>
#@+node:ekr.20170302201859.3: *7* @@file c:/leo.repo/leo-editor/leo/test/php here doc
<?php
@others
@language php
@tabwidth -4
#@+node:ekr.20170302201859.4: *8* class foo
class foo {
    public $bar = <<<EOT
a test.
bar
EOT;
}
?>
#@+node:ekr.20090529141856.4736: *5* Python tests
# Warning: setting atAuto=True can wipe out unit tests.
#@+node:ekr.20161204042938.1: *6* @@test print('end python tests')
print('end python tests')
#@+node:ekr.20161204042916.1: *6* @@test print('start python tests')
print('start python tests')
#@+node:ekr.20161115092708.1: *6* @test i.scan_state (for python)
# g.cls()
import leo.plugins.importers.python as python
# import imp
# imp.reload(python)
# A list of dictionaries.
if 0:
    tests = [
        # g.Bunch(line='s = "\\""', ctx=('', '')),
        g.Bunch(line='\\\n'),
    ]
else:
    tests = [
        g.Bunch(line='\n'),
        g.Bunch(line='\\\n'),
        g.Bunch(line='s = "\\""', ctx=('', '')), # empty string.
        g.Bunch(line="s = '\\''", ctx=('', '')), # empty string.
        g.Bunch(line='# comment'),
        g.Bunch(line='  # comment'),
        g.Bunch(line='    # comment'),
        g.Bunch(line='a = "string"'),
        g.Bunch(line='a = "Continued string', ctx=('', '"')),
        g.Bunch(line='end of continued string"', ctx=('"', '')),
        g.Bunch(line='a = """Continued docstring', ctx=('', '"""')),
        g.Bunch(line='a = """#', ctx=('', '"""')),
        g.Bunch(line='end of continued string"""', ctx=('"""', '')),
        g.Bunch(line="a = '''Continued docstring", ctx=('', "'''")),
        g.Bunch(line="end of continued string'''", ctx=("'''", '')),
        g.Bunch(line='a = {[(')
    ]
if hasattr(python, 'Py_Importer'):
    importer = python.Py_Importer(c.importCommands, atAuto=True)
    importer.test_scan_state(tests, State=python.Python_ScanState)
else:
    self.skipTest('Skipping test for new python importer')
#@+node:ekr.20161224145026.1: *6* @test leoApp fail
if 0: # Preamble...
    # g.cls()
    if c.isChanged(): c.save()
    # import leo
    import leo.core.leoImport as leoImport
    import leo.plugins.importers.linescanner as linescanner
    import leo.plugins.importers.python
    # Reload all.
    import imp
    imp.reload(leo.plugins.importers.linescanner)
    imp.reload(leo.plugins.importers.python)
    imp.reload(leoImport)
    g.app.loadManager.createAllImporetersData()
    ic = leoImport.LeoImportCommands(c)
else:
    ic = c.importCommands
    
s = '''
def isValidPython(self):
    if sys.platform == 'cli':
        return True
    minimum_python_version = '2.6'
    message = """\
Leo requires Python %s or higher.
You may download Python from
http://python.org/download/
""" % minimum_python_version
    try:
        version = '.'.join([str(sys.version_info[i]) for i in (0, 1, 2)])
        ok = g.CheckVersion(version, minimum_python_version)
        if not ok:
            print(message)
            try:
                # g.app.gui does not exist yet.
                import Tkinter as Tk
                class EmergencyDialog(object):
                    def run(self):
                        """Run the modal emergency dialog."""
                        self.top.geometry("%dx%d%+d%+d" % (300, 200, 50, 50))
                        self.top.lift()
                        self.top.grab_set() # Make the dialog a modal dialog.
                        self.root.wait_window(self.top)
                d = EmergencyDialog(
                    title='Python Version Error',
                    message=message)
                d.run()
            except Exception:
                pass
        return ok
    except Exception:
        print("isValidPython: unexpected exception: g.CheckVersion")
        traceback.print_exc()
        return 0
def loadLocalFile(self, fn, gui, old_c):
    trace = (False or g.trace_startup) and not g.unitTesting
'''
table = (
    (1, 'isValidPython'),
    # (2, 'class EmergencyDialog'),
    # (3, 'run'),
    (1, 'loadLocalFile'),
)
try:
    test_node = p.copy()
    test_node.deleteAllChildren()
    ic.pythonUnitTest(p,s=s,showTree=True)
    after = p.nodeAfterTree()
    root = p.lastChild()
    assert root.h.startswith('@@'), root.h
    p = root.firstChild()
    if 1:
        for n, h in table:
            n2 = p.level() - root.level()
            assert h == p.h, (h, p.h)
            assert n == n2, (n, n2, p.h)
            p.moveToThreadNext()
        assert p == after, ('tree comp failed', p.h)
    if 1:
        test_node.deleteAllChildren()
finally:
    c.redraw()
#@+node:ekr.20161115063144.3: *6* @test python bad class test
@tabwidth -4
    # Required when running unit tests externally.

s = '''\
class testClass1 # no colon
    pass

def spam():
    pass
'''

c.importCommands.pythonUnitTest(p,s=s,showTree=False)
#@+node:ekr.20161115063144.34: *6* @test python basic nesting test
# Was unittest/at_auto-unit-test.py
if 0: # Preamble...
    g.cls()
    if c.isChanged(): c.save()
    # import leo
    import leo.core.leoImport as leoImport
    import leo.plugins.importers.linescanner as linescanner
    import leo.plugins.importers.python
    # Reload all.
    import imp
    imp.reload(leo.plugins.importers.linescanner)
    imp.reload(leo.plugins.importers.python)
    imp.reload(leoImport)
    g.app.loadManager.createAllImporetersData()
    ic = leoImport.LeoImportCommands(c)
else:
    ic = c.importCommands

s = '''\
class class1:
    def class1_method1():
        pass
    def class1_method2():
        pass
    # After @others in child1.
class class2:
    def class2_method1():
        pass
    def class2_method2():
        pass
# last line
'''
table = (
    (1, 'class class1'),
    (2, 'class1_method1'),
    (2, 'class1_method2'),
    (1, 'class class2'),
    (2, 'class2_method1'),
    (2, 'class2_method2'),
)
try:
    test_node = p.copy()
    test_node.deleteAllChildren()
    ic.pythonUnitTest(p,s=s,showTree=True)
    after = p.nodeAfterTree()
    root = p.lastChild()
    assert root.h.startswith('@@'), root.h
    p = root.firstChild()
    if 1:
        for n, h in table:
            n2 = p.level() - root.level()
            assert h == p.h, (h, p.h)
            assert n == n2, (n, n2, p.h)
            p.moveToThreadNext()
        assert p == after, ('tree comp failed', p.h)
    if 1:
        test_node.deleteAllChildren()
finally:
    c.redraw()

#@+node:ekr.20161218103650.1: *6* @test python bug #346
@tabwidth -4
    # Required when running unit tests externally.
if 0: # Preamble...
    # g.cls()
    if c.isChanged(): c.save()
    # import leo
    import leo.core.leoImport as leoImport
    import leo.plugins.importers.linescanner as linescanner
    import leo.plugins.importers.python
    # Reload all.
    import imp
    imp.reload(leo.plugins.importers.linescanner)
    imp.reload(leo.plugins.importers.python)
    imp.reload(leoImport)
    g.app.loadManager.createAllImporetersData()
    ic = leoImport.LeoImportCommands(c)
else:
    ic = c.importCommands  
s = '''\
import sys

if sys.version_info[0] >= 3:
    exec_ = eval('exec')
else:
    def exec_(_code_, _globs_=None, _locs_=None):
        """Execute code in a namespace."""
        if _globs_ is None:
            frame = sys._getframe(1)
            _globs_ = frame.f_globals
            if _locs_ is None:
                _locs_ = frame.f_locals
            del frame
        elif _locs_ is None:
            _locs_ = _globs_
        exec("""exec _code_ in _globs_, _locs_""")

def make_parser():

    parser = argparse.ArgumentParser(
        description="""Raster calcs. with GDAL.
        The first --grid defines the projection, extent, cell size, and origin
        for all calculations, all other grids are transformed and resampled
        as needed to match.""",
        formatter_class=argparse.ArgumentDefaultsHelpFormatter
)
'''
table = (
    (1, 'Declarations'),
    (1, 'make_parser'),
)
try:
    test_node = p.copy()
    test_node.deleteAllChildren()
    ic.pythonUnitTest(p,s=s,showTree=True)
    after = p.nodeAfterTree()
    root = p.lastChild()
    assert root.h.startswith('@@'), root.h
    p = root.firstChild()
    if 1:
        for n, h in table:
            n2 = p.level() - root.level()
            assert h == p.h, (h, p.h)
            assert n == n2, (n, n2, p.h)
            p.moveToThreadNext()
        assert p == after, ('tree comp failed', p.h)
    if 1:
        test_node.deleteAllChildren()
finally:
    c.redraw()
#@+node:ekr.20161228070933.1: *6* @test python bug #354
if 0: # Preamble...
    # g.cls()
    if c.isChanged(): c.save()
    import leo.core.leoImport as leoImport
    import leo.plugins.importers.linescanner as linescanner
    import leo.plugins.importers.python
    # Reload all.
    import imp
    imp.reload(leo.plugins.importers.linescanner)
    imp.reload(leo.plugins.importers.python)
    imp.reload(leoImport)
    g.app.loadManager.createAllImporetersData()
    ic = leoImport.LeoImportCommands(c)
else:
    ic = c.importCommands 
s = """
if isPython3:
    def u(s):
        '''Return s, converted to unicode from Qt widgets.'''
        return s

    def ue(s, encoding):
        return s if g.isUnicode(s) else str(s, encoding)
else:
    def u(s):
        '''Return s, converted to unicode from Qt widgets.'''
        return builtins.unicode(s) # Suppress pyflakes complaint.

    def ue(s, encoding):
        return builtins.unicode(s, encoding)
"""
table = (
    (1, 'Declarations'),
)
try:
    test_node = p.copy()
    test_node.deleteAllChildren()
    ic.pythonUnitTest(p,s=s,showTree=True)
    after = p.nodeAfterTree()
    root = p.lastChild()
    assert root.h.startswith('@@'), root.h
    p = root.firstChild()
    if 1:
        for n, h in table:
            n2 = p.level() - root.level()
            assert h == p.h, (h, p.h)
            assert n == n2, (n, n2, p.h)
            p.moveToThreadNext()
        assert p == after, ('tree comp failed', p.h)
    if 1:
        test_node.deleteAllChildren()
finally:
    c.redraw()
#@+node:ekr.20170122033034.1: *6* @test python bug #357
if 0: # Preamble...
    # g.cls()
    if c.isChanged(): c.save()
    import leo.core.leoImport as leoImport
    import leo.plugins.importers.linescanner as linescanner
    import leo.plugins.importers.python
    # Reload all.
    import imp
    imp.reload(leo.plugins.importers.linescanner)
    imp.reload(leo.plugins.importers.python)
    imp.reload(leoImport)
    g.app.loadManager.createAllImporetersData()
    ic = leoImport.LeoImportCommands(c)
else:
    ic = c.importCommands 
s = '''
"""
sheet_stats.py - report column stats for spreadsheets

requires openpyxl and numpy

Terry N. Brown, terrynbrown@gmail.com, Fri Dec 16 13:20:47 2016
2016-12-26 Henry Helgen added average, variance, standard deviation,
                        coefficient of variation to output
2016-12-23 Henry Helgen updated to Python 3.5 syntax including print() and
                        writer = csv.writer(open(opt.output, 'w', newline=''))
"""

import csv
import argparse
import glob
import multiprocessing
import os
import sys
from collections import namedtuple
from math import sqrt, isnan
NAN = float('NAN')

from openpyxl import load_workbook

PYTHON_2 = sys.version_info[0] < 3
if not PYTHON_2:
    unicode = str

class AttrDict(dict):
    """allow d.attr instead of d['attr']
    http://stackoverflow.com/a/14620633
    """
    def __init__(self, *args, **kwargs):
        super(AttrDict, self).__init__(*args, **kwargs)
        self.__dict__ = self

FIELDS = [  # fields in outout table
    'file', 'field', 'n', 'blank', 'bad', 'min', 'max', 'mean', 'std',
    'sum', 'sumsq', 'variance', 'coefvar'
]
def make_parser():
    """build an argparse.ArgumentParser, don't call this directly,
       call get_options() instead.
    """
    parser = argparse.ArgumentParser(
        description="""Report column stats for spreadsheets""",
        formatter_class=argparse.ArgumentDefaultsHelpFormatter
    )

    parser.add_argument('files', type=str, nargs='+',
        help="Files to process, '*' patterns expanded."
    )

    required_named = parser.add_argument_group('required named arguments')

    required_named.add_argument("--output",
        help="Path to .csv file for output, will be overwritten",
        metavar='FILE'
    )

    return parser

def get_options(args=None):
    """
    get_options - use argparse to parse args, and return a
    argparse.Namespace, possibly with some changes / expansions /
    validatations.

    Client code should call this method with args as per sys.argv[1:],
    rather than calling make_parser() directly.

    :param [str] args: arguments to parse
    :return: options with modifications / validations
    :rtype: argparse.Namespace
    """
    opt = make_parser().parse_args(args)

    # modifications / validations go here

    if not opt.output:
        print("No --output supplied")
        exit(10)

    return opt

def get_aggregate(psumsqn, psumn, pcountn):
    """
    get_aggregate - compute mean, variance, standard deviation,
    coefficient of variation This function is used instead of
    numpy.mean, numpy.var, numpy.std since the sum, sumsq, and count are
    available when the function is called. It avoids an extra pass
    through the list.

    # note pcountn means the full list n,  not a sample n - 1

    :param sum of squares, sum, count
    :return: a tuple of floats mean, variance, standard deviation, coefficient of variation
    """

    Agg = namedtuple("Agg", "mean variance std coefvar")

    # validate inputs check for count == 0
    if pcountn == 0:
        result = Agg(NAN, NAN, NAN, NAN)
    else:

        mean = psumn / pcountn # mean

        # compute variance from sum squared without knowing mean while summing
        variance = (psumsqn - (psumn * psumn) / pcountn ) / pcountn

        #compute standard deviation
        if variance < 0:
            std = NAN
        else:
            std = sqrt(variance)

        # compute coefficient of variation
        if mean == 0:
            coefvar = NAN
        else:
            coefvar = std / mean

        result = Agg(mean, variance, std, coefvar)

    return result


def proc_file(filepath):
    """
    proc_file - process one .xlsx file

    :param str filepath: path to file
    :return: list of lists, rows of info. as expected in main()
    """

    print(filepath)

    # get the first sheet
    book = load_workbook(filename=filepath, read_only=True)
    sheets = book.get_sheet_names()
    sheet = book[sheets[0]]
    row_source = sheet.rows
    row0 = next(row_source)
    # get field names from the first row
    fields = [i.value for i in row0]

    data = {
        'filepath': filepath,
        'fields': {field:AttrDict({f:0 for f in FIELDS}) for field in fields}
    }

    for field in fields:
        # init. mins/maxs with invalid value for later calc.
        data['fields'][field].update(dict(
            min=NAN,
            max=NAN,
            field=field,
            file=filepath,
        ))

    rows = 0
    for row in row_source:

        if rows % 1000 == 0:  # feedback every 1000 rows
            print(rows)
            # Much cleaner to exit by creating a file called "STOP" in the
            # local directory than to try and use Ctrl-C, when using
            # multiprocessing.  Save time by checking only every 1000 rows.
            if os.path.exists("STOP"):
                return

        rows += 1

        for cell_n, cell in enumerate(row):
            d = data['fields'][fields[cell_n]]
            if cell.value is None or unicode(cell.value).strip() == '':
                d.blank += 1
            else:
                try:
                    x = float(cell.value)
                    d.sum += x
                    d.sumsq += x*x
                    d.n += 1
                    # min is x if no value seen yet, else min(prev-min, x)
                    if isnan(d.min):
                        d.min = x
                    else:
                        d.min = min(d.min, x)
                    # as for min
                    if isnan(d.max):
                        d.max = x
                    else:
                        d.max = max(d.max, x)
                except ValueError:
                    d.bad += 1

    assert sum(d.n+d.blank+d.bad for d in data['fields'].values()) == rows * len(fields)

    # compute the derived values
    for field in data['fields']:
        d = data['fields'][field]
        d.update(get_aggregate(d.sumsq, d.sum, d.n)._asdict().items())

    return data
def get_answers(opt=None, **kwargs):
    """get_answers - process files

    :param argparse.Namespace opt: options
    :return: list of answers from proc_file
    """

    if opt is None:  # API call rather than command line
        opt = type("opt", (), kwargs)

    # pass filenames through glob() to expand "2017_*.xlsx" etc.
    files = []
    for filepath in opt.files:
        files.extend(glob.glob(filepath))

    # create a pool of processors
    pool = multiprocessing.Pool(multiprocessing.cpu_count()-1)

    # process file list with processor pool
    return pool.map(proc_file, files)
def get_table_rows(answers):
    """get_table_rows - generator - convert get_answers() output to table format

    :param list answers: output from get_answers()
    :return: list of rows suitable for csv.writer
    """
    yield FIELDS
    for answer in answers:
        for field in answer['fields']:
            row = [answer['fields'][field][k] for k in FIELDS]
            if PYTHON_2:
                yield [unicode(col).encode('utf-8') for col in row]
            else:
                yield row

def main():
    """main() - when invoked directly"""
    opt = get_options()

    # csv.writer does its own EOL handling,
    # see https://docs.python.org/3/library/csv.html#csv.reader
    if PYTHON_2:
        output = open(opt.output, 'wb')
    else:
        output = open(opt.output, 'w', newline='')

    with output as out:
        writer = csv.writer(out)
        for row in get_table_rows(get_answers(opt)):
            writer.writerow(row)

if __name__ == '__main__':
    main()
'''
table = (
    (1, "Declarations"),
    (1, "class AttrDict"),
    (2, "__init__"),
    (1, "make_parser"),
    (1, "get_options"),
    (1, "get_aggregate"),
    (1, "proc_file"),
    (1, "get_answers"),
    (1, "get_table_rows"),
    (1, "main"),
)
try:
    test_node = p.copy()
    test_node.deleteAllChildren()
    ic.pythonUnitTest(p,s=s,showTree=True)
    after = p.nodeAfterTree()
    root = p.lastChild()
    assert root.h.startswith('@@'), root.h
    p = root.firstChild()
    if 1:
        for n, h in table:
            n2 = p.level() - root.level()
            assert h == p.h, (h, p.h)
            assert n == n2, (n, n2, p.h)
            p.moveToThreadNext()
        assert p == after, ('tree comp failed', p.h)
    if 1:
        test_node.deleteAllChildren()
finally:
    c.redraw()
#@+node:ekr.20170122032242.1: *6* @test python bug #360
s = """
@base_task(
    targets=['img/who_map.png', 'img/who_map.pdf'],
    file_dep=[data_path('phyto')],
    task_dep=['load_data'],
)
def make_map():
    '''make_map - plot the Thompson / Bartsh / WHO map'''
"""
table = (
    (1, 'make_map'),
)
try:
    test_node = p.copy()
    test_node.deleteAllChildren()
    c.importCommands .pythonUnitTest(p,s=s,showTree=True)
    after = p.nodeAfterTree()
    root = p.lastChild()
    assert root.h.startswith('@@'), root.h
    p = root.firstChild()
    if 1:
        for n, h in table:
            n2 = p.level() - root.level()
            assert h == p.h, (h, p.h)
            assert n == n2, (n, n2, p.h)
            p.moveToThreadNext()
        assert p == after, ('tree comp failed', p.h)
    if 1:
        test_node.deleteAllChildren()
finally:
    c.redraw()
#@+node:ekr.20170306041801.1: *6* @test python bug @390
s = """\
import sys

class Foo():
    pass
    
a = 2

def main(self):
    pass

if __name__ == '__main__':
    main()
"""
table = (
    (1, 'Declarations'),
    (1, 'class Foo'),
    (1, 'main'),
)
try:
    test_node = p.copy()
    test_node.deleteAllChildren()
    c.importCommands .pythonUnitTest(p,s=s,showTree=True)
    after = p.nodeAfterTree()
    root = p.lastChild()
    assert root.h.startswith('@@'), root.h
    p = root.firstChild()
    if 1:
        for n, h in table:
            n2 = p.level() - root.level()
            assert h == p.h, (h, p.h)
            assert n == n2, (n, n2, p.h)
            p.moveToThreadNext()
        assert p == after, ('tree comp failed', p.h)
        assert root.b.find("if __name__ == '__main__':") > -1
    if 1:
        test_node.deleteAllChildren()
finally:
    c.redraw()
#@+node:ekr.20161115063144.4: *6* @test python bug 603720
@tabwidth -4
    # Required when running unit tests externally.

# Leo bug 603720
# Within the docstring we must change '\' to '\\'
s = '''\
def foo():
    s = \\
"""#!/bin/bash
cd /tmp
ls"""
    file('/tmp/script', 'w').write(s)

class bar:
    pass

foo()
'''

tree = c.importCommands.pythonUnitTest(p,s=s,showTree=False)
#@+node:ekr.20161115063144.5: *6* @test python class test 2
@tabwidth -4
    # Required when running unit tests externally.

s = '''\
class testClass2:
    pass
'''

tree = c.importCommands.pythonUnitTest(p,s=s,showTree=False)
#@+node:ekr.20161115063144.6: *6* @test python class tests 1
@tabwidth -4
    # Required when running unit tests externally.

s = '''\
class testClass1:
    """A docstring"""
    def __init__ (self):
        pass
    def f1(self):
        pass
'''

c.importCommands.pythonUnitTest(p,s=s,showTree=False)
#@+node:ekr.20161115063144.7: *6* @test python comment after dict assign
@tabwidth -4
    # Required when running unit tests externally.
if 0: # Preamble...
    # g.cls()
    if c.isChanged(): c.save()
    # import leo
    import leo.core.leoImport as leoImport
    import leo.plugins.importers.linescanner as linescanner
    import leo.plugins.importers.python
    # Reload all.
    import imp
    imp.reload(leo.plugins.importers.linescanner)
    imp.reload(leo.plugins.importers.python)
    imp.reload(leoImport)
    g.app.loadManager.createAllImporetersData()
    ic = leoImport.LeoImportCommands(c)
else:
    ic = c.importCommands  

s = '''\
NS = { 'i': 'http://www.inkscape.org/namespaces/inkscape',
      's': 'http://www.w3.org/2000/svg',
      'xlink' : 'http://www.w3.org/1999/xlink'}

tabLevels = 4  # number of defined tablevels, FIXME, could derive from template?
'''
table = (
    (1, 'Declarations'),
)
try:
    test_node = p.copy()
    test_node.deleteAllChildren()
    ic.pythonUnitTest(p,s=s,showTree=True)
    after = p.nodeAfterTree()
    root = p.lastChild()
    assert root.h.startswith('@@'), root.h
    p = root.firstChild()
    if 1:
        for n, h in table:
            n2 = p.level() - root.level()
            assert h == p.h, (h, p.h)
            assert n == n2, (n, n2, p.h)
            p.moveToThreadNext()
        assert p == after, ('tree comp failed', p.h)
    test_node.deleteAllChildren()
finally:
    c.redraw()
#@+node:ekr.20161115063144.8: *6* @test python decls test 1
@tabwidth -4
    # Required when running unit tests externally.
if 0: # Preamble...
    # g.cls()
    if c.isChanged(): c.save()
    # import leo
    import leo.core.leoImport as leoImport
    import leo.plugins.importers.linescanner as linescanner
    import leo.plugins.importers.python
    # Reload all.
    import imp
    imp.reload(leo.plugins.importers.linescanner)
    imp.reload(leo.plugins.importers.python)
    imp.reload(leoImport)
    g.app.loadManager.createAllImporetersData()
    ic = leoImport.LeoImportCommands(c)
else:
    ic = c.importCommands  

s = '''\
import leo.core.leoGlobals as g

a = 3
'''
table = (
    (1, 'Declarations'),
)
try:
    test_node = p.copy()
    test_node.deleteAllChildren()
    ic.pythonUnitTest(p,s=s,showTree=True)
    after = p.nodeAfterTree()
    root = p.lastChild()
    assert root.h.startswith('@@'), root.h
    p = root.firstChild()
    if 1:
        for n, h in table:
            n2 = p.level() - root.level()
            assert h == p.h, (h, p.h)
            assert n == n2, (n, n2, p.h)
            p.moveToThreadNext()
        assert p == after, ('tree comp failed', p.h)
    test_node.deleteAllChildren()
finally:
    c.redraw()
#@+node:ekr.20161115063144.9: *6* @test python decorator
@tabwidth -4
    # Required when running unit tests externally.

s = '''\
class Index:
    """docstring"""
    @cherrypy.nocolor
    @cherrypy.expose
    def index(self):
        return "Hello world!"
        
    @cmd('abc')
    def abc(self):
        return "abc"
'''

try:
    c.importCommands.pythonUnitTest(p,s=s,showTree=True) # Must be true.
    index = g.findNodeInTree(c, p, 'index')
    assert index
    lines = g.splitLines(index.b)
    assert lines[0] == '@cherrypy.nocolor\n', repr(lines[0])
    assert lines[1] == '@cherrypy.expose\n', repr(lines[1])
    abc = g.findNodeInTree(c,p, 'abc')
    lines = g.splitLines(abc.b)
    assert lines[0] == "@cmd('abc')\n", repr(lines[0])
    if 1:
        p.deleteAllChildren()
finally:
    c.redraw()
#@+node:ekr.20161224101046.1: *6* @test python decorator 2
@tabwidth -4
    # Required when running unit tests externally.
if 0: # Preamble...
    g.cls()
    if c.isChanged(): c.save()
    # import leo
    import leo.core.leoImport as leoImport
    import leo.plugins.importers.linescanner as linescanner
    import leo.plugins.importers.python
    # Reload all.
    import imp
    imp.reload(leo.plugins.importers.linescanner)
    imp.reload(leo.plugins.importers.python)
    imp.reload(leoImport)
    g.app.loadManager.createAllImporetersData()
    ic = leoImport.LeoImportCommands(c)
else:
    ic = c.importCommands

s = '''
"""
A PyQt "task launcher" for quick access to python scripts.

Buttons to click to make working in Windows less unproductive.

e.g. a button to move the current window to top or bottom half
of screen, because Windows-Up / Windows-Down doesn't do that.
Or quote the text on the clipboard properly, because Outlook
can't do that.

terrynbrown@gmail.com, 2016-12-23
"""

import sys
import time
from PyQt4 import QtGui, QtCore, Qt
from PyQt4.QtCore import Qt as QtConst

COMMANDS = []

class Draggable(QtGui.QWidget):
    def __init__(self, *args, **kwargs):
        """__init__
        """

        QtGui.QWidget.__init__(self, *args, **kwargs)
        # self.setMouseTracking(True)
        self.offset = None
        layout = QtGui.QHBoxLayout()
        self.setLayout(layout)
        layout.addItem(QtGui.QSpacerItem(15, 5))
        layout.setSpacing(0)
        layout.setContentsMargins(0, 0, 0, 0)

    def mousePressEvent(self, event):
        self.offset = event.pos()

    def mouseMoveEvent(self, event):
        x=event.globalX()
        y=event.globalY()
        x_w = self.offset.x()
        y_w = self.offset.y()
        self.parent().move(x-x_w, y-y_w)

def command(name):
    def makebutton(function):
        COMMANDS.append((name, function))
        return function
    return makebutton

@command("Exit")
def exit_():
    exit()

def main():

    app = Qt.QApplication(sys.argv)

    main = QtGui.QMainWindow(None,
       # QtConst.CustomizeWindowHint  |
       QtConst.FramelessWindowHint #  |
       # QtConst.WindowCloseButtonHint
    )

    main.resize(800,16)
    main.move(40,40)
    mainwidj = Draggable()

    for name, function in COMMANDS:
        button = QtGui.QPushButton(name)
        button.clicked.connect(function)
        mainwidj.layout().addWidget(button)

    main.setCentralWidget(mainwidj)
    main.show()
    app.exec_()

if __name__ == '__main__':
    main()
'''
table = (
    (1, "Declarations"),
    (1, "class Draggable"),
    (2, "__init__"),
    (2, "mousePressEvent"),
    (2, "mouseMoveEvent"),
    (1, "command"),
    (1, "exit_"),
    (1, "main"),
)
try:
    test_node = p.copy()
    test_node.deleteAllChildren()
    c.importCommands.pythonUnitTest(p,s=s,showTree=True) # Must be true.
    after = p.nodeAfterTree()
    root = p.lastChild()
    assert root.h.startswith('@@'), root.h
    p = root.firstChild()
    if 1:
        for n, h in table:
            n2 = p.level() - root.level()
            assert h == p.h, (h, p.h)
            assert n == n2, (n, n2, p.h)
            p.moveToThreadNext()
        assert p == after, ('tree comp failed', p.h)
    target = g.findNodeInTree(c, root, 'exit_')
    assert target
    lines = g.splitLines(target.b)
    assert lines[0] == '@command("Exit")\n', repr(lines[0])
    if 1:
        test_node.deleteAllChildren()
finally:
    c.redraw()
#@+node:ekr.20161115063144.10: *6* @test python def inside def
@tabwidth -4
    # Required when running unit tests externally.
if 0: # Preamble...
    # g.cls()
    if c.isChanged(): c.save()
    # import leo
    import leo.core.leoImport as leoImport
    import leo.plugins.importers.linescanner as linescanner
    import leo.plugins.importers.python
    # Reload all.
    import imp
    imp.reload(leo.plugins.importers.linescanner)
    imp.reload(leo.plugins.importers.python)
    imp.reload(leoImport)
    g.app.loadManager.createAllImporetersData()
    ic = leoImport.LeoImportCommands(c)
else:
    ic = c.importCommands  
s = '''\
class aClass:
    def outerDef(self):
        """docstring.
        line two."""

        def pr(*args,**keys):
            g.es_print(color='blue',*args,**keys)

        a = 3
'''
table = (
    (1, 'class aClass'),
    (2, 'outerDef'),
    # (3, 'pr'),
)
try:
    test_node = p.copy()
    test_node.deleteAllChildren()
    ic.pythonUnitTest(p,s=s,showTree=True)
    after = p.nodeAfterTree()
    root = p.lastChild()
    assert root.h.startswith('@@'), root.h
    p = root.firstChild()
    if 1:
        for n, h in table:
            n2 = p.level() - root.level()
            assert h == p.h, (h, p.h)
            assert n == n2, (n, n2, p.h)
            p.moveToThreadNext()
        assert p == after, ('tree comp failed', p.h)
    test_node.deleteAllChildren()
finally:
    c.redraw()
#@+node:ekr.20161115063144.11: *6* @test python def test 1
@tabwidth -4
    # Required when running unit tests externally.
if 0: # Preamble...
    # g.cls()
    if c.isChanged(): c.save()
    # import leo
    import leo.core.leoImport as leoImport
    import leo.plugins.importers.linescanner as linescanner
    import leo.plugins.importers.python
    # Reload all.
    import imp
    imp.reload(leo.plugins.importers.linescanner)
    imp.reload(leo.plugins.importers.python)
    imp.reload(leoImport)
    g.app.loadManager.createAllImporetersData()
    ic = leoImport.LeoImportCommands(c)
else:
    ic = c.importCommands  
s = '''\

class test:

    def importFilesCommand (self,files=None,treeType=None,
        perfectImport=True,testing=False,verbose=False):
            # Not a command.  It must *not* have an event arg.

        c = self.c
        if c == None: return
        p = c.currentPosition()

    # Used by paste logic.

    def convertMoreStringToOutlineAfter (self,s,firstVnode):
        s = string.replace(s,"\\r","")
        strings = string.split(s,"\\n")
        return self.convertMoreStringsToOutlineAfter(strings,firstVnode)
'''
table = (
    (1, 'class test'),
    (2, 'importFilesCommand'),
    (2, 'convertMoreStringToOutlineAfter'),
)
try:
    test_node = p.copy()
    test_node.deleteAllChildren()
    ic.pythonUnitTest(p,s=s,showTree=True)
    after = p.nodeAfterTree()
    root = p.lastChild()
    assert root.h.startswith('@@'), root.h
    p = root.firstChild()
    if 1:
        for n, h in table:
            n2 = p.level() - root.level()
            assert h == p.h, (h, p.h)
            assert n == n2, (n, n2, p.h)
            p.moveToThreadNext()
        assert p == after, ('tree comp failed', p.h)
    if 1:
        root.doDelete()
finally:
    c.redraw()
#@+node:ekr.20161115063144.12: *6* @test python def test 2
@tabwidth -4
    # Required when running unit tests externally.
if 0: # Preamble...
    # g.cls()
    if c.isChanged(): c.save()
    # import leo
    import leo.core.leoImport as leoImport
    import leo.plugins.importers.linescanner as linescanner
    import leo.plugins.importers.python
    # Reload all.
    import imp
    imp.reload(leo.plugins.importers.linescanner)
    imp.reload(leo.plugins.importers.python)
    imp.reload(leoImport)
    g.app.loadManager.createAllImporetersData()
    ic = leoImport.LeoImportCommands(c)
else:
    ic = c.importCommands

s = '''\

class test:
    def spam(b):
        pass

    # Used by paste logic.

    def foo(a):
        pass
'''
table = (
    (1, 'class test'),
    (2, 'spam'),
    (2, 'foo'),
)
try:
    test_node = p.copy()
    test_node.deleteAllChildren()
    ic.pythonUnitTest(p,s=s,showTree=True)
    after = p.nodeAfterTree()
    root = p.lastChild()
    assert root.h.startswith('@@'), root.h
    p = root.firstChild()
    if 1:
        for n, h in table:
            n2 = p.level() - root.level()
            assert h == p.h, (h, p.h)
            assert n == n2, (n, n2, p.h)
            p.moveToThreadNext()
        assert p == after, ('tree comp failed', p.h)
    if 1:
        test_node.deleteAllChildren()
finally:
    c.redraw()
#@+node:ekr.20161115063144.13: *6* @test python docstring only
@tabwidth -4
    # Required when running unit tests externally.

s = '''\
"""A file consisting only of a docstring.
"""
'''

c.importCommands.pythonUnitTest(p,s=s,showTree=False)
#@+node:ekr.20161115063144.14: *6* @test python empty decls
@tabwidth -4
    # Required when running unit tests externally.

s = '''\
import leo.core.leoGlobals as g

a = 3
'''

c.importCommands.pythonUnitTest(p,s=s,showTree=False)
#@+node:ekr.20161115063144.15: *6* @test python extra leading ws test
@tabwidth -4
    # Required when running unit tests externally.

s = '''\

class cls:
     def fun(): # one extra space.
        pass
'''


c.importCommands.pythonUnitTest(p,s=s,showTree=False)
#@+node:ekr.20161115063144.16: *6* @test python indent decls
@tabwidth -4
    # Required when running unit tests externally.
if 0: # Preamble...
    # g.cls()
    if c.isChanged(): c.save()
    # import leo
    import leo.core.leoImport as leoImport
    import leo.plugins.importers.linescanner as linescanner
    import leo.plugins.importers.python
    # Reload all.
    import imp
    imp.reload(leo.plugins.importers.linescanner)
    imp.reload(leo.plugins.importers.python)
    imp.reload(leoImport)
    g.app.loadManager.createAllImporetersData()
    ic = leoImport.LeoImportCommands(c)
else:
    ic = c.importCommands  
s = '''\

class mammalProviderBase(object):
    """Root class for content providers used by DWEtree.py"""
    def __init__(self, params):
        """store reference to parameters"""
        self.params = params
    def provide(self, what):
        """default <BASE> value"""
        if what == 'doctitle':
            return ELE('base', href=self.params['/BASE/'])
        return None

    def imagePath(self, sppdat):
        """return path to images and list of images for *species*"""
        path = 'MNMammals/imglib/Mammalia'
        for i in 'Order', 'Family', 'Genus', 'Species':
            path = os.path.join(path, sppdat['%sName' % (i,)])
        imglib = os.path.join('/var/www',path)
        imglib = os.path.join(imglib, '*.[Jj][Pp][Gg]')
        path = os.path.join('/',path)
        lst = [os.path.split(i)[1] for i in glob.glob(imglib)]
        lst.sort()
        return path, lst

class mainPages(mammalProviderBase):
    """provide content for pages in 'main' folder"""
    __parent = mammalProviderBase
    def provide(self, what):
        """add one layer to <BASE>"""
        ans = self.__parent.provide(self, what)
        if what == 'doctitle':
            return ELE('base', href=self.params['/BASE/']+'main/')
        return ans
''' 
table = (
    (1, 'class mammalProviderBase'),
    (2, '__init__'),
    (2, 'provide'),
    (2, 'imagePath'),
    (1, 'class mainPages'),
    (2, 'provide'),
)
try:
    test_node = p.copy()
    test_node.deleteAllChildren()
    ic.pythonUnitTest(p,s=s,showTree=True)
    after = p.nodeAfterTree()
    root = p.lastChild()
    assert root.h.startswith('@@'), root.h
    p = root.firstChild()
    if 1:
        for n, h in table:
            n2 = p.level() - root.level()
            assert h == p.h, (h, p.h)
            assert n == n2, (n, n2, p.h)
            p.moveToThreadNext()
        assert p == after, ('tree comp failed', p.h)
    if 1:
        test_node.deleteAllChildren()
finally:
    c.redraw()
#@+node:ekr.20161117000902.1: *6* @test python leoImport.py (small)
if 0: # Preamble...
    # g.cls()
    if c.isChanged(): c.save()
    # import leo
    import leo.core.leoImport as leoImport
    import leo.plugins.importers.linescanner as linescanner
    import leo.plugins.importers.python
    # Reload all.
    import imp
    imp.reload(leo.plugins.importers.linescanner)
    imp.reload(leo.plugins.importers.python)
    imp.reload(leoImport)
    g.app.loadManager.createAllImporetersData()
    ic = leoImport.LeoImportCommands(c)
else:
    ic = c.importCommands

s = """\
# -*- coding: utf-8 -*-
import leo.core.leoGlobals as g
class LeoImportCommands(object):
    '''A class implementing all of Leo's import/export code.'''
    def createOutline(self, fileName, parent, atAuto=False, atShadow=False, s=None, ext=None):
        '''Create an outline by importing a file or string.'''

    def dispatch(self, ext, p):
        '''Return the correct scanner function for p, an @auto node.'''
        # Match the @auto type first, then the file extension.
        return self.scanner_for_at_auto(p) or self.scanner_for_ext(ext)
    def scanner_for_at_auto(self, p):
        '''A factory returning a scanner function for p, an @auto node.'''
        d = self.atAutoDict
        for key in d.keys():
            aClass = d.get(key)
            if aClass and g.match_word(p.h, 0, key):
                if trace: g.trace('found', aClass.__name__)

                def scanner_for_at_auto_cb(atAuto, parent, s, prepass=False):
                    try:
                        scanner = aClass(importCommands=self, atAuto=atAuto)
                        return scanner.run(s, parent, prepass=prepass)
                    except Exception:
                        g.es_print('Exception running', aClass.__name__)
                        g.es_exception()
                        return None

                if trace: g.trace('found', p.h)
                return scanner_for_at_auto_cb
        if trace: g.trace('not found', p.h, sorted(d.keys()))
        return None
    def scanner_for_ext(self, ext):
        '''A factory returning a scanner function for the given file extension.'''
        aClass = self.classDispatchDict.get(ext)
        if aClass:

            def scanner_for_ext_cb(atAuto, parent, s, prepass=False):
                try:
                    scanner = aClass(importCommands=self, atAuto=atAuto)
                    return scanner.run(s, parent, prepass=prepass)
                except Exception:
                    g.es_print('Exception running', aClass.__name__)
                    g.es_exception()
                    return None

            return scanner_for_ext_cb
        else:
            return None
    def get_import_filename(self, fileName, parent):
        '''Return the absolute path of the file and set .default_directory.'''

    def init_import(self, atAuto, atShadow, ext, fileName, s):
        '''Init ivars & vars for imports.'''
"""
table = (
    (1, 'Declarations'),
    (1, "class LeoImportCommands"),
    (2, "createOutline"),
    (2, "dispatch"),
    (2, "scanner_for_at_auto"),
    (2, "scanner_for_ext"),
    (2, "get_import_filename"),
    (2, "init_import"),
)
try:
    test_node = p.copy()
    test_node.deleteAllChildren()
    ic.pythonUnitTest(p,s=s,showTree=True)
    after = p.nodeAfterTree()
    root = p.lastChild()
    assert root.h.startswith('@@'), root.h
    p = root.firstChild()
    if 1:
        for n, h in table:
            n2 = p.level() - root.level()
            assert h == p.h, (h, p.h)
            assert n == n2, (n, n2, p.h)
            p.moveToThreadNext()
        assert p == after, ('tree comp failed', p.h)
    test_node.deleteAllChildren()
finally:
    c.redraw()
#@+node:ekr.20161115063144.18: *6* @test python looks like section ref
# ~/at-auto-test.py

s = '''\
# This is valid Python, but it looks like a section reference.
a = b << c >> d
'''

c.importCommands.pythonUnitTest(p,s=s,showTree=False)

# Always passes, but *sometimes* i.check gives a message!
#@+node:ekr.20161115063144.19: *6* @test python minimal class 1
@tabwidth -4
    # Required when running unit tests externally.

s = '''\

class ItasException(Exception):

    pass

def gpRun(gp, cmd, args, log = None):

    """Wrapper for making calls to the geoprocessor and reporting errors"""

    if log:

        log('gp: %s: %s\\n' % (cmd, str(args)))
'''

c.importCommands.pythonUnitTest(p,s=s,showTree=False)


#@+node:ekr.20161115063144.20: *6* @test python minimal class 2
@tabwidth -4
    # Required when running unit tests externally.

s = '''\

class emptyClass: pass

def followingDef():
    pass
'''

c.importCommands.pythonUnitTest(p,s=s,showTree=False)
#@+node:ekr.20161115063144.21: *6* @test python minimal class 3
@tabwidth -4
    # Required when running unit tests externally.

s = '''\

class emptyClass: pass # comment

def followingDef(): # comment
    pass
'''

c.importCommands.pythonUnitTest(p,s=s,showTree=False)
#@+node:ekr.20161115063144.22: *6* @test python overindent def--no following def
@tabwidth -4
    # Required when running unit tests externally.

s = '''\
class aClass:
    def def1(self):
        pass

    if False or g.unitTesting:

        def pr(*args,**keys): # reportMismatch test
            g.es_print(color='blue',*args,**keys)

        pr('input...')
'''

c.importCommands.pythonUnitTest(p,s=s,showTree=False)
#@+node:ekr.20170306052710.1: *7* @@file c:/leo.repo/leo-editor/leo/test/python overindent def--no following def
@others
@language python
@tabwidth -4
#@+node:ekr.20170306052710.2: *8* class aClass
class aClass:
    @others
#@+node:ekr.20170306052710.3: *9* def1
def def1(self):
    pass

if False or g.unitTesting:

    def pr(*args,**keys): # reportMismatch test
        g.es_print(color='blue',*args,**keys)

    pr('input...')
#@+node:ekr.20161115063144.23: *6* @test python overindent def--one following def
@tabwidth -4
    # Required when running unit tests externally.

s = '''\
class aClass:
    def def1(self):
        pass

    if False or g.unitTesting:

        def pr(*args,**keys): # reportMismatch test
            g.es_print(color='blue',*args,**keys)

        pr('input...')

    def def2(self):
        pass
'''

c.importCommands.pythonUnitTest(p,s=s,showTree=False)
#@+node:ekr.20161115063144.24: *6* @test python overindented def 3
@tabwidth -4
    # Required when running unit tests externally.
if 0: # Preamble...
    # g.cls()
    if c.isChanged(): c.save()
    # import leo
    import leo.core.leoImport as leoImport
    import leo.plugins.importers.linescanner as linescanner
    import leo.plugins.importers.python
    # Reload all.
    import imp
    imp.reload(leo.plugins.importers.linescanner)
    imp.reload(leo.plugins.importers.python)
    imp.reload(leoImport)
    g.app.loadManager.createAllImporetersData()
    ic = leoImport.LeoImportCommands(c)
else:
    ic = c.importCommands  
# This caused PyParse.py not to be imported properly.
s = r'''
import re
if 0: # Causes the 'overindent'
   if 0:   # for throwaway debugging output
      def dump(*stuff):
        sys.__stdout__.write(" ".join(map(str, stuff)) + "\n")
for ch in "({[":
   _tran[ord(ch)] = '('
class testClass1:
    pass
'''
table = (
    (1, 'Declarations'),
    (1, 'class testClass1'),
)
try:
    test_node = p.copy()
    test_node.deleteAllChildren()
    ic.pythonUnitTest(p,s=s,showTree=True)
    after = p.nodeAfterTree()
    root = p.lastChild()
    assert root.h.startswith('@@'), root.h
    p = root.firstChild()
    if 1:
        for n, h in table:
            n2 = p.level() - root.level()
            assert h == p.h, (h, p.h)
            assert n == n2, (n, n2, p.h)
            p.moveToThreadNext()
        assert p == after, ('tree comp failed', p.h)
    if 1:
        test_node.deleteAllChildren()
finally:
    c.redraw()
#@+node:ekr.20161115063144.25: *6* @test python string test: extra indent
@tabwidth -4
    # Required when running unit tests externally.

s = '''\
class BaseScanner:

        """The base class for all import scanner classes."""

        def __init__ (self,importCommands,language):

            self.c = ic.c

        def createHeadline (self,parent,body,headline):
            # g.trace("parent,headline:",parent,headline)
            return p
'''

c.importCommands.pythonUnitTest(p,s=s,showTree=False)
#@+node:ekr.20161115063144.26: *6* @test python string underindent lines
@tabwidth -4
    # Required when running unit tests externally.

s = '''\
class BaseScanner:
    def containsUnderindentedComment(self):
        a = 2
    # A true underindented comment.
        b = 3
    # This underindented comment should be placed with next function.
    def empty(self):
        pass
'''

c.importCommands.pythonUnitTest(p,s=s,showTree=False)
#@+node:ekr.20161115063144.27: *6* @test python string underindent lines 2
@tabwidth -4
    # Required when running unit tests externally.

s = '''\
class BaseScanner:
    def containsUnderindentedComment(self):
        a = 2
    #
        b = 3
        # This comment is part of the present function.

    def empty(self):
        pass
'''

c.importCommands.pythonUnitTest(p,s=s,showTree=False)
#@+node:ekr.20161222064421.1: *6* @test python top-level later decl
# From xo.py.
if 0: # Preamble...
    # g.cls()
    if c.isChanged(): c.save()
    # import leo
    import leo.core.leoImport as leoImport
    import leo.plugins.importers.linescanner as linescanner
    import leo.plugins.importers.python
    # Reload all.
    import imp
    imp.reload(leo.plugins.importers.linescanner)
    imp.reload(leo.plugins.importers.python)
    imp.reload(leoImport)
    g.app.loadManager.createAllImporetersData()
    ic = leoImport.LeoImportCommands(c)
else:
    ic = c.importCommands  

s = r'''#!/usr/bin/env python3

import os
import re

def merge_value(v1, v2):
    return v

class MainDisplay(object):

    def save_file(self):
        """Write the file out to disk."""
        with open(self.save_name, "w") as f:
            for newline in newlines:
                f.write(newline)

# This line should be included at the end of the class node.
ensure_endswith_newline = lambda x: x if x.endswith('\n') else x + '\n'

def retab(s, tabsize):
    return ''.join(pieces)

if __name__=="__main__":
    main()
'''
table = (
    (1, 'Declarations'),
    (1, 'merge_value'),
    (1, 'class MainDisplay'),
    (2, 'save_file'),
    (1, 'retab'),
)
try:
    test_node = p.copy()
    test_node.deleteAllChildren()
    ic.pythonUnitTest(p,s=s,showTree=True)
    after = p.nodeAfterTree()
    root = p.lastChild()
    assert root.h.startswith('@@'), root.h
    p = root.firstChild()
    if 1:
        for n, h in table:
            n2 = p.level() - root.level()
            assert h == p.h, (h, p.h)
            assert n == n2, (n, n2, p.h)
            p.moveToThreadNext()
        assert p == after, ('tree comp failed', p.h)
    if 1:
        test_node.deleteAllChildren()
finally:
    c.redraw()
#@+node:ekr.20161115063144.28: *6* @test python trailing comment
@tabwidth -4
    # Required when running unit tests externally.

s = '''\
class aClass: # trailing comment


    def def1(self):             # trailing comment
        pass
'''

c.importCommands.pythonUnitTest(p,s=s,showTree=False)
#@+node:ekr.20161115063144.29: *6* @test python trailing comment--outer levels
@tabwidth -4
    # Required when running unit tests externally.

s = '''\

xyz = 6 # trailing comment
pass
'''

c.importCommands.pythonUnitTest(p,s=s,showTree=False)
#@+node:ekr.20161115063144.30: *6* @test python two functions
# For comparison with unindent does not end function.

@tabwidth -4
    # Required when running unit tests externally.

s = '''\

def foo():
    pass

def bar():
    pass
'''

c.importCommands.pythonUnitTest(p,s=s,showTree=False)
#@+node:ekr.20161115063144.31: *6* @test python underindent method
@tabwidth -4
    # Required when running unit tests externally.
if 0: # Preamble...
    # g.cls()
    if c.isChanged(): c.save()
    # import leo
    import leo.core.leoImport as leoImport
    import leo.plugins.importers.linescanner as linescanner
    import leo.plugins.importers.python
    # Reload all.
    import imp
    imp.reload(leo.plugins.importers.linescanner)
    imp.reload(leo.plugins.importers.python)
    imp.reload(leoImport)
    g.app.loadManager.createAllImporetersData()
    ic = leoImport.LeoImportCommands(c)
else:
    ic = c.importCommands  
s = '''\

class emptyClass: 

    def spam():
        """docstring line 1
under-indented docstring line"""
        pass

def followingDef(): # comment
    pass
'''
table = (
    (1, 'class emptyClass'),
    (2, 'spam'),
    (1, 'followingDef'),
)
try:
    test_node = p.copy()
    test_node.deleteAllChildren()
    ic.pythonUnitTest(p,s=s,showTree=True)
    after = p.nodeAfterTree()
    root = p.lastChild()
    assert root.h.startswith('@@'), root.h
    p = root.firstChild()
    if 1:
        for n, h in table:
            n2 = p.level() - root.level()
            assert h == p.h, (h, p.h)
            assert n == n2, (n, n2, p.h)
            p.moveToThreadNext()
        assert p == after, ('tree comp failed', p.h)
    test_node.deleteAllChildren()
finally:
    c.redraw()
#@+node:ekr.20161115063144.32: *6* @test python unindent in triple string does not end function
@tabwidth -4
    # Required when running unit tests externally.

s = '''\

def foo():

    error("""line1
line2.
""")

    a = 5

def bar():
    pass
'''

showTree = False
keepTree = False

c.importCommands.pythonUnitTest(p,s=s,showTree=showTree)

if showTree:
    try:
        child = p.firstChild()
        n = child.numberOfChildren()
        assert n == 2, 'expected 2 children, got %s' % n
    finally:
        if keepTree:
            h = child.h
            print('h',h)
            child.setHeadString('@'+h)
        else:
            while p.hasChildren():
                p.firstChild().doDelete()
        c.redraw(p)
#@+node:ekr.20161115063144.33: *6* @test python unittest/perfectImport/formatter.py
@killcolor

s = '''\

"""Generic output formatting.
"""

import sys


AS_IS = None


class NullFormatter:
    """A formatter which does nothing.

    If the writer parameter is omitted, a NullWriter instance is created.
    No methods of the writer are called by NullFormatter instances.

    Implementations should inherit from this class if implementing a writer
    interface but don't need to inherit any implementation.

    """

    def __init__(self, writer=None):
        if writer is None:
            writer = NullWriter()
        self.writer = writer
    def end_paragraph(self, blankline): pass
    def add_line_break(self): pass
    def add_hor_rule(self, *args, **kw): pass
    def add_label_data(self, format, counter, blankline=None): pass
    def add_flowing_data(self, data): pass
    def add_literal_data(self, data): pass
    def flush_softspace(self): pass
    def push_alignment(self, align): pass
    def pop_alignment(self): pass
    def push_font(self, x): pass
    def pop_font(self): pass
    def push_margin(self, margin): pass
    def pop_margin(self): pass
    def set_spacing(self, spacing): pass
    def push_style(self, *styles): pass
    def pop_style(self, n=1): pass
    def assert_line_data(self, flag=1): pass


class AbstractFormatter:
    """The standard formatter.

    This implementation has demonstrated wide applicability to many writers,
    and may be used directly in most circumstances.  It has been used to
    implement a full-featured World Wide Web browser.

    """

    #  Space handling policy:  blank spaces at the boundary between elements
    #  are handled by the outermost context.  "Literal" data is not checked
    #  to determine context, so spaces in literal data are handled directly
    #  in all circumstances.

    def __init__(self, writer):
        self.writer = writer            # Output device
        self.align = None               # Current alignment
        self.align_stack = []           # Alignment stack
        self.font_stack = []            # Font state
        self.margin_stack = []          # Margin state
        self.spacing = None             # Vertical spacing state
        self.style_stack = []           # Other state, e.g. color
        self.nospace = 1                # Should leading space be suppressed
        self.softspace = 0              # Should a space be inserted
        self.para_end = 1               # Just ended a paragraph
        self.parskip = 0                # Skipped space between paragraphs?
        self.hard_break = 1             # Have a hard break
        self.have_label = 0

    def end_paragraph(self, blankline):
        if not self.hard_break:
            self.writer.send_line_break()
            self.have_label = 0
        if self.parskip < blankline and not self.have_label:
            self.writer.send_paragraph(blankline - self.parskip)
            self.parskip = blankline
            self.have_label = 0
        self.hard_break = self.nospace = self.para_end = 1
        self.softspace = 0

    def add_line_break(self):
        if not (self.hard_break or self.para_end):
            self.writer.send_line_break()
            self.have_label = self.parskip = 0
        self.hard_break = self.nospace = 1
        self.softspace = 0

    def add_hor_rule(self, *args, **kw):
        if not self.hard_break:
            self.writer.send_line_break()
        self.writer.send_hor_rule(*args, **kw)
        self.hard_break = self.nospace = 1
        self.have_label = self.para_end = self.softspace = self.parskip = 0

    def add_label_data(self, format, counter, blankline = None):
        if self.have_label or not self.hard_break:
            self.writer.send_line_break()
        if not self.para_end:
            self.writer.send_paragraph((blankline and 1) or 0)
        if isinstance(format, str):
            self.writer.send_label_data(self.format_counter(format, counter))
        else:
            self.writer.send_label_data(format)
        self.nospace = self.have_label = self.hard_break = self.para_end = 1
        self.softspace = self.parskip = 0

    def format_counter(self, format, counter):
        label = ''
        for c in format:
            if c == '1':
                label = label + ('%d' % counter)
            elif c in 'aA':
                if counter > 0:
                    label = label + self.format_letter(c, counter)
            elif c in 'iI':
                if counter > 0:
                    label = label + self.format_roman(c, counter)
            else:
                label = label + c
        return label

    def format_letter(self, case, counter):
        label = ''
        while counter > 0:
            counter, x = divmod(counter-1, 26)
            # This makes a strong assumption that lowercase letters
            # and uppercase letters form two contiguous blocks, with
            # letters in order!
            s = chr(ord(case) + x)
            label = s + label
        return label

    def format_roman(self, case, counter):
        ones = ['i', 'x', 'c', 'm']
        fives = ['v', 'l', 'd']
        label, index = '', 0
        # This will die of IndexError when counter is too big
        while counter > 0:
            counter, x = divmod(counter, 10)
            if x == 9:
                label = ones[index] + ones[index+1] + label
            elif x == 4:
                label = ones[index] + fives[index] + label
            else:
                if x >= 5:
                    s = fives[index]
                    x = x-5
                else:
                    s = ''
                s = s + ones[index]*x
                label = s + label
            index = index + 1
        if case == 'I':
            return label.upper()
        return label

    def add_flowing_data(self, data):
        if not data: return
        # The following looks a bit convoluted but is a great improvement over
        # data = regsub.gsub('[' + string.whitespace + ']+', ' ', data)
        prespace = data[:1].isspace()
        postspace = data[-1:].isspace()
        data = " ".join(data.split())
        if self.nospace and not data:
            return
        elif prespace or self.softspace:
            if not data:
                if not self.nospace:
                    self.softspace = 1
                    self.parskip = 0
                return
            if not self.nospace:
                data = ' ' + data
        self.hard_break = self.nospace = self.para_end = \
                          self.parskip = self.have_label = 0
        self.softspace = postspace
        self.writer.send_flowing_data(data)

    def add_literal_data(self, data):
        if not data: return
        if self.softspace:
            self.writer.send_flowing_data(" ")
        self.hard_break = data[-1:] == '\n'
        self.nospace = self.para_end = self.softspace = \
                       self.parskip = self.have_label = 0
        self.writer.send_literal_data(data)

    def flush_softspace(self):
        if self.softspace:
            self.hard_break = self.para_end = self.parskip = \
                              self.have_label = self.softspace = 0
            self.nospace = 1
            self.writer.send_flowing_data(' ')

    def push_alignment(self, align):
        if align and align != self.align:
            self.writer.new_alignment(align)
            self.align = align
            self.align_stack.append(align)
        else:
            self.align_stack.append(self.align)

    def pop_alignment(self):
        if self.align_stack:
            del self.align_stack[-1]
        if self.align_stack:
            self.align = align = self.align_stack[-1]
            self.writer.new_alignment(align)
        else:
            self.align = None
            self.writer.new_alignment(None)

    def push_font(self, (size, i, b, tt)):
        if self.softspace:
            self.hard_break = self.para_end = self.softspace = 0
            self.nospace = 1
            self.writer.send_flowing_data(' ')
        if self.font_stack:
            csize, ci, cb, ctt = self.font_stack[-1]
            if size is AS_IS: size = csize
            if i is AS_IS: i = ci
            if b is AS_IS: b = cb
            if tt is AS_IS: tt = ctt
        font = (size, i, b, tt)
        self.font_stack.append(font)
        self.writer.new_font(font)

    def pop_font(self):
        if self.font_stack:
            del self.font_stack[-1]
        if self.font_stack:
            font = self.font_stack[-1]
        else:
            font = None
        self.writer.new_font(font)

    def push_margin(self, margin):
        self.margin_stack.append(margin)
        fstack = filter(None, self.margin_stack)
        if not margin and fstack:
            margin = fstack[-1]
        self.writer.new_margin(margin, len(fstack))

    def pop_margin(self):
        if self.margin_stack:
            del self.margin_stack[-1]
        fstack = filter(None, self.margin_stack)
        if fstack:
            margin = fstack[-1]
        else:
            margin = None
        self.writer.new_margin(margin, len(fstack))

    def set_spacing(self, spacing):
        self.spacing = spacing
        self.writer.new_spacing(spacing)

    def push_style(self, *styles):
        if self.softspace:
            self.hard_break = self.para_end = self.softspace = 0
            self.nospace = 1
            self.writer.send_flowing_data(' ')
        for style in styles:
            self.style_stack.append(style)
        self.writer.new_styles(tuple(self.style_stack))

    def pop_style(self, n=1):
        del self.style_stack[-n:]
        self.writer.new_styles(tuple(self.style_stack))

    def assert_line_data(self, flag=1):
        self.nospace = self.hard_break = not flag
        self.para_end = self.parskip = self.have_label = 0


class NullWriter:
    """Minimal writer interface to use in testing & inheritance.

    A writer which only provides the interface definition; no actions are
    taken on any methods.  This should be the base class for all writers
    which do not need to inherit any implementation methods.

    """
    def __init__(self): pass
    def flush(self): pass
    def new_alignment(self, align): pass
    def new_font(self, font): pass
    def new_margin(self, margin, level): pass
    def new_spacing(self, spacing): pass
    def new_styles(self, styles): pass
    def send_paragraph(self, blankline): pass
    def send_line_break(self): pass
    def send_hor_rule(self, *args, **kw): pass
    def send_label_data(self, data): pass
    def send_flowing_data(self, data): pass
    def send_literal_data(self, data): pass


class AbstractWriter(NullWriter):
    """A writer which can be used in debugging formatters, but not much else.

    Each method simply announces itself by printing its name and
    arguments on standard output.

    """

    def new_alignment(self, align):
        print "new_alignment(%s)" % `align`

    def new_font(self, font):
        print "new_font(%s)" % `font`

    def new_margin(self, margin, level):
        print "new_margin(%s, %d)" % (`margin`, level)

    def new_spacing(self, spacing):
        print "new_spacing(%s)" % `spacing`

    def new_styles(self, styles):
        print "new_styles(%s)" % `styles`

    def send_paragraph(self, blankline):
        print "send_paragraph(%s)" % `blankline`

    def send_line_break(self):
        print "send_line_break()"

    def send_hor_rule(self, *args, **kw):
        print "send_hor_rule()"

    def send_label_data(self, data):
        print "send_label_data(%s)" % `data`

    def send_flowing_data(self, data):
        print "send_flowing_data(%s)" % `data`

    def send_literal_data(self, data):
        print "send_literal_data(%s)" % `data`


class DumbWriter(NullWriter):
    """Simple writer class which writes output on the file object passed in
    as the file parameter or, if file is omitted, on standard output.  The
    output is simply word-wrapped to the number of columns specified by
    the maxcol parameter.  This class is suitable for reflowing a sequence
    of paragraphs.

    """

    def __init__(self, file=None, maxcol=72):
        self.file = file or sys.stdout
        self.maxcol = maxcol
        NullWriter.__init__(self)
        self.reset()

    def reset(self):
        self.col = 0
        self.atbreak = 0

    def send_paragraph(self, blankline):
        self.file.write('\n'*blankline)
        self.col = 0
        self.atbreak = 0

    def send_line_break(self):
        self.file.write('\n')
        self.col = 0
        self.atbreak = 0

    def send_hor_rule(self, *args, **kw):
        self.file.write('\n')
        self.file.write('-'*self.maxcol)
        self.file.write('\n')
        self.col = 0
        self.atbreak = 0

    def send_literal_data(self, data):
        self.file.write(data)
        i = data.rfind('\n')
        if i >= 0:
            self.col = 0
            data = data[i+1:]
        data = data.expandtabs()
        self.col = self.col + len(data)
        self.atbreak = 0

    def send_flowing_data(self, data):
        if not data: return
        atbreak = self.atbreak or data[0].isspace()
        col = self.col
        maxcol = self.maxcol
        write = self.file.write
        for word in data.split():
            if atbreak:
                if col + len(word) >= maxcol:
                    write('\n')
                    col = 0
                else:
                    write(' ')
                    col = col + 1
            write(word)
            col = col + len(word)
            atbreak = 1
        self.col = col
        self.atbreak = data[-1].isspace()


def test(file = None):
    w = DumbWriter()
    f = AbstractFormatter(w)
    if file is not None:
        fp = open(file)
    elif sys.argv[1:]:
        fp = open(sys.argv[1])
    else:
        fp = sys.stdin
    while 1:
        line = fp.readline()
        if not line:
            break
        if line == '\n':
            f.end_paragraph(1)
        else:
            f.add_flowing_data(line)
    f.end_paragraph(0)


if __name__ == '__main__':
    test()
'''

c.importCommands.pythonUnitTest(p,s=s,showTree=False)
#@+node:ekr.20121011094154.3906: *5* TypeScript tests
@language python
#@+node:ekr.20121011094154.3911: *6* @test TypeScript class
s = '''

class Greeter {
    greeting: string;
    constructor (message: string) {
        this.greeting = message;
    }
    greet() {
        return "Hello, " + this.greeting;
    }
}

var greeter = new Greeter("world");

var button = document.createElement('button')
button.innerText = "Say Hello"
button.onclick = function() {
    alert(greeter.greet())
}

document.body.appendChild(button)

'''

c.importCommands.typeScriptUnitTest(p,s=s,showTree=False)
#@+node:ekr.20121011100210.4035: *6* @test TypeScript module
s = '''

module Sayings {
    export class Greeter {
        greeting: string;
        constructor (message: string) {
            this.greeting = message;
        }
        greet() {
            return "Hello, " + this.greeting;
        }
    }
}
var greeter = new Sayings.Greeter("world");

var button = document.createElement('button')
button.innerText = "Say Hello"
button.onclick = function() {
	alert(greeter.greet())
}

document.body.appendChild(button)


'''

c.importCommands.typeScriptUnitTest(p,s=s,showTree=False)
#@+node:ekr.20090529141856.4780: *5* xml tests
#@+node:ekr.20090529141856.4781: *6* @test xml 1
s = '''\
<html>
<head>
    <title>Bodystring</title>
</head>
<body class='bodystring'>
<div id='bodydisplay'></div>
</body>
</html>
'''
c.importCommands.xmlUnitTest(p,s=s,showTree=False)
#@+node:ekr.20111026105935.3966: *6* @test xml 2
s = '''\
<nodeA>
<nodeB/>
</nodeA>
'''


c.importCommands.xmlUnitTest(p,s=s,showTree=False)
#@+node:ekr.20120306173116.3933: *6* @test xml non-ascii tags
@first # -*- coding: utf-8 -*-

s = '''\
<:À.Ç>
<Ì>
<_.ÌÑ>
'''


c.importCommands.xmlUnitTest(p,s=s,showTree=False)
#@+node:ekr.20160410152100.1: *4* Tests of @auto-md
#@+node:ekr.20160410152100.2: *5* @test md-import-test
<< define s >>
if 0:
    # The preamble...
    g.cls()
    if c.isChanged(): c.save()
    # import leo
    import leo.core.leoImport as leoImport
    import leo.plugins.importers.linescanner as linescanner
    import leo.plugins.importers.markdown
    import leo.plugins.writers.markdown
    # Reload all.
    import imp
    imp.reload(leo.plugins.importers.linescanner)
    imp.reload(leo.plugins.importers.markdown)
    imp.reload(leo.plugins.writers.markdown)
    imp.reload(leoImport)
    markdown = leo.plugins.importers.markdown
    g.app.loadManager.createAllImporetersData()
    ic = leoImport.LeoImportCommands(c)
    # x = markdown.Markdown_Importer(ic, atAuto=False)
else:
    ic = c.importCommands  
try:
    ic.markdownUnitTest(p,s=s,showTree=True) # Must be true.
    table = (
        (1, 'Top'),
        (2, 'Section 1'),
        (2, 'Section 2'),
        (3, 'Section 2.1'),
        (4, 'Section 2.1.1'),
        (3, 'Section 2.2'),
        (2, 'Section 3'),
    )
    after = p.nodeAfterTree()
    root = p.lastChild()
    assert root.h.startswith('@@auto-m'), root.h
    p = root.firstChild()
    for n, h in table:
        n2 = p.level() - root.level()
        assert h == p.h, (h, p.h)
        assert n == n2, (n, n2, p.h)
        p.moveToThreadNext()
    assert p == after, p.h
finally:
    if 1:
        if root:
            root.doDelete()
        c.redraw()
#@+node:ekr.20160411034540.1: *6* << define s >> (md-import-test)
s = '''\
#Top
The top section

##Section 1
section 1, line 1
section 1, line 2

##Section 2
section 2, line 1

###Section 2.1
section 2.1, line 1

####Section 2.1.1
section 2.2.1 line 1
The next section is empty. It must not be deleted.

###Section 2.2

##Section 3
Section 3, line 1

'''
#@+node:ekr.20161202093709.1: *6* @@auto-markdown c:/leo.repo/leo-editor/leo/test/md-import-test
@others

Warning: this node is ignored when writing this file.

@language md
@tabwidth -4
#@+node:ekr.20161202093709.2: *7* !Declarations
#Top
The top section

#@+node:ekr.20161202093709.3: *8* Section 1
section 1, line 1
section 1, line 2

#@+node:ekr.20161202093709.4: *8* Section 2
section 2, line 1

#@+node:ekr.20161202093709.5: *9* Section 2.1
section 2.1, line 1

#@+node:ekr.20161202093709.6: *10* Section 2.1.1
section 2.2.1 line 1
The next section is empty. It must not be deleted.

#@+node:ekr.20161202093709.7: *9* Section 2.2

#@+node:ekr.20161202093709.8: *8* Section 3
Section 3, line 1

#@+node:ekr.20161204034142.19: *6* @@auto-markdown c:/leo.repo/leo-editor/leo/test/md-import-test
@others

Warning: this node is ignored when writing this file.

@language md
@tabwidth -4
#@+node:ekr.20161204034142.20: *7* Top
The top section

#@+node:ekr.20161204034142.21: *8* Section 1
section 1, line 1
section 1, line 2

#@+node:ekr.20161204034142.22: *8* Section 2
section 2, line 1

#@+node:ekr.20161204034142.23: *9* Section 2.1
section 2.1, line 1

#@+node:ekr.20161204034142.24: *10* Section 2.1.1
section 2.2.1 line 1
The next section is empty. It must not be deleted.

#@+node:ekr.20161204034142.25: *9* Section 2.2

#@+node:ekr.20161204034142.26: *8* Section 3
Section 3, line 1

#@+node:ekr.20161204034207.1: *6* @@auto-markdown c:/leo.repo/leo-editor/leo/test/md-import-test
@others

Warning: this node is ignored when writing this file.

@language md
@tabwidth -4
#@+node:ekr.20161204034207.2: *7* Top
The top section

#@+node:ekr.20161204034207.3: *8* Section 1
section 1, line 1
section 1, line 2

#@+node:ekr.20161204034207.4: *8* Section 2
section 2, line 1

#@+node:ekr.20161204034207.5: *9* Section 2.1
section 2.1, line 1

#@+node:ekr.20161204034207.6: *10* Section 2.1.1
section 2.2.1 line 1
The next section is empty. It must not be deleted.

#@+node:ekr.20161204034207.7: *9* Section 2.2

#@+node:ekr.20161204034207.8: *8* Section 3
Section 3, line 1

#@+node:ekr.20161204035451.19: *6* @@auto-markdown c:/leo.repo/leo-editor/leo/test/md-import-test
@others

Warning: this node is ignored when writing this file.

@language md
@tabwidth -4
#@+node:ekr.20161204035451.20: *7* Top
The top section

#@+node:ekr.20161204035451.21: *8* Section 1
section 1, line 1
section 1, line 2

#@+node:ekr.20161204035451.22: *8* Section 2
section 2, line 1

#@+node:ekr.20161204035451.23: *9* Section 2.1
section 2.1, line 1

#@+node:ekr.20161204035451.24: *10* Section 2.1.1
section 2.2.1 line 1
The next section is empty. It must not be deleted.

#@+node:ekr.20161204035451.25: *9* Section 2.2

#@+node:ekr.20161204035451.26: *8* Section 3
Section 3, line 1

#@+node:ekr.20161204041310.53: *6* @@auto-md c:/leo.repo/leo-editor/leo/test/md-import-test
@others

Warning: this node is ignored when writing this file.

@language md
@tabwidth -4
#@+node:ekr.20161204041310.54: *7* Top
The top section

#@+node:ekr.20161204041310.55: *8* Section 1
section 1, line 1
section 1, line 2

#@+node:ekr.20161204041310.56: *8* Section 2
section 2, line 1

#@+node:ekr.20161204041310.57: *9* Section 2.1
section 2.1, line 1

#@+node:ekr.20161204041310.58: *10* Section 2.1.1
section 2.2.1 line 1
The next section is empty. It must not be deleted.

#@+node:ekr.20161204041310.59: *9* Section 2.2

#@+node:ekr.20161204041310.60: *8* Section 3
Section 3, line 1

#@+node:ekr.20161204041358.103: *6* @@auto-md c:/leo.repo/leo-editor/leo/test/md-import-test
@others

Warning: this node is ignored when writing this file.

@language md
@tabwidth -4
#@+node:ekr.20161204041358.104: *7* Top
The top section

#@+node:ekr.20161204041358.105: *8* Section 1
section 1, line 1
section 1, line 2

#@+node:ekr.20161204041358.106: *8* Section 2
section 2, line 1

#@+node:ekr.20161204041358.107: *9* Section 2.1
section 2.1, line 1

#@+node:ekr.20161204041358.108: *10* Section 2.1.1
section 2.2.1 line 1
The next section is empty. It must not be deleted.

#@+node:ekr.20161204041358.109: *9* Section 2.2

#@+node:ekr.20161204041358.110: *8* Section 3
Section 3, line 1

#@+node:ekr.20161204041418.1: *6* @@auto-md c:/leo.repo/leo-editor/leo/test/md-import-test
@others

Warning: this node is ignored when writing this file.

@language md
@tabwidth -4
#@+node:ekr.20161204041418.2: *7* Top
The top section

#@+node:ekr.20161204041418.3: *8* Section 1
section 1, line 1
section 1, line 2

#@+node:ekr.20161204041418.4: *8* Section 2
section 2, line 1

#@+node:ekr.20161204041418.5: *9* Section 2.1
section 2.1, line 1

#@+node:ekr.20161204041418.6: *10* Section 2.1.1
section 2.2.1 line 1
The next section is empty. It must not be deleted.

#@+node:ekr.20161204041418.7: *9* Section 2.2

#@+node:ekr.20161204041418.8: *8* Section 3
Section 3, line 1

#@+node:ekr.20161204041645.103: *6* @@auto-md c:/leo.repo/leo-editor/leo/test/md-import-test
@others

Warning: this node is ignored when writing this file.

@language md
@tabwidth -4
#@+node:ekr.20161204041645.104: *7* Top
The top section

#@+node:ekr.20161204041645.105: *8* Section 1
section 1, line 1
section 1, line 2

#@+node:ekr.20161204041645.106: *8* Section 2
section 2, line 1

#@+node:ekr.20161204041645.107: *9* Section 2.1
section 2.1, line 1

#@+node:ekr.20161204041645.108: *10* Section 2.1.1
section 2.2.1 line 1
The next section is empty. It must not be deleted.

#@+node:ekr.20161204041645.109: *9* Section 2.2

#@+node:ekr.20161204041645.110: *8* Section 3
Section 3, line 1

#@+node:ekr.20161204041724.1: *6* @@auto-md c:/leo.repo/leo-editor/leo/test/md-import-test
@others

Warning: this node is ignored when writing this file.

@language md
@tabwidth -4
#@+node:ekr.20161204041724.2: *7* Top
The top section

#@+node:ekr.20161204041724.3: *8* Section 1
section 1, line 1
section 1, line 2

#@+node:ekr.20161204041724.4: *8* Section 2
section 2, line 1

#@+node:ekr.20161204041724.5: *9* Section 2.1
section 2.1, line 1

#@+node:ekr.20161204041724.6: *10* Section 2.1.1
section 2.2.1 line 1
The next section is empty. It must not be deleted.

#@+node:ekr.20161204041724.7: *9* Section 2.2

#@+node:ekr.20161204041724.8: *8* Section 3
Section 3, line 1

#@+node:ekr.20161204041800.1: *6* @@auto-md c:/leo.repo/leo-editor/leo/test/md-import-test
@others

Warning: this node is ignored when writing this file.

@language md
@tabwidth -4
#@+node:ekr.20161204041800.2: *7* Top
The top section

#@+node:ekr.20161204041800.3: *8* Section 1
section 1, line 1
section 1, line 2

#@+node:ekr.20161204041800.4: *8* Section 2
section 2, line 1

#@+node:ekr.20161204041800.5: *9* Section 2.1
section 2.1, line 1

#@+node:ekr.20161204041800.6: *10* Section 2.1.1
section 2.2.1 line 1
The next section is empty. It must not be deleted.

#@+node:ekr.20161204041800.7: *9* Section 2.2

#@+node:ekr.20161204041800.8: *8* Section 3
Section 3, line 1

#@+node:ekr.20161204042305.96: *6* @@auto-md c:/leo.repo/leo-editor/leo/test/md-import-test
@others

Warning: this node is ignored when writing this file.

@language md
@tabwidth -4
#@+node:ekr.20161204042305.97: *7* Top
The top section

#@+node:ekr.20161204042305.98: *8* Section 1
section 1, line 1
section 1, line 2

#@+node:ekr.20161204042305.99: *8* Section 2
section 2, line 1

#@+node:ekr.20161204042305.100: *9* Section 2.1
section 2.1, line 1

#@+node:ekr.20161204042305.101: *10* Section 2.1.1
section 2.2.1 line 1
The next section is empty. It must not be deleted.

#@+node:ekr.20161204042305.102: *9* Section 2.2

#@+node:ekr.20161204042305.103: *8* Section 3
Section 3, line 1

#@+node:ekr.20161204042719.4: *6* @@auto-md c:/leo.repo/leo-editor/leo/test/md-import-test
@others

Warning: this node is ignored when writing this file.

@language md
@tabwidth -4
#@+node:ekr.20161204042719.5: *7* Top
The top section

#@+node:ekr.20161204042719.6: *8* Section 1
section 1, line 1
section 1, line 2

#@+node:ekr.20161204042719.7: *8* Section 2
section 2, line 1

#@+node:ekr.20161204042719.8: *9* Section 2.1
section 2.1, line 1

#@+node:ekr.20161204042719.9: *10* Section 2.1.1
section 2.2.1 line 1
The next section is empty. It must not be deleted.

#@+node:ekr.20161204042719.10: *9* Section 2.2

#@+node:ekr.20161204042719.11: *8* Section 3
Section 3, line 1

#@+node:ekr.20161204042822.1: *6* @@auto-md c:/leo.repo/leo-editor/leo/test/md-import-test
@others

Warning: this node is ignored when writing this file.

@language md
@tabwidth -4
#@+node:ekr.20161204042822.2: *7* Top
The top section

#@+node:ekr.20161204042822.3: *8* Section 1
section 1, line 1
section 1, line 2

#@+node:ekr.20161204042822.4: *8* Section 2
section 2, line 1

#@+node:ekr.20161204042822.5: *9* Section 2.1
section 2.1, line 1

#@+node:ekr.20161204042822.6: *10* Section 2.1.1
section 2.2.1 line 1
The next section is empty. It must not be deleted.

#@+node:ekr.20161204042822.7: *9* Section 2.2

#@+node:ekr.20161204042822.8: *8* Section 3
Section 3, line 1

#@+node:ekr.20161204043017.19: *6* @@auto-md c:/leo.repo/leo-editor/leo/test/md-import-test
@others

Warning: this node is ignored when writing this file.

@language md
@tabwidth -4
#@+node:ekr.20161204043017.20: *7* Top
The top section

#@+node:ekr.20161204043017.21: *8* Section 1
section 1, line 1
section 1, line 2

#@+node:ekr.20161204043017.22: *8* Section 2
section 2, line 1

#@+node:ekr.20161204043017.23: *9* Section 2.1
section 2.1, line 1

#@+node:ekr.20161204043017.24: *10* Section 2.1.1
section 2.2.1 line 1
The next section is empty. It must not be deleted.

#@+node:ekr.20161204043017.25: *9* Section 2.2

#@+node:ekr.20161204043017.26: *8* Section 3
Section 3, line 1

#@+node:ekr.20161204043032.96: *6* @@auto-md c:/leo.repo/leo-editor/leo/test/md-import-test
@others

Warning: this node is ignored when writing this file.

@language md
@tabwidth -4
#@+node:ekr.20161204043032.97: *7* Top
The top section

#@+node:ekr.20161204043032.98: *8* Section 1
section 1, line 1
section 1, line 2

#@+node:ekr.20161204043032.99: *8* Section 2
section 2, line 1

#@+node:ekr.20161204043032.100: *9* Section 2.1
section 2.1, line 1

#@+node:ekr.20161204043032.101: *10* Section 2.1.1
section 2.2.1 line 1
The next section is empty. It must not be deleted.

#@+node:ekr.20161204043032.102: *9* Section 2.2

#@+node:ekr.20161204043032.103: *8* Section 3
Section 3, line 1

#@+node:ekr.20161204043346.4: *6* @@auto-md c:/leo.repo/leo-editor/leo/test/md-import-test
@others

Warning: this node is ignored when writing this file.

@language md
@tabwidth -4
#@+node:ekr.20161204043346.5: *7* Top
The top section

#@+node:ekr.20161204043346.6: *8* Section 1
section 1, line 1
section 1, line 2

#@+node:ekr.20161204043346.7: *8* Section 2
section 2, line 1

#@+node:ekr.20161204043346.8: *9* Section 2.1
section 2.1, line 1

#@+node:ekr.20161204043346.9: *10* Section 2.1.1
section 2.2.1 line 1
The next section is empty. It must not be deleted.

#@+node:ekr.20161204043346.10: *9* Section 2.2

#@+node:ekr.20161204043346.11: *8* Section 3
Section 3, line 1

#@+node:ekr.20160411033840.1: *5* @test md-import-test-rst-style
<< define s >>
if 0:
    # The preamble...
    g.cls()
    if c.isChanged(): c.save()
    # import leo
    import leo.core.leoImport as leoImport
    import leo.plugins.importers.linescanner as linescanner
    import leo.plugins.importers.markdown
    # import leo.plugins.writers.markdown
    # Reload all.
    import imp
    imp.reload(leo.plugins.importers.linescanner)
    imp.reload(leo.plugins.importers.markdown)
    # imp.reload(leo.plugins.writers.markdown)
    imp.reload(leoImport)
    markdown = leo.plugins.importers.markdown
    g.app.loadManager.createAllImporetersData()
    ic = leoImport.LeoImportCommands(c)
else:
    ic = c.importCommands  
try:
    ic.markdownUnitTest(p,s=s,showTree=True) # Must be True.
    table = (
        (1, 'Top'),
        (2, 'Section 1'),
        (2, 'Section 2'),
        (3, 'Section 2.1'),
        (4, 'Section 2.1.1'),
        (3, 'Section 2.2'),
        (2, 'Section 3'),
    )
    after = p.nodeAfterTree()
    root = p.lastChild()
    assert root.h.startswith('@@auto-m'), root.h
    p = root.firstChild()
    if 1:
        for n, h in table:
            n2 = p.level() - root.level()
            assert h == p.h, (h, p.h)
            assert n == n2, (n, n2, p.h)
            p.moveToThreadNext()
        assert p == after, p.h
finally:
    if 1:
        if root:
            root.doDelete()
        c.redraw()
#@+node:ekr.20161125230415.1: *6* << define s >> (md-import-test-rst-style)
s = '''\
Top
====

The top section

Section 1
---------

section 1, line 1
-- Not an underline
secttion 1, line 2

Section 2
---------

section 2, line 1

###Section 2.1

section 2.1, line 1

####Section 2.1.1

section 2.2.1 line 1

###Section 2.2
section 2.2, line 1.

Section 3
---------

section 3, line 1

'''
#@+node:ekr.20161202093319.1: *6* @@auto-markdown c:/leo.repo/leo-editor/leo/test/md-import-test-rst-style
@others

Warning: this node is ignored when writing this file.

@language md
@tabwidth -4
#@+node:ekr.20161202093319.2: *7* Top

The top section

#@+node:ekr.20161202093319.3: *8* Section 1

section 1, line 1
-- Not an underline
secttion 1, line 2

#@+node:ekr.20161202093319.4: *8* Section 2

section 2, line 1

#@+node:ekr.20161202093319.5: *9* Section 2.1

section 2.1, line 1

#@+node:ekr.20161202093319.6: *10* Section 2.1.1

section 2.2.1 line 1

#@+node:ekr.20161202093319.7: *9* Section 2.2
section 2.2, line 1.

#@+node:ekr.20161202093319.8: *8* Section 3

section 3, line 1

#@+node:ekr.20161202093322.9: *6* @@auto-markdown c:/leo.repo/leo-editor/leo/test/md-import-test-rst-style
@others

Warning: this node is ignored when writing this file.

@language md
@tabwidth -4
#@+node:ekr.20161202093322.10: *7* Top

The top section

#@+node:ekr.20161202093322.11: *8* Section 1

section 1, line 1
-- Not an underline
secttion 1, line 2

#@+node:ekr.20161202093322.12: *8* Section 2

section 2, line 1

#@+node:ekr.20161202093322.13: *9* Section 2.1

section 2.1, line 1

#@+node:ekr.20161202093322.14: *10* Section 2.1.1

section 2.2.1 line 1

#@+node:ekr.20161202093322.15: *9* Section 2.2
section 2.2, line 1.

#@+node:ekr.20161202093322.16: *8* Section 3

section 3, line 1

#@+node:ekr.20161202093409.1: *6* @@auto-markdown c:/leo.repo/leo-editor/leo/test/md-import-test-rst-style
@others

Warning: this node is ignored when writing this file.

@language md
@tabwidth -4
#@+node:ekr.20161202093409.2: *7* Top

The top section

#@+node:ekr.20161202093409.3: *8* Section 1

section 1, line 1
-- Not an underline
secttion 1, line 2

#@+node:ekr.20161202093409.4: *8* Section 2

section 2, line 1

#@+node:ekr.20161202093409.5: *9* Section 2.1

section 2.1, line 1

#@+node:ekr.20161202093409.6: *10* Section 2.1.1

section 2.2.1 line 1

#@+node:ekr.20161202093409.7: *9* Section 2.2
section 2.2, line 1.

#@+node:ekr.20161202093409.8: *8* Section 3

section 3, line 1

#@+node:ekr.20161202093410.1: *6* @@auto-markdown c:/leo.repo/leo-editor/leo/test/md-import-test-rst-style
@others

Warning: this node is ignored when writing this file.

@language md
@tabwidth -4
#@+node:ekr.20161202093410.2: *7* Top

The top section

#@+node:ekr.20161202093410.3: *8* Section 1

section 1, line 1
-- Not an underline
secttion 1, line 2

#@+node:ekr.20161202093410.4: *8* Section 2

section 2, line 1

#@+node:ekr.20161202093410.5: *9* Section 2.1

section 2.1, line 1

#@+node:ekr.20161202093410.6: *10* Section 2.1.1

section 2.2.1 line 1

#@+node:ekr.20161202093410.7: *9* Section 2.2
section 2.2, line 1.

#@+node:ekr.20161202093410.8: *8* Section 3

section 3, line 1

#@+node:ekr.20161202093509.22: *6* @@auto-markdown c:/leo.repo/leo-editor/leo/test/md-import-test-rst-style
@others

Warning: this node is ignored when writing this file.

@language md
@tabwidth -4
#@+node:ekr.20161202093509.23: *7* Top

The top section

#@+node:ekr.20161202093509.24: *8* Section 1

section 1, line 1
-- Not an underline
secttion 1, line 2

#@+node:ekr.20161202093509.25: *8* Section 2

section 2, line 1

#@+node:ekr.20161202093509.26: *9* Section 2.1

section 2.1, line 1

#@+node:ekr.20161202093509.27: *10* Section 2.1.1

section 2.2.1 line 1

#@+node:ekr.20161202093509.28: *9* Section 2.2
section 2.2, line 1.

#@+node:ekr.20161202093509.29: *8* Section 3

section 3, line 1

#@+node:ekr.20161204034142.27: *6* @@auto-markdown c:/leo.repo/leo-editor/leo/test/md-import-test-rst-style
@others

Warning: this node is ignored when writing this file.

@language md
@tabwidth -4
#@+node:ekr.20161204034142.28: *7* Top

The top section

#@+node:ekr.20161204034142.29: *8* Section 1

section 1, line 1
-- Not an underline
secttion 1, line 2

#@+node:ekr.20161204034142.30: *8* Section 2

section 2, line 1

#@+node:ekr.20161204034142.31: *9* Section 2.1

section 2.1, line 1

#@+node:ekr.20161204034142.32: *10* Section 2.1.1

section 2.2.1 line 1

#@+node:ekr.20161204034142.33: *9* Section 2.2
section 2.2, line 1.

#@+node:ekr.20161204034142.34: *8* Section 3

section 3, line 1

#@+node:ekr.20161204034207.9: *6* @@auto-markdown c:/leo.repo/leo-editor/leo/test/md-import-test-rst-style
@others

Warning: this node is ignored when writing this file.

@language md
@tabwidth -4
#@+node:ekr.20161204034207.10: *7* Top

The top section

#@+node:ekr.20161204034207.11: *8* Section 1

section 1, line 1
-- Not an underline
secttion 1, line 2

#@+node:ekr.20161204034207.12: *8* Section 2

section 2, line 1

#@+node:ekr.20161204034207.13: *9* Section 2.1

section 2.1, line 1

#@+node:ekr.20161204034207.14: *10* Section 2.1.1

section 2.2.1 line 1

#@+node:ekr.20161204034207.15: *9* Section 2.2
section 2.2, line 1.

#@+node:ekr.20161204034207.16: *8* Section 3

section 3, line 1

#@+node:ekr.20161204035451.27: *6* @@auto-markdown c:/leo.repo/leo-editor/leo/test/md-import-test-rst-style
@others

Warning: this node is ignored when writing this file.

@language md
@tabwidth -4
#@+node:ekr.20161204035451.28: *7* Top

The top section

#@+node:ekr.20161204035451.29: *8* Section 1

section 1, line 1
-- Not an underline
secttion 1, line 2

#@+node:ekr.20161204035451.30: *8* Section 2

section 2, line 1

#@+node:ekr.20161204035451.31: *9* Section 2.1

section 2.1, line 1

#@+node:ekr.20161204035451.32: *10* Section 2.1.1

section 2.2.1 line 1

#@+node:ekr.20161204035451.33: *9* Section 2.2
section 2.2, line 1.

#@+node:ekr.20161204035451.34: *8* Section 3

section 3, line 1

#@+node:ekr.20161204041310.61: *6* @@auto-md c:/leo.repo/leo-editor/leo/test/md-import-test-rst-style
@others

Warning: this node is ignored when writing this file.

@language md
@tabwidth -4
#@+node:ekr.20161204041310.62: *7* Top

The top section

#@+node:ekr.20161204041310.63: *8* Section 1

section 1, line 1
-- Not an underline
secttion 1, line 2

#@+node:ekr.20161204041310.64: *8* Section 2

section 2, line 1

#@+node:ekr.20161204041310.65: *9* Section 2.1

section 2.1, line 1

#@+node:ekr.20161204041310.66: *10* Section 2.1.1

section 2.2.1 line 1

#@+node:ekr.20161204041310.67: *9* Section 2.2
section 2.2, line 1.

#@+node:ekr.20161204041310.68: *8* Section 3

section 3, line 1

#@+node:ekr.20161204041359.1: *6* @@auto-md c:/leo.repo/leo-editor/leo/test/md-import-test-rst-style
@others

Warning: this node is ignored when writing this file.

@language md
@tabwidth -4
#@+node:ekr.20161204041359.2: *7* Top

The top section

#@+node:ekr.20161204041359.3: *8* Section 1

section 1, line 1
-- Not an underline
secttion 1, line 2

#@+node:ekr.20161204041359.4: *8* Section 2

section 2, line 1

#@+node:ekr.20161204041359.5: *9* Section 2.1

section 2.1, line 1

#@+node:ekr.20161204041359.6: *10* Section 2.1.1

section 2.2.1 line 1

#@+node:ekr.20161204041359.7: *9* Section 2.2
section 2.2, line 1.

#@+node:ekr.20161204041359.8: *8* Section 3

section 3, line 1

#@+node:ekr.20161204041418.9: *6* @@auto-md c:/leo.repo/leo-editor/leo/test/md-import-test-rst-style
@others

Warning: this node is ignored when writing this file.

@language md
@tabwidth -4
#@+node:ekr.20161204041418.10: *7* Top

The top section

#@+node:ekr.20161204041418.11: *8* Section 1

section 1, line 1
-- Not an underline
secttion 1, line 2

#@+node:ekr.20161204041418.12: *8* Section 2

section 2, line 1

#@+node:ekr.20161204041418.13: *9* Section 2.1

section 2.1, line 1

#@+node:ekr.20161204041418.14: *10* Section 2.1.1

section 2.2.1 line 1

#@+node:ekr.20161204041418.15: *9* Section 2.2
section 2.2, line 1.

#@+node:ekr.20161204041418.16: *8* Section 3

section 3, line 1

#@+node:ekr.20161204041646.1: *6* @@auto-md c:/leo.repo/leo-editor/leo/test/md-import-test-rst-style
@others

Warning: this node is ignored when writing this file.

@language md
@tabwidth -4
#@+node:ekr.20161204041646.2: *7* Top

The top section

#@+node:ekr.20161204041646.3: *8* Section 1

section 1, line 1
-- Not an underline
secttion 1, line 2

#@+node:ekr.20161204041646.4: *8* Section 2

section 2, line 1

#@+node:ekr.20161204041646.5: *9* Section 2.1

section 2.1, line 1

#@+node:ekr.20161204041646.6: *10* Section 2.1.1

section 2.2.1 line 1

#@+node:ekr.20161204041646.7: *9* Section 2.2
section 2.2, line 1.

#@+node:ekr.20161204041646.8: *8* Section 3

section 3, line 1

#@+node:ekr.20161204041724.9: *6* @@auto-md c:/leo.repo/leo-editor/leo/test/md-import-test-rst-style
@others

Warning: this node is ignored when writing this file.

@language md
@tabwidth -4
#@+node:ekr.20161204041724.10: *7* Top

The top section

#@+node:ekr.20161204041724.11: *8* Section 1

section 1, line 1
-- Not an underline
secttion 1, line 2

#@+node:ekr.20161204041724.12: *8* Section 2

section 2, line 1

#@+node:ekr.20161204041724.13: *9* Section 2.1

section 2.1, line 1

#@+node:ekr.20161204041724.14: *10* Section 2.1.1

section 2.2.1 line 1

#@+node:ekr.20161204041724.15: *9* Section 2.2
section 2.2, line 1.

#@+node:ekr.20161204041724.16: *8* Section 3

section 3, line 1

#@+node:ekr.20161204041800.9: *6* @@auto-md c:/leo.repo/leo-editor/leo/test/md-import-test-rst-style
@others

Warning: this node is ignored when writing this file.

@language md
@tabwidth -4
#@+node:ekr.20161204041800.10: *7* Top

The top section

#@+node:ekr.20161204041800.11: *8* Section 1

section 1, line 1
-- Not an underline
secttion 1, line 2

#@+node:ekr.20161204041800.12: *8* Section 2

section 2, line 1

#@+node:ekr.20161204041800.13: *9* Section 2.1

section 2.1, line 1

#@+node:ekr.20161204041800.14: *10* Section 2.1.1

section 2.2.1 line 1

#@+node:ekr.20161204041800.15: *9* Section 2.2
section 2.2, line 1.

#@+node:ekr.20161204041800.16: *8* Section 3

section 3, line 1

#@+node:ekr.20161204042305.104: *6* @@auto-md c:/leo.repo/leo-editor/leo/test/md-import-test-rst-style
@others

Warning: this node is ignored when writing this file.

@language md
@tabwidth -4
#@+node:ekr.20161204042305.105: *7* Top

The top section

#@+node:ekr.20161204042305.106: *8* Section 1

section 1, line 1
-- Not an underline
secttion 1, line 2

#@+node:ekr.20161204042305.107: *8* Section 2

section 2, line 1

#@+node:ekr.20161204042305.108: *9* Section 2.1

section 2.1, line 1

#@+node:ekr.20161204042305.109: *10* Section 2.1.1

section 2.2.1 line 1

#@+node:ekr.20161204042305.110: *9* Section 2.2
section 2.2, line 1.

#@+node:ekr.20161204042305.111: *8* Section 3

section 3, line 1

#@+node:ekr.20161204042719.12: *6* @@auto-md c:/leo.repo/leo-editor/leo/test/md-import-test-rst-style
@others

Warning: this node is ignored when writing this file.

@language md
@tabwidth -4
#@+node:ekr.20161204042719.13: *7* Top

The top section

#@+node:ekr.20161204042719.14: *8* Section 1

section 1, line 1
-- Not an underline
secttion 1, line 2

#@+node:ekr.20161204042719.15: *8* Section 2

section 2, line 1

#@+node:ekr.20161204042719.16: *9* Section 2.1

section 2.1, line 1

#@+node:ekr.20161204042719.17: *10* Section 2.1.1

section 2.2.1 line 1

#@+node:ekr.20161204042719.18: *9* Section 2.2
section 2.2, line 1.

#@+node:ekr.20161204042719.19: *8* Section 3

section 3, line 1

#@+node:ekr.20161204042822.9: *6* @@auto-md c:/leo.repo/leo-editor/leo/test/md-import-test-rst-style
@others

Warning: this node is ignored when writing this file.

@language md
@tabwidth -4
#@+node:ekr.20161204042822.10: *7* Top

The top section

#@+node:ekr.20161204042822.11: *8* Section 1

section 1, line 1
-- Not an underline
secttion 1, line 2

#@+node:ekr.20161204042822.12: *8* Section 2

section 2, line 1

#@+node:ekr.20161204042822.13: *9* Section 2.1

section 2.1, line 1

#@+node:ekr.20161204042822.14: *10* Section 2.1.1

section 2.2.1 line 1

#@+node:ekr.20161204042822.15: *9* Section 2.2
section 2.2, line 1.

#@+node:ekr.20161204042822.16: *8* Section 3

section 3, line 1

#@+node:ekr.20161204043017.27: *6* @@auto-md c:/leo.repo/leo-editor/leo/test/md-import-test-rst-style
@others

Warning: this node is ignored when writing this file.

@language md
@tabwidth -4
#@+node:ekr.20161204043017.28: *7* Top

The top section

#@+node:ekr.20161204043017.29: *8* Section 1

section 1, line 1
-- Not an underline
secttion 1, line 2

#@+node:ekr.20161204043017.30: *8* Section 2

section 2, line 1

#@+node:ekr.20161204043017.31: *9* Section 2.1

section 2.1, line 1

#@+node:ekr.20161204043017.32: *10* Section 2.1.1

section 2.2.1 line 1

#@+node:ekr.20161204043017.33: *9* Section 2.2
section 2.2, line 1.

#@+node:ekr.20161204043017.34: *8* Section 3

section 3, line 1

#@+node:ekr.20161204043032.104: *6* @@auto-md c:/leo.repo/leo-editor/leo/test/md-import-test-rst-style
@others

Warning: this node is ignored when writing this file.

@language md
@tabwidth -4
#@+node:ekr.20161204043032.105: *7* Top

The top section

#@+node:ekr.20161204043032.106: *8* Section 1

section 1, line 1
-- Not an underline
secttion 1, line 2

#@+node:ekr.20161204043032.107: *8* Section 2

section 2, line 1

#@+node:ekr.20161204043032.108: *9* Section 2.1

section 2.1, line 1

#@+node:ekr.20161204043032.109: *10* Section 2.1.1

section 2.2.1 line 1

#@+node:ekr.20161204043032.110: *9* Section 2.2
section 2.2, line 1.

#@+node:ekr.20161204043032.111: *8* Section 3

section 3, line 1

#@+node:ekr.20161204043346.12: *6* @@auto-md c:/leo.repo/leo-editor/leo/test/md-import-test-rst-style
@others

Warning: this node is ignored when writing this file.

@language md
@tabwidth -4
#@+node:ekr.20161204043346.13: *7* Top

The top section

#@+node:ekr.20161204043346.14: *8* Section 1

section 1, line 1
-- Not an underline
secttion 1, line 2

#@+node:ekr.20161204043346.15: *8* Section 2

section 2, line 1

#@+node:ekr.20161204043346.16: *9* Section 2.1

section 2.1, line 1

#@+node:ekr.20161204043346.17: *10* Section 2.1.1

section 2.2.1 line 1

#@+node:ekr.20161204043346.18: *9* Section 2.2
section 2.2, line 1.

#@+node:ekr.20161204043346.19: *8* Section 3

section 3, line 1

#@+node:ekr.20161125134815.1: *5* @test markdown importer-basic
if 0:
    # The preamble...
    g.cls()
    if c.isChanged(): c.save()
    # import leo
    import leo.core.leoImport as leoImport
    import leo.plugins.importers.linescanner as linescanner
    import leo.plugins.importers.markdown
    # import leo.plugins.writers.markdown
    # Reload all.
    import imp
    imp.reload(leo.plugins.importers.linescanner)
    imp.reload(leo.plugins.importers.markdown)
    # imp.reload(leo.plugins.writers.markdown)
    imp.reload(leoImport)
    markdown = leo.plugins.importers.markdown
    g.app.loadManager.createAllImporetersData()
    ic = leoImport.LeoImportCommands(c)
else:
    ic = c.importCommands  
# insert test for markdown here.
s = '''\
Decl line.
#Header

After header text

##Subheader

Not an underline

----------------

After subheader text

#Last header: no text
'''
table = (
    '!Declarations',
    'Header',
        'Subheader',
        'Last header: no text',
)
try:
    ic.markdownUnitTest(p,s=s,showTree=True)
    if 1:
        root = c.p.lastChild()
        assert root.h.startswith('@@auto-m'), root.h
        p2 = root.firstChild()
        for h in table:
            assert p2.h == h, (p2.h, h)
            p2.moveToThreadNext()
        assert not root.isAncestorOf(p2), p2.h # Extra nodes
finally:
    if 1:
        p.deleteAllChildren()
        c.redraw()
#@+node:ekr.20161126111517.1: *5* @test markdown importer-implicit section
if 0:
    # The preamble...
    g.cls()
    if c.isChanged(): c.save()
    # import leo
    import leo.core.leoImport as leoImport
    import leo.plugins.importers.linescanner as linescanner
    import leo.plugins.importers.markdown
    # import leo.plugins.writers.markdown
    # Reload all.
    import imp
    imp.reload(leo.plugins.importers.linescanner)
    imp.reload(leo.plugins.importers.markdown)
    # imp.reload(leo.plugins.writers.markdown)
    imp.reload(leoImport)
    markdown = leo.plugins.importers.markdown
    g.app.loadManager.createAllImporetersData()
    ic = leoImport.LeoImportCommands(c)
else:
    ic = c.importCommands  
# insert test for markdown here.
s = '''\
Decl line.
#Header

After header text

##Subheader

Not an underline

----------------

This *should* be a section
==========================

After subheader text

#Last header: no text
'''
table = (
    '!Declarations',
    'Header',
        'Subheader',
            'This *should* be a section',
        'Last header: no text',
)
try:
    g.app.suppressImportChecks = True
        # Required, because the implicit underlining *must*
        # cause the perfect-import test to fail!
    ic.markdownUnitTest(p,s=s,showTree=True)
    if 1:
        root = c.p.lastChild()
        assert root.h.startswith('@@auto-m'), root.h
        p2 = root.firstChild()
        for h in table:
            assert p2.h == h, (p2.h, h)
            p2.moveToThreadNext()
        assert not root.isAncestorOf(p2), p2.h # Extra nodes
finally:
    g.app.suppressImportChecks = False
        # Not needed: done in Importer.check
    if 1:
        p.deleteAllChildren()
        c.redraw()
#@+node:ekr.20161216141315.1: *5* @test markdown importer-@@-section-name
if 0:
    # The preamble...
    g.cls()
    if c.isChanged(): c.save()
    # import leo
    import leo.core.leoImport as leoImport
    import leo.plugins.importers.linescanner as linescanner
    import leo.plugins.importers.markdown
    # import leo.plugins.writers.markdown
    # Reload all.
    import imp
    imp.reload(leo.plugins.importers.linescanner)
    imp.reload(leo.plugins.importers.markdown)
    # imp.reload(leo.plugins.writers.markdown)
    imp.reload(leoImport)
    markdown = leo.plugins.importers.markdown
    g.app.loadManager.createAllImporetersData()
    ic = leoImport.LeoImportCommands(c)
else:
    ic = c.importCommands  
# insert test for markdown here.
s = '''\
Decl line.

#@verbatim
#@@ Header

After header text

##@@Subheader

Not an underline

----------------

This *should* be a section
==========================

After subheader text

#Last header: no text
'''
table = (
    '!Declarations',
    '@verbatim', # This is an artifact of the unit test.
    '@@ Header',
        '@@Subheader',
            'This *should* be a section',
        'Last header: no text',
)
try:
    g.app.suppressImportChecks = True
        # Required, because the implicit underlining *must*
        # cause the perfect-import test to fail!
    ic.markdownUnitTest(p,s=s,showTree=True)
    if 1:
        root = c.p.lastChild()
        assert root.h.startswith('@@auto-m'), root.h
        p2 = root.firstChild()
        for h in table:
            assert p2.h == h, (p2.h, h)
            p2.moveToThreadNext()
        assert not root.isAncestorOf(p2), p2.h # Extra nodes
finally:
    g.app.suppressImportChecks = False
        # Not needed: done in Importer.check
    if 1:
        p.deleteAllChildren()
        c.redraw()
#@+node:ekr.20161127181028.1: *5* @test markdown github syntax
@first # -*- coding: utf-8 -*-
    # Required (Python 2 only) because test contains ```.
if 0:
    # The preamble...
    g.cls()
    if c.isChanged(): c.save()
    # import leo
    import leo.core.leoImport as leoImport
    import leo.plugins.importers.linescanner as linescanner
    import leo.plugins.importers.markdown
    # import leo.plugins.writers.markdown
    # Reload all.
    import imp
    imp.reload(leo.plugins.importers.linescanner)
    imp.reload(leo.plugins.importers.markdown)
    # imp.reload(leo.plugins.writers.markdown)
    imp.reload(leoImport)
    markdown = leo.plugins.importers.markdown
    g.app.loadManager.createAllImporetersData()
    ic = leoImport.LeoImportCommands(c)
else:
    ic = c.importCommands  
# insert test for markdown here.
s = '''\
Decl line.
#Header

`​``python
loads.init = {
    Chloride: 11.5,
    TotalP: 0.002,
}
`​``
#Last header
'''
table = (
    '!Declarations',
    'Header',
    'Last header',
)
try:
    ic.markdownUnitTest(p,s=s,showTree=True)
    if 1:
        root = c.p.lastChild()
        assert root.h.startswith('@@'), root.h
        p2 = root.firstChild()
        for h in table:
            assert p2.h == h, (p2.h, h)
            p2.moveToThreadNext()
        assert not root.isAncestorOf(p2), p2.h # Extra nodes
finally:
    if 1:
        p.deleteAllChildren()
        c.redraw()
#@+node:ekr.20090529141856.4784: *4* Tests of @auto-rst
#@+node:ekr.20090529141856.4785: *5* @test rST import test
if 0: # Preamble
    g.cls()
    if c.isChanged(): c.save()
    import leo.core.leoImport as leoImport
    import leo.plugins.importers.linescanner as linescanner
    import leo.plugins.importers.leo_rst
    import imp
    imp.reload(leo.plugins.importers.linescanner)
    imp.reload(leo.plugins.importers.leo_rst)
    imp.reload(leoImport)
    g.app.loadManager.createAllImporetersData()
    ic = leoImport.LeoImportCommands(c)
else:
    ic = c.importCommands

s = '''\
.. toc

====
top
====

The top section

section 1
---------

section 1, line 1
--
section 1, line 2

section 2
---------

section 2, line 1

section 2.1
~~~~~~~~~~~

section 2.1, line 1

section 2.1.1
.............

section 2.2.1 line 1

section 3
---------

section 3, line 1

section 3.1.1
.............

section 3.1.1, line 1
'''
table = (
    '!Dummy chapter',
    'top',
    'section 1',
    'section 2',
    'section 2.1',
    'section 2.1.1',
    'section 3',
    'placeholder',
    'section 3.1.1',
)
try:
    ic.rstUnitTest(p,s=s,showTree=True)
    if 1:
        root = c.p.lastChild()
        assert root.h.startswith('@@'), root.h
        p2 = root.firstChild()
        for h in table:
            assert p2.h == h, (p2.h, h)
            p2.moveToThreadNext()
        assert not root.isAncestorOf(p2), p2.h # Extra nodes
finally:
    if 1:
        p.deleteAllChildren()
    c.redraw()
#@+node:ekr.20140725132959.4593: *5* @test rST import test: simple
s = '''\
.. toc

.. The section name contains trailing whitespace.

=======
Chapter 
=======

The top chapter.
'''
table = (
    "!Dummy chapter",
    "Chapter",
)
try:
    c.importCommands.rstUnitTest(p,s=s,showTree=True)
    if 1:
        root = c.p.lastChild()
        assert root.h.startswith('@@'), root.h
        p2 = root.firstChild()
        for h in table:
            assert p2.h == h, (p2.h, h)
            p2.moveToThreadNext()
        assert not root.isAncestorOf(p2), p2.h # Extra nodes
finally:
    if 1:
        p.deleteAllChildren()
    c.redraw()
#@+node:ekr.20090529141856.4786: *5* @test rST import test: no double-underlines
if 0: # Preamble
    g.cls()
    if c.isChanged(): c.save()
    import leo.core.leoImport as leoImport
    import leo.plugins.importers.linescanner as linescanner
    import leo.plugins.importers.leo_rst
    import imp
    imp.reload(leo.plugins.importers.linescanner)
    imp.reload(leo.plugins.importers.leo_rst)
    imp.reload(leoImport)
    g.app.loadManager.createAllImporetersData()
    ic = leoImport.LeoImportCommands(c)
else:
    ic = c.importCommands

s = '''\
.. toc

top
====

The top section

section 1
---------

section 1, line 1
--
section 1, line 2

section 2
---------

section 2, line 1

section 2.1
~~~~~~~~~~~

section 2.1, line 1

section 2.1.1
.............

section 2.2.1 line 1

section 3
---------

section 3, line 1

section 3.1.1
.............

section 3.1.1, line 1
'''
table = (
    '!Dummy chapter',
    'top',
    'section 1',
    'section 2',
    'section 2.1',
    'section 2.1.1',
    'section 3',
    'placeholder',
    'section 3.1.1',
)
try:
    ic.rstUnitTest(p,s=s,showTree=True)
    if 1:
        root = c.p.lastChild()
        assert root.h.startswith('@@'), root.h
        p2 = root.firstChild()
        for h in table:
            assert p2.h == h, (p2.h, h)
            p2.moveToThreadNext()
        assert not root.isAncestorOf(p2), p2.h # Extra nodes
finally:
    if 1:
        p.deleteAllChildren()
    c.redraw()
#@+node:ekr.20090529141856.4787: *5* @test rST import test: long underlines
if 0: # Preamble
    g.cls()
    if c.isChanged(): c.save()
    import leo.core.leoImport as leoImport
    import leo.plugins.importers.linescanner as linescanner
    import leo.plugins.importers.leo_rst
    import imp
    imp.reload(leo.plugins.importers.linescanner)
    imp.reload(leo.plugins.importers.leo_rst)
    imp.reload(leoImport)
    g.app.loadManager.createAllImporetersData()
    ic = leoImport.LeoImportCommands(c)
else:
    ic = c.importCommands

s = '''\
.. toc

top
-------------

The top section
'''
table = (
    '!Dummy chapter',
    'top',
)
try:
    ic.rstUnitTest(p,s=s,showTree=True)
    if 1:
        root = c.p.lastChild()
        assert root.h.startswith('@@'), root.h
        p2 = root.firstChild()
        for h in table:
            assert p2.h == h, (p2.h, h)
            p2.moveToThreadNext()
        assert not root.isAncestorOf(p2), p2.h # Extra nodes
finally:
    if 1:
        p.deleteAllChildren()
    c.redraw()
#@+node:ekr.20090529141856.4788: *5* @test rST import test: long overlines
if 0: # Preamble
    g.cls()
    if c.isChanged(): c.save()
    import leo.core.leoImport as leoImport
    import leo.plugins.importers.linescanner as linescanner
    import leo.plugins.importers.leo_rst
    import imp
    imp.reload(leo.plugins.importers.linescanner)
    imp.reload(leo.plugins.importers.leo_rst)
    imp.reload(leoImport)
    g.app.loadManager.createAllImporetersData()
    ic = leoImport.LeoImportCommands(c)
else:
    ic = c.importCommands

s = '''\
.. toc

======
top
======

The top section
'''
table = (
    "!Dummy chapter",
    "top",
)
try:
    ic.rstUnitTest(p,s=s,showTree=True)
    if 1:
        root = c.p.lastChild()
        assert root.h.startswith('@@'), root.h
        p2 = root.firstChild()
        for h in table:
            assert p2.h == h, (p2.h, h)
            p2.moveToThreadNext()
        assert not root.isAncestorOf(p2), p2.h # Extra nodes
finally:
    if 1:
        p.deleteAllChildren()
    c.redraw()
#@+node:ekr.20090529141856.4789: *5* @test rST import test: trailing whitespace
s = '''\
.. toc

.. The section name contains trailing whitespace.

======
top 
======

The top section.
'''
table = (
    "!Dummy chapter",
    "top",
)
try:
    c.importCommands.rstUnitTest(p,s=s,showTree=True)
    if 1:
        root = c.p.lastChild()
        assert root.h.startswith('@@'), root.h
        p2 = root.firstChild()
        for h in table:
            assert p2.h == h, (p2.h, h)
            p2.moveToThreadNext()
        assert not root.isAncestorOf(p2), p2.h # Extra nodes
finally:
    if 1:
        p.deleteAllChildren()
    c.redraw()
#@+node:ekr.20161129104243.1: *5* @test leo_rst
if 0:
    # The preamble...
    # g.cls()
    if c.isChanged(): c.save()
    import leo
    import leo.core.leoImport as leoImport
    import leo.plugins.importers.linescanner as linescanner
    import leo.plugins.importers.leo_rst as leo_rst
    # Reload all.
    import imp
    imp.reload(leo.plugins.importers.linescanner)
    imp.reload(leo.plugins.importers.leo_rst)
    imp.reload(leoImport)
    g.app.loadManager.createAllImporetersData()
    ic = leoImport.LeoImportCommands(c)
else:
    ic = c.importCommands

# Notes:
# All heading must be followed by an empty line.
### g.app.suppressImportChecks = True
s = '''\
  #########
Chapter 1
  #########

It was a dark and stormy night.
section 1
+++++++++

Sec 1.
section 2
+++++++++

Sec 2.
'''
table = (
    '!Dummy chapter',
    'section 1',
    'section 2',
)
try:
    ic.rstUnitTest(p,s=s,showTree=True)
    if 1:
        root = c.p.lastChild()
        assert root.h.startswith('@@'), root.h
        p2 = root.firstChild()
        for h in table:
            assert p2.h == h, (p2.h, h)
            p2.moveToThreadNext()
        assert not root.isAncestorOf(p2), p2.h # Extra nodes
finally:
    if 1:
        p.deleteAllChildren()
        c.redraw()
#@+node:ekr.20140724220921.5199: *4* Tests of individual methods
#@+node:ekr.20111214100515.3921: *5* @@@test ic.createOutline: at-auto with lines that look like section references
# Disabled: this now fails *regardless* of python.v2 switch

ic = c.importCommands

def setup(p):
    while p.hasChildren():
        p.firstChild().doDelete()

fn = g.os_path_finalize_join(g.app.loadDir,'..','test','unittest','at-auto-section-ref-test.py')
# fn = r'c:\Users\edreamleo\at-auto-test.py'
assert g.os_path_exists(fn),fn

try:
    setup(p)
    child = p.insertAsNthChild(0)
    child.h = 'child'
    assert child

    ic.errors = 0
    ic.createOutline (fn,parent=child,atAuto=True,atShadow=False,s=None,ext=None)
    assert ic.errors == 0
finally:
    setup(p)
    c.redraw(p)
#@+node:ekr.20140206132559.4567: *5* @@@test ic.parse-body
tm = c.testManager
before   = g.findNodeInTree(c,p,'before')
expected = g.findNodeInTree(c,p,'expected')
assert before,expected
try:
    c.selectPosition(before)
    before.h = 'expected' # To make the compare work.
    c.importCommands.parse_body(before)
    # compare tree.
    assert tm.compareOutlines(before,expected,compareHeadlines=True,tag='',report=True)
    c.undoer.undo()
finally:
    before.h = 'before'
    c.redraw()
#@+node:ekr.20150919073819.1: *6* copy
class aClass:
    def __init__(self):
        pass
    def spam(self):
        pass
bClass = aClass
#@+node:ekr.20140206132559.4560: *6* before
@others
#@+node:ekr.20161112061414.1: *7* class aClass
class aClass:
    @others
#@+node:ekr.20161112061414.2: *8* __init__
def __init__(self):
    pass
#@+node:ekr.20161112061414.3: *8* spam
def spam(self):
    pass
#@+node:ekr.20161112061414.4: *7* bClass = aClass
bClass = aClass
#@+node:ekr.20140206132559.4564: *6* expected
@others
bClass = aClass
#@+node:ekr.20150919074321.1: *7* class aClass
class aClass:
    @others
#@+node:ekr.20150919074321.2: *8* __init__
def __init__(self):
    pass
#@+node:ekr.20150919074321.3: *8* spam
def spam(self):
    pass
#@+node:ekr.20150919074122.1: *5* @@@test ic.parse-body mypy
tm = c.testManager
before   = g.findNodeInTree(c,p,'before')
expected = g.findNodeInTree(c,p,'expected')
assert before,expected
try:
    c.selectPosition(before)
    before.h = 'expected' # To make the compare work.
    c.importCommands.parse_body(before)
    # compare tree.
    assert tm.compareOutlines(before,expected,compareHeadlines=True,tag='',report=True)
    c.undoer.undo()
finally:
    before.h = 'before'
    c.redraw()
#@+node:ekr.20150919074220.1: *6* copy
class TypeJoinVisitor(TypeVisitor[Type]):
    """Implementation of the least upper bound algorithm.

    Attributes:
      s: The other (left) type operand.
    """

    def __init__(self, s: Type) -> None:
        self.s = s

    def visit_unbound_type(self, t: UnboundType) -> Type:
        if isinstance(self.s, Void) or isinstance(self.s, ErrorType):
            return ErrorType()
        else:
            return AnyType()

    def visit_union_type(self, t: UnionType) -> Type:
        if is_subtype(self.s, t):
            return t
        else:
            return UnionType(t.items + [self.s])

    def visit_error_type(self, t: ErrorType) -> Type:
        return t

    def visit_type_list(self, t: TypeList) -> Type:
        assert False, 'Not supported'

    def visit_any(self, t: AnyType) -> Type:
        return t

    def visit_void(self, t: Void) -> Type:
        if isinstance(self.s, Void):
            return t
        else:
            return ErrorType()

    def visit_none_type(self, t: NoneTyp) -> Type:
        if not isinstance(self.s, Void):
            return self.s
        else:
            return self.default(self.s)

    def visit_erased_type(self, t: ErasedType) -> Type:
        return self.s

    def visit_type_var(self, t: TypeVarType) -> Type:
        if isinstance(self.s, TypeVarType) and (cast(TypeVarType, self.s)).id == t.id:
            return self.s
        else:
            return self.default(self.s)

    def visit_instance(self, t: Instance) -> Type:
        if isinstance(self.s, Instance):
            return join_instances(t, cast(Instance, self.s))
        elif isinstance(self.s, FunctionLike):
            return join_types(t, self.s.fallback)
        else:
            return self.default(self.s)

    def visit_callable_type(self, t: CallableType) -> Type:
        # TODO: Consider subtyping instead of just similarity.
        if isinstance(self.s, CallableType) and is_similar_callables(
                t, cast(CallableType, self.s)):
            return combine_similar_callables(t, cast(CallableType, self.s))
        elif isinstance(self.s, Overloaded):
            # Switch the order of arguments to that we'll get to visit_overloaded.
            return join_types(t, self.s)
        else:
            return join_types(t.fallback, self.s)

    def visit_overloaded(self, t: Overloaded) -> Type:
        # This is more complex than most other cases. Here are some
        # examples that illustrate how this works.
        #
        # First let's define a concise notation:
        #  - Cn are callable types (for n in 1, 2, ...)
        #  - Ov(C1, C2, ...) is an overloaded type with items C1, C2, ...
        #  - Callable[[T, ...], S] is written as [T, ...] -> S.
        #
        # We want some basic properties to hold (assume Cn are all
        # unrelated via Any-similarity):
        #
        #   join(Ov(C1, C2), C1) == C1
        #   join(Ov(C1, C2), Ov(C1, C2)) == Ov(C1, C2)
        #   join(Ov(C1, C2), Ov(C1, C3)) == C1
        #   join(Ov(C2, C2), C3) == join of fallback types
        #
        # The presence of Any types makes things more interesting. The join is the
        # most general type we can get with respect to Any:
        #
        #   join(Ov([int] -> int, [str] -> str), [Any] -> str) == Any -> str
        #
        # We could use a simplification step that removes redundancies, but that's not
        # implemented right now. Consider this example, where we get a redundancy:
        #
        #   join(Ov([int, Any] -> Any, [str, Any] -> Any), [Any, int] -> Any) ==
        #       Ov([Any, int] -> Any, [Any, int] -> Any)
        #
        # TODO: Use callable subtyping instead of just similarity.
        result = []  # type: List[CallableType]
        s = self.s
        if isinstance(s, FunctionLike):
            # The interesting case where both types are function types.
            for t_item in t.items():
                for s_item in s.items():
                    if is_similar_callables(t_item, s_item):
                        result.append(combine_similar_callables(t_item, s_item))
            if result:
                # TODO: Simplify redundancies from the result.
                if len(result) == 1:
                    return result[0]
                else:
                    return Overloaded(result)
            return join_types(t.fallback, s.fallback)
        return join_types(t.fallback, s)

    def visit_tuple_type(self, t: TupleType) -> Type:
        if (isinstance(self.s, TupleType) and
                cast(TupleType, self.s).length() == t.length()):
            items = []  # type: List[Type]
            for i in range(t.length()):
                items.append(self.join(t.items[i],
                                       (cast(TupleType, self.s)).items[i]))
            # TODO: What if the fallback types are different?
            return TupleType(items, t.fallback)
        else:
            return self.default(self.s)

    def join(self, s: Type, t: Type) -> Type:
        return join_types(s, t)

    def default(self, typ: Type) -> Type:
        if isinstance(typ, Instance):
            return object_from_instance(typ)
        elif isinstance(typ, UnboundType):
            return AnyType()
        elif isinstance(typ, Void) or isinstance(typ, ErrorType):
            return ErrorType()
        elif isinstance(typ, TupleType):
            return self.default(typ.fallback)
        elif isinstance(typ, FunctionLike):
            return self.default(typ.fallback)
        elif isinstance(typ, TypeVarType):
            return self.default(typ.upper_bound)
        else:
            return AnyType()
#@+node:ekr.20150919074132.1: *6* before
@others
#@+node:ekr.20161112061406.1: *7* class TypeJoinVisitor
class TypeJoinVisitor(TypeVisitor[Type]):
    """Implementation of the least upper bound algorithm.

    Attributes:
      s: The other (left) type operand.
    """

    def __init__(self, s: Type) -> None:
        self.s = s

    def visit_unbound_type(self, t: UnboundType) -> Type:
        if isinstance(self.s, Void) or isinstance(self.s, ErrorType):
            return ErrorType()
        else:
            return AnyType()

    def visit_union_type(self, t: UnionType) -> Type:
        if is_subtype(self.s, t):
            return t
        else:
            return UnionType(t.items + [self.s])

    def visit_error_type(self, t: ErrorType) -> Type:
        return t

    def visit_type_list(self, t: TypeList) -> Type:
        assert False, 'Not supported'

    def visit_any(self, t: AnyType) -> Type:
        return t

    def visit_void(self, t: Void) -> Type:
        if isinstance(self.s, Void):
            return t
        else:
            return ErrorType()

    def visit_none_type(self, t: NoneTyp) -> Type:
        if not isinstance(self.s, Void):
            return self.s
        else:
            return self.default(self.s)

    def visit_erased_type(self, t: ErasedType) -> Type:
        return self.s

    def visit_type_var(self, t: TypeVarType) -> Type:
        if isinstance(self.s, TypeVarType) and (cast(TypeVarType, self.s)).id == t.id:
            return self.s
        else:
            return self.default(self.s)

    def visit_instance(self, t: Instance) -> Type:
        if isinstance(self.s, Instance):
            return join_instances(t, cast(Instance, self.s))
        elif isinstance(self.s, FunctionLike):
            return join_types(t, self.s.fallback)
        else:
            return self.default(self.s)

    def visit_callable_type(self, t: CallableType) -> Type:
        # TODO: Consider subtyping instead of just similarity.
        if isinstance(self.s, CallableType) and is_similar_callables(
                t, cast(CallableType, self.s)):
            return combine_similar_callables(t, cast(CallableType, self.s))
        elif isinstance(self.s, Overloaded):
            # Switch the order of arguments to that we'll get to visit_overloaded.
            return join_types(t, self.s)
        else:
            return join_types(t.fallback, self.s)

    def visit_overloaded(self, t: Overloaded) -> Type:
        # This is more complex than most other cases. Here are some
        # examples that illustrate how this works.
        #
        # First let's define a concise notation:
        #  - Cn are callable types (for n in 1, 2, ...)
        #  - Ov(C1, C2, ...) is an overloaded type with items C1, C2, ...
        #  - Callable[[T, ...], S] is written as [T, ...] -> S.
        #
        # We want some basic properties to hold (assume Cn are all
        # unrelated via Any-similarity):
        #
        #   join(Ov(C1, C2), C1) == C1
        #   join(Ov(C1, C2), Ov(C1, C2)) == Ov(C1, C2)
        #   join(Ov(C1, C2), Ov(C1, C3)) == C1
        #   join(Ov(C2, C2), C3) == join of fallback types
        #
        # The presence of Any types makes things more interesting. The join is the
        # most general type we can get with respect to Any:
        #
        #   join(Ov([int] -> int, [str] -> str), [Any] -> str) == Any -> str
        #
        # We could use a simplification step that removes redundancies, but that's not
        # implemented right now. Consider this example, where we get a redundancy:
        #
        #   join(Ov([int, Any] -> Any, [str, Any] -> Any), [Any, int] -> Any) ==
        #       Ov([Any, int] -> Any, [Any, int] -> Any)
        #
        # TODO: Use callable subtyping instead of just similarity.
        result = []  # type: List[CallableType]
        s = self.s
        if isinstance(s, FunctionLike):
            # The interesting case where both types are function types.
            for t_item in t.items():
                for s_item in s.items():
                    if is_similar_callables(t_item, s_item):
                        result.append(combine_similar_callables(t_item, s_item))
            if result:
                # TODO: Simplify redundancies from the result.
                if len(result) == 1:
                    return result[0]
                else:
                    return Overloaded(result)
            return join_types(t.fallback, s.fallback)
        return join_types(t.fallback, s)

    def visit_tuple_type(self, t: TupleType) -> Type:
        if (isinstance(self.s, TupleType) and
                cast(TupleType, self.s).length() == t.length()):
            items = []  # type: List[Type]
            for i in range(t.length()):
                items.append(self.join(t.items[i],
                                       (cast(TupleType, self.s)).items[i]))
            # TODO: What if the fallback types are different?
            return TupleType(items, t.fallback)
        else:
            return self.default(self.s)

    def join(self, s: Type, t: Type) -> Type:
        return join_types(s, t)

    def default(self, typ: Type) -> Type:
        if isinstance(typ, Instance):
            return object_from_instance(typ)
        elif isinstance(typ, UnboundType):
            return AnyType()
        elif isinstance(typ, Void) or isinstance(typ, ErrorType):
            return ErrorType()
        elif isinstance(typ, TupleType):
            return self.default(typ.fallback)
        elif isinstance(typ, FunctionLike):
            return self.default(typ.fallback)
        elif isinstance(typ, TypeVarType):
            return self.default(typ.upper_bound)
        else:
            return AnyType()
#@+node:ekr.20150919074154.1: *6* expected
@others
#@+node:ekr.20150919074211.1: *7* class TypeJoinVisitor
class TypeJoinVisitor(TypeVisitor[Type]):
    """Implementation of the least upper bound algorithm.

    Attributes:
      s: The other (left) type operand.
    """
    @others
#@+node:ekr.20150919074211.2: *8* __init__

def __init__(self, s: Type) -> None:
    self.s = s

#@+node:ekr.20150919074211.3: *8* visit_unbound_type
def visit_unbound_type(self, t: UnboundType) -> Type:
    if isinstance(self.s, Void) or isinstance(self.s, ErrorType):
        return ErrorType()
    else:
        return AnyType()

#@+node:ekr.20150919074211.4: *8* visit_union_type
def visit_union_type(self, t: UnionType) -> Type:
    if is_subtype(self.s, t):
        return t
    else:
        return UnionType(t.items + [self.s])

#@+node:ekr.20150919074211.5: *8* visit_error_type
def visit_error_type(self, t: ErrorType) -> Type:
    return t

#@+node:ekr.20150919074211.6: *8* visit_type_list
def visit_type_list(self, t: TypeList) -> Type:
    assert False, 'Not supported'

#@+node:ekr.20150919074211.7: *8* visit_any
def visit_any(self, t: AnyType) -> Type:
    return t

#@+node:ekr.20150919074211.8: *8* visit_void
def visit_void(self, t: Void) -> Type:
    if isinstance(self.s, Void):
        return t
    else:
        return ErrorType()

#@+node:ekr.20150919074211.9: *8* visit_none_type
def visit_none_type(self, t: NoneTyp) -> Type:
    if not isinstance(self.s, Void):
        return self.s
    else:
        return self.default(self.s)

#@+node:ekr.20150919074211.10: *8* visit_erased_type
def visit_erased_type(self, t: ErasedType) -> Type:
    return self.s

#@+node:ekr.20150919074211.11: *8* visit_type_var
def visit_type_var(self, t: TypeVarType) -> Type:
    if isinstance(self.s, TypeVarType) and (cast(TypeVarType, self.s)).id == t.id:
        return self.s
    else:
        return self.default(self.s)

#@+node:ekr.20150919074211.12: *8* visit_instance
def visit_instance(self, t: Instance) -> Type:
    if isinstance(self.s, Instance):
        return join_instances(t, cast(Instance, self.s))
    elif isinstance(self.s, FunctionLike):
        return join_types(t, self.s.fallback)
    else:
        return self.default(self.s)

#@+node:ekr.20150919074211.13: *8* visit_callable_type
def visit_callable_type(self, t: CallableType) -> Type:
    # TODO: Consider subtyping instead of just similarity.
    if isinstance(self.s, CallableType) and is_similar_callables(
            t, cast(CallableType, self.s)):
        return combine_similar_callables(t, cast(CallableType, self.s))
    elif isinstance(self.s, Overloaded):
        # Switch the order of arguments to that we'll get to visit_overloaded.
        return join_types(t, self.s)
    else:
        return join_types(t.fallback, self.s)

#@+node:ekr.20150919074211.14: *8* visit_overloaded
def visit_overloaded(self, t: Overloaded) -> Type:
    # This is more complex than most other cases. Here are some
    # examples that illustrate how this works.
    #
    # First let's define a concise notation:
    #  - Cn are callable types (for n in 1, 2, ...)
    #  - Ov(C1, C2, ...) is an overloaded type with items C1, C2, ...
    #  - Callable[[T, ...], S] is written as [T, ...] -> S.
    #
    # We want some basic properties to hold (assume Cn are all
    # unrelated via Any-similarity):
    #
    #   join(Ov(C1, C2), C1) == C1
    #   join(Ov(C1, C2), Ov(C1, C2)) == Ov(C1, C2)
    #   join(Ov(C1, C2), Ov(C1, C3)) == C1
    #   join(Ov(C2, C2), C3) == join of fallback types
    #
    # The presence of Any types makes things more interesting. The join is the
    # most general type we can get with respect to Any:
    #
    #   join(Ov([int] -> int, [str] -> str), [Any] -> str) == Any -> str
    #
    # We could use a simplification step that removes redundancies, but that's not
    # implemented right now. Consider this example, where we get a redundancy:
    #
    #   join(Ov([int, Any] -> Any, [str, Any] -> Any), [Any, int] -> Any) ==
    #       Ov([Any, int] -> Any, [Any, int] -> Any)
    #
    # TODO: Use callable subtyping instead of just similarity.
    result = []  # type: List[CallableType]
    s = self.s
    if isinstance(s, FunctionLike):
        # The interesting case where both types are function types.
        for t_item in t.items():
            for s_item in s.items():
                if is_similar_callables(t_item, s_item):
                    result.append(combine_similar_callables(t_item, s_item))
        if result:
            # TODO: Simplify redundancies from the result.
            if len(result) == 1:
                return result[0]
            else:
                return Overloaded(result)
        return join_types(t.fallback, s.fallback)
    return join_types(t.fallback, s)

#@+node:ekr.20150919074211.15: *8* visit_tuple_type
def visit_tuple_type(self, t: TupleType) -> Type:
    if (isinstance(self.s, TupleType) and
            cast(TupleType, self.s).length() == t.length()):
        items = []  # type: List[Type]
        for i in range(t.length()):
            items.append(self.join(t.items[i],
                                   (cast(TupleType, self.s)).items[i]))
        # TODO: What if the fallback types are different?
        return TupleType(items, t.fallback)
    else:
        return self.default(self.s)

#@+node:ekr.20150919074211.16: *8* join
def join(self, s: Type, t: Type) -> Type:
    return join_types(s, t)

#@+node:ekr.20150919074211.17: *8* default
def default(self, typ: Type) -> Type:
    if isinstance(typ, Instance):
        return object_from_instance(typ)
    elif isinstance(typ, UnboundType):
        return AnyType()
    elif isinstance(typ, Void) or isinstance(typ, ErrorType):
        return ErrorType()
    elif isinstance(typ, TupleType):
        return self.default(typ.fallback)
    elif isinstance(typ, FunctionLike):
        return self.default(typ.fallback)
    elif isinstance(typ, TypeVarType):
        return self.default(typ.upper_bound)
    else:
        return AnyType()
#@+node:ekr.20161204041557.1: *4* All other tests
#@+node:ekr.20090529141856.4793: *5* @@test test imports for modes
d = g.app.extra_extension_dict

for ext in g.app.extension_dict.keys():
    language =  c.importCommands.languageForExtension(ext)
    language2 = c.importCommands.languageForExtension('.'+ext)
    assert language == language2

    # Now a many-one relationship.
    if language:
        # Do not test extensions that have 'none' as the value of d.get(ext)
        # Otherwise, test only d.get(ext).
        language2 = d.get(ext)
        if language2 in ('None','none'):  continue
        if language2: language = language2
        # Made-up languages do not have mode files.
        if not language.endswith('_language') and language not in ('autohotkey','rest','rst','typescript',):
            path = g.os_path_join(g.app.loadDir,'..','modes','%s.py' % (language))
            assert g.os_path_exists(path), 'for ext=%s does not exist: %s' % (ext,path)

    if 0:
        if language is None:
            print('no language for ext=%s' % (ext))
#@+node:ekr.20140723134017.4464: *5* @test @auto importers
# This causes problems!
import glob
import importlib
path = g.os_path_finalize_join(g.app.loadDir,'..','plugins','importers')
# print('path: %s' % path)
assert g.os_path_exists(path)
pattern = g.os_path_finalize_join(path,'*.py')
for fn in glob.glob(pattern):
    sfn = g.shortFileName(fn)
    m = importlib.import_module('leo.plugins.importers.%s' % sfn[:-3])
    assert m
#@+node:ekr.20161109065940.1: *5* @test Importer.get_leading_indent
# g.cls()
import leo.plugins.importers.linescanner as linescanner
# import imp
# imp.reload(linescanner)
lines_table = [
    'abc',
    '    xyz',
    '    ',
    '  # comment',
]
for language in ('python', 'coffeescript'):
    importer = linescanner.Importer(
        c.importCommands,
        atAuto = True,
        language = language,
    )
    # print('%s %r' % (language, importer.comment_delim))
    assert importer.single_comment == '#', importer.single_comment
    for line in lines_table:
        lines = [line]
        n = importer.get_leading_indent(lines, 0)
        # print('%s %r' % (n, line))
#@+node:ekr.20161117011147.1: *5* @test Importer.get_str_lws
import leo.plugins.importers.linescanner as linescanner
table = [
    ('', 'abc\n'),
    ('    ', '    xyz\n'),
    ('    ', '    \n'),
    ('  ','  # comment\n'),
    ('', '\n'),
]
importer = linescanner.Importer(c.importCommands,
    atAuto=True, language='python')
for val, s in table:
    assert val == importer.get_str_lws(s), (val, repr(s))
#@+node:ekr.20161109065949.1: *5* @test Importer.is_ws_line
# g.cls()
import leo.plugins.importers.linescanner as linescanner
# import imp
# imp.reload(linescanner)
table = [
    (False, 'abc'),
    (False, '    xyz'),
    (True, '    '),
    (True,'  # comment'),
]
importer = linescanner.Importer(
    c.importCommands,
    atAuto = True,
    language = 'python',
)
for val, s in table:
    assert val == importer.is_ws_line(s), (val, repr(s))
#@+node:ekr.20161011052016.1: *5* @test importers.javascript.scan_line
import leo.plugins.importers.javascript as js
table = (
    (None, (0, 0, '/*'),    r'/* abc'),
    (None, (0, 0, ''),      r'a + b // /*'),
    (None, (0, 1, ''),      r'(function'),
    (None, (1, 1, ''),      r'(function(a) {'),
    (None, (0, 0, ''),      r'var x = /abc/'),
    (None, (0, 0, ''),      r'var x = /a"c/'),
    (None, (0, 0, ''),      r'var x = /a\//'),
    (None, (0, 0, ''),      r'var x = /a\//'),
    (None, (0, 0, ''),      r"console.log(/'\d+'/)"),
    (None, (0, 1, ''),      r'var x = (0,'),
)
for base, result, s in table:
    importer = js.JS_Importer(c.importCommands, atAuto=False)
    prev_state = js.JS_ScanState()
    new_state = importer.scan_line(s, prev_state)
    curlies, parens, context = result
    ok = (
        new_state.curlies == curlies and
        new_state.parens == parens and
        new_state.context == context)
    assert ok, '\nexpected %r\n     got %r' % (expected_state, new_state)
#@+node:ekr.20140724164600.4590: *4* @test zz end of leoImport tests
# This is **not** a real unit test.
# It simply restores the screen to a more convenient state.

# c.contractParent()
# g.app.unitTestDict['restoreSelectedNode']=False

print('\nEnd of leoImport tests.')
#@+node:ekr.20100131171342.5604: *3* leoKeys
#@+node:ekr.20100131171342.5606: *4* @@test k.autoCompleterClass.calltip
# This test is difficult to get right on all platforms.
# It's not worth doing.

try:
    k = c.k
    w = c.frame.body.wrapper
    ac = k.autoCompleter
    # Set the insertion point.
    s = w.getAllText()
    w.setInsertPoint(len(s)-1)
    # Just test that this doesn't crash.
    ac.w = w
    ac.calltip()
finally:
    w.setAllText(s)
    p.setBodyString(s)
    c.recolor()

# c.frame
#@+node:ekr.20110509104953.3474: *4* @test k.get_leo_completions
table = (
    ( 50,'c.'),
    (  3,'p.ins'),
    ( 17,'g.print'),
)
g.pr
ac = c.k.autoCompleter
ac.w = c.frame.body.wrapper

for expected,prefix in table:
    
    aList = ac.get_leo_completions(prefix)
    assert len(aList) >= expected,'len(aList): %s, prefix: %s' % (len(aList),prefix)
    
    if 0:
        print()
        for z in aList:
            print(z)
#@+node:ekr.20111121224307.3934: *4* @test k.handleDefaultChar from log pane
if g.app.isExternalUnitTest:
    self.skipTest('Can not be run externally')
else:
    tabs = ('Log','Find')
    log = c.frame.log
    c.bodyWantsFocusNow()
    last_widget = c.frame.body
        
    for tab in tabs:
        # A small hack: fudge up the widget to pass to the command.
        event = g.bunch(widget=last_widget)
        c.editCommands.cycleAllFocus(event=event)
        assert log.tabName == tab,'expected %s, got %s' % (
            tab,log.tabName)
        last_widget = log.contentsDict.get(tab)
        # print('pass',tab,last_widget)
        event = g.bunch(widget=last_widget)
        
        # This throws exception: LeoQTextBrowser has no attribute logCtrl.
        c.k.handleDefaultChar(event, stroke='a')
#@+node:ekr.20100131171342.5605: *4* @test k.isPlainKey
import string

k = c.k

for ch in (string.printable):
    if ch == '\n': continue # A special case.
    assert k.isPlainKey(ch), 'wrong: not plain: %s' % (ch)

special = (
    'Return', # A special case.
    'Begin','Break','Caps_Lock','Clear','Down','End','Escape',
    'F1','F2','F3','F4','F5','F6','F7','F8','F9','F10','F11','F12',
    'KP_Add', 'KP_Decimal', 'KP_Divide', 'KP_Enter', 'KP_Equal',
    'KP_Multiply, KP_Separator,KP_Space, KP_Subtract, KP_Tab',
    'KP_F1','KP_F2','KP_F3','KP_F4',
    'KP_0','KP_1','KP_2','KP_3','KP_4','KP_5','KP_6','KP_7','KP_8','KP_9',
    'Home','Left','Linefeed','Next','Num_Lock',
    'PageDn','PageUp','Pause','Prior','Right','Up',
    'Sys_Req',
)

for ch in special:
    assert not k.isPlainKey(ch), 'wrong: is plain: %s' % (ch)
#@+node:ekr.20100212110954.5359: *4* @test k.print-bindings
lines = c.k.printBindings()
# assert lines[0].strip().endswith('Alt+Ctrl+Shift')
#@+node:ekr.20100131171342.5607: *4* @test k.registerCommand
k = c.k ; p = c.p
w = c.edit_widget(p)
commandName = 'test-registerCommand'

def callback (event=None,c=c): # Must have an event param to pass later unit test.
    g.app.unitTestDict[commandName] = True

# Test 1
g.app.unitTestDict[commandName] = False
k.registerCommand(commandName,'Alt-Ctrl-Shift-z',callback,pane='all',verbose=True)
k.simulateCommand(commandName)
assert g.app.unitTestDict.get(commandName)

if 0: # Test 2
    g.app.unitTestDict[commandName] = False
    k.manufactureKeyPressForCommandName(w,commandName)
    assert g.app.unitTestDict.get(commandName)
#@+node:ekr.20100131171342.5608: *4* @test k.strokeFromSetting
# print('settingsNameDict',c.k.settingsNameDict)

table = (
    ('Key-1','1'), # 2016/04/12
    ('key-1','1'), # 2016/04/12
    ('1', '1'), # 2016/04/12
    ('a','a'),
    ('A','a'),
    ('Alt-a','Alt+a'),
    ('Alt-A','Alt+a'),
    ('Alt-Shift-a','Alt+A'),
    ('Alt-=','Alt+equal'),
    ('Alt-+','Alt+plus'),
    # We can no longer igtnore the shift.
    # ('Alt-Shift++','Alt+plus'), # Ignore the shift.
    ('Alt--','Alt+minus'),
    ('Shift-a','A'),
    ('Shift-A','A'),
    ('RtArrow','Right'),
    ('Shift-RtArrow','Shift+Right'),
    ('Ctrl-RtArrow','Ctrl+Right'),
    ('Control-Right','Ctrl+Right'),
    ('PageUp','Prior'), ('Prior','Prior'),('Shift-PageUp','Shift+Prior'),
    ('PageDn','Next'),('Next','Next'),('Shift-Next','Shift+Next'),
)
for setting, result in table:
    val = c.k.strokeFromSetting(setting)
    assert val==result,'Expected %s, Got %s' % (result,val)
#@+node:ekr.20100131171342.5609: *4* @test zz end of leoKeys tests
# This is **not** a real unit test.
# It simply restores the screen to a more convenient state.

# c.contractParent()
# g.app.unitTestDict['restoreSelectedNode']=False

print('\nEnd of leoKeys tests.')
#@+node:ekr.20071113194424.1: *3* leoNodes
#@+node:ekr.20040712101754.181: *4*  inner @test: Test consistency between parents iter and v.parents
# The actual test is in a child node.
#@+node:ekr.20040712101754.182: *5* parent
#@+node:ekr.20040712101754.183: *6* @test consistency between parents_iter and v.parents
try:
    for p in c.all_positions():
        if 0: # Check all ancestors.  This is tricky and doesn't work yet.
            parents1 = [parent.v for parent in p.parents_iter()]
            parents2 = []
            parent2 = p.v.directParents()
            while parent2:
                v = parent2[0]
                parents2.append(v)
                parent2 = v.directParents()
        else:
            parents1 = p.v.parents
            parents2 = p.v.directParents()

        assert len(parents1) == len(parents2), "length mismatch: %s" % (p)
        for parent in parents1:
            assert parent in parents2, "%s not in %s" % (parent,parent1)
        for parent in parents2:
            assert parent in parents1, "%s not in %s" % (parent,parent2)

except AssertionError:
    print("parents1")
    for parent in parents1: print(parent)
    print("parents2")
    for parent in parents2: print(parent)
    raise
#@+node:ville.20090312195309.2: *4* @@@test find_h / find_b / filter_h / filter_b
#if this starts failing due to much refacting in unitTest.leo,
# adjust accordingly

# These seem to fail if various nodes are cloned.
import random,fnmatch

all_h = [z.copy().h for z in c.find_h('.')]

assert len(all_h) > 1000,'fail 1'

sample = random.sample(all_h, 20)    

# Test that all nodes are found at least once.
for h in sample:
    pat = fnmatch.translate(h)
    pl = c.find_h(pat)
    assert len(pl) > 0 and len(pl) < len(all_h),'fail 2'

tests = c.find_h('@test(.*)')

bm = tests.filter_b('(.*)all_positions')
forloops = 0
for node in bm:   
    # many of these are for loops
    for m in node.matchiter:
        if 'for' in m.group(1):
            forloops += 1

assert forloops > 10,'fail for'

# all of these should also be found by find_b
all_bm = c.find_b('(.*)all_positions')
assert len(all_bm) >= len(bm),'fail len'

assert set(el.h for el in bm).issubset(set(el.h for el in all_bm)),'fail set'

itertest = c.find_h('@test p.iters and v.iters')
assert len(itertest) >= 1,'fail 3'
tn = itertest[0]
assert tn.h == '@test p.iters and v.iters','fail h'
assert len(itertest.filter_b('notfound, really')) == 0,'fail 4'
assert len(itertest.filter_b('leoNodes')) == 1,'fail 5'
chi = itertest.children().filter_h('child?')
assert chi[0].h == 'child1','fail 6'
assert chi[1].h == 'child2','fail 7'
# twice, in clones
chi_b = chi.children().filter_h('a').children().filter_h('b')

if 0:
    assert len(chi_b) == 2,'fail len 2: %s: %s' % (chi_b,len(chi_b))
    assert chi_b[0].h == chi_b[1].h == 'b'
    chi_e = chi.children().filter_h('d').children().filter_h('e')
    assert len(chi_e) == 1,'fail 8'
    assert chi_e[0].h == 'e','fail 9'

#@+node:ekr.20080310073711.1: *4* @@@test nodeIndices.toString(None) allocates a new index
gnx = g.app.nodeIndices.toString(None)
assert(gnx not in (None,'None'))
assert(len(gnx) > 1)
#@+node:ekr.20040712101754.175: *4* @@test p.t == p.v
# p.__getattr__ must be enabled for this test to work.

for p in c.all_positions():
    assert(p.t == p.v)
#@+node:ekr.20040712101754.200: *4* @@test that clones share subtrees
for p in c.all_positions():
    if p.isCloned() and p.hasChildren():
        childv = p.firstChild().v
        firstChild = p.v.children[0]
        assert childv == firstChild
#@+node:ekr.20070611071101: *4* @@test visback
p1 = p.copy()
a = p.firstChild()
b = a.firstChild()
c2 = b.firstChild()
limit = a.next()
d = limit.firstChild()
e = limit.next()
assert e.h == 'e'
for p2,h in ((a,'a'),(b,'b'),(c2,'c2'),(d,'d'),(limit,'limit')):
    p2.expand()
    assert p2.h==h,'headString mismatch'

try: # Tests without hoist...
    p1.expand()
    assert not c.hoistStack
    c.selectPosition(limit)
    result = limit.copy().moveToVisBack(c)
    assert result==c2,'visBack != c2: %s' % result
    #
    result = limit.copy().moveToVisNext(c)
    assert result==d,'visNext != d: %s' % result
finally:
    p1.contract()

try: # Tests with hoist.
    p1.expand()
    c.selectPosition(limit)
    c.hoist()
    result = limit.copy().moveToVisBack(c)
    assert not result,'limited visBack: %s' % result
    #
    result = limit.copy().moveToVisNext(c)
    assert result==d,'limited visNext !=d: %s' % result
finally:
    c.dehoist()
    c.selectPosition(p1)
    p1.contract()
    c.redraw_now()

#@+node:ekr.20070611071101.1: *5* a
#@+node:ekr.20070611071101.2: *6* b
#@+node:ekr.20070611071101.3: *7* c2
#@+node:ekr.20070611071101.4: *5* limit
#@+node:ekr.20070611071101.5: *6* d
#@+node:ekr.20070611071954: *5* e
#@+node:ekr.20161002020559.1: *4* @test all generator return unique positions
# This fixes a major bug in *all* generators returning positions.
trace = False
root = c.rootPosition
table = (
    ('all_positions', c.all_positions),
    ('all_unique_positions', c.all_unique_positions),
    ('children', root().children),
    ('self_and_siblings', root().self_and_siblings),
    ('self_and_parents', root().firstChild().self_and_parents),
    ('self_and_subtree', root().self_and_subtree),
    ('following_siblings', root().following_siblings),
    ('parents', root().firstChild().firstChild().parents),
    ('unique_subtree', root().unique_subtree),
)
fail = []
for kind, generator in table:
    aList = list(generator())
    aList2 = list(set(aList))
    if len(aList) == len(aList2) and len(aList) > 1:
        if trace: print('  OK: %s %s' % (kind, len(aList)))
    else:
        if trace: print('FAIL: %s %s %s' % (kind, len(aList), len(aList2)))
        fail.append(kind)
assert not fail, fail
#@+node:ekr.20040712101754.99: *4* @test c iters
<< coverage tests >>
<< duplicate tests >>

if 0:
    print("vnodes",len([v for v in c.all_vnodes_iter()]),len([v for v in c.all_unique_vnodes_iter()]))
    print("tnodes",len([t for t in c.all_tnodes_iter()]),len([t for t in c.all_unique_tnodes_iter()]))

if 0: # all nodes
    for v in c.all_vnodes_iter(): print(v)
    for t in c.all_tnodes_iter(): print(t)

if 0: # unique nodes
    for v in c.all_unique_vnodes_iter(): print(v)
    for t in c.all_unique_tnodes_iter(): print(t)
#@+node:ekr.20040712101754.100: *5* << coverage tests >>
v1 = [p.v for p in c.all_positions()]
v2 = [v for v in c.all_nodes()]
for v in v2: assert(v in v1)
for v in v1: assert(v in v2)

# print("coverage tests pass")
#@+node:ekr.20040712101754.101: *5* << duplicate tests >>
nodes = []
for v in c.all_unique_nodes():
    assert v not in nodes
    nodes.append(v)

# print("duplicate tests pass")
#@+node:ekr.20090102061858.2: *4* @test c.positionExists
child = p.insertAsLastChild()
assert c.positionExists(child)
child.doDelete()
assert not c.positionExists(child),'fail 1'

# also check the same on root level
child = c.rootPosition().insertAfter()
assert c.positionExists(child)
child.doDelete()
assert not c.positionExists(child),'fail 2'
#@+node:ekr.20120212130242.4704: *5* newHeadline
#@+node:ekr.20090102062037.2: *4* @test c.positionExists for all nodes
for p in c.all_positions():
    assert c.positionExists(p)
        # 2012/03/08: If a root is given, the search is confined to that root only.

#@+node:ekr.20150317093233.11: *4* @test c.safe_all_positions
aList1 = list(c.all_positions())
aList2 = list(c.safe_all_positions())
n1,n2 = len(aList1),len(aList2)
assert n1 == n2,(n1,n2)
#@+node:ekr.20141022175515.11: *4* @test check all gnx's exist and are unique
d = {} # Keys are gnx's, values are lists of vnodes with that gnx.
for p in c.all_positions():
    gnx = p.v.fileIndex
    assert gnx,p.v
    aSet = d.get(gnx,set())
    aSet.add(p.v)
    d[gnx] = aSet
for gnx in sorted(d.keys()):
    aList = sorted(d.get(gnx))
    # print(gnx,aList)
    assert len(aList) == 1,(gnx,aList)
#@+node:ekr.20040712101754.204: *4* @test consistency of back/next links
for p in c.all_positions():

    back = p.back()
    next = p.next()
    if back: assert(back.getNext() == p)
    if next: assert(next.getBack() == p)
#@+node:ekr.20040712101754.201: *4* @test consistency of c.all_positions() and p.ThreadNext()
p2 = c.rootPosition()
for p in c.all_positions():
    assert p==p2, "%s != %s" % (p,p2)
    p2.moveToThreadNext()

assert not p2, repr(p2)
#@+node:ekr.20040712101754.202: *4* @test consistency of firstChild & children_iter()
for p in c.all_positions():
    p2 = p.firstChild()
    for p3 in p.children_iter():
        assert p3==p2, "%s != %s" % (p3,p2)
        p2.moveToNext()

assert not p2, repr(p2)
#@+node:ekr.20040712101754.203: *4* @test consistency of level
for p in c.all_positions():

    if p.hasParent():
        assert(p.parent().level() == p.level() - 1)

    if p.hasChildren():
        assert(p.firstChild().level() == p.level() + 1)

    if p.hasNext():
        assert(p.next().level() == p.level())

    if p.hasBack():
        assert(p.back().level() == p.level())
#@+node:ekr.20040712101754.205: *4* @test consistency of parent & parents_iter()
for p in c.all_positions():
    p2 = p.parent()
    for p3 in p.parents_iter():
        assert p3==p2, "%s != %s" % (p3,p2)
        p2.moveToParent()

    assert not p2, repr(p2)
#@+node:ekr.20040712101754.206: *4* @test consistency of parent/child links
# Test consistency of p.parent, p.next, p.back and p.firstChild.
for p in c.all_positions():

    if p.hasParent():
        n = p.childIndex()
        assert(p == p.parent().moveToNthChild(n))

    for child in p.children_iter():
        assert(p == child.parent())

    if p.hasNext():
        assert(p.next().parent() == p.parent())

    if p.hasBack():
        assert(p.back().parent() == p.parent())
#@+node:ekr.20040712101754.207: *4* @test consistency of threadBack/Next links
for p in c.all_positions():

    threadBack = p.threadBack()
    threadNext = p.threadNext()

    if threadBack:
        assert(p == threadBack.getThreadNext())

    if threadNext:
        assert(p == threadNext.getThreadBack())
#@+node:ekr.20040712101754.177: *4* @test convertTreeToString and allies
p = p.firstChild()
assert(p.h=="File Conversion")
p.convertTreeToString()
#@+node:ekr.20040712101754.178: *5* File Conversion
@
- convertTreeToString and moreHead can't be VNode methods because they uses level().
- moreBody could be anywhere: it may as well be a postion method.
#@+node:ekr.20040712101754.179: *6* moreHead
def moreHead (self, firstLevel,useVerticalBar=False):

    """Return the headline string in MORE format."""

    p = self

    level = self.level() - firstLevel
    plusMinus = g.choose(p.hasChildren(), "+", "-")

    return "%s%s %s" % ('\t'*level,plusMinus,p.h)
#@+node:ekr.20040712101754.180: *6* moreBody
@ 
    + test line
    - test line
    \ test line
    test line +
    test line -
    test line \
    More lines...
@c

def moreBody (self):

    """Returns the body string in MORE format.  

    Inserts a backslash before any leading plus, minus or backslash."""

    p = self ; list = []

    # Only escape the first non-blank character of the line.
    s =  p.b ; result = []
    lines = string.split(s,'\n')
    for s in lines:
        i = g.skip_ws(s,0)
        if i < len(s):
            ch = s[i]
            if ch == '+' or ch == '-' or ch == '\\':
                s = s[:i] + '\\' + s[i:]
        result.append(s)
    return string.join(result,'\n')
#@+node:ekr.20090130133404.2: *4* @test leoNodes properties
v = p.v
b = p.b
p.b = b
assert p.b == b
v.b = b
assert v.b == b

h = p.h
p.h = h
assert p.h == h
v.h = h
assert v.h == h

for p in c.all_positions():
    assert p.b == p.bodyString()
    assert p.v.b == p.v.bodyString()
    assert p.h == p.headString()
    assert p.v.h == p.v.headString()
#@+node:ekr.20130524112342.4137: *4* @test new vnodes methods
parent_v = p.parent().v or c.hiddenRootNode
while p.hasChildren():
    p.firstChild().doDelete()
# print(parent_v,p.childIndex())
if 0: # passes
    p.v.cloneAsNthChild(parent_v,p.childIndex())
if 1:
    v2 = p.v.insertAsFirstChild()
    v2.h = 'insertAsFirstChild'
    v2 = p.v.insertAsLastChild()
    v2.h = 'insertAsLastChild'
    v2 = p.v.insertAsNthChild(1)
    v2.h = 'insertAsNthChild(1)'
p.expand()
c.redraw()
#@+node:ekr.20140724164208.5505: *5* insertAsFirstChild
#@+node:ekr.20140724164208.5507: *5* insertAsNthChild(1)
#@+node:ekr.20140724164208.5506: *5* insertAsLastChild
#@+node:ekr.20141020110954.4750: *4* @test newlines in headlines
# Bug https://bugs.launchpad.net/leo-editor/+bug/1245535
h = p.h
try:
    p.h = '\nab\nxy\n'
    assert p.h == 'abxy',p.h
finally:
    p.h = h
#@+node:ekr.20041013062906: *4* @test onHyperLinkControlClick
# This hack is needed only for tkinter gui.
if g.app.gui.guiName() == 'tkinter':
    p.OnHyperLinkControlClick(event=None)
#@+node:ekr.20160123044102.1: *4* @test p.__eq__
# These must not return NotImplemented!
root = c.rootPosition()
assert p.__eq__(None) is False, p.__eq__(None)
assert p.__ne__(None) is True, p.__ne__(None)
assert p.__eq__(root) is False, p.__eq__(root)
assert p.__ne__(root) is True, p.__ne__(root)
#@+node:ekr.20131220083358.3982: *4* @test p._relinkAsCloneOf
u = c.undoer
p1 = g.findNodeInTree(c,p,'a')
p2 = g.findNodeInTree(c,p,'b')
assert p1 and p2
assert not p1.isCloned()
assert not p2.isCloned()
bunch = u.beforeChangeTree(p)
p1._relinkAsCloneOf(p2)
u.afterChangeTree(p,'relink-clone',bunch)
assert p.firstChild().isCloned()
assert p.firstChild().next().isCloned()
c.redraw()
u.undo()
c.redraw()
p1 = g.findNodeInTree(c,p,'a')
p2 = g.findNodeInTree(c,p,'b')
assert not p1.isCloned()
assert not p2.isCloned()
assert p1 and p2
u.clearUndoState()
#@+node:ekr.20131220083358.3983: *5* a
#@+node:ekr.20131220083358.3984: *5* b
b text.
#@+node:ekr.20100131180007.5369: *4* @test p.adjustPositionBeforeUnlink
table = (
    '1',
    '1-1','1-1-1','1-1-2',
    '1-2','1-2-1','1-2-2',
    '2',
    '2-1','2-1-1','2-1-2',
    '2-2','2-2-1','2-2-2',
    '3',
    '3-1','3-1-1','3-1-2',
    '3-2','3-2-1','3-2-2',
)

for suffix in table:
    h = 'node %s' % suffix
    p2 = g.findNodeInTree(c,p,h)
    assert p2,h

table2 = (
    ('2-1-2','2-1-1','2-1-1'),
    ('3','2','2'),
)  

for h1,h2,h3 in table2:
    p1 = g.findNodeInTree(c,p,'node %s' % h1)
    p2 = g.findNodeInTree(c,p,'node %s' % h2)
    p3 = g.findNodeInTree(c,p,'node %s' % h3)
    p1._adjustPositionBeforeUnlink(p2)
    result = p1
    assert result.stack == p3.stack,'expected %s got %s' % (
        p3.h,result and result.h or '<none>')

# Data.
@others
#@+node:ekr.20100131180007.5370: *5* node 1
# Node 1
#@+node:ekr.20100131180007.5371: *6* node 1-1
# node 1-1
#@+node:ekr.20100131180007.5372: *7* node 1-1-1
# node 1-1-1
#@+node:ekr.20100131180007.5373: *7* node 1-1-2
# node 1-1-2
#@+node:ekr.20100131180007.5374: *6* node 1-2
# node 1-2
#@+node:ekr.20100131180007.5375: *7* node 1-2-1
# node 1-2-1
#@+node:ekr.20100131180007.5376: *7* node 1-2-2
# node 1-2-2
#@+node:ekr.20100131180007.5377: *5* node 2
# node 2
#@+node:ekr.20100131180007.5378: *6* node 2-1
# node 2-1
#@+node:ekr.20100131180007.5379: *7* node 2-1-1
# node 2-1-1
#@+node:ekr.20100131180007.5380: *7* node 2-1-2
# node 2-1-2
#@+node:ekr.20100131180007.5381: *6* node 2-2
# node 2-2
#@+node:ekr.20100131180007.5382: *7* node 2-2-1
# node 2-2-1
#@+node:ekr.20100131180007.5383: *7* node 2-2-2
# node 2-2-2
#@+node:ekr.20100131180007.5384: *5* node 3
# node 3
#@+node:ekr.20100131180007.5385: *6* node 3-1
# node 3-1
#@+node:ekr.20100131180007.5386: *7* node 3-1-1
# node 3-1-1
#@+node:ekr.20100131180007.5387: *7* node 3-1-2
# node 3-1-2
#@+node:ekr.20100131180007.5388: *6* node 3-2
# node 3-2
#@+node:ekr.20100131180007.5389: *7* node 3-2-1
# node 3-2-1
#@+node:ekr.20100131180007.5390: *7* node 3-2-2
# node 3-2-2
#@+node:ekr.20040712101754.199: *4* @test p.comparisons
copy = p.copy()
assert(p == copy)
assert(p != p.threadNext())

root = c.rootPosition()
# assert p.equal(p.copy()) is True
# assert p.equal(root) is False
assert p.__eq__(copy) is True
assert p.__ne__(copy) is False
assert p.__eq__(root) is False
assert p.__ne__(root) is True
#@+node:ekr.20130703132516.4188: *4* @test p.deletePositionsInList
p1 = p.copy()
while p.hasChildren():
    p.firstChild().doDelete()
root = p.insertAsLastChild()
root.h = 'root'
# Top level
a1 = root.insertAsLastChild()
a1.h = 'a'
a2 = a1.clone()
d1 = a1.insertAfter()
d1.h = 'd'
b1 = root.insertAsLastChild()
b1.h = 'b'
# Children of a.
b11 = b1.clone()
b11.moveToLastChildOf(a1)
b12 = b11.clone()
c2 = b11.insertAfter()
c2.h = 'c'
# Children of d
b11 = b1.clone()
b11.moveToLastChildOf(d1)
def parent(p):
    return p.stack[-1][0].h
n = root.level()
aList = []
nodes = 0
for p in root.subtree():
    nodes += 1
    if p.h == 'b':
        if 0:
            parent = p.stack[-1][0]
            print('found',p.level()-n,p.h,'childIndex',p.childIndex(),'parent:',parent.h)
        aList.append(p.copy())
n_aList = len(aList)
assert n_aList == 6,n_aList
try:
    c.deletePositionsInList(aList)
finally:
    if 1:
        while p1.hasChildren():
            p1.firstChild().doDelete()
c.redraw()
#@+node:ekr.20040712101754.209: *4* @test p.hasNextBack
for p in c.all_positions():

    back = p.back()
    next = p.next()

    assert(
        (back and p.hasBack()) or
        (not back and not p.hasBack()))

    assert(
        (next and p.hasNext()) or
        (not next and not p.hasNext()))
#@+node:ekr.20040712101754.210: *4* @test p.hasParentChild
for p in c.all_positions():

    child = p.firstChild()
    parent = p.parent()

    assert(
        (child and p.hasFirstChild()) or
        (not child and not p.hasFirstChild()))

    assert(
        (parent and p.hasParent()) or
        (not parent and not p.hasParent()))
#@+node:ekr.20040712101754.211: *4* @test p.hasThreadNextBack
for p in c.all_positions():

    threadBack = p.getThreadBack()
    threadNext = p.getThreadNext()

    assert(
        (threadBack and p.hasThreadBack()) or
        (not threadBack and not p.hasThreadBack()))

    assert(
        (threadNext and p.hasThreadNext()) or
        (not threadNext and not p.hasThreadNext()))
#@+node:ekr.20040722055040: *4* @test p.isAncestorOf
for p in c.all_positions():

    child = p.firstChild()
    while child:
        for parent in p.self_and_parents_iter():
            assert parent.isAncestorOf(child)
        child.moveToNext()

    next = p.next()
    assert not p.isAncestorOf(next)
#@+node:ekr.20060106211922: *4* @test p.isCurrentPosition
n = g.app.positions
assert c.isCurrentPosition(None) is False
assert c.isCurrentPosition(p) is True
assert g.app.positions == n
#@+node:ekr.20060106211922.1: *4* @test p.isRootPosition
assert not c.isRootPosition(None),'fail 1'
assert not c.isRootPosition(p),'fail 2'
#@+node:ekr.20040712101754.188: *4* @test p.iters and v.iters
import leo.core.leoNodes as leoNodes

current = c.p
child = current.firstChild()

allList = [p.v for p in c.all_positions_iter()]
vList1 = [v for v in c.p.vnodes_iter()]
vList2 = [v for v in c.p.unique_vnodes_iter()]

if 0:
    for v in vList1: print(v)
    for v in vList2: print(v)

if 0:
    print(len(allList),len(vList1),len(vList2))

if 0: # v.iters no longer exist.
    << tests of consistency of p and v iters >>
<< tests that node iterators return no duplicate nodes >>
<< print nodes returned by iterators >>
#@+node:ekr.20040712101754.189: *5* child1
#@+node:ekr.20040712101754.190: *6* a
#@+node:ekr.20040712101754.191: *7* b
#@+node:ekr.20040712101754.192: *6* c
#@+node:ekr.20040712101754.193: *6* d
#@+node:ekr.20040712101754.194: *7* e
#@+node:ekr.20040712101754.195: *5* child2
#@+node:ekr.20040712101754.196: *5* << tests of consistency of p and v iters >>
try:
    tag = "test1"
    list1 = [v for v in current.vnodes_iter()]
    list2 = [v for v in current.v.self_and_subtree_iter()]
    assert(list1==list2)

    tag = "test2"
    list1 = [p.v for p in c.all_positions_iter()]
    list2 = [v   for v in c.all_vnodes_iter()]
    assert(list1==list2)

    # print("consistency tests pass")

except AssertionError:
    print(tag)
    print("list1")
    for v in list1: print(v)
    print("list2")
    for v in list2: print(v)
    raise
#@+node:ekr.20040712101754.197: *5* << tests that node iterators return no duplicate nodes >>
nodes = []
for v in current.unique_vnodes_iter():
    assert v not in nodes
    nodes.append(v)

nodes = []
for t in current.unique_tnodes_iter():
    assert t not in nodes
    nodes.append(t)

# print("duplicate tests pass")
#@+node:ekr.20040712101754.198: *5* << print nodes returned by iterators >>
if 0:
    for v in current.vnodes_iter(): print(v)
    for v in current.unique_vnodes_iter(): print(v)

if 0: # subtree of root node:
    root = c.rootPosition()
    for v in root.vnodes_iter(): print(v)
    for t in root.tnodes_iter(): print(t)

if 0: # child1's tree.  child2 should not be included.
    for v in child.vnodes_iter(): print(v)
    for t in child.tnodes_iter(): print(t)
#@+node:ekr.20111210104652.3958: *4* @test p.moveToFirst/LastChild
def setup(p):
    while p.hasChildren():
        p.firstChild().doDelete()

child = p.firstChild()
assert child
setup(child)
p2 = child.insertAfter()
p2.h = "test"
try:
    assert c.positionExists(p2),p2
    p2.moveToFirstChildOf(child)
    assert c.positionExists(p2),p2
    p2.moveToLastChildOf(child)
    assert c.positionExists(p2),p2
finally:
    if 1:
        setup(child)
    c.redraw(p)
#@+node:ekr.20111210104652.3959: *5* child
#@+node:ekr.20120212130242.4755: *5* test
#@+node:ekr.20131227150324.3983: *4* @test p.moveToVisBack in a chapter
# Verify a fix for bug https://bugs.launchpad.net/leo-editor/+bug/1264350
if g.app.isExternalUnitTest:
    # There is no @chapter node in the copied file.
    self.skipTest('Can not be run externally') 
else:
    aaa1 = g.findNodeAnywhere(c,'@chapter aaa')
    assert aaa1
    try:
        c.chapterController.selectChapterByName('aaa',collapse=True)
        aaa = c.p
        assert aaa.h == 'aaa node 1',repr(aaa)
        p2 = p.moveToVisBack(c)
        assert p2 is None,p2
    finally:
        c.chapterController.selectChapterByName('main',collapse=True)
#@+node:ekr.20140218045755.4348: *4* @test p.nosentinels
@language python
@tabwidth -4

def not_a_sentinel(x):
    pass
@not_a_sentinel
def spam():
    pass

s1 = ''.join(g.splitLines(p.b) [2:])
s2 = p.nosentinels   
assert s1 == s2,'expected:\n%s\ngot:\n%s' % (s1,s2)
#@+node:ekr.20040802071519: *4* @test p.setBodyString
# Tests that c.setBodyString works immediately.
h = p.h

try:
    w = c.frame.body.wrapper
    child = p.firstChild()
    before = child.b
    after = "after"
    c.setBodyString(child,"after")
    c.selectPosition(child)
    s = w.get("1.0","end")
    assert s.rstrip() == after.rstrip(), 'expected %s, got %s' % (
        repr(after),repr(s))
finally:
    c.setBodyString(child,before)
    c.selectPosition(p)
#@+node:ekr.20040802071519.1: *5* child
before
#@+node:ekr.20160129082128.1: *4* @test p.u
assert p.u == p.v.u, (p.u, p.v.u)
p.v.u = None
assert p.u == {}, p.u
assert p.v.u == {}, p.v.u
d = {'my_plugin': 'val'}
p.u = d
assert p.u == d, (p.u, d)
assert p.v.u == d, (p.v.u, d)
#@+node:ekr.20110502130500.3471: *4* @test p.unique_nodes
aList = [z for z in p.unique_nodes()]
assert len(aList) == 3,len(aList)
v1,v2,v3 = aList
assert v1.h == p.h,p.h
assert v2.h == 'node 1',v2.h
assert v3.h == 'node 2',v3.h
#@+node:ekr.20110502130500.3472: *5* node 1
# Node 1
#@+node:ekr.20110502130500.3473: *6* node 2
# node 3
#@+node:ekr.20100131180007.5391: *4* @test v.atAutoNodeName & v.atAutoRstNodeName
table = (
    ('@auto-rst rst-file','rst-file','rst-file'),
    ('@auto x','x',''),
    ('xyz','',''),
)

for s,expected1,expected2 in table:
    result1 = p.v.atAutoNodeName(h=s)
    result2 = p.v.atAutoRstNodeName(h=s)
    assert result1 == expected1,'fail1: given %s expected %s got %s' % (
        repr(s),repr(expected1),repr(result1))
    assert result2 == expected2,'fail2: given %s expected %s got %s' % (
        repr(s),repr(expected2),repr(result2))
#@+node:ekr.20060913084600: *4* @test v/t.__hash__
import leo.core.leoNodes as leoNodes

if leoNodes.use_zodb:
    p.v.__hash__()
#@+node:ekr.20071113202452: *4* @test zz end of leoNodes tests
# This is **not** a real unit test.
# It simply restores the screen to a more convenient state.

# c.contractParent()
# g.app.unitTestDict['restoreSelectedNode']=False

print('\nEnd of leoNodes tests.')
#@+node:ekr.20080501121449.1: *4* Fundamental node operations (undo operations fail)
#@+node:ekr.20080423110627.2: *5* @test at most one VNode has str_leo_pos attribute
n = 0
for v in c.all_unique_vnodes_iter():
    if hasattr(v,'unknownAttributes'):
        d = v.unknownAttributes
        if d.get('str_leo_pos'):
            n += 1

# print(n)
assert n < 2
#@+node:ekr.20080423110627.3: *5* @test clone and move the clone to the root
# Delete all children.
while p.hasChildren():
    p.firstChild().doDelete(newNode=None)

child = p.insertAsNthChild(0)
c.setHeadString(child,'child') # Force the headline to update.

try:
    assert child, 'no child'
    c.selectPosition(child)
    clone = c.clone()
    assert clone == c.p
    assert clone.h == 'child','fail headstring: %s' % clone.h
    assert child.isCloned(), 'fail 1'
    assert clone.isCloned(), 'fail 2'
    assert child.isCloned(), 'fail 3'
    assert clone.isCloned(), 'fail 4'
    c.undoer.undo()
    assert not child.isCloned(), 'fail 1-a'
    c.undoer.redo()
    assert child.isCloned(),    'fail 1-b'
    c.undoer.undo()
    assert not child.isCloned(), 'fail 1-c'
    c.undoer.redo()
    assert child.isCloned(),    'fail 1-d'
    oldRoot = c.rootPosition()
    clone.moveToRoot(oldRoot=oldRoot) # Does not change child position.
    assert child.isCloned(),    'fail 3-2'
    assert clone.isCloned(),    'fail 4-2'
    assert not clone.parent(),  'fail 5'
    assert not clone.back(),    'fail 6'
    clone.doDelete()
    assert not child.isCloned(), 'fail 7'
finally:
    # Delete all children.
    if 1:
        while p.hasChildren():
            p.firstChild().doDelete(newNode=None)
    c.redraw_now(p)
#@+node:ekr.20080503082625.3: *5* @test delete node
root = p.copy()
while p.hasChildren():
    p.firstChild().doDelete(newNode=None)
try:
    p2 = p.insertAsNthChild(0)
    p2.setHeadString('A')
    p3 = p.insertAsNthChild(1)
    p3.setHeadString('B')
    p4 = p.insertAsNthChild(2)
    p4.setHeadString('C')
    p.expand()
    c.selectPosition(p3)
    # print(c.p.h) # Correct: B
    c.deleteOutline()
    # print(c.p.h) # Should be A. was All unit tests until the hack above.
    c.redraw_now()
    p = c.p
    assert p.h == 'A', 'fail 1: got %s' % p.h
    assert p.next().h == 'C', 'fail 2'
    c.undoer.undo()
    c.outerUpdate()
    p = c.p
    assert p.back() == p2, 'fail 4 %s' % p.back()
    assert p.next() == p4, 'fail 5'
    c.undoer.redo()
    c.outerUpdate()
    p = c.p
    assert p.h == 'A',          'fail 1-2'
    assert p.next().h == 'C',   'fail 2-2'
    c.undoer.undo()
    c.outerUpdate()
    p = c.p
    assert p.back() == p2,  'fail 4-2'
    assert p.next() == p4,  'fail 5-2'
    c.undoer.redo()
    c.outerUpdate()
    p = c.p
    assert p.h == 'A',          'fail 1-3'
    assert p.next().h == 'C',   'fail 2-3'

finally:
    if 1:
        while root.hasChildren():
            root.firstChild().doDelete(newNode=None)
    c.redraw_now(root)
#@+node:ekr.20080423110627.13: *5* @test deleting the root should select another node
# Do not change the root during external unit tests!
if g.app.isExternalUnitTest:
    self.skipTest('Can not be run externally')
else:

    import leo.core.leoNodes as leoNodes
    
    while p.hasChildren():
        p.firstChild().doDelete(newNode=None)
    
    child = p.insertAsNthChild(0)
    child.setHeadString('child')
    
    try:
        oldRoot = c.rootPosition()
        child.moveToRoot(oldRoot=oldRoot) # Does not change child position.
        c.setRootPosition(child)
        assert c.positionExists(child)
        assert c.rootPosition().h == 'child', 'fail 1'
        next = c.rootPosition().next()
        assert next.h == 'Startup', 'fail 2: next: %s' % next
        c.rootPosition().doDelete(newNode=next)
        c.setRootPosition(next)
    finally:
        while p.hasChildren():
            p.firstChild().doDelete(newNode=None)
        # c.selectPosition(p)
        c.redraw_now()
#@+node:ekr.20080503082625.5: *5* @test demote
root = p.copy()
while p.hasChildren():
    p.firstChild().doDelete(newNode=None)

try:
    p2 = p.insertAsNthChild(0)
    p2.setHeadString('A')
    p3 = p.insertAsNthChild(1)
    p3.setHeadString('B')
    p4 = p.insertAsNthChild(2)
    p4.setHeadString('C')
    p5 = p.insertAsNthChild(3)
    p5.setHeadString('D')
    p.expand()
    c.setCurrentPosition(p3)
    c.demote()
    p = c.p
    assert p == p3,         'fail 1'
    assert p.h == 'B',      'fail 2'
    assert not p.next(),    'fail 3'
    assert p.firstChild().h == 'C',          'fail child 1'
    assert p.firstChild().next().h == 'D',   'fail child 2'
    c.undoer.undo()
    p = c.p
    assert p == p3
    assert p.back() == p2, 'fail 5'
    assert p.next() == p4, 'fail 6'
    c.undoer.redo()
    assert p == p3,         'fail 1-2'
    assert p.h == 'B',      'fail 2-2'
    assert not p.next(),    'fail 3-2'
    assert p.firstChild().h == 'C',         'fail child 1-2'
    assert p.firstChild().next().h == 'D',  'fail child 2-2'
    c.undoer.undo()
    p = c.p
    assert p.back() == p2, 'fail 4-2'
    assert p.next() == p4, 'fail 5-2'
    c.undoer.redo()
    assert p == p3,         'fail 1-3'
    assert p.h == 'B',      'fail 2-3'
    assert not p.next(),    'fail 3-3'
    assert p.firstChild().h == 'C',         'fail child 1-3'
    assert p.firstChild().next().h == 'D',  'fail child 2-3'

finally:
    if 1:
        while root.hasChildren():
            root.firstChild().doDelete(newNode=None)
    c.redraw_now(root)
#@+node:ekr.20080501121449.3: *5* @test insert node
assert p.h == '@test insert node',repr(p.h)
root = p.copy()
while p.hasChildren():
    p.firstChild().doDelete(newNode=None)
try:
    assert p.h == '@test insert node',repr(p.h)
    p2 = p.insertAsNthChild(0)
    p2.setHeadString('A')
    p3 = p.insertAsNthChild(1)
    p3.setHeadString('B')
    p.expand()
    c.setCurrentPosition(p2)
    p4 = c.insertHeadline()
    assert p4 == c.p
    p = c.p
    assert p,'no p'
    p.setHeadString('inserted')
    assert p.back(),'no p.back(): %s' % (p)
    assert p.back().h == 'A', 'fail 1'
    assert p.next().h == 'B', 'fail 2'
    c.undoer.undo()
    # With the new undo logic, it takes 2 undoes.
    # The first undo undoes the headline changes,
    # the second undo undoes the insert node.
    if g.app.isExternalUnitTest:
        # The situation is different in a null Gui.
        pass
    else:
        c.undoer.undo() 
    p = c.p
    assert p == p2,         'fail 3:\n p: %s\np2: %s' % (p,p2)
    assert p.next() == p3,  'fail 4'
    c.undoer.redo()
    p = c.p
    assert p.back(),          'fail 0-2'
    assert p.back().h == 'A', 'fail 1-2'
    assert p.next().h == 'B', 'fail 2-2'
    c.undoer.undo()
    p = c.p
    assert p == p2,         'fail 3-2'
    assert p.next() == p3,  'fail 3-2'
    c.undoer.redo()
    p = c.p
    assert p.back().h == 'A', 'fail 1-3'
    assert p.next().h == 'B', 'fail 2-3'
finally:
    if 0:
        while root.hasChildren():
            root.firstChild().doDelete(newNode=None)
    c.redraw_now(root)
#@+node:ekr.20140923083354.6274: *6* A
#@+node:ekr.20140923083354.6276: *6* inserted
#@+node:ekr.20140923083354.6275: *6* B
#@+node:ekr.20080423110627.11: *5* @test move-outline-down & undo/redo
root = p.copy()
while p.hasChildren():
    p.firstChild().doDelete(newNode=None)

try:
    p2 = p.insertAsNthChild(0)
    p2.setHeadString('A')
    p3 = p.insertAsNthChild(1)
    p3.setHeadString('B')
    p4 = p.insertAsNthChild(2)
    p4.setHeadString('C')
    p5 = p.insertAsNthChild(3)
    p5.setHeadString('D')
    p.expand()
    c.setCurrentPosition(p3)
    c.moveOutlineDown()
    moved = c.p
    assert moved.h == 'B',          'fail 1: %s' % moved.h
    assert moved.back().h == 'C',   'fail 2'
    assert moved.next().h == 'D',   'fail 3'
    # This assert fails because p4._childIndex != moved.back()._childIndex.
    # assert moved.back() == p4, 'fail 4: %s != %s' % (moved.back(),p4)
    assert moved.next() == p5,      'fail 5: %s != %s' % (moved.next(),p5)
    c.undoer.undo()
    moved = c.p
    assert moved.back() == p2,      'fail 4'
    assert moved.next() == p4,      'fail 5'
    c.undoer.redo()
    moved = c.p
    assert moved.h == 'B',          'fail 1-2: %s' % moved.h
    assert moved.back().h == 'C',   'fail 2-2'
    assert moved.next().h == 'D',   'fail 3-2'
    c.undoer.undo()
    moved = c.p
    assert moved.back() == p2,      'fail 4-2'
    assert moved.next() == p4,      'fail 5-2'
    c.undoer.redo()
    moved = c.p
    assert moved.h == 'B',          'fail 1-3'
    assert moved.back().h == 'C',   'fail 2-3'
    assert moved.next().h == 'D',   'fail 3-3'

finally:
    if 1:
        while root.hasChildren():
            root.firstChild().doDelete(newNode=None)
    c.redraw_now(root)
#@+node:ekr.20080503073030.1: *5* @test move-outline-left
while p.hasChildren():
    p.firstChild().doDelete(newNode=None)

try:
    p2 = p.insertAsNthChild(0)
    p2.setHeadString('A')
    p.expand()
    c.setCurrentPosition(p2)
    c.moveOutlineLeft()
    moved = c.p
    assert moved.h == 'A','fail 1'
    # This assert fails because p4._childIndex != moved.back()._childIndex.
    assert moved.back() == p, 'fail 2: %s != %s' % (moved.back(),p4)
    c.undoer.undo()
    c.undoer.redo()
    c.undoer.undo()
    c.undoer.redo()

    moved.doDelete(newNode=p)

finally:
    if 1:
        while p.hasChildren():
            p.firstChild().doDelete(newNode=None)
        c.redraw_now(p)
#@+node:ekr.20080503073030.2: *5* @test move-outline-right
while p.hasChildren():
    p.firstChild().doDelete(newNode=None)

try:
    p2 = p.insertAsNthChild(0)
    p2.setHeadString('A')
    p3 = p.insertAsNthChild(1)
    p3.setHeadString('B')
    p4 = p.insertAsNthChild(2)
    p4.setHeadString('C')
    p.expand()
    c.setCurrentPosition(p3)
    c.moveOutlineRight()
    moved = c.p
    assert moved.h == 'B', 'fail 1'
    assert moved.parent() == p2
    c.undoer.undo()
    c.undoer.redo()
    c.undoer.undo()
    c.undoer.redo()
finally:
    if 1:
        while p.hasChildren():
            p.firstChild().doDelete(newNode=None)
    if 1:
        c.redraw_now(p)
#@+node:ekr.20080423110627.12: *5* @test move-outline-up
while p.hasChildren():
    p.firstChild().doDelete(newNode=None)

try:
    p2 = p.insertAsNthChild(0)
    p2.setHeadString('A')
    p3 = p.insertAsNthChild(1)
    p3.setHeadString('B')
    p4 = p.insertAsNthChild(2)
    p4.setHeadString('C')
    p5 = p.insertAsNthChild(3)
    p5.setHeadString('D')
    p.expand()
    c.setCurrentPosition(p4)
    c.moveOutlineUp()
    moved = c.p
    assert moved.h == 'C',          'fail 1'
    assert moved.back().h == 'A',   'fail 2'
    assert moved.next().h == 'B',   'fail 3'
    assert moved.back() == p2,      'fail 4: %s != %s' % (moved.back(),p2)
    # This assert fails because p4._childIndex != moved.back()._childIndex.
    # assert moved.next() == p3,    'fail 5: %s != %s' % (moved.next(),p3)
    c.undoer.undo()
    c.undoer.redo()
    c.undoer.undo()
    c.undoer.redo()
finally:
    if 1:
        while p.hasChildren():
            p.firstChild().doDelete(newNode=None)
    if 1:
        c.redraw_now(p)
#@+node:ekr.20080423110627.5: *5* @test paste-node
while p.hasChildren():
    p.firstChild().doDelete(newNode=None)

child = p.insertAsNthChild(0)
child.setHeadString('child')
child2 = p.insertAsNthChild(1)
child2.setHeadString('child2')
grandChild = child.insertAsNthChild(0)
grandChild.setHeadString('grand child')
c.selectPosition(grandChild)
c.clone()
c.selectPosition(child)

try:
    p.expand()
    c.selectPosition(child)
    assert c.p.h == 'child','fail 1'
    c.copyOutline()
    oldVnodes = [p2.v for p2 in child.self_and_subtree()]
    c.selectPosition(child)
    c.p.contract() # Essential
    c.pasteOutline()
    assert c.p != child, 'fail 2'
    assert c.p.h == 'child','fail 3'
    newVnodes = [p2.v for p2 in c.p.self_and_subtree()]
    for v in newVnodes:
        assert v not in oldVnodes, 'fail 4'
    c.undoer.undo()
    c.undoer.redo()
    c.undoer.undo()
    c.undoer.redo()

finally:
    if 1:
        while p.hasChildren():
            p.firstChild().doDelete(newNode=None)
    if 1:
        c.redraw_now(p)
#@+node:ekr.20080423110627.8: *5* @test paste-retaining-clones
while p.hasChildren():
    p.firstChild().doDelete(newNode=None)

child = p.insertAsNthChild(0)
child.setHeadString('child')
assert child, 'no child'
grandChild = child.insertAsNthChild(0)
grandChild.setHeadString('grand child')

try:
    c.selectPosition(child)
    c.copyOutline()
    oldVnodes = [p2.v for p2 in child.self_and_subtree()]
    c.p.contract() # Essential
    c.pasteOutlineRetainingClones()
    assert c.p != child, 'fail 2'
    newVnodes = [p2.v for p2 in c.p.self_and_subtree()]
    for v in newVnodes:
        assert v in oldVnodes, 'fail 3'
finally:
    if 1:
        while p.hasChildren():
            p.firstChild().doDelete(newNode=None)
    if 1:
        c.redraw_now(p)
#@+node:ekr.20080503082625.4: *5* @test promote
root = p.copy()
while p.hasChildren():
    p.firstChild().doDelete(newNode=None)

try:
    p2 = p.insertAsNthChild(0)
    p2.setHeadString('A')
    p3 = p.insertAsNthChild(1)
    p3.setHeadString('B')
    p4 = p3.insertAsNthChild(0)
    p4.setHeadString('child 1')
    p5 = p3.insertAsNthChild(1)
    p5.setHeadString('child 2')
    p.expand()
    p6 = p.insertAsNthChild(2)
    p6.setHeadString('C')
    c.setCurrentPosition(p3)
    c.promote()
    p = c.p
    assert p == p3,         'fail 1'
    assert p.h == 'B',      'fail 2'
    assert p.next().h=='child 1',            'fail 3'
    assert p.next().next().h == 'child 2',   'fail child 1'
    assert p.next().next().next().h == 'C',  'fail child 2'
    c.undoer.undo()
    p = c.p
    assert p == p3
    assert p.back() == p2,  'fail 5'
    assert p.next() == p6,  'fail 6'
    assert p.firstChild().h=='child 1',          'fail child 3'
    assert p.firstChild().next().h == 'child 2', 'fail child 4'
    c.undoer.redo()
    p = c.p
    assert p == p3,         'fail 1-2'
    assert p.h == 'B',      'fail 2-2'
    assert p.next().h=='child 1',            'fail 3-2'
    assert p.next().next().h == 'child 2',   'fail child 1-2'
    assert p.next().next().next().h == 'C',  'fail child 2-2'
    c.undoer.undo()
    p = c.p
    assert p == p3
    assert p.back() == p2,                      'fail 5-2'
    assert p.next() == p6,                      'fail 6-2'
    assert p.firstChild().h=='child 1',         'fail child 3-2'
    assert p.firstChild().next().h == 'child 2','fail child 4-2'
    c.undoer.redo()
    p = c.p
    assert p == p3,     'fail 1-3'
    assert p.h == 'B',  'fail 2-3'
    assert p.next().h=='child 1',            'fail 3-3'
    assert p.next().next().h == 'child 2',   'fail child 1-3'
    assert p.next().next().next().h == 'C',  'fail child 2-3'

finally:
    if 1:
        while root.hasChildren():
            root.firstChild().doDelete(newNode=None)
    c.redraw_now(root)
#@+node:ekr.20081001094920.2: *4* tests for p.textOffset()
#@+node:ekr.20081001094920.3: *5* @test node that doesn't belong to a derived file
# Change @file activeUnitTests.txt to @@file activeUnitTests.txt
for parent in p.parents():
    if parent.isAnyAtFileNode():
        parent.h = '@' + parent.h
        break
else:
    parent = None
root = p.copy()
while p.hasChildren():
    p.firstChild().doDelete(newNode=None)
try:
    p1 = p.insertAsLastChild()
    assert p1.textOffset() is None
finally:
    if 1:
        while root.hasChildren():
            root.firstChild().doDelete(newNode=None)
    if parent:
        parent.h = parent.h[1:]
    c.redraw_now()
#@+node:ekr.20081001094920.4: *5* @test root of a derived file
root = p.copy()
while p.hasChildren():
    p.firstChild().doDelete(newNode=None)
try:
    p1 = p.insertAsLastChild()
    p1.setHeadString('@file zzz')
    assert p1.textOffset() == 0
finally:
    if 1:
        while root.hasChildren():
            root.firstChild().doDelete(newNode=None)
    c.redraw_now()
#@+node:ekr.20081001094920.5: *5* @test organizer node
root = p.copy()
while p.hasChildren():
    p.firstChild().doDelete(newNode=None)
try:
    p1 = p.insertAsLastChild()
    p1.setHeadString('@file zzz')
    p2 = p1.insertAsLastChild()
    assert p1.textOffset() == 0
    assert p2.textOffset() == 0
finally:
    if 1:
        while root.hasChildren():
            root.firstChild().doDelete(newNode=None)
    c.redraw_now()
#@+node:ekr.20081001094920.6: *5* @test section node
root = p.copy()
while p.hasChildren():
    p.firstChild().doDelete(newNode=None)
try:
    p1 = p.insertAsLastChild()
    p1.setHeadString('@file zzz')
    body = '''   %s
    ''' % (g.angleBrackets(' section '))
    p1.setBodyString(body)
    p2 = p1.insertAsLastChild()
    head = g.angleBrackets(' section ')
    p2.setHeadString(head)
    assert p1.textOffset() == 0
    assert p2.textOffset() == 3
        # Section nodes can appear in with @others nodes,
        # so they don't get special treatment.
finally:
    if 1:
        while root.hasChildren():
            root.firstChild().doDelete(newNode=None)
    c.redraw_now()
#@+node:ekr.20081001094920.7: *5* @test "others" directive
root = p.copy()
while p.hasChildren():
    p.firstChild().doDelete(newNode=None)
try:
    p1 = p.insertAsLastChild()
    p1.setHeadString('@file zzz')
    body = '''     %s
    ''' % (chr(64) + 'others') # ugly hack
    p1.setBodyString(body)
    p2 = p1.insertAsLastChild()
    assert p1.textOffset() == 0
    assert p2.textOffset() == 5
    root.firstChild().doDelete(newNode=None)
finally:
    if 1:
        while root.hasChildren():
            root.firstChild().doDelete(newNode=None)
    c.redraw_now()
#@+node:ekr.20140712142620.4458: *3* leoPersistence tests (do not clone)
#@+node:ekr.20140712142620.4537: *4* @@@test pd.find_absolute_unl_node
pd = c.persistenceController
root = c.rootPosition().insertAfter()
root.h = 'root'
child1 = root.insertAsLastChild()
child1.h = 'child1'
child2 = child1.insertAfter()
child2.h = 'child2'
child11 = child1.insertAsLastChild()
child11.h = 'child11'
try:
    for unl in ('root','root-->child1','root-->child2','root-->child1-->child11'):
        p = pd.find_absolute_unl_node(unl)
        parts = unl.split('-->')
        assert p,unl
        assert p.h == parts[-1],p.h
finally:
    root.doDelete()
    c.selectPosition(p)
    c.redraw()
#@+node:ekr.20140712142620.4583: *4* @@@test pd.pack & pd.unpack
# At present, neither the pack nor the unpack commands exist.
pd = c.persistenceController
persistence = pd.find_at_persistence_node()
assert persistence
persistence.deleteAllChildren()
view = g.findNodeInTree(c,p,'@view test')
assert view
assert c.positionExists(view)
try:
    c.selectPosition(view)
    v_b = view.b
    pd.pack()
    assert c.p.v == view.v
    pd.unpack()
    assert view.b == v_b,view.b
    assert view.lastChild().isCloned()
finally:
    # views.deleteAllChildren()
    c.undoer.clearUndoState()
    c.redraw()
#@+node:ekr.20140712142620.4587: *5* clone
clone body
#@+node:ekr.20140712142620.4585: *5* @view test
view body
#@+node:ekr.20140712142620.4586: *6* not a clone
not a clone text
#@+node:ekr.20140712142620.4587: *6* clone
clone body
#@+node:ekr.20140712142620.4503: *4* @test p.sort_key
aList = [p.copy() for p in c.all_positions()]
aList2 = sorted(reversed(aList),key=p.sort_key)
i = 0
for p in aList2:
    p2 = aList[i]
    i += 1
    assert p == p2,'\n%s:%s\n%s:%s' % (
        p.sort_key(p),p.h,p2.sort_key(p2),p2.h)
#@+node:ekr.20140712142620.4550: *4* @test pd.find_at_...
# Also a test of find_at_views_node, find_at_organizers_node and find_at_clones_node.
import sys
if sys.platform.startswith('linux'):
    self.skipTest('linux test')
else:
    pd = c.persistenceController
    root = g.findNodeInTree(c,p,'root')
    assert root
    try:
        persistence = pd.find_at_persistence_node()
        assert persistence
        persistence.deleteAllChildren()
        root.h = '@auto root' # Make root look like an @auto node.
        assert pd.find_at_data_node(root)
        assert pd.find_at_gnxs_node(root)
    finally:
        root.h = 'root' # Make sure root is *not* an @auto node.
        # views.deleteAllChildren()
        c.selectPosition(p)
        c.redraw()
#@+node:ekr.20140712142620.4551: *5* root
#@+node:ekr.20140712142620.4552: *6* aClass
class aClass:
    @others
#@+node:ekr.20140712142620.4556: *7* clone
#@+node:ekr.20140712142620.4556: *5* clone
#@+node:ekr.20140712142620.4538: *4* @test pd.find_at_persistence_node
import sys
if sys.platform.startswith('linux'):
    self.skipTest('linux test')
else:
    pd = c.persistenceController
    h = '@persistence'
    p1 = pd.find_at_persistence_node()
    assert p1
    p2 = pd.has_at_persistence_node()
    assert p1 == p2,(p1,p2)
#@+node:ekr.20140712142620.4539: *4* @test pd.find_position_for_relative_unl
pd = c.persistenceController
parent = p.copy()
node1 = p.firstChild()
node2 = node1.next()
node3 = node2.next()
assert node1 and node2 and node3
child11 = node1.firstChild()
child12 = child11.next()
assert child11 and child12
child21 = node2.firstChild()
child22 = child21.next()
assert child21 and child22
node3_child1 = node3.firstChild()
assert node3_child1
node3_child1_child21 = node3_child1.firstChild()
assert node3_child1_child21
table = (
    ('node1',node1),
    ('',parent), # This special case is important.
    ('node1-->child11',child11),
    ('node1-->child12',child12),
    ('node2',node2),
    ('node2-->child21',child21),
    ('node2-->child22',child22),
    # Partial matches.
    ### ('node3-->child1-->child21',node3_child1_child21),
    ### ('child1-->child21',node3_child1_child21),
    ### ('xxx-->child21',node3_child1_child21),
        # This is ambiguous.
    # No matches.
    ('nodex',None),
    ('node1-->childx',None),
    ('node3-->childx',None),
)
for unl,expected in table:
    got = pd.find_position_for_relative_unl(parent,unl)
    assert got == expected,'unl: %s expected: %s got: %s' % (
        unl,expected and expected.h,got and got.h)
#@+node:ekr.20140712142620.4540: *5* node1
#@+node:ekr.20140712142620.4541: *6* child11
#@+node:ekr.20140712142620.4542: *6* child12
#@+node:ekr.20140712142620.4543: *5* node2
#@+node:ekr.20140712142620.4544: *6* child21
#@+node:ekr.20140712142620.4545: *6* child22
#@+node:ekr.20140715080507.4340: *5* node3
#@+node:ekr.20140715080507.4341: *6* node3_child1
#@+node:ekr.20140715080507.4339: *7* child21
#@+node:ekr.20140712142620.4546: *4* @test pd.find_representative_node
if g.app.isExternalUnitTest:
    # There will not be a proper cloned node in the copy of these tests.
    self.skipTest('Can not be run externally')
else:
    pd = c.persistenceController
    root = g.findNodeInTree(c,p,'root')
    assert root
    root.h = '@auto root'
    try:
        clone = root.next()
        assert clone and clone.h == 'clone'
        inner_clone = root.firstChild()
        assert inner_clone
        assert clone.v == inner_clone.v
        rep = pd.find_representative_node(root,inner_clone)
        # Careful: cloning this test can cause problems.
        oops = '\n  rep: %s\nparent:%s\nclone: %s\nparent:%s\ninner: %s\nparent: %s' % (
            rep,rep.parent(),clone,clone.parent(),inner_clone,inner_clone.parent())
        if g.app.isExternalUnitTest:
            pass
        else:
            assert rep == clone,(repr(rep),repr(clone))
    finally:
        root.h = 'root' # root must not be an @auto node.
        c.redraw()
#@+node:ekr.20140712142620.4547: *5* root
#@+node:ekr.20140712142620.4549: *6* clone
#@+node:ekr.20140712142620.4549: *5* clone
#@+node:ekr.20140712142620.4557: *4* @test pd.has_..._node
import sys
if sys.platform.startswith('linux'):
    self.skipTest('linux test')
else:
    # Test pd.has_at_auto_view_node, pd.has_at_clones_node and pd.has_at_organizers_node.
    pd = c.persistenceController
    persistence = g.findNodeAnywhere(c,'@persistence')
    assert persistence
    assert pd.has_at_persistence_node()
    persistence.deleteAllChildren()
    assert persistence
    root = g.findNodeInTree(c,p,'root')
    assert root
    # The representative of clone_test node must appear outside of root's tree.
    clone_test = g.findNodeInTree(c,p,'clone-test')
    if g.app.isExternalUnitTest:
        # There will not be a proper node in the copied tree.
        self.skipTest('Can not be run externally')
    else:
        assert clone_test
        assert clone_test.v == root.next().v,(clone_test.v,root.next().v)
        try:
            root.h = '@auto root' # Make root look like an @auto node.
            pd.update_before_write_foreign_file(root)
            data = g.findNodeInTree(c,persistence,'@data:@auto root')
            assert data
            data2 = pd.has_at_data_node(root)
            assert data2
            assert data == data2,(data,data2)
            gnxs = g.findNodeInTree(c,persistence,'@gnxs')
            assert gnxs
            gnxs2 = pd.has_at_gnxs_node(root)
            assert gnxs2
            assert gnxs == gnxs2,(gnxs,gnxs2)
        finally:
            root.h = 'root' # Make the root *not* an @auto node.
            c.redraw()
#@+node:ekr.20140712142620.4558: *5* root
@others
#@+node:ekr.20140712142620.4559: *6* aClass
class aClass:
    @others
#@+node:ekr.20140712142620.4563: *7* clone-test
def clone_test():
    pass
#@+node:ekr.20140712142620.4561: *7* organizer node
#@+node:ekr.20140712142620.4562: *8* child2
def spam():
    pass
#@+node:ekr.20140712142620.4563: *5* clone-test
def clone_test():
    pass
#@+node:ekr.20170302110925.1: *4* @@test pd.prepass
# This was part of the ill-fated leoViews project.
import sys
if sys.platform.startswith('linux'):
    self.skipTest('linux test')
else:
    pd = c.persistenceController
    h = '@persistence'
    p1 = pd.find_at_persistence_node()
    assert p1
    p2 = pd.has_at_persistence_node()
    assert p1 == p2,(p1,p2)
    print(p1.h)
    pd.prepass(p2)
#@+node:ekr.20140716115306.4345: *4* @@test pd.recovery_ua_for_gnx
pd = c.persistenceController
at_persistence = pd.find_at_persistence_node()
assert at_persistence
at_persistence.deleteAllChildren()
root = at_persistence.insertAsLastChild()
root.h = 'test root'
root.b = root.gnx
at_data = pd.find_at_data_node(root)
assert at_data
try:
    at_uas = at_data.insertAsLastChild()
    at_uas.h = '@uas'
    at_ua = at_uas.insertAsLastChild()
    at_ua.h = '@ua:dummy-gnx'
    at_ua.b = 'unl:dummy-unl\nua:dummy-ua'
    at_recovery = pd.find_at_recovery_node(root)
    if at_recovery:
        at_recovery.deleteAllChildren()
    pd.recover_ua_for_gnx('dummy-gnx',root,'dummy-unl')
    assert at_recovery
    at_ua2 = g.findNodeInTree(c,at_recovery,'@ua:dummy-gnx')
    assert at_ua2
    assert at_ua2.h == at_ua.h
    assert at_ua2.b == at_ua.b,repr(at_ua2.b)
finally:
    pass # root.doDelete()

#@+node:ekr.20140712142620.4507: *4* @test pd.restore_gnxs
pd = c.persistenceController
gnxs = g.findNodeInTree(c,p,'@gnxs')
root = g.findNodeInTree(c,p,'root')
node1 = g.findNodeInTree(c,p,'node1')
assert gnxs and root and node1
root.deleteAllChildren()
new_node1 = root.insertAsLastChild()
new_node1.h = 'node1'
gnxs.b = 'gnx: %s\nunl: %s\n' % (node1.v.gnx,'node1')
try:
    pd.restore_gnxs(gnxs,root)
    # Important: p._relinkAsCloneOf leaves new_node1 unchanged,
    # but new_node1 should not be used.
finally:
    c.redraw()
#@+node:ekr.20140712142620.4508: *5* @gnxs
gnx: ekr.20140923080452.6565
unl: node1
#@+node:ekr.20140923080452.6565: *5* node1
#@+node:ekr.20140712142620.4510: *5* root
#@+node:ekr.20140923080452.6565: *6* node1
#@+node:ekr.20140712142620.4574: *4* @test pd.unl
pd = c.persistenceController
unl = pd.unl(p)
expected = p.h if g.app.isExternalUnitTest else '-->'+p.h
assert unl.endswith(expected),repr(unl)
#@+node:ekr.20140712142620.4575: *4* @test pd.update_before_write_foreign_file
import sys
if sys.platform.startswith('linux'):
    self.skipTest('linux test')
else:
    pd = c.persistenceController
    root = g.findNodeInTree(c,p,'root')
    assert root
    persistence = pd.find_at_persistence_node()
    assert persistence
    persistence.deleteAllChildren()
    try:
        root.h = '@auto root' # Make root look like an @auto node.
        pd.update_before_write_foreign_file(root)
        data = g.findNodeAnywhere(c,'@data:@auto root')
        assert data
        gnxs = g.findNodeInTree(c,data,'@gnxs')
        assert gnxs
    finally:
        root.h = 'root' # Make root *not* an @auto node.
        # persistence.deleteAllChildren()
        c.redraw()
#@+node:ekr.20140712142620.4576: *5* root
#@+node:ekr.20140712142620.4577: *6* aClass
class aClass:
    @others
#@+node:ekr.20140712142620.4582: *7* clone
#@+node:ekr.20140712142620.4579: *6* organizer node
#@+node:ekr.20140712142620.4580: *7* child1
#@+node:ekr.20140712142620.4581: *7* child2
def spam():
    pass
#@+node:ekr.20140712142620.4582: *5* clone
#@+node:ekr.20150216111306.25: *4* @test delete all children of @persistence node
import sys
if sys.platform.startswith('linux'):
    self.skipTest('linux test')
else:
    pd = c.persistenceController
    persistence = g.findNodeAnywhere(c,'@persistence')
    assert persistence
    assert pd.has_at_persistence_node()
    persistence.deleteAllChildren()
    assert persistence
#@+node:ekr.20100131171342.5610: *3* leoPlugins
#@+node:ekr.20100131171342.5611: *4* @test getHandlersForTag
pc = g.app.pluginsController

aList1 = pc.getHandlersForTag('select1')
aList2 = pc.getHandlersForOneTag('select1')

assert type(aList1) == type([])
assert type(aList2) == type([])
assert aList1 == aList2
#@+node:ekr.20100909082308.5990: *4* @test regularizeName
pc = g.app.pluginsController

table = (
    ('x',               'x'),
    ('foo.bar',         'foo.bar'),
    ('x.py',            'leo.plugins.x'),
    ('leo.plugins.x',   'leo.plugins.x')    
)

for fn,expected in table:
    result = pc.regularizeName(fn)
    assert result==expected,'expected %s, got %s' % (
        expected,result)
    # Make sure that calling regularizeName twice is benign.
    result2 = pc.regularizeName(result)
    assert result2==result
#@+node:ekr.20091219122958.5066: *3* leoRst
# Warning: these depend on the .css files in leo\test\unittest.
#@+node:ekr.20100813100841.5825: *4* @@@test show_doc_parts_in_rst_mode
# Applies to options doc parts as well.
#@+node:ekr.20100813100841.5847: *4* @ignore
#@+node:ekr.20100812213445.5824: *5* @test code_mode: rst3 show_doc_parts_as_paragraphs
exec(g.findTestScript(c,'@common leoRst test code'))

rst3Test(c,p)
#@+node:ekr.20100812213445.5825: *6* source
@language rest
#@+node:ekr.20100812213445.5826: *7* @rst test.html
@ @rst-options
show_doc_parts_as_paragraphs=True
@c
#####
Title
#####

This is test.html
#@+node:ekr.20100812213445.5827: *8* section
@ This is a doc part
it has two lines.
@c
This is the body of the section.
#@+node:ekr.20100812213445.5828: *6* expected
@language html
#@+node:ekr.20100813100841.5843: *7* rst
.. rst3: filename: test.html


#####
Title
#####

This is test.html

section
+++++++

@ This is a doc part
it has two lines.
@c

This is the body of the section.

#@+node:ekr.20100813100841.5844: *7*  html
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="generator" content="Docutils 0.8: http://docutils.sourceforge.net/" />
<title>Title</title>
<style type="text/css">

/*ORIGINAL GOODGER + changes; up to line 224 it's standard reST stylesheet
:Author: David Goodger
:Contact: goodger@users.sourceforge.net
:date: $Date: 2006/10/19 13:23:15 $
:version: $Revision: 1.2 $
:copyright: This stylesheet has been placed in the public domain.

Default cascading style sheet for the HTML output of Docutils.
*/

/* EKR 10/19/06 */
/* some browsers require imported rules to precede all rulesets */
@import url(leo_rst.css);
@import url(silver_city.css);

.first {
  margin-top: 0 }

.last {
  margin-bottom: 0 }

a.toc-backref {
  text-decoration: none ;
  color: black }

dd {
  margin-bottom: 0.5em }

div.abstract {
  margin: 2em 5em }

div.abstract p.topic-title {
  font-weight: bold ;
  text-align: center }

div.attention, div.caution, div.danger, div.error, div.hint,
div.important, div.note, div.tip, div.warning, div.admonition {
  margin: 2em ;
  border: medium outset ;
  padding: 1em }

div.attention p.admonition-title, div.caution p.admonition-title,
div.danger p.admonition-title, div.error p.admonition-title,
div.warning p.admonition-title {
  color: red ;
  font-weight: bold ;
  font-family: sans-serif }

div.hint p.admonition-title, div.important p.admonition-title,
div.note p.admonition-title, div.tip p.admonition-title,
div.admonition p.admonition-title {
  font-weight: bold ;
  font-family: sans-serif }

div.dedication {
  margin: 2em 5em ;
  text-align: center ;
  font-style: italic }

div.dedication p.topic-title {
  font-weight: bold ;
  font-style: normal }

div.figure {
  margin-left: 2em }

div.footer, div.header {
  font-size: smaller }

div.sidebar {
  margin-left: 1em ;
  border: medium outset ;
  padding: 0em 1em ;
  background-color: #ffffee ;
  width: 40% ;
  float: right ;
  clear: right }

div.sidebar p.rubric {
  font-family: sans-serif ;
  font-size: medium }

div.system-messages {
  margin: 5em }

div.system-messages h1 {
  color: red }

div.system-message {
  border: medium outset ;
  padding: 1em }

div.system-message p.system-message-title {
  color: red ;
  font-weight: bold }

div.topic {
  margin: 2em }

h1.title {
  text-align: center }

h2.subtitle {
  text-align: center }

ol.simple, ul.simple {
  margin-bottom: 1em }

ol.arabic {
  list-style: decimal }

ol.loweralpha {
  list-style: lower-alpha }

ol.upperalpha {
  list-style: upper-alpha }

ol.lowerroman {
  list-style: lower-roman }

ol.upperroman {
  list-style: upper-roman }

p.attribution {
  text-align: right ;
  margin-left: 50% }

p.caption {
  font-style: italic }

p.credits {
  font-style: italic ;
  font-size: smaller }

p.label {
  white-space: nowrap }

p.rubric {
  font-weight: bold ;
  font-size: larger ;
  color: maroon ;
  text-align: center }

p.sidebar-title {
  font-family: sans-serif ;
  font-weight: bold ;
  font-size: larger }

p.sidebar-subtitle {
  font-family: sans-serif ;
  font-weight: bold }

p.topic-title {
  font-weight: bold }

pre.address {
  margin-bottom: 0 ;
  margin-top: 0 ;
  font-family: serif ;
  font-size: 100% }

pre.line-block {
  font-family: serif ;
  font-size: 100% }

pre.literal-block, pre.doctest-block {
  margin-left: 2em ;
  margin-right: 2em ;}
  /*background-color: #eeeeee }*/
  /*for some reason i can't overide in an import*/

span.classifier {
  font-family: sans-serif ;
  font-style: oblique }

span.classifier-delimiter {
  font-family: sans-serif ;
  font-weight: bold }

span.interpreted {
  font-family: sans-serif }

span.option {
  white-space: nowrap }

span.option-argument {
  font-style: italic }

span.pre {
  white-space: pre }

span.problematic {
  color: red }

table {
  margin-top: 0.5em ;
  margin-bottom: 0.5em }

table.citation {
  border-left: solid thin gray ;
  padding-left: 0.5ex }

table.docinfo {
  margin: 2em 4em }

table.footnote {
  border-left: solid thin black ;
  padding-left: 0.5ex }

td, th {
  padding-left: 0.5em ;
  padding-right: 0.5em ;
  vertical-align: top }

th.docinfo-name, th.field-name {
  font-weight: bold ;
  text-align: left ;
  white-space: nowrap }

h1 tt, h2 tt, h3 tt, h4 tt, h5 tt, h6 tt {
  font-size: 100% }

/*for some reason, the following isn't being overridden by the imports
at the end of this style sheet so I've commented it out*/
/*tt {
  background-color: #eeeeee }*/

ul.auto-toc {
  list-style-type: none }

hr { /* EKR */
  width: 100%;
  height: 1pt;
  color: gray;
}



</style>
</head>
<body>
<div class="document" id="title">
<h1 class="title">Title</h1>

<!-- rst3: filename: test.html -->
<p>This is test.html</p>
<div class="section" id="section">
<h1>section</h1>
<p>&#64; This is a doc part
it has two lines.
&#64;c</p>
<p>This is the body of the section.</p>
</div>
</div>
</body>
</html>
#@+node:ekr.20100813100841.5827: *5* @test code_mode: show_leo_directives
#@+node:ekr.20100813100841.5828: *5* @test code_mode: show_markup_doc_parts
#@+node:ekr.20100813100841.5829: *5* @test code_mode: show_options_doc_parts
#@+node:ekr.20091219121039.5065: *4* @test c.rstCommands.handleMissingStyleSheetArgs
x = c.rstCommands
result = x.handleMissingStyleSheetArgs(p,s=None)
assert result == {},'expected {}, got %s' % result
expected = {
    'documentoptions':'[english,12pt,lettersize]',
    'language':'ca',
    'use-latex-toc':'1',
}
for s in (
    '--language=ca, --use-latex-toc,--documentoptions=[english,12pt,lettersize]',
    '--documentoptions=[english,12pt,lettersize],--language=ca, --use-latex-toc',
    '--use-latex-toc,--documentoptions=[english,12pt,lettersize],--language=ca, ',
):
    result = x.handleMissingStyleSheetArgs(p,s=s)
    assert result == expected,'expected %s\ngot %s' % (expected,result)
#@+node:ekr.20111103213154.3823: *4* @test c.rstCommands.writeToDocutils: pdf
@first # -*- coding: utf-8 -*-
@encoding utf-8

'''Test the interface between docutils and leo_pdf.py.
No file is written.
'''

try:
    import docutils
    import reportlab.platypus
except ImportError:
    # print('skipping test')
    docutils = None

if docutils:
    path = g.os_path_finalize_join(g.app.loadDir,'..','plugins')
    module = g.importFromPath(
        moduleName='leo_pdf',
        path=path,
        verbose = False)

    assert module
    s = '''This is a test.'''
    result = c.rstCommands.writeToDocutils(p,s,'.pdf')
    # print(result)
    assert result,result
elif 0:
    print('no docutils')
#@+node:ekr.20100131180007.5459: *4* @test rst.initAtAutoWrite
rst = c.rstCommands
rst.initAtAutoWrite(p,fileName='<test file>',outputFile=None)

# Ensure we are actually testing the default logic.
d = p.v.u.get('rst-import',{})
underlines = d.get('underline_characters')
assert underlines is None,'fail 1: %s' % repr(underlines)
assert d == {},'fail 2: %s' % repr(d)
# Now test the logic.
assert rst.underlines2 == '','fail 3: %s' % repr(rst.underlines2)
assert rst.underlines1 == '=+*^~"\'`-:><_', 'fail4 %s' % repr(rst.underlines1)
assert rst.atAutoWriteUnderlines == '=+*^~"\'`-:><_', 'fail 5: %s' % (
    repr(rst.atAutoWriteUnderlines))
#@+node:ekr.20100813100841.5850: *4* @test rst3Test @no-head
s = g.findTestScript(c,'@common leoRst test code',warn=False)
if s:
    exec(s)
    rst3Test(c,p)
#@+node:ekr.20100813100841.5854: *5* source
@language rest
#@+node:ekr.20100813100841.5855: *6* @rst test.html
@language rest

#####
Title
#####

This is test.html
#@+node:ekr.20100813100841.5856: *7* @rst-no-head section
This is the body of the section.
#@+node:ekr.20100813100841.5857: *5* expected
#@+node:ekr.20100813100841.5858: *6* rst
.. rst3: filename: test.html


#####
Title
#####

This is test.html

This is the body of the section.

#@+node:ekr.20100813100841.5859: *6* html
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="generator" content="Docutils VER: http://docutils.sourceforge.net/" />
<title>Title</title>
<style type="text/css">

/*ORIGINAL GOODGER + changes; up to line 224 it's standard reST stylesheet
:Author: David Goodger
:Contact: goodger@users.sourceforge.net
:date: $Date: 2006/10/19 13:23:15 $
:version: $Revision: 1.2 $
:copyright: This stylesheet has been placed in the public domain.

Default cascading style sheet for the HTML output of Docutils.
*/

/* EKR 10/19/06 */
/* some browsers require imported rules to precede all rulesets */
@import url(leo_rst.css);
@import url(silver_city.css);

.first {
  margin-top: 0 }

.last {
  margin-bottom: 0 }

a.toc-backref {
  text-decoration: none ;
  color: black }

dd {
  margin-bottom: 0.5em }

div.abstract {
  margin: 2em 5em }

div.abstract p.topic-title {
  font-weight: bold ;
  text-align: center }

div.attention, div.caution, div.danger, div.error, div.hint,
div.important, div.note, div.tip, div.warning, div.admonition {
  margin: 2em ;
  border: medium outset ;
  padding: 1em }

div.attention p.admonition-title, div.caution p.admonition-title,
div.danger p.admonition-title, div.error p.admonition-title,
div.warning p.admonition-title {
  color: red ;
  font-weight: bold ;
  font-family: sans-serif }

div.hint p.admonition-title, div.important p.admonition-title,
div.note p.admonition-title, div.tip p.admonition-title,
div.admonition p.admonition-title {
  font-weight: bold ;
  font-family: sans-serif }

div.dedication {
  margin: 2em 5em ;
  text-align: center ;
  font-style: italic }

div.dedication p.topic-title {
  font-weight: bold ;
  font-style: normal }

div.figure {
  margin-left: 2em }

div.footer, div.header {
  font-size: smaller }

div.sidebar {
  margin-left: 1em ;
  border: medium outset ;
  padding: 0em 1em ;
  background-color: #ffffee ;
  width: 40% ;
  float: right ;
  clear: right }

div.sidebar p.rubric {
  font-family: sans-serif ;
  font-size: medium }

div.system-messages {
  margin: 5em }

div.system-messages h1 {
  color: red }

div.system-message {
  border: medium outset ;
  padding: 1em }

div.system-message p.system-message-title {
  color: red ;
  font-weight: bold }

div.topic {
  margin: 2em }

h1.title {
  text-align: center }

h2.subtitle {
  text-align: center }

ol.simple, ul.simple {
  margin-bottom: 1em }

ol.arabic {
  list-style: decimal }

ol.loweralpha {
  list-style: lower-alpha }

ol.upperalpha {
  list-style: upper-alpha }

ol.lowerroman {
  list-style: lower-roman }

ol.upperroman {
  list-style: upper-roman }

p.attribution {
  text-align: right ;
  margin-left: 50% }

p.caption {
  font-style: italic }

p.credits {
  font-style: italic ;
  font-size: smaller }

p.label {
  white-space: nowrap }

p.rubric {
  font-weight: bold ;
  font-size: larger ;
  color: maroon ;
  text-align: center }

p.sidebar-title {
  font-family: sans-serif ;
  font-weight: bold ;
  font-size: larger }

p.sidebar-subtitle {
  font-family: sans-serif ;
  font-weight: bold }

p.topic-title {
  font-weight: bold }

pre.address {
  margin-bottom: 0 ;
  margin-top: 0 ;
  font-family: serif ;
  font-size: 100% }

pre.line-block {
  font-family: serif ;
  font-size: 100% }

pre.literal-block, pre.doctest-block {
  margin-left: 2em ;
  margin-right: 2em ;}
  /*background-color: #eeeeee }*/
  /*for some reason i can't overide in an import*/

span.classifier {
  font-family: sans-serif ;
  font-style: oblique }

span.classifier-delimiter {
  font-family: sans-serif ;
  font-weight: bold }

span.interpreted {
  font-family: sans-serif }

span.option {
  white-space: nowrap }

span.option-argument {
  font-style: italic }

span.pre {
  white-space: pre }

span.problematic {
  color: red }

table {
  margin-top: 0.5em ;
  margin-bottom: 0.5em }

table.citation {
  border-left: solid thin gray ;
  padding-left: 0.5ex }

table.docinfo {
  margin: 2em 4em }

table.footnote {
  border-left: solid thin black ;
  padding-left: 0.5ex }

td, th {
  padding-left: 0.5em ;
  padding-right: 0.5em ;
  vertical-align: top }

th.docinfo-name, th.field-name {
  font-weight: bold ;
  text-align: left ;
  white-space: nowrap }

h1 tt, h2 tt, h3 tt, h4 tt, h5 tt, h6 tt {
  font-size: 100% }

/*for some reason, the following isn't being overridden by the imports
at the end of this style sheet so I've commented it out*/
/*tt {
  background-color: #eeeeee }*/

ul.auto-toc {
  list-style-type: none }

hr { /* EKR */
  width: 100%;
  height: 1pt;
  color: gray;
}



</style>
</head>
<body>
<div class="document" id="title">
<h1 class="title">Title</h1>

<!-- rst3: filename: test.html -->
<p>This is test.html</p>
<p>This is the body of the section.</p>
</div>
</body>
</html>
#@+node:ekr.20100827182529.6843: *5* got
#@+node:ekr.20100827182529.6844: *6* rst
.. rst3: filename: test.html


#####
Title
#####

This is test.html

This is the body of the section.

#@+node:ekr.20100827182529.6845: *6* html
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="generator" content="Docutils VER: http://docutils.sourceforge.net/" />
<title>Title</title>
<style type="text/css">

/*ORIGINAL GOODGER + changes; up to line 224 it's standard reST stylesheet
:Author: David Goodger
:Contact: goodger@users.sourceforge.net
:date: $Date: 2006/10/19 13:23:15 $
:version: $Revision: 1.2 $
:copyright: This stylesheet has been placed in the public domain.

Default cascading style sheet for the HTML output of Docutils.
*/

/* EKR 10/19/06 */
/* some browsers require imported rules to precede all rulesets */
@import url(leo_rst.css);
@import url(silver_city.css);

.first {
  margin-top: 0 }

.last {
  margin-bottom: 0 }

a.toc-backref {
  text-decoration: none ;
  color: black }

dd {
  margin-bottom: 0.5em }

div.abstract {
  margin: 2em 5em }

div.abstract p.topic-title {
  font-weight: bold ;
  text-align: center }

div.attention, div.caution, div.danger, div.error, div.hint,
div.important, div.note, div.tip, div.warning, div.admonition {
  margin: 2em ;
  border: medium outset ;
  padding: 1em }

div.attention p.admonition-title, div.caution p.admonition-title,
div.danger p.admonition-title, div.error p.admonition-title,
div.warning p.admonition-title {
  color: red ;
  font-weight: bold ;
  font-family: sans-serif }

div.hint p.admonition-title, div.important p.admonition-title,
div.note p.admonition-title, div.tip p.admonition-title,
div.admonition p.admonition-title {
  font-weight: bold ;
  font-family: sans-serif }

div.dedication {
  margin: 2em 5em ;
  text-align: center ;
  font-style: italic }

div.dedication p.topic-title {
  font-weight: bold ;
  font-style: normal }

div.figure {
  margin-left: 2em }

div.footer, div.header {
  font-size: smaller }

div.sidebar {
  margin-left: 1em ;
  border: medium outset ;
  padding: 0em 1em ;
  background-color: #ffffee ;
  width: 40% ;
  float: right ;
  clear: right }

div.sidebar p.rubric {
  font-family: sans-serif ;
  font-size: medium }

div.system-messages {
  margin: 5em }

div.system-messages h1 {
  color: red }

div.system-message {
  border: medium outset ;
  padding: 1em }

div.system-message p.system-message-title {
  color: red ;
  font-weight: bold }

div.topic {
  margin: 2em }

h1.title {
  text-align: center }

h2.subtitle {
  text-align: center }

ol.simple, ul.simple {
  margin-bottom: 1em }

ol.arabic {
  list-style: decimal }

ol.loweralpha {
  list-style: lower-alpha }

ol.upperalpha {
  list-style: upper-alpha }

ol.lowerroman {
  list-style: lower-roman }

ol.upperroman {
  list-style: upper-roman }

p.attribution {
  text-align: right ;
  margin-left: 50% }

p.caption {
  font-style: italic }

p.credits {
  font-style: italic ;
  font-size: smaller }

p.label {
  white-space: nowrap }

p.rubric {
  font-weight: bold ;
  font-size: larger ;
  color: maroon ;
  text-align: center }

p.sidebar-title {
  font-family: sans-serif ;
  font-weight: bold ;
  font-size: larger }

p.sidebar-subtitle {
  font-family: sans-serif ;
  font-weight: bold }

p.topic-title {
  font-weight: bold }

pre.address {
  margin-bottom: 0 ;
  margin-top: 0 ;
  font-family: serif ;
  font-size: 100% }

pre.line-block {
  font-family: serif ;
  font-size: 100% }

pre.literal-block, pre.doctest-block {
  margin-left: 2em ;
  margin-right: 2em ;}
  /*background-color: #eeeeee }*/
  /*for some reason i can't overide in an import*/

span.classifier {
  font-family: sans-serif ;
  font-style: oblique }

span.classifier-delimiter {
  font-family: sans-serif ;
  font-weight: bold }

span.interpreted {
  font-family: sans-serif }

span.option {
  white-space: nowrap }

span.option-argument {
  font-style: italic }

span.pre {
  white-space: pre }

span.problematic {
  color: red }

table {
  margin-top: 0.5em ;
  margin-bottom: 0.5em }

table.citation {
  border-left: solid thin gray ;
  padding-left: 0.5ex }

table.docinfo {
  margin: 2em 4em }

table.footnote {
  border-left: solid thin black ;
  padding-left: 0.5ex }

td, th {
  padding-left: 0.5em ;
  padding-right: 0.5em ;
  vertical-align: top }

th.docinfo-name, th.field-name {
  font-weight: bold ;
  text-align: left ;
  white-space: nowrap }

h1 tt, h2 tt, h3 tt, h4 tt, h5 tt, h6 tt {
  font-size: 100% }

/*for some reason, the following isn't being overridden by the imports
at the end of this style sheet so I've commented it out*/
/*tt {
  background-color: #eeeeee }*/

ul.auto-toc {
  list-style-type: none }

hr { /* EKR */
  width: 100%;
  height: 1pt;
  color: gray;
}



</style>
</head>
<body>
<div class="document" id="title">
<h1 class="title">Title</h1>

<!-- rst3: filename: test.html -->
<p>This is test.html</p>
<p>This is the body of the section.</p>
</div>
</body>
</html>
#@+node:ekr.20100812172232.5801: *4* @test rst3Test default
s = g.findTestScript(c,'@common leoRst test code',warn=False)
if s:
    exec(s)
    rst3Test(c,p)
#@+node:ekr.20100812182942.5805: *5* source
@language rest
#@+node:ekr.20100812182942.5807: *6* @rst test.html
@language rest

#####
Title
#####

This is test.html
#@+node:ekr.20100812182942.5808: *7* section
@ This is a doc part
it has two lines.
@c
This is the body of the section.
#@+node:ekr.20100812213445.5814: *5* expected
@language html
#@+node:ekr.20100813100841.5848: *6* rst
.. rst3: filename: test.html


#####
Title
#####

This is test.html

section
+++++++

@ This is a doc part
it has two lines.
This is the body of the section.

#@+node:ekr.20100813100841.5849: *6*  html
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="generator" content="Docutils VER: http://docutils.sourceforge.net/" />
<title>Title</title>
<style type="text/css">

/*ORIGINAL GOODGER + changes; up to line 224 it's standard reST stylesheet
:Author: David Goodger
:Contact: goodger@users.sourceforge.net
:date: $Date: 2006/10/19 13:23:15 $
:version: $Revision: 1.2 $
:copyright: This stylesheet has been placed in the public domain.

Default cascading style sheet for the HTML output of Docutils.
*/

/* EKR 10/19/06 */
/* some browsers require imported rules to precede all rulesets */
@import url(leo_rst.css);
@import url(silver_city.css);

.first {
  margin-top: 0 }

.last {
  margin-bottom: 0 }

a.toc-backref {
  text-decoration: none ;
  color: black }

dd {
  margin-bottom: 0.5em }

div.abstract {
  margin: 2em 5em }

div.abstract p.topic-title {
  font-weight: bold ;
  text-align: center }

div.attention, div.caution, div.danger, div.error, div.hint,
div.important, div.note, div.tip, div.warning, div.admonition {
  margin: 2em ;
  border: medium outset ;
  padding: 1em }

div.attention p.admonition-title, div.caution p.admonition-title,
div.danger p.admonition-title, div.error p.admonition-title,
div.warning p.admonition-title {
  color: red ;
  font-weight: bold ;
  font-family: sans-serif }

div.hint p.admonition-title, div.important p.admonition-title,
div.note p.admonition-title, div.tip p.admonition-title,
div.admonition p.admonition-title {
  font-weight: bold ;
  font-family: sans-serif }

div.dedication {
  margin: 2em 5em ;
  text-align: center ;
  font-style: italic }

div.dedication p.topic-title {
  font-weight: bold ;
  font-style: normal }

div.figure {
  margin-left: 2em }

div.footer, div.header {
  font-size: smaller }

div.sidebar {
  margin-left: 1em ;
  border: medium outset ;
  padding: 0em 1em ;
  background-color: #ffffee ;
  width: 40% ;
  float: right ;
  clear: right }

div.sidebar p.rubric {
  font-family: sans-serif ;
  font-size: medium }

div.system-messages {
  margin: 5em }

div.system-messages h1 {
  color: red }

div.system-message {
  border: medium outset ;
  padding: 1em }

div.system-message p.system-message-title {
  color: red ;
  font-weight: bold }

div.topic {
  margin: 2em }

h1.title {
  text-align: center }

h2.subtitle {
  text-align: center }

ol.simple, ul.simple {
  margin-bottom: 1em }

ol.arabic {
  list-style: decimal }

ol.loweralpha {
  list-style: lower-alpha }

ol.upperalpha {
  list-style: upper-alpha }

ol.lowerroman {
  list-style: lower-roman }

ol.upperroman {
  list-style: upper-roman }

p.attribution {
  text-align: right ;
  margin-left: 50% }

p.caption {
  font-style: italic }

p.credits {
  font-style: italic ;
  font-size: smaller }

p.label {
  white-space: nowrap }

p.rubric {
  font-weight: bold ;
  font-size: larger ;
  color: maroon ;
  text-align: center }

p.sidebar-title {
  font-family: sans-serif ;
  font-weight: bold ;
  font-size: larger }

p.sidebar-subtitle {
  font-family: sans-serif ;
  font-weight: bold }

p.topic-title {
  font-weight: bold }

pre.address {
  margin-bottom: 0 ;
  margin-top: 0 ;
  font-family: serif ;
  font-size: 100% }

pre.line-block {
  font-family: serif ;
  font-size: 100% }

pre.literal-block, pre.doctest-block {
  margin-left: 2em ;
  margin-right: 2em ;}
  /*background-color: #eeeeee }*/
  /*for some reason i can't overide in an import*/

span.classifier {
  font-family: sans-serif ;
  font-style: oblique }

span.classifier-delimiter {
  font-family: sans-serif ;
  font-weight: bold }

span.interpreted {
  font-family: sans-serif }

span.option {
  white-space: nowrap }

span.option-argument {
  font-style: italic }

span.pre {
  white-space: pre }

span.problematic {
  color: red }

table {
  margin-top: 0.5em ;
  margin-bottom: 0.5em }

table.citation {
  border-left: solid thin gray ;
  padding-left: 0.5ex }

table.docinfo {
  margin: 2em 4em }

table.footnote {
  border-left: solid thin black ;
  padding-left: 0.5ex }

td, th {
  padding-left: 0.5em ;
  padding-right: 0.5em ;
  vertical-align: top }

th.docinfo-name, th.field-name {
  font-weight: bold ;
  text-align: left ;
  white-space: nowrap }

h1 tt, h2 tt, h3 tt, h4 tt, h5 tt, h6 tt {
  font-size: 100% }

/*for some reason, the following isn't being overridden by the imports
at the end of this style sheet so I've commented it out*/
/*tt {
  background-color: #eeeeee }*/

ul.auto-toc {
  list-style-type: none }

hr { /* EKR */
  width: 100%;
  height: 1pt;
  color: gray;
}



</style>
</head>
<body>
<div class="document" id="title">
<h1 class="title">Title</h1>

<!-- rst3: filename: test.html -->
<p>This is test.html</p>
<div class="section" id="section">
<h1>section</h1>
<p>&#64; This is a doc part
it has two lines.
This is the body of the section.</p>
</div>
</div>
</body>
</html>
#@+node:ekr.20100827182529.6840: *5* got
#@+node:ekr.20100827182529.6841: *6* rst
.. rst3: filename: test.html


#####
Title
#####

This is test.html

section
+++++++

@ This is a doc part
it has two lines.
This is the body of the section.

#@+node:ekr.20100827182529.6842: *6* html
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="generator" content="Docutils VER: http://docutils.sourceforge.net/" />
<title>Title</title>
<style type="text/css">

/*ORIGINAL GOODGER + changes; up to line 224 it's standard reST stylesheet
:Author: David Goodger
:Contact: goodger@users.sourceforge.net
:date: $Date: 2006/10/19 13:23:15 $
:version: $Revision: 1.2 $
:copyright: This stylesheet has been placed in the public domain.

Default cascading style sheet for the HTML output of Docutils.
*/

/* EKR 10/19/06 */
/* some browsers require imported rules to precede all rulesets */
@import url(leo_rst.css);
@import url(silver_city.css);

.first {
  margin-top: 0 }

.last {
  margin-bottom: 0 }

a.toc-backref {
  text-decoration: none ;
  color: black }

dd {
  margin-bottom: 0.5em }

div.abstract {
  margin: 2em 5em }

div.abstract p.topic-title {
  font-weight: bold ;
  text-align: center }

div.attention, div.caution, div.danger, div.error, div.hint,
div.important, div.note, div.tip, div.warning, div.admonition {
  margin: 2em ;
  border: medium outset ;
  padding: 1em }

div.attention p.admonition-title, div.caution p.admonition-title,
div.danger p.admonition-title, div.error p.admonition-title,
div.warning p.admonition-title {
  color: red ;
  font-weight: bold ;
  font-family: sans-serif }

div.hint p.admonition-title, div.important p.admonition-title,
div.note p.admonition-title, div.tip p.admonition-title,
div.admonition p.admonition-title {
  font-weight: bold ;
  font-family: sans-serif }

div.dedication {
  margin: 2em 5em ;
  text-align: center ;
  font-style: italic }

div.dedication p.topic-title {
  font-weight: bold ;
  font-style: normal }

div.figure {
  margin-left: 2em }

div.footer, div.header {
  font-size: smaller }

div.sidebar {
  margin-left: 1em ;
  border: medium outset ;
  padding: 0em 1em ;
  background-color: #ffffee ;
  width: 40% ;
  float: right ;
  clear: right }

div.sidebar p.rubric {
  font-family: sans-serif ;
  font-size: medium }

div.system-messages {
  margin: 5em }

div.system-messages h1 {
  color: red }

div.system-message {
  border: medium outset ;
  padding: 1em }

div.system-message p.system-message-title {
  color: red ;
  font-weight: bold }

div.topic {
  margin: 2em }

h1.title {
  text-align: center }

h2.subtitle {
  text-align: center }

ol.simple, ul.simple {
  margin-bottom: 1em }

ol.arabic {
  list-style: decimal }

ol.loweralpha {
  list-style: lower-alpha }

ol.upperalpha {
  list-style: upper-alpha }

ol.lowerroman {
  list-style: lower-roman }

ol.upperroman {
  list-style: upper-roman }

p.attribution {
  text-align: right ;
  margin-left: 50% }

p.caption {
  font-style: italic }

p.credits {
  font-style: italic ;
  font-size: smaller }

p.label {
  white-space: nowrap }

p.rubric {
  font-weight: bold ;
  font-size: larger ;
  color: maroon ;
  text-align: center }

p.sidebar-title {
  font-family: sans-serif ;
  font-weight: bold ;
  font-size: larger }

p.sidebar-subtitle {
  font-family: sans-serif ;
  font-weight: bold }

p.topic-title {
  font-weight: bold }

pre.address {
  margin-bottom: 0 ;
  margin-top: 0 ;
  font-family: serif ;
  font-size: 100% }

pre.line-block {
  font-family: serif ;
  font-size: 100% }

pre.literal-block, pre.doctest-block {
  margin-left: 2em ;
  margin-right: 2em ;}
  /*background-color: #eeeeee }*/
  /*for some reason i can't overide in an import*/

span.classifier {
  font-family: sans-serif ;
  font-style: oblique }

span.classifier-delimiter {
  font-family: sans-serif ;
  font-weight: bold }

span.interpreted {
  font-family: sans-serif }

span.option {
  white-space: nowrap }

span.option-argument {
  font-style: italic }

span.pre {
  white-space: pre }

span.problematic {
  color: red }

table {
  margin-top: 0.5em ;
  margin-bottom: 0.5em }

table.citation {
  border-left: solid thin gray ;
  padding-left: 0.5ex }

table.docinfo {
  margin: 2em 4em }

table.footnote {
  border-left: solid thin black ;
  padding-left: 0.5ex }

td, th {
  padding-left: 0.5em ;
  padding-right: 0.5em ;
  vertical-align: top }

th.docinfo-name, th.field-name {
  font-weight: bold ;
  text-align: left ;
  white-space: nowrap }

h1 tt, h2 tt, h3 tt, h4 tt, h5 tt, h6 tt {
  font-size: 100% }

/*for some reason, the following isn't being overridden by the imports
at the end of this style sheet so I've commented it out*/
/*tt {
  background-color: #eeeeee }*/

ul.auto-toc {
  list-style-type: none }

hr { /* EKR */
  width: 100%;
  height: 1pt;
  color: gray;
}



</style>
</head>
<body>
<div class="document" id="title">
<h1 class="title">Title</h1>

<!-- rst3: filename: test.html -->
<p>This is test.html</p>
<div class="section" id="section">
<h1>section</h1>
<p>&#64; This is a doc part
it has two lines.
This is the body of the section.</p>
</div>
</div>
</body>
</html>
#@+node:ekr.20100813100841.5824: *4* @test rst3Test doc_only_mode (set in headline)
# Skip test when running test dynamically.
s = g.findTestScript(c,'@common leoRst test code',warn=False)
if s:
    exec(s)
    rst3Test(c,p)
#@+node:ekr.20100813100841.5839: *5* source
@language rest
#@+node:ekr.20100813100841.5840: *6* @rst test.html
#####
Title
#####

This is test.html
#@+node:ekr.20100813124317.5868: *7* @rst-option doc_only_mode=True
#@+node:ekr.20100813100841.5841: *8* section
@ This is a doc part
it has two lines.
@c
This is the body of the section.
#@+node:ekr.20100813100841.5842: *5* expected
#@+node:ekr.20100813124317.5869: *6* rst
.. rst3: filename: test.html

#####
Title
#####

This is test.html



section
*******

This is a doc part
it has two lines.

#@+node:ekr.20100813124317.5870: *6*  html
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="generator" content="Docutils VER: http://docutils.sourceforge.net/" />
<title>Title</title>
<style type="text/css">

/*ORIGINAL GOODGER + changes; up to line 224 it's standard reST stylesheet
:Author: David Goodger
:Contact: goodger@users.sourceforge.net
:date: $Date: 2006/10/19 13:23:15 $
:version: $Revision: 1.2 $
:copyright: This stylesheet has been placed in the public domain.

Default cascading style sheet for the HTML output of Docutils.
*/

/* EKR 10/19/06 */
/* some browsers require imported rules to precede all rulesets */
@import url(leo_rst.css);
@import url(silver_city.css);

.first {
  margin-top: 0 }

.last {
  margin-bottom: 0 }

a.toc-backref {
  text-decoration: none ;
  color: black }

dd {
  margin-bottom: 0.5em }

div.abstract {
  margin: 2em 5em }

div.abstract p.topic-title {
  font-weight: bold ;
  text-align: center }

div.attention, div.caution, div.danger, div.error, div.hint,
div.important, div.note, div.tip, div.warning, div.admonition {
  margin: 2em ;
  border: medium outset ;
  padding: 1em }

div.attention p.admonition-title, div.caution p.admonition-title,
div.danger p.admonition-title, div.error p.admonition-title,
div.warning p.admonition-title {
  color: red ;
  font-weight: bold ;
  font-family: sans-serif }

div.hint p.admonition-title, div.important p.admonition-title,
div.note p.admonition-title, div.tip p.admonition-title,
div.admonition p.admonition-title {
  font-weight: bold ;
  font-family: sans-serif }

div.dedication {
  margin: 2em 5em ;
  text-align: center ;
  font-style: italic }

div.dedication p.topic-title {
  font-weight: bold ;
  font-style: normal }

div.figure {
  margin-left: 2em }

div.footer, div.header {
  font-size: smaller }

div.sidebar {
  margin-left: 1em ;
  border: medium outset ;
  padding: 0em 1em ;
  background-color: #ffffee ;
  width: 40% ;
  float: right ;
  clear: right }

div.sidebar p.rubric {
  font-family: sans-serif ;
  font-size: medium }

div.system-messages {
  margin: 5em }

div.system-messages h1 {
  color: red }

div.system-message {
  border: medium outset ;
  padding: 1em }

div.system-message p.system-message-title {
  color: red ;
  font-weight: bold }

div.topic {
  margin: 2em }

h1.title {
  text-align: center }

h2.subtitle {
  text-align: center }

ol.simple, ul.simple {
  margin-bottom: 1em }

ol.arabic {
  list-style: decimal }

ol.loweralpha {
  list-style: lower-alpha }

ol.upperalpha {
  list-style: upper-alpha }

ol.lowerroman {
  list-style: lower-roman }

ol.upperroman {
  list-style: upper-roman }

p.attribution {
  text-align: right ;
  margin-left: 50% }

p.caption {
  font-style: italic }

p.credits {
  font-style: italic ;
  font-size: smaller }

p.label {
  white-space: nowrap }

p.rubric {
  font-weight: bold ;
  font-size: larger ;
  color: maroon ;
  text-align: center }

p.sidebar-title {
  font-family: sans-serif ;
  font-weight: bold ;
  font-size: larger }

p.sidebar-subtitle {
  font-family: sans-serif ;
  font-weight: bold }

p.topic-title {
  font-weight: bold }

pre.address {
  margin-bottom: 0 ;
  margin-top: 0 ;
  font-family: serif ;
  font-size: 100% }

pre.line-block {
  font-family: serif ;
  font-size: 100% }

pre.literal-block, pre.doctest-block {
  margin-left: 2em ;
  margin-right: 2em ;}
  /*background-color: #eeeeee }*/
  /*for some reason i can't overide in an import*/

span.classifier {
  font-family: sans-serif ;
  font-style: oblique }

span.classifier-delimiter {
  font-family: sans-serif ;
  font-weight: bold }

span.interpreted {
  font-family: sans-serif }

span.option {
  white-space: nowrap }

span.option-argument {
  font-style: italic }

span.pre {
  white-space: pre }

span.problematic {
  color: red }

table {
  margin-top: 0.5em ;
  margin-bottom: 0.5em }

table.citation {
  border-left: solid thin gray ;
  padding-left: 0.5ex }

table.docinfo {
  margin: 2em 4em }

table.footnote {
  border-left: solid thin black ;
  padding-left: 0.5ex }

td, th {
  padding-left: 0.5em ;
  padding-right: 0.5em ;
  vertical-align: top }

th.docinfo-name, th.field-name {
  font-weight: bold ;
  text-align: left ;
  white-space: nowrap }

h1 tt, h2 tt, h3 tt, h4 tt, h5 tt, h6 tt {
  font-size: 100% }

/*for some reason, the following isn't being overridden by the imports
at the end of this style sheet so I've commented it out*/
/*tt {
  background-color: #eeeeee }*/

ul.auto-toc {
  list-style-type: none }

hr { /* EKR */
  width: 100%;
  height: 1pt;
  color: gray;
}



</style>
</head>
<body>
<div class="document" id="title">
<h1 class="title">Title</h1>

<!-- rst3: filename: test.html -->
<p>This is test.html</p>
<div class="section" id="section">
<h1>section</h1>
<p>This is a doc part
it has two lines.</p>
</div>
</div>
</body>
</html>
#@+node:ekr.20100827182529.6846: *5* got
#@+node:ekr.20100827182529.6847: *6* rst
.. rst3: filename: test.html

#####
Title
#####

This is test.html



section
*******

@ This is a doc part
it has two lines.
This is the body of the section.

#@+node:ekr.20100827182529.6848: *6* html
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="generator" content="Docutils VER: http://docutils.sourceforge.net/" />
<title>Title</title>
<style type="text/css">

/*ORIGINAL GOODGER + changes; up to line 224 it's standard reST stylesheet
:Author: David Goodger
:Contact: goodger@users.sourceforge.net
:date: $Date: 2006/10/19 13:23:15 $
:version: $Revision: 1.2 $
:copyright: This stylesheet has been placed in the public domain.

Default cascading style sheet for the HTML output of Docutils.
*/

/* EKR 10/19/06 */
/* some browsers require imported rules to precede all rulesets */
@import url(leo_rst.css);
@import url(silver_city.css);

.first {
  margin-top: 0 }

.last {
  margin-bottom: 0 }

a.toc-backref {
  text-decoration: none ;
  color: black }

dd {
  margin-bottom: 0.5em }

div.abstract {
  margin: 2em 5em }

div.abstract p.topic-title {
  font-weight: bold ;
  text-align: center }

div.attention, div.caution, div.danger, div.error, div.hint,
div.important, div.note, div.tip, div.warning, div.admonition {
  margin: 2em ;
  border: medium outset ;
  padding: 1em }

div.attention p.admonition-title, div.caution p.admonition-title,
div.danger p.admonition-title, div.error p.admonition-title,
div.warning p.admonition-title {
  color: red ;
  font-weight: bold ;
  font-family: sans-serif }

div.hint p.admonition-title, div.important p.admonition-title,
div.note p.admonition-title, div.tip p.admonition-title,
div.admonition p.admonition-title {
  font-weight: bold ;
  font-family: sans-serif }

div.dedication {
  margin: 2em 5em ;
  text-align: center ;
  font-style: italic }

div.dedication p.topic-title {
  font-weight: bold ;
  font-style: normal }

div.figure {
  margin-left: 2em }

div.footer, div.header {
  font-size: smaller }

div.sidebar {
  margin-left: 1em ;
  border: medium outset ;
  padding: 0em 1em ;
  background-color: #ffffee ;
  width: 40% ;
  float: right ;
  clear: right }

div.sidebar p.rubric {
  font-family: sans-serif ;
  font-size: medium }

div.system-messages {
  margin: 5em }

div.system-messages h1 {
  color: red }

div.system-message {
  border: medium outset ;
  padding: 1em }

div.system-message p.system-message-title {
  color: red ;
  font-weight: bold }

div.topic {
  margin: 2em }

h1.title {
  text-align: center }

h2.subtitle {
  text-align: center }

ol.simple, ul.simple {
  margin-bottom: 1em }

ol.arabic {
  list-style: decimal }

ol.loweralpha {
  list-style: lower-alpha }

ol.upperalpha {
  list-style: upper-alpha }

ol.lowerroman {
  list-style: lower-roman }

ol.upperroman {
  list-style: upper-roman }

p.attribution {
  text-align: right ;
  margin-left: 50% }

p.caption {
  font-style: italic }

p.credits {
  font-style: italic ;
  font-size: smaller }

p.label {
  white-space: nowrap }

p.rubric {
  font-weight: bold ;
  font-size: larger ;
  color: maroon ;
  text-align: center }

p.sidebar-title {
  font-family: sans-serif ;
  font-weight: bold ;
  font-size: larger }

p.sidebar-subtitle {
  font-family: sans-serif ;
  font-weight: bold }

p.topic-title {
  font-weight: bold }

pre.address {
  margin-bottom: 0 ;
  margin-top: 0 ;
  font-family: serif ;
  font-size: 100% }

pre.line-block {
  font-family: serif ;
  font-size: 100% }

pre.literal-block, pre.doctest-block {
  margin-left: 2em ;
  margin-right: 2em ;}
  /*background-color: #eeeeee }*/
  /*for some reason i can't overide in an import*/

span.classifier {
  font-family: sans-serif ;
  font-style: oblique }

span.classifier-delimiter {
  font-family: sans-serif ;
  font-weight: bold }

span.interpreted {
  font-family: sans-serif }

span.option {
  white-space: nowrap }

span.option-argument {
  font-style: italic }

span.pre {
  white-space: pre }

span.problematic {
  color: red }

table {
  margin-top: 0.5em ;
  margin-bottom: 0.5em }

table.citation {
  border-left: solid thin gray ;
  padding-left: 0.5ex }

table.docinfo {
  margin: 2em 4em }

table.footnote {
  border-left: solid thin black ;
  padding-left: 0.5ex }

td, th {
  padding-left: 0.5em ;
  padding-right: 0.5em ;
  vertical-align: top }

th.docinfo-name, th.field-name {
  font-weight: bold ;
  text-align: left ;
  white-space: nowrap }

h1 tt, h2 tt, h3 tt, h4 tt, h5 tt, h6 tt {
  font-size: 100% }

/*for some reason, the following isn't being overridden by the imports
at the end of this style sheet so I've commented it out*/
/*tt {
  background-color: #eeeeee }*/

ul.auto-toc {
  list-style-type: none }

hr { /* EKR */
  width: 100%;
  height: 1pt;
  color: gray;
}



</style>
</head>
<body>
<div class="document" id="title">
<h1 class="title">Title</h1>

<!-- rst3: filename: test.html -->
<p>This is test.html</p>
<div class="section" id="section">
<h1>section</h1>
<p>&#64; This is a doc part
it has two lines.
This is the body of the section.</p>
</div>
</div>
</body>
</html>
#@+node:ekr.20100813124317.5879: *4* @test rst3Test doc_only_mode (set in options doc part)
# Skip test when running test dynamically.
s = g.findTestScript(c,'@common leoRst test code',warn=False)
if s:
    exec(s)
    rst3Test(c,p)
#@+node:ekr.20100813124317.5880: *5* source
@language rest
#@+node:ekr.20100813124317.5881: *6* @rst test.html
#####
Title
#####

This is test.html
#@+node:ekr.20100813124317.5883: *7* section
@ @rst-options
doc_only_mode=True
@c
@ This is a doc part
it has two lines.
@c
This is the body of the section.
#@+node:ekr.20100813124317.5884: *5* expected
#@+node:ekr.20100813124317.5889: *6* rst
.. rst3: filename: test.html

#####
Title
#####

This is test.html

section
+++++++

This is a doc part
it has two lines.

#@+node:ekr.20100813124317.5890: *6*  html
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="generator" content="Docutils VER: http://docutils.sourceforge.net/" />
<title>Title</title>
<style type="text/css">

/*ORIGINAL GOODGER + changes; up to line 224 it's standard reST stylesheet
:Author: David Goodger
:Contact: goodger@users.sourceforge.net
:date: $Date: 2006/10/19 13:23:15 $
:version: $Revision: 1.2 $
:copyright: This stylesheet has been placed in the public domain.

Default cascading style sheet for the HTML output of Docutils.
*/

/* EKR 10/19/06 */
/* some browsers require imported rules to precede all rulesets */
@import url(leo_rst.css);
@import url(silver_city.css);

.first {
  margin-top: 0 }

.last {
  margin-bottom: 0 }

a.toc-backref {
  text-decoration: none ;
  color: black }

dd {
  margin-bottom: 0.5em }

div.abstract {
  margin: 2em 5em }

div.abstract p.topic-title {
  font-weight: bold ;
  text-align: center }

div.attention, div.caution, div.danger, div.error, div.hint,
div.important, div.note, div.tip, div.warning, div.admonition {
  margin: 2em ;
  border: medium outset ;
  padding: 1em }

div.attention p.admonition-title, div.caution p.admonition-title,
div.danger p.admonition-title, div.error p.admonition-title,
div.warning p.admonition-title {
  color: red ;
  font-weight: bold ;
  font-family: sans-serif }

div.hint p.admonition-title, div.important p.admonition-title,
div.note p.admonition-title, div.tip p.admonition-title,
div.admonition p.admonition-title {
  font-weight: bold ;
  font-family: sans-serif }

div.dedication {
  margin: 2em 5em ;
  text-align: center ;
  font-style: italic }

div.dedication p.topic-title {
  font-weight: bold ;
  font-style: normal }

div.figure {
  margin-left: 2em }

div.footer, div.header {
  font-size: smaller }

div.sidebar {
  margin-left: 1em ;
  border: medium outset ;
  padding: 0em 1em ;
  background-color: #ffffee ;
  width: 40% ;
  float: right ;
  clear: right }

div.sidebar p.rubric {
  font-family: sans-serif ;
  font-size: medium }

div.system-messages {
  margin: 5em }

div.system-messages h1 {
  color: red }

div.system-message {
  border: medium outset ;
  padding: 1em }

div.system-message p.system-message-title {
  color: red ;
  font-weight: bold }

div.topic {
  margin: 2em }

h1.title {
  text-align: center }

h2.subtitle {
  text-align: center }

ol.simple, ul.simple {
  margin-bottom: 1em }

ol.arabic {
  list-style: decimal }

ol.loweralpha {
  list-style: lower-alpha }

ol.upperalpha {
  list-style: upper-alpha }

ol.lowerroman {
  list-style: lower-roman }

ol.upperroman {
  list-style: upper-roman }

p.attribution {
  text-align: right ;
  margin-left: 50% }

p.caption {
  font-style: italic }

p.credits {
  font-style: italic ;
  font-size: smaller }

p.label {
  white-space: nowrap }

p.rubric {
  font-weight: bold ;
  font-size: larger ;
  color: maroon ;
  text-align: center }

p.sidebar-title {
  font-family: sans-serif ;
  font-weight: bold ;
  font-size: larger }

p.sidebar-subtitle {
  font-family: sans-serif ;
  font-weight: bold }

p.topic-title {
  font-weight: bold }

pre.address {
  margin-bottom: 0 ;
  margin-top: 0 ;
  font-family: serif ;
  font-size: 100% }

pre.line-block {
  font-family: serif ;
  font-size: 100% }

pre.literal-block, pre.doctest-block {
  margin-left: 2em ;
  margin-right: 2em ;}
  /*background-color: #eeeeee }*/
  /*for some reason i can't overide in an import*/

span.classifier {
  font-family: sans-serif ;
  font-style: oblique }

span.classifier-delimiter {
  font-family: sans-serif ;
  font-weight: bold }

span.interpreted {
  font-family: sans-serif }

span.option {
  white-space: nowrap }

span.option-argument {
  font-style: italic }

span.pre {
  white-space: pre }

span.problematic {
  color: red }

table {
  margin-top: 0.5em ;
  margin-bottom: 0.5em }

table.citation {
  border-left: solid thin gray ;
  padding-left: 0.5ex }

table.docinfo {
  margin: 2em 4em }

table.footnote {
  border-left: solid thin black ;
  padding-left: 0.5ex }

td, th {
  padding-left: 0.5em ;
  padding-right: 0.5em ;
  vertical-align: top }

th.docinfo-name, th.field-name {
  font-weight: bold ;
  text-align: left ;
  white-space: nowrap }

h1 tt, h2 tt, h3 tt, h4 tt, h5 tt, h6 tt {
  font-size: 100% }

/*for some reason, the following isn't being overridden by the imports
at the end of this style sheet so I've commented it out*/
/*tt {
  background-color: #eeeeee }*/

ul.auto-toc {
  list-style-type: none }

hr { /* EKR */
  width: 100%;
  height: 1pt;
  color: gray;
}



</style>
</head>
<body>
<div class="document" id="title">
<h1 class="title">Title</h1>

<!-- rst3: filename: test.html -->
<p>This is test.html</p>
<div class="section" id="section">
<h1>section</h1>
<p>This is a doc part
it has two lines.</p>
</div>
</div>
</body>
</html>
#@+node:ekr.20100827182529.6849: *5* got
#@+node:ekr.20100827182529.6850: *6* rst
.. rst3: filename: test.html

#####
Title
#####

This is test.html

section
+++++++

@ This is a doc part
it has two lines.
This is the body of the section.

#@+node:ekr.20100827182529.6851: *6* html
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="generator" content="Docutils VER: http://docutils.sourceforge.net/" />
<title>Title</title>
<style type="text/css">

/*ORIGINAL GOODGER + changes; up to line 224 it's standard reST stylesheet
:Author: David Goodger
:Contact: goodger@users.sourceforge.net
:date: $Date: 2006/10/19 13:23:15 $
:version: $Revision: 1.2 $
:copyright: This stylesheet has been placed in the public domain.

Default cascading style sheet for the HTML output of Docutils.
*/

/* EKR 10/19/06 */
/* some browsers require imported rules to precede all rulesets */
@import url(leo_rst.css);
@import url(silver_city.css);

.first {
  margin-top: 0 }

.last {
  margin-bottom: 0 }

a.toc-backref {
  text-decoration: none ;
  color: black }

dd {
  margin-bottom: 0.5em }

div.abstract {
  margin: 2em 5em }

div.abstract p.topic-title {
  font-weight: bold ;
  text-align: center }

div.attention, div.caution, div.danger, div.error, div.hint,
div.important, div.note, div.tip, div.warning, div.admonition {
  margin: 2em ;
  border: medium outset ;
  padding: 1em }

div.attention p.admonition-title, div.caution p.admonition-title,
div.danger p.admonition-title, div.error p.admonition-title,
div.warning p.admonition-title {
  color: red ;
  font-weight: bold ;
  font-family: sans-serif }

div.hint p.admonition-title, div.important p.admonition-title,
div.note p.admonition-title, div.tip p.admonition-title,
div.admonition p.admonition-title {
  font-weight: bold ;
  font-family: sans-serif }

div.dedication {
  margin: 2em 5em ;
  text-align: center ;
  font-style: italic }

div.dedication p.topic-title {
  font-weight: bold ;
  font-style: normal }

div.figure {
  margin-left: 2em }

div.footer, div.header {
  font-size: smaller }

div.sidebar {
  margin-left: 1em ;
  border: medium outset ;
  padding: 0em 1em ;
  background-color: #ffffee ;
  width: 40% ;
  float: right ;
  clear: right }

div.sidebar p.rubric {
  font-family: sans-serif ;
  font-size: medium }

div.system-messages {
  margin: 5em }

div.system-messages h1 {
  color: red }

div.system-message {
  border: medium outset ;
  padding: 1em }

div.system-message p.system-message-title {
  color: red ;
  font-weight: bold }

div.topic {
  margin: 2em }

h1.title {
  text-align: center }

h2.subtitle {
  text-align: center }

ol.simple, ul.simple {
  margin-bottom: 1em }

ol.arabic {
  list-style: decimal }

ol.loweralpha {
  list-style: lower-alpha }

ol.upperalpha {
  list-style: upper-alpha }

ol.lowerroman {
  list-style: lower-roman }

ol.upperroman {
  list-style: upper-roman }

p.attribution {
  text-align: right ;
  margin-left: 50% }

p.caption {
  font-style: italic }

p.credits {
  font-style: italic ;
  font-size: smaller }

p.label {
  white-space: nowrap }

p.rubric {
  font-weight: bold ;
  font-size: larger ;
  color: maroon ;
  text-align: center }

p.sidebar-title {
  font-family: sans-serif ;
  font-weight: bold ;
  font-size: larger }

p.sidebar-subtitle {
  font-family: sans-serif ;
  font-weight: bold }

p.topic-title {
  font-weight: bold }

pre.address {
  margin-bottom: 0 ;
  margin-top: 0 ;
  font-family: serif ;
  font-size: 100% }

pre.line-block {
  font-family: serif ;
  font-size: 100% }

pre.literal-block, pre.doctest-block {
  margin-left: 2em ;
  margin-right: 2em ;}
  /*background-color: #eeeeee }*/
  /*for some reason i can't overide in an import*/

span.classifier {
  font-family: sans-serif ;
  font-style: oblique }

span.classifier-delimiter {
  font-family: sans-serif ;
  font-weight: bold }

span.interpreted {
  font-family: sans-serif }

span.option {
  white-space: nowrap }

span.option-argument {
  font-style: italic }

span.pre {
  white-space: pre }

span.problematic {
  color: red }

table {
  margin-top: 0.5em ;
  margin-bottom: 0.5em }

table.citation {
  border-left: solid thin gray ;
  padding-left: 0.5ex }

table.docinfo {
  margin: 2em 4em }

table.footnote {
  border-left: solid thin black ;
  padding-left: 0.5ex }

td, th {
  padding-left: 0.5em ;
  padding-right: 0.5em ;
  vertical-align: top }

th.docinfo-name, th.field-name {
  font-weight: bold ;
  text-align: left ;
  white-space: nowrap }

h1 tt, h2 tt, h3 tt, h4 tt, h5 tt, h6 tt {
  font-size: 100% }

/*for some reason, the following isn't being overridden by the imports
at the end of this style sheet so I've commented it out*/
/*tt {
  background-color: #eeeeee }*/

ul.auto-toc {
  list-style-type: none }

hr { /* EKR */
  width: 100%;
  height: 1pt;
  color: gray;
}



</style>
</head>
<body>
<div class="document" id="title">
<h1 class="title">Title</h1>

<!-- rst3: filename: test.html -->
<p>This is test.html</p>
<div class="section" id="section">
<h1>section</h1>
<p>&#64; This is a doc part
it has two lines.
This is the body of the section.</p>
</div>
</div>
</body>
</html>
#@+node:ekr.20100827140832.5913: *4* @test rst3Test show_leo_directives=False
# Skip test when running test dynamically.
s = g.findTestScript(c,'@common leoRst test code',warn=False)
if s:
    exec(s)
    rst3Test(c,p)
#@+node:ekr.20100827140832.5917: *5* source
@language rest
#@+node:ekr.20100827140832.5918: *6* @rst test.html
@language rest

@ @rst-options
show_leo_directives=False
@c

#####
Title
#####

This is test.html
#@+node:ekr.20100827140832.5919: *7* section
@ This is a doc part
it has two lines.
@c
This is the body of the section.
#@+node:ekr.20100827140832.5926: *5* expected
#@+node:ekr.20100827140832.5929: *6* rst
.. rst3: filename: test.html



#####
Title
#####

This is test.html

section
+++++++

@ This is a doc part
it has two lines.
This is the body of the section.

#@+node:ekr.20100827140832.5930: *6* html
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="generator" content="Docutils VER: http://docutils.sourceforge.net/" />
<title>Title</title>
<style type="text/css">

/*ORIGINAL GOODGER + changes; up to line 224 it's standard reST stylesheet
:Author: David Goodger
:Contact: goodger@users.sourceforge.net
:date: $Date: 2006/10/19 13:23:15 $
:version: $Revision: 1.2 $
:copyright: This stylesheet has been placed in the public domain.

Default cascading style sheet for the HTML output of Docutils.
*/

/* EKR 10/19/06 */
/* some browsers require imported rules to precede all rulesets */
@import url(leo_rst.css);
@import url(silver_city.css);

.first {
  margin-top: 0 }

.last {
  margin-bottom: 0 }

a.toc-backref {
  text-decoration: none ;
  color: black }

dd {
  margin-bottom: 0.5em }

div.abstract {
  margin: 2em 5em }

div.abstract p.topic-title {
  font-weight: bold ;
  text-align: center }

div.attention, div.caution, div.danger, div.error, div.hint,
div.important, div.note, div.tip, div.warning, div.admonition {
  margin: 2em ;
  border: medium outset ;
  padding: 1em }

div.attention p.admonition-title, div.caution p.admonition-title,
div.danger p.admonition-title, div.error p.admonition-title,
div.warning p.admonition-title {
  color: red ;
  font-weight: bold ;
  font-family: sans-serif }

div.hint p.admonition-title, div.important p.admonition-title,
div.note p.admonition-title, div.tip p.admonition-title,
div.admonition p.admonition-title {
  font-weight: bold ;
  font-family: sans-serif }

div.dedication {
  margin: 2em 5em ;
  text-align: center ;
  font-style: italic }

div.dedication p.topic-title {
  font-weight: bold ;
  font-style: normal }

div.figure {
  margin-left: 2em }

div.footer, div.header {
  font-size: smaller }

div.sidebar {
  margin-left: 1em ;
  border: medium outset ;
  padding: 0em 1em ;
  background-color: #ffffee ;
  width: 40% ;
  float: right ;
  clear: right }

div.sidebar p.rubric {
  font-family: sans-serif ;
  font-size: medium }

div.system-messages {
  margin: 5em }

div.system-messages h1 {
  color: red }

div.system-message {
  border: medium outset ;
  padding: 1em }

div.system-message p.system-message-title {
  color: red ;
  font-weight: bold }

div.topic {
  margin: 2em }

h1.title {
  text-align: center }

h2.subtitle {
  text-align: center }

ol.simple, ul.simple {
  margin-bottom: 1em }

ol.arabic {
  list-style: decimal }

ol.loweralpha {
  list-style: lower-alpha }

ol.upperalpha {
  list-style: upper-alpha }

ol.lowerroman {
  list-style: lower-roman }

ol.upperroman {
  list-style: upper-roman }

p.attribution {
  text-align: right ;
  margin-left: 50% }

p.caption {
  font-style: italic }

p.credits {
  font-style: italic ;
  font-size: smaller }

p.label {
  white-space: nowrap }

p.rubric {
  font-weight: bold ;
  font-size: larger ;
  color: maroon ;
  text-align: center }

p.sidebar-title {
  font-family: sans-serif ;
  font-weight: bold ;
  font-size: larger }

p.sidebar-subtitle {
  font-family: sans-serif ;
  font-weight: bold }

p.topic-title {
  font-weight: bold }

pre.address {
  margin-bottom: 0 ;
  margin-top: 0 ;
  font-family: serif ;
  font-size: 100% }

pre.line-block {
  font-family: serif ;
  font-size: 100% }

pre.literal-block, pre.doctest-block {
  margin-left: 2em ;
  margin-right: 2em ;}
  /*background-color: #eeeeee }*/
  /*for some reason i can't overide in an import*/

span.classifier {
  font-family: sans-serif ;
  font-style: oblique }

span.classifier-delimiter {
  font-family: sans-serif ;
  font-weight: bold }

span.interpreted {
  font-family: sans-serif }

span.option {
  white-space: nowrap }

span.option-argument {
  font-style: italic }

span.pre {
  white-space: pre }

span.problematic {
  color: red }

table {
  margin-top: 0.5em ;
  margin-bottom: 0.5em }

table.citation {
  border-left: solid thin gray ;
  padding-left: 0.5ex }

table.docinfo {
  margin: 2em 4em }

table.footnote {
  border-left: solid thin black ;
  padding-left: 0.5ex }

td, th {
  padding-left: 0.5em ;
  padding-right: 0.5em ;
  vertical-align: top }

th.docinfo-name, th.field-name {
  font-weight: bold ;
  text-align: left ;
  white-space: nowrap }

h1 tt, h2 tt, h3 tt, h4 tt, h5 tt, h6 tt {
  font-size: 100% }

/*for some reason, the following isn't being overridden by the imports
at the end of this style sheet so I've commented it out*/
/*tt {
  background-color: #eeeeee }*/

ul.auto-toc {
  list-style-type: none }

hr { /* EKR */
  width: 100%;
  height: 1pt;
  color: gray;
}



</style>
</head>
<body>
<div class="document" id="title">
<h1 class="title">Title</h1>

<!-- rst3: filename: test.html -->
<p>This is test.html</p>
<div class="section" id="section">
<h1>section</h1>
<p>&#64; This is a doc part
it has two lines.
This is the body of the section.</p>
</div>
</div>
</body>
</html>
#@+node:ekr.20100827182529.6852: *5* got
#@+node:ekr.20100827182529.6853: *6* rst
.. rst3: filename: test.html



#####
Title
#####

This is test.html

section
+++++++

@ This is a doc part
it has two lines.
This is the body of the section.

#@+node:ekr.20100827182529.6854: *6* html
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="generator" content="Docutils VER: http://docutils.sourceforge.net/" />
<title>Title</title>
<style type="text/css">

/*ORIGINAL GOODGER + changes; up to line 224 it's standard reST stylesheet
:Author: David Goodger
:Contact: goodger@users.sourceforge.net
:date: $Date: 2006/10/19 13:23:15 $
:version: $Revision: 1.2 $
:copyright: This stylesheet has been placed in the public domain.

Default cascading style sheet for the HTML output of Docutils.
*/

/* EKR 10/19/06 */
/* some browsers require imported rules to precede all rulesets */
@import url(leo_rst.css);
@import url(silver_city.css);

.first {
  margin-top: 0 }

.last {
  margin-bottom: 0 }

a.toc-backref {
  text-decoration: none ;
  color: black }

dd {
  margin-bottom: 0.5em }

div.abstract {
  margin: 2em 5em }

div.abstract p.topic-title {
  font-weight: bold ;
  text-align: center }

div.attention, div.caution, div.danger, div.error, div.hint,
div.important, div.note, div.tip, div.warning, div.admonition {
  margin: 2em ;
  border: medium outset ;
  padding: 1em }

div.attention p.admonition-title, div.caution p.admonition-title,
div.danger p.admonition-title, div.error p.admonition-title,
div.warning p.admonition-title {
  color: red ;
  font-weight: bold ;
  font-family: sans-serif }

div.hint p.admonition-title, div.important p.admonition-title,
div.note p.admonition-title, div.tip p.admonition-title,
div.admonition p.admonition-title {
  font-weight: bold ;
  font-family: sans-serif }

div.dedication {
  margin: 2em 5em ;
  text-align: center ;
  font-style: italic }

div.dedication p.topic-title {
  font-weight: bold ;
  font-style: normal }

div.figure {
  margin-left: 2em }

div.footer, div.header {
  font-size: smaller }

div.sidebar {
  margin-left: 1em ;
  border: medium outset ;
  padding: 0em 1em ;
  background-color: #ffffee ;
  width: 40% ;
  float: right ;
  clear: right }

div.sidebar p.rubric {
  font-family: sans-serif ;
  font-size: medium }

div.system-messages {
  margin: 5em }

div.system-messages h1 {
  color: red }

div.system-message {
  border: medium outset ;
  padding: 1em }

div.system-message p.system-message-title {
  color: red ;
  font-weight: bold }

div.topic {
  margin: 2em }

h1.title {
  text-align: center }

h2.subtitle {
  text-align: center }

ol.simple, ul.simple {
  margin-bottom: 1em }

ol.arabic {
  list-style: decimal }

ol.loweralpha {
  list-style: lower-alpha }

ol.upperalpha {
  list-style: upper-alpha }

ol.lowerroman {
  list-style: lower-roman }

ol.upperroman {
  list-style: upper-roman }

p.attribution {
  text-align: right ;
  margin-left: 50% }

p.caption {
  font-style: italic }

p.credits {
  font-style: italic ;
  font-size: smaller }

p.label {
  white-space: nowrap }

p.rubric {
  font-weight: bold ;
  font-size: larger ;
  color: maroon ;
  text-align: center }

p.sidebar-title {
  font-family: sans-serif ;
  font-weight: bold ;
  font-size: larger }

p.sidebar-subtitle {
  font-family: sans-serif ;
  font-weight: bold }

p.topic-title {
  font-weight: bold }

pre.address {
  margin-bottom: 0 ;
  margin-top: 0 ;
  font-family: serif ;
  font-size: 100% }

pre.line-block {
  font-family: serif ;
  font-size: 100% }

pre.literal-block, pre.doctest-block {
  margin-left: 2em ;
  margin-right: 2em ;}
  /*background-color: #eeeeee }*/
  /*for some reason i can't overide in an import*/

span.classifier {
  font-family: sans-serif ;
  font-style: oblique }

span.classifier-delimiter {
  font-family: sans-serif ;
  font-weight: bold }

span.interpreted {
  font-family: sans-serif }

span.option {
  white-space: nowrap }

span.option-argument {
  font-style: italic }

span.pre {
  white-space: pre }

span.problematic {
  color: red }

table {
  margin-top: 0.5em ;
  margin-bottom: 0.5em }

table.citation {
  border-left: solid thin gray ;
  padding-left: 0.5ex }

table.docinfo {
  margin: 2em 4em }

table.footnote {
  border-left: solid thin black ;
  padding-left: 0.5ex }

td, th {
  padding-left: 0.5em ;
  padding-right: 0.5em ;
  vertical-align: top }

th.docinfo-name, th.field-name {
  font-weight: bold ;
  text-align: left ;
  white-space: nowrap }

h1 tt, h2 tt, h3 tt, h4 tt, h5 tt, h6 tt {
  font-size: 100% }

/*for some reason, the following isn't being overridden by the imports
at the end of this style sheet so I've commented it out*/
/*tt {
  background-color: #eeeeee }*/

ul.auto-toc {
  list-style-type: none }

hr { /* EKR */
  width: 100%;
  height: 1pt;
  color: gray;
}



</style>
</head>
<body>
<div class="document" id="title">
<h1 class="title">Title</h1>

<!-- rst3: filename: test.html -->
<p>This is test.html</p>
<div class="section" id="section">
<h1>section</h1>
<p>&#64; This is a doc part
it has two lines.
This is the body of the section.</p>
</div>
</div>
</body>
</html>
#@+node:ekr.20120307070541.3937: *4* @test rst3Test unicode characters
@first # -*- coding: utf-8 -*-

# Skip test when running test dynamically.
s = g.findTestScript(c,'@common leoRst test code',warn=False)
if s:
    exec(s)
    rst3Test(c,p)
#@+node:ekr.20120307070541.3941: *5* source
@language rest
#@+node:ekr.20120307070541.3942: *6* @rst test.html
@language rest

Test of unicode characters: ÀǋϢﻙ

End of test.
#@+node:ekr.20120307070541.3944: *5* expected
#@+node:ekr.20120307070541.3946: *6* rst
.. rst3: filename: test.html


Test of unicode characters: ÀǋϢﻙ

End of test.

#@+node:ekr.20120307070541.3947: *6* html
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="generator" content="Docutils VER: http://docutils.sourceforge.net/" />
<title></title>
<style type="text/css">

/*ORIGINAL GOODGER + changes; up to line 224 it's standard reST stylesheet
:Author: David Goodger
:Contact: goodger@users.sourceforge.net
:date: $Date: 2006/10/19 13:23:15 $
:version: $Revision: 1.2 $
:copyright: This stylesheet has been placed in the public domain.

Default cascading style sheet for the HTML output of Docutils.
*/

/* EKR 10/19/06 */
/* some browsers require imported rules to precede all rulesets */
@import url(leo_rst.css);
@import url(silver_city.css);

.first {
  margin-top: 0 }

.last {
  margin-bottom: 0 }

a.toc-backref {
  text-decoration: none ;
  color: black }

dd {
  margin-bottom: 0.5em }

div.abstract {
  margin: 2em 5em }

div.abstract p.topic-title {
  font-weight: bold ;
  text-align: center }

div.attention, div.caution, div.danger, div.error, div.hint,
div.important, div.note, div.tip, div.warning, div.admonition {
  margin: 2em ;
  border: medium outset ;
  padding: 1em }

div.attention p.admonition-title, div.caution p.admonition-title,
div.danger p.admonition-title, div.error p.admonition-title,
div.warning p.admonition-title {
  color: red ;
  font-weight: bold ;
  font-family: sans-serif }

div.hint p.admonition-title, div.important p.admonition-title,
div.note p.admonition-title, div.tip p.admonition-title,
div.admonition p.admonition-title {
  font-weight: bold ;
  font-family: sans-serif }

div.dedication {
  margin: 2em 5em ;
  text-align: center ;
  font-style: italic }

div.dedication p.topic-title {
  font-weight: bold ;
  font-style: normal }

div.figure {
  margin-left: 2em }

div.footer, div.header {
  font-size: smaller }

div.sidebar {
  margin-left: 1em ;
  border: medium outset ;
  padding: 0em 1em ;
  background-color: #ffffee ;
  width: 40% ;
  float: right ;
  clear: right }

div.sidebar p.rubric {
  font-family: sans-serif ;
  font-size: medium }

div.system-messages {
  margin: 5em }

div.system-messages h1 {
  color: red }

div.system-message {
  border: medium outset ;
  padding: 1em }

div.system-message p.system-message-title {
  color: red ;
  font-weight: bold }

div.topic {
  margin: 2em }

h1.title {
  text-align: center }

h2.subtitle {
  text-align: center }

ol.simple, ul.simple {
  margin-bottom: 1em }

ol.arabic {
  list-style: decimal }

ol.loweralpha {
  list-style: lower-alpha }

ol.upperalpha {
  list-style: upper-alpha }

ol.lowerroman {
  list-style: lower-roman }

ol.upperroman {
  list-style: upper-roman }

p.attribution {
  text-align: right ;
  margin-left: 50% }

p.caption {
  font-style: italic }

p.credits {
  font-style: italic ;
  font-size: smaller }

p.label {
  white-space: nowrap }

p.rubric {
  font-weight: bold ;
  font-size: larger ;
  color: maroon ;
  text-align: center }

p.sidebar-title {
  font-family: sans-serif ;
  font-weight: bold ;
  font-size: larger }

p.sidebar-subtitle {
  font-family: sans-serif ;
  font-weight: bold }

p.topic-title {
  font-weight: bold }

pre.address {
  margin-bottom: 0 ;
  margin-top: 0 ;
  font-family: serif ;
  font-size: 100% }

pre.line-block {
  font-family: serif ;
  font-size: 100% }

pre.literal-block, pre.doctest-block {
  margin-left: 2em ;
  margin-right: 2em ;}
  /*background-color: #eeeeee }*/
  /*for some reason i can't overide in an import*/

span.classifier {
  font-family: sans-serif ;
  font-style: oblique }

span.classifier-delimiter {
  font-family: sans-serif ;
  font-weight: bold }

span.interpreted {
  font-family: sans-serif }

span.option {
  white-space: nowrap }

span.option-argument {
  font-style: italic }

span.pre {
  white-space: pre }

span.problematic {
  color: red }

table {
  margin-top: 0.5em ;
  margin-bottom: 0.5em }

table.citation {
  border-left: solid thin gray ;
  padding-left: 0.5ex }

table.docinfo {
  margin: 2em 4em }

table.footnote {
  border-left: solid thin black ;
  padding-left: 0.5ex }

td, th {
  padding-left: 0.5em ;
  padding-right: 0.5em ;
  vertical-align: top }

th.docinfo-name, th.field-name {
  font-weight: bold ;
  text-align: left ;
  white-space: nowrap }

h1 tt, h2 tt, h3 tt, h4 tt, h5 tt, h6 tt {
  font-size: 100% }

/*for some reason, the following isn't being overridden by the imports
at the end of this style sheet so I've commented it out*/
/*tt {
  background-color: #eeeeee }*/

ul.auto-toc {
  list-style-type: none }

hr { /* EKR */
  width: 100%;
  height: 1pt;
  color: gray;
}



</style>
</head>
<body>
<div class="document">


<!-- rst3: filename: test.html -->
<p>Test of unicode characters: ÀǋϢﻙ</p>
<p>End of test.</p>
</div>
</body>
</html>
#@+node:ekr.20120307070541.3945: *5* got
#@+node:ekr.20120307070541.3948: *6* rst
.. rst3: filename: test.html


Test of unicode characters: ÀǋϢﻙ

End of test.

#@+node:ekr.20120307070541.3949: *6* html
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="generator" content="Docutils VER: http://docutils.sourceforge.net/" />
<title></title>
<style type="text/css">

/*ORIGINAL GOODGER + changes; up to line 224 it's standard reST stylesheet
:Author: David Goodger
:Contact: goodger@users.sourceforge.net
:date: $Date: 2006/10/19 13:23:15 $
:version: $Revision: 1.2 $
:copyright: This stylesheet has been placed in the public domain.

Default cascading style sheet for the HTML output of Docutils.
*/

/* EKR 10/19/06 */
/* some browsers require imported rules to precede all rulesets */
@import url(leo_rst.css);
@import url(silver_city.css);

.first {
  margin-top: 0 }

.last {
  margin-bottom: 0 }

a.toc-backref {
  text-decoration: none ;
  color: black }

dd {
  margin-bottom: 0.5em }

div.abstract {
  margin: 2em 5em }

div.abstract p.topic-title {
  font-weight: bold ;
  text-align: center }

div.attention, div.caution, div.danger, div.error, div.hint,
div.important, div.note, div.tip, div.warning, div.admonition {
  margin: 2em ;
  border: medium outset ;
  padding: 1em }

div.attention p.admonition-title, div.caution p.admonition-title,
div.danger p.admonition-title, div.error p.admonition-title,
div.warning p.admonition-title {
  color: red ;
  font-weight: bold ;
  font-family: sans-serif }

div.hint p.admonition-title, div.important p.admonition-title,
div.note p.admonition-title, div.tip p.admonition-title,
div.admonition p.admonition-title {
  font-weight: bold ;
  font-family: sans-serif }

div.dedication {
  margin: 2em 5em ;
  text-align: center ;
  font-style: italic }

div.dedication p.topic-title {
  font-weight: bold ;
  font-style: normal }

div.figure {
  margin-left: 2em }

div.footer, div.header {
  font-size: smaller }

div.sidebar {
  margin-left: 1em ;
  border: medium outset ;
  padding: 0em 1em ;
  background-color: #ffffee ;
  width: 40% ;
  float: right ;
  clear: right }

div.sidebar p.rubric {
  font-family: sans-serif ;
  font-size: medium }

div.system-messages {
  margin: 5em }

div.system-messages h1 {
  color: red }

div.system-message {
  border: medium outset ;
  padding: 1em }

div.system-message p.system-message-title {
  color: red ;
  font-weight: bold }

div.topic {
  margin: 2em }

h1.title {
  text-align: center }

h2.subtitle {
  text-align: center }

ol.simple, ul.simple {
  margin-bottom: 1em }

ol.arabic {
  list-style: decimal }

ol.loweralpha {
  list-style: lower-alpha }

ol.upperalpha {
  list-style: upper-alpha }

ol.lowerroman {
  list-style: lower-roman }

ol.upperroman {
  list-style: upper-roman }

p.attribution {
  text-align: right ;
  margin-left: 50% }

p.caption {
  font-style: italic }

p.credits {
  font-style: italic ;
  font-size: smaller }

p.label {
  white-space: nowrap }

p.rubric {
  font-weight: bold ;
  font-size: larger ;
  color: maroon ;
  text-align: center }

p.sidebar-title {
  font-family: sans-serif ;
  font-weight: bold ;
  font-size: larger }

p.sidebar-subtitle {
  font-family: sans-serif ;
  font-weight: bold }

p.topic-title {
  font-weight: bold }

pre.address {
  margin-bottom: 0 ;
  margin-top: 0 ;
  font-family: serif ;
  font-size: 100% }

pre.line-block {
  font-family: serif ;
  font-size: 100% }

pre.literal-block, pre.doctest-block {
  margin-left: 2em ;
  margin-right: 2em ;}
  /*background-color: #eeeeee }*/
  /*for some reason i can't overide in an import*/

span.classifier {
  font-family: sans-serif ;
  font-style: oblique }

span.classifier-delimiter {
  font-family: sans-serif ;
  font-weight: bold }

span.interpreted {
  font-family: sans-serif }

span.option {
  white-space: nowrap }

span.option-argument {
  font-style: italic }

span.pre {
  white-space: pre }

span.problematic {
  color: red }

table {
  margin-top: 0.5em ;
  margin-bottom: 0.5em }

table.citation {
  border-left: solid thin gray ;
  padding-left: 0.5ex }

table.docinfo {
  margin: 2em 4em }

table.footnote {
  border-left: solid thin black ;
  padding-left: 0.5ex }

td, th {
  padding-left: 0.5em ;
  padding-right: 0.5em ;
  vertical-align: top }

th.docinfo-name, th.field-name {
  font-weight: bold ;
  text-align: left ;
  white-space: nowrap }

h1 tt, h2 tt, h3 tt, h4 tt, h5 tt, h6 tt {
  font-size: 100% }

/*for some reason, the following isn't being overridden by the imports
at the end of this style sheet so I've commented it out*/
/*tt {
  background-color: #eeeeee }*/

ul.auto-toc {
  list-style-type: none }

hr { /* EKR */
  width: 100%;
  height: 1pt;
  color: gray;
}



</style>
</head>
<body>
<div class="document">


<!-- rst3: filename: test.html -->
<p>Test of unicode characters: ÀǋϢﻙ</p>
<p>End of test.</p>
</div>
</body>
</html>
#@+node:ekr.20090529115704.4396: *3* leoShadow
#@+node:ekr.20090529115704.4560: *4* @@test (minitest) x.show_error
x = c.shadowController

lines1 = ('a','b','c')
lines2 = ('a','x','c')

x.show_error(
    lines1,lines2,
    message = "Test of x.show_error",
    lines1_message = "lines1",
    lines2_message = "lines2")
#@+node:ekr.20090529115704.4397: *4* @suite run @shadow-test nodes in the @shadow-tests tree
import unittest
import leo.core.leoShadow as leoShadow
# Possible: replace this suite with individual @test nodes
# exec(g.findTestScript(c,'@common @shadow test code'))
x = c.shadowController
suite = unittest.makeSuite(unittest.TestCase)
root = g.findNodeInTree(c,p,'@shadow-tests')
assert root, 'Node not found: @shadow-tests'
for p in root.children_iter():
    h = p.h.strip()
    if h.startswith('@shadow-test'):
        test = x.AtShadowTestCase(c,p,x,trace=False)
        suite.addTest(test)
#@+node:ekr.20090529115704.4398: *5* @shadow-tests
@

All the tags should be tested at least once (equal, replace, delete, insert).

The replace, delete, insert operations should happen at least once:
    1. At the beginning of a node.
    2. In the middle of a node.
    3. At the end of a node.

For the delete and replace operators we must also test the case that the
deletion or replacement spans more than one block.
#@+node:ekr.20101023195640.6033: *6* @shadow-test replace in node new > old
#@+node:ekr.20101023195640.6034: *7* old
@others
#@+node:ekr.20101023195640.6035: *8* node 1
node 1 line 1
node 1 old line 1
node 1 old line 2
node 1 line 2
#@+node:ekr.20101023195640.6037: *7* new
@others
#@+node:ekr.20101023195640.6038: *8* node 1
node 1 line 1
node 1 new line 1
node 1 new line 2
node 1 new line 3
node 1 line 2
#@+node:ekr.20101023204543.6042: *6* @shadow-test replace in node new < old
#@+node:ekr.20101023204543.6043: *7* old
@others
#@+node:ekr.20101023204543.6044: *8* node 1
node 1 line 1
node 1 old line 1
node 1 old line 2
node 1 old line 3
node 1 old line 4
node 1 line 2
#@+node:ekr.20101023204543.6045: *7* new
@others
#@+node:ekr.20101023204543.6046: *8* node 1
node 1 line 1
node 1 new line 1
node 1 new line 2
node 1 line 2
#@+node:ekr.20090529115704.4400: *6* @shadow-test change middle line
#@+node:ekr.20090529115704.4401: *7* old
line 1
line 2
line 3
#@+node:ekr.20090529115704.4402: *7* new
line 1
line 2 changed
line 3
#@+node:ekr.20090529115704.4403: *6* @shadow-test change first line
#@+node:ekr.20090529115704.4404: *7* old
line 1
line 2
line 3
#@+node:ekr.20090529115704.4405: *7* new
line 1 changed
line 2
line 3
#@+node:ekr.20090529115704.4406: *6* @shadow-test change last line
#@+node:ekr.20090529115704.4407: *7* old
line 1
line 2
line 3
#@+node:ekr.20090529115704.4408: *7* new
line 1
line 2
line 3 changed
#@+node:ekr.20090529115704.4409: *6* @shadow-test delete first line
#@+node:ekr.20090529115704.4410: *7* old
line 1
line 2
line 3
#@+node:ekr.20090529115704.4411: *7* new
line 2
line 3
#@+node:ekr.20090529115704.4412: *6* @shadow-test delete middle line
#@+node:ekr.20090529115704.4413: *7* old
line 1
line 2
line 3
#@+node:ekr.20090529115704.4414: *7* new
line 1
line 3
#@+node:ekr.20090529115704.4415: *6* @shadow-test delete last line
#@+node:ekr.20090529115704.4416: *7* old
line 1
line 2
line 3
#@+node:ekr.20090529115704.4417: *7* new
line 1
line 2
#@+node:ekr.20090529115704.4418: *6* @shadow-test insert before first line
#@+node:ekr.20090529115704.4419: *7* old
line 1
line 2
line 3
#@+node:ekr.20090529115704.4420: *7* new
inserted line
line 1
line 2
line 3
#@+node:ekr.20090529115704.4421: *6* @shadow-test insert middle line (after first line)
#@+node:ekr.20090529115704.4422: *7* old
line 1
line 2
line 3
#@+node:ekr.20090529115704.4423: *7* new
line 1
inserted line
line 2
line 3
#@+node:ekr.20090529115704.4424: *6* @shadow-test insert middle line (before last line)
#@+node:ekr.20090529115704.4425: *7* old
line 1
line 2
line 3
#@+node:ekr.20090529115704.4426: *7* new
line 1
line 2
inserted line
line 3
#@+node:ekr.20090529115704.4427: *6* @shadow-test insert after last line
#@+node:ekr.20090529115704.4428: *7* old
line 1
line 2
line 3
#@+node:ekr.20090529115704.4429: *7* new
line 1
line 2
line 3
inserted line
#@+node:ekr.20090529115704.4430: *6* @shadow-test-lax insert between nodes: at end of prev node
#@+node:ekr.20090529115704.4431: *7* old
@others
#@+node:ekr.20090529115704.4432: *8* node 1
node 1 line 1
#@+node:ekr.20090529115704.4433: *8* node 2
node 2 line 1
#@+node:ekr.20090529115704.4434: *7* new
@others
#@+node:ekr.20090529115704.4435: *8* node 1
node 1 line 1
inserted node at end of node 1
#@+node:ekr.20090529115704.4436: *8* node 2
node 2 line 1
#@+node:ekr.20090529115704.4444: *6* @shadow-test delete between nodes: at end of prev node
#@+node:ekr.20090529115704.4445: *7* old
@others
#@+node:ekr.20090529115704.4446: *8* node 1
node 1 line 1
node 1 line 2
#@+node:ekr.20090529115704.4447: *8* node 2
node 2 line 1
node 2 line 2
#@+node:ekr.20090529115704.4448: *7* new
@others
#@+node:ekr.20090529115704.4449: *8* node 1
node 1 line 1
#@+node:ekr.20090529115704.4450: *8* node 2
node 2 line 1
node 2 line 2
#@+node:ekr.20090529115704.4451: *6* @shadow-test delete between nodes: at start of next node
#@+node:ekr.20090529115704.4452: *7* old
@others
#@+node:ekr.20090529115704.4453: *8* node 1
node 1 line 1
#@+node:ekr.20090529115704.4454: *8* node 2
node 2 line 1
node 2 line 2
#@+node:ekr.20090529115704.4455: *7* new
@others
#@+node:ekr.20090529115704.4456: *8* node 1
node 1 line 1
#@+node:ekr.20090529115704.4457: *8* node 2
node 2 line 2
#@+node:ekr.20090529115704.4458: *6* @shadow-test change end of prev node
#@+node:ekr.20090529115704.4459: *7* old
@others
#@+node:ekr.20090529115704.4460: *8* node 1
node 1 line 1
node 1 line 2
#@+node:ekr.20090529115704.4461: *8* node 2
node 2 line 1
node 2 line 2
#@+node:ekr.20090529115704.4462: *7* new
@others
#@+node:ekr.20090529115704.4463: *8* node 1
node 1 line 1
node 1 line 1 changed
#@+node:ekr.20090529115704.4464: *8* node 2
node 2 line 1
node 2 line 2
#@+node:ekr.20090529115704.4465: *6* @shadow-test change start of next node
#@+node:ekr.20090529115704.4466: *7* old
@others
#@+node:ekr.20090529115704.4467: *8* node 1
node 1 line 1
node 1 line 2
#@+node:ekr.20090529115704.4468: *8* node 2
node 2 line 1
node 2 line 2
#@+node:ekr.20090529115704.4469: *7* new
@others
#@+node:ekr.20090529115704.4470: *8* node 1
node 1 line 1
node 1 line 2
#@+node:ekr.20090529115704.4471: *8* node 2
node 2 line 1 changed
node 2 line 2
#@+node:ekr.20090529115704.4472: *6* @shadow-test-lax multiple-line insert between nodes: at end of prev node
#@+node:ekr.20090529115704.4473: *7* old
@others
#@+node:ekr.20090529115704.4474: *8* node 1
node 1 line 1
inserted node 1 at end of node 1
inserted node 2 at end of node 1
#@+node:ekr.20090529115704.4475: *8* node 2
node 2 line 1
#@+node:ekr.20090529115704.4476: *7* new
@others
#@+node:ekr.20090529115704.4477: *8* node 1
node 1 line 1
#@+node:ekr.20090529115704.4478: *8* node 2
node 2 line 1
#@+node:ekr.20090529115704.4486: *6* @shadow-test multiple-line change end of prev node
#@+node:ekr.20090529115704.4487: *7* old
@others
#@+node:ekr.20090529115704.4488: *8* node 1
node 1 line 1
node 1 line 2
node 1 line 3
#@+node:ekr.20090529115704.4489: *8* node 2
node 2 line 1
node 2 line 2
#@+node:ekr.20090529115704.4490: *7* new
@others
#@+node:ekr.20090529115704.4491: *8* node 1
node 1 line 1
node 1 line 2 changed
node 1 line 3 changed
#@+node:ekr.20090529115704.4492: *8* node 2
node 2 line 1
node 2 line 2
#@+node:ekr.20090529115704.4493: *6* @shadow-test multiple-line change start of next node
#@+node:ekr.20090529115704.4494: *7* old
@others
#@+node:ekr.20090529115704.4495: *8* node 1
node 1 line 1
node 1 line 2
#@+node:ekr.20090529115704.4496: *8* node 2
node 2 line 1
node 2 line 2
#@+node:ekr.20090529115704.4497: *7* new
@others
#@+node:ekr.20090529115704.4498: *8* node 1
node 1 line 1
node 1 line 2
#@+node:ekr.20090529115704.4499: *8* node 2
node 2 line 1 changed
node 2 line 2 changed
#@+node:ekr.20100107110353.5105: *6* @shadow-test multiple-NODE changes
#@+node:ekr.20100107110353.5106: *7* old
@others
#@+node:ekr.20100107110353.5107: *8* node 1
node 1 line 1
node 1 line 2
#@+node:ekr.20100107110353.5108: *8* node 2
node 2 line 1
node 2 line 2
#@+node:ekr.20100107110353.5109: *7* new
@others
#@+node:ekr.20100107110353.5110: *8* node 1
node 1 line 1
node 1 line 2 changed
#@+node:ekr.20100107110353.5111: *8* node 2
node 2 line 1 changed
node 2 line 2 changed
#@+node:ekr.20090529115704.4500: *6* @shadow-test multiple-line delete between nodes: at end of prev node
#@+node:ekr.20090529115704.4501: *7* old
@others
#@+node:ekr.20090529115704.4502: *8* node 1
node 1 line 1
node 1 line 2
node 1 line 3
#@+node:ekr.20090529115704.4503: *8* node 2
node 2 line 1
node 2 line 2
#@+node:ekr.20090529115704.4504: *7* new
@others
#@+node:ekr.20090529115704.4505: *8* node 1
node 1 line 1
#@+node:ekr.20090529115704.4506: *8* node 2
node 2 line 1
node 2 line 2
#@+node:ekr.20090529115704.4507: *6* @shadow-test multiple-line delete between nodes: at start of next node
#@+node:ekr.20090529115704.4508: *7* old
@others
#@+node:ekr.20090529115704.4509: *8* node 1
node 1 line 1
#@+node:ekr.20090529115704.4510: *8* node 2
node 2 line 1
node 2 line 2
node 2 line 3
#@+node:ekr.20090529115704.4511: *7* new
@others
#@+node:ekr.20090529115704.4512: *8* node 1
node 1 line 1
#@+node:ekr.20090529115704.4513: *8* node 2
node 2 line 3
#@+node:ekr.20090529115704.4514: *6* @shadow-test verbatim sentinels-delete verbatim line
#@+node:ekr.20090529115704.4515: *7* old
@others
#@+node:ekr.20090529115704.4516: *8* node 1
node 1 line 1
@verbatim
@verbatim
@verbatim
@verbatim
#@verbatim
#@ should be handled by verbatim
line 1 line 3
#@+node:ekr.20090529115704.4517: *8* node 2
node 2 line 1
node 2 line 2
node 2 line 3
#@+node:ekr.20090529115704.4518: *7* new
@others
#@+node:ekr.20090529115704.4519: *8* node 1
node 1 line 1
line 1 line 3
#@+node:ekr.20090529115704.4520: *8* node 2
node 2 line 1
node 2 line 2
node 2 line 3
#@+node:ekr.20090529115704.4521: *6* @shadow-test verbatim sentinels-delete verbatim line: at start of node
#@+node:ekr.20090529115704.4522: *7* old
@others
#@+node:ekr.20090529115704.4523: *8* node 1
node 1 line 1
#@+node:ekr.20090529115704.4524: *8* node 2
@verbatim
@verbatim
@verbatim
@verbatim
#@verbatim
#@ should be handled by verbatim
node 2 line 2
#@+node:ekr.20090529115704.4525: *7* new
@others
#@+node:ekr.20090529115704.4526: *8* node 1
node 1 line 1
#@+node:ekr.20090529115704.4527: *8* node 2
node 2 line 2
#@+node:ekr.20090529115704.4528: *6* @shadow-test verbatim sentinels-no change
#@+node:ekr.20090529115704.4529: *7* old
@others
#@+node:ekr.20090529115704.4530: *8* node 1
node 1 line 1
@verbatim
@verbatim
@verbatim
@verbatim
#@verbatim
#@ should be handled by verbatim
line 1 line 3
#@+node:ekr.20090529115704.4531: *8* node 2
node 2 line 1
node 2 line 2
node 2 line 3
#@+node:ekr.20090529115704.4532: *7* new
@others
#@+node:ekr.20090529115704.4533: *8* node 1
node 1 line 1
@verbatim
@verbatim
@verbatim
@verbatim
#@verbatim
#@ should be handled by verbatim
line 1 line 3
#@+node:ekr.20090529115704.4534: *8* node 2
node 2 line 1
node 2 line 2
node 2 line 3
#@+node:ekr.20090529115704.4535: *6* @shadow-test verbatim sentinels-delete verbatim line: at end of node
#@+node:ekr.20090529115704.4536: *7* old
@others
#@+node:ekr.20090529115704.4537: *8* node 1
node 1 line 1
@verbatim
@verbatim
@verbatim
@verbatim
#@verbatim
#@ should be handled by verbatim
#@+node:ekr.20090529115704.4538: *8* node 2
node 2 line 1
node 2 line 2
#@+node:ekr.20090529115704.4539: *7* new
@others
#@+node:ekr.20090529115704.4540: *8* node 1
node 1 line 1
#@+node:ekr.20090529115704.4541: *8* node 2
node 2 line 1
node 2 line 2
#@+node:ekr.20090529115704.4542: *6* @shadow-test verbatim sentinels-add verbatim line
# This fails because the @all read logic inserts a second verbatim, I think.
#@+node:ekr.20090529115704.4543: *7* old
@others
#@+node:ekr.20090529115704.4544: *8* node 1
node 1 line 1
node 1 line 2
#@+node:ekr.20090529115704.4545: *8* node 2
node 2 line 1
node 2 line 2
#@+node:ekr.20090529115704.4546: *7* new
@others
#@+node:ekr.20090529115704.4547: *8* node 1
node 1 line 1
@verbatim
#@verbatim
#@ should be handled by verbatim
node 1 line 2
#@+node:ekr.20090529115704.4548: *8* node 2
node 2 line 1
node 2 line 2
#@+node:ekr.20150210195923.11: *6* @shadow-test no change, no ending newline
#@+node:ekr.20150210195923.12: *7* old
line
#@+node:ekr.20150210195923.15: *7* new
line
#@+node:ekr.20150216070628.11: *4* @@suite @nosent with javascript
import unittest
import leo.core.leoShadow as leoShadow
# Possible: replace this suite with individual @test nodes
# exec(g.findTestScript(c,'@common @shadow test code'))
x = c.shadowController
suite = unittest.makeSuite(unittest.TestCase)
root = g.findNodeInTree(c,p,'@shadow-tests')
assert root, 'Node not found: @shadow-tests'
delims = '//','',''
for p in root.children_iter():
    h = p.h.strip()
    if h.startswith('@shadow-test'):
        test = x.AtShadowTestCase(c,p,x,delims=delims,trace=False)
        suite.addTest(test)
#@+node:ekr.20150216070628.12: *5* @shadow-tests
@

All the tags should be tested at least once (equal, replace, delete, insert).

The replace, delete, insert operations should happen at least once:
    1. At the beginning of a node.
    2. In the middle of a node.
    3. At the end of a node.

For the delete and replace operators we must also test the case that the
deletion or replacement spans more than one block.
#@+node:ekr.20150216070628.168: *6* @shadow-test equal @nosent @doc
#@+node:ekr.20150216070628.14: *7* old
@others
#@+node:ekr.20150216070628.15: *8* node 1
@
node 1 old line 1
node 1 old line 2
node 1 line 2
#@+node:ekr.20150216070628.16: *7* new
@others
#@+node:ekr.20150216070628.17: *8* node 1
@
node 1 old line 1
node 1 old line 2
node 1 line 2
#@+node:ekr.20150216070628.18: *6* @shadow-test replace in node new < old
#@+node:ekr.20150216070628.19: *7* old
@others
#@+node:ekr.20150216070628.20: *8* node 1
node 1 line 1
node 1 old line 1
node 1 old line 2
node 1 old line 3
node 1 old line 4
node 1 line 2
#@+node:ekr.20150216070628.21: *7* new
@others
#@+node:ekr.20150216070628.22: *8* node 1
node 1 line 1
node 1 new line 1
node 1 new line 2
node 1 line 2
#@+node:ekr.20150216070628.23: *6* @shadow-test change middle line
#@+node:ekr.20150216070628.24: *7* old
line 1
line 2
line 3
#@+node:ekr.20150216070628.25: *7* new
line 1
line 2 changed
line 3
#@+node:ekr.20150216070628.26: *6* @shadow-test change first line
#@+node:ekr.20150216070628.27: *7* old
line 1
line 2
line 3
#@+node:ekr.20150216070628.28: *7* new
line 1 changed
line 2
line 3
#@+node:ekr.20150216070628.29: *6* @shadow-test change last line
#@+node:ekr.20150216070628.30: *7* old
line 1
line 2
line 3
#@+node:ekr.20150216070628.31: *7* new
line 1
line 2
line 3 changed
#@+node:ekr.20150216070628.32: *6* @shadow-test delete first line
#@+node:ekr.20150216070628.33: *7* old
line 1
line 2
line 3
#@+node:ekr.20150216070628.34: *7* new
line 2
line 3
#@+node:ekr.20150216070628.35: *6* @shadow-test delete middle line
#@+node:ekr.20150216070628.36: *7* old
line 1
line 2
line 3
#@+node:ekr.20150216070628.37: *7* new
line 1
line 3
#@+node:ekr.20150216070628.38: *6* @shadow-test delete last line
#@+node:ekr.20150216070628.39: *7* old
line 1
line 2
line 3
#@+node:ekr.20150216070628.40: *7* new
line 1
line 2
#@+node:ekr.20150216070628.41: *6* @shadow-test insert before first line
#@+node:ekr.20150216070628.42: *7* old
line 1
line 2
line 3
#@+node:ekr.20150216070628.43: *7* new
inserted line
line 1
line 2
line 3
#@+node:ekr.20150216070628.44: *6* @shadow-test insert middle line (after first line)
#@+node:ekr.20150216070628.45: *7* old
line 1
line 2
line 3
#@+node:ekr.20150216070628.46: *7* new
line 1
inserted line
line 2
line 3
#@+node:ekr.20150216070628.47: *6* @shadow-test insert middle line (before last line)
#@+node:ekr.20150216070628.48: *7* old
line 1
line 2
line 3
#@+node:ekr.20150216070628.49: *7* new
line 1
line 2
inserted line
line 3
#@+node:ekr.20150216070628.50: *6* @shadow-test insert after last line
#@+node:ekr.20150216070628.51: *7* old
line 1
line 2
line 3
#@+node:ekr.20150216070628.52: *7* new
line 1
line 2
line 3
inserted line
#@+node:ekr.20150216070628.53: *6* @shadow-test-lax insert between nodes: at end of prev node
#@+node:ekr.20150216070628.54: *7* old
@others
#@+node:ekr.20150216070628.55: *8* node 1
node 1 line 1
#@+node:ekr.20150216070628.56: *8* node 2
node 2 line 1
#@+node:ekr.20150216070628.57: *7* new
@others
#@+node:ekr.20150216070628.58: *8* node 1
node 1 line 1
inserted node at end of node 1
#@+node:ekr.20150216070628.59: *8* node 2
node 2 line 1
#@+node:ekr.20150216070628.60: *6* @shadow-test delete between nodes: at end of prev node
#@+node:ekr.20150216070628.61: *7* old
@others
#@+node:ekr.20150216070628.62: *8* node 1
node 1 line 1
node 1 line 2
#@+node:ekr.20150216070628.63: *8* node 2
node 2 line 1
node 2 line 2
#@+node:ekr.20150216070628.64: *7* new
@others
#@+node:ekr.20150216070628.65: *8* node 1
node 1 line 1
#@+node:ekr.20150216070628.66: *8* node 2
node 2 line 1
node 2 line 2
#@+node:ekr.20150216070628.67: *6* @shadow-test delete between nodes: at start of next node
#@+node:ekr.20150216070628.68: *7* old
@others
#@+node:ekr.20150216070628.69: *8* node 1
node 1 line 1
#@+node:ekr.20150216070628.70: *8* node 2
node 2 line 1
node 2 line 2
#@+node:ekr.20150216070628.71: *7* new
@others
#@+node:ekr.20150216070628.72: *8* node 1
node 1 line 1
#@+node:ekr.20150216070628.73: *8* node 2
node 2 line 2
#@+node:ekr.20150216070628.74: *6* @shadow-test change end of prev node
#@+node:ekr.20150216070628.75: *7* old
@others
#@+node:ekr.20150216070628.76: *8* node 1
node 1 line 1
node 1 line 2
#@+node:ekr.20150216070628.77: *8* node 2
node 2 line 1
node 2 line 2
#@+node:ekr.20150216070628.78: *7* new
@others
#@+node:ekr.20150216070628.79: *8* node 1
node 1 line 1
node 1 line 1 changed
#@+node:ekr.20150216070628.80: *8* node 2
node 2 line 1
node 2 line 2
#@+node:ekr.20150216070628.81: *6* @shadow-test change start of next node
#@+node:ekr.20150216070628.82: *7* old
@others
#@+node:ekr.20150216070628.83: *8* node 1
node 1 line 1
node 1 line 2
#@+node:ekr.20150216070628.84: *8* node 2
node 2 line 1
node 2 line 2
#@+node:ekr.20150216070628.85: *7* new
@others
#@+node:ekr.20150216070628.86: *8* node 1
node 1 line 1
node 1 line 2
#@+node:ekr.20150216070628.87: *8* node 2
node 2 line 1 changed
node 2 line 2
#@+node:ekr.20150216070628.88: *6* @shadow-test-lax multiple-line insert between nodes: at end of prev node
#@+node:ekr.20150216070628.89: *7* old
@others
#@+node:ekr.20150216070628.90: *8* node 1
node 1 line 1
inserted node 1 at end of node 1
inserted node 2 at end of node 1
#@+node:ekr.20150216070628.91: *8* node 2
node 2 line 1
#@+node:ekr.20150216070628.92: *7* new
@others
#@+node:ekr.20150216070628.93: *8* node 1
node 1 line 1
#@+node:ekr.20150216070628.94: *8* node 2
node 2 line 1
#@+node:ekr.20150216070628.95: *6* @shadow-test multiple-line change end of prev node
#@+node:ekr.20150216070628.96: *7* old
@others
#@+node:ekr.20150216070628.97: *8* node 1
node 1 line 1
node 1 line 2
node 1 line 3
#@+node:ekr.20150216070628.98: *8* node 2
node 2 line 1
node 2 line 2
#@+node:ekr.20150216070628.99: *7* new
@others
#@+node:ekr.20150216070628.100: *8* node 1
node 1 line 1
node 1 line 2 changed
node 1 line 3 changed
#@+node:ekr.20150216070628.101: *8* node 2
node 2 line 1
node 2 line 2
#@+node:ekr.20150216070628.102: *6* @shadow-test multiple-line change start of next node
#@+node:ekr.20150216070628.103: *7* old
@others
#@+node:ekr.20150216070628.104: *8* node 1
node 1 line 1
node 1 line 2
#@+node:ekr.20150216070628.105: *8* node 2
node 2 line 1
node 2 line 2
#@+node:ekr.20150216070628.106: *7* new
@others
#@+node:ekr.20150216070628.107: *8* node 1
node 1 line 1
node 1 line 2
#@+node:ekr.20150216070628.108: *8* node 2
node 2 line 1 changed
node 2 line 2 changed
#@+node:ekr.20150216070628.109: *6* @shadow-test multiple-NODE changes
#@+node:ekr.20150216070628.110: *7* old
@others
#@+node:ekr.20150216070628.111: *8* node 1
node 1 line 1
node 1 line 2
#@+node:ekr.20150216070628.112: *8* node 2
node 2 line 1
node 2 line 2
#@+node:ekr.20150216070628.113: *7* new
@others
#@+node:ekr.20150216070628.114: *8* node 1
node 1 line 1
node 1 line 2 changed
#@+node:ekr.20150216070628.115: *8* node 2
node 2 line 1 changed
node 2 line 2 changed
#@+node:ekr.20150216070628.116: *6* @shadow-test multiple-line delete between nodes: at end of prev node
#@+node:ekr.20150216070628.117: *7* old
@others
#@+node:ekr.20150216070628.118: *8* node 1
node 1 line 1
node 1 line 2
node 1 line 3
#@+node:ekr.20150216070628.119: *8* node 2
node 2 line 1
node 2 line 2
#@+node:ekr.20150216070628.120: *7* new
@others
#@+node:ekr.20150216070628.121: *8* node 1
node 1 line 1
#@+node:ekr.20150216070628.122: *8* node 2
node 2 line 1
node 2 line 2
#@+node:ekr.20150216070628.123: *6* @shadow-test multiple-line delete between nodes: at start of next node
#@+node:ekr.20150216070628.124: *7* old
@others
#@+node:ekr.20150216070628.125: *8* node 1
node 1 line 1
#@+node:ekr.20150216070628.126: *8* node 2
node 2 line 1
node 2 line 2
node 2 line 3
#@+node:ekr.20150216070628.127: *7* new
@others
#@+node:ekr.20150216070628.128: *8* node 1
node 1 line 1
#@+node:ekr.20150216070628.129: *8* node 2
node 2 line 3
#@+node:ekr.20150216070628.130: *6* @shadow-test verbatim sentinels-delete verbatim line
#@+node:ekr.20150216070628.131: *7* old
@others
#@+node:ekr.20150216070628.132: *8* node 1
node 1 line 1
@verbatim
@verbatim
@verbatim
@verbatim
#@verbatim
#@ should be handled by verbatim
line 1 line 3
#@+node:ekr.20150216070628.133: *8* node 2
node 2 line 1
node 2 line 2
node 2 line 3
#@+node:ekr.20150216070628.134: *7* new
@others
#@+node:ekr.20150216070628.135: *8* node 1
node 1 line 1
line 1 line 3
#@+node:ekr.20150216070628.136: *8* node 2
node 2 line 1
node 2 line 2
node 2 line 3
#@+node:ekr.20150216070628.137: *6* @shadow-test verbatim sentinels-delete verbatim line: at start of node
#@+node:ekr.20150216070628.138: *7* old
@others
#@+node:ekr.20150216070628.139: *8* node 1
node 1 line 1
#@+node:ekr.20150216070628.140: *8* node 2
@verbatim
@verbatim
@verbatim
@verbatim
#@verbatim
#@ should be handled by verbatim
node 2 line 2
#@+node:ekr.20150216070628.141: *7* new
@others
#@+node:ekr.20150216070628.142: *8* node 1
node 1 line 1
#@+node:ekr.20150216070628.143: *8* node 2
node 2 line 2
#@+node:ekr.20150216070628.144: *6* @shadow-test verbatim sentinels-no change
#@+node:ekr.20150216070628.145: *7* old
@others
#@+node:ekr.20150216070628.146: *8* node 1
node 1 line 1
@verbatim
@verbatim
@verbatim
@verbatim
#@verbatim
#@ should be handled by verbatim
line 1 line 3
#@+node:ekr.20150216070628.147: *8* node 2
node 2 line 1
node 2 line 2
node 2 line 3
#@+node:ekr.20150216070628.148: *7* new
@others
#@+node:ekr.20150216070628.149: *8* node 1
node 1 line 1
@verbatim
@verbatim
@verbatim
@verbatim
#@verbatim
#@ should be handled by verbatim
line 1 line 3
#@+node:ekr.20150216070628.150: *8* node 2
node 2 line 1
node 2 line 2
node 2 line 3
#@+node:ekr.20150216070628.151: *6* @shadow-test verbatim sentinels-delete verbatim line: at end of node
#@+node:ekr.20150216070628.152: *7* old
@others
#@+node:ekr.20150216070628.153: *8* node 1
node 1 line 1
@verbatim
@verbatim
@verbatim
@verbatim
#@verbatim
#@ should be handled by verbatim
#@+node:ekr.20150216070628.154: *8* node 2
node 2 line 1
node 2 line 2
#@+node:ekr.20150216070628.155: *7* new
@others
#@+node:ekr.20150216070628.156: *8* node 1
node 1 line 1
#@+node:ekr.20150216070628.157: *8* node 2
node 2 line 1
node 2 line 2
#@+node:ekr.20150216070628.158: *6* @shadow-test verbatim sentinels-add verbatim line
# This fails because the @all read logic inserts a second verbatim, I think.
#@+node:ekr.20150216070628.159: *7* old
@others
#@+node:ekr.20150216070628.160: *8* node 1
node 1 line 1
node 1 line 2
#@+node:ekr.20150216070628.161: *8* node 2
node 2 line 1
node 2 line 2
#@+node:ekr.20150216070628.162: *7* new
@others
#@+node:ekr.20150216070628.163: *8* node 1
node 1 line 1
@verbatim
#@verbatim
#@ should be handled by verbatim
node 1 line 2
#@+node:ekr.20150216070628.164: *8* node 2
node 2 line 1
node 2 line 2
#@+node:ekr.20150216070628.165: *6* @shadow-test no change, no ending newline
#@+node:ekr.20150216070628.166: *7* old
line
#@+node:ekr.20150216070628.167: *7* new
line
#@+node:ekr.20100131180007.5363: *4* @test class Marker.getDelims
x = c.shadowController
table = (
    ('python','#',''),
    ('c','//',''),
    ('html','<!--','-->'),
    ('xxxx','#--unknown-language--',''),
)
for language,delim1,delim2 in table:
    delims = g.set_delims_from_language(language)
    marker = x.Marker(delims)
    result = marker.getDelims()
    expected = delim1,delim2
    assert result==expected,'language %s expected %s got %s' % (
        language,expected,result)
#@+node:ekr.20100131180007.5362: *4* @test class Marker.isSentinel
x = c.shadowController
table = (
    ('python','abc',False),
    ('python','#abc',False),
    ('python','#@abc',True),
    ('python','@abc#',False),
    ('c','abc',False),
    ('c','//@',True),
    ('c','// @abc',False),
    ('c','/*@ abc */',True),
    ('c','/*@ abc',False),
    ('html','#@abc',False),
    ('html','<!--abc-->',False),
    ('html','<!--@ abc -->',True),
    ('html','<!--@ abc ->',False),
    ('xxxx','#--unknown-language--@',True)
)
for language,s,expected in table:
    delims = g.set_delims_from_language(language)
    marker = x.Marker(delims)
    result = marker.isSentinel(s)
    assert result==expected,'language %s s: %s expected %s got %s' % (
        language,s,expected,result)
#@+node:ekr.20100131180007.5361: *4* @test class Marker.isVerbatimSentinel
x = c.shadowController
table = (
    ('python','abc',False),
    ('python','#abc',False),
    ('python','#verbatim',False),
    ('python','#@verbatim',True),
    ('c','abc',False),
    ('c','//@',False),
    ('c','//@verbatim',True),
    ('html','#@abc',False),
    ('html','<!--abc-->',False),
    ('html','<!--@verbatim -->',True),
    ('xxxx','#--unknown-language--@verbatim',True)
)
for language,s,expected in table:
    delims = g.set_delims_from_language(language)
    marker = x.Marker(delims)
    result = marker.isVerbatimSentinel(s)
    assert result==expected,'language %s s: %s expected %s got %s' % (
        language,s,expected,result)
#@+node:ekr.20090529115704.4550: *4* @test x.baseDirName
x = c.shadowController

path = x.baseDirName()
expected = g.os_path_dirname(g.os_path_abspath(g.os_path_join(c.fileName())))

# print(path)
# print(expected)

assert path == expected,'\nexpected: %s\ngot     : %s' % (expected,path)
#@+node:ekr.20090529115704.4552: *4* @test x.dirName
x = c.shadowController

filename = 'xyzzy'
path = x.dirName(filename)
expected = g.os_path_dirname(g.os_path_abspath(
    g.os_path_join(g.os_path_dirname(c.fileName()),filename)))

# print(path)
# print(expected)

assert path == expected,'\nexpected: %s\ngot     : %s' % (expected,path)
#@+node:ekr.20100131180007.5366: *4* @test x.findAtLeoLine
x = c.shadowController
table = (
    ('c',('//@+leo','a'),                   '//@+leo'),
    ('c',('//@first','//@+leo','b'),        '//@+leo'),
    ('c',('/*@+leo*/','a'),                 '/*@+leo*/'),
    ('c',('/*@first*/','/*@+leo*/','b'),    '/*@+leo*/'),
    ('python',('#@+leo','a'),               '#@+leo'),
    ('python',('#@first','#@+leo','b'),     '#@+leo'),
    ('error',('',),''),
    ('html',('<!--@+leo-->','a'),                '<!--@+leo-->'),
    ('html',('<!--@first-->','<!--@+leo-->','b'),'<!--@+leo-->'),
)
for language,lines,expected in table:
    result = x.findLeoLine(lines)
    assert expected==result, 'language %s expected %s got %s lines %s' % (
        language,expected,result,'\n'.join(lines))
#@+node:ekr.20090529115704.4557: *4* @test x.makeShadowDirectory
import glob
import os

x = c.shadowController

@others

shadow_fn  = x.shadowPathName('unittest/xyzzy/test.py')
shadow_dir = x.shadowDirName('unittest/xyzzy/test.py')

if g.os_path_exists(shadow_fn):
    g.utils_remove(shadow_fn,verbose=True)
    assert not os.path.exists(shadow_fn),'still exists: %s' % shadow_fn

deleteShadowDir(shadow_dir)

x.makeShadowDirectory(shadow_dir)
assert os.path.exists(shadow_dir)

deleteShadowDir(shadow_dir)
#@+node:ekr.20090529115704.4558: *5* deleteShadowDir
def deleteShadowDir(shadowDir):

    if g.os_path_exists(shadow_dir):
        files = g.os_path_abspath(g.os_path_join(shadow_dir,"*.*"))
        files = glob.glob(files)
        for z in files:
            if z != shadow_dir:
                # g.trace(z)
                os.unlink(z)
        # g.trace(shadow_dir)
        os.rmdir(shadow_dir)
        assert not os.path.exists(shadow_dir),'still exists: %s' % shadow_dir
#@+node:ekr.20100131180007.5365: *4* @test x.markerFromFileLines
x = c.shadowController
# Add -ver=4 so at.parseLeoSentinel does not complain.
table = (
    ('c',('//@+leo-ver=4','a'),                   '//',''),
    ('c',('//@first','//@+leo-ver=4','b'),        '//',''),
    ('c',('/*@+leo-ver=4*/','a'),                 '/*','*/'),
    ('c',('/*@first*/','/*@+leo-ver=4*/','b'),    '/*','*/'),
    ('python',('#@+leo-ver=4','a'),               '#',''),
    ('python',('#@first','#@+leo-ver=4','b'),     '#',''),
    ('error',('',),             '#--unknown-language--',''),
    ('html',('<!--@+leo-ver=4-->','a'),                '<!--','-->'),
    ('html',('<!--@first-->','<!--@+leo-ver=4-->','b'),'<!--','-->'),
)

for language,lines,delim1,delim2 in table:
    s = x.findLeoLine(lines)
    marker = x.markerFromFileLines(lines,'test-file-name')
    result1,result2 = marker.getDelims()
    assert delim1==result1, 'language %s expected1 %s got %s lines %s' % (
        language,delim1,result1,'\n'.join(lines))
    assert delim2==result2, 'language %s expected2 %s got %s lines %s' % (
        language,delim1,result1,'\n'.join(lines))
#@+node:ekr.20100131180007.5364: *4* @test x.markerFromFileName
x = c.shadowController

table = (
    ('ini',';','',),
    ('c','//',''),
    ('h','//',''),
    ('py','#',''),
    ('xyzzy','#--unknown-language--',''),
)

for ext,delim1,delim2 in table:
    filename = 'x.%s' % ext
    marker = x.markerFromFileName(filename)
    result1,result2 = marker.getDelims()
    assert delim1==result1, 'ext=%s, got %s, expected %s' % (
        ext,delim1,result1)
    assert delim2==result2, 'ext=%s, got %s, expected %s' % (
        ext,delim2,result2)
#@+node:ekr.20090529115704.4551: *4* @test x.pathName
x = c.shadowController

filename = 'xyzzy'

path = x.pathName(filename)
expected = g.os_path_abspath(g.os_path_join(x.baseDirName(),filename))

# print(path)
# print(expected)

assert path == expected,'\nexpected: %s\ngot     : %s' % (expected,path)
#@+node:ekr.20090529115704.4555: *4* @@test x.rename
if 0: # x.rename no longer exists
    x = c.shadowController

    filename = x.pathName('xyzzy')
    assert not g.os_path_exists(filename)
    n = x.errors
    x.rename('xyzzy','xyzzy2',silent=True)
    assert x.errors == n+1
    assert x.last_error.startswith('can not rename')
    # print(x.last_error)
#@+node:ekr.20090529115704.4559: *4* @test x.replaceFileWithString
x = c.shadowController
s = 'abc'

fn = '../test/unittest/replaceFileWithStringTestFile.py'
path = g.os_path_abspath(g.os_path_join(g.app.loadDir,fn))

x.replaceFileWithString(path,s)
f = open(path)
s2 = f.read()
f.close()
assert s == s2
#@+node:ekr.20100131180007.5367: *4* @test x.replaceFileWithString 2
c,p = g.getTestVars()
x = c.shadowController

fn = 'does/not/exist'
assert not g.os_path_exists(fn)
assert not x.replaceFileWithString (fn,'abc')
#@+node:ekr.20090529115704.4554: *4* @test x.shadowDirName
x = c.shadowController

subdir = c.config.getString('shadow_subdir') or '.leo_shadow'
prefix = c.config.getString('shadow_prefix') or ''

# print('c.fileName',c.fileName())
# print('c.relativeFileName',c.relativeFileName())

filename = 'xyzzy'
path = x.shadowDirName(filename)
expected = g.os_path_abspath(
    g.os_path_join(g.os_path_dirname(c.fileName()),subdir))

# print(path)
# print(expected)

assert path == expected,'\nexpected: %s\ngot     : %s' % (expected,path)
#@+node:ekr.20090529115704.4553: *4* @test x.shadowPathName
x = c.shadowController

# print(c.config.getString('shadow_subdir'))

subdir = c.config.getString('shadow_subdir') or '.leo_shadow'
prefix = c.config.getString('shadow_prefix') or ''

# print('c.fileName',c.fileName())
# print('c.relativeFileName',c.relativeFileName())

filename = 'xyzzy'
path = x.shadowPathName(filename)
expected = g.os_path_abspath(g.os_path_join(
    g.os_path_dirname(c.fileName()),subdir,prefix+filename))

if 0:
    print('prefix',prefix)
    print(path)
    print(expected)

assert path == expected,'\nexpected: %s\ngot     : %s' % (expected,path)
#@+node:ekr.20090529115704.4556: *4* @test x.unlink
x = c.shadowController

filename = x.pathName('xyzzy')
# print(filename)
assert not g.os_path_exists(filename)
n = x.errors
x.unlink('xyzzy',silent=True)
assert x.errors == n+1
assert x.last_error.startswith('can not delete xyzzy')
# print(x.last_error)
#@+node:ekr.20100131171342.5612: *3* leoTest
#@+node:ekr.20111102122424.3975: *4* @test all unit tests have access to sources
if c.shortFileName() == 'dynamicUnitTest.leo':
    
    setting = 'c.write_script_file'
    assert c.write_script_file is True,'fail1: %s should be hard set' % (setting)
    
else:
    setting = "c.config.getBool('write_script_file')"
    assert c.write_script_file is True,'fail2: check %s' % (setting)
#@+node:ekr.20111105221757.3833: *4* @test TM.findAllUnitTestNodes
p1 = p.copy()

def found(p,result):
    return any([p.v == p2.v for p2 in result])

table = (('all',True,False),('marked',False,True))
try:
    p.setMarked()
    assert p.isMarked(),p
    for kind,all,marked in table:
        result = c.testManager.findAllUnitTestNodes(all,marked)
        assert found(p,result),(kind,len(result))
    assert p == p1,(p,p1)
finally:
    p1.clearMarked()
#@+node:ekr.20100131171342.5613: *4* @test unit testing with embedded class
def sendEmail(self):
    pass # g.trace('self2',self)

class test:
    pass

X = test()
sendEmail(X)
#@+node:ekr.20071113193729: *3* leoUndo
@

9 failures with Alt-5.

Any unit test that changes the structure of the outline should do the
following:

- The setUp method should do
    self.undoMark = c.undoer.getMark()
before altering the outline.

- The tearDown method should do
    c.undoer.rollBackToMark(self.undoMark)
after restoring the outline.

u.rollBackToMark deletes all entries in the undo stack following the saved mark.
This eliminates references to nodes that no longer exist in the present outline.
#@+node:ekr.20040712101754.37: *4* @suite Edit body tests
# Create unit tests in g.app.scriptDict["suite"]

suite = c.testManager.makeEditBodySuite(p)

# g.app.scriptDict['suite'] = suite
#@+node:ekr.20040712101754.38: *5* editBodyTests
@language plain
@

The names of child nodes are the names of commander methods to be called to do the test.

Each child node will in turn have two or more children:

- a "before" node
- an "after" node
- an optional selection node containing two lines giving the selection range in Tk coordinates.
- An optional insert node containing one line giving the insert point in Tk coordinates.
#@+node:ekr.20060127120604: *6* tempNode
#@+node:ekr.20050417202713: *6* addComments
#@+node:ekr.20050417202713.1: *7* before
@language python

def addCommentTest():

    if 1:
        a = 2
        b = 3

    pass
#@+node:ekr.20050417202713.2: *7* after
@language python

def addCommentTest():

    # if 1:
        # a = 2
        # b = 3

    pass
#@+node:ekr.20050417202713.3: *7* selection
5.0
7.8
#@+node:ekr.20050417204940: *6* convertAllBlanks
#@+node:ekr.20050417204940.1: *7* before
@tabwidth -4

line 1
    line 2
      line 3
line4
#@+node:ekr.20050417204940.2: *7* after
@tabwidth -4

line 1
	line 2
	  line 3
line4
#@+node:ekr.20050417204940.3: *7* selection
1.0
6.5
#@+node:ekr.20050417205012: *6* convertAllTabs
#@+node:ekr.20050417205012.1: *7* before
@tabwidth -4

line 1
	line 2
	  line 3
line4
#@+node:ekr.20050417205012.2: *7* after
@tabwidth -4

line 1
    line 2
      line 3
line4
#@+node:ekr.20050417205012.3: *7* selection
1.0
6.5
#@+node:ekr.20050417203114: *6* convertBlanks
#@+node:ekr.20050417203310: *7* before
@tabwidth -4

line 1
    line 2
      line 3
line4
#@+node:ekr.20050417203310.1: *7* after
@tabwidth -4

line 1
	line 2
	  line 3
line4
#@+node:ekr.20050417203336: *7* selection
1.0
6.5
#@+node:ekr.20050417203114.1: *6* convertTabs
#@+node:ekr.20050417204834: *7* before
@tabwidth -4

line 1
	line 2
	  line 3
line4
#@+node:ekr.20050417204830: *7* after
@tabwidth -4

line 1
    line 2
      line 3
line4
#@+node:ekr.20050417204901: *7* selection
1.0
6.5
#@+node:ekr.20040712101754.49: *6* dedentBody
#@+node:ekr.20040712101754.50: *7* before
line 1
    line 2
    line 3
line 4
#@+node:ekr.20040712101754.51: *7* after
line 1
line 2
line 3
line 4
#@+node:ekr.20040712101754.52: *7* selection
2.0
3.5
#@+node:ekr.20050417202817: *6* deleteComments
# created by new add-comments
#@+node:ekr.20050417202817.1: *7* before
@language python

def deleteCommentTest():

#     if 1:
#         a = 2
#         b = 3

    pass
#@+node:ekr.20050417202817.2: *7* after
@language python

def deleteCommentTest():

    if 1:
        a = 2
        b = 3

    pass
#@+node:ekr.20050417202817.3: *7* selection
5.0
7.8
#@+node:ekr.20111112211307.3910: *6* deleteComments
# created by old and new add-comments.
#@+node:ekr.20111112211307.3911: *7* before
@language python

def deleteCommentTest():

#     if 1:
#         a = 2
#         b = 3

    # if 1:
        # a = 2
        # b = 3

    pass
#@+node:ekr.20111112211307.3912: *7* after
@language python

def deleteCommentTest():

    if 1:
        a = 2
        b = 3

    if 1:
        a = 2
        b = 3

    pass
#@+node:ekr.20111112211307.3913: *7* selection
5.0
12.8
#@+node:ekr.20050417201845: *6* extract test1
#@+node:ekr.20050417201845.1: *7* before
before
    << section >>
    sec line 1
        sec line 2 indented
sec line 3
after
#@+node:ekr.20050417201845.2: *7* after
before
    << section >>
after
#@+node:ekr.20050417201845.3: *8* << section >> @nonl
sec line 1
    sec line 2 indented
sec line 3
#@+node:ekr.20050417201845.4: *7* selection
2.0
5.10
#@+node:ekr.20050518070540: *6* extract test2
#@+node:ekr.20050518070540.1: *7* before
before
    << section >>
    sec line 1
        sec line 2 indented
sec line 3
after
#@+node:ekr.20050518070545: *7* after
before
    << section >>
    sec line 1
        sec line 2 indented
sec line 3
after
#@+node:ekr.20050518070540.4: *7* selection
2.0
2.16
#@+node:ekr.20050518070927: *6* extractSection test1
#@+node:ekr.20050518070927.1: *7* before
before
    << section >>
    sec line 1
        sec line 2 indented
sec line 3
after
#@+node:ekr.20050518070927.2: *7* after
before
    << section >>
after
#@+node:ekr.20050518070927.3: *8* << section >> @nonl
sec line 1
    sec line 2 indented
sec line 3
#@+node:ekr.20050518070927.4: *7* selection
2.0
5.10
#@+node:ekr.20050518071251: *6* extractSection test2
#@+node:ekr.20050518071251.1: *7* before
before
    << section >>
    sec line 1
        sec line 2 indented
sec line 3
after
#@+node:ekr.20050518071258: *7* after
before
    << section >>
    sec line 1
        sec line 2 indented
sec line 3
after
#@+node:ekr.20050518071251.4: *7* selection
2.0
2.16
#@+node:ekr.20071113202510: *4* @test zz end of leoUndo tests
# This is **not** a real unit test.
# It simply restores the screen to a more convenient state.

# c.contractParent()
# g.app.unitTestDict['restoreSelectedNode']=False

print('\nEnd of leoUndo tests.')
#@+node:ekr.20140802074328.4471: *3* leoVim.py
#@+node:ekr.20140802074328.4472: *4* @test vc.on_same_line
vc = c.vimCommands
s = '''
abc
xyz
pdq
'''
table = (
    ('ab','y',False),
    ('a','c',True),
    ('x','\np',True),
    ('\nx','z',False),
)
for a,b,expected in table:
    i1,i2 = s.find(a),s.find(b)
    result = vc.on_same_line(s,i1,i2)
    assert result == expected,'%s expected: %s got: %s' % (
        s[i1:i2],expected,got)
#@+node:ekr.20140802074328.4473: *4* @test vc.to_bol
vc = c.vimCommands
s = '''
abc
xyz
'''
table = (
    ('a','a'),
    ('a','b'),
    ('a','\nx')
)
for a,b,in table:
    i1,i2 = s.find(a),s.find(b)
    result = vc.to_bol(s,i2)
    assert result == i1,'%s expected: %s got: %s' % (
        s[i1:i2],expected,got)
#@+node:ekr.20140802074328.4474: *4* @test vc.to_eol
vc = c.vimCommands
s = '''
abc
xyz
'''
table = (
    ('a','\nx'),
    ('b','\nx'),
    ('c','\nx'),
    ('\nx','\nx'),
)
for a,b,in table:
    i1,i2 = s.find(a),s.find(b)
    result = vc.to_eol(s,i1)
    assert result == i2,'%s expected: %s got: %s' % (
        s[i1:i2],expected,got)
#@+node:ekr.20050120095423: *3* Plugins
# Do this last.
#@+node:ekr.20110610082755.3362: *4*  qt gui
#@+node:ekr.20100131171342.5503: *5* @test c.vnode2position
trace = False
if trace: print('=' * 20)
for p in c.all_positions():
    p2 = c.vnode2position(p.v)
    if trace: print(p2.level(), p2.headString())
    # We can *not* assert that p == p2, only that
    # p2.v == p.v and c.positionExists(p2)
    assert p2
    assert p2.v == p.v,'p2.v: %s, p.v: %s' % (p2.v,v)
    assert c.positionExists(p2),'does not exist: %s' % p2
#@+node:ekr.20100131171342.5504: *5* @test position2Item
tree = c.frame.tree
# position2item does not exist when running unit tests dynamically.
if hasattr(tree,'position2item'):
    c.redraw()
    p = c.rootPosition()
    while p:
        item = tree.position2item(p)
        v = tree.item2vnode(item)
        if v: # New test needed with per-clone expansions.
            assert v == p.v, 'item2: %s, p.v: %s' % (item,p.v)
        p.moveToVisNext(c)
#@+node:ekr.20100131171342.5505: *5* @@test item2position
# This test is no longer valid because of per-position node expansions.
def test_sibs(parent_p,parent_item):
    trace = False
    tree = c.frame.tree
    sib_items = tree.childItems(parent_item)
    sibs = [z.copy() for z in parent_p.self_and_siblings_iter()]
    assert len(sib_items) == len(sibs),(
        'child_items: %s, children: %s' % (
            g.listToString(sib_items),g.listToString(sibs)))
    for item,p in zip(sib_items,sibs):
        p2 = tree.item2position(item)
        if trace: print (id(item),p2 and p2.headString() or not p2 and '**None**')
        assert p == p2, 'item: %s, p: %s, p2: %s' % (id(item),p,p2)
        # Recursively test.
        child = p.firstChild()
        if child.isVisible(c):
            test_sibs(child,parent_item=item)
if hasattr(c.frame.tree,'item2position'):
    c.redraw()
    test_sibs(c.rootPosition(),None)
#@+node:ekr.20050218015346: *4* @@suite run all plugin test routines
# This test, if run at all, should be run elsewhere:
# Actually importing plugins affects other unit tests.

import glob
import inspect
import unittest

changed = c.isChanged() ; p1 = c.p
<< class testRoutineTestCase >>
@others

plugins = getAllPlugins()

# g.printList(plugins)

print('@suite run all plugin test routines')

if 1:
    g.app.unitTestDict["fail"] = False
    suite = unittest.makeSuite(unittest.TestCase)
    for plugin in plugins:
        n = addTestRoutinesInPluginToSuite(c,g,plugin,suite)
        if n:
            plural = g.choose(n==1,'','s')
            s = 'found %2d test routine%s for %s' % (n,plural,plugin)
            g.es_print(s)
    # if 1: # For @suite nodes.  Better for unit testing.
        # g.app.scriptDict['suite'] = suite
    # else: # For script button nodes.  Good for testing.
        # # Verbosity: 1: print just dots.
        # unittest.TextTestRunner(verbosity=1).run(suite)
        # c.setChanged(changed) # Restore changed state.
        # c.selectVnode(p1) # N.B. Restore the selected node.
#@+node:ekr.20050218015346.11: *5* << class testRoutineTestCase >>
class testRoutineTestCase(unittest.TestCase):

    """Create a unit test from a snippet of code."""

    @others
#@+node:ekr.20050218015346.12: *6* __init__
def __init__ (self,c,g,moduleName,theClass,f,code,verbose=False):

     # Init the base class.
    unittest.TestCase.__init__(self)

    self.c = c
    self.moduleName = moduleName
    self.theClass = theClass
    self.f = f
    self.g = g
    self.code = code
    self.p = c.p.copy()
    self.verbose = verbose
#@+node:ekr.20050218015346.13: *6*  fail
def fail (self,msg=None):

    """Mark a unit test as having failed."""

    g.app.unitTestDict["fail"] = g.callerName(2)
#@+node:ekr.20050218015346.16: *6* runTest
def runTest (self):

    f = self.f ; name = f.__name__ ; theClass = self.theClass

    d = {'c':self.c,'g':self.g,'p':self.p}

    if 1: # Use dead text to ensure a clean environment.
        # The present code assumes all leading whitespace is consistent.
        code = removeLeadingWs(self.code)
        # The code is a def statement.  We concoct a call to the function or method.
        if theClass:
            s = '%s\n%s(self=None)\n' % (code,name)
        else:
            s = '%s\n%s()\n' % (code,name)

        if self.verbose:
            g.trace('executing...\n\n%s' % s)

        exec(s,d) # Execute s in a environment containing c, g and p.

    else: # Use live objects.
        if theClass:
            # Create a subclass of f's original class.
            class __dummyClass(theClass):
                # Create a ctor with a known signature.
                def __init__(self): pass
            # Make f a method of the dummyClass with name 'f'.
            # N.B. f is still a method of theClass, and must be called as such!
            if 0: # Override the method with f's actual name.
                g.funcToMethod(f,__dummyClass,name)
                obj = __dummyClass()
                f = getattr(obj,name)
                f(obj)
            else:
                # Use the name 'f' for f's name.
                g.funcToMethod(f,__dummyClass,'f')
                # Create an instance of __dummyClass and call it's f method.
                obj = __dummyClass()
                obj.f()
        else: # Execute a plain function.
            f(**keys)
#@+node:ekr.20050218015346.17: *6* shortDescription
def shortDescription (self):

    return 'test function',repr(self.f)
#@+node:ekr.20050218015346.18: *5* addTestRoutinesInPluginToSuite
def addTestRoutinesInPluginToSuite (c,g,pluginName,suite):

    path = g.os_path_abspath(g.os_path_join(g.app.loadDir,"..","plugins"))

    plugin = g.importFromPath(pluginName,path,verbose=True)
    if not plugin:
        return len([])

    tests = findTestsInModule(plugin,pluginName)

    for test in tests:
        theClass,f = test
        code = inspect.getsource(f)
        testCase = testRoutineTestCase(c,g,pluginName,theClass,f,code,verbose=False)
        suite.addTest(testCase)

    return len(tests)
#@+node:ekr.20050218015346.19: *5* findTestsInModule
def findTestsInModule (module,moduleName):

    # g.trace(moduleName)

    toString = g.listToString
    try:
        functions = inspect.getmembers(module,inspect.isfunction)
    except Exception:
        g.trace('Exception in inspect.getmembers(module,inspect.isfunction) for %s' % moduleName)
        functions = []
    try:
        classes = inspect.getmembers(module,inspect.isclass)
    except Exception:
        g.trace('Exception in inspect.getmembers(module,inspect.isclass) for %s' % moduleName)
        classes = []

    # Ignore subclasses of TestCase.
    classes = [theClass for className,theClass in classes
        if not issubclass(theClass,unittest.TestCase)]

    allMethods = []
    for theClass in classes:
        try:
            methods = inspect.getmembers(theClass,inspect.ismethod)
        except Exception:
            # This looks like a bug in inspect: The zodb classes have no methods.
            # g.trace('Exception in inspect.getmembers(theClass,inspect.ismethod) for %s' % moduleName)
            methods = []
        # print('\nmethods of class %s...\n\n%s' % (theClass,toString(methods)))
        methods = [(theClass,f) for name,f in methods if name.startswith('test_')]
        allMethods.extend(methods)

    # Hack: remove duplicate tests from leoGlobals.py.
    functions = [(None,f) for name,f in functions
        if name.startswith('test_') and not name.startswith('test_g_')]

    if 0:
        << print classes, methods & functions >>

    result = functions
    result.extend(allMethods)
    return result
#@+node:ekr.20050218015346.20: *6* << print classes, methods & functions >>
print('=' * 40)

if classes:
    print('classes in %s...\n%s' % (moduleName,toString(classes)))
else:
    print('no classes in %s' % (moduleName))
if allMethods:
    print('test methods in %s...\n%s'   % (moduleName,toString(allMethods)))
else:
    print('no test methods in %s' % (moduleName))
if functions:
    print('test functions in %s...\n%s' % (moduleName,toString(functions)))
else:
    print('no test functions in %s' % (moduleName))
#@+node:ekr.20050218015346.22: *5* removeLeadingWs
def removeLeadingWs (code):

    if not code.strip():
        return ''

    lines = g.splitLines(code)
    line = lines[0]
    i = g.skip_ws(line,0)
    ws = line[0:i]
    if not ws:
        return code
    result = [] ; n = len(ws)
    for line in lines:
        if line.startswith(ws):
            result.append(line[n:])
        elif not line.strip() and line.endswith('\n'):
            result.append('\n')
        else:
            print('unitTest.leo:underindented line:%s' % repr(line))
            result.append(line)

    # g.trace(g.listToString(result))

    result = ''.join(result)
    return result
#@+node:ekr.20100131171342.5497: *4* @@test detect_urls.py
import leo.plugins.detect_urls as detect_urls

# print(c.frame.body.wrapper)
w = c.frame.body.wrapper
s = w.getAllText()

# s will be empty when running unit tests dynamically.
if s:
    if s.endswith('\n'): s = s[:-1]
    w.setInsertPoint(len(s))
    url = detect_urls.openURL(tag='test',keywords={'c':c})
    assert url == 'http://webpages.charter.net/edreamleo/front.html','Got:%s' % repr(url)
    
@ The last line is the url
http://webpages.charter.net/edreamleo/front.html
#@+node:ekr.20100131171342.5500: *4* @@test macros.parameterize
import leo.plugins.macros as macros

controller = macros.ParamClass(c)
controller.parameterize()
    # Not much will happen because there are no children.
    # However, this does test recent changes.
#@+node:ekr.20050120095423.11: *4* @suite import or test syntax of all plugins
'''Imports all plugins or just tests their syntax,
epending on a switch in PluginTestCase.runTest.'''

import glob
import sys
import unittest

@others

suite = makePluginsTestSuite(c)

# g.app.scriptDict['suite'] = suite
#@+node:ekr.20050120095423.12: *5* makePluginsTestSuite
def makePluginsTestSuite(c):

    '''Create a plugin test for .py file in the plugins directory'''

    # Create the suite.
    suite = unittest.makeSuite(unittest.TestCase)

    # Add a test case for every plugin.
    paths = (
        g.os_path_join(g.app.loadDir,'..','plugins','*.py'),
        g.os_path_join(g.app.loadDir,'..','plugins','examples','*.py'),
    )
    all_files = []
    for path in paths:
        plugins = g.os_path_join(path)
        plugins = g.os_path_abspath(plugins)
        files = glob.glob(plugins)
        files = [g.os_path_abspath(f) for f in files]
        all_files.extend(files)
    all_files.sort()
    
    for fn in all_files:
        test = pluginTestCase(c,fn)
        suite.addTest(test)

    if 0:
        # Open a new window after all tests are completed.  Tests many plugins.
        lastTest = lastTestCase(c,openFlag=True)
        suite.addTest(lastTest)

    return suite
#@+node:ekr.20050120095423.13: *5* class pluginTestCase
class pluginTestCase(unittest.TestCase):

    '''A test case to test a single Leo plugin.'''

    @others
#@+node:ekr.20050120095423.14: *6* __init__
def __init__ (self,c,path):

    # Init the base class.
    unittest.TestCase.__init__(self)

    self.c = c
    self.path = path
#@+node:ekr.20050120095423.15: *6* fail
def fail (self,msg=None):

    """Mark a unit test as having failed."""

    g.app.unitTestDict["fail"] = g.callerName(2)
#@+node:ekr.20050120095423.16: *6* runTest
def runTest(self):

    trace = False
    c = self.c ; path = self.path
    path,base = g.os_path_split(path)
    fn = base[:-3]
    
    ignore = (
        # Read error.
        'chinese_menu',
        # Unfinished/obsolute gui's.
        'gtkDialogs','gtkGui','ironPython','ironPythonGui',
        'swing_gui','tkGui','wxGui','temacs',
        # Tk-only.
        'ipython',
        # Imports path & win32clipboard.
        'at_view',
        # Experimental.
        'stickynotes_plus',
        # Generated by unit tests.
        'pluginsTest',
        # Imports non-standard modules.
        'interact',         # import pexpect
        'jinjarender',      # import jinga2
        'leofeeds',         # import feedparser
    )

    if fn in ignore:
        return
    
    if trace: g.trace(fn)
    
    if 1:
        # Just check the syntax.  Doesn't pollute other unit tests.
        f = open(self.path,'r')
        s = f.read()
        f.close
        assert c.testManager.checkFileSyntax(fn,s,reraise=False,suppress=False)
    else: # Good for initial tests, but pollutes all other unit tests.
        exec('import leo.plugins.%s' % fn)
    
#@+node:ekr.20050120095423.17: *6* setUp
def setUp(self):

    g.app.unitTestDict = {}
#@+node:ekr.20050120095423.18: *6* shortDescription
def shortDescription (self):

    return "pluginTestCase: %s" % g.shortFileName(self.path)
#@+node:ekr.20050120095423.20: *5* class lastTestCase
class lastTestCase(unittest.TestCase):

    '''A test case to print a message at the end of plugin tests.'''

    def __init__ (self,c,openFlag):
        # Init the base class.
        unittest.TestCase.__init__(self)
        self.c = c
        self.openFlag = openFlag

    def runTest(self):
        c = self.c
        print('\n%s a new window to test more plugin logic\n' % g.choose(
            self.openFlag,'opening','open'))
        if self.openFlag:
            self.new_c = new_c = c.new() # Create the new window.
            new_c.frame.setTitle("unit test for 'new' hook")

    if 0: # Doesn't work
        def shutDown(self):
            c = self.new_c
            c.close()
#@+node:ekr.20111104214341.3835: *4* @test all plugins have top-level init method
'''Ensure all plugins have top-level init method *without* importing them.'''

import glob
import inspect

# Get a list of all plugins.
plugins = g.os_path_join(g.app.loadDir,'..','plugins','*.py')
plugins = g.os_path_abspath(plugins)
files = glob.glob(plugins)
files = [g.os_path_abspath(z) for z in files]
files = [z for z in files if not z.endswith('__init__.py')]
files.sort()

exclude = [
    # These are not real plugins...
    'baseNativeTree.py','leocursor.py',
    'qtGui.py',
    'qt_big_text.py',
    'qt_commands.py',
    'qt_events.py',
    'qt_frame.py',
    'qt_idle_time.py',
    'qt_main.py',
    'qt_quickheadlines.py',
    'qt_quicksearch_sub.py',
    'qt_text.py',
    'qt_tree.py',
    'qt_quicksearch.py',
    'swing_gui.py',
]

for fn in files:
    if not g.shortFileName(fn) in exclude:
        f = open(fn,'r')
        s = f.read()
        f.close()
        ok1 = s.find('def init():') > -1
        ok2 = s.find('def init ():') > -1
        assert ok1 or ok2,'fail: %s' % (fn)
    
#@+node:ekr.20140217055617.4230: *4* @test c.theScriptingController.atScriptNodes
# This must be true even though @bool scriptingatscriptnodes is True in this file.
if hasattr(c,'theScriptingController'):
    # mod_scripting may be disabled when running tests externally.
    assert not c.theScriptingController.atScriptNodes
#@+node:ekr.20100131171342.5501: *4* @test zz end of plugins unit tests
# This is **not** a real unit test.
# It simply restores the screen to a more convenient state.

if 0: # No longer needed.
    c.contractAllHeadlines()
    h = 'All unit tests'
    p = c.testManager.findNodeAnywhere(h)
    if p:
        p.expand()
        g.app.unitTestDict['restoreSelectedNode']=False
        c.selectPosition(p)
        c.redraw()

print('\nEnd of plugins unit tests')
#@+node:ekr.20090306091634.1: ** @test print redraw count
tree = c.frame.tree
if hasattr(tree,'redrawCount'):
    print('%s: %s' % (p.h,tree.redrawCount))
#@+node:ekr.20170123053430.1: ** @test print calls to jedit.setTag
if 0:
    print('calls to jedit.setTag: %s' %
        c.frame.body.colorizer.highlighter.colorer.n_setTag)
#@+node:ekr.20081111150402.11: ** @test zz end of all tests
# This is **not** a real unit test.
# It simply restores the screen to a more convenient state.

if 0:
    c.selectPosition(p)
    c.contractParent()
    c.selectPosition(p.parent())
    # Do not do this! It would changed unitTest.leo!
        # c.save()
    g.app.unitTestDict['restoreSelectedNode']=False
    c.bodyWantsFocus()
    
# Print does not work: it is redirected.
g.es('all unit tests done',color='blue')
#@+node:ekr.20140822063016.4474: ** @test zzz force a quit
# import sys
# if not sys.platform.startswith('win'):
    # print(p.h)
    # c.k.simulateCommand(':q!')
    
if 0:
    # These won't do any good if a unit test foolishly saves the outline!
    c.k.simulateCommand('contract-all')
    c.setChanged(False)

c.k.simulateCommand(':q!')
#@-all
#@-leo
