1"""
2Python library calling enry Go implementation trough cFFI (API, out-of-line) and Cgo.
3"""
4
5from _c_enry import ffi, lib
6
7## cgo -> ffi helpers
8def py_bytes_to_go(py_bytes: bytes):
9    c_bytes = ffi.new("char[]", len(py_bytes))
10    go_slice = ffi.new("GoSlice *", [c_bytes, len(py_bytes), len(py_bytes)])
11    return (go_slice[0], c_bytes)
12
13def py_str_to_go(py_str: str):
14    str_bytes = py_str.encode()
15    c_str = ffi.new("char[]", str_bytes)
16    go_str = ffi.new("_GoString_ *", [c_str, len(str_bytes)])
17    return (go_str[0], c_str)
18
19def go_str_to_py(go_str: str):
20    str_len = go_str.n
21    if str_len > 0:
22        return ffi.unpack(go_str.p, go_str.n).decode()
23    return ""
24
25def go_bool_to_py(go_bool: bool):
26    return go_bool == 1
27
28
29## API, TODO(bzz): add docstrings
30def language(filename: str, content: bytes) -> str:
31    fName, c_str = py_str_to_go(filename)
32    fContent, c_bytes = py_bytes_to_go(content)
33    guess = lib.GetLanguage(fName, fContent)
34    lang = go_str_to_py(guess)
35    return lang
36
37def language_by_extension(filename: str) -> str:
38    fName, c_str = py_str_to_go(filename)
39    guess = lib.GetLanguageByExtension(fName)
40    lang = go_str_to_py(guess.r0)
41    return lang
42
43def language_by_filename(filename: str) -> str:
44    fName, c_str = py_str_to_go(filename)
45    guess = lib.GetLanguageByFilename(fName)
46    lang = go_str_to_py(guess.r0)
47    return lang
48
49def is_vendor(filename: str) -> bool:
50    fName, c_str = py_str_to_go(filename)
51    guess = lib.IsVendor(fName)
52    return go_bool_to_py(guess)
53
54def is_generated(filename: str, content: bytes) -> bool:
55    fname, c_str = py_str_to_go(filename)
56    fcontent, c_bytes = py_bytes_to_go(content)
57    guess = lib.IsGenerated(fname, fcontent)
58    return go_bool_to_py(guess)
59
60
61## Tests
62from collections import namedtuple
63
64def main():
65    TestFile = namedtuple("TestFile", "name, content, lang")
66    files = [
67        TestFile("Parse.hs", b"", "Haskell"), TestFile("some.cpp", b"", "C++"),
68        TestFile("orand.go", b"", "Go"), TestFile("type.h", b"", "C"),
69        TestFile(".bashrc", b"", "Shell"), TestFile(".gitignore", b"", "Ignore List")
70    ]
71
72    print("\nstrategy: extension")
73    for f in files:
74        lang = language_by_extension(f.name)
75        print("\tfile: {:10s} language: '{}'".format(f.name, lang))
76
77    print("\nstrategy: filename")
78    for f in files:
79        lang = language_by_filename(f.name)
80        print("\tfile: {:10s} language: '{}'".format(f.name, lang))
81
82    print("\ncheck: is vendor?")
83    for f in files:
84        vendor = is_vendor(f.name)
85        print("\tfile: {:10s} vendor: '{}'".format(f.name, vendor))
86
87    print("\nstrategy: all")
88    for f in files:
89        lang = language(f.name, f.content)
90        print("\tfile: {:10s} language: '{}'".format(f.name, lang))
91        assert lang == f.lang, "Expected '{}' but got '{}'".format(f.lang, lang)
92
93if __name__ == "__main__":
94    main()
95