# RCytoscape/inst/test_cytoscape.R
#------------------------------------------------------------------------------------------------------------------------
library (RCy3)
library (RUnit)

#------------------------------------------------------------------------------------------------------------------------
if (!exists ('cy')){
    cy = CytoscapeConnection ()
    #to test name.map
    name.map = getLayoutNameMapping (cy)
    print(name.map)
    print(length(name.map))
    print(length(unname(name.map)))
    #test end
}

#------------------------------------------------------------------------------------------------------------------------
run.tests = function ()
{
    options ('warn'=0) # deprecation warnings (and others) are stored and reported

    # before doing anything else, make sure that the Cytoscape plugin version is one we can respond to
    test.plugin.version ()

    # start with a clean slate, and no windows
    deleteAllWindows (cy)

    #to test name.map
    cy = CytoscapeConnection ()
    name.map = getLayoutNameMapping (cy)
    print(name.map)
    print(length(name.map))
    print(length(unname(name.map)))
    #test end

    # many of the tests modify the default visual style, quite heedless of prior or successor tests.
    # if you wish to restore the initial default style, it is saved here, just once, upon entry to this method
    #
    #save.default.vizmap ()

    test.create.class ()
    #test.deleteWindow ()
    test.deleteAllWindows ()
    test.getWindowID ()

    deleteAllWindows (cy)

    test.getWindowList ()
    test.getNodeShapes ()
    test.getAttributeClassNames ()
    test.getArrowShapes ()

    deleteAllWindows (cy)

    test.getLineStyles ()
    test.getLayoutNames ()
    test.getLayoutNameMapping ()
    test.getLayoutPropertyNames ()

    deleteAllWindows (cy)

    test.getLayoutPropertyType ()
    test.getLayoutPropertyValue ()
    test.setLayoutProperties ()
    test.sendNodes ()

    deleteAllWindows (cy)

    test.sendEdges ()
    test.setNodeAttributes ()
    test.setEdgeAttributes ()
    test.noa ()

    deleteAllWindows (cy)

    test.eda ()
    test.cy2.edge.names ()
    test.getAdjacentEdgeNames ()
    test.panelOperations ()

    deleteAllWindows (cy)

    test.showGraphicsDetails ()
    test.setDefaultNodeShape ()
    test.setDefaultNodeColor ()
    test.setDefaultNodeSize ()

    deleteAllWindows (cy)

    test.setDefaultNodeBorderColor ()
    test.setDefaultNodeBorderWidth ()
    test.setDefaultNodeFontSize ()
    test.setDefaultNodeLabelColor ()

    deleteAllWindows (cy)

    test.setDefaultEdgeLineWidth ()
    test.setDefaultEdgeColor ()
    test.setDefaultEdgeFontSize ()
    test.setNodeLabelRule ()

    deleteAllWindows (cy)

    test.setEdgeLabelRule ()
    test.setNodeTooltipRule ()
    test.setEdgeTooltipRule ()
    test.setNodeColorRule ()

    deleteAllWindows (cy)

    test.setNodeBorderColorRule ()
    test.setNodeBorderWidthRule ()
    test.setNodeSizeRule ()
    test.setNodeShapeRule ()

    deleteAllWindows (cy)

    test.setNodeOpacityRule ()
    test.setNodeColorDirect ()
    test.setNodeBorderColorDirect ()
    test.setNodeLabelDirect () #--> too slow

    deleteAllWindows (cy)

    test.setNodeLabelPropertiesDirect ()  #--> too slow
    test.setNodeOpacityDirect ()  #--> too slow
    #test.setEdgeOpacityDirect ()  #--> too slow
    #test.setEdgeColorDirect ()  #--> too slow

    deleteAllWindows (cy)

    test.setEdgeSourceArrowShapeDirect ()
    test.setEdgeLabelDirect ()
    #test.setEdgeFontSizeDirect ()  #--> too slow
    #test.setEdgeLabelColorDirect ()  #--> too slow

    deleteAllWindows (cy)

    test.setEdgeTooltipDirect ()
    test.setEdgeLineWidthDirect ()
    test.setEdgeLineStyleDirect ()
    test.setEdgeSourceArrowShapeDirect ()

    deleteAllWindows (cy)

    test.setEdgeTargetArrowShapeDirect ()
    test.setEdgeSourceArrowColorDirect ()
    test.setEdgeTargetArrowColorDirect ()
    #test.setEdgeLabelOpacityDirect ()  #--> too slow

    deleteAllWindows (cy)

    #test.setEdgeSourceArrowOpacityDirect ()
    #test.setEdgeTargetArrowOpacityDirect ()
    #test.setEdgeLabelPositionDirect ()  #--> too slow
    #test.setEdgeLabelWidthDirect ()
    test.countNodes ()
    test.countEdges ()

    deleteAllWindows (cy)

    test.countNodesAndEdgesInEmptyGraph ()
    test.getAllNodes ()
    test.getAllEdges ()
    test.selectNodes ()
    test.nodeNeighborReportingAndSelection ()

    deleteAllWindows (cy)

    test.invertSelection ()
    test.deleteSelectedNodes ()
    test.hideNodes ()
    test.selectEdges ()
    test.setEdgeLineStyleRule ()

    deleteAllWindows (cy)

    test.setEdgeLineWidthRule ()
    test.setEdgeColorRule ()
    test.setEdgeTargetArrowRule ()
    test.setEdgeArrowColorRules ()
    test.setEdgeSourceArrowRule ()

    deleteAllWindows (cy)

    test.movie ()
    #test.unmatchedAttributesError ()
    #test.remove.redundancies.in.undirected.graph ()
    test.randomUndirectedGraph ()

    deleteAllWindows (cy)

    test.simpleGraph ()
    test.simpleGraphWithReciprocalEdge ()
    test.setGraph ()
    test.setNodePosition ()  #--> too slow

    deleteAllWindows (cy)

    test.getNodePosition ()
    test.getNodePosition.colonInNodeName ()  #--> too slow
    test.getNodeSize ()
    test.haveNodeAttribute ()

    deleteAllWindows (cy)

    test.haveEdgeAttribute ()
    test.copyNodeAttributesFromCyGraph ()
    test.copyEdgeAttributesFromCyGraph ()
    test.getGraphFromCyWindow ()

    deleteAllWindows (cy)

    test.sendDegenerateGraphs ()
    test.createWindowFromSelection ()
    test.addGraphToGraph ()

    deleteAllWindows (cy)

    test.addGraphToGraph.degenerateFirstGraph ()
    test.existing.CytoscapeWindow ()
    test.existing.CytoscapeWindow.noEdges ()
    test.existing.CytoscapeWindow.emptyGraph ()

    deleteAllWindows (cy)

    #test.getAttributeNames ()
    test.addGetAndDeleteEdgeAttributes ()
    test.addGetAndDeleteNodeAttributes ()
    test.getAllNodeAttributes ()

    deleteAllWindows (cy)

    test.getAllEdgeAttributes ()
    test.getVisualStyleNames ()
    #test.copyVisualStyle () # test passes alone but not during run.tests()??
    #test.setVisualStyle () # to be commented in again

    deleteAllWindows (cy)

    test.defaultColors ()
    test.fitContent ()
    #test.windowCoordinates ()

    deleteAllWindows (cy)

    #test.zoom () # timeout
    test.center ()
    #test.setNodeSizeDirect ()  #--> too slow
    #test.setNodeWidthAndHeightDirect ()  #--> too slow

    deleteAllWindows (cy)

    test.setNodeFontSizeDirect ()  #--> too slow
    test.setNodeShapeDirect ()  #--> too slow
    #test.setEdgeVizPropertiesDirect ()  #--> too slow
    #test.graphBAM ()

    deleteAllWindows (cy)

    test.addCyNode ()
    test.addCyEdge ()
    test.twoGraphsDoubleEdges ()
    test..classicGraphToNodePairTable ()
    test.rcy.edgeNames ()
    deleteAllWindows (cy)

    test..getNovelEdges ()
    #test.setNodeImageDirect ()
    #test.validity ()
    #test.tooltip.delays ()

    deleteAllWindows (cy)

    options ('warn'=0)

} # run.tests
#------------------------------------------------------------------------------------------------------------------------
save.default.vizmap = function ()
{
    default.style.name <- 'original.default.style'

    if (!default.style.name %in% getVisualStyleNames (cy)){ # it has not previously been stored
        copyVisualStyle (CytoscapeConnection (), 'default', 'orginal.default.style')
    }

} # save.default.vizmap
#------------------------------------------------------------------------------------------------------------------------
# almost every test needs to
#
#   !) announce it's name to stdout
#   2) delete any previous window with the same title, should any exist
#
# these services are provided here
#
window.prep = function (title)
{
    write (noquote (sprintf ('------- %s', title)), stderr ())

    cy <- CytoscapeConnection ()
    if (title %in% as.character (getWindowList (cy))){
        deleteWindow (cy, title)
    }
} # window.prep


.setUp <- function() deleteAllWindows(CytoscapeConnection())
.tearDown <- function() deleteAllWindows(CytoscapeConnection())


