diff --git a/src/GraphQueries/GraphQueries.g4 b/src/GraphQueries/GraphQueries.g4 new file mode 100644 index 0000000..e92ddfa --- /dev/null +++ b/src/GraphQueries/GraphQueries.g4 @@ -0,0 +1,95 @@ +grammar GraphQueries; + +script : (stmt SEMI)* EOF ; + +stmt : KW_CONNECT KW_TO STRING + | KW_LIST KW_ALL? STRING? + | select_stmt + | named_pattern + ; + +named_pattern : NT_NAME OP_EQ pattern ; + +select_stmt : KW_SELECT func KW_FROM from_expr KW_WHERE where_expr alg? ; + +func : KW_GET + | KW_COUNT + | KW_EXISTS + ; + +alg : KW_USING KW_HELLINGS + | KW_USING KW_MATRICES + | KW_USING KW_TENSORS + ; + +from_expr : graph_expr? STRING + ; + +where_expr : LBR v_expr RBR OP_MINUS pattern OP_MINUS OP_GR LBR v_expr RBR ; + +v_expr : INT + | UNDERSCORE + ; + +graph_expr : STRING + | KW_INTERSEC LBR graph_expr COMMA graph_expr RBR + | KW_UNION LBR graph_expr COMMA graph_expr RBR + | KW_COMPL LBR graph_expr RBR + ; + +pattern : elem + | elem MID pattern + ; + +elem : seq + | LBR RBR + ; + +seq : seq_elem + | seq_elem seq + ; + +seq_elem : prim_pattern + | prim_pattern OP_STAR + ; + +prim_pattern : SYMB + | NT_NAME + | LBR pattern RBR + ; + +LBR : '(' ; +RBR : ')' ; +COMMA : ',' ; +SEMI : ';' ; +MID : '|' ; +DOT : '.' ; +UNDERSCORE : '_' ; +OP_STAR : '*' ; +OP_MINUS : '-' ; +OP_GR : '>' ; +OP_EQ : '=' ; +KW_SELECT : 'select' ; +KW_GET : 'get' ; +KW_COUNT : 'count' ; +KW_EXISTS : 'exists' ; +KW_FROM : 'from' ; +KW_WHERE : 'where' ; +KW_LIST : 'list' ; +KW_ALL : 'all' ; +KW_CONNECT : 'connect' ; +KW_TO : 'to' ; +KW_USING : 'using' ; +KW_HELLINGS : 'hellings' ; +KW_MATRICES : 'matrices' ; +KW_TENSORS : 'tensors' ; +KW_INTERSEC : 'intersec' ; +KW_UNION : 'union' ; +KW_COMPL : 'compl' ; +INT : '0' + | [1-9][0-9]* + ; +SYMB : [a-z]+ ; +NT_NAME : [A-Z]+ ; +STRING : '[' ([a-zA-Z]|[0-9]|('\\' | '-' | '_' | ' ' | '/' | '.' | ',' | ':'))* ']' ; +WS : [ \r\n\t]+ -> skip ; diff --git a/src/GraphQueries/MyGraphQueriesVisitor.py b/src/GraphQueries/MyGraphQueriesVisitor.py new file mode 100644 index 0000000..530a362 --- /dev/null +++ b/src/GraphQueries/MyGraphQueriesVisitor.py @@ -0,0 +1,220 @@ +#!/usr/bin/env python3 +import os +from collections import defaultdict +from antlr4 import * +from chomsky import to_weak_CNF +from algebra import matrix_alg +from algebra import tensor_alg +from chomsky import get_new_nonterm +from cyk import parse_graph +from cyk import Hellings +from graph_lang import * +if __name__ is not None and "." in __name__: + from .GraphQueriesParser import GraphQueriesParser +else: + from GraphQueriesParser import GraphQueriesParser + +# This class defines a complete generic visitor for a parse tree produced by GraphQueriesParser. + +class MyGraphQueriesVisitor(ParseTreeVisitor): + def __init__(self, parent=None): + self.addr = "" + self.prods = defaultdict(str) + + + def get_addr(self): + return self.addr + + + def get_prods(self): + return self.prods.items() + + + def get_res(self, start, finish, nonterm, matrix, n): + res = [] + if start == "_" and finish == "_": + for i in range(n): + for j in range(n): + if matrix[nonterm][i, j]: + res.append((i, j)) + elif start == "_": + for i in range(n): + if matrix[nonterm][i, int(finish)]: + res.append((i, int(finish))) + elif finish == "_": + for i in range(n): + if matrix[nonterm][int(start), i]: + res.append((int(start), i)) + else: + if matrix[nonterm][int(start), int(finish)]: + res.append((int(start), int(finish))) + + return res + + + def select_get_tensors(self, start, finish, pattern, graph): + nonterms = self.prods.keys() + add_nonterm = get_new_nonterm("S", nonterms) + _, matrix, _, n = tensor_alg(list(self.prods.items()) + [(add_nonterm, pattern)], graph) + return self.get_res(start, finish, add_nonterm, matrix, n) + + + def select_get(self, start, finish, pattern, graph, alg): + nonterms = self.prods.keys() + add_nonterm = get_new_nonterm("S", nonterms) + new_prods = [] + for nonterm in self.prods.keys(): + lst = self.prods[nonterm].split(" | ") + new_prods += [(nonterm, element.split()) for element in lst] + new_prods = to_weak_CNF(new_prods + [(add_nonterm, pattern.split())], add_nonterm) + if alg == "hellings": + res = Hellings(new_prods, graph) + else: + res = matrix_alg(new_prods, graph) + ans = [] + if start == "_" and finish == "_": + for nonterm, u, v in res: + if nonterm == add_nonterm: + ans.append((u, v)) + elif start == "_": + for nonterm, u, v in res: + if nonterm == add_nonterm and v == int(finish): + ans.append((u, v)) + elif finish == "_": + for nonterm, u, v in res: + if nonterm == add_nonterm and u == int(start): + ans.append((u, v)) + else: + for nonterm, u, v in res: + if nonterm == add_nonterm and u == int(start) and v == int(finish): + ans.append((u, v)) + + return ans + + + def select_get_graph_lang(self, start, finish, pattern, graph, automata): + nonterms = self.prods.keys() + add_nonterm = get_new_nonterm("S", nonterms) + _, matrix1, _, n1 = tensor_alg(list(self.prods.items()) + [(add_nonterm, pattern)], graph) + _, matrix2, _, n2 = tensor_alg([(add_nonterm, "")], graph, automata) + res1 = self.get_res(start, finish, add_nonterm, matrix1, n1) + res2 = self.get_res(start, finish, add_nonterm, matrix2, n2) + + return sorted(list(set(res1) & set(res2))) + + + # Visit a parse tree produced by GraphQueriesParser#script. + def visitScript(self, ctx:GraphQueriesParser.ScriptContext): + self.visitChildren(ctx) + + + # Visit a parse tree produced by GraphQueriesParser#stmt. + def visitStmt(self, ctx:GraphQueriesParser.StmtContext): + if ctx.getChild(0).getText() == "connect": + self.addr = ctx.STRING().getText()[1:-1] + elif ctx.getChild(0).getText() == "list": + if ctx.getChild(1).getText() == "all": + if ctx.getChildCount() == 3: + path = ctx.STRING().getText()[1:-1] + else: + path = self.addr + for file in sorted(os.listdir(path)): + print(open(os.path.join(path, file), "r").read() + "\n") + else: + filename = ctx.STRING().getText()[1:-1] + labels = set() + with open(os.path.join(filename)) as file: + for line in file.readlines(): + labels.add(line.split()[1]) + print(" ".join(sorted(list(labels)))) + else: + self.visitChildren(ctx) + + + # Visit a parse tree produced by GraphQueriesParser#named_pattern. + def visitNamed_pattern(self, ctx:GraphQueriesParser.Named_patternContext): + nonterm = ctx.NT_NAME().getText() + if self.prods[nonterm]: + self.prods[nonterm] += " | " + self.visitPattern(ctx.pattern()) + else: + self.prods[nonterm] = self.visitPattern(ctx.pattern()) + + + # Visit a parse tree produced by GraphQueriesParser#select_stmt. + def visitSelect_stmt(self, ctx:GraphQueriesParser.Select_stmtContext): + if ctx.from_expr().getChildCount() == 1: + pattern = self.visitPattern(ctx.where_expr().pattern()) + if ctx.getChildCount() == 6 or (ctx.getChildCount() == 7 and ctx.alg().getChild(1).getText() == "tensors"): + res = self.select_get_tensors(ctx.where_expr().getChild(1).getText(), + ctx.where_expr().getChild(8).getText(), pattern, + parse_graph(ctx.from_expr().STRING().getText()[1:-1])) + else: + res = self.select_get(ctx.where_expr().getChild(1).getText(), ctx.where_expr().getChild(8).getText(), + pattern, parse_graph(ctx.from_expr().STRING().getText()[1:-1]), ctx.alg().getChild(1).getText()) + else: + pattern = self.visitPattern(ctx.where_expr().pattern()) + automata = self.visitGraph_expr(ctx.from_expr().graph_expr()) + res = self.select_get_graph_lang(ctx.where_expr().getChild(1).getText(), ctx.where_expr().getChild(8).getText(), + pattern, parse_graph(ctx.from_expr().STRING().getText()[1:-1]), automata) + if ctx.func().getText() == "exists": + if res: + print("exists") + else: + print("does not exist") + elif ctx.func().getText() == "count": + print(len(res)) + else: + for u, v in res: + print(str(u) + " " + str(v)) + + + # Visit a parse tree produced by GraphQueriesParser#graph_expr. + def visitGraph_expr(self, ctx: GraphQueriesParser.Graph_exprContext): + if ctx.getChildCount() == 1: + return build_automata_from_graph(ctx.STRING().getText()[1:-1]) + elif ctx.getChild(0).getText() == "intersec": + return intersec(self.visitGraph_expr(ctx.getChild(2)), self.visitGraph_expr(ctx.getChild(4))) + elif ctx.getChild(0).getText() == "union": + return union(self.visitGraph_expr(ctx.getChild(2)), self.visitGraph_expr(ctx.getChild(4))) + else: + return compl(self.visitGraph_expr(ctx.getChild(2))) + + + # Visit a parse tree produced by GraphQueriesParser#pattern. + def visitPattern(self, ctx:GraphQueriesParser.PatternContext): + if ctx.getChildCount() == 3: + return self.visitElem(ctx.elem()) + " " + ctx.MID().getText() + " " + self.visitPattern(ctx.pattern()) + return self.visitElem(ctx.elem()) + + + # Visit a parse tree produced by GraphQueriesParser#elem. + def visitElem(self, ctx:GraphQueriesParser.ElemContext): + if ctx.getChildCount() == 1: + return self.visitSeq(ctx.seq()) + else: + return "eps" + + + # Visit a parse tree produced by GraphQueriesParser#seq. + def visitSeq(self, ctx:GraphQueriesParser.SeqContext): + if ctx.getChildCount() == 2: + return self.visitSeq_elem(ctx.seq_elem()) + " " + self.visitSeq(ctx.seq()) + else: + return self.visitSeq_elem(ctx.seq_elem()) + + + # Visit a parse tree produced by GraphQueriesParser#seq_elem. + def visitSeq_elem(self, ctx:GraphQueriesParser.Seq_elemContext): + if ctx.getChildCount() == 2: + return self.visitPrim_pattern(ctx.prim_pattern()) + ctx.getChild(1).getText() + return self.visitPrim_pattern(ctx.prim_pattern()) + + + # Visit a parse tree produced by GraphQueriesParser#prim_pattern. + def visitPrim_pattern(self, ctx:GraphQueriesParser.Prim_patternContext): + if ctx.getChildCount() == 3: + return ctx.LBR().getText() + self.visitPattern(ctx.pattern()) + ctx.RBR().getText() + else: return ctx.getChild(0).getText() + + +del GraphQueriesParser diff --git a/src/algebra.py b/src/algebra.py new file mode 100644 index 0000000..b984286 --- /dev/null +++ b/src/algebra.py @@ -0,0 +1,238 @@ +#!/usr/bin/env python3 +import scipy +from collections import defaultdict +from pyformlang.finite_automaton import NondeterministicFiniteAutomaton +from automata import reg2min_dfa +from chomsky import eps +from chomsky import is_term +from chomsky import parse_grammar +from chomsky import print_grammar +from chomsky import to_weak_CNF +from cyk import parse_graph +from cyk import print_res + + +def parse_ext_grammar(filename): + prods = [] + with open(filename) as file: + for line in file.readlines(): + lst = line.split()[1:] + prods.append((line.split()[0], " ".join(lst))) + + return prods + + +def print_res_tensor(start, matrix_automata, matrix_graph, m, n, filename): + ans = [[[] for _ in range(m + 1)] for _ in range(m + 1)] + + for symb in matrix_automata.keys(): + for i in range(m): + for j in range(m): + if matrix_automata[symb][i, j]: + ans[i][j].append(str(symb.value)) + + with open(filename, "w") as file: + for i in range(m): + for j in range(m): + if ans[i][j]: + ans[i][j].sort() + file.write("[" + ", ".join(ans[i][j]) + "] ") + else: + file.write(". ") + file.write("\n") + + for i in range(n): + for j in range(n): + if matrix_graph[start][i, j]: + file.write(str(i) + " " + str(j) + "\n") + + +def matrix_alg(prods, graph): + dict = defaultdict(list) + nonterms = set() + + for prod in prods: + if (len(prod[1]) == 1) and is_term(prod[1][0]): + dict[prod[1][0]].append(prod[0]) + nonterms.add(prod[0]) + + vert = set() + for v, _, u in graph: + vert.add(v) + vert.add(u) + + n = len(vert) + rows = defaultdict(list) + cols = defaultdict(list) + data = defaultdict(list) + + for v, symb, u in graph: + for x in dict[symb]: + rows[x].append(v) + cols[x].append(u) + data[x].append(True) + + for i in range(n): + for x in dict[eps]: + rows[x].append(i) + cols[x].append(i) + data[x].append(True) + + res = defaultdict() + for nonterm in nonterms: + res[nonterm] = scipy.sparse.csr_matrix((data[nonterm], (rows[nonterm], cols[nonterm])), shape=(n, n), dtype=bool) + + change = True + while change: + change = False + for prod in prods: + if len(prod[1]) == 2 and not is_term(prod[1][0]) and not is_term(prod[1][1]): + a = prod[0] + b = prod[1][0] + c = prod[1][1] + if (res[a] != res[a] + res[b] * res[c]).count_nonzero() > 0: + change = True + res[a] = res[a] + res[b] * res[c] + + ans = [] + for symb in res.keys(): + for i in range(n): + for j in range(n): + if res[symb][i, j]: + ans.append((symb, i, j)) + + return ans + + +def build_automata(prods, automata_intersec=None): + start_set = defaultdict(str) + final_set = defaultdict(str) + nodes = defaultdict() + nonterms = set() + eps_nonterms = set() + edges = [] + cnt = 0 + sz = 0 + for prod in prods: + if automata_intersec is not None: + automata = automata_intersec + else: + automata = reg2min_dfa(prod[1]) + nonterm = prod[0] + nonterms.add(nonterm) + dict = automata.to_dict() + state_values = set() + for u in dict.keys(): + state_values.add(u.value) + for symb in dict[u].keys(): + v = dict[u][symb] + state_values.add(v.value) + lst = sorted(list(state_values)) + for value in lst: + nodes[value, cnt] = sz + sz += 1 + for u in dict.keys(): + for symb in dict[u].keys(): + if symb.value == eps: + continue + v = dict[u][symb] + edges.append((nodes[(u.value, cnt)], symb, nodes[(v.value, cnt)])) + if eps in prod[1] or automata.start_state in automata.final_states: + eps_nonterms.add(nonterm) + start_set[nodes[(automata.start_state.value, cnt)]] = nonterm + for state in list(automata.final_states): + final_set[nodes[(state.value, cnt)]] = nonterm + cnt += 1 + + matrix_automata = defaultdict() + rows = defaultdict(list) + cols = defaultdict(list) + data = defaultdict(list) + + for u, symb, v in edges: + rows[symb].append(u) + cols[symb].append(v) + data[symb].append(True) + + for symb in data.keys(): + matrix_automata[symb] = scipy.sparse.csr_matrix((data[symb], (rows[symb], cols[symb])), shape=(sz, sz), dtype=bool) + + start_lst = ["" for _ in range(sz + 1)] + final_lst = ["" for _ in range(sz + 1)] + + for num, nonterm in start_set.items(): + start_lst[num] = nonterm + + for num, nonterm in final_set.items(): + final_lst[num] = nonterm + + return matrix_automata, start_lst, final_lst, edges, eps_nonterms, nonterms, sz + + +def tensor_alg(prods, graph, automata_intersec=None): + matrix_automata, start_set, final_set, edges, eps_nonterms, nonterms, m = build_automata(prods, automata_intersec) + + vert = set() + for v, _, u in graph: + vert.add(v) + vert.add(u) + + n = len(vert) + rows = defaultdict(list) + cols = defaultdict(list) + data = defaultdict(list) + + for v, symb, u in graph: + rows[symb].append(v) + cols[symb].append(u) + data[symb].append(True) + + for i in range(n): + for nonterm in eps_nonterms: + rows[nonterm].append(i) + cols[nonterm].append(i) + data[nonterm].append(True) + + matrix_graph = defaultdict() + symbols = matrix_automata.keys() | data.keys() | nonterms + for symb in symbols: + matrix_graph[symb] = scipy.sparse.csr_matrix((data[symb], (rows[symb], cols[symb])), shape=(n, n), dtype=bool) + + symbols_ = matrix_automata.keys() & matrix_graph.keys() + change = True + k = m * n + while change: + change = False + matrix_prod = scipy.sparse.csr_matrix((k, k), dtype=bool) + for symb in symbols_: + matrix_prod += scipy.sparse.kron(matrix_automata[symb], matrix_graph[symb]) + pow = k - 1 + while pow: + pow //= 2 + matrix_prod += matrix_prod * matrix_prod + r_nnz, c_nnz = matrix_prod.nonzero() + for i, j in zip(r_nnz, c_nnz): + if matrix_prod[i, j]: + s = i // n + f = j // n + if start_set[s] != "" and final_set[f] != "": + x = i % n + y = j % n + if start_set[s] == final_set[f]: + if matrix_graph[start_set[s]][x, y] == False: + change = True + matrix_graph[start_set[s]][x, y] = True + + return matrix_automata, matrix_graph, m, n + + +def solve_matrix_alg(filename_grammar, filename_graph, filename_res): + prods = to_weak_CNF(parse_grammar(filename_grammar)) + res = matrix_alg(prods, parse_graph(filename_graph)) + print_grammar(prods, filename_res) + print_res("S", res, filename_res) + + +def solve_tensor_alg(filename_grammar, filename_graph, filename_res): + matrix_automata, matrix_graph, m, n = tensor_alg(parse_ext_grammar(filename_grammar), parse_graph(filename_graph)) + print_res_tensor("S", matrix_automata, matrix_graph, m, n, filename_res) diff --git a/src/graph_lang.py b/src/graph_lang.py new file mode 100644 index 0000000..f9b2c1b --- /dev/null +++ b/src/graph_lang.py @@ -0,0 +1,45 @@ +#!/usr/bin/env python3 +from pyformlang.finite_automaton import State +from pyformlang.finite_automaton import Symbol +from pyformlang.finite_automaton import NondeterministicFiniteAutomaton +from cyk import parse_graph + + +def build_automata_from_graph(filename): + automata = NondeterministicFiniteAutomaton() + graph = parse_graph(filename) + vert = set() + for u, symb, v in graph: + vert.add(u) + vert.add(v) + for v in vert: + automata.add_start_state(State((filename, v))) + automata.add_final_state(State((filename, v))) + for u, symb, v in graph: + automata.add_transition(State((filename, u)), Symbol(symb), State((filename, v))) + + return automata.minimize() + + +def universal(): + automata = NondeterministicFiniteAutomaton() + node = State(("", 0)) + automata.add_start_state(node) + automata.add_final_state(node) + for chr in "abcdefghijklmnopqrstuvwxyz": + automata.add_transition(node, Symbol(chr), node) + + return automata + + +def intersec(automata1, automata2): + return automata1.get_intersection(automata2).minimize() + + +def union(automata1, automata2): + return compl(intersec(compl(automata1), compl(automata2))).minimize() + + +def compl(automata): + return universal().get_difference(automata).minimize() + diff --git a/syntax_lang.md b/syntax_lang.md new file mode 100644 index 0000000..a5d025f --- /dev/null +++ b/syntax_lang.md @@ -0,0 +1,113 @@ +### syntax: +``` +script: EPS | stmt SEMI script +stmt: KW_CONNECT KW_TO STRING | KW_LIST KW_ALL? STRING? | select_stmt | named_pattern +named_pattern: NT_NAME OP_EQ pattern +select_stmt: KW_SELECT func KW_FROM from_expr KW_WHERE where_expr alg? +func: KW_GET | KW_COUNT | KW_EXISTS +alg: KW_USING KW_HELLINGS | KW_USING KW_MATRICES | KW_USING KW_TENSORS +from_expr: graph_expr? STRING +where_expr: LBR v_expr RBR OP_MINUS pattern OP_MINUS OP_GR LBR v_expr RBR +v_expr: INT | UNDERSCORE +graph_expr: STRING | KW_INTERSEC LBR graph_expr COMMA graph_expr RBR | +KW_UNION LBR graph_expr COMMA graph_expr RBR | KW_COMPL LBR graph_expr RBR +pattern: elem | elem MID pattern +elem: seq | LBR RBR +seq: seq_elem | seq_elem seq +seq_elem: prim_pattern | prim_pattern OP_STAR +prim_pattern: SYMB | NT_NAME | LBR pattern RBR +``` +### tokens (terminals): +``` +LBR = "(" +RBR = ")" +COMMA = "," +SEMI = ";" +MID = "|" +DOT = "." +UNDERSCORE = "_" +EPS = "" +OP_STAR = "*" +OP_MINUS = "-" +OP_GR = ">" +OP_EQ = "=" +KW_SELECT = "select" +KW_GET = "get" +KW_COUNT = "count" +KW_EXISTS = "exists" +KW_FROM = "from" +KW_WHERE = "where" +KW_LIST = "list" +KW_ALL : "all" ; +KW_CONNECT = "connect" +KW_TO = "to" +KW_USING = 'using' +KW_HELLINGS = "hellings" +KW_MATRICES = "matrices" +KW_TENSORS = "tensors" +KW_INTERSEC = "intersec" +KW_UNION = "union" +KW_COMPL = "compl" +SYMB = [a − z][a − z]* +INT = 0 | [1 − 9][0 − 9]* +NT_NAME = [A − Z]+ +STRING = "["([aA − zZ] | [0 − 9] | ("\\" | "-"| " " | "_" | "/" | "." | "," | ":"))*"]" +``` +### examples: + +#### patterns +``` +a S (a | b)* +() | (a S)* +``` +#### named patterns +``` +S = a S b | () +A = (a)* +``` +#### connect +``` +connect to [\home\user\graph_db] +``` +#### list + +###### by default displays graphs from the connected database if no path is specified +``` +list all +list all [\home\user\another_graph_db] +``` +###### print set of different edge labels in the specified graph +``` +list [\home\user\agraph_db\graph1.txt] +``` +#### select statements + +###### it is possible to specify the vertex number or write underscore instead (vertex with any number) +###### getting all pairs of vertices that match the conditions: +``` +select get from [graph1.txt] where (_) - (a | b)* -> (_) +``` +###### finding the number of pairs of vertices that match the conditions: +``` +select count from [graph1.txt] where (2) - (a | b)* -> (_) +``` +###### checking for the existence of a pair of vertices that match the conditions: +``` +select exists from [graph1.txt] where (1) - S -> (3) +``` +###### it is possible to specify the used algorithm: "using hellings", "using matrices" or "using tensors" (by default the algorithm with tensors is used): +``` +select count from [graph1.txt] where (2) - (a | b)* -> (_) using hellings +``` +###### adding a graph expression means that between the required pairs of vertices there must be a path belonging to the language generated by this expression + +``` +select count from intersec ([graph1.txt], compl ([graph2.txt])) [graph3.txt] where (_) - S -> (3) +``` +#### script +``` +connect to [\home\user\graph_db]; +S = a S b S | (); +select count from [graph.txt] where (_) - S -> (1); +``` + diff --git a/test/graph_queries_tests.py b/test/graph_queries_tests.py new file mode 100644 index 0000000..6266ef9 --- /dev/null +++ b/test/graph_queries_tests.py @@ -0,0 +1,672 @@ +#!/usr/bin/env python3 +import pytest +import os +from antlr_parser import get_stream +from antlr_parser import parse +from MyGraphQueriesVisitor import MyGraphQueriesVisitor + + +def process(stream): + tree = parse(stream) + visitor = MyGraphQueriesVisitor() + visitor.visit(tree) + + return visitor + + +def test_connect1(tmp_path): + tmp_file = tmp_path / "file.txt" + tmp_file.write_text("connect to [home/graph_db];") + visitor = process(get_stream(True, os.path.normpath(tmp_file))) + + assert visitor.get_addr() == "home/graph_db" + + +def test_connect2(tmp_path): + tmp_file = tmp_path / "file.txt" + tmp_file.write_text("connect to [home/graph_db];\nconnect to [home/another_graph_db];") + visitor = process(get_stream(True, os.path.normpath(tmp_file))) + + assert visitor.get_addr() == "home/another_graph_db" + + +def test_list1(tmp_path, capsys): + top_dir = tmp_path / "top_dir" + top_dir.mkdir() + file1 = top_dir / "graph1.txt" + file2 = top_dir / "graph2.txt" + file1.write_text("0 a 1\n1 b 2") + file2.write_text("0 a 1\n1 a 0") + file_in = tmp_path / "file.txt" + file_in.write_text("connect to [" + os.path.normpath(top_dir) + "];\nlist all;") + process(get_stream(True, os.path.normpath(file_in))) + out, err = capsys.readouterr() + + assert out == "0 a 1\n1 b 2\n\n0 a 1\n1 a 0\n\n" + assert err == "" + + +def test_list2(tmp_path, capsys): + dir1 = tmp_path / "dir1" + dir1.mkdir() + dir2 = tmp_path / "dir2" + dir2.mkdir() + file1 = dir1 / "graph1.txt" + file2 = dir2 / "graph2.txt" + file1.write_text("0 a 1\n1 b 2") + file2.write_text("0 a 1\n1 a 0") + file_in = tmp_path / "file.txt" + file_in.write_text("connect to [" + os.path.normpath(dir1) + "];\nlist all [" + os.path.normpath(dir2) + "];") + process(get_stream(True, os.path.normpath(file_in))) + out, err = capsys.readouterr() + + assert out == "0 a 1\n1 a 0\n\n" + assert err == "" + + +def test_list3(tmp_path, capsys): + dir1 = tmp_path / "dir1" + dir1.mkdir() + file1 = dir1 / "graph1.txt" + file2 = dir1 / "graph2.txt" + file1.write_text("0 a 1\n1 b 2\n2 c 3") + file2.write_text("0 a 1\n1 a 0\n1 b 2") + file_in = tmp_path / "file.txt" + file_in.write_text("connect to [" + os.path.normpath(dir1) + "];\nlist [" + os.path.normpath(file2) + "];") + process(get_stream(True, os.path.normpath(file_in))) + out, err = capsys.readouterr() + + assert out == "a b\n" + assert err == "" + + +def test_list4(tmp_path, capsys): + file1 = tmp_path / "graph1.txt" + file2 = tmp_path / "graph2.txt" + file1.write_text("0 a 1\n1 b 2\n2 c 3") + file2.write_text("0 d 1\n1 d 0\n1 d 2\n2 c 1") + file_in = tmp_path / "file.txt" + file_in.write_text("list [" + os.path.normpath(file2) + "];") + process(get_stream(True, os.path.normpath(file_in))) + out, err = capsys.readouterr() + + assert out == "c d\n" + assert err == "" + + +def test_named_pattern1(tmp_path): + tmp_file = tmp_path / "file.txt" + tmp_file.write_text("S = a S b S;") + visitor = process(get_stream(True, os.path.normpath(tmp_file))) + prods = visitor.get_prods() + + assert len(prods) == 1 + assert ("S", "a S b S") in prods + + +def test_named_pattern2(tmp_path): + tmp_file = tmp_path / "file.txt" + tmp_file.write_text("S = a S b S;\nA = a;") + visitor = process(get_stream(True, os.path.normpath(tmp_file))) + prods = visitor.get_prods() + + assert len(prods) == 2 + assert ("S", "a S b S") in prods + assert ("A", "a") in prods + + +def test_named_pattern3(tmp_path): + tmp_file = tmp_path / "file.txt" + tmp_file.write_text("S = a S b S;\nconnect to [data_base];\nS = A B;") + visitor = process(get_stream(True, os.path.normpath(tmp_file))) + prods = visitor.get_prods() + + assert len(prods) == 1 + assert ("S", "a S b S | A B") in prods + + +def test_named_pattern4(tmp_path): + tmp_file = tmp_path / "file.txt" + tmp_file.write_text("S = a b c;\nS = (c S c)*;") + visitor = process(get_stream(True, os.path.normpath(tmp_file))) + prods = visitor.get_prods() + + assert len(prods) == 1 + assert ("S", "a b c | (c S c)*") in prods + + +def test_named_pattern5(tmp_path): + tmp_file = tmp_path / "file.txt" + tmp_file.write_text("A = (a B b)* | c d c (A b)* | (a | c)*;") + visitor = process(get_stream(True, os.path.normpath(tmp_file))) + prods = visitor.get_prods() + + assert len(prods) == 1 + assert ("A", "(a B b)* | c d c (A b)* | (a | c)*") in prods + + + +def test_select_exists1(tmp_path, capsys): + file_script = tmp_path / "script.txt" + file_graph = tmp_path / "graph.txt" + file_graph.write_text("0 a 1\n1 b 0") + file_script.write_text("S = a S b S;\nS = ();\nselect exists from [" + os.path.normpath(file_graph) + "] where (_) - S -> (_);") + process(get_stream(True, os.path.normpath(file_script))) + out, err = capsys.readouterr() + + assert out == "exists\n" + assert err == "" + + +def test_select_exists2(tmp_path, capsys): + file_script = tmp_path / "script.txt" + file_graph = tmp_path / "graph.txt" + file_graph.write_text("0 a 1\n1 b 0") + file_script.write_text("S = a S b S;\nS = ();\nselect exists from [" + os.path.normpath(file_graph) + "] where (_) - S -> (_);") + process(get_stream(True, os.path.normpath(file_script))) + out, err = capsys.readouterr() + + assert out == "exists\n" + assert err == "" + + +def test_select_exists3(tmp_path, capsys): + file_script = tmp_path / "script.txt" + file_graph = tmp_path / "graph.txt" + file_graph.write_text("0 a 1\n1 a 0") + file_script.write_text("S = a S b S;\nselect exists from [" + os.path.normpath(file_graph) + "] where (_) - S -> (_);") + process(get_stream(True, os.path.normpath(file_script))) + out, err = capsys.readouterr() + + assert out == "does not exist\n" + assert err == "" + + +def test_select_exists4(tmp_path, capsys): + file_script = tmp_path / "script.txt" + file_graph = tmp_path / "graph.txt" + file_graph.write_text("0 a 1\n1 b 2\n2 c 3") + file_script.write_text("select exists from [" + os.path.normpath(file_graph) + "] where (_) - a b c -> (_);") + process(get_stream(True, os.path.normpath(file_script))) + out, err = capsys.readouterr() + + assert out == "exists\n" + assert err == "" + + +def test_select_exists5(tmp_path, capsys): + file_script = tmp_path / "script.txt" + file_graph = tmp_path / "graph.txt" + file_graph.write_text("0 a 1\n1 b 2\n2 c 3") + file_script.write_text("select exists from [" + os.path.normpath(file_graph) + "] where (_) - a b b -> (_);") + process(get_stream(True, os.path.normpath(file_script))) + out, err = capsys.readouterr() + + assert out == "does not exist\n" + assert err == "" + + +def test_select_exists6(tmp_path, capsys): + file_script = tmp_path / "script.txt" + file_graph = tmp_path / "graph.txt" + file_graph.write_text("0 b 1\n1 a 2\n2 b 1") + file_script.write_text("A = a;\nB = b;\nselect exists from [" + os.path.normpath(file_graph) + "] where (_) - A B -> (_);") + process(get_stream(True, os.path.normpath(file_script))) + out, err = capsys.readouterr() + + assert out == "exists\n" + assert err == "" + + +def test_select_exists7(tmp_path, capsys): + file_script = tmp_path / "script.txt" + file_graph = tmp_path / "graph.txt" + file_graph.write_text("0 a 1\n1 a 0") + file_script.write_text("S = a S b S;\nS = ();\nselect exists from [" + os.path.normpath(file_graph) + "] where (_) - S -> (_);") + process(get_stream(True, os.path.normpath(file_script))) + out, err = capsys.readouterr() + + assert out == "exists\n" + assert err == "" + + +def test_select_exists8(tmp_path, capsys): + file_script = tmp_path / "script.txt" + file_graph = tmp_path / "graph.txt" + file_graph.write_text("0 a 1\n1 b 2\n2 a 3") + file_script.write_text("S = a | ();\nselect exists from [" + os.path.normpath(file_graph) + "] where (0) - a b S -> (3);") + process(get_stream(True, os.path.normpath(file_script))) + out, err = capsys.readouterr() + + assert out == "exists\n" + assert err == "" + + +def test_select_exists9(tmp_path, capsys): + file_script = tmp_path / "script.txt" + file_graph = tmp_path / "graph.txt" + file_graph.write_text("0 a 1\n1 b 2\n2 a 3") + file_script.write_text("S = a | ();\nselect exists from [" + os.path.normpath(file_graph) + "] where (0) - a b b S -> (3);") + process(get_stream(True, os.path.normpath(file_script))) + out, err = capsys.readouterr() + + assert out == "does not exist\n" + assert err == "" + + +def test_select_exists10(tmp_path, capsys): + file_script = tmp_path / "script.txt" + file_graph = tmp_path / "graph.txt" + file_graph.write_text("0 a 1\n1 b 2\n2 a 3") + file_script.write_text("S = a | ();\nselect exists from [" + os.path.normpath(file_graph) + "] where (0) - a S S S -> (_);") + process(get_stream(True, os.path.normpath(file_script))) + out, err = capsys.readouterr() + + assert out == "exists\n" + assert err == "" + + +def test_select_count1(tmp_path, capsys): + file_script = tmp_path / "script.txt" + file_graph = tmp_path / "graph.txt" + file_graph.write_text("0 a 1\n1 b 2\n1 c 3") + file_script.write_text("S = a (b | c);\nselect count from [" + os.path.normpath(file_graph) + "] where (0) - S -> (_);") + process(get_stream(True, os.path.normpath(file_script))) + out, err = capsys.readouterr() + + assert out == "2\n" + assert err == "" + + +def test_select_count2(tmp_path, capsys): + file_script = tmp_path / "script.txt" + file_graph = tmp_path / "graph.txt" + file_graph.write_text("0 a 1\n1 b 2\n1 c 3\n2 a 4") + file_script.write_text("S = a | b | eps;\nselect count from [" + os.path.normpath(file_graph) + "] where (0) - S -> (_);") + process(get_stream(True, os.path.normpath(file_script))) + out, err = capsys.readouterr() + + assert out == "2\n" + assert err == "" + + +def test_select_count3(tmp_path, capsys): + file_script = tmp_path / "script.txt" + file_graph = tmp_path / "graph.txt" + file_graph.write_text("0 a 1\n1 b 2\n1 c 3\n2 a 4") + file_script.write_text("select count from [" + os.path.normpath(file_graph) + "] where (0) - (a | b)* -> (_);") + process(get_stream(True, os.path.normpath(file_script))) + out, err = capsys.readouterr() + + assert out == "4\n" + assert err == "" + + +def test_select_count4(tmp_path, capsys): + file_script = tmp_path / "script.txt" + file_graph = tmp_path / "graph.txt" + file_graph.write_text("0 a 1\n1 b 2\n1 c 3\n2 a 4") + file_script.write_text("select count from [" + os.path.normpath(file_graph) + "] where (_) - a b -> (0);") + process(get_stream(True, os.path.normpath(file_script))) + out, err = capsys.readouterr() + + assert out == "0\n" + assert err == "" + + +def test_select_count5(tmp_path, capsys): + file_script = tmp_path / "script.txt" + file_graph = tmp_path / "graph.txt" + file_graph.write_text("0 a 1\n1 b 2\n1 c 3\n2 a 4") + file_script.write_text("select count from [" + os.path.normpath(file_graph) + "] where (_) - a b -> (_);") + process(get_stream(True, os.path.normpath(file_script))) + out, err = capsys.readouterr() + + assert out == "1\n" + assert err == "" + + +def test_select_count6(tmp_path, capsys): + file_script = tmp_path / "script.txt" + file_graph = tmp_path / "graph.txt" + file_graph.write_text("0 a 1\n1 b 2\n1 c 3\n2 a 4") + file_script.write_text("select count from [" + os.path.normpath(file_graph) + "] where (1) - (a | b)* | c -> (_);") + process(get_stream(True, os.path.normpath(file_script))) + out, err = capsys.readouterr() + + assert out == "4\n" + assert err == "" + + +def test_select_count7(tmp_path, capsys): + file_script = tmp_path / "script.txt" + file_graph = tmp_path / "graph.txt" + file_graph.write_text("0 a 1\n1 b 2\n2 a 3") + file_script.write_text("S = a | ();\nselect count from [" + os.path.normpath(file_graph) + "] where (_) - S S S -> (_);") + process(get_stream(True, os.path.normpath(file_script))) + out, err = capsys.readouterr() + + assert out == "6\n" + assert err == "" + + +def test_select_get1(tmp_path, capsys): + file_script = tmp_path / "script.txt" + file_graph = tmp_path / "graph.txt" + file_graph.write_text("0 a 1\n1 b 2\n1 c 3") + file_script.write_text("S = a (b | c);\nselect get from [" + os.path.normpath(file_graph) + "] where (0) - S -> (_);") + process(get_stream(True, os.path.normpath(file_script))) + out, err = capsys.readouterr() + + assert out == "0 2\n0 3\n" + assert err == "" + + +def test_select_get2(tmp_path, capsys): + file_script = tmp_path / "script.txt" + file_graph = tmp_path / "graph.txt" + file_graph.write_text("0 a 1\n1 b 2\n1 c 3\n2 a 4") + file_script.write_text("select get from [" + os.path.normpath(file_graph) + "] where (0) - (a | b)* -> (_);") + process(get_stream(True, os.path.normpath(file_script))) + out, err = capsys.readouterr() + + assert out == "0 0\n0 1\n0 2\n0 4\n" + assert err == "" + + +def test_select_get3(tmp_path, capsys): + file_script = tmp_path / "script.txt" + file_graph = tmp_path / "graph.txt" + file_graph.write_text("0 a 1\n1 b 2\n1 c 3\n2 a 4") + file_script.write_text("select get from [" + os.path.normpath(file_graph) + "] where (_) - a b -> (0);") + process(get_stream(True, os.path.normpath(file_script))) + out, err = capsys.readouterr() + + assert out == "" + assert err == "" + + +def test_select_get4(tmp_path, capsys): + file_script = tmp_path / "script.txt" + file_graph = tmp_path / "graph.txt" + file_graph.write_text("0 a 1\n1 b 2\n1 c 3\n2 a 4") + file_script.write_text("select get from [" + os.path.normpath(file_graph) + "] where (_) - (a | b)* | c -> (_);") + process(get_stream(True, os.path.normpath(file_script))) + out, err = capsys.readouterr() + + assert out == "0 0\n0 1\n0 2\n0 4\n1 1\n1 2\n1 3\n1 4\n2 2\n2 4\n3 3\n4 4\n" + assert err == "" + + +def test_select_get5(tmp_path, capsys): + file_script = tmp_path / "script.txt" + file_graph = tmp_path / "graph.txt" + file_graph.write_text("0 a 1\n1 b 2\n2 a 3") + file_script.write_text("S = A B;\nA = a | ();\nB = b | ();\nselect get from [" + os.path.normpath(file_graph) + "]\ + where (_) - S -> (2);") + process(get_stream(True, os.path.normpath(file_script))) + out, err = capsys.readouterr() + + assert out == "0 2\n1 2\n2 2\n" + assert err == "" + + +def test_script(tmp_path, capsys): + file_script = tmp_path / "script.txt" + file_graph = tmp_path / "graph.txt" + file_graph.write_text("0 a 1\n1 b 2\n1 c 3\n2 a 4") + file_script.write_text("select count from [" + os.path.normpath(file_graph) + "] where (0) - (a | b)* -> (_);\n\ + S = (a | b)*;\nselect get from [" + os.path.normpath(file_graph) + "] where (0) - S -> (_);") + process(get_stream(True, os.path.normpath(file_script))) + out, err = capsys.readouterr() + + assert out == "4\n0 0\n0 1\n0 2\n0 4\n" + assert err == "" + + +def test_select_using_hellings1(tmp_path, capsys): + file_script = tmp_path / "script.txt" + file_graph = tmp_path / "graph.txt" + file_graph.write_text("0 a 1\n1 a 0") + file_script.write_text("S = a S b S;\nS = ();\nselect exists from [" + os.path.normpath(file_graph) + "] where (_) - S -> (_) using hellings;") + process(get_stream(True, os.path.normpath(file_script))) + out, err = capsys.readouterr() + + assert out == "exists\n" + assert err == "" + + +def test_select_using_hellings2(tmp_path, capsys): + file_script = tmp_path / "script.txt" + file_graph = tmp_path / "graph.txt" + file_graph.write_text("0 a 1\n1 b 2\n2 c 3") + file_script.write_text("select exists from [" + os.path.normpath(file_graph) + "] where (_) - a b b -> (_) using hellings;") + process(get_stream(True, os.path.normpath(file_script))) + out, err = capsys.readouterr() + + assert out == "does not exist\n" + assert err == "" + + +def test_select_using_matrices(tmp_path, capsys): + file_script = tmp_path / "script.txt" + file_graph = tmp_path / "graph.txt" + file_graph.write_text("0 a 1\n1 b 2\n2 a 3") + file_script.write_text("S = a;\nS = ();\nselect count from [" + os.path.normpath(file_graph) + "] where (_) - S S S -> (_) using matrices;") + process(get_stream(True, os.path.normpath(file_script))) + out, err = capsys.readouterr() + + assert out == "6\n" + assert err == "" + + +def test_select_using_tensors(tmp_path, capsys): + file_script = tmp_path / "script.txt" + file_graph = tmp_path / "graph.txt" + file_graph.write_text("0 a 1\n1 b 2\n2 a 3") + file_script.write_text("S = A B;\nA = a | ();\nB = b | ();\nselect get from [" + os.path.normpath(file_graph) + "]\ + where (_) - S -> (2) using tensors;") + process(get_stream(True, os.path.normpath(file_script))) + out, err = capsys.readouterr() + + assert out == "0 2\n1 2\n2 2\n" + assert err == "" + + +def test_select_graph_lang1(tmp_path, capsys): + file_script = tmp_path / "script.txt" + file_graph1 = tmp_path / "graph1.txt" + file_graph2 = tmp_path / "graph2.txt" + file_graph3 = tmp_path / "graph3.txt" + file_graph1.write_text("0 a 1\n1 a 2\n2 b 3") + file_graph2.write_text("0 b 1\n1 a 2\n2 c 3") + file_graph3.write_text("0 a 1\n1 b 2\n2 c 3") + file_script.write_text("select get from intersec ([" + os.path.normpath(file_graph1) + "], [" + \ + os.path.normpath(file_graph2) + "]) [" + os.path.normpath(file_graph3) + "] where (_) - (a | b | c)* -> (_);") + process(get_stream(True, os.path.normpath(file_script))) + out, err = capsys.readouterr() + + assert out == "0 0\n0 1\n1 1\n1 2\n2 2\n3 3\n" + assert err == "" + + +def test_select_graph_lang2(tmp_path, capsys): + file_script = tmp_path / "script.txt" + file_graph1 = tmp_path / "graph1.txt" + file_graph2 = tmp_path / "graph2.txt" + file_graph3 = tmp_path / "graph3.txt" + file_graph1.write_text("0 a 1\n1 a 2\n2 b 3") + file_graph2.write_text("0 a 1\n1 b 2\n2 c 3") + file_graph3.write_text("0 a 1\n1 b 2\n2 c 3") + file_script.write_text("select get from intersec ([" + os.path.normpath(file_graph1) + "], [" + \ + os.path.normpath(file_graph2) + "]) [" + os.path.normpath(file_graph3) + "] where (_) - (a | b | c)* -> (_);") + process(get_stream(True, os.path.normpath(file_script))) + out, err = capsys.readouterr() + + assert out == "0 0\n0 1\n0 2\n1 1\n1 2\n2 2\n3 3\n" + assert err == "" + + +def test_select_graph_lang3(tmp_path, capsys): + file_script = tmp_path / "script.txt" + file_graph1 = tmp_path / "graph1.txt" + file_graph2 = tmp_path / "graph2.txt" + file_graph3 = tmp_path / "graph3.txt" + file_graph1.write_text("0 a 1\n1 b 2\n2 c 0") + file_graph2.write_text("0 a 1\n1 b 2\n2 c 3\n3 a 0") + file_graph3.write_text("0 a 1\n1 b 2\n2 c 3\n3 b 0") + file_script.write_text("select get from intersec ([" + os.path.normpath(file_graph1) + "], [" + \ + os.path.normpath(file_graph2) + "]) [" + os.path.normpath(file_graph3) + "] where (1) - (a | b | c)* -> (_);") + process(get_stream(True, os.path.normpath(file_script))) + out, err = capsys.readouterr() + + assert out == "1 1\n1 2\n1 3\n" + assert err == "" + + +def test_select_graph_lang4(tmp_path, capsys): + file_script = tmp_path / "script.txt" + file_graph1 = tmp_path / "graph1.txt" + file_graph2 = tmp_path / "graph2.txt" + file_graph3 = tmp_path / "graph3.txt" + file_graph1.write_text("0 b 1\n1 b 2\n2 c 0") + file_graph2.write_text("0 a 1\n1 b 2\n2 c 3\n3 a 0") + file_graph3.write_text("0 a 1\n1 b 2\n2 c 3\n3 b 0") + file_script.write_text("select get from intersec ([" + os.path.normpath(file_graph1) + "], [" + \ + os.path.normpath(file_graph2) + "]) [" + os.path.normpath(file_graph3) + "] where (_) - a | b | c -> (_);") + process(get_stream(True, os.path.normpath(file_script))) + out, err = capsys.readouterr() + + assert out == "1 2\n2 3\n3 0\n" + assert err == "" + + +def test_select_graph_lang5(tmp_path, capsys): + file_script = tmp_path / "script.txt" + file_graph1 = tmp_path / "graph1.txt" + file_graph2 = tmp_path / "graph2.txt" + file_graph3 = tmp_path / "graph3.txt" + file_graph1.write_text("0 a 1\n1 c 2\n2 c 3") + file_graph2.write_text("0 b 1\n1 c 2") + file_graph3.write_text("0 a 1\n1 b 2\n2 c 3") + file_script.write_text("select get from union ([" + os.path.normpath(file_graph1) + "], [" + \ + os.path.normpath(file_graph2) + "]) [" + os.path.normpath(file_graph3) + "] where (_) - (a | b | c)* -> (_);") + process(get_stream(True, os.path.normpath(file_script))) + out, err = capsys.readouterr() + + assert out == "0 0\n0 1\n1 1\n1 2\n1 3\n2 2\n2 3\n3 3\n" + assert err == "" + + +def test_select_graph_lang6(tmp_path, capsys): + file_script = tmp_path / "script.txt" + file_graph1 = tmp_path / "graph1.txt" + file_graph2 = tmp_path / "graph2.txt" + file_graph3 = tmp_path / "graph3.txt" + file_graph1.write_text("0 a 1\n1 c 2\n2 c 3") + file_graph2.write_text("0 b 1\n1 c 2") + file_graph3.write_text("0 a 1\n1 b 2\n2 c 3") + file_script.write_text("S = a | b c;\nselect get from union ([" + os.path.normpath(file_graph1) + "], [" + \ + os.path.normpath(file_graph2) + "]) [" + os.path.normpath(file_graph3) + "] where (_) - S -> (_);") + process(get_stream(True, os.path.normpath(file_script))) + out, err = capsys.readouterr() + + assert out == "0 1\n1 3\n" + assert err == "" + + +def test_select_graph_lang7(tmp_path, capsys): + file_script = tmp_path / "script.txt" + file_graph1 = tmp_path / "graph1.txt" + file_graph2 = tmp_path / "graph2.txt" + file_graph3 = tmp_path / "graph3.txt" + file_graph1.write_text("0 a 1\n1 b 2\n2 c 3\n3 c 0") + file_graph2.write_text("0 a 1\n1 a 2") + file_graph3.write_text("0 a 1\n1 a 2\n2 a 3\n2 b 1\n1 c 0") + file_script.write_text("S = a | b c | ();\nselect get from union ([" + os.path.normpath(file_graph1) + "], [" + \ + os.path.normpath(file_graph2) + "]) [" + os.path.normpath(file_graph3) + "] where (_) - a S -> (_);") + process(get_stream(True, os.path.normpath(file_script))) + out, err = capsys.readouterr() + + assert out == "0 1\n0 2\n1 0\n1 2\n1 3\n2 3\n" + assert err == "" + + +def test_select_graph_lang7(tmp_path, capsys): + file_script = tmp_path / "script.txt" + file_graph1 = tmp_path / "graph1.txt" + file_graph2 = tmp_path / "graph2.txt" + file_graph1.write_text("0 a 1\n1 b 2\n2 c 3") + file_graph2.write_text("0 a 1\n1 a 2\n2 c 3") + file_script.write_text("select get from compl ([" + os.path.normpath(file_graph1) + "]) \ + [" + os.path.normpath(file_graph2) + "] where (_) - (a | b | c)* -> (_);") + process(get_stream(True, os.path.normpath(file_script))) + out, err = capsys.readouterr() + + assert out == "0 2\n0 3\n1 3\n" + assert err == "" + + +def test_select_graph_lang8(tmp_path, capsys): + file_script = tmp_path / "script.txt" + file_graph1 = tmp_path / "graph1.txt" + file_graph2 = tmp_path / "graph2.txt" + file_graph1.write_text("0 a 1\n1 b 2\n2 c 3") + file_graph2.write_text("0 a 1\n1 a 2\n2 c 3") + file_script.write_text("S = (a | b | c)*;\nselect get from compl ([" + os.path.normpath(file_graph1) + "]) \ + [" + os.path.normpath(file_graph2) + "] where (_) - S -> (3);") + process(get_stream(True, os.path.normpath(file_script))) + out, err = capsys.readouterr() + + assert out == "0 3\n1 3\n" + assert err == "" + + +def test_select_graph_lang9(tmp_path, capsys): + file_script = tmp_path / "script.txt" + file_graph1 = tmp_path / "graph1.txt" + file_graph2 = tmp_path / "graph2.txt" + file_graph1.write_text("0 a 1\n1 b 2\n2 c 3") + file_graph2.write_text("0 a 1\n1 b 2\n2 c 3\n3 a 4") + file_script.write_text("select get from compl ([" + os.path.normpath(file_graph1) + "]) \ + [" + os.path.normpath(file_graph2) + "] where (_) - a | b c -> (_);") + process(get_stream(True, os.path.normpath(file_script))) + out, err = capsys.readouterr() + + assert out == "" + assert err == "" + + +def test_select_graph_lang10(tmp_path, capsys): + file_script = tmp_path / "script.txt" + file_graph1 = tmp_path / "graph1.txt" + file_graph2 = tmp_path / "graph2.txt" + file_graph3 = tmp_path / "graph3.txt" + file_graph1.write_text("0 a 1\n1 b 2\n2 c 3\n3 c 0") + file_graph2.write_text("0 a 1\n1 a 2") + file_graph3.write_text("0 a 1\n1 a 2\n2 a 3\n2 b 1\n1 c 0") + file_script.write_text("select get from union ([" + os.path.normpath(file_graph1) + "], intersec ([" \ + + os.path.normpath(file_graph2) + "], [" + os.path.normpath(file_graph3) + "])) [" \ + + os.path.normpath(file_graph3) + "] where (0) - (a | b | c)* -> (_);") + process(get_stream(True, os.path.normpath(file_script))) + out, err = capsys.readouterr() + + assert out == "0 0\n0 1\n0 2\n" + assert err == "" + + +def test_select_graph_lang11(tmp_path, capsys): + file_script = tmp_path / "script.txt" + file_graph1 = tmp_path / "graph1.txt" + file_graph2 = tmp_path / "graph2.txt" + file_graph3 = tmp_path / "graph3.txt" + file_graph1.write_text("0 a 1\n1 b 2\n2 c 3\n3 c 0") + file_graph2.write_text("0 a 1\n1 a 2\n1 b 2") + file_graph3.write_text("0 a 1\n1 a 2\n2 a 3\n2 b 1\n1 c 0") + file_script.write_text("select get from compl (intersec ([" + os.path.normpath(file_graph1) + "], [" + \ + os.path.normpath(file_graph2) + "])) [" + os.path.normpath(file_graph3) + "] where (_) - a | b | c -> (0);") + process(get_stream(True, os.path.normpath(file_script))) + out, err = capsys.readouterr() + + assert out == "1 0\n" + assert err == ""