Skip to content

Commit

Permalink
three-way merge test works
Browse files Browse the repository at this point in the history
  • Loading branch information
Simaris committed Dec 28, 2020
1 parent ea51d95 commit ac133d4
Show file tree
Hide file tree
Showing 7 changed files with 79 additions and 104 deletions.
65 changes: 52 additions & 13 deletions quit/merge.py
Original file line number Diff line number Diff line change
Expand Up @@ -176,10 +176,14 @@ def _merge_threeway_graph_blobs(self, graphAOid, graphBOid, graphBaseOid):
source = rdflib.parser.create_input_source(data=graphBblob.decode("utf-8"))
parserGraphB.parse(source.getCharacterStream())

nameNodeBaseMap = None
if graphBaseOid is not None:
graphBaseblob = self._repository[graphBaseOid].data
compGraphBase = comp_graph.ComparableGraph()
compGraphBase.parse(data=graphBaseblob.decode("utf-8"), format="nt")
parserGraphBase = ntriples.W3CNTriplesParser(ntriples.NTGraphSink(compGraphBase))
source = rdflib.parser.create_input_source(data=graphBaseblob.decode("utf-8"))
parserGraphBase.parse(source.getCharacterStream())
nameNodeBaseMap = parserGraphBase._bnode_ids
diffA = aGraph.diff(compGraphBase)
diffB = bGraph.diff(compGraphBase)

Expand All @@ -198,7 +202,8 @@ def _merge_threeway_graph_blobs(self, graphAOid, graphBOid, graphBaseOid):
colourMap = {**(compGraphBase.getBNodeColourMap()),
**(bGraph.getBNodeColourMap()),
**(aGraph.getBNodeColourMap())}
colourToNameMap = self._create_colour_to_name_map(colourMap, parserGraphA._bnode_ids)
colourToNameMap = self._create_colour_to_name_map(colourMap, parserGraphA._bnode_ids,
parserGraphB._bnode_ids, nameNodeBaseMap)
merged = self._serialize_triple_sets(merged, colourMap, colourToNameMap)
blob = self._repository.create_blob(("\n".join(merged) + "\n").encode("utf-8"))

Expand Down Expand Up @@ -227,18 +232,47 @@ def _serialize_triple_sets(self, tripleSet, colourMap, colourToNameMap):
def _serialize_bNode(self, node, colourMap, colourToNameMap):
if(isinstance(node, rdflib.BNode)):
try:
return "_:{}".format(colourToNameMap[colourMap[node]])
return colourToNameMap[colourMap[node]]
except KeyError:
return node.n3()
else:
return node.n3()

def _create_colour_to_name_map(self, nodeColourMap, nodeNameMap):
def _create_colour_to_name_map(self, nodeColourMap, nameNodeMapA,
nameNodeMapB, nameNodeMapC=None):
colourToNameMap = {}
for bNodeName in nodeNameMap:
colourKey = nodeColourMap[nodeNameMap[bNodeName]]
if not colourKey in colourToNameMap or bNodeName < colourToNameMap[colourKey]:
colourToNameMap[colourKey] = bNodeName
for bNodeName in nameNodeMapA:
colourKey = nodeColourMap[nameNodeMapA[bNodeName]]
if colourKey not in colourToNameMap or bNodeName < colourToNameMap[colourKey]:
colourToNameMap[colourKey] = "_:{}".format(bNodeName)

for bNodeName in nameNodeMapB:
bNode = nameNodeMapB[bNodeName]
colourKey = nodeColourMap[bNode]
# check if the first two loops already took the label
unusedCheck = bNodeName not in nameNodeMapA
if colourKey not in colourToNameMap:
if unusedCheck:
colourToNameMap[colourKey] = "_:{}".format(bNodeName)
else:
colourToNameMap[colourKey] = bNode.n3()
if bNodeName < colourToNameMap[colourKey] and unusedCheck:
colourToNameMap[colourKey] = "_:{}".format(bNodeName)

if nameNodeMapC is not None:
for bNodeName in nameNodeMapB:
bNode = nameNodeMapB[bNodeName]
colourKey = nodeColourMap[bNode]
# check if the first two loops already took the label
unusedCheck = bNodeName not in nameNodeMapA and bNodeName not in nameNodeMapB
if colourKey not in colourToNameMap:
if unusedCheck:
colourToNameMap[colourKey] = "_:{}".format(bNodeName)
else:
colourToNameMap[colourKey] = bNode.n3()
if bNodeName < colourToNameMap[colourKey] and unusedCheck:
colourToNameMap[colourKey] = "_:{}".format(bNodeName)

return colourToNameMap