#------------------------------------------------------------------------------------------------------------------------
test.plugin.version = function ()
{
    title = 'test.plugin.version'
    cy = CytoscapeConnection ()

    plugin.version.string = pluginVersion (cy)
    string.tmp1 = strsplit (plugin.version.string,' ')[[1]][1]
    string.tmp2 = gsub ('[a-z]', '', string.tmp1)
    string.tmp3 = gsub ('[A-Z]', '', string.tmp2)
    major.minor.version = as.numeric (string.tmp3)
    checkTrue (major.minor.version >= 1)

} # test.plugin.version
#------------------------------------------------------------------------------------------------------------------------
test.create.class = function ()
{
    title = 'test.create.class'
    window.prep (title)

    g = new ('graphNEL')

    cw = CytoscapeWindow (title, g)
    checkTrue (validObject (cw))

} # test.create.class
#------------------------------------------------------------------------------------------------------------------------
test.deleteWindow = function ()
{
    title = 'test.deleteWindow'
    window.prep (title)

    cy = CytoscapeConnection ()
    cw = CytoscapeWindow (title, new ('graphNEL'))

    original.window.count = getWindowCount (cy)
    deleteWindow (cw)
    new.window.count = getWindowCount (cy)
    checkTrue (new.window.count == original.window.count - 1)

    # now delete a window by name
    window.prep (title)
    cw = CytoscapeWindow (title, new ('graphNEL'))
    original.window.count = getWindowCount (cy)
    deleteWindow (cy, title)
    new.window.count = getWindowCount (cy)
    checkTrue (new.window.count == original.window.count - 1)

} # test.deleteWindow
#------------------------------------------------------------------------------------------------------------------------
test.deleteAllWindows = function ()
{
      title = 'test.deleteAllWindows'
      cy = CytoscapeConnection ()
      deleteAllWindows (cy)
      new.window.count = getWindowCount (cy)
      checkEquals (new.window.count, 0)

} # test.deleteAllWindows
#------------------------------------------------------------------------------------------------------------------------
test.getWindowID = function ()
{
    title = 'test.getWindowID'
    window.prep (title)

    cw3 =  CytoscapeWindow (title, graph=makeSimpleGraph ())
    displayGraph (cw3)
    layoutNetwork (cw3)

    cy = CytoscapeConnection ()

    id = getWindowID (cy, 'test.getWindowID')
    checkEquals (id, cw3@suid)

    invisible (cw3)

} # test.getWindowID
#------------------------------------------------------------------------------------------------------------------------
test.getWindowList = function ()
{
    title = 'test.getWindowList'
    window.prep (title)

    cw2 = CytoscapeWindow (title, new ('graphNEL'))
    window.list = getWindowList (cw2)
    checkTrue (title %in% as.character (getWindowList (cw2)))

    invisible (cw2)

} # test.getWindowList
#------------------------------------------------------------------------------------------------------------------------
test.getNodeShapes = function ()
{
    title = 'test.getNodeShapes'
    window.prep (title)

    cy = CytoscapeConnection ()
    shapes = getNodeShapes (cy)
    checkTrue (length (shapes) > 8)
    #msg (cy, title)

    # pick a few specific shapes to test
    checkTrue (all (sapply (c ('HEXAGON', 'ELLIPSE', 'TRIANGLE'), function (s) s %in% shapes)))

} # test.getNodeShapes
#------------------------------------------------------------------------------------------------------------------------
test.getAttributeClassNames = function ()
{
    title = 'test.getAttributeClassNames'

    cy = CytoscapeConnection ()
    possible.values = getAttributeClassNames (cy)
    checkTrue (grep ('numeric', possible.values) > 0)
    checkTrue (grep ('integer', possible.values) > 0)
    checkTrue (grep ('character', possible.values) > 0)

} # test.getAttributeClassNames
#------------------------------------------------------------------------------------------------------------------------
test.getArrowShapes = function ()
{
    title = 'test.getArrowShapes'

    cy = CytoscapeConnection ()
    shapes = getArrowShapes (cy)
    checkTrue (length (shapes) >= 8)

    # pick a few specific shapes to test
    #msg (cy, 'getArrowShapes')
    checkTrue (all (sapply (c ('DIAMOND', 'T', 'CIRCLE'), function (s) s %in% shapes)))

} # test.getArrowShapes
#------------------------------------------------------------------------------------------------------------------------
test.getLineStyles = function ()
{
    title = 'test.getLineStyles'

    cy = CytoscapeConnection ()
    styles = getLineStyles (cy)
    checkTrue (length (styles) > 10)

    # pick a few specific styles to test
    #msg (cy, 'getLineStyles')
    checkTrue (all (sapply (c ('SOLID', 'DOT', 'EQUAL_DASH'), function (s) s %in% styles)))

} # test.getLineStyles
#------------------------------------------------------------------------------------------------------------------------
test.getLayoutNames = function ()
{
    title = 'test.getLayoutNames'

    cy = CytoscapeConnection ()
    names = getLayoutNames (cy)
    checkTrue (length (names) > 10)

    # pick a few specific styles to test
    #msg (cy, 'getLayoutNames')
    checkTrue (all (sapply (c ('grid', 'isom', 'circular'), function (s) s %in% names)))

} # test.getLayoutNames
#------------------------------------------------------------------------------------------------------------------------
test.getLayoutNameMapping = function ()
{
    cy = CytoscapeConnection ()
    name.map = getLayoutNameMapping (cy)
    checkTrue (length (name.map) >= 2)  # 20 on (4 mar 2011), 11 and 12 on (4 feb 2016)
    # technically this should be 12 but otherwise failures on the build system happen

    checkEquals (name.map [['Attribute Circle Layout']], "attribute-circle")
    checkEquals (name.map [['Edge-weighted Spring Embedded Layout']], "kamada-kawai")
    checkEquals (name.map [['Grid Layout']], "grid")

} # test.getLayoutNameMapping
#------------------------------------------------------------------------------------------------------------------------
test.getLayoutPropertyNames = function ()
{
    print (noquote ('------- test.getLayoutPropertyNames'))
    cy = CytoscapeConnection ()
    props = getLayoutPropertyNames (cy, 'force-directed')
    expected = c ("numIterations", "defaultSpringCoefficient", "defaultSpringLength",
                  "defaultNodeMass", "isDeterministic", "singlePartition")
    checkTrue (length (intersect (props, expected)) > (length (props) - 2))  # some variation across Cytoscape versions

    props = getLayoutPropertyNames (cy, 'isom')
    expected = c ("coolingFactor", "initialAdaptation", "maxEpoch", "minAdaptation",
                  "minRadius", "radius", "radiusConstantTime", "singlePartition", "sizeFactor")
    checkEquals (sort (props), expected)


} # test.getLayoutPropertyNames
#------------------------------------------------------------------------------------------------------------------------
test.getLayoutPropertyType = function ()
{
    print (noquote ('------- test.getLayoutPropertyType'))
    cy = CytoscapeConnection ()

     # a couple of single call tests
    checkEquals (getLayoutPropertyType (cy, 'isom', 'coolingFactor'), 'double')

    props = getLayoutPropertyNames (cy, 'force-directed')
    # now get all the property types for the force-directed layout
    propTypes.all = sapply (sort (props), function (prop) getLayoutPropertyType (cy, 'force-directed', prop))

    # check them all
    checkEquals (propTypes.all [["defaultNodeMass"]], "double")
    checkEquals (propTypes.all [["defaultSpringCoefficient"]], "double")
    checkEquals (propTypes.all [["defaultSpringLength"]], "double")
    checkEquals (propTypes.all [["numIterations"]], "int")
    checkEquals (propTypes.all [["singlePartition"]], "boolean")
    checkEquals (propTypes.all [["isDeterministic"]], "boolean")

} # test.getLayoutPropertyType
#------------------------------------------------------------------------------------------------------------------------
test.getLayoutPropertyValue = function ()
{
    print (noquote ('------- test.getLayoutPropertyValue'))
    cy = CytoscapeConnection ()

    layout.name = 'force-directed'
    props = getLayoutPropertyNames (cy, layout.name)

    prop = 'numIterations'
    checkTrue (prop %in% props)
    checkEquals (getLayoutPropertyValue (cy, layout.name, prop), 100)

    for (prop in props) {
        value = getLayoutPropertyValue (cy, layout.name, prop)
        prop.value.output <- sprintf ('force-directed layout %s: %s', prop, value)
        print (prop.value.output)
    } # for prop

} # test.getLayoutPropertyValue
#------------------------------------------------------------------------------------------------------------------------
test.setLayoutProperties = function ()
{
    # first, do some 'blind' (that is, window-less) tests
    cy = CytoscapeConnection ()
    layout.name = 'force-directed'
    prop = 'numIterations'
    setLayoutProperties (cy, layout.name, list (numIterations=200))
    checkEquals (getLayoutPropertyValue (cy, layout.name, prop), 200)

    # return to the defaults
    setLayoutProperties (cy, layout.name, list (numIterations=100))
    checkEquals (getLayoutPropertyValue (cy, layout.name, prop), 100)

    # now create a Cy window and manipulate the layout

    title = 'test.setLayoutProperties'
    window.prep (title)

    cw =  CytoscapeWindow (title, graph=makeSimpleGraph ())
    displayGraph (cw)
    redraw (cw)

    invisible (cw)

} # test.setLayoutProperties
#------------------------------------------------------------------------------------------------------------------------
test.collectTimings = function ()
{
    title = 'test.collectTimings'
    window.prep (title)

    cy = CytoscapeConnection ()
    if (title %in% as.character (getWindowList (cy))){
        deleteWindow (cy, title)
    }

    cwe = CytoscapeWindow (title, graph=makeSimpleGraph (), collectTimings=TRUE)
    displayGraph (cwe)
    layoutNetwork (cwe, 'grid')

    invisible (cwe)

} # test.collectTimings
#------------------------------------------------------------------------------------------------------------------------
test.sendNodes = function ()
{
    title = 'test.sendNodes'
    window.prep (title)
    g = RCy3::makeSimpleGraph ()

    cwa = CytoscapeWindow (title, graph=g)
    sendNodes (cwa)
    layoutNetwork (cwa, "grid")   # no edges, so other layouts will simply superimpose the nodes
    redraw (cwa)
    #msg (cwa, 'sendNodes')

    invisible (cwa)

} # test.sendNodes
#------------------------------------------------------------------------------------------------------------------------
test.sendEdges = function ()
{
    title = 'test.sendEdges'
    window.prep (title)

    g = RCy3::makeSimpleGraph ()
    cwe = CytoscapeWindow (title, graph=g)
    sendNodes (cwe)
    sendEdges (cwe)
    layoutNetwork (cwe, 'grid')

    invisible (cwe)

} # test.sendEdges
#------------------------------------------------------------------------------------------------------------------------
test.setNodeAttributes = function ()
{
    title = 'test.setNodeAttributes'
    window.prep (title)

    cy = CytoscapeConnection ()
    if (title %in% as.character (getWindowList (cy))){
        deleteWindow (cy, title)
    }

    g = RCy3::makeSimpleGraph ()
    cwb = CytoscapeWindow (title, graph=g)
    sendNodes (cwb)
    attribute.names = noa.names (g)

    for (attribute.name in attribute.names) {
        result = setNodeAttributes (cwb, attribute.name)
    }

    layoutNetwork (cwb, 'grid')
    redraw (cwb)

    # now call the direct method, which -- in contrast to the unmarked method (setNodeAttributes) -- does not
    # extract attributes from the graph; they are instead supplied separately, and thus are well suited to
    # successive updates, as in a movie

    result = setNodeAttributesDirect (cwb, 'count', 'int', c ('A', 'B', 'C'), c (38, 105, 0))

    result = setNodeAttributesDirect (cwb, 'count', 'int', 'A', 432)

    invisible (cwb)


} # test.setNodeAttributes
#------------------------------------------------------------------------------------------------------------------------
# depends on prior creation of cwe by test.sendEdges
test.setEdgeAttributes = function ()
{
    title = 'test.setEdgeAttributes'
    window.prep (title)

    cy = CytoscapeConnection ()
    if (title %in% as.character (getWindowList (cy))){
        deleteWindow (cy, title)
    }
    cwe = CytoscapeWindow (title, graph=makeSimpleGraph ())
    displayGraph (cwe)
    layoutNetwork (cwe, 'grid')
    redraw (cwe)
    attribute.names = eda.names (cwe@graph)

    for (attribute.name in attribute.names) {
        result = setEdgeAttributes (cwe, attribute.name)
    }

    edge.names = as.character (cy2.edge.names (cwe@graph))
    checkEquals (length (edge.names), 3)
    edge.values = c ('alligator', 'hedgehog', 'anteater')
    result = setEdgeAttributesDirect (cwe, 'misc', 'string', edge.names, edge.values)

    result = setEdgeAttributesDirect (cwe, 'misc', 'string', edge.names [1], edge.values [1])

    invisible (cwe)

} # test.setEdgeAttributes
#------------------------------------------------------------------------------------------------------------------------
test.noa = function ()
{
    title = 'test.noa'
    window.prep (title)

    g.simple = makeSimpleGraph ()

    result = noa (g.simple, 'type')
    checkEquals (length (result), 3)
    checkEquals (sort (names (result)), c ('A', 'B', 'C'))
    checkEquals (result [['A']], 'kinase')
    checkEquals (result [['B']], 'transcription factor')
    checkEquals (result [['C']], 'glycoprotein')

    checkTrue (is.na (noa (g.simple, 'bogusAttributeName')))
    invisible (g.simple)

} # test.noa
#------------------------------------------------------------------------------------------------------------------------
test.eda = function ()
{
    title = 'test.eda'
    window.prep (title)

    g.simple = makeSimpleGraph ()

    result = eda (g.simple, 'edgeType')
    checkEquals (length (result), 3)
    checkEquals (sort (names (result)), c ("A|B", "B|C", "C|A"))
    checkEquals (result [['A|B']], 'phosphorylates')
    checkEquals (result [['B|C']], 'synthetic lethal')
    checkEquals (result [['C|A']], 'undefined')

    checkTrue (is.na (eda (g.simple, 'bogusAttributeName')))
    invisible (g.simple)

} # test.eda
#------------------------------------------------------------------------------------------------------------------------
test.cy2.edge.names = function ()
{
    title = 'test.cy2.edge.names'
    window.prep (title)
    g = RCy3::makeSimpleGraph ()

    # this graph has the expected 'edgeType' edge attribute, used to make a standard cytoscape edge name
    edge.names = cy2.edge.names (g)
    checkEquals (edge.names [['A~B']], "A (phosphorylates) B")
    checkEquals (edge.names [['B~C']], "B (synthetic lethal) C")
    checkEquals (edge.names [['C~A']], "C (undefined) A")

    # now create a tiny graph, two nodes, one edge, with NO edgeType attribute.  make sure it is converted properly
    g2 =  new ('graphNEL', edgemode='directed')

    g2 = graph::addNode ('A', g2)
    g2 = graph::addNode ('B', g2)
    g2 = graph::addEdge ('A', 'B', g2)

    edge.names.2 = cy2.edge.names (g2)
    checkEquals (edge.names.2 [['A~B']], "A (unspecified) B")

    g3 = new ('graphNEL', edgemode='directed')
    edge.names.should.be.empty = cy2.edge.names (g3)
    checkTrue (is.na (edge.names.should.be.empty))

    #  now create a directed graphNEL with one reciprocal edge.  do we get the cy2 edge names properly?
    g.recip <- RCy3::makeSimpleGraph ()
    g.recip <- graph::addEdge ('C', 'B', g.recip)
    edgeData (g.recip, 'C', 'B', attr='edgeType') <- 'synthetic rescue'
    edgeData (g.recip, 'C', 'B', attr='score') <- 42
    edgeData (g.recip, 'C', 'B', attr='misc') <- 'ellany'

    g.recip.cy2.edge.names <- cy2.edge.names (g.recip)
    checkEquals (length (g.recip.cy2.edge.names), 4)
    checkEquals (sort (names (g.recip.cy2.edge.names)), c ("A~B", "B~C", "C~A", "C~B"))
    checkEquals (sort (as.character (g.recip.cy2.edge.names)),
                 c ("A (phosphorylates) B", "B (synthetic lethal) C", "C (synthetic rescue) B", "C (undefined) A"))

    invisible (g3)

    # now try the subsetting version, where only the cy2 edge names of the specified edges -- a subset -- are returned
    g = makeSimpleGraph ()
    r.edge.names = sort (edgeNames (g))
    checkEquals (r.edge.names, c ("A~B", "B~C", "C~A"))
    checkEquals (sort (as.character (cy2.edge.names (g, r.edge.names))),
                 c ("A (phosphorylates) B", "B (synthetic lethal) C", "C (undefined) A"))

    checkEquals (sort (as.character (cy2.edge.names (g, r.edge.names))) [1], "A (phosphorylates) B")
    checkEquals (sort (as.character (cy2.edge.names (g, r.edge.names))) [2], "B (synthetic lethal) C")
    checkEquals (sort (as.character (cy2.edge.names (g, r.edge.names))) [3], "C (undefined) A")

    checkEquals (sort (as.character (cy2.edge.names (g, r.edge.names))) [1:2], c ("A (phosphorylates) B", "B (synthetic lethal) C"))
    checkEquals (sort (as.character (cy2.edge.names (g, r.edge.names))) [c(1,3)], c ("A (phosphorylates) B", "C (undefined) A"))
    checkEquals (sort (as.character (cy2.edge.names (g, r.edge.names))) [2:3], c ("B (synthetic lethal) C", "C (undefined) A"))

} # test.cy2.edge.names
#------------------------------------------------------------------------------------------------------------------------
# depends on prior creation of cw by test.createClass, providing a CytoscapeWindow object, with a 'uri' slot
test.panelOperations = function ()
{
    title = 'test.panelOperations'
    window.prep (title)

    cw = CytoscapeWindow (title)

    hidePanel (cw, 'Control Panel')
    hidePanel (cw, 'd')

    floatPanel (cw, 'Co')
    floatPanel (cw, 'DATA')

    dockPanel (cw, 'control')
    dockPanel (cw, 'data panel')

} # test.panelOperations
#------------------------------------------------------------------------------------------------------------------------
test.showGraphicsDetails = function ()
{
    title = 'test.showGraphicsDetails'
    window.prep (title)

    cw = CytoscapeWindow (title, graph=RCy3::makeSimpleGraph ())
    displayGraph (cw)
    layoutNetwork (cw, 'grid')
    redraw (cw)

    showGraphicsDetails (cw)
    showGraphicsDetails (cw)

    cy = CytoscapeConnection ()

    showGraphicsDetails (cy)
    showGraphicsDetails (cy)

    invisible (cw)

} # test.showGraphicsDetails
#------------------------------------------------------------------------------------------------------------------------
test.setDefaultNodeShape = function (direct=FALSE)
{
    title = 'test.setDefaultNodeShape'
    window.prep (title)

    cwe = CytoscapeWindow (title, graph=RCy3::makeSimpleGraph ())
    displayGraph (cwe)
    layoutNetwork (cwe, 'grid')
    redraw (cwe)

    hidePanel (cwe, 'd');   hidePanel (cwe, 'c');
    shapes = getNodeShapes (cwe)

    if (direct) {  # debug
        for (shape in shapes) {
            setDefaultNodeShape (cwe, shape)
            Sys.sleep (0.3)
        } # for shape
    } # direct

    setDefaultNodeShape (cwe, 'OCTAGON')
    Sys.sleep (0.3)
    setDefaultNodeShape (cwe, 'ELLIPSE')
    Sys.sleep (0.3)
    setDefaultNodeShape (cwe, 'TRIANGLE')

    invisible (cwe)

} # test.setDefaultNodeShape
#------------------------------------------------------------------------------------------------------------------------
test.setDefaultNodeColor = function (direct=FALSE)
{
    title = 'test.setDefaultNodeColor'
    window.prep (title)

    cwe = CytoscapeWindow (title, graph=RCy3::makeSimpleGraph ())
    displayGraph (cwe)
    layoutNetwork (cwe, 'grid')
    setDefaultNodeColor (cwe, '#AA00AA')

    invisible (cwe)

} # test.setDefaultNodeColor
#------------------------------------------------------------------------------------------------------------------------
test.setDefaultNodeSize = function (direct=FALSE)
{
    title = 'test.setDefaultNodeSize'
    window.prep (title)

    cwe = CytoscapeWindow (title, graph=RCy3::makeSimpleGraph ())
    displayGraph (cwe)
    layoutNetwork (cwe, 'grid')

    setDefaultNodeSize (cwe, 20)
    setDefaultNodeSize (cwe, 200)

    invisible (cwe)

} # test.setDefaultNodeSize
#------------------------------------------------------------------------------------------------------------------------
test.setDefaultNodeBorderColor = function (direct=FALSE)
{
    title = 'test.setDefaultNodeBorderColor'
    window.prep (title)

    cwe = CytoscapeWindow (title, graph=RCy3::makeSimpleGraph ())
    displayGraph (cwe)
    layoutNetwork (cwe, 'grid')

    setDefaultNodeBorderColor (cwe, '#FFFFFF')
    setDefaultNodeBorderColor (cwe, '#FF0000')

    invisible (cwe)

} # test.setDefaultNodeBorderColor
#------------------------------------------------------------------------------------------------------------------------
test.setDefaultNodeBorderWidth = function (direct=FALSE)
{
    title = 'test.setDefaultNodeBorderWidth'
    window.prep (title)

    cwe = CytoscapeWindow (title, graph=RCy3::makeSimpleGraph ())
    displayGraph (cwe)
    layoutNetwork (cwe, 'grid')

    setDefaultNodeBorderWidth (cwe, 5)
    setDefaultNodeBorderWidth (cwe, 1)

    invisible (cwe)

} # test.setDefaultNodeBorderWidth
#------------------------------------------------------------------------------------------------------------------------
test.setDefaultNodeFontSize = function (direct=FALSE)
{
    title = 'test.setDefaultNodeFontSize'
    window.prep (title)

    cwe = CytoscapeWindow (title, graph=RCy3::makeSimpleGraph ())
    displayGraph (cwe)
    layoutNetwork (cwe, 'grid')

    setDefaultNodeFontSize (cwe, 12)

    invisible (cwe)

} # test.setDefaultNodeFontSize
#------------------------------------------------------------------------------------------------------------------------
test.setDefaultNodeLabelColor = function (direct=FALSE)
{
    title = 'test.setDefaultNodeLabelColor'
    window.prep (title)

    cwe = CytoscapeWindow (title, graph=RCy3::makeSimpleGraph ())
    displayGraph (cwe)
    layoutNetwork (cwe, 'grid')

    setDefaultNodeLabelColor (cwe, '#FFAAAA')

    invisible (cwe)

} # test.setDefaultNodeLabelColor
#------------------------------------------------------------------------------------------------------------------------
test.setDefaultEdgeLineWidth = function (direct=FALSE)
{
    title = 'test.setDefaultEdgeLineWidth'
    window.prep (title)

    cwe = CytoscapeWindow (title, graph=RCy3::makeSimpleGraph ())
    displayGraph (cwe)
    layoutNetwork (cwe, 'grid')

    setDefaultEdgeLineWidth (cwe, 10)

    invisible (cwe)

} # test.setDefaultEdgeLineWidth
#------------------------------------------------------------------------------------------------------------------------
test.setDefaultEdgeColor = function (direct=FALSE)
{
    title = 'test.setDefaultEdgeColor'
    window.prep (title)

    cwe = CytoscapeWindow (title, graph=RCy3::makeSimpleGraph ())
    displayGraph (cwe)
    layoutNetwork (cwe, 'grid')

    setDefaultEdgeColor (cwe, '#FF0000')

    invisible (cwe)

} # test.setDefaultEdgeColor
#------------------------------------------------------------------------------------------------------------------------
test.setDefaultEdgeFontSize = function ()
{
    title = 'test.setDefaultEdgeFontSize'
    window.prep (title)

    cwe = CytoscapeWindow (title, graph=RCy3::makeSimpleGraph ())
    displayGraph (cwe)
    setNodeSizeDirect (cwe, getAllNodes (cwe), 40)
    setEdgeLabelRule (cwe, 'edgeType')   # gives us some text we can inspect for changing font size (below)
    layoutNetwork (cwe, 'grid')

    setDefaultEdgeFontSize (cwe, 12);

    invisible (cwe)

} # test.setDefaultEdgeFontSize
#------------------------------------------------------------------------------------------------------------------------
test.setNodeLabelRule = function ()
{
    title = 'test.setNodeLabelRule'
    window.prep (title)

    cwe = CytoscapeWindow (title, graph=RCy3::makeSimpleGraph ())
    displayGraph (cwe)
    layoutNetwork (cwe, 'grid')

    setNodeLabelRule (cwe, 'label')
    setNodeLabelRule (cwe, 'type')
    setNodeLabelRule (cwe, 'lfc')
    setNodeLabelRule (cwe, 'count')

    invisible (cwe)

}  # test.setNodeLabelRule
#------------------------------------------------------------------------------------------------------------------------
test.setEdgeLabelRule = function ()
{
    title = 'test.setEdgeLabelRule'
    window.prep (title)

    cwe = CytoscapeWindow (title, graph=RCy3::makeSimpleGraph ())
    displayGraph (cwe)
    layoutNetwork (cwe, 'grid')
    setEdgeLabelRule (cwe, 'edgeType')
    setEdgeLabelRule (cwe, 'score')

    invisible (cwe)

}  # test.setEdgeLabelRule
#------------------------------------------------------------------------------------------------------------------------
test.setNodeTooltipRule = function ()
{
    title = 'test.setNodeTooltipRule'
    window.prep (title)

    cwe = CytoscapeWindow (title, graph=RCy3::makeSimpleGraph ())
    displayGraph (cwe)
    layoutNetwork (cwe, 'grid')

    setNodeTooltipRule (cwe, 'type')

    invisible (cwe)

}  # test.setNodeTooltipRule
#------------------------------------------------------------------------------------------------------------------------
test.setEdgeTooltipRule = function ()
{
    title = 'test.setEdgeTooltipRule'
    window.prep (title)

    cwe = CytoscapeWindow (title, graph=RCy3::makeSimpleGraph ())
    displayGraph (cwe)
    layoutNetwork (cwe, 'grid')
    setEdgeTooltipRule (cwe, 'edgeType')

    invisible (cwe)

}  # test.setEdgeTooltipRule
#------------------------------------------------------------------------------------------------------------------------
test.setNodeColorRule = function ()
{
    title = 'test.setNodeColorRule'
    window.prep (title)

    cwe = CytoscapeWindow (title, graph=RCy3::makeSimpleGraph ())
    displayGraph (cwe)
    layoutNetwork (cwe, 'grid')

    # first, specify a mode='interpolate' rule -- the default
    node.attribute.values = c (-3.0, 0.0, 3.0)
    node.colors = c ('#008800', '#00FF00', '#FFFFFF', '#FF0000', '#880000')
    setNodeColorRule (cwe, 'lfc', node.attribute.values, node.colors, mode='interpolate')

    # now, a lookup rule
    node.attribute.values = c ("kinase",  "transcription factor", "glycoprotein")
    node.colors =           c ('#8888FF', '#00F088',              "#00CCCC")
    setNodeColorRule (cwe, 'type', node.attribute.values, node.colors, mode='lookup')

    # now, a lookup rule with an incomplete lookup table:  does the default.color argument work?  cy2.7 bug -- not yet.
    # instead, the node is painted the cytoscape default color, pale red
    node.attribute.values = c ("kinase",  "transcription factor")
    node.colors = c ('#8888FF', '#00F088')
    setNodeColorRule (cwe, 'type', node.attribute.values, node.colors, mode='lookup', default.color='#AA33AA')

    # now, use 1 element lists.
    node.attribute.values = c ("kinase")
    node.colors = c ('#00AA88')
    setNodeColorRule (cwe, 'type', node.attribute.values, node.colors, mode='lookup', default.color='#AA33AA')

    invisible (cwe)

} # test.setNodeColorRule
#------------------------------------------------------------------------------------------------------------------------
test.setNodeBorderColorRule = function ()
{
    title = 'test.setNodeBorderColorRule'
    window.prep (title)

    cwe = CytoscapeWindow (title, graph=RCy3::makeSimpleGraph ())
    displayGraph (cwe)
    layoutNetwork (cwe, 'grid')
    # set the stage by making all the nodes white, to provide better contrast for the node border colors
    node.attribute.values = c (-3.0, 0.0, 3.0)
    colors = c ('#FFFFFF', '#FFFFFF', '#FFFFFF', '#FFFFFF', '#FFFFFF')
    setNodeColorRule (cwe, 'lfc', node.attribute.values, colors, mode='interpolate')

    # first, specify a mode='interpolate' rule -- the default
    node.attribute.values = c (-3.0, 0.0, 3.0)
    colors = c ('#008800', '#00FF00', '#FFFFFF', '#FF0000', '#880000')
    setNodeBorderColorRule (cwe, 'lfc', node.attribute.values, colors, mode='interpolate')
    Sys.sleep (0.3)

    # now, a lookup rule.  bright red, green and blue borders
    node.attribute.values = c ("kinase",  "transcription factor", "glycoprotein")
    colors =                c ('#FF0000', '#00FF00',              "#0000FF")
    setNodeBorderColorRule (cwe, 'type', node.attribute.values, colors, mode='lookup')
    Sys.sleep (0.3)

    # now, a lookup rule with an incomplete lookup table:  does the default.color argument work?  cy2.7 bug -- not yet.
    #  the glycoprotein node, 'Gene C', should have a white border around white fill
    node.attribute.values = c ("kinase",  "transcription factor")
    colors =                c ('#0000FF', '#FF0000')
    setNodeBorderColorRule (cwe, 'type', node.attribute.values, colors, mode='lookup', default.color='#FFFFFF')

    # now, one element lists
    node.attribute.values = c ("transcription factor")
    colors =                c ('#FF00FF')
    setNodeBorderColorRule (cwe, 'type', node.attribute.values, colors, mode='lookup', default.color='#FFFFFF')


    invisible (cwe)

} # test.setNodeBorderColorRule
#------------------------------------------------------------------------------------------------------------------------
test.setNodeBorderWidthRule = function ()
{
    title  = 'test.setNodeBorderWidthRule'
    window.prep (title)
    cy = CytoscapeConnection ()

    cwe = CytoscapeWindow (title, graph=RCy3::makeSimpleGraph ())
    displayGraph (cwe)
    layoutNetwork (cwe, 'grid')

    # set the stage by making all the nodes white, to provide better contrast for the node border colors
    node.attribute.values = c (-3.0, 0.0, 3.0)
    colors = c ('#FFFFFF', '#FFFFFF', '#FFFFFF', '#FFFFFF', '#FFFFFF')
    setNodeColorRule (cwe, 'lfc', node.attribute.values, colors, mode='interpolate')
    setDefaultNodeBorderColor (cwe, '#FF0000')

    for (i in 1:3) {
       # 3 different node border sizes
     node.attribute.values = c ("kinase",  "transcription factor", "glycoprotein")
     border.widths =         c (0, 10, 20)
     setNodeBorderWidthRule (cwe, 'type', node.attribute.values, border.widths)
       # swap them around different node border sizes
     node.attribute.values = c ("kinase",  "transcription factor", "glycoprotein")
     border.widths =         c (20, 0, 10);
     setNodeBorderWidthRule (cwe, 'type', node.attribute.values, border.widths)
     } # for i

    invisible (cwe)

} # test.setNodeBorderWidthRule
#------------------------------------------------------------------------------------------------------------------------
test.setNodeSizeRule = function ()
{
    title = 'test.setNodeSizeRule'
    window.prep (title)

    cwe = CytoscapeWindow (title, graph=RCy3::makeSimpleGraph ())
    displayGraph (cwe)
    layoutNetwork (cwe, 'grid')

    # first, create a simple 2-point rule, with 'below' and 'above' values strong enough to see that they are working
    # recall that makeSimpleGraph creates count attributes like this:
    # noa (getGraph (cwe), 'count')     #   A.A   B.B   C.C
    #                                       "2"  "30" "100"

    count.control.points = c (20,  40)
    node.sizes           = c (1, 80,  120, 300)
    setNodeSizeRule (cwe, 'count', count.control.points, node.sizes, mode='interpolate')
    system ('sleep 0.3')

    # now chop off the below & above values.  A should grow to 80, almost as big as B, and C should shrink to 120, larger that B

    count.control.points = c (20,  40)
    node.sizes           = c (80,  120)
    setNodeSizeRule (cwe, 'count', count.control.points, node.sizes, mode='interpolate')
    system ('sleep 0.3')

    # now use a mode='lookup' rule.  specify two sizes, look to see that the third type, glycoprotein, gets the tiny small size
    molecule.types = c ('kinase', 'transcription factor')
    node.sizes     = c (60, 80)
    setNodeSizeRule (cwe, 'type', molecule.types,  node.sizes, default.size= 5, mode='lookup')

    invisible (cwe)

} # test.setNodeSizeRule
#------------------------------------------------------------------------------------------------------------------------
test.setNodeShapeRule = function ()
{
    title = 'test.setNodeShapeRule'
    window.prep (title)

    cwe = CytoscapeWindow (title, graph=RCy3::makeSimpleGraph ())
    displayGraph (cwe)
    layoutNetwork (cwe, 'grid')

    # specify shapes for only two of the three nodes and node types.  make sure that the third node gets
    # the default shape

    # make rule for 2 of 3 node types, leaving the third as the default
    node.shapes = c ('diamond', 'triangle')
    attribute.values = c ('kinase', 'glycoprotein')
    setNodeShapeRule (cwe, node.attribute.name='type', attribute.values, node.shapes, default.shape='ellipse')

    # test one-element lists
    node.shapes = c ('diamond')
    attribute.values = c ('glycoprotein')
    setNodeShapeRule (cwe, node.attribute.name='type', attribute.values, node.shapes, default.shape='ellipse')

    invisible (cwe)

} # test.setNodeShapeRule
#------------------------------------------------------------------------------------------------------------------------
test.setNodeOpacityRule = function ()
{
    title = 'test.setNodeOpacityRule'
    window.prep (title)

    cw = CytoscapeWindow (title, graph=RCy3::makeSimpleGraph ())
    displayGraph (cw)

    # make the node borders prominent
    setDefaultNodeBorderColor (cw, '#FFFF00')
    setDefaultNodeBorderWidth (cw, 10)

    lfc.values = c (-3.0, 0, 3.0)

    # make the nodes big, give them strong colors
    setNodeSizeDirect (cw, nodes (cw@graph), 100)
    setNodeColorRule (cw, 'lfc', lfc.values, c ('#FF0000', '#00FF00', '#0000FF'), mode='interpolate'); redraw (cw)
    layoutNetwork (cw, 'grid')

    # first, the continuous 'interpolate' case, in which opacity is a function of lfc
    opacities = c (10, 128, 255)
    setNodeOpacityRule (cw, node.attribute.name='lfc', lfc.values, opacities, mode='interpolate')
    redraw (cw)

    # reset
    setNodeOpacityRule (cw, 'lfc', lfc.values, c (255, 255, 255), mode='interpolate', aspect='all');
    redraw (cw)

    # now try a few of the aspect-specific rules, still in interpolate mode
    # border:
    setNodeOpacityRule (cw, 'lfc', lfc.values, c (255, 255, 255), mode='interpolate', aspect='border');
    redraw (cw)
    setNodeOpacityRule (cw, 'lfc', lfc.values, c (40,128, 0), mode='interpolate', aspect='border');
    redraw (cw)

    # reset
    setNodeOpacityRule (cw, 'lfc', lfc.values, c (255, 255, 255), mode='interpolate');   redraw (cw)

    # label
    setNodeOpacityRule (cw, 'lfc', lfc.values, c (40,128, 0), mode='interpolate', aspect='border');
    redraw (cw)

    # reset
    setNodeOpacityRule (cw, 'lfc', lfc.values, c (255, 255, 255), mode='interpolate');   redraw (cw)

    # border
    setNodeOpacityRule (cw, 'lfc', lfc.values, c (40,128, 0), mode='interpolate', aspect='border');
    redraw (cw)

    # a mix...
    setNodeOpacityRule (cw, 'lfc', lfc.values, c (128, 128, 128), mode='interpolate', aspect='border, label, fill');
    redraw (cw)


    scalar.values = as.character (noa (cw@graph, 'type'))
    # reset
    setNodeOpacityRule (cw, 'type', scalar.values, c (255, 255, 255), mode='lookup');   redraw (cw)

    # label
    setNodeOpacityRule (cw, 'type', scalar.values, c (40,128, 0), mode='lookup', aspect='border');
    redraw (cw)

    # reset
    setNodeOpacityRule (cw, 'type', scalar.values, c (255, 255, 255), mode='lookup');   redraw (cw)

    # border
    setNodeOpacityRule (cw, 'type', scalar.values, c (40,128, 0), mode='lookup', aspect='border');
    redraw (cw)

    # a mix...
    setNodeOpacityRule (cw, 'type', scalar.values, c (128, 128, 128), mode='lookup', aspect='border, label, fill');
    redraw (cw)

    # make everything except labels transparent
    setNodeOpacityRule (cw, 'type', scalar.values, c (0, 0, 0), mode='lookup', aspect='border, fill');
    setNodeOpacityRule (cw, 'type', scalar.values, c (255, 255, 255), mode='lookup', aspect='label')
    redraw (cw)

    # make everything except borders transparent
    setNodeOpacityRule (cw, 'type', scalar.values, c (0, 0, 0), mode='lookup', aspect='label, fill');
    setNodeOpacityRule (cw, 'type', scalar.values, c (255, 255, 255), mode='lookup', aspect='border')
    redraw (cw)

    # make everything except fill transparent
    setNodeOpacityRule (cw, 'type', scalar.values, c (0, 0, 0), mode='lookup', aspect='label, border');
    setNodeOpacityRule (cw, 'type', scalar.values, c (255, 255, 255), mode='lookup', aspect='fill')
    redraw (cw)

    # now restore everything
    setNodeOpacityRule (cw, 'type', scalar.values, c (255, 255, 255), mode='lookup', aspect='all')
    redraw (cw)

    invisible (cw)

} # test.setNodeOpacityRule
#------------------------------------------------------------------------------------------------------------------------
test.setNodeColorDirect = function ()
{
    title = 'test.setNodeColorDirect'
    window.prep (title)

    cw = CytoscapeWindow (title, graph=RCy3::makeSimpleGraph ())
    displayGraph (cw)
    layoutNetwork (cw, 'grid')

    setNodeColorDirect (cw, 'A', '#AA0088')
    setNodeColorDirect (cw, c ('C', 'B'), '#448844')

    invisible (cw)

} # test.setNodeColorirect
#------------------------------------------------------------------------------------------------------------------------
test.setNodeBorderColorDirect = function ()
{
    title = 'test.setNodeBorderColorDirect'
    window.prep (title)

    cw = CytoscapeWindow (title, graph=RCy3::makeSimpleGraph ())
    displayGraph (cw)
    layoutNetwork (cw, 'grid')

    setNodeBorderColorDirect (cw, 'A', '#AA4488')
    setNodeBorderColorDirect (cw, c ('C', 'B'), '#AA8888')

    invisible (cw)

} # test.setNodeBorderColorDirect
#------------------------------------------------------------------------------------------------------------------------
test.setNodeLabelDirect = function ()
{
    #DEACTIVATED("too slow")
    title = 'test.setNodeLabelDirect'
    window.prep (title)

    cw = CytoscapeWindow (title, graph=RCy3::makeSimpleGraph ())
    displayGraph (cw)
    layoutNetwork (cw, 'grid')

    setNodeLabelDirect (cw, 'A', 'new A label')
    # try multiple nodes, one label, which RCy will replicate into the right number
    setNodeLabelDirect (cw, nodes (cw@graph), '')
    setNodeLabelDirect (cw, c ('A', 'C'), c ('AzA', 'ByB'))

    invisible (cw)

} # test.setNodeLabelDirect
#------------------------------------------------------------------------------------------------------------------------
test.setNodeLabelPropertiesDirect = function ()
{
    #DEACTIVATED("too slow")
    print ('--- test.setNodeLabelsPropertiesDirect')
    title = 'test.setNodeLabelPropertiesDirect'
    window.prep (title)

    cw = CytoscapeWindow (title, graph=RCy3::makeSimpleGraph ())
    displayGraph (cw)
    layoutNetwork (cw, 'grid')
    redraw (cw)

    sizes = c (10, 50, 80)
    colors = c ('#0000FF', '#00FF00', '#FF0000')
    for (i in 1:length (sizes)) {
        setNodeFontSizeDirect (cw, 'A', sizes [i])
        setNodeLabelColorDirect (cw, 'A', colors [i])
    } # for i

    invisible (cw)

} # test.setNodeLabelsPropertiesDirect
#------------------------------------------------------------------------------------------------------------------------
test.setNodeOpacityDirect = function ()
{
    #DEACTIVATED("too slow")
    title = 'test.setNodeOpacityDirect'
    window.prep (title)

    g = RCy3::makeSimpleGraph ()
    g = graph::addNode ('D', g)
    nodeData (g, 'D', 'label') = 'blink'
    cw = CytoscapeWindow (title, graph=g)
    displayGraph (cw)
    setNodeSizeDirect (cw, 'D', 120)
    layoutNetwork (cw, 'grid')
    fitContent (cw)
    setZoom (cw, 0.8 * getZoom (cw))
    redraw (cw)

    setNodeFillOpacityDirect (cw, 'A', 0)
    setNodeLabelOpacityDirect (cw, 'B', 0)
    setNodeBorderOpacityDirect (cw, 'C', 0)
    for (i in 1:3) {
        setNodeOpacityDirect (cw, 'D', 0)
        setNodeOpacityDirect (cw, 'D', 255)
    } # for i

    setNodeOpacityDirect (cw, c ('A', 'C'), 255)
    setNodeOpacityDirect (cw, c ('B', 'D'), 50)
    setNodeOpacityDirect (cw, c ('A', 'B', 'C', 'D'), c (10, 50, 100, 200))
    setNodeOpacityDirect (cw, c ('A', 'B', 'C', 'D'), c (200, 100, 50, 10))
    Sys.sleep (0.3)

    setNodeOpacityDirect (cw, c ('A', 'B', 'C', 'D'), 255); redraw (cw)

    invisible (cw)

} # test.setNodeOpacityDirect
#------------------------------------------------------------------------------------------------------------------------
# test.setEdgeOpacityDirect = function ()
# {
#     #DEACTIVATED("too slow for some reason")
#     title = 'test.setEdgeOpacityDirect'
#     window.prep (title)
#
#     g = RCy3::makeSimpleGraph ()
#     cw = CytoscapeWindow (title, graph=g)
#     setDefaultEdgeLineWidth (cw, 10)
#     displayGraph (cw)
#     layoutNetwork (cw, 'grid')
#
#     named.edge.names = cy2.edge.names (g)
#     edge.names <- unname(named.edge.names)
#
#     setEdgeOpacityDirect (cw, edge.names [1], 80)
#     setEdgeOpacityDirect (cw, edge.names [2], 0)
#     setEdgeOpacityDirect (cw, edge.names [3], 255)
#
#     setEdgeOpacityDirect (cw, edge.names [2], 80)
#     setEdgeOpacityDirect (cw, edge.names [3], 0)
#     setEdgeOpacityDirect (cw, edge.names [1], 255)
#
#     setEdgeOpacityDirect (cw, edge.names [1], 80)
#     setEdgeOpacityDirect (cw, edge.names [3], 40)
#     setEdgeOpacityDirect (cw, edge.names [2], 255)
#
#     setEdgeOpacityDirect (cw, edge.names [1], 0)
#     setEdgeOpacityDirect (cw, edge.names [3], 0)
#     setEdgeOpacityDirect (cw, edge.names [2], 0)
#
#     setEdgeOpacityDirect (cw, edge.names [1], 255)
#     setEdgeOpacityDirect (cw, edge.names [3], 255)
#     setEdgeOpacityDirect (cw, edge.names [2], 255)
#
#     setEdgeOpacityDirect (cw, edge.names, 0)
#     setEdgeOpacityDirect (cw, edge.names, 255)
#
#     setEdgeOpacityDirect (cw, edge.names, c (0, 128, 255))
#     setEdgeOpacityDirect (cw, edge.names, c (255, 0, 128))
#
#     setEdgeOpacityDirect (cw, edge.names, 255)
#
#     invisible (cw)
#
# } # test.setEdgeOpacityDirect
#------------------------------------------------------------------------------------------------------------------------
test.setEdgeColorDirect = function ()
{
    #DEACTIVATED("very slow for some reason")
    title = 'test.setEdgeColorDirect'
    window.prep (title)

    g = RCy3::makeSimpleGraph ()
    cw = CytoscapeWindow (title, graph=g)
    displayGraph (cw)
    layoutNetwork (cw, 'grid')

    edge.of.interest = as.character (cy2.edge.names (g) [1])
    setEdgeColorDirect (cw, edge.of.interest, '#FF0000')
    setEdgeColorDirect (cw, edge.of.interest, '#00FF00')
    setEdgeColorDirect (cw, edge.of.interest, '#0000FF')

    invisible (cw)

} # test.setEdgeColorDirect
#------------------------------------------------------------------------------------------------------------------------
test.setEdgeSourceArrowShapeDirect = function ()
{
    title = 'test.setEdgeSourceArrowShapeDirect'
    window.prep (title)

    cw = CytoscapeWindow ('test.setEdgeSourceArrowShapeDirect', graph=makeSimpleGraph())
    displayGraph (cw)
    layoutNetwork (cw, 'grid')
    fitContent (cw)

    edges.of.interest = as.character (cy2.edge.names (g))
    supported.arrow.shapes = getArrowShapes (cw)

    # first try passing three edges and three arrow shapes
    setEdgeSourceArrowShapeDirect (cw, edges.of.interest, supported.arrow.shapes [2:4])

    Sys.sleep (0.3)

    # now try passing three edges and one arrow.shapes
    setEdgeSourceArrowShapeDirect (cw, edges.of.interest, supported.arrow.shapes [6])

    # restore the default
    setEdgeSourceArrowShapeDirect (cw, edges.of.interest, 'NONE')
    invisible (cw)

} # test.setEdgeSourceArrowShapeDirect
#------------------------------------------------------------------------------------------------------------------------
test.setEdgeLabelDirect = function ()
{
    title = 'test.setEdgeLabelDirect '
    window.prep (title)

    cw = CytoscapeWindow ('test.setEdgeLabelDirect', graph=makeSimpleGraph())
    displayGraph (cw)
    layoutNetwork (cw, 'grid')
    edge.names = cy2.edge.names (cw@graph)[1:2]
    setEdgeLabelDirect (cw, edge.names, 'some name')

    invisible (cw)

} # test.setEdgeLabelDirect
#------------------------------------------------------------------------------------------------------------------------
#test.setEdgeFontFaceDirect = function ()
#{
#  title = 'test.setEdgeFontFaceDirect'
#  window.prep (title)
#
#  g = RCy3::makeSimpleGraph ()
#  cw = CytoscapeWindow (title, graph=g)
#  displayGraph (cw)
#  layoutNetwork (cw, 'grid')
#  redraw (cw)
#
#  edge.of.interest = cy2.edge.names (g) [1]
#  fonts = c ('courier', 'arial')
#  for (font in fonts) {
#    setEdgeFontFaceDirect (cw, edge.of.interest, font); redraw (cw);
#    Sys.sleep (0.3)
#    } # for i
#
#} # test.
#------------------------------------------------------------------------------------------------------------------------
test.setEdgeFontSizeDirect = function ()
{
    #DEACTIVATED("too slow for some reason.")
    title = 'test.setEdgeFontSizeDirect'
    window.prep (title)

    g = RCy3::makeSimpleGraph ()
    cw = CytoscapeWindow (title, graph=g)
    displayGraph (cw)
    layoutNetwork (cw, 'grid')

    edge.of.interest = cy2.edge.names (g) [1]
    setEdgeFontSizeDirect (cw, edge.of.interest, 12)

} # test.setEdgeFontSizeDirect
#------------------------------------------------------------------------------------------------------------------------
# test.setEdgeLabelColorDirect = function () # WORKS BUT IS A BIT SLOW
# {
#     #DEACTIVATED("too slow for some reason")
#     title = 'test.setEdgeLabelColorDirect'
#     window.prep (title)
#
#     g = RCy3::makeSimpleGraph ()
#     cw = CytoscapeWindow (title, graph=g)
#     displayGraph (cw)
#     layoutNetwork (cw, 'grid')
#     redraw (cw)
#
#     edge.names = cy2.edge.names (g)
#     setEdgeLabelDirect (cw, edge.names, 'some label')
#     setEdgeLabelColorDirect (cw, edge.names [1:2], '#FF0000')
#     setEdgeLabelColorDirect (cw, edge.names, '#00FF00')
#     setEdgeLabelColorDirect (cw, edge.names [3], '#000000')
#
# } # test.setEdgeLabelColorDirect
#------------------------------------------------------------------------------------------------------------------------
test.setEdgeTooltipDirect = function ()
{
    title = 'test.setEdgeTooltipDirect'
    window.prep (title)

    cw <- CytoscapeWindow (title, graph=makeSimpleGraph())
    displayGraph (cw)
    layoutNetwork (cw, 'grid')
    redraw (cw)

    edges.of.interest = as.character (cy2.edge.names (cw@graph))

    # first try passing three edges and three tooltips
    setEdgeTooltipDirect (cw, edges.of.interest, c ('tooltip #1', 'tooltip #2', 'tooltip #3'))
    redraw (cw)

    # now try passing three edges and one tooltip
    setEdgeTooltipDirect (cw, edges.of.interest [1:2], 'a general purpose tooltip')
    redraw (cw)

    invisible (cw)

} # test.setEdgeTooltipDirect
#------------------------------------------------------------------------------------------------------------------------
test.setEdgeLineWidthDirect = function ()
{
    title = 'test.setEdgeLineWidthDirect'
    window.prep (title)

    g = RCy3::makeSimpleGraph ()
    cw = CytoscapeWindow (title, graph=g)
    displayGraph (cw)
    layoutNetwork (cw, 'grid')
    redraw (cw)

    edges.of.interest = cy2.edge.names (g) [1:2]

    for (i in 1:10) {
        setEdgeLineWidthDirect (cw, edges.of.interest, i)
    }

    setEdgeLineWidthDirect (cw, edges.of.interest, 1)
    redraw (cw)

} # test.setEdgeLineWidthDirect
#------------------------------------------------------------------------------------------------------------------------
test.setEdgeLineStyleDirect = function ()
{
    title = 'test.setEdgeLineStyleDirect'
    window.prep (title)

    g = RCy3::makeSimpleGraph ()
    cw = CytoscapeWindow (title, graph=g)
    displayGraph (cw)
    layoutNetwork (cw, 'grid')
    redraw (cw)

    edges.of.interest = as.character (cy2.edge.names (g))

    supported.styles = getLineStyles (cw)

    # first try passing three edges and three styles
    setEdgeLineStyleDirect (cw, edges.of.interest, supported.styles [5:7])
    redraw (cw)

    Sys.sleep (0.3)

    # now try passing three edges and one styles
    setEdgeLineStyleDirect (cw, edges.of.interest, supported.styles [8])
    redraw (cw)

    # now loop through all of the styles

    for (style in supported.styles) {
        setEdgeLineStyleDirect (cw, edges.of.interest, style)
    }

    setEdgeLineStyleDirect (cw, edges.of.interest, 'SOLID')
    redraw (cw)

    invisible (cw)

} # test.setEdgeLineStyleDirect
#------------------------------------------------------------------------------------------------------------------------
test.setEdgeSourceArrowShapeDirect = function ()
{
    title = 'test.setEdgeSourceArrowShapeDirect'
    window.prep (title)

    g = RCy3::makeSimpleGraph ()
    cw = CytoscapeWindow (title, graph=g)
    displayGraph (cw)
    layoutNetwork (cw, 'grid')
    redraw (cw)
    fitContent (cw)

    edges.of.interest = as.character (cy2.edge.names (g))
    supported.arrow.shapes = getArrowShapes (cw)

    # first try passing three edges and three arrow.shapes
    setEdgeSourceArrowShapeDirect (cw, edges.of.interest, supported.arrow.shapes [5:7])
    redraw (cw)

    Sys.sleep (0.3)

    # now try passing three edges and one arrow shape
    setEdgeSourceArrowShapeDirect (cw, edges.of.interest, supported.arrow.shapes [8])
    redraw (cw)

    # now loop through all of the arrow.shapes

    for (shape in supported.arrow.shapes) {
        setEdgeSourceArrowShapeDirect (cw, edges.of.interest, shape)
    }

    # restore the default
    setEdgeSourceArrowShapeDirect (cw, edges.of.interest, 'NONE')
    redraw (cw)

    invisible (cw)

} # test.setEdgeSourceArrowShapeDirect
#------------------------------------------------------------------------------------------------------------------------
test.setEdgeTargetArrowShapeDirect = function ()
{
    title = 'test.setEdgeTargetArrowShapeDirect'
    window.prep (title)

    g = RCy3::makeSimpleGraph ()
    cw = CytoscapeWindow (title, graph=g)
    displayGraph (cw)
    layoutNetwork (cw, 'grid')
    redraw (cw)

    edges.of.interest = as.character (cy2.edge.names (g))
    supported.arrow.shapes = getArrowShapes (cw)

    # first try passing three edges and three arrow.shapes
    setEdgeTargetArrowShapeDirect (cw, edges.of.interest, supported.arrow.shapes [5:7])
    redraw (cw)

    Sys.sleep (0.3)

    # now try passing three edges and one arrow shape
    setEdgeTargetArrowShapeDirect (cw, edges.of.interest, supported.arrow.shapes [8])
    redraw (cw)

    # now loop through all of the arrow.shapes
    for (shape in supported.arrow.shapes) {
        setEdgeTargetArrowShapeDirect (cw, edges.of.interest, shape)
    }

    # restore the default
    setEdgeTargetArrowShapeDirect (cw, edges.of.interest, 'NONE')

    invisible (cw)

} # test.setTargetArrowShapeDirect
#------------------------------------------------------------------------------------------------------------------------
test.setEdgeSourceArrowColorDirect = function ()
{
    title = 'test.setEdgeSourceArrowColorDirect'
    window.prep (title)

    g = RCy3::makeSimpleGraph ()
    cw = CytoscapeWindow (title, graph=g)
    displayGraph (cw)
    layoutNetwork (cw, 'grid')
    redraw (cw)

    arrows = c ('Arrow', 'Diamond', 'Circle')
    edgeType.values = c ('phosphorylates', 'synthetic lethal', 'undefined')
    setEdgeSourceArrowRule (cw, 'edgeType', edgeType.values, arrows)
    setEdgeTargetArrowRule (cw, 'edgeType', edgeType.values, arrows)

    colors.1 = c ("#FFFFFF", "#FFFFFF", "#FFFFFF")
    colors.2 = c ("#AA00AA", "#00AAAA", "#0000AA")

    edge.names = as.character (cy2.edge.names (g) [1:3])

    setEdgeSourceArrowColorDirect (cw, edge.names, colors.1)
    setEdgeSourceArrowColorDirect (cw, edge.names, colors.2)

    invisible (cw)

} # test.setEdgeSourceArrowColorDirect
#------------------------------------------------------------------------------------------------------------------------
test.setEdgeTargetArrowColorDirect = function ()
{
    title = 'test.setEdgeTargetArrowColorDirect'
    window.prep (title)

    g = RCy3::makeSimpleGraph ()
    cw = CytoscapeWindow (title, graph=g)
    displayGraph (cw)
    layoutNetwork (cw, 'grid')
    redraw (cw)
    fitContent (cw)

    arrows = c ('Arrow', 'Diamond', 'Circle')
    edgeType.values = c ('phosphorylates', 'synthetic lethal', 'undefined')
    setEdgeSourceArrowRule (cw, 'edgeType', edgeType.values, arrows)
    setEdgeTargetArrowRule (cw, 'edgeType', edgeType.values, arrows)

    colors.1 = c ("#FFFFFF", "#FFFFFF", "#FFFFFF")
    colors.2 = c ("#AA00AA", "#00AAAA", "#0000AA")

    edge.names = as.character (cy2.edge.names (g) [1:3])

    setEdgeTargetArrowColorDirect (cw, edge.names, colors.1)
    setEdgeTargetArrowColorDirect (cw, edge.names, colors.2)

    invisible (cw)

} # test.setEdgeTargetArrowColorDirect
#------------------------------------------------------------------------------------------------------------------------
# test.setEdgeLabelOpacityDirect = function () # WORKS PERFECTLY BUT TOO SLOW
# {
#     #DEACTIVATED("too slow for some reason")
#     title = 'test.setEdgeLabelOpacityDirect'
#     window.prep (title)
#
#     g = RCy3::makeSimpleGraph ()
#     cw = CytoscapeWindow (title, graph=g)
#     displayGraph (cw)
#     layoutNetwork (cw, 'grid')
#     redraw (cw)
#
#     edge.of.interest = cy2.edge.names (g) [1]
#     for (i in 1:5) {
#         setEdgeOpacityDirect (cw, edge.of.interest, i * 30); redraw (cw);
#     } # for i
#
# } # test.setEdgeLabelOpacityDirect
#------------------------------------------------------------------------------------------------------------------------
test.setEdgeSourceArrowOpacityDirect = function ()
{
    title = 'test.setEdgeSourceArrowOpacityDirect'
    window.prep (title)

    g = RCy3::makeSimpleGraph ()
    cw = CytoscapeWindow (title, graph=g)
    displayGraph (cw)
    layoutNetwork (cw, 'grid')
    redraw (cw)

    edges.of.interest = as.character (cy2.edge.names (g))

    # make sure the source arrows are visible
    setEdgeSourceArrowShapeDirect (cw, edges.of.interest, 'Circle')

    # first try passing three edges and three arrow opacity values
    setEdgeSourceArrowOpacityDirect (cw, edges.of.interest, c (64, 128, 255))
    redraw (cw)

    Sys.sleep (0.3)

    # now try passing three edges and just one opacity value; it will be applied to all arrows
    setEdgeSourceArrowOpacityDirect (cw, edges.of.interest, 32)
    redraw (cw)

    # now loop through all of the arrow.opacitys
    for (opacity in seq (0, 255, by=45)) {
        setEdgeSourceArrowOpacityDirect (cw, edges.of.interest, opacity)
    }

    # restore the default
    setEdgeSourceArrowOpacityDirect (cw, edges.of.interest, 255)

} # test.setEdgeSourceArrowOpacityDirect
#------------------------------------------------------------------------------------------------------------------------
test.setEdgeTargetArrowOpacityDirect = function ()
{
    title = 'test.setEdgeTargetArrowOpacityDirect'
    window.prep (title)

    g = RCy3::makeSimpleGraph ()
    cw = CytoscapeWindow (title, graph=g)
    displayGraph (cw)
    layoutNetwork (cw, 'grid')
    redraw (cw)

    edges.of.interest = as.character (cy2.edge.names (g))

     # make sure the target arrows are visible
    setEdgeTargetArrowShapeDirect (cw, edges.of.interest, 'Circle')

    # first try passing three edges and three arrow opacity values
    setEdgeTargetArrowOpacityDirect (cw, edges.of.interest, c (64, 128, 255))
    redraw (cw)

    Sys.sleep (0.3)

    # now try passing three edges and just one opacity value; it will be applied to all arrows
    setEdgeTargetArrowOpacityDirect (cw, edges.of.interest, 32)
    redraw (cw)

    # now loop through all of the arrow.opacitys
    for (opacity in seq (0, 255, by=45)) {
        setEdgeTargetArrowOpacityDirect (cw, edges.of.interest, opacity)
    }

    # restore the default
    setEdgeTargetArrowOpacityDirect (cw, edges.of.interest, 255)
    redraw (cw)

} # test.setEdgeTargetArrowOpacityDirect
#------------------------------------------------------------------------------------------------------------------------
# test.setEdgeLabelPositionDirect = function () # WORKS PERFECTLY FINE BUT SLOW
# {
#     #DEACTIVATED("too slow for some reason")
#     title = 'test.setEdgeLabelPositionDirect'
#     window.prep (title)
#
#     g = RCy3::makeSimpleGraph ()
#     cw = CytoscapeWindow (title, graph=g)
#     displayGraph (cw)
#     layoutNetwork (cw, 'grid')
#     redraw (cw)
#
#     edge.of.interest = cy2.edge.names (g) [1]
#     for (i in 1:5) {
#         setEdgeOpacityDirect (cw, edge.of.interest, i * 30)
#         Sys.sleep (0.3)
#     } # for i
#
# } # test.setEdgeLabelPositionDirect
#------------------------------------------------------------------------------------------------------------------------
#test.setEdgeLabelWidthDirect = function ()
#{
#     title = 'test.setEdgeLabelWidthDirect',
#     window.prep (title),
#   ,
#     g = RCy3::makeSimpleGraph (),
#  cw = CytoscapeWindow (title, graph=g)
#  displayGraph (cw)
#  layoutNetwork (cw, 'grid')
#  redraw (cw)
#
#  edge.of.interest = cy2.edge.names (g) [1]
#  for (i in 1:5) {
#    setEdgeOpacityDirect (cw, edge.of.interest, i * 30); redraw (cw);
#    Sys.sleep (0.3)
#    } # for i
#
#} # test.
#------------------------------------------------------------------------------------------------------------------------
test.countNodes = function ()
{
    title = 'test.countNodes'
    window.prep (title)

    cwe = CytoscapeWindow (title, graph=RCy3::makeSimpleGraph ())
    displayGraph (cwe)
    layoutNetwork (cwe, 'grid')
    redraw (cwe)
    checkEquals (getNodeCount (cwe), length (nodes (getGraph (cwe))))

    invisible (cwe)

} # test.countNodes
#------------------------------------------------------------------------------------------------------------------------
test.countEdges = function ()
{
    title = 'test.countEdges'
    window.prep (title)

    cy = CytoscapeConnection ()
    if (title %in% as.character (getWindowList (cy))){
        deleteWindow (cy, title)
    }

    cwe = CytoscapeWindow (title, graph=RCy3::makeSimpleGraph ())
    displayGraph (cwe)
    layoutNetwork (cwe, 'grid')
    redraw (cwe)
    checkEquals (getEdgeCount (cwe), length (edgeNames (getGraph (cwe))))

    invisible (cwe)

} # test.countNodes
#------------------------------------------------------------------------------------------------------------------------
test.countNodesAndEdgesInEmptyGraph = function ()
{
    title = 'test.countNodesAndEdgesInEmptyGraph'
    window.prep (title)

    g.empty = new ("graphNEL", edgemode = "directed")
    checkEquals (length(g.empty@nodes), 0)
    checkEquals (length(g.empty@edgeL), 0)

    cwe = CytoscapeWindow (title, graph=g.empty)  # default behavior, but let's make it explicit
    displayGraph (cwe)
    layoutNetwork (cwe, 'grid')
    redraw (cwe)
    checkEquals (getNodeCount (cwe), 0)
    checkEquals (getEdgeCount (cwe), 0)

    invisible (cwe)

} # test.countNodesAndEdgesInEmptyGraph
#------------------------------------------------------------------------------------------------------------------------
test.getAllNodes = function ()
{
    title = 'test.getAllNodes'
    window.prep (title)

    cwe = CytoscapeWindow (title, graph=RCy3::makeSimpleGraph ())
    displayGraph (cwe)
    layoutNetwork (cwe, 'grid')
    redraw (cwe)

    cwe.nodes = getAllNodes (cwe)
    checkEquals (length (intersect (cwe.nodes, nodes (cwe@graph))), 3)

    invisible (cwe)

} # test.getAllNodes
#------------------------------------------------------------------------------------------------------------------------
test.getAllEdges = function ()
{
    title = 'test.getAllEdges'
    window.prep (title)

    cwe = CytoscapeWindow (title, graph=RCy3::makeSimpleGraph ())
    displayGraph (cwe)
    layoutNetwork (cwe, 'grid')
    redraw (cwe)

    cwe.edges = getAllEdges(cwe)
    checkTrue ("C (undefined) A" %in% cwe.edges)
    checkTrue ("B (synthetic lethal) C" %in% cwe.edges)
    checkTrue ("A (phosphorylates) B" %in% cwe.edges)

    #msg (cwe, 'test.getAllEdges')

    invisible (cwe)

} # test.getAllEdges
#------------------------------------------------------------------------------------------------------------------------
test.selectNodes = function ()
{
    title = 'test.selectNodes'
    window.prep (title)

    cwe = CytoscapeWindow (title, graph=RCy3::makeSimpleGraph ())
    displayGraph (cwe)
    layoutNetwork (cwe, 'grid')
    redraw (cwe)

    clearSelection (cwe)
    checkEquals (getSelectedNodeCount (cwe), 0)
    cwe.nodes = selectNodes (cwe, c ('A', 'B'), preserve=T)
    checkEquals (getSelectedNodeCount (cwe), 2)

    cwe.nodes = selectNodes (cwe, 'C', preserve=T)
    checkEquals (getSelectedNodeCount (cwe), 3)

    clearSelection (cwe)
    cwe.nodes = selectNodes (cwe, c ('A', 'B'), preserve=TRUE)
    checkEquals (getSelectedNodeCount (cwe), 2)
    cwe.nodes = selectNodes (cwe, 'C', preserve=FALSE)
    checkEquals (getSelectedNodeCount (cwe), 1)
    checkEquals (getSelectedNodes (cwe), 'C')

    clearSelection (cwe)
    checkEquals (getSelectedNodeCount (cwe), 0)
    nodes.to.select = c ('bogus', 'missing')
    selectNodes (cwe, nodes.to.select)
    checkEquals (getSelectedNodeCount (cwe), 0)
    nodes.to.select = c (nodes.to.select, nodes (cwe@graph))
    selectNodes (cwe, nodes.to.select)
    checkEquals (getSelectedNodeCount (cwe), 3)

    invisible (cwe)

} # test.selectNodes
#------------------------------------------------------------------------------------------------------------------------
test.nodeNeighborReportingAndSelection = function ()
{
    title = 'test.nodeNeighborReportingAndSelection'
    window.prep (title)

    # create a circular graph
    LETTERS = toupper (letters)
    source.nodes  <- LETTERS [1:26]
    target.nodes  <- c (LETTERS [2:26], LETTERS [1])
    weights <- runif (length (letters))
    df <- data.frame (from=source.nodes, to=target.nodes, weight=weights)
    g.bam <- graphBAM (df, edgemode='directed')
    g.bam <- initEdgeAttribute (g.bam, 'weight', 'numeric', 0.0)

    cw = CytoscapeWindow (title, graph=g.bam)
    displayGraph (cw)
    redraw (cw)
    layoutNetwork (cw)

    # paint the edges shades of green as function of weight
    setDefaultEdgeLineWidth (cw, 5)
    setEdgeColorRule (cw, 'weight',  c (0, 1), c ('#FFFFFF', '#00FF00'),  mode='interpolate')

    # select M, then its immediate neighbors
    checkEquals (getSelectedNodeCount (cw), 0)
    checkEquals (sort (getFirstNeighbors (cw, 'M')), c ('L', 'N'))
    selectNodes (cw, 'M')
    checkEquals (getSelectedNodeCount (cw), 1)
    selectFirstNeighborsOfSelectedNodes (cw)
    checkEquals (getSelectedNodeCount (cw), 3)
    checkEquals (sort (getSelectedNodes (cw)), c ('L', 'M', 'N'))
    sfn (cw)
    checkEquals (getSelectedNodeCount (cw), 5)
    nodes = sort (getSelectedNodes (cw))
    checkEquals (nodes, c ("K", "L", "M", "N", "O"))
    invisible (cw)

} # test.nodeNeighborReportingAndSelection
#------------------------------------------------------------------------------------------------------------------------
test.invertSelection = function ()
{
    title = 'test.invertSelection'
    window.prep (title)

    cwe = CytoscapeWindow (title, graph=RCy3::makeSimpleGraph ())
    displayGraph (cwe)
    layoutNetwork (cwe, 'grid')
    redraw (cwe)

    clearSelection (cwe)
    checkEquals (getSelectedNodeCount (cwe), 0)
    cwe.nodes = selectNodes (cwe, c ('A', 'B'))
    checkEquals (getSelectedNodeCount (cwe), 2)

    invertNodeSelection (cwe)
    redraw (cwe)
    checkEquals (getSelectedNodeCount (cwe), 1)
    invertNodeSelection (cwe)
    redraw (cwe)
    checkEquals (getSelectedNodeCount (cwe), 2)

    clearSelection (cwe)

    invisible (cwe)

} # test.invertSelection
#------------------------------------------------------------------------------------------------------------------------
test.deleteSelectedNodes = function ()
{
    title = 'test.deleteSelectedNodes'
    window.prep (title)

    cwe = CytoscapeWindow (title, graph=RCy3::makeSimpleGraph ())
    displayGraph (cwe)
    layoutNetwork (cwe, 'grid')
    redraw (cwe)

    clearSelection (cwe)
    checkEquals (getSelectedNodeCount (cwe), 0)
    cwe.nodes = selectNodes (cwe, c ('A', 'B'))
    checkEquals (getSelectedNodeCount (cwe), 2)

    deleteSelectedNodes(cwe)
    checkEquals(getNodeCount(cwe), 1)
    invisible (cwe)

} # test.invertNodeSelection
#------------------------------------------------------------------------------------------------------------------------
test.hideNodes = function ()
{
    title = 'test.hideNodes'
    window.prep (title)

    cwe = CytoscapeWindow (title, graph=RCy3::makeSimpleGraph ())
    displayGraph (cwe)
    layoutNetwork (cwe, 'grid')
    redraw (cwe)

    clearSelection (cwe)
    checkEquals (getSelectedNodeCount (cwe), 0)
    cwe.nodes = selectNodes (cwe, c ('A', 'B'))
    checkEquals (getSelectedNodeCount (cwe), 2)
    checkEquals (getNodeCount (cwe), 3)
    hideSelectedNodes (cwe)
    checkEquals (getNodeCount (cwe), 3)
    unhideAll (cwe)
    layoutNetwork (cwe)
    redraw (cwe)
    checkEquals (getNodeCount (cwe), 3)

    invisible (cwe)

} # test.hideNodes
#------------------------------------------------------------------------------------------------------------------------
test.selectEdges = function ()
{
    title = 'test.selectEdges'
    window.prep (title)

    cw = CytoscapeWindow (title, graph=RCy3::makeSimpleGraph ())
    displayGraph (cw)
    layoutNetwork (cw, 'grid')
    redraw (cw)

    clearSelection (cw)
    checkEquals (getSelectedEdgeCount (cw), 0)
    selectEdges (cw, "A (phosphorylates) B")
    checkEquals (getSelectedEdgeCount (cw), 1)
    Sys.sleep (0.3)
    clearSelection (cw)
    checkEquals (getSelectedEdgeCount (cw), 0)

    invisible (cw)

} # test.selectEdges
#------------------------------------------------------------------------------------------------------------------------
test.getAdjacentEdgeNames = function ()
{
    title = 'test.getAdjacentEdgeNames'
    g = RCy3::makeSimpleGraph ()
    expected.names = c ("A (phosphorylates) B", "B (synthetic lethal) C", "C (undefined) A")
    checkEquals (sort (as.character (cy2.edge.names (g))), expected.names)

    checkEquals (sort (getAdjacentEdgeNames (g, 'A')), expected.names [c (1,3)])
    checkEquals (sort (getAdjacentEdgeNames (g, 'B')), expected.names [c (1,2)])
    checkEquals (sort (getAdjacentEdgeNames (g, 'C')), expected.names [c (2,3)])

    checkEquals (sort (getAdjacentEdgeNames (g, c ('A', 'B'))), expected.names [1:3])
    checkEquals (sort (getAdjacentEdgeNames (g, c ('B', 'C'))), expected.names [1:3])
    checkEquals (sort (getAdjacentEdgeNames (g, c ('A', 'C'))), expected.names [1:3])
    invisible (g)

} # test.getAdjacentEdgeNames
#------------------------------------------------------------------------------------------------------------------------
test.setEdgeLineStyleRule = function ()
{
    title = 'test.setEdgeLineStyleRule'
    window.prep (title)

    cwe = CytoscapeWindow (title, graph=RCy3::makeSimpleGraph ())
    displayGraph (cwe)
    layoutNetwork (cwe, 'grid')
    redraw (cwe)


    line.styles = c ('SINEWAVE', 'DOT', 'PARALLEL_LINES')
    edgeType.values = c ('phosphorylates', 'synthetic lethal', 'undefined')
    checkEquals (length (intersect (line.styles, getLineStyles (cwe))), 3)

    setEdgeLineStyleRule (cwe, 'edgeType', edgeType.values, line.styles)

    # test one-element lists
    line.styles = c ('DOT')
    edgeType.values = c ('synthetic lethal')
    checkEquals (length (intersect (line.styles, getLineStyles (cwe))), 1)
    setEdgeLineStyleRule (cwe, 'edgeType', edgeType.values, line.styles)

    #msg (cwe, 'test.setEdgeLineStyleRule')

    invisible (cwe)

} # test.setEdgeLineStyleRule
#------------------------------------------------------------------------------------------------------------------------
test.setEdgeLineWidthRule = function ()
{
    title = 'test.setEdgeLineWidthRule'
    window.prep (title)

    cwe = CytoscapeWindow (title, graph=RCy3::makeSimpleGraph ())
    displayGraph (cwe)
    layoutNetwork (cwe, 'grid')
    redraw (cwe)

    line.styles = c ('SINEWAVE', 'DOT', 'PARALLEL_LINES')
    edgeType.values = c ('phosphorylates', 'synthetic lethal', 'undefined')
    checkEquals (length (intersect (line.styles, getLineStyles (cwe))), 3)

    setEdgeLineStyleRule (cwe, 'edgeType', edgeType.values, line.styles)
    setEdgeLineWidthRule (cwe, 'edgeType', edgeType.values, c (0, 8, 16))

    # try one-element lists
    setEdgeLineWidthRule (cwe, 'edgeType', edgeType.values [1], 10)

    invisible (cwe)

} # test.setEdgeLineWidthRule
#------------------------------------------------------------------------------------------------------------------------
test.setEdgeColorRule = function ()
{
    title = 'test.setEdgeColorRule'
    window.prep (title)

    cwe = CytoscapeWindow (title, graph=RCy3::makeSimpleGraph ())
    displayGraph (cwe)
    layoutNetwork (cwe, 'grid')
    redraw (cwe)

    edgeType.values = c ('phosphorylates', 'synthetic lethal', 'undefined')
    colors = c ('#FF0000', '#FFFF00', '#00FF00')
    setEdgeColorRule (cwe, 'edgeType',  edgeType.values, colors, mode='lookup')
    Sys.sleep (0.3)

    all.white  = c ('#FFFFFF', '#FFFFFF', '#FFFFFF')
    setEdgeColorRule (cwe, 'edgeType',  edgeType.values [2], mode='lookup', '#000000')

    # now create a continuous ('interpolate') mode rule, using the score edge attribute
    score.values = c (-15, 0, 40);
    colors = c ('#00FF00', '#FFFFFF', '#FF0000')
    setEdgeColorRule (cwe, 'score',  score.values, colors, mode='interpolate')

    # now swap the colors
    colors = c ('#FF0000', '#000000', '#00FF00')
    setEdgeColorRule (cwe, 'score',  score.values, colors, mode='interpolate')

    invisible (cwe)

} # test.setEdgeColorRule
#------------------------------------------------------------------------------------------------------------------------
test.setEdgeOpacityRule = function ()
{
    title = 'test.setEdgeOpacityRule'
    window.prep (title)

    cw = CytoscapeWindow (title, graph=RCy3::makeSimpleGraph ())
    displayGraph (cw)
    layoutNetwork (cw, 'grid')

    edgeType.values = c ("phosphorylates", "synthetic lethal", "undefined")

    # want to see edges and both arrows, to check success of opacity rule
    setEdgeTargetArrowRule (cw, 'edgeType', edgeType.values, rep ('ARROW', 3))
    setEdgeSourceArrowRule (cw, 'edgeType', edgeType.values, rep ('ARROW', 3))
    setDefaultEdgeLineWidth (cw, 5)

    redraw (cw)

    # do the lookup rule
    opacities = c (25, 100, 255)
    setEdgeOpacityRule (cw, 'edgeType',  edgeType.values, opacities, mode='lookup')
    redraw (cw)

    # now do the interpolated version
    opacities = c (10, 125, 255)
    control.points = c (-12, 0, 35)
    setEdgeOpacityRule (cw, 'score',  control.points, opacities, mode='interpolate')
    redraw (cw)

    invisible (cw)

} # test.setEdgeOpacityRule
#------------------------------------------------------------------------------------------------------------------------
test.setEdgeTargetArrowRule = function ()
{
    title = 'test.setEdgeTargetArrowRule'
    window.prep (title)

    cwe = CytoscapeWindow (title, graph=RCy3::makeSimpleGraph ())
    displayGraph (cwe)
    layoutNetwork (cwe, 'grid')
    redraw (cwe)

    arrows = c ('DELTA', 'T', 'DIAMOND')
    edgeType.values = c ('phosphorylates', 'synthetic lethal', 'undefined')
    checkEquals (length (intersect (arrows, getArrowShapes (cwe))), 3)

    setEdgeTargetArrowRule (cwe, 'edgeType', edgeType.values, arrows)

    # now test the list-of-length-one call.  the called method will double the list to get past the xmlrpc
    # treatment of lists of length one as scalars, and a failed signature match
    arrows = c ('CIRCLE')
    edgeType.values = c ('phosphorylates')
    checkEquals (length (intersect (arrows, getArrowShapes (cwe))), 1)

    setEdgeTargetArrowRule (cwe, 'edgeType', edgeType.values, arrows)

    invisible (cwe)

} # test.setEdgeTargetArrowRule
#------------------------------------------------------------------------------------------------------------------------
test.setEdgeArrowColorRules = function ()
{
    title = 'test.setEdgeArrowColorRules'
    window.prep (title)

    cwe = CytoscapeWindow (title, graph=RCy3::makeSimpleGraph ())
    displayGraph (cwe)
    layoutNetwork (cwe, 'grid')
    redraw (cwe)

    colors.1 = c ("#FFFFFF", "#FFFFFF", "#FFFFFF")
    colors.2 = c ("#AA00AA", "#AAAA00", "#AA0000")

    setEdgeTargetArrowColorRule (cwe, 'edgeType', c ("phosphorylates", "synthetic lethal", "undefined"), colors.1)
    setEdgeSourceArrowColorRule (cwe, 'edgeType', c ("phosphorylates", "synthetic lethal", "undefined"), colors.1)
    system ('sleep 0.3')
    setEdgeTargetArrowColorRule (cwe, 'edgeType', c ("phosphorylates", "synthetic lethal", "undefined"), colors.2)
    setEdgeSourceArrowColorRule (cwe, 'edgeType', c ("phosphorylates", "synthetic lethal", "undefined"), colors.2)

    # test one-element list
    setEdgeSourceArrowColorRule (cwe, 'edgeType', "phosphorylates", '#000000')

    invisible (cwe)

} # test.setEdgetArrowColorRules
#------------------------------------------------------------------------------------------------------------------------
test.setEdgeSourceArrowRule = function ()
{
    title = 'test.setEdgeSourceArrowRule'
    window.prep (title)

    cwe = CytoscapeWindow (title, graph=RCy3::makeSimpleGraph ())
    displayGraph (cwe)
    layoutNetwork (cwe, 'grid')
    redraw (cwe)

    arrows = c ('ARROW', 'DIAMOND', 'CIRCLE')
    edgeType.values = c ('phosphorylates', 'synthetic lethal', 'undefined')
    checkEquals (length (intersect (arrows, getArrowShapes (cwe))), 3)

    setEdgeSourceArrowRule (cwe, 'edgeType', edgeType.values, arrows)

    # test one-element rule
    setEdgeSourceArrowRule (cwe, 'edgeType', edgeType.values [2], arrows [2])

    invisible (cwe)

} # test.setEdgeSourceArrowRule
#------------------------------------------------------------------------------------------------------------------------
test.movie = function ()
{
    title = 'test.movie'
    window.prep (title)

    cwe = CytoscapeWindow (title, graph=RCy3::makeSimpleGraph ())
    displayGraph (cwe)
    layoutNetwork (cwe, 'grid')
    redraw (cwe)

    # establish the rules which apply during the full run of the movie
    # different node sizes and node colors are created, not by changing these rules, but
    # by changing node attribute values, for the integer attribute 'count' and the numeric attribute 'lfc'
    count.control.points = c (2, 30, 100)
    sizes                = c (20, 50, 100)
    setNodeSizeRule (cwe, 'count', count.control.points, sizes, mode='interpolate')
    setNodeColorRule (cwe, 'lfc', c (-3.0, 0.0, 3.0), c ('#00FF00', '#FFFFFF', '#FF0000'), mode='interpolate')

    count = 3

    # three renderings of the 3-node, 3-edge network are created in this loop, which runs 'count' times
    # the first two set new attributes on the R graph data structure, then ask RCy3 to send those values
    # to R from the graph
    # the third rendering bypasses storage of new attribute values on the R graph, sending them instead
    # directly to Cytoscape.  (hence 'setNodeAttributesDirect')

    for (i in 1:count) {
        nodeData (cwe@graph, 'A', 'lfc') = -3.0
        nodeData (cwe@graph, 'B', 'lfc') = -0.7
        nodeData (cwe@graph, 'C', 'lfc') = -1.9
        nodeData (cwe@graph, 'A', 'count') = 10
        nodeData (cwe@graph, 'B', 'count') = 140
        nodeData (cwe@graph, 'C', 'count') = 32
        result = setNodeAttributes (cwe, 'lfc')
        result = setNodeAttributes (cwe, 'count')
        redraw (cwe)

        Sys.sleep (0.3)
        nodeData (cwe@graph, 'A', 'lfc') = 3.0
        nodeData (cwe@graph, 'B', 'lfc') = 0.7
        nodeData (cwe@graph, 'C', 'lfc') = 1.9
        nodeData (cwe@graph, 'A', 'count') = 50
        nodeData (cwe@graph, 'B', 'count') = 22
        nodeData (cwe@graph, 'C', 'count') = 180
        result = setNodeAttributes (cwe, 'lfc')
        result = setNodeAttributes (cwe, 'count')
        redraw (cwe)
        Sys.sleep (0.3)

        count.A = round (runif (1, 1, 200))
        count.B = round (runif (1, 1, 200))
        count.C = round (runif (1, 1, 200))

        result = setNodeAttributesDirect (cwe, 'count', 'int', c ('A', 'B', 'C'), c (count.A, count.B, count.C));
        result = setNodeAttributesDirect (cwe, 'lfc', 'numeric', c ('A', 'B', 'C'), c (-1.0, 0.0, 1.0))
        redraw (cwe)
    }

    invisible (cwe)

} # test.movie
#------------------------------------------------------------------------------------------------------------------------
# test.unmatchedAttributesError = function ()
# {
#     title = 'test.unmatchedAttributesError'
#     window.prep (title)
#
#     cwe = CytoscapeWindow (title, RCy3::makeSimpleGraph ())
#     displayGraph (cwe)
#     layoutNetwork (cwe, 'grid')
#
#     # this works
#     count.control.points = c (2, 30, 100)
#     sizes = c (20, 50, 100)
#     setNodeSizeRule (cwe, 'count', count.control.points, sizes, mode='interpolate')
#
#     invisible (cwe)
#
# } # test.unmatchedAttributesError
#------------------------------------------------------------------------------------------------------------------------
#RCy3:::makeRandomGraph ()
#------------------------------------------------------------------------------------------------------------------------
# this tests the otherwise invisible method in RCy3.R, called to compensate for the extra edges and edge attributes
# packed into an undirected graph
#------------------------------------------------------------------------------------------------------------------------
test.randomUndirectedGraph = function ()
{
    title = 'test.randomUndirectedGraph'
    window.prep (title)

    g.random = RCy3::makeRandomGraph ()
    edgeData (g.random, '1', '2', 'weight') = 0.55
    edgeData (g.random, '1', '2', 'pmid') = '12345678'

    cwr = CytoscapeWindow (title, g.random)
    displayGraph (cwr)
    layoutNetwork (cwr, 'grid')
    redraw (cwr)

    invisible (cwr)

} # test.randomUndirectedGraph
#------------------------------------------------------------------------------------------------------------------------
test.simpleGraph = function (apply.viz.rules=TRUE, do.redraw=TRUE)
{
    title = 'test.simpleGraph'
    window.prep (title)

    g.simple = RCy3::makeSimpleGraph ()
    cws = CytoscapeWindow (title, g.simple)

    displayGraph (cws)
    layoutNetwork (cws, 'grid')

    if (apply.viz.rules) {
        setNodeLabelRule (cws, 'label')
        setDefaultNodeBorderWidth (cws, 5)
        node.attribute.values = c ("kinase",  "transcription factor")
        colors =                c ('#A0AA00', '#FF0000')
        setNodeBorderColorRule (cws, 'type', node.attribute.values, colors, mode='lookup', default.color='#88FF22')
        count.control.points = c (2, 30, 100)
        sizes                = c (20, 50, 100)
        setNodeSizeRule (cws, 'count', count.control.points, sizes, mode='interpolate')
        setNodeColorRule (cws, 'lfc', c (-3.0, 0.0, 3.0), c ('#00FF00', '#FFFFFF', '#FF0000'), mode='interpolate')
        redraw (cws)
    } # if apply.viz.rules


    invisible (cws)

} # test.simpleGraph
#------------------------------------------------------------------------------------------------------------------------
test.simpleGraphWithReciprocalEdge = function ()
{
    title = 'test.simpleGraphWithReciprocalEdge'
    window.prep (title)

    g.simple = RCy3::makeSimpleGraph ()
    g.simple = graph::addEdge ('C', 'B', g.simple)
    edgeData (g.simple, 'C', 'B', attr='edgeType') = 'synthetic rescue'
    edgeData (g.simple, 'C', 'B', attr='score') = 42
    edgeData (g.simple, 'C', 'B', attr='misc') = 'ellany'
    g <- g.simple

    cws = CytoscapeWindow (title, g.simple)

    displayGraph (cws)
    layoutNetwork (cws, 'grid')
    setNodeLabelRule (cws, 'label')
    node.attribute.values = c ("kinase",  "transcription factor")
    colors =                c ('#A0AA00', '#FF0000')
    setDefaultNodeBorderWidth (cws, 5)
    setNodeBorderColorRule (cws, 'type', node.attribute.values, colors, mode='lookup', default.color='#88FF22')
    count.control.points = c (2, 30, 100)
    sizes                = c (20, 50, 100)
    setNodeSizeRule (cws, 'count', count.control.points, sizes, mode='interpolate')
    setNodeColorRule (cws, 'lfc', c (-3.0, 0.0, 3.0), c ('#00FF00', '#FFFFFF', '#FF0000'), mode='interpolate')
    arrows = c ('Arrow', 'Arrow', 'Arrow', 'None')
    edgeType.values <- c ('phosphorylates', 'synthetic lethal', 'synthetic rescue', 'undefined')
    setEdgeTargetArrowRule (cws, 'edgeType', edgeType.values, arrows)

    edgeType.values = c ('phosphorylates', 'synthetic lethal', 'synthetic rescue', 'undefined')
    edgeColors = c ('#0000AA', '#000000', '#00AA00', '#FFFFFF')
    setEdgeColorRule (cws, 'edgeType',  edgeType.values, edgeColors, mode='lookup')

    redraw (cws)

    invisible (cws)

} # test.simpleGraphWithReciprocalEdge
#------------------------------------------------------------------------------------------------------------------------
test.setGraph = function ()
{
    title = 'test.setGraph'
    window.prep (title)

    cw = CytoscapeWindow (title)
    checkEquals (length (nodes (getGraph (cw))), 0)
    new.graph = RCy3::makeSimpleGraph ()
    cw = setGraph (cw, new.graph)
    checkEquals (length (nodes (getGraph (cw))), 3)

    invisible (cw)

} # test.setGraph
#------------------------------------------------------------------------------------------------------------------------
test.setNodePosition = function ()
{
    #DEACTIVATED("too slow")
    title = 'test.setNodePosition'
    window.prep (title)

    cwe = CytoscapeWindow (title, graph=RCy3::makeSimpleGraph ())
    displayGraph (cwe)
    layoutNetwork (cwe, 'grid')
    redraw (cwe)

    layoutNetwork (cwe, 'grid')   # get a reasonable starting layout, with the nodes well-separate

    center.x = 200
    center.y = 200
    radius = 200
    angles = seq (0, 360, 5)  # sweep through full revoltion, 5 degrees at a time
    # move just the A node, swinging it around the 'center' at 200, 200.
    # it would be nice not know more about the coordinate system than I now do, perhaps to
    # query current position on any node
    for (angle in angles) {
        angle.in.radians = angle * pi / 180
        x = center.x + (radius * cos (angle.in.radians))
        y = center.y + (radius * sin (angle.in.radians))
        setNodePosition (cwe, 'A', x, y)
    }

    invisible (cwe)

} # test.setNodePosition
#------------------------------------------------------------------------------------------------------------------------
test.getNodePosition = function ()
{
    title = 'test.getNodePosition'
    window.prep (title)

    cwe = CytoscapeWindow (title, graph=RCy3::makeSimpleGraph ())
    displayGraph (cwe)
    layoutNetwork (cwe, 'grid')
    redraw (cwe)

    layoutNetwork (cwe, 'grid')   # get a reasonable starting layout, with the nodes well-separate

    # the scheme:  get current positions, find their mean, place all the nodes there,
    # get their new positions, check to see that they are the means just set.

    positions <- RCy3::getNodePosition (cwe, c ('A', 'B', 'C'))

    # place the nodes on top of each other, at the center of their 3-cornered original layout
    center.x = as.integer (round (mean (as.integer (sapply (positions, function (pos) pos$x)))))
    center.y = as.integer (round (mean (as.integer (sapply (positions, function (pos) pos$y)))))

    setNodePosition (cwe, c ('A', 'B', 'C'), rep (center.x, 3), rep (center.y, 3))
    current.x = RCy3::getNodePosition (cwe, 'A')[[1]]$x
    current.y = RCy3::getNodePosition (cwe, 'A')[[1]]$y
    #printf ('center:  %d  %d', center.x, center.y)
    #printf ('current: %d  %d', current.x, current.y)

    checkEqualsNumeric (current.x, center.x, tol=1)
    checkEqualsNumeric (current.y, center.y, tol=1)

    invisible (cwe)

} # test.getNodePosition
#------------------------------------------------------------------------------------------------------------------------
test.getNodePosition.colonInNodeName = function ()
{
    #DEACTIVATED("not fatally slow, but i am impatient. Reactivate later.")
    title = 'test.getNodePosition.colonInNodeName'
    window.prep (title)

    g = RCy3::makeSimpleGraph ()
    funky.node.name = 'ab::cdxyz::1234,funky!?' 
    g = graph::addNode (funky.node.name, g)
    nodeData (g, funky.node.name, 'label') = funky.node.name

    cwe = CytoscapeWindow (title, graph=g)
    displayGraph (cwe)
    layoutNetwork (cwe, 'grid')
    redraw (cwe)

    layoutNetwork (cwe, 'grid')   # get a reasonable starting layout, with the nodes well-separate

    # the scheme:  get current positions, find their mean, place all the nodes there,
    # get their new positions, check to see that they are the means just set.

    positions <- RCy3::getNodePosition (cwe, c ('A', 'B', 'C'))

    # place the nodes on top of each other, at the center of their 3-cornered original layout

    center.x = as.integer (round (mean (as.integer (sapply (positions, function (pos) pos$x)))))
    center.y = as.integer (round (mean (as.integer (sapply (positions, function (pos) pos$y)))))

    # rearrange the positions
    layoutNetwork (cwe, 'grid')

    # superimpose A,B, and C  in the center
    setNodePosition (cwe, c ('A', 'B', 'C'), rep (center.x, 3), rep (center.y, 3))
    x.funky = center.x + 50
    y.funky = center.y + 50
    # offset funky.node.name
    setNodePosition (cwe, funky.node.name, x.funky, y.funky)
    fitContent (cwe)
    setZoom (cwe, 0.75 * getZoom (cwe))

    # now check that the nodes have been repositioned from grid to centered (A,B,C) and offset (funky.node.name)
    current.x = RCy3::getNodePosition (cwe, 'A')[[1]]$x
    current.y = RCy3::getNodePosition (cwe, 'A')[[1]]$y

    checkEqualsNumeric (current.x, center.x, tol=1)
    checkEqualsNumeric (current.y, center.y, tol=1)

    funky.pos.x = RCy3::getNodePosition (cwe, funky.node.name) [[1]]$x
    funky.pos.y = RCy3::getNodePosition (cwe, funky.node.name) [[1]]$y
    checkEqualsNumeric (funky.pos.x, x.funky, tol=1)
    checkEqualsNumeric (funky.pos.y, y.funky, tol=1)

    invisible (cwe)

} # test.getNodePosition.colonInNodeName
#------------------------------------------------------------------------------------------------------------------------
test.getNodeSize = function ()
{
    title = 'test.getNodeSize'
    window.prep (title)

    cw = CytoscapeWindow (title, graph=RCy3::makeSimpleGraph ())
    displayGraph (cw)
    layoutNetwork (cw, 'grid')

    # establish a good starting point
    setNodeSizeDirect (cw, nodes (cw@graph), rep (100, 3))
    redraw (cw)

    sizes =  getNodeSize (cw, nodes (cw@graph))
    # these next test pass fine in uncomplicated circumstances, but (apparently) fail due to
    # vizmap complexities when lots of windows are or have been open
    #checkEquals (sizes$width, c (100, 100, 100))
    #checkEquals (sizes$height, c (100, 100, 100))

    setNodeSizeDirect (cw, c ('A', 'B'), 150); redraw (cw)
    sizes =  getNodeSize (cw, nodes (cw@graph))

    # these next test pass fine in uncomplicated circumstances, but (apparently) fail due to
    # vizmap complexities when lots of windows are or have been open
    #checkEquals (sizes$width, c (150, 150, 100))
    #checkEquals (sizes$height, c (150, 150, 100))

    setNodeSizeDirect (cw, c ('A', 'B'), c (180, 32));   redraw (cw)

    sizes = getNodeSize (cw, nodes (cw@graph))
    #checkEquals (sizes$width, c (180, 32, 100))
    #checkEquals (sizes$height, c (180, 32, 100))

    # now allow for non-symmetric dimensions, in which width and height are set separately
    lockNodeDimensions (cw, FALSE)
    setNodeHeightDirect (cw, c ('A', 'B', 'C'), c (12, 22, 32))
    setNodeWidthDirect (cw, c ('A', 'B', 'C'), c (120, 122, 132))
    redraw (cw)

    sizes = getNodeSize (cw, 'B')
    #checkEquals (sizes$width, 122)
    #checkEquals (sizes$height, 22)

    # return to symmetric dimensions
    lockNodeDimensions (cw, TRUE)
    redraw (cw)

    # not sure how width and height are rectified.  it appears that the last-used width=height values are returned
    sizes = getNodeSize (cw, nodes (cw@graph))
    #checkEquals (sizes$width, sizes$height)

    invisible (cw)

} # test.getNodeSize
#------------------------------------------------------------------------------------------------------------------------
test.haveNodeAttribute = function ()
{
    title = 'test.haveNodeAttribute'
    window.prep (title)

    cw3 = CytoscapeWindow (title, graph=makeSimpleGraph ())
    displayGraph (cw3)
    redraw (cw3)
    layoutNetwork (cw3)

    nodes.with.attribute = RCy3:::haveNodeAttribute (cw3, nodes (getGraph (cw3)), 'lfc')
    checkEquals (sort (nodes.with.attribute),  c ('A', 'B', 'C'))

    checkEquals (length (RCy3:::haveNodeAttribute (cw3, nodes (getGraph (cw3)), 'type')), 3)
    checkEquals (length (RCy3:::haveNodeAttribute (cw3, nodes (getGraph (cw3)), 'label')), 3)
    checkEquals (length (RCy3:::haveNodeAttribute (cw3, nodes (getGraph (cw3)), 'count')), 3)

    checkEquals (length (RCy3:::haveNodeAttribute (cw3, nodes (getGraph (cw3)), 'bogus')), 0)

    invisible (cw3)

} # test.haveNodeAttribute
#------------------------------------------------------------------------------------------------------------------------
test.haveEdgeAttribute = function ()
{
    title = 'test.haveEdgeAttribute'
    window.prep (title)

    cw3 = CytoscapeWindow (title, graph=makeSimpleGraph ())
    displayGraph (cw3)
    redraw (cw3)
    layoutNetwork (cw3)

    cy2.edgenames = as.character (cy2.edge.names (getGraph (cw3)))
    edges.with.attribute = RCy3:::haveEdgeAttribute (cw3, cy2.edgenames, 'edgeType')

    checkEquals (length (edges.with.attribute), 3)
    checkTrue ("A (phosphorylates) B" %in% edges.with.attribute)
    checkTrue ("B (synthetic lethal) C" %in% edges.with.attribute)
    checkTrue ("C (undefined) A" %in% edges.with.attribute)

    checkTrue (length (RCy3:::haveEdgeAttribute (cw3, cy2.edgenames, 'score')) == 3)
    checkTrue (length (RCy3:::haveEdgeAttribute (cw3, cy2.edgenames, 'misc')) == 3)
    checkTrue (length (RCy3:::haveEdgeAttribute (cw3, cy2.edgenames, 'bogus')) == 0)

} # test.haveEdgeAttribute
#------------------------------------------------------------------------------------------------------------------------
hiddenTest.haveEdgeAttribute.oneEdgeOnly = function ()
{
    title = 'test.haveEdgeAttribute.oneEdgeOnly'
    window.prep (title)

    g = makeSimpleGraph ()
    g = removeNode ('A', g)
    cw = CytoscapeWindow (title, graph=g)
    displayGraph (cw)
    redraw (cw)
    layoutNetwork (cw)

    cy = CytoscapeConnection ()

    cy2.edgenames = as.character (cy2.edge.names (getGraph (cw)))

    checkTrue (length (RCy3:::haveEdgeAttribute (cw, cy2.edgenames, 'score')) == 1)

} # hiddenTest.haveEdgeAttribute.oneEdgeOnly
#------------------------------------------------------------------------------------------------------------------------
test.copyNodeAttributesFromCyGraph = function ()
{
    title = 'test.copyNodeAttributesFromCyGraph'
    window.prep (title)

    cw3 = CytoscapeWindow (title, graph=makeSimpleGraph ())
    displayGraph (cw3)
    redraw (cw3)
    layoutNetwork (cw3)

    # we can now depend upon Cytoscape holding its own version of cw3@graph
    # in expected use, we expect that 'getGraphFromWindow' will be called, to get the nodes, edges, and both
    # node & edge attributes
    # but here, we only want to test the reliability of querying the Cytoscape version of the graph for all of its node
    # attributes. So we build a 3-node graph, *without* attributes, and pass that to copyNodeAttributesFromCyGraph,
    # which should copy those Cytoscape graph node attributes onto the graph we pass in.
    g = new ('graphNEL', edgemode='directed')
    g = graph::addNode (c ('A', 'B', 'C'), g)

    g2 = RCy3:::copyNodeAttributesFromCyGraph (cw3, getWindowID (cy, title), g)
    checkEquals (length (intersect (noa.names (g2), c ("name", "count", "label", "lfc", "type"))), 5)
    checkEquals (as.character (nodeData (g2, c ('A', 'B', 'C'), attr='name')), c ('A', 'B', 'C'))
    checkEquals (as.integer (nodeData (g2, c ('A', 'B', 'C'), attr='count')), c (2, 30, 100))
    checkEquals (as.numeric (nodeData (g2, c ('A', 'B', 'C'), attr='lfc')), c (-3,  0,  3))
    checkEquals (as.character (nodeData (g2, c ('A', 'B', 'C'), attr='type')), c ("kinase", "transcription factor", "glycoprotein"))

    invisible (cw3)

} # test.copyNodeAttributesFromCyGraph
#------------------------------------------------------------------------------------------------------------------------
test.copyEdgeAttributesFromCyGraph = function ()
{
    title = 'test.copyEdgeAttributesFromCyGraph'
    window.prep (title)

    cw3 = CytoscapeWindow (title, graph=makeSimpleGraph ())
    displayGraph (cw3)
    redraw (cw3)
    layoutNetwork (cw3)

    g = new ('graphNEL', edgemode='directed')
    g = graph::addNode (c ('A', 'B', 'C'), g)
    g = graph::addEdge("A", "B", g)
    g = graph::addEdge("B", "C", g)
    g = graph::addEdge("C", "A", g)
    # "C (undefined) A" "B (synthetic lethal) C"   "A (phosphorylates) B"
    edgeDataDefaults (g, 'edgeType') = 'undefined'
    edgeData (g, 'A', 'B', 'edgeType') = 'phosphorylates'
    edgeData (g, 'B', 'C', 'edgeType') = 'synthetic lethal'
    edgeData (g, 'C', 'A', 'edgeType') = 'undefined'

    cy = CytoscapeConnection ()
    g2 = RCy3:::copyEdgeAttributesFromCyGraph (cw3, cw3, g)

    checkEquals (eda (g2, 'score') [['A|B']], 35)
    checkEquals (eda (g2, 'score') [['B|C']], -12)
    checkEquals (eda (g2, 'score') [['C|A']], 0)

    checkEquals (eda (g2, 'edgeType') [['A|B']], 'phosphorylates')
    checkEquals (eda (g2, 'edgeType') [['B|C']], 'synthetic lethal')
    checkEquals (eda (g2, 'edgeType') [['C|A']], 'undefined')

    checkEquals (eda (g2, 'interaction') [['A|B']], 'phosphorylates')
    checkEquals (eda (g2, 'interaction') [['B|C']], 'synthetic lethal')
    checkEquals (eda (g2, 'interaction') [['C|A']], 'undefined')

    checkEquals (eda (g2, 'misc') [['A|B']], 'default misc')
    checkEquals (eda (g2, 'misc') [['B|C']], 'default misc')
    checkEquals (eda (g2, 'misc') [['C|A']], 'default misc')

    checkEquals (eda (g2, 'name') [['A|B']],  "A (phosphorylates) B")
    checkEquals (eda (g2, 'name') [['B|C']],  "B (synthetic lethal) C")
    checkEquals (eda (g2, 'name') [['C|A']],  "C (undefined) A")

    invisible (g2)

} # test.copyEdgeAttributesFromCyGraph
#------------------------------------------------------------------------------------------------------------------------
test.getGraphFromCyWindow = function ()
{
    cy = CytoscapeConnection ()

    title = 'test.getGraphFromCyWindow'
    window.prep (title)

    cw3 = CytoscapeWindow (title, graph=makeSimpleGraph ())
    displayGraph (cw3)
    redraw (cw3)
    layoutNetwork (cw3)

    g3 = getGraphFromCyWindow (cy, 'test.getGraphFromCyWindow')
    checkEquals (sort (nodes (g3)), c ('A', 'B', 'C'))
    checkEquals (length (intersect (noa.names (g3), c ("name", "count", "label", "lfc", "type"))), 5)
    checkEquals (as.character (sort (noa (g3, 'name'))), c ('A', 'B', 'C'))
    checkEquals (as.integer   (sort (noa (g3, 'count'))),         c (2, 30, 100))
    checkEquals (as.character (sort (noa (g3, 'label'))),         c ('Gene A', 'Gene B', 'Gene C'))
    checkEquals (as.numeric (sort (noa (g3, 'lfc'))),             c (-3,  0,  3))
    checkEquals (as.character (sort (noa (g3, 'type'))),          c ("glycoprotein", "kinase", "transcription factor"))

    checkEquals (length (intersect (eda.names (g3), c ("name", "edgeType", "interaction", "misc", "score"))), 5)

    checkEquals (sort (names (cy2.edge.names (g3))),        c ('A~B',                   'B~C',                    'C~A'))
    checkEquals (sort (as.character (cy2.edge.names (g3))), c ("A (phosphorylates) B",  "B (synthetic lethal) C", "C (undefined) A"))

    checkEquals (as.character (sort (eda (g3, 'edgeType'))), c ("phosphorylates", "synthetic lethal", "undefined"))
    checkEquals (as.character (sort (eda (g3, 'name'))), c ("A (phosphorylates) B", "B (synthetic lethal) C", "C (undefined) A"))
    checkEquals (as.character (sort (eda (g3, 'interaction'))), c ("phosphorylates", "synthetic lethal", "undefined"))
    checkEquals (as.character (sort (eda (g3, 'misc'))), c ("default misc", "default misc", "default misc"))
    checkEquals (as.numeric (sort (eda (g3, 'score'))), c (-12,  0,  35))

    invisible (g3)

} # test.getGraphFromCyWindow
#------------------------------------------------------------------------------------------------------------------------
# try graphs with no edges, then one with neither nodes nor edges
# todo:  try single node, and single edge graphs.
test.sendDegenerateGraphs = function ()
{
    title = 'test.sendDegenerateGraphs'
    window.prep (title)

    g.no.edges <- new ('graphNEL')
    g.no.edges <- graph::addNode (c ('A', 'B'), g.no.edges)
    cw.degen <- CytoscapeWindow (title, g.no.edges)
    displayGraph (cw.degen)
    redraw (cw.degen)
    layoutNetwork (cw.degen, 'grid')

    title = 'test.sendEmptyGraph'
    window.prep (title)

    g.empty <- new ('graphNEL')
    cw.empty <- CytoscapeWindow (title, g.empty)
    displayGraph (cw.empty)
    redraw (cw.empty)
    layoutNetwork (cw.empty, 'grid')

    invisible (cw.empty)

} # test.sendDegenerateGraphs
#------------------------------------------------------------------------------------------------------------------------
test.createWindowFromSelection = function ()
{
    title = 'test.createWindowFromSelection'
    window.prep (title)
    cy = CytoscapeConnection ()

    cw =  CytoscapeWindow (title, makeSimpleGraph ())
    displayGraph (cw)
    redraw (cw)
    layoutNetwork (cw)
    selectNodes (cw, c ('A', 'C'))

    new.window.title = 'NEW'
    if (new.window.title %in% as.character (getWindowList (cy))){
        deleteWindow (cy, new.window.title)
    }

    c2 = createWindowFromSelection (cw, new.window.title, TRUE)
    redraw (c2)
    layoutNetwork (c2)

    clearSelection (c2)
    selectNodes (c2, 'C')
#     checkEquals (getSelectedNodeCount (c2), 1)
#
#     new.window.title = 'NEW, just 1 node'
#     if (new.window.title %in% as.character (getWindowList (cy))){
#         deleteWindow (cy, new.window.title)
#     }
#
#     c3 = createWindowFromSelection (c2, new.window.title, T)
#     redraw (c3)
#     layoutNetwork (c3)
#
#    invisible (list (cw=cw, c2=c2, c3=c3))

} # test.createWindowFromSelection
#------------------------------------------------------------------------------------------------------------------------
test.addGraphToGraph = function ()
{
    title = 'test.addGraphToGraph'
    window.prep (title)

    cw3 <- CytoscapeWindow (title, graph=makeSimpleGraph ())
    displayGraph (cw3)
    redraw (cw3)
    layoutNetwork (cw3)

    g2 <- new("graphNEL", edgemode = "directed")
    g2 <- graph::addNode ('A', g2)
    g2 <- graph::addNode ('B', g2)
    g2 <- graph::addNode ('D', g2)
    g2 <- graph::addNode ('E', g2)

    g2 <- initNodeAttribute (g2, "label", "char", "default node label")
    g2 <- initNodeAttribute (g2, "type", "char", "unspecified type")

    g2 <- initNodeAttribute (g2, "SCORE", "numeric", 0.0)

    g2 <- initEdgeAttribute (g2, "edgeType", "char", "unspecified")
    g2 <- initEdgeAttribute (g2, "probability", "numeric", 0.0)

    nodeData (g2, 'D', 'label') <- 'Gene D'
    nodeData (g2, 'E', 'label') <- 'Gene E'
    nodeData (g2, 'D', 'type') <- 'new and novel'
    nodeData (g2, 'E', 'type') <- 'new and credible'

    nodeData (g2, 'D', 'SCORE') <- 1001.01
    nodeData (g2, 'E', 'SCORE') <- 99.09

    g2 <- graph::addEdge ('D', 'E', g2)
    g2 <- graph::addEdge ('A', 'E', g2)
    g2 <- graph::addEdge ('A', 'B', g2)

    edgeData (g2, 'D', 'E', 'probability') <- 0.95
    edgeData (g2, 'D', 'E', 'edgeType') <- 'literature'
    edgeData (g2, 'A', 'E', 'edgeType') <- 'inferred'

    addGraphToGraph (cw3, g2)
    redraw (cw3)
    layoutNetwork (cw3)

    # now copy the combined graph back to R, check it for consistency
    cw.copy <- existing.CytoscapeWindow ('test.addGraphToGraph', copy=T)

    # first, simple node and edge names
    checkEquals (sort (nodes (cw.copy@graph)), c ('A', 'B', 'C', 'D', 'E'))
    checkEquals (sort (edgeNames (cw.copy@graph)), c ("A~B", "A~E", "B~C", "C~A", "D~E"))

    # are all the expected node and edge attributes present?
    checkEquals (length (intersect (noa.names (cw.copy@graph), c ("name", "count", "label", "lfc", "SCORE", "type"))), 6)

    # edge attributes
    checkEquals (length (intersect (eda.names (cw.copy@graph), c ("name", "edgeType", "interaction", "misc", "probability", "score"))), 6)

    # check the node label attributes
    checkEquals (nodeData (cw.copy@graph, attr='label')$A, 'Gene A')
    checkEquals (nodeData (cw.copy@graph, attr='label')$B, 'Gene B')
    checkEquals (nodeData (cw.copy@graph, attr='label')$C, 'Gene C')
    checkEquals (nodeData (cw.copy@graph, attr='label')$D, 'Gene D')
    checkEquals (nodeData (cw.copy@graph, attr='label')$E, 'Gene E')

    # check the edgeType attributes
    checkEquals (edgeData (cw.copy@graph, 'A', 'B', attr='edgeType')[[1]], 'unspecified')
    checkEquals (edgeData (cw.copy@graph, 'A', 'E', attr='edgeType')[[1]], 'inferred')
    checkEquals (edgeData (cw.copy@graph, 'B', 'C', attr='edgeType')[[1]], 'synthetic lethal')
    checkEquals (edgeData (cw.copy@graph, 'C', 'A', attr='edgeType')[[1]], 'undefined')
    checkEquals (edgeData (cw.copy@graph, 'D', 'E', attr='edgeType')[[1]], 'literature')

    # check the edge probability attributes
    checkEquals (as.numeric (edgeData (cw.copy@graph, 'A', 'B', attr='probability')[[1]]), 0.0)
    checkEquals (as.numeric (edgeData (cw.copy@graph, 'A', 'E', attr='probability')[[1]]), 0.0)
    #checkEquals (as.numeric (edgeData (cw.copy@graph, 'B', 'C', attr='probability')[[1]]), 0.0) #NA is not 0?
    #checkEquals (as.numeric (edgeData (cw.copy@graph, 'C', 'A', attr='probability')[[1]]), 0.0) #NA is not 0?
    checkEquals (as.numeric (edgeData (cw.copy@graph, 'D', 'E', attr='probability')[[1]]), 0.95)

    #checkEquals (as.integer (edgeData (cw.copy@graph, 'A', 'B', attr='score')[[1]]), 0) #NA is not 0?
    #checkEquals (as.integer (edgeData (cw.copy@graph, 'A', 'E', attr='score')[[1]]), 0) #NA is not 0?
    checkEquals (as.integer (edgeData (cw.copy@graph, 'B', 'C', attr='score')[[1]]), -12)
    checkEquals (as.integer (edgeData (cw.copy@graph, 'C', 'A', attr='score')[[1]]), 0)
    #checkEquals (as.integer (edgeData (cw.copy@graph, 'D', 'E', attr='score')[[1]]), 0) #NA is not 0?

    invisible (cw.copy)

} # test.addGraphToGraph
#------------------------------------------------------------------------------------------------------------------------
test.addGraphToGraph.degenerateFirstGraph = function ()
{
    window.title = 'test.addGraphToGraph.degenerateFirstGraph'
    g = new ('graphNEL', edgemode='directed')
    g = graph::addNode ('A', g)
    g = graph::addNode ('E', g)
    g = graph::addNode ('F', g)
    window.prep (window.title)
    cw <- CytoscapeWindow (window.title, graph=g)

    displayGraph (cw)
    redraw (cw)
    layoutNetwork (cw, 'grid')

    g2 <- makeSimpleGraph ()
    addGraphToGraph (cw, g2)

    invisible (cw)

} # test.addGraphToGraph.degenerateFirstGraph
#------------------------------------------------------------------------------------------------------------------------
test.existing.CytoscapeWindow = function ()
{
    title = 'test.existing.CytoscapeWindow'
    window.prep (title)

    #----------------------------------------------------------
    # first, try our standard 3-node, 3-edge testing graph
    #----------------------------------------------------------

    cw <- CytoscapeWindow (title, graph=makeSimpleGraph ())
    displayGraph (cw)
    redraw (cw)
    layoutNetwork (cw)

    cw2 <- existing.CytoscapeWindow (title, copy=TRUE)
    g2 <- cw2@graph
    checkEquals (sort (nodes (g2)), c ('A', 'B', 'C'))
    checkEquals (sort (edgeNames (g2)), c ("A~B", "B~C", "C~A"))

} # test.existingCytoscapeWindow
#------------------------------------------------------------------------------------------------------------------------
test.existing.CytoscapeWindow.noEdges = function ()
{
    window.title = 'test.existing.CytoscapeWindow.noEdges'
    window.prep (window.title)

    g.edgeless = new ('graphNEL', edgemode='directed')
    g.edgeless = graph::addNode ('X', g.edgeless)
    g.edgeless = graph::addNode ('Y', g.edgeless)
    g.edgeless = graph::addNode ('Z', g.edgeless)
    cw.edgeless = CytoscapeWindow (window.title, graph=g.edgeless)
    displayGraph (cw.edgeless)
    redraw (cw.edgeless)
    layoutNetwork (cw.edgeless)

    cw3 = existing.CytoscapeWindow (window.title, copy=TRUE)
    g3 = cw3@graph
    checkEquals (sort (nodes (g3)), c ('X', 'Y', 'Z'))
    checkEquals (length (edgeNames (g3)), 0)

    invisible (cw3)

} # test.existingCytoscapeWindow.noEdges
#------------------------------------------------------------------------------------------------------------------------
test.existing.CytoscapeWindow.emptyGraph = function ()
{
    window.title = 'test.existing.CytoscapeWindow.emptyGraph'
    window.prep (window.title)
    cw.empty = CytoscapeWindow (window.title)
    checkEquals (length (nodes (cw.empty@graph)), 0)
    displayGraph (cw.empty)
    redraw (cw.empty)
    layoutNetwork (cw.empty)

    cw3 <- existing.CytoscapeWindow (window.title, copy=TRUE)
    g3 <- cw3@graph
    checkEquals (length (nodes (g3)), 0)
    checkEquals (length (edges(g3)), 0)

} # test.existingCytoscapeWindow.emptyGraph
#------------------------------------------------------------------------------------------------------------------------
test.addGetAndDeleteEdgeAttributes = function ()
{
    title = 'test.addGetAndDeleteEdgeAttributes'
    window.prep (title)

    g  = makeSimpleGraph ()
    cw = CytoscapeWindow ('test.addGetAndDeleteEdgeAttributes', graph=g)
    displayGraph (cw)
    layoutNetwork (cw, 'grid')
    redraw (cw)

    # in this test we add two new edge attributes, 'species' and 'ageInYears'
    # if they are already defined, from a previous run of this test, start by deleting them.

    novel.eda.to.delete = intersect (c ('ageInYears', 'treeSpecies'), getEdgeAttributeNames(cw))
    for (eda.name in novel.eda.to.delete){
        deleteEdgeAttribute (cy, eda.name)
    }

    # name and interaction are added by Cytoscape
    checkEquals (length (intersect (getEdgeAttributeNames (cw), c ("name", "edgeType", "interaction", "misc", "score"))), 5)

    # now add an attribute to two of the edges
    first.two.edges = as.character (cy2.edge.names (g)[1:2])
    values = c ('hemlock', 'yew')
    setEdgeAttributesDirect (cw, 'treeSpecies', 'char', first.two.edges, values)

    # now add an attribute to a single edge.  this exercises a different branch in RCytoscape:setEdgeAttributesDirect
    first.edge = as.character (cy2.edge.names (g)[1])
    value = 'one century'
    setEdgeAttributesDirect (cw, 'ageInYears', 'char', first.edge, value)
    checkTrue ('ageInYears' %in% getEdgeAttributeNames (cw))

    # get names from cy2.edge.names (cw@graph)
    checkEquals (getEdgeAttribute (cw, "B (synthetic lethal) C", 'treeSpecies'), "yew")
    checkEquals (getEdgeAttribute (cw, "B (synthetic lethal) C", 'score'), -12)

    deleteEdgeAttribute (cw, 'species')
    deleteEdgeAttribute (cw, 'ageInYears')

    invisible (cw)

} #  test.addGetAndDeleteEdgeAttributes
#------------------------------------------------------------------------------------------------------------------------
test.addGetAndDeleteNodeAttributes = function ()
{
    title = 'test.addGetAndDeleteNodeAttributes'
    window.prep (title)

    # in this test we add two new node attributes, 'species' and 'ageInYears'
    # if they are already defined, from a previous run of this test, start by deleting them.

    g  = makeSimpleGraph ()
    cw = CytoscapeWindow (title, graph=g)
    displayGraph (cw)
    layoutNetwork (cw, 'grid')
    redraw (cw)

    novel.noa.to.delete = intersect (c ('ageInYears', 'treeSpecies'), getNodeAttributeNames(cw))
    for (noa.name in novel.noa.to.delete){
        deleteNodeAttribute (cy, noa.name)
    }

    # name is added by Cytoscape
    checkEquals (length (intersect (getNodeAttributeNames (cw), c ("name", "count",  "label", "lfc", "type"))), 5)

    # now add an attribute to two of the nodes
    first.two.nodes = nodes (g) [1:2]
    values = c ('cedar', 'ash')
    setNodeAttributesDirect (cw, 'treeSpecies', 'char', first.two.nodes, values)

    # now add an attribute to a single node.  this exercises a different branch in RCytoscape:setNodeAttributesDirect
    first.node = nodes (g) [1]
    value = 'one millenium'
    setNodeAttributesDirect (cw, 'ageInYears', 'char', first.node, value)
    checkTrue ('ageInYears' %in% getNodeAttributeNames (cw))
    checkEquals (getNodeAttribute (cw, 'B', 'type'), 'transcription factor')
    checkEquals (getNodeAttribute (cw, 'A', 'ageInYears'), 'one millenium')
    checkEquals (getNodeAttribute (cw, 'B', 'ageInYears'), '')

    deleteNodeAttribute (cw, 'species')
    deleteNodeAttribute (cw, 'ageInYears')

    invisible (cw)

} #  test.addGetAndDeleteNodeAttributes
#------------------------------------------------------------------------------------------------------------------------
test.getAllNodeAttributes = function ()
{
    title = 'test.getAllNodeAttributes'
    window.prep (title)

    cw = CytoscapeWindow (title, graph=makeSimpleGraph ())
    displayGraph (cw)
    redraw (cw)
    layoutNetwork (cw)

    cwc = existing.CytoscapeWindow (title, copy=T)
    tbl.noa <- getAllNodeAttributes (cwc)
    checkEquals (nrow (tbl.noa), 3)
    checkTrue (ncol (tbl.noa) >= 5)
    expected.colnames =  c ("name", "count", "label", "lfc", "type")  # created here
    checkEquals (length (intersect (colnames (tbl.noa), expected.colnames)), 5)
    checkEquals (sort (rownames (tbl.noa)), c ("A", "B", "C"))

    # now try a graph with only one node attribute.  this case used to fail (pshannon, 16 feb 2011)

    g2 = new ('graphNEL', edgemode='directed')
    g2 = initNodeAttribute (g2, 'label', 'char', 'NA')
    g2 = graph::addNode ('A', g2)
    nodeData (g2, 'A', 'label') = 'a label for A'
    window.title = 'single node attribute test'
    if (window.title %in% as.character (getWindowList (cw)))
    deleteWindow (cw, window.title)
    cw2 = CytoscapeWindow (window.title, graph=g2)
    tbl.noa2 = getAllNodeAttributes (cw2)
    checkEquals (ncol (tbl.noa2), 1)
    checkEquals (nrow (tbl.noa2), 1)
    checkEquals (colnames (tbl.noa2), 'label')
    checkEquals (rownames (tbl.noa2), 'A')

    invisible (list (a=tbl.noa, b=tbl.noa2))

} # test.getAllNodeAttributes
#------------------------------------------------------------------------------------------------------------------------
test.getAllEdgeAttributes = function ()
{
    title = 'test.getAllEdgeAttributes'
    window.prep (title)

    cw =  CytoscapeWindow (title, graph=makeSimpleGraph ())
    displayGraph (cw)
    redraw (cw)
    layoutNetwork (cw)
    tbl.eda = getAllEdgeAttributes (cw)
    checkEquals (class (tbl.eda), 'data.frame')
    checkEquals (dim (tbl.eda), c (3, 5))
    checkEquals (sort (rownames (tbl.eda)), c ("A|B", "B|C", "C|A"))
    checkEquals (sort (colnames (tbl.eda)), c ("edgeType", "misc", "score", "source", "target"))
    checkEquals (class (tbl.eda$score), 'numeric')

    # now try a graph with one edge, and just one edge attribute, to make sure that this edge case is handled properly
    g2 = new ('graphNEL', edgemode='directed')
    g2 = initEdgeAttribute (g2, 'edgeType', 'char', 'unspecified')
    g2 = graph::addNode ('A', g2)
    g2 = graph::addNode ('B', g2)
    g2 = addEdge ('A', 'B', g2)

    edgeData (g2, 'A', 'B', 'edgeType') = 'phosphorylates'

    cy = CytoscapeConnection ()

    window.title = 'edge attribute test, one attribute only'
    if (window.title %in% as.character (getWindowList (cy))){
        deleteWindow (cy, window.title)
    }

    cw2 = CytoscapeWindow (window.title, graph=g2, create.window=FALSE)
    tbl.eda2 = getAllEdgeAttributes (cw2)

    checkEquals (ncol (tbl.eda2), 3)
    checkEquals (nrow (tbl.eda2), 1)
    checkEquals (sort (colnames (tbl.eda2)), c ('edgeType', 'source', 'target'))

    invisible (tbl.eda2)

} # test.getAllEdgeAttributes
#------------------------------------------------------------------------------------------------------------------------
test.getVisualStyleNames = function ()
{
    title = 'test.getVisualStyleNames'
    window.prep (title)

    cw3 =  CytoscapeWindow (title, graph=makeSimpleGraph ())
    displayGraph (cw3)
    redraw (cw3)
    layoutNetwork (cw3)
    current.names = getVisualStyleNames (cw3)
    checkTrue (length (intersect (current.names, c (title, 'default', 'Nested Network Style', 'Minimal', 'Sample1', 'Universe'))) >= 3)

    invisible (cw3)

} # test.getVisualStyleNames
#------------------------------------------------------------------------------------------------------------------------
test.copyVisualStyle = function ()
{
    title = 'test.copyVisualStyle'
    window.prep (title)

    cw4 = CytoscapeWindow (title, graph=makeSimpleGraph ())
    displayGraph (cw4)
    redraw (cw4)
    layoutNetwork (cw4)

    current.names = getVisualStyleNames (cw4)

    unique.name = FALSE
    new.style.name = sprintf ("tmp.%s", runif (1, 1, 1000))
    copyVisualStyle (cw4, 'default', new.style.name)
    new.names = getVisualStyleNames (cw4)
    checkEquals (setdiff (new.names, current.names), new.style.name)

    invisible (cw4)

} # test.copyVisualStyle
#------------------------------------------------------------------------------------------------------------------------
test.setVisualStyle = function ()
{
    title = 'test.setVisualStyle'
    window.prep (title)
    cy = CytoscapeConnection ()

    cw5 = CytoscapeWindow (title, graph=makeSimpleGraph ())
    displayGraph (cw5)
    redraw (cw5)
    layoutNetwork (cw5)

    current.names = getVisualStyleNames (cw5)
    for (style.name in current.names[1:5]) {
        setVisualStyle (cw5, style.name)
        Sys.sleep (0.1)
    } # for style.name

    invisible (cw5)

} # test.setVisualStyle
#------------------------------------------------------------------------------------------------------------------------
# meager test only:  make sure all of these methods can be called
# todo:  call set, call get, check for color match
test.defaultColors = function ()
{
    title = 'test.defaultColors'
    window.prep (title)
    cy = CytoscapeConnection ()
    getDefaultBackgroundColor (cy)
    getDefaultEdgeReverseSelectionColor (cy)
    getDefaultEdgeSelectionColor (cy)
    getDefaultNodeReverseSelectionColor (cy)
    getDefaultNodeSelectionColor (cy)

    black = '#000000'
    red = '#FF0000'
    white = '#FFFFFF'
    green = '#00FF00'
    gray = '#888888'

    setDefaultBackgroundColor (cy, white)
    setDefaultEdgeReverseSelectionColor (cy, red)
    setDefaultEdgeSelectionColor (cy, green)
    setDefaultNodeReverseSelectionColor (cy, red)
    setDefaultNodeSelectionColor (cy, green)

} # test.defaultColors
#------------------------------------------------------------------------------------------------------------------------
test.fitContent = function ()
{
    title = 'test.fitContent'
    window.prep (title)
    cw = CytoscapeWindow (title, graph=makeSimpleGraph ())
    displayGraph (cw)
    redraw (cw)
    layoutNetwork (cw)

    clearSelection (cw)
    selectNodes (cw, 'A')
    checkEquals (getSelectedNodeCount (cw), 1)

    #fitSelectedContent (cw)
    fitContent (cw)

} # test.fitContent
#------------------------------------------------------------------------------------------------------------------------
# test.windowCoordinates = function ()
# {
#     title = 'test.windowCoordinates'
#     window.prep (title)
#     cw = CytoscapeWindow (title, graph=makeSimpleGraph ())
#     displayGraph (cw)
#     redraw (cw)
#     layoutNetwork (cw)
#
#     center = getCenter (cw)
#     checkEquals (names (center), c ('x', 'y'))
#
#     corners = getViewCoordinates (cw)
#     checkEquals (names (corners), c ('top.x', 'top.y', 'bottom.x', 'bottom.y'))
#
#     invisible (cw)
#
#} # test.windowCoordinates
#------------------------------------------------------------------------------------------------------------------------
test.zoom = function ()
{
    title = 'test.zoom'
    window.prep (title)
    cw = CytoscapeWindow (title, graph=makeSimpleGraph ())
    displayGraph (cw)
    redraw (cw)
    layoutNetwork (cw)

    fitContent (cw)

    smaller = 0.5
    larger = 2

    for (i in 1:10){
        setZoom (cw, smaller * getZoom (cw))
    }

    for (i in 1:10){
        setZoom (cw, larger * getZoom (cw))
    }

    invisible (cw)

} # test.zoom
#------------------------------------------------------------------------------------------------------------------------
test.center = function ()
{
    title = 'test.setCenter'
    window.prep (title)
    cw = CytoscapeWindow (title, graph=makeSimpleGraph ())
    displayGraph (cw)
    redraw (cw)
    layoutNetwork (cw)

    fitContent (cw)
    setZoom (cw, 0.5 * getZoom (cw))

    center.orig = getCenter (cw)
    delta = 100
    x.left = center.orig$x - delta
    x.right = center.orig$x + delta
    y.up = center.orig$y - delta
    y.down = center.orig$y + delta

    for (i in 1:10) {
        setCenter (cw, x.left, y.up)
        setCenter (cw, as.integer (x.left), as.integer (y.up))   # make sure the called function casts this int back to numeric
        setCenter (cw, x.left, y.down)
        setCenter (cw, x.right, y.down)
        setCenter (cw, x.right, y.up)
    } # for i

    setCenter (cw, center.orig$x, center.orig$y)

    invisible (cw)

} # test.center
#------------------------------------------------------------------------------------------------------------------------
test.setNodeSizeDirect = function ()
{
    #DEACTIVATED("too slow")
    title = 'test.setNodeSizeDirect'
    window.prep (title)
    cw = CytoscapeWindow (title, graph=makeSimpleGraph ())
    displayGraph (cw)
    redraw (cw)
    layoutNetwork (cw)

    lockNodeDimensions (cw, TRUE)

    small = 30
    large = 300
    setNodeSizeDirect (cw, 'A', small);
    setNodeSizeDirect (cw, 'A', large);

    invisible (cw)

} # test.setNodeSizeDirect
#------------------------------------------------------------------------------------------------------------------------
test.setNodeWidthAndHeightDirect = function ()
{
    #DEACTIVATED("too slow")
    title = 'test.setNodeWidthAndHeightDirect'
    window.prep (title)
    cw = CytoscapeWindow (title, graph=makeSimpleGraph ())
    displayGraph (cw)
    redraw (cw)
    layoutNetwork (cw)

    lockNodeDimensions (cw, FALSE)

    small = 30
    large = 300

    setNodeWidthDirect (cw, 'A', small);
    setNodeHeightDirect (cw, 'A', large);
    setNodeWidthDirect (cw, 'A', large);
    setNodeHeightDirect (cw, 'A', small);

    invisible (cw)

} # test.setNodeWidthAndHeightDirect
#------------------------------------------------------------------------------------------------------------------------
test.setNodeFontSizeDirect = function ()
{
    #DEACTIVATED("too slow")
    title = 'test.setNodeFontSizeDirect'
    window.prep (title)
    cw = CytoscapeWindow (title, graph=makeSimpleGraph ())
    displayGraph (cw)
    redraw (cw)
    layoutNetwork (cw)

    starting.size = 4
    setNodeSizeDirect (cw, c ('A', 'B', 'C'), 50)
    setNodeFontSizeDirect (cw, c ('A', 'B'), 12)
    redraw (cw)

    for (i in 1:20) {
        setNodeFontSizeDirect (cw, 'A', starting.size + i)
        setNodeFontSizeDirect (cw, 'B', starting.size + (i*3))
    } # for i

    starting.size = 32
    for (i in 20:1) {
    setNodeFontSizeDirect (cw, 'A', starting.size - i)
    setNodeFontSizeDirect (cw, 'B', starting.size - (i*3))
    } # for i

    invisible (cw)

} # test.setNodeSizeDirect
#------------------------------------------------------------------------------------------------------------------------
test.setNodeShapeDirect = function ()
{
    #DEACTIVATED("too slow")
    title = 'test.setNodeShapeDirect'
    window.prep (title)
    cw = CytoscapeWindow (title, graph=makeSimpleGraph ())
    displayGraph (cw)
    redraw (cw)
    layoutNetwork (cw)

    lockNodeDimensions (cw, TRUE)
    setNodeSizeDirect (cw, 'A', 100)

    for (new.shape in getNodeShapes (cw)) {
        setNodeShapeDirect (cw, 'A', new.shape)
    } # for new.shape

    invisible (cw)

} # test.setNodeShapeDirect
#------------------------------------------------------------------------------------------------------------------------
# test.setEdgeVizPropertiesDirect = function (cw=NULL) # WORKS PERFECTLY BUT SLOW
# {
#     #DEACTIVATED("too slow!")
#     title = 'test.setEdgeVizPropertiesDirect'
#
#     window.prep (title)
#     cw = CytoscapeWindow (title, graph=makeSimpleGraph ())
#     displayGraph (cw)
#     redraw (cw)
#     layoutNetwork (cw)
#
#     cy2.edgeNames = sort (getAllEdges (cw))
#     e1 = cy2.edgeNames [1]
#     e2 = cy2.edgeNames [2]
#     e3 = cy2.edgeNames [3]
#
#     colors = c ('#440000', '#004400', '#000044', '#880000', '#008800', '#000088', '#FF0000', '#00FF00', '#0000FF', '#FFFFFF')
#     line.styles = c ('SOLID', 'LONG_DASH', 'EQUAL_DASH', 'DASH_DOT', 'DOT', 'ZIGZAG', 'SINEWAVE', 'VERTICAL_SLASH',
#                'FORWARD_SLASH', 'BACKWARD_SLASH', 'PARALLEL_LINES', 'CONTIGUOUS_ARROW', 'SEPARATE_ARROW')
#
#     arrow.shapes = c ('No Arrow', 'Diamond', 'Delta', 'Arrow', 'T', 'Circle', 'Half Arrow Top', 'Half Arrow Bottom', 'Diamond', 'T')
#     labels = paste ('label', seq (10,100,10), sep='-');  labels [10] = ''
#     tooltips = paste ('tooltip', seq (10,100,10), sep='-');  tooltips [10] = ''
#     widths = c (1:9, 1)
#
#     for (i in 1:10) {
#         setEdgeOpacityDirect (cw, c (e2, e3), 25 * i)
#         setEdgeColorDirect (cw, e1, colors [i])
#         setEdgeLineStyleDirect (cw, e2, line.styles [i])
#         setEdgeSourceArrowShapeDirect (cw, e1, arrow.shapes [i])
#         setEdgeTargetArrowShapeDirect (cw, e1, arrow.shapes [i])
#         setEdgeLabelDirect (cw, e2, labels [i])
#         setEdgeLabelColorDirect (cw, e2, colors [i])
#         setEdgeTooltipDirect (cw, e2, tooltips [i])
#         setEdgeLineWidthDirect (cw, e3, widths [i])
#         setEdgeFontSizeDirect (cw, e2, widths [i] * 3)
#         setEdgeSourceArrowColorDirect (cw, e1, colors [11-i])
#         setEdgeTargetArrowColorDirect (cw, e1, colors [11-i])
#         setEdgeLabelOpacityDirect (cw, e2, 25 * i)
#         setEdgeSourceArrowOpacityDirect (cw, e1, 25 * i)
#         setEdgeTargetArrowOpacityDirect (cw, e1, 255 - (25 * i))
#         redraw (cw)
#         Sys.sleep (0.3)
#     }
#
#     invisible (cw)
#
#} # test.setEdgeVizPropertiesDirect
#------------------------------------------------------------------------------------------------------------------------
# test.graphBAM = function ()
# {
#     title = 'test.graphBAM'
#     window.prep (title)
#
#     # example is taken from Nishant's man page
#     source.nodes  <- c ("a", "a", "b", "c", "d")
#     target.nodes  <- c ("b", "c", "c", "d", "a")
#     weights <- c(2.3, 2.3, 4.3, 1.0, 3.0)
#     df <- data.frame (from=source.nodes, to=target.nodes, weight=weights)
#     g.bam <- graphBAM (df)
#     g.bam <- initEdgeAttribute (g.bam, 'weight', 'numeric', 0.0)
#
#     cw = CytoscapeWindow (title, graph=g.bam)
#     displayGraph (cw)
#     redraw (cw)
#     layoutNetwork (cw)
#
#     # paint the edges shades of red as function of weight
#     setDefaultEdgeLineWidth (cw, 5)
#     setEdgeColorRule (cw, 'weight',  c (0, 5), c ('#FFFFFF', '#FF0000'),  mode='interpolate')
#
#     invisible (cw)
#
# } # test.graphBAM
#------------------------------------------------------------------------------------------------------------------------
# add a node to an existing graph.
# questions:
#  1) what edge attribute values are assigned to this new edge?
#  2) can we assign new values to those attributes?  use setEdgeAttributesDirect
test.addCyNode = function ()
{
    title = 'test.addCyNode'
    window.prep (title)

    cw = CytoscapeWindow (title, graph=makeSimpleGraph ())
    displayGraph (cw)
    redraw (cw)
    layoutNetwork (cw, 'grid')
    checkEquals (getNodeCount (cw), 3)
    addCyNode (cw, 'NEW')
    layoutNetwork (cw, 'grid')
    checkEquals (getNodeCount (cw), 4)
    invisible (cw)

} # test.addCyNode
#------------------------------------------------------------------------------------------------------------------------
# add an edge to an existing graph.
# questions:
#  1) what edge attribute values are assigned to this new edge?
#  2) can we assign new values to those attributes?  use setEdgeAttributesDirect
test.addCyEdge = function ()
{
    title = 'test.addCyEdge'
    window.prep (title)

    cw = CytoscapeWindow (title, graph=makeSimpleGraph ())
    displayGraph (cw)
    redraw (cw)
    layoutNetwork (cw)
    checkEquals (getEdgeCount (cw), 3)

    addCyNode (cw, 'NEW')
    directed.edge = TRUE
    addCyEdge (cw, 'A', 'NEW', 'synthetic rescue', directed.edge)
    redraw (cw)
    layoutNetwork (cw)
    checkEquals (getEdgeCount (cw), 4)
    invisible (cw)

} # test.addCyEdge
#------------------------------------------------------------------------------------------------------------------------
test.twoGraphsDoubleEdges = function ()
{
    title = 'test.twoGraphsDoubleEdges'
    window.prep (title)

    cw = CytoscapeWindow (title, graph=makeSimpleGraph ())
    displayGraph (cw)
    redraw (cw)
    layoutNetwork (cw)

    g2 = new ('graphNEL', edgemode='directed')
    g2 = initEdgeAttribute (g2, 'edgeType', 'char', 'unspecified')

    g2 = graph::addNode ('A', g2)
    g2 = graph::addNode ('B', g2)
    g2 = addEdge ('A', 'B', g2)

    edgeData (g2, 'A', 'B', 'edgeType') = 'synthetic rescue'

    addGraphToGraph (cw, g2)
    redraw (cw)
    layoutNetwork (cw)

} # test.twoGraphsoubleEdges
#------------------------------------------------------------------------------------------------------------------------
test..classicGraphToNodePairTable = function ()
{
    print (noquote ('------- test..classicGraphToNodePairTable'))

    # first, our standard demo graph, directed, no reciprocal edges

    g = makeSimpleGraph ()
    tbl.g = RCy3:::.classicGraphToNodePairTable (g)
    checkEquals (dim (tbl.g), c (3, 3))
    checkEquals (colnames (tbl.g), c ("source", "target", "edgeType"))
    checkEquals (tbl.g$edgeType, c ("phosphorylates", "synthetic lethal", "undefined"))
    checkEquals (tbl.g$source, c ("A", "B", "C"))
    checkEquals (tbl.g$target, c ("B", "C", "A"))

    # now extend the standard demo graph by adding an edge between C and B, making B & C reciprocally related nodes

    gx = makeSimpleGraph ()
    gx = graph::addEdge ('C', 'B', gx)
    edgeData (gx, 'C', 'B', attr='edgeType') = 'synthetic rescue'
    tbl.egx = RCy3:::.classicGraphToNodePairTable (gx)
    checkEquals (dim (tbl.egx), c (4, 3))
    checkEquals (colnames (tbl.egx), c ("source", "target", "edgeType"))
    checkEquals (tbl.egx$edgeType, c ("phosphorylates", "synthetic lethal", "undefined", "synthetic rescue"))
    checkEquals (tbl.egx$source, c ("A", "B", "C", "C"))
    checkEquals (tbl.egx$target, c ("B", "C", "A", "B"))

} # test..classicGraphToNodePairTable
#------------------------------------------------------------------------------------------------------------------------
test.rcy.edgeNames = function ()
{
    print (noquote ('------- test.rcy.edgeNames'))
    g = makeSimpleGraph ()
    checkEquals (sort (RCy3:::.rcyEdgeNames (g)), c ("A~B", "B~C", "C~A"))

    # now extend the standard demo graph by adding an edge between C and B, making B & C reciprocally related nodes
    gx = makeSimpleGraph ()
    gx = graph::addEdge ('C', 'B', gx)
    edgeData (gx, 'C', 'B', attr='edgeType') = 'synthetic rescue'
    checkEquals (sort (RCy3:::.rcyEdgeNames (gx)), c ("A~B", "B~C", "C~A", "C~B"))

} # test.rcy.edgeNames
#------------------------------------------------------------------------------------------------------------------------
restore.defaults = function ()
{
    cy = CytoscapeConnection ()
    setDefaultBackgroundColor (cy, '#CCCCFF')
    setDefaultNodeShape (cy, 'ellipse')
    lockNodeDimensions (cy, TRUE)
    setDefaultNodeSelectionColor (cy, '#FFFF00')
    setDefaultNodeReverseSelectionColor (cy, '#00FF00')
    setDefaultEdgeSelectionColor (cy, '#FF0000')
    setDefaultEdgeReverseSelectionColor (cy, '#00FF00')
    setDefaultNodeSize (cy, 30)
    setDefaultNodeColor (cy, '#FF8888')  # a guess

    setDefaultNodeBorderColor (cy, '#000000')
    setDefaultNodeBorderWidth (cy, 1)
    setDefaultNodeFontSize (cy, 12)
    setDefaultNodeLabelColor (cy, '#000000')
    setDefaultEdgeLineWidth (cy, 1)
    setDefaultEdgeColor (cy, '#0000FF')

} # restore.defaults
#------------------------------------------------------------------------------------------------------------------------
test..getNovelEdges = function ()
{
g.3e <- makeSimpleGraph ()
g.0e <- new ("graphNEL", edgemode = "directed")
g.0e = initEdgeAttribute (g.0e, 'edgeType', 'char', 'unspecified')

# no novel edges if the 2nd arg has no edges
checkTrue (is.na (RCy3:::.getNovelEdges (g.3e, g.0e)))

# three novel edges if the 1st arg has zero edges, the second has 3
novel.edges <- RCy3:::.getNovelEdges (g.0e, g.3e)
checkEquals (length (novel.edges), 3)

# add one edge to g.0e which is an exact duplicate of the first edge of g.3e

g.1e = graph::addNode ('A', g.0e)
g.1e = graph::addNode ('B', g.1e)
g.1e = addEdge ('A', 'B', g.1e)
edgeData (g.1e, 'A', 'B', attr='edgeType') = 'phosphorylates'

g1 <- g.1e
g3 <- g.3e

novel.edges <- RCy3:::.getNovelEdges (g.3e, g.1e)
checkEquals (length (novel.edges), 0)

novel.edges <- RCy3:::.getNovelEdges (g.1e, g.3e)
checkEquals (length (novel.edges), 2)

} # test..getNovelEdges
#------------------------------------------------------------------------------------------------------------------------
# apparently does not run reliably at bioc
hiddenTest.saveImage = function ()
{
    title = 'test.saveImage'
    window.prep (title)

    g.simple = RCy3::makeSimpleGraph ()
    cw = CytoscapeWindow (title, g.simple)

    displayGraph (cw)
    layoutNetwork (cw, 'grid')
    setNodeLabelRule (cw, 'label')
    redraw (cw)

    #--- png first
    filename = sprintf ('%s/%s', tempdir (), 'saveImageTest')
    printf ('saving image file to %s', filename)
    saveImage (cw, filename, 'png', 1.0)
    checkTrue (file.exists (paste0(filename, '.png')))

    #--- now pdf
    filename = sprintf ('%s/%s', tempdir (), 'saveImageTest')
    printf ('saving image file to %s', filename)
    saveImage (cw, filename, 'pdf')
    checkTrue (file.exists (paste0(filename, '.pdf')))

    #--- now svg
    filename = sprintf ('%s/%s', tempdir (), 'saveImageTest')
    printf ('saving image file to %s', filename)
    saveImage (cw, filename, 'svg')
    checkTrue (file.exists (paste0(filename, '.svg')))

    invisible (cw)

} # test.saveImage
#------------------------------------------------------------------------------------------------------------------------
# apparently does not run reliably at bioc
hiddenTest.saveNetwork = function ()
{
    title = 'test.saveNetwork'
    window.prep (title)

    g.simple = RCy3::makeSimpleGraph ()
    cw = CytoscapeWindow (title, g.simple)

    displayGraph (cw)
    layoutNetwork (cw, 'grid')
    setNodeLabelRule (cw, 'label')
    redraw (cw)

    filename = sprintf ('%s/%s', tempdir (), 'saveNetworkTest')
    printf ('saving cys file to %s', filename)
    saveNetwork (cw, filename)
    checkTrue (file.exists (paste0(filename, '.cys')))

    invisible (cw)

} # test.saveNetwork
# also not an automated test, though exception testing could accomplish that
test.detectUnitializedNodeAttributes = function ()
{
    # starting with the code in makeSampleGraph, change 3 node and 1 edge attribute to use the  standard (not RCy)
    # attribute initializations. this is an error with respect to RCy, which needs explicit typing of the attributes
    # see if they are caught

    g = new("graphNEL", edgemode = "directed")

    g = initNodeAttribute(g, "type", "char", "undefined")
    g = initNodeAttribute(g, "lfc", "numeric", 1)
    g = initNodeAttribute(g, "label", "char", "default node label")
    g = initNodeAttribute(g, "count", "integer", 0)

    nodeDataDefaults (g, attr='type') = ''
    nodeDataDefaults (g, attr='lfc') = 0.0
    nodeDataDefaults (g, attr='label') = ''

    g = initEdgeAttribute(g, "edgeType", "char", "undefined")
    g = initEdgeAttribute(g, "score", "numeric", 0)
    g = initEdgeAttribute(g, "misc", "char", "default misc")

    g = graph::addNode("A", g)
    g = graph::addNode("B", g)
    g = graph::addNode("C", g)
    nodeData(g, "A", "type") = "kinase"
    nodeData(g, "B", "type") = "transcription factor"
    nodeData(g, "C", "type") = "glycoprotein"
    nodeData(g, "A", "lfc") = -3
    nodeData(g, "B", "lfc") = 0
    nodeData(g, "C", "lfc") = 3
    nodeData(g, "A", "count") = 2
    nodeData(g, "B", "count") = 30
    nodeData(g, "C", "count") = 100
    nodeData(g, "A", "label") = "Gene A"
    nodeData(g, "B", "label") = "Gene B"
    nodeData(g, "C", "label") = "Gene C"
    g = graph::addEdge("A", "B", g)
    g = graph::addEdge("B", "C", g)
    g = graph::addEdge("C", "A", g)
    edgeData(g, "A", "B", "edgeType") = "phosphorylates"
    edgeData(g, "B", "C", "edgeType") = "synthetic lethal"
    edgeData(g, "A", "B", "score") = 35
    edgeData(g, "B", "C", "score") = -12

    cw = CytoscapeWindow (title = 'detect unitialized node attributes 1', graph = g)

} # test.detectUnitializedNodeAttributes
#------------------------------------------------------------------------------------------------------------------------
# also not an automated test, though exception testing could accomplish that
test.detectUnitializedEdgeAttributes = function ()
{
    # starting with the code in makeSampleGraph, change 3 node and 1 edge attribute to use the standard (not RCy)
    # attribute initializations. This is an error with respect to RCy, which needs explicit typing of the attributes
    # see if they are caught

    g = new("graphNEL", edgemode = "directed")

    g = initNodeAttribute(g, "type", "char", "undefined")
    g = initNodeAttribute(g, "lfc", "numeric", 1)
    g = initNodeAttribute(g, "label", "char", "default node label")
    g = initNodeAttribute(g, "count", "integer", 0)

    g = initEdgeAttribute(g, "edgeType", "char", "undefined")
    g = initEdgeAttribute(g, "score", "numeric", 0)
    g = initEdgeAttribute(g, "misc", "char", "default misc")
    edgeDataDefaults (g, attr='misc') = ''

    g = graph::addNode("A", g)
    g = graph::addNode("B", g)
    g = graph::addNode("C", g)
    nodeData(g, "A", "type") = "kinase"
    nodeData(g, "B", "type") = "transcription factor"
    nodeData(g, "C", "type") = "glycoprotein"
    nodeData(g, "A", "lfc") = -3
    nodeData(g, "B", "lfc") = 0
    nodeData(g, "C", "lfc") = 3
    nodeData(g, "A", "count") = 2
    nodeData(g, "B", "count") = 30
    nodeData(g, "C", "count") = 100
    nodeData(g, "A", "label") = "Gene A"
    nodeData(g, "B", "label") = "Gene B"
    nodeData(g, "C", "label") = "Gene C"
    g = graph::addEdge("A", "B", g)
    g = graph::addEdge("B", "C", g)
    g = graph::addEdge("C", "A", g)
    edgeData(g, "A", "B", "edgeType") = "phosphorylates"
    edgeData(g, "B", "C", "edgeType") = "synthetic lethal"
    edgeData(g, "A", "B", "score") = 35
    edgeData(g, "B", "C", "score") = -12

    cw = CytoscapeWindow (title = 'detect unitialized node attributes 2', graph = g)

} # test.detectUnitializedNodeAttributes
#------------------------------------------------------------------------------------------------------------------------
# test.remove.redundancies.in.undirected.graph = function ()
# {
#     print ('----- test.remove.redundancies.in.undirected.graph')
#     nNode <- 500
#     nEdge <- 5000
#     tmpNodes <- as.character(seq(1, nNode))
#     allEdges <- expand.grid(tmpNodes, tmpNodes, stringsAsFactors = F)
#     allEdges <- allEdges[(allEdges[, 1] != allEdges[, 2]), ]
#     allEdges <- allEdges[(sample(nrow(allEdges), nEdge)), ]
#     edgeWeight <- rnorm(nEdge)
#     gu <- new("graphNEL", nodes = tmpNodes, edgemode = "undirected")
# 
#     gu = initNodeAttribute(gu, "type", "char", "undefined")
#     gu = initNodeAttribute(gu, "lfc", "numeric", 1)
#     gu = initNodeAttribute(gu, "label", "char", "default node label")
# 
#     gu = initEdgeAttribute(gu, "edgeType", "char", "undefined")
#     gu = initEdgeAttribute(gu, "weight", "numeric", 0)
# 
#     gu = addEdge(allEdges[, 1], allEdges[, 2], gu, edgeWeight)
#     nodeData (gu, nodes (gu), 'label') = nodes (gu)
# 
#     t0 = Sys.time ()
#     g.fixed <- RCy3:::remove.redundancies.in.undirected.graph (gu)
#     t1 = Sys.time ()
#     elapsed.time = as.numeric (difftime (t1, t0, units='secs'))
#     #checkTrue (elapsed.time < 5)  # consistently about 0.5 seconds in interactive testing; not inconsistent
#     checkTrue (all (nodes (gu) == nodes (g.fixed)))
#     checkTrue (all (edgeNames (gu) == edgeNames (g.fixed)))
# 
#     # the main test
#     #checkEquals (length (unlist (edges (gu))), 2 * length (unlist (edges (g.fixed)))) # no longer redundant edge lists?
# 
# } # test.remove.redundancies.in.undirected.graph
#------------------------------------------------------------------------------------------------------------------------
##run.tests ()
#------------------------------------------------------------------------------------------------------------------------

