#@+leo-ver=5-thin
#@+node:ekr.20070114140212: * @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.4701: *4* tempNode
#@+node:ekr.20090529141856.4702: *4* importAtRoot
#@+node:ekr.20090529141856.4703: *5* dialog
openFileDialog
test\\unittest\\perfectImport\\formatter.py
#@+node:ekr.20090529141856.4704: *4* importDerivedFile
#@+node:ekr.20090529141856.4705: *5* dialog
openFileDialog
core\\runLeo.py
#@+node:ekr.20090529141856.4706: *4* importNowebFiles
#@+node:ekr.20090529141856.4707: *5* dialog
openFileDialog
test\\unittest\\input\\noweave.nw.txt
#@+node:ekr.20090529141856.4708: *4* importFlattenedOutline
#@+node:ekr.20090529141856.4709: *5* dialog
openFileDialog
test\\unittest\\input\\flat.txt
#@+node:ekr.20090529141856.4710: *4* importCWEBFiles
#@+node:ekr.20090529141856.4711: *5* dialog
openFileDialog
test\\unittest\\input\\cweave.w
#@+node:ekr.20090529141856.4712: *4* removeSentinels
#@+node:ekr.20090529141856.4713: *5* dialog
openFileDialog
test\\unittest\\input\\testLeoAtFile.py
#@+node:ekr.20090529141856.4714: *4* importAtFile
#@+node:ekr.20090529141856.4715: *5* dialog
openFileDialog
test\\unittest\\perfectImport\\formatter.py
#@+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.bodyCtrl
        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

        assert s1 == s2, 'mismatch in %s\nexpected: %s\n     got: %s' % (location,repr(s2),repr(s1))
        sel3 = w.getSelectionRange()
        ins = w.toGuiIndex(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.toGuiIndex(i),w.toGuiIndex(j)
        assert len(sel3) == 2,'Bad headline index.  Expected index,index.  got: %s' % sel3
        i,j = sel3 ; sel3 = w.toGuiIndex(i),w.toGuiIndex(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:

    def __init__ (self,c,p):
        self.c = c
        self.p = p.copy()
        self.run()

    @others
#@+node:ekr.20100827194549.5963: *5* report
def report (self,expected,got):

    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):
    import sys

    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()
    rc.processTree(p=source.firstChild(),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.
    html = html.replace('Docutils 0.8.1:','Docutils 0.8:')
    html = html.replace('Docutils 0.6:','Docutils 0.8:')
    html = html.replace('Docutils 0.7:','Docutils 0.8:')
    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 = []

    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 = [
    # 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
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.20100208230953.5383: ** Cache tests
#@+node:ekr.20100208095817.5387: *3* @@test leoCache
# Disabled this test because it's best to open this file without caching.

import leo.core.leoCache as leoCache

cacher = leoCache.cacher(c)

assert cacher.test()
#@+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 = list(d.keys()) ; keys.sort()

for key in keys:
    f = d.get(key) ; name = f and f.__name__
    args, varargs, varkw, defaults = data = inspect.getargspec(f)
    # print('%-28s' % (name),data)
    arg0 = len(args) > 0 and args[0]
    arg1 = len(args) > 1 and args[1]
    assert arg0 == 'self' and arg1 == 'event' or arg0 == 'event',\
       'no event arg for %s, args: %s' % (name,data)
#@+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.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.widget.
body = c.frame.body
old_w = body.widget
assert old_w is not None
try:
    body.bodyCtrl = None
    assert body.widget is None
finally:
    body.widget = 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.20111118183928.3881: *4* @test logCtrl property
# Test that changing c.frame.log.logCtrl also changes c.frame.log.widget.
log = c.frame.log
old_w = log.widget
assert old_w is not None
try:
    log.logCtrl = None
    assert log.widget is None
finally:
    log.widget = old_w
#@+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.bodyCtrl.
        #'bodyCtrl', # 2007/10/27: this ivar is evil and has been removed.
        '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','loadManager','pluginsController','recentFilesManager',
    # These are non-official and might be removed...
    'batchMode',
    # 'debug',
    'debugSwitch','disableSave',
    'gui','hasOpenWithMenu','hookError',
    'hookFunction',
    'idle_imported','idleTimeDelay','idleTimeHook',
    'initing','killed',
    'leoID','log','logIsLocked','logWaiting',
    'nodeIndices','numberOfUntitledWindows',
    'quitting','realMenuNameDict','searchDict','scriptDict',
    # trace_ switches are now defined in leoGlobals.py.
    'unitTestDict','unitTesting','use_psyco','windowList',
)

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

for ivar in ivars:
    assert hasattr(g.app,ivar), 'missing app ivar: %s' % ivar
    if ivar not in mayBeNone:
        val = getattr(g.app,ivar)
        assert val is not None, 'null app ivar: %s'% ivar

# These do not have to be initied.
for ivar in (
    'commandName',
    'openWithFiles','openWithFileNum','openWithTable',
    # 'root',
):
    assert hasattr(g.app,ivar), 'missing app ivar: %s' % ivar
#@+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 os

# The files in leoGuiPlugins.leo.
guiPluginsList = (
    'cursesGui','ironPythonGui','swing_gui','tkGui','wxGui',
)

passList = (
    '__init__','FileActions',
    'active_path','add_directives','attrib_edit',
    'backlink','baseNativeTree','bibtex','bookmarks',
    'codewisecompleter','colorize_headlines','contextmenu',
    'ctagscompleter','cursesGui','datenodes','debugger_pudb',
    # 'detect_urls',
    'dtest','empty_leo_file','enable_gc','initinclass',
    'leo_to_html','leo_interface','leo_pdf','leo_to_rtf',
    # 'leoN',
    'leoOPML','leoremote','lineNumbers',
    'macros','mime','mod_autosave','mod_framesize','mod_leo2ascd',
    'mod_scripting','mod_speedups','mod_timestamp',
    'nav_qt','niceNosent','nodeActions',
    'open_shell','outline_export','quit_leo',
    'paste_as_headlines','plugins_menu','pretty_print','projectwizard',
    'qtGui','qt_main','qt_quicksearch','qtframecommands',
    'quickMove','quicksearch','redirect_to_log','rst3','run_nodes',
    'screenshots',
    # 'scrolledmessage',
    'setHomeDirectory','slideshow','spydershell','startfile',
    'testRegisterCommand','todo','trace_gc_plugin','trace_keys','trace_tags',
    'vim','xemacs',
)
core_files = (
    'leoApp','leoAtFile','leoCache','leoChapters','leoCommands',
    'leoEditCommands','leoFileCommands','leoFind','leoFrame',
    'leoGlobals','leoGui','leoImport','leoMenu','leoNodes',
    'leoPlugins','leoShadow','leoTangle','leoUndo',
)
external_files = (
    'ipy_leo','lproto',
)

recent = (
    #'leo_interface',
)

# The files in scripts.leo.
scriptsList = (
    'convert_to_shadow','leoFindScript','LinixInstall',
    'tangle_done','untangle_done',
)

table = (
    ('plugins',recent),
    ('plugins',passList),
    ('plugins',guiPluginsList),
    ('core',core_files),
    ('external',external_files),
    ('scripts',scriptsList),
)
files = []
for theDir,aList in table:
    for z in aList:
        if not z.endswith('.py'): z = z + '.py'
        fn = os.path.abspath(os.path.join('leo',theDir,z))
        if os.path.exists(fn): files.append(fn)
        else: print('*** file not found: %s' % (fn))

failed = []
for z in files:
    fn = g.shortFileName(z)
    s,e = g.readFileIntoString(z)
    if not c.testManager.checkFileSyntax(fn,s,reraise=False,suppress=False):
        failed.append(fn)

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 -*-

# g.openWithFileName *always* opens the file.

if 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 -*-

if g.isPython3:
    table = (
        ('aĂbĂ',    'ascii'),
        ('炰',               'ascii'),
        ('aĂbĂ',            'utf-8'),
        ('炰',               'utf-8'),
    ) 
else:
    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:
    pass
else:
    assert not isinstance(c.frame,leoFrame.nullFrame)
    
    # These commands are implemented by qtGui.py
    def closeEnough(f1,f2):
        return abs(f1-f2) < 0.0001
    
    f = c.frame
    ratio,ratio2 = f.ratio,f.secondary_ratio
    
    table = (
        c.bodyWantsFocusNow,
        c.logWantsFocusNow,
        c.treeWantsFocusNow,
    )
    
    for func in table:
        func()
        f.contractPane()
        if func == c.logWantsFocusNow:
            assert ratio2 != f.secondary_ratio,'fail 1'
        else:
            assert ratio != f.ratio,'fail 2: %s, %s' % (ratio,f.ratio)
        func()
        f.expandPane()
        assert closeEnough(ratio,f.ratio),'fail 3 %s != %s' % (
            ratio,f.ratio)
        assert closeEnough(ratio2,f.secondary_ratio),'fail 4 %s != %s' % (
            ratio2,f.secondary_ratio)
#@+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.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.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.

f = at.openStringFile('abc')

assert f.__class__.__name__ == 'fileLikeObject'

s = 'abc'
f.write(s)
s2 = at.closeStringFile(f)

assert s == 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)
    # shadow_fn = x.shadowPathName(fn)
    at.writeOneAtShadowNode(child,toString=False,force=True)
    at.readOneAtShadowNode(fn,child)
finally:
    child.setHeadString('@@shadow %s' % fn)
    c.setChanged(changed)
    # c.redraw_now()
#@+node:ekr.20090529115704.4565: *5* @@shadow unittest/read_test.py
@language python
@tabwidth -4
@others
# body of @shadow test node
# The last line.
#@+node:ekr.20111210175541.3957: *4* @test at.readOneAtShadowNode retains @shadow links clones
# Important: the child of this node must be a clone of
# the corresponding node in @shadow unittest/at-shadow-unlink-clones.py

# The @shadow node will not exist for an external test.
if not g.app.isExternalUnitTest:
    try:
        # print('start',p.h)
        b = c.undoer.beforeChangeTree(p)
        h = '@shadow unittest/at-shadow-unlink-clones.py'
        root = g.findNodeAnywhere(c,h)
        assert root
        assert root.h == h,repr(root.h)
        child = p.firstChild()
        assert child
        assert child.isCloned(),'fail 1: test not set up properly'
        c.selectPosition(root)
        fn = root.atShadowFileNodeName()
        assert fn
        c.atFileCommands.readOneAtShadowNode (fn,root,force=True)
        c.undoer.afterChangeTree(p,'fc.readOneAtShadowNode',b)
        assert child.isCloned(),'fail 2: intended test fails'
        c.undoer.undo()
    finally:
        c.selectPosition(p)
        c.redraw()
#@+node:ekr.20120228174052.3929: *5* 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

at = c.atFileCommands
exists = g.os_path_exists

at.outputFileName = g.os_path_join(g.app.testDir,'xyzzy1')
at.targetFileName = g.os_path_join(g.app.testDir,'xyzzy2')

# Create both paths (different contents)
for p in (at.outputFileName,at.targetFileName):
    if exists(p):
        os.remove(p)
    assert not exists(p)
    f = open(p,'w')
    s = 'test %s' % p
    # print(repr(p),repr(s))
    f.write(s)
    f.close()
    assert exists(p) # , '%s does not exist' % repr(p)

at.toString = False # Set by execute script stuff.
at.shortFileName = at.targetFileName
root = at.root
assert at.replaceTargetFileIfDifferent(root), 'replaceTargetFileIfDifferent returns False'
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()
# print('Contents of %s: %s' % (at.targetFileName,s))
assert s == 'test %s' % at.outputFileName, 'unexpected contents of target file'
os.remove(at.targetFileName)
#@+node:ekr.20050105095743: *4* @test at.replaceTargetFileIfDifferent (identical)
import os

at = c.atFileCommands
exists = g.os_path_exists

at.outputFileName = g.os_path_join(g.app.testDir,'xyzzy1')
at.targetFileName = g.os_path_join(g.app.testDir,'xyzzy2')

# Create both paths (identical contents)
for p in (at.outputFileName,at.targetFileName):
    if exists(p):
        os.remove(p)
    assert not exists(p)
    f = open(p,'w')
    s = 'test %s' % at.outputFileName
    # print(repr(p),repr(s))
    f.write(s)
    f.close()
    assert exists(p)

at.toString = False # Set by execute script stuff.
at.shortFileName = at.targetFileName
root = at.root
assert not at.replaceTargetFileIfDifferent(root), 'replaceTargetFileIfDifferent returns True'
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()
# print('Contents of %s: %s' % (at.targetFileName,s))
assert s == 'test %s' % at.outputFileName, 'unexpected contents of target file'
os.remove(at.targetFileName)
#@+node:ekr.20050105100227: *4* @test at.replaceTargetFileIfDifferent (no target file)
import os

at = c.atFileCommands
exists = g.os_path_exists

at.outputFileName = g.os_path_join(g.app.testDir,'xyzzy1')
at.targetFileName = g.os_path_join(g.app.testDir,'xyzzy2')

# Remove both files, then create only the output file
for p in (at.outputFileName,at.targetFileName):
    if exists(p):
        os.remove(p)

for p in (at.outputFileName,):
    assert not exists(p)
    f = open(p,'w')
    s = 'test %s' % at.outputFileName
    # print(repr(p),repr(s))
    f.write(s)
    f.close()
    assert exists(p)

at.toString = False # Set by execute script stuff.
at.shortFileName = at.targetFileName
root = at.root
assert not at.replaceTargetFileIfDifferent(root), 'replaceTargetFileIfDifferent returns True'
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()
# print('Contents of %s: %s' % (at.targetFileName,s))
assert s == 'test %s' % at.outputFileName, 'unexpected contents of target file'
os.remove(at.targetFileName)
#@+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.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 restore the screen
# 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.5455: *5* @test at.fullDirectoryPath
at = c.atFileCommands

p2 = p.firstChild().firstChild()
path = at.fullPath(p2,simulate=True)
end = g.os_path_normpath('abc/xyz')
assert path.endswith(end),repr(path)
#@+node:ekr.20100131180007.5456: *6* @path abc
#@+node:ekr.20100131180007.5457: *7* xyz
#@+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 ../test/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 ../test/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 ../test/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 ../test/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 ../test/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.
child4 = clone(child31,root,3)

for z in root.self_and_subtree():
    z.setVisited()
for z in child2,child31: # These should be moved.
    z.clearVisited()

c.atFileCommands.deleteUnvisitedNodes(root)

if 1:
    r = g.findNodeAnywhere(c,'Resurrected Nodes')
    assert r,'r'
    r1 = r.firstChild()
    r2 = r1.next()
    r3 = r2.next()
    test(r1,'child2','r1')
    test(r2,'child31','r2')
    assert root.numberOfChildren() == 3,'root.n'
if 1:
    delete_r()
    delete_children()

c.redraw_now()
#@+node:ekr.20110615130436.3319: *5* @test writing a .leo file retains orphan bits
# Not valid for external tests: uses @<file> node.
if not g.app.isExternalUnitTest:
    
    # Writing a .leo file must retain orphan bits of erroneous external files.
    
    h = '@file nonexistent-directory/orphan-bit-test.txt'
    p2 = g.findNodeAnywhere(c,h)
    assert p2,'not found: %s' % (h)
    assert p2.isOrphan(),'not an orphan originally'
    
    # It's dangerous to do the write, but this does test the bug fix.
    c.atFileCommands.clearAllOrphanBits(p2)
    assert p2.isOrphan(),'not an orphan after calling at.clearAllOrphanBits'
#@+node:ekr.20040707141957.12: *5* @test @thin: @last
# Doesn't work when run externally because the copy operation changes the gnx.
if not g.app.isExternalUnitTest:

    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.20100131171342.5508: *3* leoBridge
#@+node:ekr.20100131171342.5509: *4* @test leoBridge init logic
import leo.core.leoBridge as leoBridge

if 0: # This can not be run locally: it contains another Tk event loop.
    controller = leoBridge.controller(gui='nullGui',verbose=False)
    g = controller.globals()
#@+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.
cc = c.chapterController
if 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)
#@+node:ekr.20110608162543.3365: *4* @test chapter-rename & undo
# cc will be None when unit tests run dynamically.
cc = c.chapterController
if 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)
#@+node:ekr.20110608181936.3368: *4* @test chapter-move/clone/copy-node-to
# cc will be None when unit tests run dynamically.
cc = c.chapterController
if 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'
        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:
                # if not g.findNodeInTree(c,p,h):
                    # p2 = p.insertAsLastChild()
                    # p2.h = h
                    # p2.b = '# %s' % h
                p3 = g.findNodeInTree(c,chapterNode,h)
                if p3: p3.doDelete()
        cc.selectChapterByName('main',collapse=True)
        c.redraw()
