Browse Source

Pass basic test.

Stefano Cossu 2 years ago
parent
commit
9785f83782
6 changed files with 230 additions and 57 deletions
  1. 73 26
      Makefile
  2. 3 3
      include/desc.h
  3. 20 3
      src/core.c
  4. 77 23
      src/desc.c
  5. 2 2
      test.c
  6. 55 0
      test/test_desc.c

+ 73 - 26
Makefile

@@ -8,7 +8,7 @@ AR = ar
 
 ## Paths.
 
-PREFIX = /usr/local
+PREFIX ?= /usr/local
 bindir = $(PREFIX)/bin
 libdir = $(PREFIX)/lib
 includedir = $(PREFIX)/include/lsup
@@ -16,83 +16,130 @@ includedir = $(PREFIX)/include/lsup
 INCLUDE = -I. -Iinclude -I$(includedir)
 # Link all ext libraries statically.
 CFLAGS += -Wall -fPIC -MMD $(INCLUDE)
-TEST_CFLAGS = -Itest -O0 -g3 -DDEBUG
-LDFLAGS = -llsuprdf
+DBG_CFLAGS = -Itest -O0 -g3 -DDEBUG
+LDFLAGS = -L. -L$(libdir) -llsuprdf -luuid
+DBG_LDFLAGS = -L. -L$(libdir) -llsuprdf_dbg -luuid
 
 SRC = $(wildcard src/*.c)
 OBJ = $(SRC:.c=.o)
+DBG_OBJ = $(SRC:.c=_dbg.o)
 
 TEST_SRC = $(wildcard test/*.c) test.c
 
 LIBS = liblsuprepo.a liblsuprepo.so
+DBG_LIBS = liblsuprepo_dbg.a liblsuprepo_dbg.so
+
+
+## Environment.
+
+export LD_LIBRARY_PATH = $(libdir):.
 
 
 ## Rules.
 
-all: $(LIBS)
+.DEFAULT_GOAL := lib
+
+
+# Extract all rule comment into a help message.
+.PHONY: help
+help:
+	@echo "Command overview:"; echo; \
+		grep -E '^[a-zA-Z0-9_-]+:.*?## .*$$' $(MAKEFILE_LIST) \
+		| sed -n 's/^\(.*\): \(.*\)##\(.*\)/\1::\3/p' \
+		| column -t  -s '::'
+
+
+lib: $(LIBS)
+
+
+debug: $(DBG_LIBS)
+
 
 liblsuprepo.a: $(OBJ)
 	$(AR) rs $@ $^
 
+
 liblsuprepo.so: $(OBJ)
 	$(CC) -shared $(LDFLAGS) -o $@ $^
 
 
-install: all
+liblsuprepo_dbg.a: $(DBG_OBJ)
+	$(AR) rs $@ $^
+
+
+liblsuprepo_dbg.so: $(DBG_OBJ)
+	$(CC) -shared $(LDFLAGS) -o $@ $^
+
+
+# Debug objects.
+%_dbg.o: %.c
+	$(CC) $(CFLAGS) $(DBG_CFLAGS) $(LDFLAGS) -c $^ -o $@
+
+
+install: lib ## Install default libraries to $PREFIX. May require sudo.
 	mkdir -p $(DESTDIR)$(libdir)
 	mkdir -p $(DESTDIR)$(includedir)
 	cp liblsuprepo.* $(DESTDIR)$(libdir) && \
 		cp include/*.h $(EXT_H) $(DESTDIR)$(includedir)
+
+
+debug_install: install debug ## Install default and debug libraries.
+	cp liblsuprdf_dbg.{a,so} $(DESTDIR)$(libdir)
 	
+
 .PHONY: clean
 clean:
-	rm -rf src/*.[aod] ./*[aod] src/codec/*[aod]
+	rm -rf src/*.[aod] ./*[aod]
+	rm -f bin/test*
+
 
 .PHONY: uninstall
 uninstall:
 	rm -f $(DESTDIR)$(libdir)/liblsuprepo.*
 	rm -rf $(DESTDIR)$(includedir)
 
-bin/test: $(OBJ) $(TEST_SRC)
-	$(CC) \
-		$(CFLAGS) $(TEST_CFLAGS) $(SRC) $(CODEC_SRC) test.c -L. $(LDFLAGS) \
-		-o bin/test
 
-.PHONY: debug
-debug: bin/test
-	exec gdb bin/test
+# For testing, use debug symbols.
+bin/test: debug $(TEST_SRC)
+	$(CC) $(CFLAGS) $(DBG_CFLAGS) -Itest $(DBG_LDFLAGS) -llsuprepo_dbg \
+		test.c -o bin/test
+
 
 .PHONY: test
-test: bin/test
+test: bin/test ## Run a test suite.
 	exec bin/test
 
 
+.PHONY: gdb_test
+gdb_test: bin/test ## Run a test suite within gdb.
+	exec gdb bin/test
+
+
 .PHONY: memcheck
 memcheck:
 	valgrind \
-	--leak-check=full --show-leak-kinds=all --track-origins=yes \
-	--log-file=/tmp/lsup_valgrind.log \
-	./bin/test
-	echo "Memcheck complete. Valgrind log is at /tmp/lsup_valgrind.log"
+		--leak-check=full --show-leak-kinds=all --track-origins=yes \
+		--log-file=/tmp/lsup_valgrind.log \
+		./bin/test
+	@echo "Memcheck complete. Valgrind log is at /tmp/lsup_valgrind.log"
 
 
-memtest: test memcheck
+memtest: bin/test memcheck ## Run a test suite using Valgrind. Output to separate file.
 
 
-bin/profile: $(OBJ)
-	$(CC) \
-		$(CFLAGS) -g -DTESTING $(SRC) $(CODEC_SRC) profile.c -L. $(LDFLAGS) \
-		-o bin/profile
+bin/profile: debug profile.c
+	$(CC) $(CFLAGS) -g -DTESTING profile.c $(DBG_LDFLAGS) \
+		-llsuprepo_dbg -o bin/profile
 
 
 .PHONY: profile
 profile: bin/profile
 	exec valgrind --tool=callgrind --callgrind-out-file="$(CALLGRIND_DUMP)" \
-		bin/profile 10000 && \
-		echo "Profile dump written at $(CALLGRIND_DUMP)"
+		bin/profile 10000
+	@echo "Profile dump written at $(CALLGRIND_DUMP)"
 
 
 .PHONY: pytest
 py_test:
-	pip3 install --user . && \
+	pip3 install --user .
 	python3 test/cpython_test.py

+ 3 - 3
include/desc.h

@@ -76,7 +76,7 @@ typedef struct desc_t {
  * @param[out] rsrc Resource handle. It must be freed with #LSR_desc_free().
  */
 LSUP_rc
-LSR_desc_new_multi (const LSUP_Graph *data[], LSR_Desc **rsrc);
+LSR_desc_new_multi (LSUP_Graph *const *data, LSR_Desc **rsrc);
 
 
 /** @brief Shortcut to create a resource from a single graph.
@@ -103,13 +103,13 @@ LSR_desc_new (const LSUP_Graph *data, LSR_Desc **rsrc);
  *
  * @param[out] rsrc Resource handle to be populated with the found resource. It
  *  must be freed with #LSR_desc_free(). If NULL, the resource is only checked
- *  for existence.
+ *  for existence (much faster).
  *
  * @return LSUP_OK if the resource is found; LSUP_NORESULT if not found; <0
  *  on error.
  */
 LSUP_rc
-LSR_desc_get (char *id, LSR_Desc **rsrc);
+LSR_desc_get (const uuid_t id, LSR_Desc **rsrc);
 
 
 /** @brief Free a DESC-R.

+ 20 - 3
src/core.c

@@ -66,7 +66,7 @@ LSUP_rc LSR_init (void)
     LSUP_mdbstore_nsm_store (LSUP_default_env->mdb_store, nsm);
 
     // Cache managed predicates.
-    for (int i = 0; mgd_pred_str != NULL; i++) {
+    for (int i = 0; mgd_pred_str[i] != NULL; i++) {
         LSUP_Term *uri = LSUP_iriref_new (
                 mgd_pred_str[i], LSUP_default_env->nsm);
 
@@ -79,7 +79,7 @@ LSUP_rc LSR_init (void)
     }
 
     // Cache managed types.
-    for (int i = 0; mgd_type_str != NULL; i++) {
+    for (int i = 0; mgd_type_str[i] != NULL; i++) {
         LSUP_Term *uri = LSUP_iriref_new (
                 mgd_type_str[i], LSUP_default_env->nsm);
 
@@ -92,15 +92,32 @@ LSUP_rc LSR_init (void)
     }
     LSR_is_init = true;
 
+    atexit (LSR_done);
+
     return LSUP_OK;
 }
 
 
 void LSR_done (void)
 {
-    // TODO other teardown.
+    if (!LSR_is_init) return;
+
+    log_info ("Tering down LSUP repo environment.");
+
+    LSR_TermMap *entry, *tmp;
+    HASH_ITER (hh, LSR_managed_preds, entry, tmp) {
+        HASH_DEL (LSR_managed_preds, entry);
+        LSUP_term_free (entry->term);
+        free (entry);
+    }
+    HASH_ITER (hh, LSR_managed_types, entry, tmp) {
+        HASH_DEL (LSR_managed_types, entry);
+        LSUP_term_free (entry->term);
+        free (entry);
+    }
 
     LSUP_done();
+    LSR_is_init = false;
 }
 
 

+ 77 - 23
src/desc.c

@@ -1,7 +1,7 @@
 #include "desc.h"
 
 LSUP_rc
-LSR_desc_new_multi (const LSUP_Graph *data[], LSR_Desc **rsrc_p)
+LSR_desc_new_multi (LSUP_Graph *const *data, LSR_Desc **rsrc_p)
 {
     LSUP_rc rc = LSUP_OK;
 
@@ -27,7 +27,7 @@ LSR_desc_new_multi (const LSUP_Graph *data[], LSR_Desc **rsrc_p)
 
     // Count graphs inserted.
     size_t ct = 0;
-    while (data[ct++]);
+    while (data[ct]) ct++;
     rsrc->user_data = calloc (sizeof (*rsrc->user_data), ct + 1);
     if (UNLIKELY (! rsrc->user_data)) return LSUP_MEM_ERR;
 
@@ -35,9 +35,9 @@ LSR_desc_new_multi (const LSUP_Graph *data[], LSR_Desc **rsrc_p)
 
     // Loop over input graphs.
     for (size_t i = 0; i < ct; i++) {
-        LSUP_Term *gr_uri = LSUP_graph_uri (rsrc->user_data[i]);
+        LSUP_Term *gr_uri = LSUP_term_copy (LSUP_graph_uri (data[i]));
 
-        LSUP_Term *rel_uri = LSUP_iriref_relative (gr_uri, rsrc_uri);
+        LSUP_Term *rel_uri = LSUP_iriref_relative (rsrc_uri, gr_uri);
         if (strstr (rel_uri->data, "#__") == rel_uri->data) {
             log_error ("Fragment URI cannot start with double underscore.");
             rc = LSUP_VALUE_ERR;
@@ -53,15 +53,15 @@ LSR_desc_new_multi (const LSUP_Graph *data[], LSR_Desc **rsrc_p)
         // Loop over graph triples.
         while (LSUP_graph_iter_next (lu_it, src_spo) == LSUP_OK) {
             dest_s = LSUP_IS_IRI (src_spo->s) ?
-                    LSUP_iriref_relative (src_spo->s, rsrc_uri) : src_spo->s;
-            dest_p = src_spo->p;
+                    LSUP_iriref_relative (rsrc_uri, src_spo->s) : src_spo->s;
+            dest_p = LSUP_term_copy (src_spo->p);
             dest_o = LSUP_IS_IRI (src_spo->s) ?
-                    LSUP_iriref_relative (src_spo->s, rsrc_uri) : src_spo->s;
+                    LSUP_iriref_relative (rsrc_uri, src_spo->s) : src_spo->s;
             LSUP_triple_init (dest_spo, dest_s, dest_p, dest_o);
 
             // if the pred is managed, ignore the triple and send a warning.
             LSR_TermMap *tmp;
-            LSUP_Key pk = LSUP_term_hash (src_spo->p);
+            LSUP_Key pk = LSUP_term_hash (dest_spo->p);
             HASH_FIND (hh, LSR_managed_preds, &pk, sizeof (pk), tmp);
 
             if (tmp) {
@@ -76,19 +76,26 @@ LSR_desc_new_multi (const LSUP_Graph *data[], LSR_Desc **rsrc_p)
              * If the subject or object is a resource, check if it exists; if
              * it does, add triple to user_data; if not, return an error.
              */
-            char *id_tmp;
+            uuid_t id_tmp;
+            LSUP_rc tmp_rc;
             if (LSR_IS_RSRC_IRI (dest_s)) {
-                id_tmp = dest_s->data + strlen (LSR_RSRC_PFX);
-                if (LSR_desc_get (id_tmp, NULL) != LSUP_OK) {
-                    log_error ("Referenced subject does not exist: %s", id_tmp);
+                uuid_parse (dest_s->data + strlen (LSR_RSRC_PFX), id_tmp);
+                tmp_rc = LSR_desc_get (id_tmp, NULL);
+                if (tmp_rc != LSUP_OK) {
+                    log_error (
+                            "Referenced subject does not exist: %s",
+                            dest_s->data + strlen (LSR_RSRC_PFX));
                     rc = LSUP_VALUE_ERR;
                     goto finally;
                 }
             }
             if (LSR_IS_RSRC_IRI (dest_o)) {
-                id_tmp = dest_o->data + strlen (LSR_RSRC_PFX);
-                if (LSR_desc_get (id_tmp, NULL) != LSUP_OK) {
-                    log_error ("Referenced object does not exist: %s", id_tmp);
+                uuid_parse (dest_o->data + strlen (LSR_RSRC_PFX), id_tmp);
+                tmp_rc = LSR_desc_get (id_tmp, NULL);
+                if (tmp_rc != LSUP_OK) {
+                    log_error (
+                            "Referenced object does not exist: %s",
+                            dest_o->data + strlen (LSR_RSRC_PFX));
                     rc = LSUP_VALUE_ERR;
                     goto finally;
                 }
@@ -97,8 +104,8 @@ LSR_desc_new_multi (const LSUP_Graph *data[], LSR_Desc **rsrc_p)
             // RDF type check.
             if (
                 LSUP_term_equals (
-                    gr_uri, LSUP_iriref_absolute (src_spo->p, gr_uri))
-                && LSUP_term_equals (rdf_t, src_spo->p)
+                    gr_uri, LSUP_iriref_absolute (rsrc_uri, dest_spo->p))
+                && LSUP_term_equals (rdf_t, dest_spo->p)
             ) {
                 // If the resource is a special type, handle specific workflow.
                 // TODO
@@ -125,7 +132,6 @@ loop_end:
         LSUP_triple_init (dest_spo, dest_s, dest_p, dest_o);
         LSUP_graph_add_iter (admin_add_it, dest_spo);
         LSUP_term_free (dest_o);
-
         LSUP_term_free (dest_p);
 
         // Relationship between data graph and resource.
@@ -134,7 +140,6 @@ loop_end:
         LSUP_triple_init (dest_spo, dest_s, dest_p, dest_o);
         LSUP_graph_add_iter (admin_add_it, dest_spo);
         LSUP_term_free (dest_p);
-        LSUP_term_free (dest_o);
 
         LSUP_graph_iter_free (lu_it);
         LSUP_graph_add_done (add_it);
@@ -159,12 +164,12 @@ loop_end:
 
     dest_o = LSUP_iriref_new ("lsup:Resource", LSUP_DEF_NSM);
     LSUP_triple_init (admin_spo, dest_s, dest_p, dest_o);
-    LSUP_graph_add_iter (add_it, admin_spo);
+    LSUP_graph_add_iter (admin_add_it, admin_spo);
     LSUP_term_free (dest_o);
 
     dest_o = LSUP_iriref_new ("lsup:DescriptiveResource", LSUP_DEF_NSM);
     LSUP_triple_init (admin_spo, dest_s, dest_p, dest_o);
-    LSUP_graph_add_iter (add_it, admin_spo);
+    LSUP_graph_add_iter (admin_add_it, admin_spo);
     LSUP_term_free (dest_o);
 
     // Timestamps. For now, second precision is fine.
@@ -185,9 +190,11 @@ loop_end:
     LSUP_graph_add_iter (admin_add_it, admin_spo);
     LSUP_term_free (dest_p);
     LSUP_term_free (dest_o);
+    LSUP_graph_add_done (admin_add_it);
 
     // Add admin graph metadata to default graph.
     admin_add_it = LSUP_graph_add_init (rsrc->main_data);
+    LSUP_term_free (dest_s);
     dest_s = gr_uri;
     dest_p = rdf_t;
 
@@ -206,9 +213,7 @@ loop_end:
     dest_o = rsrc_uri;
     LSUP_triple_init (dest_spo, dest_s, dest_p, dest_o);
     LSUP_graph_add_iter (admin_add_it, dest_spo);
-
     LSUP_term_free (dest_p);
-    LSUP_term_free (dest_o);
 
     LSUP_graph_add_done (admin_add_it);
     admin_add_it = NULL;
@@ -238,6 +243,55 @@ fail:
 }
 
 
+LSUP_rc
+LSR_desc_get (const uuid_t id, LSR_Desc **rsrc)
+{
+    LSUP_rc rc = LSUP_OK;
+
+    LSUP_Term *default_gr_uri = LSUP_term_new_from_buffer (
+            LSUP_default_env->default_ctx);
+    LSUP_Graph *main_gr = LSUP_graph_new (default_gr_uri, LSUP_STORE_MDB);
+
+    LSUP_Term
+        *s = LSR_id_to_urn (id, NULL),
+        *p = LSUP_iriref_new ("rdf:type", LSUP_DEF_NSM),
+        *o = LSUP_iriref_new ("lsup:Resource", LSUP_DEF_NSM);
+
+    LSUP_Triple *spo = LSUP_triple_new (s, p, o);
+
+    if (!LSUP_graph_contains (main_gr, spo)) rc = LSUP_NORESULT;
+    LSUP_term_free (p);
+    LSUP_term_free (o);
+
+    if (rsrc && rc == LSUP_OK) {
+        p = LSUP_iriref_new ("foaf:primaryTopic", LSUP_DEF_NSM);
+        size_t ct = 0, i = 0;
+
+        // Find all graphs making up the resource.
+        LSUP_GraphIterator *it = LSUP_graph_lookup (main_gr, NULL, p, s, &ct);
+        LSUP_Graph **data = calloc (sizeof (*data), ct + 1);
+        while (LSUP_graph_iter_next (it, spo)) {
+            data[i] = LSUP_graph_new (spo->s, LSUP_STORE_MDB);
+            if (! data[i++]) break;
+        }
+        LSUP_graph_iter_free (it);
+
+        rc = LSR_desc_new_multi (data, rsrc);
+
+        i = 0;
+        while (i < ct) LSUP_graph_free (data[i++]);
+        free (data);
+
+        LSUP_term_free (s);
+        LSUP_term_free (p);
+    }
+
+    LSUP_graph_free (main_gr);
+
+    return rc;
+}
+
+
 void LSR_desc_free (LSR_Desc *rsrc)
 {
     size_t i = 0;

+ 2 - 2
test.c

@@ -16,8 +16,8 @@ int main(int argc, char **argv) {
 
     start = clock();
 
-    int rc = LSUP_init();
-    if (rc != LSUP_OK) return rc;
+    int rc = LSR_init();
+    if (rc < 0) return rc;
 
     if (
         desc_tests() ||

+ 55 - 0
test/test_desc.c

@@ -4,6 +4,61 @@
 static int
 test_desc_create()
 {
+    LSUP_Term *terms1[] = {
+        LSUP_iriref_new ("usn:s:1", NULL),
+        LSUP_iriref_new ("usn:s:2", NULL),
+        LSUP_iriref_new ("usn:p:1", NULL),
+        LSUP_iriref_new ("usn:p:2", NULL),
+        LSUP_iriref_new ("usn:o:1", NULL),
+        LSUP_iriref_new ("usn:o:2", NULL),
+    };
+    LSUP_Term *terms2[] = {
+        LSUP_iriref_new ("usn:s:10", NULL),
+        LSUP_iriref_new ("usn:s:20", NULL),
+        LSUP_iriref_new ("usn:p:10", NULL),
+        LSUP_iriref_new ("usn:p:20", NULL),
+        LSUP_iriref_new ("usn:o:10", NULL),
+        LSUP_iriref_new ("usn:o:20", NULL),
+    };
+
+    LSUP_Triple trp1[] = {
+        {terms1[0], terms1[2], terms1[4]},
+        {terms1[0], terms1[3], terms1[4]},
+        {terms1[0], terms1[3], terms1[5]},
+        {terms1[1], terms1[2], terms1[4]},
+        {NULL}
+    };
+    LSUP_Triple trp2[] = {
+        {terms2[0], terms2[2], terms2[4]},
+        {terms2[0], terms2[3], terms2[4]},
+        {terms2[0], terms2[3], terms2[5]},
+        {terms2[1], terms2[2], terms2[4]},
+        {NULL}
+    };
+
+    LSUP_Graph *gr1 = LSUP_graph_new (
+            LSUP_iriref_new ("#usr1", NULL), LSUP_STORE_MEM);
+    LSUP_graph_add (gr1, trp1, NULL);
+    LSUP_Graph *gr2 = LSUP_graph_new (
+            LSUP_iriref_new ("#usr2", NULL), LSUP_STORE_MEM);
+    LSUP_graph_add (gr2, trp2, NULL);
+    LSUP_Graph *data[] = {gr1, gr2, NULL};
+
+    LSR_Desc *rsrc;
+    EXPECT_PASS (LSR_desc_new_multi (data, &rsrc));
+
+    LSUP_graph_free (gr1);
+    LSUP_graph_free (gr2);
+
+    for (int i = 0; i < 6; i++) {
+        LSUP_term_free (terms1[i]);
+        LSUP_term_free (terms2[i]);
+    }
+
+    // TODO more action
+
+    LSR_desc_free (rsrc);
+
     return 0;
 }