def _merge_context_graph_blobs(self, graphAOid, graphBOid, graphBaseOid):
Expand All @@ -256,10 +290,14 @@ def _merge_context_graph_blobs(self, graphAOid, graphBOid, graphBaseOid):
source = rdflib.parser.create_input_source(data=graphBblob.decode("utf-8"))
parserGraphB.parse(source.getCharacterStream())

nameNodeBaseMap = None
if graphBaseOid is not None:
graphBaseblob = self._repository[graphBaseOid].data
graphBase = comp_graph.ComparableGraph()
graphBase.parse(data=graphBaseblob.decode("utf-8"), format="nt")
parserGraphBase = ntriples.W3CNTriplesParser(ntriples.NTGraphSink(graphBase))
source = rdflib.parser.create_input_source(data=graphBaseblob.decode("utf-8"))
parserGraphBase.parse(source.getCharacterStream())
nameNodeBaseMap = parserGraphBase._bnode_ids
else:
graphBase = comp_graph.ComparableGraph()

Expand All @@ -269,7 +307,8 @@ def _merge_context_graph_blobs(self, graphAOid, graphBOid, graphBaseOid):
colourMap = {**(graphBase.getBNodeColourMap()),
**(graphB.getBNodeColourMap()),
**(graphA.getBNodeColourMap())}
colourToNameMap = self._create_colour_to_name_map(colourMap, parserGraphA._bnode_ids)
colourToNameMap = self._create_colour_to_name_map(colourMap, parserGraphA._bnode_ids,
parserGraphB._bnode_ids, nameNodeBaseMap)

# those operations are not ready since they actually need to be done by their colour
diffANewTriples = self._accumulate_triples(diffA[1]) # C+c
Expand Down Expand Up @@ -315,7 +354,7 @@ def conflictSet(tripleSet, conflictingNodes, colNameMap):
else:
object = triple[2].n3()

cTriple = ("%s %s %s .\n" % (subject, triple[1], object)).rstrip()
cTriple = ("%s %s %s .\n" % (subject, triple[1].n3(), object)).rstrip()
if conflicted:
conflicts.add(cTriple)
else:
Expand Down Expand Up @@ -380,12 +419,12 @@ def _convert_colour_to_name_triple_rows(self, tripleSet, colNameMap):
result = set()
for triple in tripleSet:
if isinstance(triple[0], bytes):
subject = "_:{}".format(colNameMap[triple[0]])
subject = colNameMap[triple[0]]
else:
subject = triple[0].n3()

if isinstance(triple[2], bytes):
object = "_:{}".format(colNameMap[triple[2]])
object = colNameMap[triple[2]]
elif isinstance(triple[2], rdflib.Literal):
object = _qLiteral(triple[2])
else:
Expand Down
4 changes: 4 additions & 0 deletions tests/merges/TestD/a_graphs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
_:a <ed:a> _:b .
_:b <ed:b> _:a .
---
_:a <ed:b> _:a .
Empty file added tests/merges/TestD/base.nt
Empty file.
4 changes: 4 additions & 0 deletions tests/merges/TestD/branch.nt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
_:a <ed:b> _:b .
_:b <ed:b> _:c .
_:c <ed:b> _:d .
_:d <ed:b> _:a .
1 change: 1 addition & 0 deletions tests/merges/TestD/debugResult
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
_:a <ed:b> _:a .
4 changes: 4 additions & 0 deletions tests/merges/TestD/target.nt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
_:a <ed:a> _:b .
_:b <ed:b> _:c .
_:c <ed:a> _:d .
_:d <ed:b> _:a .
105 changes: 14 additions & 91 deletions tests/merges/test_merge_methods.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,19 +21,19 @@ def setUp(self):
def tearDown(self):
return

def testThreeWayMerge(self):
"""Test merging two commits."""
# def testThreeWayMerge(self):
# """Test merging two commits. Method: Three-Way"""
# testPath = os.path.dirname(os.path.abspath(__file__))
# for d in listdir(testPath):
# if d[0:4] == "Test" and isdir(join(testPath, d)):
# self._merge_test(d, "three-way")

def testContextMerge(self):
"""Test merging two commits. Method: Context"""
testPath = os.path.dirname(os.path.abspath(__file__))
# for d in listdir(testPath):
# for d in ["TestA", "TestHouseMerge", "TestABCD", "TestB", "TestC"]:
# if isdir(join(testPath, d)) and d != "__pycache__":
# self._merge_test(d, "three-way")
for d in ["TestD"]:
if isdir(join(testPath, d)) and d != "__pycache__":
print("#######################################")
print("### {} ###".format(d))
print("#######################################")
self._merge_test(d, "three-way")
for d in listdir(testPath):
if d[0:4] == "Test" and isdir(join(testPath, d)):
self._merge_test(d, "context")