#@+node:ekr.20080503132221.1: *4* @test chapter-create-from-node
# cc will be None when unit tests run dynamically.
cc = c.chapterController
if 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()
#@+node:ekr.20090615053403.4876: *3* leoColor
#@+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.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 restore the screen
# 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.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.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.20111112171235.3854: *4* @test add/delete html comments
w = c.frame.body.bodyCtrl
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.20111112171235.3855: *5* 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.bodyCtrl
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.20120309155126.3949: *4* @test add/delete comments with multiple @language directives
# Can't be run externally.
w = c.frame.body.bodyCtrl
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.20110510054817.3475: *4* @test c.alert
c.alert('test of c.alert')
#@+node:ekr.20050512084850: *4* @test c.checkOutline
errors = c.checkOutline(verbose=False,unittest=True,full=True) # Run full check.

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.20111104171708.3843: *4* @test c.CPrettyPrinter
cpp = c.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.20100209155559.5386: *4* @test c.createOpenWithTempFile
c.createOpenWithTempFile(p,'.py')
#@+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(event=None,verbose=False,unittest=True,full=True), '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.20100203103015.5355: *4* @test c.getOpenWithExt
@language python

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

for ext,result in table:
    result2 = c.getOpenWithExt(p,ext)
    assert result==result2,'ext: %s, expected %s, got %s' % (
        repr(ext),repr(result),repr(result2))
#@+node:ekr.20100212072149.5341: *4* @test c.goToScriptLineNumber
child = g.findNodeInChildren(c,p,'syntax-error')
assert child,'no child'
script = child.b
try:
    c.goToScriptLineNumber(child,script,1)
finally:
    p.contract()
    c.selectPosition(p)
    c.redraw()
#@+node:ekr.20100212072149.5342: *5* syntax-error
@language python
def spam:
    pass
#@+node:ekr.20071113105654.1: *4* @test c.hoist with no children
c.hoist()
c.dehoist()
#@+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:
        assert not c.hoistStack
        c.selectPosition(p1)
        assert c.p == p1
        c.hoist()
        assert c.p == p2
        c.dehoist()
        assert c.p == p2
        assert not c.hoistStack
    finally:
        c.selectPosition(p)
        c.redraw()
#@+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.20061106112522: *4* @test c.insertBodyTime
w = c.frame.body.bodyCtrl
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.20100203103015.5354: *4* @test c.openWithTempFilePath
s = c.openWithTempFilePath(p,'.py')
assert s.find('LeoTemp') > -1
assert s.endswith('.py')
#@+node:ekr.20111212142649.3971: *4* @test c.pasteOutline does not clone top node
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.20041019124050: *4* @test c.prettyPrintPythonCode
test1 = p.firstChild()
test2 = p.firstChild().next()

c.prettyPrintPythonCode(p=test2,dump=False)

assert(test2.b==test1.b)
#@+node:ekr.20041019124050.1: *5* Original
"""
line 1
line 2
line 3
"""
#@+node:ekr.20041019124050.2: *5* Test
"""
line 1
line 2
line 3
"""
#@+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: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.20100203103015.5353: *4* @test open-with conflict dialog
# A copy of the code from c.createOrRecreateTempFileAsNeeded.
# Not a perfect test, but stil significant.

assert c.conflict_message,'fail 1'

result = g.app.gui.runAskYesNoCancelDialog(c,
    "Conflict!", c.conflict_message,
    yesMessage = "Outline",
    noMessage = "File",
    defaultButton = "Cancel")

assert result in (None,'cancel'),'fail 2: %s' % result
#@+node:ekr.20071113201833: *4* @test zz restore the screen
# 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.20101021205258.6009: *4* c.Directives & directories
#@+node:ekr.20080917151620.9: *5* @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: *5* @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: *6* @path one
#@+node:ekr.20100131180007.5468: *7* @path two
#@+node:ekr.20100131180007.5469: *8* xyz
#@+node:sps.20100531034136.20110: *5* @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: *6* @path again
#@+node:sps.20100531034136.20112: *7* @path again
#@+node:sps.20100531034136.20113: *8* xyz
#@+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:
    pass
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 restore the screen
# 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 apropos_bindings
# vr plugin not loaded externally.
if not g.app.isExternalUnitTest:

    c.helpCommands.aproposBindings()
#@+node:ekr.20071113145804.17: *5* @test apropos_find_commands
# vr plugin not loaded externally.
if not g.app.isExternalUnitTest:

    c.helpCommands.aproposFindCommands()
#@+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.177,1.177
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.331,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
aaaacccc dddd
#@+node:ekr.20100817131738.5888: *6* before sel=1.10,1.10
aaaa bbbb cccc dddd
#@+node:ekr.20100817131738.5889: *6* after sel=1.4,1.4
aaaacccc 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
 is 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.0,3.0
This is the first sentence.  This
is the second sentence.  And
 is 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.1: *5* @test zz restore the screen
# This is **not** a real unit test.
# It simply restores the screen to a more convenient state.

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

