Commit cdc4c41c authored by Lysander Trischler's avatar Lysander Trischler

Add subject

parent fe122d6f
......@@ -55,18 +55,38 @@ class _Link(ctypes.Structure):
def to_python(self):
link = Link()
if self.text is not None:
if self.text:
link.text = self.text.decode("utf-8")
if self.target is not None:
if self.target:
link.target = self.target.decode("utf-8")
return link
class Subject:
def __init__(self, text=None, tag=None):
self.text = text
self.tag = tag
class _Subject(ctypes.Structure):
_fields_ = [("text", ctypes.c_char_p),
("tag", ctypes.POINTER(_Link))]
def to_python(self):
subject = Subject()
if self.text:
subject.text = self.text.decode("utf-8")
if self.tag:
subject.tag = self.tag.contents.to_python()
return subject
class Twt:
def __init__(self, twter=None, created=None, hash=None, links=None):
def __init__(self, twter=None, created=None, hash=None, subject=None, links=None):
self.twter = twter
self.created = created
self.hash = hash
self.subject = subject
self.links = links
......@@ -74,6 +94,7 @@ class _Twt(ctypes.Structure):
_fields_ = [("twter", ctypes.POINTER(_Twter)),
("created", ctypes.c_char_p),
("hash", ctypes.c_char_p),
("subject", ctypes.POINTER(_Subject)),
("links", ctypes.POINTER(ctypes.POINTER(_Link))),
("links_len", ctypes.c_int)]
......@@ -85,6 +106,8 @@ class _Twt(ctypes.Structure):
twt.created = datetime.datetime.fromisoformat(self.created.decode("utf-8"))
if self.hash is not None:
twt.hash = self.hash.decode("utf-8")
if self.subject is not None:
twt.subject = self.subject.contents.to_python()
twt.links = []
for i in range(self.links_len):
......
......@@ -24,7 +24,7 @@ struct twt {
struct twter *twter;
char *created;
char *hash;
//struct subject *subject;
struct subject *subject;
//struct twter *mentions[];
struct link *links;
int links_len;
......@@ -127,6 +127,9 @@ func convertTwt(t types.Twt) *C.struct_twt {
twt.twter = convertTwter(t.Twter())
twt.created = C.CString(t.Created().Format(time.RFC3339))
twt.hash = C.CString(t.Hash())
if subject, ok := t.Subject().(*lextwt.Subject); ok && subject != nil {
twt.subject = convertSubject(subject)
}
linksPtr := C.malloc(C.size_t(len(t.Links())) * C.size_t(unsafe.Sizeof(uintptr(0))))
links := (*[1<<30 - 1]*C.struct_link)(linksPtr)
......@@ -144,6 +147,7 @@ func freeTwt(t *C.struct_twt) {
freeTwter(t.twter)
free_string(t.created)
free_string(t.hash)
freeSubject(t.subject)
freeLinks(t.links, t.links_len)
C.free(unsafe.Pointer(t))
}
......@@ -159,6 +163,32 @@ func freeTwts(t *C.struct_twt, length C.int) {
}
}
func convertSubject(s types.Subject) *C.struct_subject {
ptr := C.malloc(C.sizeof_struct_subject)
subject := (*C.struct_subject)(ptr)
subject.text = C.CString(s.Text())
if tag, ok := s.Tag().(*lextwt.Tag); ok && tag != nil {
subject.tag = convertTag(tag)
}
return subject
}
func freeSubject(s *C.struct_subject) {
if s != nil {
free_string(s.text)
freeLink(s.tag)
C.free(unsafe.Pointer(s))
}
}
func convertTag(t types.TwtTag) *C.struct_link {
ptr := C.malloc(C.sizeof_struct_link)
link := (*C.struct_link)(ptr)
link.text = C.CString(t.Text())
link.target = C.CString(t.Target())
return link
}
func convertLink(l types.TwtLink) *C.struct_link {
ptr := C.malloc(C.sizeof_struct_link)
link := (*C.struct_link)(ptr)
......
......@@ -2,7 +2,7 @@
import datetime
import unittest
from libgotwtxt import Link, parse_file, Twt, Twter
from libgotwtxt import Link, parse_file, Subject, Twt, Twter
UTC_PLUS_2 = datetime.timezone(datetime.timedelta(hours=2))
TWTER = Twter(nick="hugo",
......@@ -18,7 +18,9 @@ class ParseFileTest(unittest.TestCase):
self.assertEqual(1, len(twtfile.twts), "number of twts does not match")
self.assertTwtEqual(Twt(twter=TWTER,
created=datetime.datetime(2021, 8, 2, 10, 27, 42, tzinfo=UTC_PLUS_2),
hash="slrnx6a", links=[]),
hash="slrnx6a",
subject=Subject(text="#slrnx6a", tag=Link(text="slrnx6a", target=None)),
links=[]),
twtfile.twts[0])
......@@ -32,11 +34,15 @@ class ParseFileTest(unittest.TestCase):
self.assertEqual(2, len(twtfile.twts), "number of twts does not match")
self.assertTwtEqual(Twt(twter=TWTER,
created=datetime.datetime(2021, 8, 2, 10, 27, 42, tzinfo=UTC_PLUS_2),
hash="slrnx6a", links=[]),
hash="slrnx6a",
subject=Subject(text="#slrnx6a", tag=Link(text="slrnx6a", target=None)),
links=[]),
twtfile.twts[0], "first twt does not match")
self.assertTwtEqual(Twt(twter=TWTER,
created=datetime.datetime(2021, 8, 3, 9, 28, 45, tzinfo=UTC_PLUS_2),
hash="zm7fnka", links=[]),
hash="zm7fnka",
subject=Subject(text="#zm7fnka", tag=Link(text="zm7fnka", target=None)),
links=[]),
twtfile.twts[1], "second twt does not match")
......@@ -51,10 +57,33 @@ class ParseFileTest(unittest.TestCase):
self.assertTwtEqual(Twt(twter=TWTER,
created=datetime.datetime(2021, 8, 3, 11, 16, 13, tzinfo=UTC_PLUS_2),
hash="zv6vujq",
subject=Subject(text="#zv6vujq", tag=Link(text="zv6vujq", target=None)),
links=[Link(text="wonderful", target="https://example.com/"),
Link(text="nice", target="https://example.com/test")]),
twtfile.twts[0])
def test_subjects(self):
twtfile = parse_file(
"2021-08-03T12:28:26+02:00\t(#<1234567 https://example.com/1234567>) I agree!\n"
"2021-08-03T12:33:17+02:00\t(re: foo) Well, it's quite complicated.\n",
TWTER)
self.assertIsNotNone(twtfile, "parse_file returned None")
self.assertTwterEqual(TWTER, twtfile.twter, "twter of twt file does not match")
self.assertEqual(2, len(twtfile.twts), "number of twts does not match")
self.assertTwtEqual(Twt(twter=TWTER,
created=datetime.datetime(2021, 8, 3, 12, 28, 26, tzinfo=UTC_PLUS_2),
hash="g2xdgsq",
subject=Subject(text="#<1234567 https://example.com/1234567>",
tag=Link(text="1234567", target="https://example.com/1234567")),
links=[]),
twtfile.twts[0], "first twt does not match")
self.assertTwtEqual(Twt(twter=TWTER,
created=datetime.datetime(2021, 8, 3, 12, 33, 17, tzinfo=UTC_PLUS_2),
hash="wqw7ipq",
subject=Subject(text="re: foo", tag=None),
links=[]),
twtfile.twts[1], "second twt does not match")
def msg(self, message_prefix):
"""Construct a message factory using the prefix, if present."""
......@@ -78,6 +107,8 @@ class ParseFileTest(unittest.TestCase):
self.assertTwterEqual(expected.twter, actual.twter, msg("twter of twt does not match"))
self.assertEqual(expected.created, actual.created, msg("twt creation timestamp does not match"))
self.assertEqual(expected.hash, actual.hash, msg("twt hash does not match"))
self.assertSubjectEqual(expected.subject, actual.subject, "twt subject does not match")
if expected.links is None:
self.assertIsNone(actual.links, "twt links do not match")
else:
......@@ -89,9 +120,22 @@ class ParseFileTest(unittest.TestCase):
def assertLinkEqual(self, expected, actual, msg=None):
msg = self.msg(msg)
if expected is None:
self.assertIsNone(actual, msg("link must be None"))
return
self.assertIsNotNone(actual, msg("link is None"))
self.assertEqual(expected.text, actual.text, msg("link text does not match"))
self.assertEqual(expected.target, actual.target, msg("link target does not match"))
def assertSubjectEqual(self, expected, actual, msg=None):
msg = self.msg(msg)
if expected is None:
self.assertIsNone(actual, msg("subject must be None"))
return
self.assertIsNotNone(actual, msg("subject is None"))
self.assertEqual(expected.text, actual.text, msg("subject text does not match"))
self.assertLinkEqual(expected.tag, actual.tag, msg("subject tag does not match"))
if __name__ == "__main__":
unittest.main()
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment