Skip to content

Commit

Permalink
More stuff
Browse files Browse the repository at this point in the history
  • Loading branch information
ioggstream committed Jun 26, 2024
1 parent f4f1aab commit 86dee1b
Show file tree
Hide file tree
Showing 8 changed files with 161 additions and 88 deletions.
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -130,3 +130,7 @@ dmypy.json

# IDE
.vscode/

# C
*.o
*.so
1 change: 1 addition & 0 deletions c-project/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
example
10 changes: 5 additions & 5 deletions c-project/Makefile
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
CC=gcc
CFLAGS=-fPIC -g
CFLAGS=-fPIC -g -lc -lm -Wall

all: example example.so
all: example libexample.so

example: example.o
$(CC) -o example example.o $(CFLAGS)

example.o: example.c
$(CC) -c example.c $(CFLAGS)

example.so: example.o
$(CC) -shared -o example.so example.o
libexample.so: example.o
$(CC) -shared -o libexample.so example.o

clean:
rm -f example example.o example.so
rm -f example example.o
rm -f example example.o
84 changes: 26 additions & 58 deletions c-project/example.c
Original file line number Diff line number Diff line change
@@ -1,78 +1,46 @@
/**
* A C file with a library function that appends a buffer to a linked list.
* A C file with a library function with a simple parsing funciton
* based on sscanf
*/

#include <stdlib.h>
#include <string.h>

#include <search.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#include "example.h"

struct person
{
int id;
char name[20];
} person;

static element *
new_element(void)
int parse_person(char *line, struct person *p)
{
element *e;
int n;

e = malloc(sizeof(*e));
if (e == NULL)
// Beware! There is an error in the format string.
// %s reads until the first whitespace character, so it won't work.
n = sscanf(line, "%d;%19s", &p->id, p->name);
if (n != 2)
{
fprintf(stderr, "malloc() failed\n");
exit(EXIT_FAILURE);
return -1;
}

return e;
return 0;
}



element* append(queue *q, char *name) {
element *elem, *prev;

if (!q) return NULL; // Check if the queue pointer itself is NULL

elem = new_element();
if (!elem) return NULL; // Check if memory allocation failed

elem->name = name; // Assuming name is properly allocated and managed outside this function

if (!*q) {
// If the queue is empty, insert the new element at the beginning
*q = elem;
} else {
// Find the last element in the queue
for (prev = *q; prev->forward != NULL; prev = prev->forward)
;
// Insert the new element at the end of the queue
}
insque(elem, prev);

return elem;
}


int main(int argc, char *argv[])
{
element *first, *elem, *prev;
queue *q = malloc(sizeof(queue));

elem = append(q, "1");
char line[] = "42;John Doe";
struct person p;


printf("Traversing completed list:\n");
elem = first;
do
if (parse_person(line, &p) == 0)
{
printf(" %s\n", elem->name);
elem = elem->forward;
} while (elem != NULL && elem != first);

if (elem == first)
printf("That was a circular list\n");
printf("ID: %d\n", p.id);
printf("Name: %s\n", p.name);
}
else
{
fprintf(stderr, "Parsing failed\n");
}

exit(EXIT_SUCCESS);
return 0;
}
9 changes: 1 addition & 8 deletions c-project/example.h
Original file line number Diff line number Diff line change
@@ -1,8 +1 @@
typedef struct element
{
struct element *forward;
struct element *backward;
char *name;
} element;

typedef element* queue;
int parse_person(char *line, struct person *p);
17 changes: 0 additions & 17 deletions tests/test_ctypes.py

This file was deleted.

21 changes: 21 additions & 0 deletions tests/test_ctypes_1.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import ctypes
from ctypes import Structure, byref, c_char, c_int, create_string_buffer
from pathlib import Path

# Load libraries.
l_so = Path(__file__).parent.parent / "c-project" / "libexample.so"
libc = ctypes.CDLL("libc.so.6")
libexample = ctypes.CDLL(l_so)


class Person(Structure):
_fields_ = [("id", c_int), ("name", c_char * 20)]


def test_parse_person():
p = Person()
row = "1;John Dow"
row_p = create_string_buffer(row.encode())
libexample.parse_person(row_p, byref(p))
assert p.id == 1
assert p.name == b"John Dow"
103 changes: 103 additions & 0 deletions tests/test_ctypes_2.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
import ctypes
import json
from ctypes import *
from ctypes import POINTER, Structure, c_int
from pathlib import Path

import pytest

# Load libraries.
cJSON_so = Path(__file__).parent / "libcjson.so"
libc = ctypes.CDLL("libc.so.6")
libcjson = ctypes.CDLL(cJSON_so)


#
# Define cJSON struct in two steps to avoid circular references.
#
class cJSON(Structure):
pass


cJSON._fields_ = [
("next", POINTER(cJSON)),
("prev", POINTER(cJSON)),
("child", POINTER(cJSON)),
("type", c_int),
("valuestring", c_char_p),
("valueint", c_int),
("valuedouble", c_double),
("string", c_char_p),
]

#
# Associate a return type with cJSON_Parse.
#
cJSON_Parse = libcjson.cJSON_Parse
cJSON_Parse.restype = ctypes.POINTER(cJSON)


@pytest.mark.parametrize(
"json_document, json_type, expected_values",
[
(b"1", 1 << 3, 1),
(b"1.1", 1 << 3, 1.1),
(b"1e+2", 1 << 3, 100),
(b"1_000", 1 << 3, 1.0),
],
)
def test_cJSON_Parse_can_parse_numbers(json_document, json_type, expected_values):
msg = ctypes.create_string_buffer(json_document)
c_json = cJSON_Parse(msg)
assert c_json.contents.type == json_type
assert c_json.contents.valuedouble == expected_values


@pytest.mark.parametrize(
"json_document, json_type, expected_values",
[
(b'"ciao"', 1 << 4, b"ciao"),
(json.dumps("però").encode(), 1 << 4, "però".encode()),
],
)
def test_cJSON_Parse_can_parse_strings(json_document, json_type, expected_values):
msg = ctypes.create_string_buffer(json_document)
c_json = cJSON_Parse(msg)
assert c_json.contents.type == json_type
assert c_json.contents.valuestring == expected_values


@pytest.mark.parametrize(
"json_document, json_type, expected_values",
[
(b"[1,2,3]", 1 << 5, [1, 2, 3]),
],
)
def test_cJSON_Parse_can_parse_arrays(json_document, json_type, expected_values):
msg = ctypes.create_string_buffer(json_document)
c_json = cJSON_Parse(msg)
assert c_json.contents.type == json_type

e = c_json.contents.child.contents
for expected_value in expected_values:
assert e.valueint == expected_value
try:
e = e.next.contents
except ValueError:
assert expected_value == expected_values[-1]
break


@pytest.mark.parametrize(
"json_document, json_type, expected_values",
[
(b'{"a": 1', None, None),
],
)
def test_cJSON_Parse_raises_when_invalid_json(
json_document, json_type, expected_values
):
msg = ctypes.create_string_buffer(json_document)
c_json = cJSON_Parse(msg)
with pytest.raises(ValueError):
assert c_json.contents

0 comments on commit 86dee1b

Please sign in to comment.