#@+node:ekr.20081111084046.2: *4*  Commands C-E
#@+node:ekr.20111104171708.3847: *5* @test C_to_python
cpp = c.CPrettyPrinter(c)
c2p = c.editCommands.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)
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.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 not g.app.isExternalUnitTest:
    
    # Not valid when run externally.

    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.'''

if g.app.isExternalUnitTest or not g.isPython3:
    # print('external test')
    pass
else:
    log = c.frame.log
    c.bodyWantsFocusNow()
    tabs = log.orderedTabNames()
    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)
        
    # Test transfer into tree widget.
    event = g.bunch(widget=last_widget)
    c.editCommands.cycleAllFocus(event=event)
    last_widget = w = g.app.gui.get_focus()
    name = w.__class__.__name__
    assert name == 'LeoQTreeWidget',name
    
    # Test transfer into body widget.
    event = g.bunch(widget=last_widget)
    c.editCommands.cycleAllFocus(event=event)
    w = g.app.gui.get_focus()
    w_name = g.app.gui.widget_name(w)
    assert w_name == 'richTextEdit',w_name

#@+node:ekr.20111121164644.3928: *5* @test cycle-tab-focus
'''Test that cycle-all-focus cycles through all tabs.'''

if g.app.isExternalUnitTest:
    # print('external test')
    pass
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.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 not g.app.isExternalUnitTest:
    
    # Not valid when run externally.

    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)
if g.app.gui.guiName() == 'qt':
    exec(g.findTestScript(c,'@common leoEditCommands test code'))
    runEditCommandTest(c,p,inHeadline=False)
    runEditCommandTest(c,p,inHeadline=True)
#@+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)
if g.app.gui.guiName() == 'qt':

    exec(g.findTestScript(c,'@common leoEditCommands test code'))
    runEditCommandTest(c,p,inHeadline=False)
    runEditCommandTest(c,p,inHeadline=True)
#@+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.20081111082931.1: *5* @test zz restore the screen
# This is **not** a real unit test.
# It simply restores the screen to a more convenient state.

c.contractParent()
g.app.unitTestDict['restoreSelectedNode']=False
#@+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.20061128090441: *5* @@test kill-line end-2
c.testManager.runEditCommandTest(p)
#@+node:ekr.20061128090441.1: *6* work
line 1
line 2
#@+node:ekr.20061128090441.3: *6* before sel=3.0,3.0
line 1
line 2
#@+node:ekr.20061128090441.2: *6* after sel=2.6,2.6
line 1
line 2
#@+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.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.18,18.18
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.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-for-command')
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.20061128090338: *5* @test kill-line end-1
c.testManager.runEditCommandTest(p)
#@+node:ekr.20061128090338.1: *6* work
line 1
line 2

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

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

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

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

line 4
#@+node:ekr.20061128090147.3: *6* after sel=3.0,3.0
line 1
line 2
line 4
#@+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.20081111084046.3: *5* @test zz restore the screen
# This is **not** a real unit test.
# It simply restores the screen to a more convenient state.

c.contractParent()
g.app.unitTestDict['restoreSelectedNode']=False
#@+node:ekr.20110610122533.3369: *5* goto-global-line tests
#@+node:ekr.20110610122533.3388: *6* Tests with @auto as the root
#@+node:ekr.20110610122533.3389: *7* @test goto-line-number @auto 1
# Not valid for external tests: uses @<file> node.
if not g.app.isExternalUnitTest:
    
    root = p.parent().parent()
    h = '@auto unittest/at-auto-line-number-test.py'
    target = g.findNodeAnywhere(c,h)
    assert target,'no @auto node'
    
    p,n,found = c.goToLineNumber(c).countLines(target,2)
    assert found,'not found'
    assert n == 1,'n: %s' % (n)
    assert p.h == 'at_auto_child',p.h
#@+node:ekr.20110610122533.3390: *7* @test goto-global-line @auto 2
# Not valid for external tests: uses @<file> node.
if not g.app.isExternalUnitTest:
    
    h = '@auto unittest/at-auto-line-number-test.py'
    root = g.findNodeAnywhere(c,h)
    assert root,'no root'
    p,n,found = c.goToLineNumber(c).countLines(root,20)
    assert not found,'not found'
#@+node:ekr.20110610122533.3391: *7* @test goto-global-line @auto 3
# Not valid for external tests: uses @<file> node.
if not g.app.isExternalUnitTest:
    
    h = '@auto unittest/at-auto-line-number-test.py'
    root1 = g.findNodeAnywhere(c,h)
    assert root1
    assert root1.isAnyAtFileNode()
    
    fileName,lines,n,root = c.goToLineNumber(c).setup_file(n=3,p=root1)
    assert fileName == h[6:],'fileName: %s' % (fileName)
    assert root == root1,'root: %s, root1: %s' % (root and root.h,root1 and root1.h)
    
    if 0:
        print('root:%s, isRaw:%s, n:%s, len(lines): %s' % (
            root and root.h,isRaw,n,len(lines)))
#@+node:ekr.20110610122533.3392: *7* @test goto-global-line @auto 4
# Not valid for external tests: uses @<file> node.
if not g.app.isExternalUnitTest:
    
    h = '@auto unittest/at-auto-line-number-test.py'
    root1 = g.findNodeAnywhere(c,h)
    assert root1
    assert root1.isAnyAtFileNode()
    
    scriptData = {'p':root1.copy(),'lines':['a','b','c']}
    fileName,lines2,p2,root2 = c.goToLineNumber(c).setup_script(scriptData)
    
    assert fileName == h[6:],'fileName'
    assert lines2 == scriptData.get('lines'),'lines'
    assert p2 == root1,'p'
    assert root2 == root1,'root'
    
    if 0:
        print('root:%s, n:%s, len(lines): %s' % (
            root and root.h,n,len(lines)))
#@+node:ekr.20110610122533.3406: *7* @test goto-global-line @auto 5
# Not valid for external tests: uses @<file> node.
if not g.app.isExternalUnitTest:

    fn = '../test/at-auto-unit-test.py'
    root = g.findNodeAnywhere(c,'@auto %s' % (fn))
    assert root,'no root'
    
    child1 = root.firstChild()
    assert child1,'no child1'
    grand11 = child1.firstChild()
    assert grand11,'no grand11'
    grand12 = grand11.next()
    assert grand12,'no grand12'
    
    child2 = child1.next()
    assert child2,'no child2'
    grand21 = child2.firstChild()
    assert grand21,'no grand21'
    grand22 = grand21.next()
    assert grand22,'no grand22'
    
    def oops(found,p2,node,n,n2):
        result = [' ']
        result.append('goto-global-line test failed at line %s' % (n))
        if not found:
            result.append('line %s not found',n)
        else:
            result.append('got node "%s", expected "%s"' % (p2.h,node.h))
            result.append('got offset %s, expected %s' % (n2,n))
        return '\n'.join(result)
    
    table = (
        # Use 1-based numbers externally.
        # countLines converts to zero-based numbers.
        (1, child1,  0),
        (2, grand11, 0),
        (3, grand11, 1),
        (4, grand12, 0),
        (5, grand12, 1),
        (6, child1,  2),
        (7, child2,  0),
        (8, grand21, 0),
        (9, grand21, 1),
        (10,grand22, 0),
        (11,grand22, 1),
        (12,root,    3),
    )
    
    # Test against actual lines of the file.
    path = g.os_path_finalize_join(g.app.loadDir,'..','test',fn)
    f = open(path,'r') ; s = f.read() ; f.close()
    lines = g.splitLines(s) # The lines from the file.
    for n,node,index in table:
        goto = c.goToLineNumber(c)
        p2,n2,found = goto.countLines(root,n)
            # n, the argument to countLines, is 1-based
            # n2, the returned index into p2.b, is zero-based
        n -= 1
            # Convert n to zero-based for the comparisons below.
        lines2 = g.splitLines(p2.b)
        if 0:
            print('%2d %s' % (n,repr(lines[n])))
        else:
            ok = lines2[n2].lstrip() == lines[n].lstrip() 
            if not ok:
                i = 0
                for z in lines:
                    print('%2d %s' % (i,repr(z)))
                    i += 1
            if not ok:
                print('at line %s, index %s, node %s\ngot line %s\nexpected %s' % (
                    n,n2,p2.h,repr(lines2[n2].lstrip()),repr(lines[n].lstrip())))
            assert ok
#@+node:ekr.20110610122533.3401: *7* @test goToLineNumber.findRoot 1
# Not valid for external tests: uses @<file> node.
if not g.app.isExternalUnitTest:
    
    root = p.parent().parent()
    h = '@auto unittest/at-auto-line-number-test.py'
    target = g.findNodeAnywhere(c,h)
    assert target,'no target'
    child = target.firstChild()
    assert child.h == 'at_auto_child','child.h'
    
    p,found = c.goToLineNumber(c).findRoot(child)
    
    assert p == target,'p' #p and p.h
    assert found,'not found'
#@+node:ekr.20110610122533.3393: *6* Tests with @file as the root
#@+node:ekr.20110610122533.3394: *7* @test goto-global-line @file 1
# Not valid for external tests: uses @<file> node.
if not g.app.isExternalUnitTest:

    root = p.parent().parent()
    h = '@file unittest/at-file-line-number-test.py'
    target = g.findNodeAnywhere(c,h)
    assert target,'no target'
    
    gnx = g.app.nodeIndices.toString(target.v.fileIndex)
    assert gnx,'no gnx'
    
    delim = '#'
    found = c.goToLineNumber(c).findGnx(delim,root,gnx,h)
    assert found,'not found'
#@+node:ekr.20110610122533.3395: *7* @test goto-global-line @file 2
# Not valid for external tests: uses @<file> node.
if not g.app.isExternalUnitTest:
    
    root = p.parent().parent()
    h = '@file unittest/at-file-line-number-test.py'
    target = g.findNodeAnywhere(c,h)
    assert target,'no target'
    
    n = 2
    fileName,lines,n,root = c.goToLineNumber(c).setup_file(n,p=target)
    assert fileName == h[6:]
    # print('lines\n%s' % g.listToString(lines))
    assert root == target
    
    ignoreSentinels = True
    vnodeName,gnx,offset,delim = c.goToLineNumber(c).findVnode(root,lines,n,ignoreSentinels)
    
    assert lines,'no lines'
    assert offset is not None,repr(offset)
    assert vnodeName,repr(vnodeName)
#@+node:ekr.20110610122533.3396: *6* Tests with @shadow as the root
#@+node:ekr.20110610122533.3397: *7* @test goto-global-line @shadow
# Not valid for external tests: uses @<file> node.
if not g.app.isExternalUnitTest:

    h = '@shadow unittest/at-shadow-line-number-test.py'
    root1 = g.findNodeAnywhere(c,h)
    assert root1
    assert root1.isAnyAtFileNode()
    
    fileName,lines,n,root2 = c.goToLineNumber(c).setup_file(n=6,p=root1)
    assert fileName == h[8:],'fileName'
    assert root2 == root1
    
    if 0:
        print('root:%s, isRaw:%s, n:%s, len(lines): %s' % (
            root and root.h,isRaw,n,len(lines)))
#@+node:ekr.20110610122533.3398: *6* Tests with @nosent as the root
#@+node:ekr.20110610122533.3399: *7* @test goto-global-line @nosent
# Not valid for external tests: uses @<file> node.
if not g.app.isExternalUnitTest:
    
    h = '@nosent unittest/at-nosent-line-number-test.py'
    root1 = g.findNodeAnywhere(c,h)
    assert root1
    assert root1.isAnyAtFileNode()
    
    fileName,lines,n,root2 = c.goToLineNumber(c).setup_file(n=6,p=root1)
    assert fileName == h[8:],'fileName'
    assert root2 == root1
    
    if 0:
        print('root:%s, isRaw:%s, n:%s, len(lines): %s' % (
            root and root.h,isRaw,n,len(lines)))
#@+node:ekr.20110610122533.3404: *6* @test goto_showResults not found
c.goToLineNumber(c).showResults(
    found=False,p=p,n=3,n2=3,lines=['a','b'])



#@+node:ekr.20110610122533.3405: *6* @test zz restore the screen
# This is **not** a real unit test.
# It simply restores the screen to a more convenient state.

c.contractParent()
g.app.unitTestDict['restoreSelectedNode']=False
#@+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 not g.app.isExternalUnitTest:

    exec(g.findTestScript(c,'@common x-marked-nodes test code'))
    
    def test(p):
        setup_test(p)
        c.moveMarked()
        root = c.rootPosition()
        assert root.h == 'Moved marked nodes',root.h
        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,'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.20111121140833.3916: *5* @test selectToMatchingBracket
'''selectToMatchingBracket was crashing.'''

ec = c.editCommands
w = c.frame.body

s = w.getAllText()
i = s.find('(')
w.setInsertPoint(i)
ec.selectToMatchingBracket(event=None)
i,j = w.getSelectionRange()
assert i < j,'i: %s j: %s' % (i,j)
#@+node:ekr.20071113145804.4: *5* @test selfInsertCommand-1
@first # -*- coding: utf-8 -*-
@language python

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

    # This strings tests unicode, paren matching, and auto-indentation.
    u = g.u('(a\u00c9\u03a9B\u3045\u4e7cz):\n') # '(aÉΩBぅ乼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.bodyCtrl
    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.bodyCtrl
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.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.20081111084046.4: *5* @test zz restore the screen
# This is **not** a real unit test.
# It simply restores the screen to a more convenient state.

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

#@+node:ekr.20110118082508.3729: *5* reformat-paragraph tests
#@+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.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.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.18,14.18
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.20061104172236.1: *4*  Function tests
#@+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.bodyCtrl

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.20061104172236.5: *5* @test extendHelper
ec = c.editCommands ; w = c.frame.body.bodyCtrl

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.bodyCtrl

w.setInsertPoint(0)
k.arg = 't' # 'targetWord'
k.setState('find-word',1)
e.oneLineFlag = False
f = e.findWord(event=None)
i,j = w.getSelectionRange()
assert i == 10, 'expected 15, got %s' % (i)
#@+node:ekr.20061104172236.2: *5* @test findWordInLine
# targetWord

e = c.editCommands
k = c.k ; w = c.frame.body.bodyCtrl

w.setInsertPoint(0)
k.arg = 't' # 'targetWord'
k.setState('find-word',1)
for val in (True,False):
    e.oneLineFlag = val
    f = e.findWordInLine(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
c.helpCommands.helpForMinibuffer()
#@+node:ekr.20061104172236.6: *5* @test moveToHelper
ec = c.editCommands ; w = c.frame.body.bodyCtrl

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.bodyCtrl

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.bodyCtrl

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.bodyCtrl
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.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.bodyCtrl
    w.setInsertPoint(2)
    c.outerUpdate() # This fixed the problem.
    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 1:
        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.bodyCtrl
    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 inserting a new 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.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:
        pass # Fails, and it doesn't matter why.
    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
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
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
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.bodyCtrl)
    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)
assert p,'node not found: %s' % h
c.selectPosition(p)
c.bodyWantsFocus()
paste = '# Should be a comment'
g.app.gui.replaceClipboardWith(paste)
c.outerUpdate()
n = c.frame.body.colorizer.count
event = g.app.gui.create_key_event(c,None,None,c.frame.body.bodyCtrl)
c.frame.pasteText(event)

# Move around and and make sure it doesn't change.
try:
    # There is no colorizer to test for wx.
    if g.app.gui.guiName() == 'tkinter':
        c.outerUpdate() # Force the coloring before doing the test.
        assert c.frame.body.colorizer.count > n, 'did not recolor text'
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
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
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
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.
if g.app.gui.guiName() != 'tkinter':

    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.bodyCtrl
        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.bodyCtrl
    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* print end of typing and undo tests
print('\nEnd of typing and undo tests')
#@+node:ekr.20051109143831: *5* @test zz restore the screen
# This is **not** a real unit test.
# It simply restores the screen to a more convenient state.

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


#@+node:ekr.20100131180007.5453: *4* @test dynamicExpandHelper
# A totally wimpy test.
c.abbrevCommands.dynamicExpandHelper(event=None,prefix='',rlist=None,w=None)
#@+node:ekr.20070306091949: *4* @test zz restore the screen
# 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.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.bodyCtrl
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
table = (
    ('ignore_case','toggle-find-ignore-case-option'),
    ('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'),
)

finder = c.searchCommands.getHandler().finder
for ivar,command in table:
    val1 = finder.getOption(ivar)
    try:
        c.k.simulateCommand(command)
        val2 = finder.getOption(ivar)
        assert val2 == (not val1),'failed 1 %s' % command
        c.k.simulateCommand(command)
        val3 = finder.getOption(ivar)
        assert val3 == val1,'failed 2 %s' % command
    finally:
        finder.setOption(ivar,val1)
#@+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 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:
    pass # Not a valid test when run externally.
else:
    assert p.v.fileIndex == ('ekr', '20090507084947', 5152)
#@+node:ekr.20071113202045: *4* @test zz restore the screen
# 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' ; bodyCtrl = c.frame.body.bodyCtrl

c.searchCommands.openFindTab()
h = c.searchCommands.findTabHandler
w = h.find_ctrl
w.setAllText(s)
c.bodyWantsFocus()
bodyCtrl.setInsertPoint(0)
c.searchCommands.findTabFindNext()
w = c.get_focus()
wName = g.app.gui.widget_name(w)

# in wxPython w != bodyCtrl (it's a proxy)
assert 'body' in wName, 'focus: %s = %s, expected %s = %s' % (
    w,wName,bodyCtrl,g.app.gui.widget_name(bodyCtrl))
#@+node:ekr.20060130151716.3: *4* @test minbuffer find commands
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
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
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 restore the screen
# 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.20111113194727.3869: *4* @test bastTextWidget methods
import leo.core.leoFrame as leoFrame

w = leoFrame.baseTextWidget(c,'base-name','class-name',widget=None)

def check(expected):
    s = w.getAllText()
    assert s == expected,'expected %s got %s' % (expected,s)

w.setAllText('')        ; check('')
w.appendText('abc')     ; check('abc')
w.delete(1,2)           ; check('ac')
w.insert(0,'xy')        ; check('xyac')
w.insert(1,'z')         ; check('xzyac')
w.replace(2,4,'ABCD')   ; check('xzABCDc')

w.setSelectionRange(3,6)
s = w.getSelectedText()
assert s == 'BCD',repr(s)

w.deleteTextSelection() ; check('xzAc')
#@+node:ekr.20061106201509.6: *4* @test c.frame.body.getInsertLines
# line 1
# line 2
# line 3

w = c.frame.body.bodyCtrl
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.bodyCtrl
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.bodyCtrl
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
import PyQt4.QtGui as QtGui

log = c.frame.log
name = log.__class__.__name__

if g.app.isExternalUnitTest:
    assert name == 'nullLog',name
else:
    assert name == 'leoQtLog',name
    assert log.widget.__class__.__name__ == 'leoQTextEditWidget' 
    assert not issubclass(log.widget.__class__,QtGui.QWidget.__class__)
        # leoQTextEditWidget us a poor name: it is not a Qt widget.
    assert log.widget.widget.__class__.__name__ == 'LeoQTextBrowser'
    assert hasattr(log.widget,'widget') and log.widget.widget
    assert hasattr(log.widget.widget,'leo_log_wrapper')
    wrapper = log.widget.widget.leo_log_wrapper
    assert wrapper == log.widget

#@+node:ekr.20111121081052.3908: *4* @test c.frame.log.numberOfVisibleTabs
if g.app.isExternalUnitTest or not g.isPython3:
    # print('external test')
    pass
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)
    assert n == n3,'n: %s len(log.orederedTabNames()): %s' % (n,n3)
#@+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:
    pass # 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 not g.app.isExternalUnitTest:
    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.bodyCtrl
    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.bodyCtrl
    # 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 not g.app.isExternalUnitTest:

    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 restore the screen
# 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\nd'

    result = g.adjustTripleString(s,c.tab_width)
    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.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.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'):

    fn1 = r'file://C:\leo.repo\trunk\leo\doc\LeoDocs.leo#Leo 4.10 Release notes'
    
    table = (
        (r'file://C:/prog/test.sh',             ['os_startfile']),
        (r'file://C:/prog',                     ['os_startfile']),
        (r'http://writemonkey.com/index.php',   ['browser']),
        (fn1,                                   ['g.openWithFileName']), # ,'g.recursiveUNLSearch']),
        (r'#-->Before 4.10 b1',                 ['g.recursiveUNLSearch']),
    )
    
    for url,aList in table:
        
        g.handleUrl(c=c,p=c.p,url=url)
        for kind in aList:
            assert g.app.unitTestDict.get(kind),'kind: %s url: %s' % (
                kind,url)
    
    
#@+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,pluginName='xyz',verbose=False)
assert not module,repr(module)
#@+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.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.20080917151620.23: *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.20080917151620.30: *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.20080917151620.26: *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.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.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 restore the screen
# 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
import PyQt4.QtCore as QtCore
import PyQt4.QtGui as QtGui
import leo.plugins.qtGui as leoQtGui

if g.app.isExternalUnitTest:
    pass
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__,QtGui.QApplication)
    
    w = c.frame.body.bodyCtrl.widget
    assert issubclass(w.__class__,QtGui.QTextEdit)
    w_name = w.__class__.__name__
    assert w_name == 'LeoQTextBrowser',w_name
    
    p1 = p.copy()
    
    filter_obj = leoQtGui.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.'''