def _merge_test(self, dirPath, method):
# Prepate a git Repository
Expand Down Expand Up @@ -64,26 +64,16 @@ def _merge_test(self, dirPath, method):
aControllGraphContents = file.read().split("---")
file.close()
resultContent = branchCommit.tree["graph.nt"].data.decode("utf-8")
print(resultContent)
resultGraph = rdflib.Graph().parse(data=resultContent, format="nt")
aResultGraphs = set(iter(aGraphFactory(resultGraph)))
print("ResultContent:\n{}\n-----".format(resultContent))
print("Current Result Set:\n-->{}".format({a.__hash__() for a in aResultGraphs}))
for aControllGraphContent in aControllGraphContents:
graph = rdflib.Graph().parse(data=aControllGraphContent, format="nt")
for aGraph in aGraphFactory(graph):
print("aGraph: {}".format(aGraph.__hash__()))
message = "Merge test {}:\n Graph {} is not in the set: {}"
resultSetString = {a.__hash__() for a in aResultGraphs}
message = message.format(dirPath, aGraph.__hash__(), resultSetString)
try:
self.assertTrue(aGraph in aResultGraphs, message)
except AssertionError:
graphFile = open(join(dirPath, "debugResult"), "w")
graphFile.write(self.__show_comparison(aGraph, aControllGraphContent))
graphFile.close()
print("- {}".format(self.__show_colours(next(iter(aResultGraphs)))))
print("- {}".format(self.__show_colours(aGraph)))
raise
self.assertTrue(aGraph in aResultGraphs, message)
aResultGraphs.remove(aGraph)
message = "Merge test {}:\n Not all graphs were defined in a_graphs: {}"
message = message.format(dirPath, aResultGraphs)
Expand All @@ -108,72 +98,5 @@ def expand_branch(self, repo, branch, graphFile):
repo.state_cleanup()
return newCommitOid

# TODO remove
def __show_comparison(self, graph, controllContent):
listLabel = ["a", "b", "c", "d", "e", "f", "g", "h", "i"]
bNodeMap = {}
for triple in graph:
node = triple[0]
if node.n3() not in bNodeMap:
if isinstance(node, rdflib.BNode):
bNodeMap[node.n3()] = "_:{}".format(listLabel.pop(0))
else:
bNodeMap[node.n3()] = "<{}>".format(node.n3())
node = triple[2]
if node.n3() not in bNodeMap:
if isinstance(node, rdflib.BNode):
bNodeMap[node.n3()] = "_:{}".format(listLabel.pop(0))
else:
bNodeMap[node.n3()] = "<{}>".format(node.n3())
template = "{1}"
result = ""
for triple in graph:
newLine = "{} <{}> {} .".format(bNodeMap[triple[0].n3()],
triple[1], bNodeMap[triple[2].n3()])
result = template.format(result, newLine)
template = "{0}\n{1}"
return result

def __show_colours(self, graph):
bNodeSet = set()
for triple in graph:
if isinstance(triple[0], rdflib.BNode):
bNodeSet.add(triple[0])
if isinstance(triple[2], rdflib.BNode):
bNodeSet.add(triple[2])
colourSet = set(graph.colourPartitions[x] for x in bNodeSet)
print("===")
for node in bNodeSet:
print("node {}".format(graph.colourPartitions[node]))
return sorted(colourSet)


# def testContextMerge(self):
# """Test merging two commits."""
#
# # Prepate a git Repository
# content = "<http://ex.org/a> <http://ex.org/b> <http://ex.org/c> ."
# with TemporaryRepositoryFactory().withGraph("http://example.org/", content) as repo:
#
# # Start Quit
# args = quitApp.getDefaults()
# args['targetdir'] = repo.workdirdevelop
# app = create_app(args).test_client()
#
# app.post("/branch", data={"oldbranch": "master", "newbranch": "develop"})
#
# # execute INSERT DATA query
# update = "INSERT DATA {graph <http://example.org/> {<http://ex.org/x> <http://ex.org/y> <http://ex.org/z> .}}"
# app.post('/sparql', data={"query": update})
#
# app = create_app(args).test_client()
# # start new app to syncAll()
#
# update = "INSERT DATA {graph <http://example.org/> {<http://ex.org/z> <http://ex.org/z> <http://ex.org/z> .}}"
# app.post('/sparql/develop?ref=develop', data={"query": update})
#
# app.post("/merge", data={"target": "master", "branch": "develop", "method": "context"})


if __name__ == '__main__':
unittest.main()

0 comments on commit ac133d4

Please sign in to comment.