fn = '<file name>'
p2 = p.firstChild()
tree = c.frame.tree
if hasattr(tree,'treeWidget'):
    for cloneDrag in (True,False):
        tree.treeWidget.intraFileDrop(cloneDrag,fn,p,p2)
        assert True==g.app.unitTestDict['checkMoveWithParentWithWarning']
#@+node:ekr.20111003145300.3467: *5* a
#@+node:ekr.20100131171342.5602: *4* @test leoTextWidget
if g.app.gui.guiName() == 'tkinter':

    pc = g.app.pluginsController
    tkGui = pc.loadOnePlugin('leo.plugins.tkGui',verbose=False)
    import Tkinter as Tk
    w = tkGui.leoTkTextWidget()
    w.setAllText('abcdef\n')
    s = w.getAllText()
    assert s == 'abcdef\n'
    s1 = w.get(0,len(s))
    assert s1 == 'abcdef\n'
    w.delete(0,len(s))
    assert len(w.getAllText()) == 0
    w.setAllText('')
    w.insert(0,'abcdef\n')
    s = w.getAllText()
    assert s == 'abcdef\n','got: %s' % repr(s)
    w.setInsertPoint(2)
    i = w.getInsertPoint()
    assert i == 2
    w.setSelectionRange(2,4)
    assert w.hasSelection()
    i,j = w.getSelectionRange()
    assert i==2 and j==4
    s3 = w.getSelectedText()
    assert s3 == 'cd'
    w.deleteTextSelection()
    s4 = w.getAllText()
    assert s4 == 'abef\n'
    w.selectAllText()
    i,j = w.getSelectionRange()
    assert i==0 and j==5,'getSelectionRange failed: i=%d,j=%d' % (i,j)
    w.replace(0,3,'wxyz')
    s5 = w.getAllText()
    assert s5 == 'wxyzf\n','getAllText failed'
    w.flashCharacter(3)
    i = w.xyToGuiIndex(0,0)
    assert i == '1.0','wxToGuiIndex failed'
    i = w.xyToPythonIndex(0,0)
    assert i == 0
    w.mark_set('insert','1.3'),'xyToPythonIndex failed'
    i = w.getInsertPoint()
    assert i == 3
    w.tag_add('test',4,6)
    aTuple = w.tag_ranges('test')
    assert aTuple == (4,6),'tag_add failed: %s' % aTuple
#@+node:ekr.20111123214629.3941: *4* @test unbound Alt-N key is completely ignored
import PyQt4.QtCore as QtCore
import PyQt4.QtGui as QtGui
import leo.plugins.qtGui as leoQtGui

if g.app.isExternalUnitTest:
    pass
else:
    w = c.frame.body.bodyCtrl.widget
    assert issubclass(w.__class__,QtGui.QTextEdit)
    
    filter_obj = leoQtGui.leoQtEventFilter(c,w=w)
    g.app.unitTestDict[p.h] = filter_obj # keep a pointer to the filter.

    # Create an Alt-7 key event.
    ev = QtCore.QEvent
    e = QtGui.QKeyEvent(ev.KeyPress,ord('7'),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.5600: *4* @test w.toGui/PythonIndex
w = c.frame.body.bodyCtrl
s = w.getAllText()

for i in range(len(s)):
    i2 = w.toGuiIndex(i)
    i3 = w.toPythonIndex(i2)
    assert(i3==i)
#@+node:ekr.20100131171342.5601: *4* @test w.toGuiIndex (test2)
#ab
#

w = c.frame.body.bodyCtrl

# This test applies only to tkinter indices.
if g.app.gui.guiName() == 'tkinter':

    table = (
        (-1,'1.0'), # One too small.
        (0,'1.0'),
        (1,'1.1'),
        (2,'1.2'),
        (3,'1.3'), # The newline ends a row.
        (4,'2.0'),
        (5,'2.1'),
    )

    for i,expected in table:
        result = w.toGuiIndex(i)
        assert result == expected,'toGuiIndex(i): %s, expected: %s, got: %s' % (i,expected,result)
#@+node:ekr.20100131171342.5603: *4* @test zz restore the screen
# 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.4790: *4*  Test files
import leo.core.leoImport as leoImport
ic = c.importCommands
runner = leoImport.baseScannerClass(ic,atAuto=True,language='python')
i = 0
lines1 = ['abc',]
lines2 = ['xyz',]

g.app.unitTestDict ['expectedErrors'] = 1
g.app.unitTestDict ['expectedMismatchLine'] = 1

runner.compareHelper(lines1,lines2,i,strict=True)
#@+node:ekr.20090529141856.4716: *4*  Tests of @auto
@tabwidth -4
@language python
#@+node:ekr.20090529141856.4782: *5* @test checkTrialWrite
@first # -*- coding: utf-8 -*-

import leo.core.leoImport as leoImport
import sys

ic = c.importCommands
runner = leoImport.baseScannerClass(ic,atAuto=True,language='python')
runner.root = p.copy()

g.app.unitTestDict ['expectedMismatchLine'] = 0

s1 = 'line Ä, 궯, 奠 end'
s2 = 'line Ä, 궯, end'

# Tracing checkTrialWrite causes a UnicodeDecodeError.
ok = runner.checkTrialWrite(s1=s1,s2=s2)

assert ok
#@+node:ekr.20090529141856.4783: *5* @test collapse-all
c.contractAllHeadlines()
#@+node:ekr.20090529141856.4717: *5* C tests
#@+node:ekr.20090529141856.4718: *6* @test c class 1
fileName = p.h

s = '''\
class cTestClass1 {

    int foo (int a) {
        a = 2 ;
    }

    char bar (float c) {
        ;
    }
}
'''

c.importCommands.cUnitTest(p,s=s,showTree=False)
#@+node:ekr.20090529141856.4719: *6* @test c class--underindented line
fileName = p.h

s = '''\
class cTestClass1 {

    int foo (int a) {
# an underindented line.
        a = 2 ;
    }

    # This should go with the next function.

    char bar (float c) {
        ;
    }
}
'''

g.app.unitTestDict ['expectedErrors'] = 1
g.app.unitTestDict ['expectedMismatchLine'] = None
c.importCommands.cUnitTest(p,s=s,showTree=False)
#@+node:ekr.20090529141856.4720: *6* @test defaultImporter
fileName = p.h

s = '''\
class cTestClass1 {

    int foo (int a) {
        a = 2 ;
    }

    char bar (float c) {
        ;
    }
}
'''

c.importCommands.defaultImporterUnitTest(p,s=s,showTree=False)
#@+node:ekr.20090529141856.4721: *6* @test c test--comment follows arg list
fileName = p.h

s = '''\
void
aaa::bbb::doit
    (
    awk* b
    )
{
    assert(false);
}

bool
aaa::bbb::dothat
    (
    xyz *b
    ) //  <---------------------problem
{
    return true;
}
'''

c.importCommands.cUnitTest(p,s=s,showTree=False)
#@+node:ekr.20090529141856.4722: *6* @test c test--comment follows block delim
fileName = p.h

s = '''\
void
aaa::bbb::doit
    (
    awk* b
    )
{
    assert(false);
}

bool
aaa::bbb::dothat
    (
    xyz *b
    ) 
{
    return true;
} //  <---------------------problem
'''

c.importCommands.cUnitTest(p,s=s,showTree=False)
#@+node:ekr.20090529141856.4723: *6* @test c test--intermixed blanks and tabs
fileName = p.h

s = '''
void
aaa::bbb::doit
    (
    awk* b  // leading blank
    )
{
	assert(false); // leading tab
}

'''

g.app.unitTestDict ['expectedErrors'] = 0 # Intermixed blanks and tabs are ok for C.

c.importCommands.cUnitTest(p,s=s,showTree=False)
#@+node:ekr.20090529141856.4724: *6* @test c old-style decl 1
fileName = p.h

s = '''\
static void
ReleaseCharSet(cset)
    CharSet *cset;
{
    ckfree((char *)cset->chars);
    if (cset->ranges) {
    ckfree((char *)cset->ranges);
    }
}
'''

g.app.unitTestDict ['expectedErrors'] = 0

c.importCommands.cUnitTest(p,s=s,showTree=False)
#@+node:ekr.20090529141856.4725: *6* @test c old-style decl 2
fileName = p.h

s = '''\
Tcl_Obj *
Tcl_NewLongObj(longValue)
    register long longValue;	/* Long integer used to initialize the
         * new object. */
{
    return Tcl_DbNewLongObj(longValue, "unknown", 0);
}
'''

g.app.unitTestDict ['expectedErrors'] = 0

c.importCommands.cUnitTest(p,s=s,showTree=False)
#@+node:ekr.20090529141856.4726: *6* @test c extern
fileName = p.h

s = '''\
extern  "C"
{
#include "stuff.h"
void    init(void);
#include "that.h"
}
'''

g.app.unitTestDict ['expectedErrors'] = 0

c.importCommands.cUnitTest(p,s=s,showTree=False)
#@+node:ekr.20090529141856.4727: *5* c# tests
#@+node:ekr.20090529141856.4728: *6* @test c# namespace indent
s = '''\
namespace {
    class cTestClass1 {
        ;
    }
}
'''

g.app.unitTestDict ['expectedErrors'] = 0

c.importCommands.cSharpUnitTest(p,s=s,showTree=False)
#@+node:ekr.20090529141856.4729: *6* @test c# namespace no indent
s = '''\
namespace {
class cTestClass1 {
    ;
}
}
'''

g.app.unitTestDict ['expectedErrors'] = 0

c.importCommands.cSharpUnitTest(p,s=s,showTree=False)
#@+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.20090529141856.4731: *5* elisp tests
#@+node:ekr.20090529141856.4732: *6* @test elisp functions
s = '''\
;;; a.el --- Test

;; some other verbose comment
;; some other verbose comment
;; some other verbose comment

(defun abc (a1 a2)
  "Return blah blah."
  (+ 1 2))

(defun fgh (a1 a2)
  "Return blah blah."
  (- 1 2))

;;; a.el ends here
'''

g.app.unitTestDict ['expectedErrors'] = 0

c.importCommands.elispUnitTest(p,s=s,showTree=False)
#@+node:ekr.20090529141856.4733: *6* @test elisp 2
s = '''\
;;; comment
;;; continue
;;;

(defun abc (a b)
   (+ 1 2 3))

; comm
(defun cde (a b)
   (+ 1 2 3))
'''

g.app.unitTestDict ['expectedErrors'] = 0

c.importCommands.elispUnitTest(p,s=s,showTree=False)
#@+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>
'''

g.app.unitTestDict ['expectedErrors'] = 0

c.importCommands.htmlUnitTest(p,s=s,showTree=False)
#@+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>

'''

g.app.unitTestDict ['expectedErrors'] = 0

c.importCommands.htmlUnitTest(p,s=s,showTree=False)
#@+node:ekr.20111102164107.3975: *6* @test html: underindented comment
s = '''\

<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>

'''

g.app.unitTestDict ['expectedErrors'] = 0

c.importCommands.htmlUnitTest(p,s=s,showTree=False)
#@+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>
'''

g.app.unitTestDict ['expectedErrors'] = 0

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>
'''

g.app.unitTestDict ['expectedErrors'] = 0

c.importCommands.htmlUnitTest(p,s=s,showTree=False)
#@+node:ekr.20111112103320.3887: *6* @test html: improperly terminated tags
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>
    
<!-- oops: missing tags. -->
'''

g.app.unitTestDict ['expectedErrors'] = 0

c.importCommands.htmlUnitTest(p,s=s,showTree=False)
#@+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>
'''

g.app.unitTestDict ['expectedErrors'] = 0

c.importCommands.htmlUnitTest(p,s=s,showTree=False)
#@+node:ekr.20100803234640.5804: *5* ini tests
#@+node:ekr.20100803234640.5805: *6* @test ini-test-1
s = '''\
; last modified 1 April 2001 by John Doe
[owner]
name=John Doe
organization=Acme Widgets Inc.

[database]
server=192.0.2.62     ; use IP address in case network name resolution is not working
port=143
file = "payroll.dat"
'''

g.app.unitTestDict ['expectedErrors'] = 0

c.importCommands.iniUnitTest(p,s=s,showTree=False)
#@+node:ekr.20090529141856.4766: *5* Java tests
#@+node:ekr.20090529141856.4767: *6* @test java interface test1
s = '''\
interface Bicycle {
    void changeCadence(int newValue);
    void changeGear(int newValue);
}
'''

g.app.unitTestDict ['expectedErrors'] = 0

c.importCommands.javaUnitTest(p,s=s,showTree=False)
#@+node:ekr.20090529141856.4768: *6* @test java interface test2
s = '''\
interface Bicycle {
void changeCadence(int newValue);
void changeGear(int newValue);
}
'''

g.app.unitTestDict ['expectedErrors'] = 0

c.importCommands.javaUnitTest(p,s=s,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
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");
    }
}
'''

g.app.unitTestDict ['expectedErrors'] = 0

c.importCommands.javaUnitTest(p,s=s,showTree=False)

#@+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.4773: *6* @test from BundleException.java
@language python
@tabwidth 8
    # Must be in this node when run externally.

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;
	}
}

'''

g.app.unitTestDict ['expectedErrors'] = 0

c.importCommands.javaUnitTest(p,s=s,showTree=False)
#@+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 + '"';
};

'''

g.app.unitTestDict ['expectedErrors'] = 0

c.importCommands.javaScriptUnitTest(p,s=s,showTree=False)
#@+node:ekr.20090529141856.4777: *6* @test Javascript-2
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 + '"';
};

'''

g.app.unitTestDict ['expectedErrors'] = 0

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);
}

'''

# Double each backslash (they are in a docstring).
# chars = [z for z in s]
# s = []
# for z in char:
    # if z == '\\': s.append('\\\\')
    # else: s.append(z)
# s = s.join('')

g.app.unitTestDict ['expectedErrors'] = 0

c.importCommands.javaScriptUnitTest(p,s=s,showTree=False)
#@+node:ekr.20090529141856.4734: *5* Pascal tests
#@+node:ekr.20090529141856.4735: *6* @test pascal-to-delphi interface
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.
'''

g.app.unitTestDict ['expectedErrors'] = None
g.app.unitTestDict ['expectedMismatchLine'] = None
c.importCommands.pascalUnitTest(p,s=s,showTree=False)
#@+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!';
    }
}

?>

'''

g.app.unitTestDict ['expectedErrors'] = None
g.app.unitTestDict ['expectedMismatchLine'] = None
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
    }
}

?>
'''

g.app.unitTestDict ['expectedErrors'] = None
g.app.unitTestDict ['expectedMismatchLine'] = None
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);
    }
}
?>

'''

g.app.unitTestDict ['expectedErrors'] = None
g.app.unitTestDict ['expectedMismatchLine'] = None
c.importCommands.phpUnitTest(p,s=s,showTree=False)
#@+node:ekr.20090529141856.4736: *5* Python tests
# Warning: setting atAuto=True can wipe out unit tests.
#@+node:ekr.20090529141856.4737: *6* @@test nested class
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?
'''

g.app.unitTestDict ['expectedErrors'] = None
g.app.unitTestDict ['expectedMismatchLine'] = None
c.importCommands.pythonUnitTest(p,s=s,showTree=False)
#@+node:ekr.20090529141856.4738: *6* @test python comment after dict assign
@tabwidth -4
    # Required when running unit tests externally.

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?
'''

g.app.unitTestDict ['expectedErrors'] = None
g.app.unitTestDict ['expectedMismatchLine'] = None
c.importCommands.pythonUnitTest(p,s=s,showTree=False)
#@+node:ekr.20090529141856.4739: *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!"
'''

g.app.unitTestDict ['expectedErrors'] = None
g.app.unitTestDict ['expectedMismatchLine'] = None
c.importCommands.pythonUnitTest(p,s=s,showTree=False)
#@+node:ekr.20090529141856.4740: *6* @test python def inside def
@tabwidth -4
    # Required when running unit tests externally.

s = '''\
class aClass:
    def outerDef(self):
        """docstring.
        line two."""

        def pr(*args,**keys):
            g.es_print(color='blue',*args,**keys)

        a = 3
'''

g.app.unitTestDict ['expectedErrors'] = None
g.app.unitTestDict ['expectedMismatchLine'] = None
c.importCommands.pythonUnitTest(p,s=s,showTree=False)
#@+node:ekr.20090529141856.4741: *6* @test docstring only
@tabwidth -4
    # Required when running unit tests externally.

s = '''\
"""A file consisting only of a docstring.
"""
'''

g.app.unitTestDict ['expectedErrors'] = None
g.app.unitTestDict ['expectedMismatchLine'] = None
c.importCommands.pythonUnitTest(p,s=s,showTree=False)
#@+node:ekr.20090529141856.4742: *6* @test 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...')
'''

g.app.unitTestDict ['expectedErrors'] = None
g.app.unitTestDict ['expectedMismatchLine'] = None
c.importCommands.pythonUnitTest(p,s=s,showTree=False)
#@+node:ekr.20090529141856.4743: *6* @test 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
'''

g.app.unitTestDict ['expectedErrors'] = None
g.app.unitTestDict ['expectedMismatchLine'] = None
c.importCommands.pythonUnitTest(p,s=s,showTree=False)
#@+node:ekr.20090529141856.4744: *6* @test overindented def 3
@tabwidth -4
    # Required when running unit tests externally.

# This caused PyParse.py not to be imported properly.

s = '''\

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
# '''

c.importCommands.pythonUnitTest(p,s=s,showTree=False)
#@+node:ekr.20090529141856.4745: *6* @test python bad class test
@tabwidth -4
    # Required when running unit tests externally.

s = '''\
class testClass1 # no colon
    pass

def spam():
    pass
'''

g.app.unitTestDict ['expectedErrors'] = 0 # Not really an error.

c.importCommands.pythonUnitTest(p,s=s,showTree=False)
#@+node:ekr.20101101034131.6042: *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()
'''

showTree = False

tree = c.importCommands.pythonUnitTest(p,s=s,showTree=showTree)

if showTree:
    c.redraw_now()
    foo = g.findNodeInTree(c,p,'foo')
    assert foo
    s = "file('/tmp/script', 'w').write(s)"
    print('foo.b',repr(foo.b))
    assert foo.b.find(s) > -1,"foo.b: %s" % foo.b
#@+node:ekr.20090529141856.4746: *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.20090529141856.4747: *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.20090529141856.4748: *6* @test python decls test 1
@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.20090529141856.4749: *6* @test python def test 1
@tabwidth -4
    # Required when running unit tests externally.

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)
'''

c.importCommands.pythonUnitTest(p,s=s,showTree=False)
#@+node:ekr.20090529141856.4750: *6* @test python def test 2
@tabwidth -4
    # Required when running unit tests externally.

s = '''\

class test:
    def spam(b):
        pass

    # Used by paste logic.

    def foo(a):
        pass
'''

c.importCommands.pythonUnitTest(p,s=s,showTree=False)
#@+node:ekr.20090529141856.4751: *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.20090529141856.4752: *6* @test python extra leading ws test
@tabwidth -4
    # Required when running unit tests externally.

s = '''\

class cls:
     def fun(): # one extra space.
        pass
'''

g.app.unitTestDict ['expectedErrors'] = None # No error unless we get an unexpected mismatch line.
g.app.unitTestDict ['expectedMismatchLine'] = 3 # The error happens before any lines are checked.
g.app.unitTestDict ['expectedErrorMessage'] = 'leading whitespace not consistent with @tabwidth -4'

c.importCommands.pythonUnitTest(p,s=s,showTree=False)
#@+node:ekr.20090529141856.4753: *6* @test python indent decls
@tabwidth -4
    # Required when running unit tests externally.

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
''' 

g.app.unitTestDict ['expectedErrors'] = None
g.app.unitTestDict ['expectedMismatchLine'] = None
c.importCommands.pythonUnitTest(p,s=s,showTree=False)
#@+node:ekr.20090529141856.4754: *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.20090529141856.4755: *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.20090529141856.4756: *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.20090529141856.4757: *6* @test python underindent method
@tabwidth -4
    # Required when running unit tests externally.

s = '''\

class emptyClass: 

    def spam():

        """docstring line 1
under-indented docstring line"""
        pass

def followingDef(): # comment
    pass
'''

c.importCommands.pythonUnitTest(p,s=s,showTree=False)
#@+node:ekr.20090529141856.4758: *6* @test scanPythonText: leoImportNosent.py
@encoding utf-8
# leoImport.py uses unicode characters, so *this* test must have the directive above.

@tabwidth -4
    # Required when running unit tests externally.

fileName = g.os_path_abspath(g.os_path_join(g.app.loadDir,'leoImport.py'))

f = open(fileName)
s = f.read()
f.close()

g.app.unitTestDict['testingLeoImport.py'] = True

c.importCommands.pythonUnitTest(p,s=None,fileName=fileName,showTree=False)
#@+node:ekr.20090529141856.4759: *6* @test string test: extra indent
@tabwidth -4
    # Required when running unit tests externally.

s = '''\
class baseScannerClass:

        """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
'''

# We expect mismatches because the indentation does not match @tabwidth -4.
g.app.unitTestDict ['expectedErrors'] = None # No error unless we get an unexpected mismatch line.
g.app.unitTestDict ['expectedMismatchLine'] = 3
c.importCommands.pythonUnitTest(p,s=s,showTree=False)
#@+node:ekr.20090529141856.4760: *6* @test string underindent lines
@tabwidth -4
    # Required when running unit tests externally.

s = '''\
class baseScannerClass:
    def containsUnderindentedComment(self):
        a = 2
    # A true underindented comment.
        b = 3
    # This underindented comment should be placed with next function.
    def empty(self):
        pass
'''

g.app.unitTestDict ['expectedErrors'] = 0 # underindented comments are no longer an error.
c.importCommands.pythonUnitTest(p,s=s,showTree=False)
#@+node:ekr.20090529141856.4761: *6* @test string underindent lines 2
@tabwidth -4
    # Required when running unit tests externally.

s = '''\
class baseScannerClass:
    def containsUnderindentedComment(self):
        a = 2
    #
        b = 3
        # This comment is part of the present function.

    def empty(self):
        pass
'''

g.app.unitTestDict ['expectedErrors'] = 0 # underindented comments are no longer an error.
c.importCommands.pythonUnitTest(p,s=s,showTree=False)
#@+node:ekr.20090529141856.4762: *6* @test trailing comment
@tabwidth -4
    # Required when running unit tests externally.

s = '''\
class aClass: # trailing comment


    def def1(self):             # trailing comment
        pass
'''

g.app.unitTestDict ['expectedErrors'] = None
g.app.unitTestDict ['expectedMismatchLine'] = None
c.importCommands.pythonUnitTest(p,s=s,showTree=False)
#@+node:ekr.20090529141856.4763: *6* @test trailing comment--outer levels
@tabwidth -4
    # Required when running unit tests externally.

s = '''\

xyz = 6 # trailing comment
pass
'''

g.app.unitTestDict ['expectedErrors'] = None
g.app.unitTestDict ['expectedMismatchLine'] = None
c.importCommands.pythonUnitTest(p,s=s,showTree=False)
#@+node:ekr.20090529141856.4764: *6* @test 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
'''

g.app.unitTestDict ['expectedErrors'] = None
g.app.unitTestDict ['expectedMismatchLine'] = None
c.importCommands.pythonUnitTest(p,s=s,showTree=False)
#@+node:ekr.20090529141856.4765: *6* @test 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

g.app.unitTestDict ['expectedErrors'] = None
g.app.unitTestDict ['expectedMismatchLine'] = None
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.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>
'''

g.app.unitTestDict ['expectedErrors'] = 0

c.importCommands.xmlUnitTest(p,s=s,showTree=False)
#@+node:ekr.20111026105935.3966: *6* @test xml 2
s = '''\
<nodeA>
<nodeB/>
</nodeA>
'''

g.app.unitTestDict ['expectedErrors'] = 0

c.importCommands.xmlUnitTest(p,s=s,showTree=False)
#@+node:ekr.20120306173116.3933: *6* @test xml non-ascii tags
@first # -*- coding: utf-8 -*-

s = '''\
<:À.Ç>
<Ì>
<_.ÌÑ>
'''

g.app.unitTestDict ['expectedErrors'] = 0

c.importCommands.xmlUnitTest(p,s=s,showTree=False)
#@+node:ekr.20090529141856.4784: *4*  Tests of @auto-rst
#@+node:ekr.20090529141856.4785: *5* @test rST import test
s = '''\
.. toc

====
top
====

The top section

section 1
---------

section 1, line 1
--
selction 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
'''

g.app.unitTestDict ['expectedErrors'] = None
g.app.unitTestDict ['expectedMismatchLine'] = None
c.importCommands.rstUnitTest(p,s=s,showTree=False)
#@+node:ekr.20090529141856.4786: *5* @test rST import test (no double-underlines)
s = '''\
.. toc

top
====

The top section

section 1
---------

section 1, line 1
--
selction 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
'''

g.app.unitTestDict ['expectedErrors'] = None
g.app.unitTestDict ['expectedMismatchLine'] = None
c.importCommands.rstUnitTest(p,s=s,showTree=False)
#@+node:ekr.20090529141856.4787: *5* @test rST import test: long underlines
s = '''\
.. toc

top
-------------

The top section
'''

g.app.unitTestDict ['expectedErrors'] = None
g.app.unitTestDict ['expectedMismatchLine'] = None
c.importCommands.rstUnitTest(p,s=s,showTree=False)
#@+node:ekr.20090529141856.4788: *5* @test rST import test: long overlines
s = '''\
.. toc

======
top
======

The top section
'''

g.app.unitTestDict ['expectedErrors'] = None
g.app.unitTestDict ['expectedMismatchLine'] = None
c.importCommands.rstUnitTest(p,s=s,showTree=False)
#@+node:ekr.20090529141856.4789: *5* @test rST import test: trailing whitespace
s = '''\
.. toc

.. The section name contains trailing whitespace.

======
top 
======

The top section.
'''

g.app.unitTestDict ['expectedErrors'] = None
g.app.unitTestDict ['expectedMismatchLine'] = None
c.importCommands.rstUnitTest(p,s=s,showTree=False)
#@+node:ekr.20090529141856.4793: *4* @@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',):
            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.20111228125719.3909: *4* @test ic.baseScannerClass.insertIgnoreDirective
import leo.core.leoImport as leoImport

def setup(p):
    while p.hasChildren():
        p.firstChild().doDelete()

importCommands = c.importCommands
bic = leoImport.baseScannerClass(importCommands,atAuto=False,language='python')

try:
    setup(p)
    child = p.insertAsLastChild()
    child.h = 'child'
    bic.insertIgnoreDirective(parent=child)
    assert child.b.find('@ignore') == 0
finally:
    if 1:
        setup(p)
#@+node:ekr.20111110095252.3845: *4* @test ic.compareTokens: mismatched length
import leo.core.leoImport as leoImport

ic = c.importCommands
bs = leoImport.baseScannerClass(ic,atAuto=True,language='html')

<< define tokens >>

table = (
    (tokens11,tokens12),
    (tokens21,tokens22),
)

for tokens1,tokens2 in table:
    bs.compareTokens(tokens1,tokens2)
#@+node:ekr.20111110095252.3846: *5* << define tokens >>
@ 2011/11/10:

File "/usr/fetching/leo-editor/leo/core/leoImport.py", line 2074, in scanAndCompare
n1,n2,ok = self.compareTokens(tokens1,tokens2)
File "/usr/fetching/leo-editor/leo/core/leoImport.py", line 2094, in compareTokens
else:      kind1,val1 = 'eof','',n1
ValueError: too many values to unpack
@c

tokens11 = ()
tokens12 = (('id','abc',0),)

# Test similar situation, reversed.

tokens21 = (('id','abc',0),)
tokens22 = ()
#@+node:ekr.20111105221757.3831: *4* @test ic.createImportParent
files = ('x.h','x.cpp')

while p.hasChildren():
    p.firstChild().doDelete()

try:
    current = c.importCommands.createImportParent(c.p,files)
    assert current
    assert current.h == 'x'
    assert p.firstChild() == current
finally:
    while p.hasChildren():
        p.firstChild().doDelete()
    c.redraw()
#@+node:ekr.20111214100515.3921: *4* @test ic.createOutline: at-auto with lines that look like section references
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.20111104112332.3954: *4* @test ic.htmlScanner.adjust_class_ref
import leo.core.leoImport as leoImport
ic = c.importCommands
hs = leoImport.htmlScanner(importCommands=ic,atAuto=True)

s = '''
<aTag>  @others
</aTag>
'''

# Avoid probems with representation of @others in scripts.
expected = '\n<aTag>\n@others\n</aTag>\n'

result = hs.adjust_class_ref(s)
assert result == expected,'expected...\n%s\ngot...\n%s' % (
    repr(expected),repr(result))
#@+node:ekr.20111111074026.3972: *4* @test ic.htmlScanner.skipComment/Id/String
import leo.core.leoImport as leoImport
ic = c.importCommands
hs = leoImport.htmlScanner(importCommands=ic,atAuto=True)

table = (
    # Yes, both single and double quotes are valid in html.
    (hs.skipComment, '<!-- comment --> after',  '<!-- comment -->'),
    (hs.skipComment, '<!-- a\nb --> after',     '<!-- a\nb -->'),
    (hs.skipId,      'abc>',                    'abc'),
    (hs.skipId,      'abc"',                    'abc'),
    (hs.skipId,      'abc<!--',                 'abc'),
    (hs.skipId,      'a.b-c9:d after',          'a.b-c9:d'),
    (hs.skipString,  '"a string" after',        '"a string"'),
    (hs.skipString,  "'a string2' after",       "'a string2'"),
    (hs.skipString,  "'a string<'>",            "'a string<'"),
    (hs.skipString,  "'a string>'<",            "'a string>'"),
)

for func,s,expected in table:
    
    i = func(s,0)
    result = s[0:i]
    assert result == expected,'expected %s got %s' % (
        repr(expected),repr(result))
#@+node:ekr.20100131180007.5393: *4* @test ic.reportMismatch
import leo.core.leoImport as leoImport

ic = c.importCommands
scanner = leoImport.rstScanner(importCommands=ic,atAuto=True)
scanner.root = p
s1 = ["abc","xyz",]
s2 = ["xyz",]

scanner.reportMismatch(s1,s2,1,1)

s1 = ["xyz",]
s2 = ["abc","xyz",]

scanner.reportMismatch(s1,s2,1,1)
#@+node:ekr.20111105065243.3837: *4* @test ic.rstScanner.removeBlankLinesTokens (rst)
# Important: at present only the rstScanner sets ignoreBlankLines == True
import leo.core.leoImport as leoImport
sc = leoImport.rstScanner(c.importCommands,atAuto=False)

assert sc.ignoreBlankLines,'fail0'

def strip(tokens):
    '''Remove the line number item from all tokens.'''
    return [(kind,val) for kind,val,n in tokens]
    
table = (
    ('a\n\nb',          'a\nb'),
    ('a\n \t\nb',       'a\nb'),
    ('a\n \n\t\n\n\nb', 'a\nb'),
    ('a\nb\n',          'a\nb\n'),
)

for s,expected in table:

    tokens = sc.tokenize(s)
    s2 = ''.join([val for (kind,val,n) in tokens])
    assert s == s2,'fail1\nexpected:\n%s\ngot:\n%s' % (
        repr(s),repr(s2))
    
    # A: Remove tokens for blank lines from tokens.
    tokens2 = sc.removeBlankLinesTokens(tokens)
    
    # B: Remove blank lines first, then tokenize.
    lines = g.splitLines(s)
    lines2 = [z for z in lines if z.strip()]
    s2 = ''.join(lines2)
    tokens3 = sc.tokenize(s2)
    
    if 0:
        for kind,val,n in tokens3:
            print('%3s %7s %s' % (n,kind,repr(val)))
    
    # A and B should give the same result: just like abstract algebra diagrams.
    if 0:
        if strip(tokens2) != strip(tokens3):
            sc.compareTokens(tokens2,tokens3,trace=True)
    assert strip(tokens2) == strip(tokens3),'fail2\nexpected:\n%s\ngot:\n%s' % (
        strip(tokens3),strip(tokens2))
    
    # C: Removing blank tokens from already-compressed tokens should have no effect.
    tokens4 = sc.removeBlankLinesTokens(tokens3)
    assert tokens4 == tokens3,'fail3'
#@+node:ekr.20111104112332.3955: *4* @test ic.skip...Token (htmlScanner)
import leo.core.leoImport as leoImport
ic = c.importCommands
scanner = leoImport.htmlScanner(importCommands=ic,atAuto=True)

tails = (
    '<whatever>',
    '+ abc', # don't concatenate with id or whitespace.
    '<!-- tail comment -->',
    '"tail string"',
)
    
table = (
    (scanner.skipCommentToken,  '<!-- Test -->'),
    (scanner.skipIdToken,       'a_b-c.d:e'), # Valid in xml ids:  ".-:"
    # (scanner.skipNewlineToken,'\n'),
        # xmlScanner.skipNewlineToken throws exception (on purpose).
    (scanner.skipOtherToken,    '+'),
    (scanner.skipOtherToken,    '#'),
    (scanner.skipStringToken,   '"A string"'),
    (scanner.skipWsToken,       ' '),
)

# Special test for whitespace: Converts all runs of whitespace to a single blank.
if 0: # No longer does this.
    s = ' \n\t\t \n'
    i,result = scanner.skipWsToken(s+tails[0],0)
    assert i == len(s),'expected i==%s, got i==%s' % (len(s),i)
    expected = ' '
    assert result == expected,'expected...\n%s\ngot...\n%s' % (
        repr(expected),repr(result))
    
for f,s in table:
    for tail in tails:
        i,result = f(s+tail,0)
        expected = s
        assert i == len(s),'expected i==%s, got i==%s' % (len(s),i)
        assert result == expected,'expected...\n%s\ngot...\n%s' % (
            repr(expected),repr(result))
#@+node:ekr.20111104112332.3956: *4* @test ic.skip...Token (pythonScanner)
import leo.core.leoImport as leoImport
ic = c.importCommands
scanner = leoImport.pythonScanner(importCommands=ic,atAuto=True)
    
tails = (
    '+ abc', # don't concatenate with id or whitespace.
    '# tail comment',
    '"tail string"',
    "'tail string'",
)

table = (
    (scanner.skipCommentToken,  '# Test'),
    (scanner.skipIdToken,       'ab_c'),
    (scanner.skipNewlineToken,  '\n'),
    (scanner.skipOtherToken,    '+'),
    (scanner.skipOtherToken,    '#'),
    (scanner.skipStringToken,   '"A string"'),
    (scanner.skipWsToken,       ' '),
    (scanner.skipWsToken,       '\t '),
)
    
for f,s in table:
    for tail in tails:
        if f.__name__ == 'skipCommentToken':
            i,result = f(s,0)
        else:
            i,result = f(s+tail,0)
        expected = s
        assert i == len(s),'expected i==%s, got i==%s' % (len(s),i)
        assert result == expected,'expected...\n%s\ngot...\n%s' % (
            repr(expected),repr(result))
#@+node:ekr.20111104114406.3833: *4* @test ic.tokenize (htmlScanner)
import leo.core.leoImport as leoImport
ic = c.importCommands
hs = leoImport.htmlScanner(importCommands=ic,atAuto=True)

s = '''
<!-- a comment -->
<html "string">
Test.
</html>
'''

<< define expected >>

result = hs.tokenize(s)

if 1:
    assert result == expected,'expected...\n%s\ngot...\n%s' % (
        repr(expected),repr(result))
else:
    print(result)
    
@


AssertionError: expected...
[('ws', ' ', 0), ('comment', '<!-- a comment -->', 1), ('ws', ' ', 1), ('other', '<', 2), ('id', 'html', 2), ('ws', ' ',
 2), ('string', '"string"', 2), ('other', '>', 2), ('ws', ' ', 2), ('id', 'Test.', 3), ('ws', ' ', 3), ('other', '<', 4)
, ('other', '/', 4), ('id', 'html', 4), ('other', '>', 4), ('ws', ' ', 4)]
got...
[('nl', '\n', 0), ('comment', '<!-- a comment -->', 1), ('nl', '\n', 1), ('other', '<', 2), ('id', 'html', 2), ('ws', '
', 2), ('string', '"string"', 2), ('other', '>', 2), ('nl', '\n', 2), ('id', 'Test.', 3), ('nl', '\n', 3), ('other', '<'
, 4), ('other', '/', 4), ('id', 'html', 4), ('other', '>', 4), ('nl', '\n', 4)]

----------------------------------------------------------------------
Ran 1 test in 0.018s

FAILED (failures=1)

#@+node:ekr.20111104114406.3834: *5* << define expected >>
# expected = [
    # ('ws', ' ', 0),
    # ('comment', '<!-- a comment -->', 1),
    # ('ws', ' ', 1),
    # ('other', '<', 2), ('id', 'html', 2),
    # ('ws', ' ',2), ('string', '"string"', 2),
    # ('other', '>', 2),
    # ('ws', ' ', 2),
    # ('id', 'Test.', 3),
    # ('ws', ' ', 3),
    # ('other', '<', 4), ('other', '/', 4), ('id', 'html', 4), ('other', '>', 4),
    # ('ws', ' ', 4),
# ]

expected = [
    ('nl', '\n', 0),
    ('comment', '<!-- a comment -->', 1),
    ('nl', '\n', 1),
    ('other', '<', 2),
    ('id', 'html', 2),
    ('ws', ' ', 2),
    ('string', '"string"', 2),
    ('other', '>', 2),
    ('nl', '\n', 2),
    ('id', 'Test.', 3),
    ('nl', '\n', 3),
    ('other', '<', 4),
    ('other', '/', 4),
    ('id', 'html', 4),
    ('other', '>', 4),
    ('nl', '\n', 4),
]
#@+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.bodyCtrl
    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'),
    ( 20,'g.print'),
)

ac = c.k.autoCompleter
ac.w = c.frame.body.bodyCtrl

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:
    # print('external test')
    pass
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 = (
    ('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 restore the screen
# 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.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.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)

# also check the same on root level
child = c.rootPosition().insertAfter()
assert c.positionExists(child)
child.doDelete()
assert not c.positionExists(child)
#@+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.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.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.20041013062906: *4* @test onHyperLinkControlClick
# This hack is needed only for tkinter gui.
if g.app.gui.guiName() == 'tkinter':
    p.OnHyperLinkControlClick(event=None)
#@+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.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.20040802071519: *4* @test p.setBodyString
# Tests that c.setBodyString works immediately.
h = p.h

try:
    w = c.frame.body.bodyCtrl
    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.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 restore the screen
# 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)
    c.deleteOutline()
    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 not g.app.isExternalUnitTest:

    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()
    p = c.p
    assert p == p2,         'fail 3'
    assert p.next() == p3,  'fail 4'
    c.undoer.redo()
    p = c.p
    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 1:
        while root.hasChildren():
            root.firstChild().doDelete(newNode=None)
    c.redraw_now(root)
#@+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
root = p.copy()
while p.hasChildren():
    p.firstChild().doDelete(newNode = None)

try:

    p1 = p.insertAsLastChild()
    assert p1.textOffset() == 0

finally:
    if 1:
        while root.hasChildren():
            root.firstChild().doDelete(newNode = None)
    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

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.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(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(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(name = 'leo_pdf.py',
        path=path,
        pluginName = 'leo_pdf',
        verbose = False)

    assert module
    s = '''This is a test.'''
    result = c.rstCommands.writeToDocutils(s,'.pdf')
    # print(result)
    assert result,result
#@+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 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>
<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 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>
<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 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.
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 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.
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 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>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.

#@+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 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>This is a doc part
it has two lines.</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 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>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.

#@+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 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>This is a doc part
it has two lines.</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 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.
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 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.
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 0.8: 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 0.8: 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

if 1:
    x = c.shadowController
else:
    import leo.core.leoShadow as leoShadow
    x = leoShadow.shadowController(c,trace=False,trace_writers=False)

suite = unittest.makeSuite(unittest.TestCase)
root = g.findNodeAnywhere(c,'@shadow-tests')
assert root, 'Node not found: @shadow-tests'

trace = False ; vrbose = False
for p in root.children_iter():
    h = p.h.strip()
    if h.startswith('@shadow-test-lax'):
        test = x.atShadowTestCase(c,p,x,lax=True)
    elif h.startswith('@shadow-test'):
        test = x.atShadowTestCase(c,p,x,lax=False)
    else:
        test = None
    if test:
        if trace and verbose: print(h)
        suite.addTest(test)
if suite:
    g.app.scriptDict['suite'] = suite
#@+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 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 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.4437: *6* @shadow-test insert between nodes: at start of next node
#@+node:ekr.20090529115704.4438: *7* old
@others
#@+node:ekr.20090529115704.4439: *8* node 1
node 1 line 1
#@+node:ekr.20090529115704.4440: *8* node 2
node 2 line 1
#@+node:ekr.20090529115704.4441: *7* new
@others
#@+node:ekr.20090529115704.4442: *8* node 1
node 1 line 1
#@+node:ekr.20090529115704.4443: *8* node 2
inserted node at start of 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
#@+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
inserted node 1 at end of node 1
inserted node 2 at end of node 1
#@+node:ekr.20090529115704.4478: *8* node 2
node 2 line 1
#@+node:ekr.20090529115704.4479: *6* @shadow-test multiple-line insert between nodes: at start of next node
#@+node:ekr.20090529115704.4480: *7* old
@others
#@+node:ekr.20090529115704.4481: *8* node 1
node 1 line 1
#@+node:ekr.20090529115704.4482: *8* node 2
node 2 line 1
#@+node:ekr.20090529115704.4483: *7* new
@others
#@+node:ekr.20090529115704.4484: *8* node 1
node 1 line 1
#@+node:ekr.20090529115704.4485: *8* node 2
inserted node 1 at start of node 2
inserted node 2 at start of 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 NEW 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.20100131180007.5363: *4* @test class markerClass.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.markerClass(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 markerClass.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.markerClass(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 markerClass.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.markerClass(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):
    for p2 in result:
        if p == p2: return True
    else: return False

table = (('all',True,False),('marked',False,True))

try:
    p.setMarked()
    for kind,all,marked in table:
        result = c.testManager.findAllUnitTestNodes(all,marked)
        assert found(p,result),kind
    assert 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 restore the screen
# 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.20050120095423: ** Plugins
# Do this last.
#@+node:ekr.20110610082755.3362: *3*  qtGui.py
#@+node:ekr.20100131171342.5503: *4* @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: *4* @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)
        assert v == p.v, 'item2: %s, p.v: %s' % (item,p.v)
        p.moveToVisNext(c)
#@+node:ekr.20100131171342.5505: *4* @test item2position
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.20050120095423.11: *3* @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: *4* 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: *4* class pluginTestCase
class pluginTestCase(unittest.TestCase):

    '''A test case to test a single Leo plugin.'''

    @others
#@+node:ekr.20050120095423.14: *5* __init__
def __init__ (self,c,path):

    # Init the base class.
    unittest.TestCase.__init__(self)

    self.c = c
    self.path = path
#@+node:ekr.20050120095423.15: *5* fail
def fail (self,msg=None):

    """Mark a unit test as having failed."""

    g.app.unitTestDict["fail"] = g.callerName(2)
#@+node:ekr.20050120095423.16: *5* 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: *5* setUp
def setUp(self):

    g.app.unitTestDict = {}
#@+node:ekr.20050120095423.18: *5* shortDescription
def shortDescription (self):

    return "pluginTestCase: %s" % g.shortFileName(self.path)
#@+node:ekr.20050120095423.20: *4* 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.20050218015346: *3* @@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: *4* << class testRoutineTestCase >>
class testRoutineTestCase(unittest.TestCase):

    """Create a unit test from a snippet of code."""

    @others
#@+node:ekr.20050218015346.12: *5* __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: *5*  fail
def fail (self,msg=None):

    """Mark a unit test as having failed."""

    g.app.unitTestDict["fail"] = g.callerName(2)
#@+node:ekr.20050218015346.16: *5* 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: *5* shortDescription
def shortDescription (self):

    return 'test function',repr(self.f)
#@+node:ekr.20050218015346.18: *4* 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: *4* 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: *5* << 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: *4* 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: *3* @@test detect_urls.py
import leo.plugins.detect_urls as detect_urls

# print(c.frame.body.bodyCtrl)
w = c.frame.body.bodyCtrl
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: *3* @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.20111104214341.3835: *3* @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',
    'qt_main.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.20100131171342.5501: *3* @test zz restore the screen
# This is **not** a real unit test.
# It simply restores the screen to a more convenient state.

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.20111103213154.3822: ** Recent unit tests
#@+node:ekr.20090306091634.1: ** @test print redraw count
tree = c.frame.tree
if hasattr(tree,'redrawCount'):
    print('tree.redrawCount:',tree.redrawCount)
#@+node:ekr.20081111150402.11: ** @test zz restore the screen
# This is **not** a real unit test.
# It simply restores the screen to a more convenient state.

c.selectPosition(p)
c.contractParent()
c.selectPosition(p.parent())
### c.save() # Only good way to save the present expansion/selection state.
g.app.unitTestDict['restoreSelectedNode']=False
c.bodyWantsFocus()

# Print does not work: it is redirected.
g.es('all unit tests done',color='blue')
#@-all
#@-leo
