• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Nic30 / hdlConvertor / #220

30 Jun 2025 04:05PM UTC coverage: 60.052% (+0.02%) from 60.029%
#220

push

travis-ci

web-flow
Merge pull request #203 from nicorum/aliasimpure

Add Support for VHDL Aliases and Impure Functions

28 of 31 new or added lines in 7 files covered. (90.32%)

41627 of 69318 relevant lines covered (60.05%)

1047658.78 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

75.21
/hdlConvertor/toPy.cpp
1
#include "toPy.h"
2

3
#include <typeinfo>
4
#include <iterator>
5
#include <stdexcept>
6
#include <string>
7
#include <tuple>
8
#include <utility>
9

10
#include <hdlConvertor/hdlAst/bigInteger.h>
11
#include <hdlConvertor/hdlAst/hdlDirection.h>
12
#include <hdlConvertor/hdlAst/hdlValue.h>
13
#include <hdlConvertor/conversion_exception.h>
14

15
namespace hdlConvertor {
16

17
using namespace hdlAst;
18

19
ToPy::ToPy() {
18,372✔
20
        hdlAst_module = PyImport_ImportModule("hdlConvertorAst.hdlAst");
18,372✔
21
        if (hdlAst_module == nullptr) {
18,372✔
22
                // this could happen only if there are missing files in library
23
                PyErr_Print();
×
24
                throw std::runtime_error("can not import hdlConvertorAst.hdlAst");
×
25
        }
26
        auto import =
27
                        [this](PyObject *&obj, const std::string &name) {
789,996✔
28
                                obj = PyObject_GetAttrString(hdlAst_module, name.c_str());
789,996✔
29
                                assert(
789,996✔
30
                                                obj != NULL && "hdlConvertorAst.hdlAst not as expected from hdlConvertor");
31
                        };
18,372✔
32
        import(ContextCls, "HdlContext");
36,744✔
33
        import(CodePositionCls, "CodePosition");
36,744✔
34
        import(HdlModuleDefCls, "HdlModuleDef");
36,744✔
35
        import(HdlModuleDecCls, "HdlModuleDec");
36,744✔
36
        import(HdlIdDefCls, "HdlIdDef");
36,744✔
37
        import(HdlOpCls, "HdlOp");
36,744✔
38
        import(HdlOpTypeEnum, "HdlOpType");
36,744✔
39
        import(HdlValueIntCls, "HdlValueInt");
36,744✔
40
        import(HdlExprNotImplementedCls, "HdlExprNotImplemented");
36,744✔
41
        import(HdlValueIdCls, "HdlValueId");
36,744✔
42
        import(HdlDirectionEnum, "HdlDirection");
36,744✔
43
        import(HdlAllCls, "HdlAll");
36,744✔
44
        import(HdlOthersCls, "HdlOthers");
36,744✔
45
        import(HdlTypeAutoCls, "HdlTypeAuto");
36,744✔
46
        import(HdlTypeTypeCls, "HdlTypeType");
36,744✔
47
        import(HdlTypeSubtypeCls, "HdlTypeSubtype");
36,744✔
48
        import(HdlClassTypeEnum, "HdlClassType");
36,744✔
49
        import(HdlClassDefCls, "HdlClassDef");
36,744✔
50
        import(HdlPhysicalDefCls, "HdlPhysicalDef");
36,744✔
51
        import(HdlEnumDefCls, "HdlEnumDef");
36,744✔
52
        import(HdlStmIfCls, "HdlStmIf");
36,744✔
53
        import(HdlStmAssignCls, "HdlStmAssign");
36,744✔
54
        import(HdlStmProcessTriggerConstrainEnum, "HdlStmProcessTriggerConstrain");
36,744✔
55
        import(HdlStmProcessCls, "HdlStmProcess");
36,744✔
56
        import(HdlStmCaseUniqConstrainEnum, "HdlStmCaseUniqConstrain");
36,744✔
57
        import(HdlStmCaseTypeEnum, "HdlStmCaseType");
36,744✔
58
        import(HdlStmCaseCls, "HdlStmCase");
36,744✔
59
        import(HdlStmForCls, "HdlStmFor");
36,744✔
60
        import(HdlStmForInCls, "HdlStmForIn");
36,744✔
61
        import(HdlStmWhileCls, "HdlStmWhile");
36,744✔
62
        import(HdlStmNopCls, "HdlStmNop");
36,744✔
63
        import(HdlStmRepeatCls, "HdlStmRepeat");
36,744✔
64
        import(HdlStmReturnCls, "HdlStmReturn");
36,744✔
65
        import(HdlStmBreakCls, "HdlStmBreak");
36,744✔
66
        import(HdlStmContinueCls, "HdlStmContinue");
36,744✔
67
        import(HdlStmWaitCls, "HdlStmWait");
36,744✔
68
        import(HdlStmBlockJoinTypeCls, "HdlStmBlockJoinType");
36,744✔
69
        import(HdlStmBlockCls, "HdlStmBlock");
36,744✔
70
        import(HdlLibraryCls, "HdlLibrary");
36,744✔
71
        import(HdlImportCls, "HdlImport");
36,744✔
72
        import(HdlCompInstCls, "HdlCompInst");
36,744✔
73
        import(HdlFunctionDefCls, "HdlFunctionDef");
36,744✔
74
        import(HdlValueIdspaceCls, "HdlValueIdspace");
18,372✔
75
}
18,372✔
76

77
std::string ToPy::PyObject_repr(PyObject *o) {
×
78
        PyObject *args = Py_BuildValue("(O)", PyObject_Repr(o));
×
79
        if (!args)
×
80
                return "";
×
81
        const char *s = nullptr;
×
82
        if (!PyArg_ParseTuple(args, "s", &s)) {
×
83
                Py_DECREF(args);
84
                return "";
×
85
        }
86
        std::string ret = s;
×
87
        Py_DECREF(args);
88
        return ret;
×
89
}
×
90

91
PyObject* ToPy::toPy(const HdlContext *o) {
8,883✔
92
        PyObject *py_inst = PyObject_CallObject(ContextCls, NULL);
8,883✔
93
        if (!py_inst)
8,883✔
94
                return nullptr;
×
95
        if (toPy_arr(py_inst, "objs", o->objs)) {
26,649✔
96
                return nullptr;
×
97
        }
98
        return py_inst;
8,883✔
99
}
100

101
PyObject* ToPy::toPy(const HdlLibrary *o) {
2,476✔
102
        Py_INCREF(Py_None);
103
        PyObject *py_inst = PyObject_CallFunctionObjArgs(HdlLibraryCls, Py_None,
2,476✔
104
        NULL);
105
        if (!py_inst)
2,476✔
106
                return nullptr;
×
107
        if (toPy(static_cast<const WithNameAndDoc*>(o), py_inst))
2,476✔
108
                return nullptr;
×
109
        return toPy_fillHdlAttributes(py_inst, o);
2,476✔
110
}
111

112
PyObject* ToPy::toPy(const iHdlObj *o) {
501,077✔
113
        auto ex = dynamic_cast<const iHdlExprItem*>(o);
501,077✔
114
        if (ex)
501,077✔
115
                return toPy(ex);
×
116
        auto fn = dynamic_cast<const HdlFunctionDef*>(o);
501,077✔
117
        if (fn)
501,077✔
118
                return toPy(fn);
19,048✔
119
        auto v = dynamic_cast<const HdlIdDef*>(o);
482,029✔
120
        if (v)
482,029✔
121
                return toPy(v);
68,530✔
122
        auto s = dynamic_cast<const iHdlStatement*>(o);
413,499✔
123
        if (s)
413,499✔
124
                return toPy(s);
388,130✔
125
        auto md = dynamic_cast<const HdlModuleDec*>(o);
25,369✔
126
        if (md)
25,369✔
127
                return toPy(md);
2,555✔
128
        auto mdef = dynamic_cast<const HdlModuleDef*>(o);
22,814✔
129
        if (mdef)
22,814✔
130
                return toPy(mdef);
13,098✔
131
        auto ci = dynamic_cast<const HdlCompInst*>(o);
9,716✔
132
        if (ci)
9,716✔
133
                return toPy(ci);
6,279✔
134
        auto ns = dynamic_cast<const HdlValueIdspace*>(o);
3,437✔
135
        if (ns)
3,437✔
136
                return toPy(ns);
961✔
137
        auto lib = dynamic_cast<const HdlLibrary*>(o);
2,476✔
138
        if (lib)
2,476✔
139
                return toPy(lib);
2,476✔
140

141
        std::string err_msg;
×
142
        if (o)
×
143
                err_msg = std::string("ToPy::toPy unknown type of iHdlObj:")
×
144
                                + std::string(typeid(*o).name());
×
145
        else
146
                err_msg = "ToPy::toPy called for nullptr";
×
147
        PyErr_SetString(PyExc_ValueError, err_msg.c_str());
×
148
        return nullptr;
×
149
}
×
150

151
int ToPy::toPy(const WithNameAndDoc *o, PyObject *py_inst) {
205,701✔
152
        if (!o) {
205,701✔
153
                PyErr_SetString(PyExc_ValueError, "ToPy::toPy invalid WithNameAndDoc*");
×
154
                Py_DECREF(py_inst);
155
                return -1;
×
156
        }
157
        int e;
158
        if (o->name.size()) {
205,701✔
159
                if (toPy_property(py_inst, "name", o->name))
194,526✔
160
                        return -1;
×
161
        }
162
        e = toPy(static_cast<const WithDoc*>(o), py_inst);
205,701✔
163
        if (e < 0)
205,701✔
164
                return e;
×
165
        return toPy(static_cast<const WithPos*>(o), py_inst);
205,701✔
166
}
167

168
int ToPy::toPy(const WithDoc *o, PyObject *py_inst) {
480,164✔
169
        if (o->__doc__.size())
480,164✔
170
                if (toPy_property(py_inst, "doc", o->__doc__))
26,999✔
171
                        return -1;
×
172
        return 0;
480,164✔
173
}
174

175
int ToPy::toPy(const WithPos *o, PyObject *py_inst) {
481,040✔
176
        if (toPy_property(py_inst, "position", o->position))
481,040✔
177
                return -1;
×
178
        return 0;
481,040✔
179
}
180

181
PyObject* ToPy::toPy(const CodePosition o) {
481,040✔
182
        PyObject *py_inst = PyObject_CallObject(CodePositionCls, NULL);
481,040✔
183
        if (!py_inst)
481,040✔
184
                return nullptr;
×
185
        if (toPy_property(py_inst, "start_line", o.start_line))
481,040✔
186
                return nullptr;
×
187
        if (toPy_property(py_inst, "start_column", o.start_column))
481,040✔
188
                return nullptr;
×
189
        if (toPy_property(py_inst, "stop_line", o.stop_line))
481,040✔
190
                return nullptr;
×
191
        if (toPy_property(py_inst, "stop_column", o.stop_column))
481,040✔
192
                return nullptr;
×
193
        return py_inst;
481,040✔
194
}
195

196
PyObject* ToPy::toPy(const HdlModuleDef *o) {
13,098✔
197
        PyObject *py_inst = PyObject_CallObject(HdlModuleDefCls, NULL);
13,098✔
198
        if (py_inst == nullptr)
13,098✔
199
                return nullptr;
×
200
        if (toPy(static_cast<const WithNameAndDoc*>(o), py_inst))
13,098✔
201
                return nullptr;
×
202
        if (o->module_name) {
13,098✔
203
                if (toPy_property(py_inst, "module_name", o->module_name))
13,098✔
204
                        return nullptr;
×
205
        }
206
        if (o->dec) {
13,098✔
207
                if (toPy_property(py_inst, "dec", o->dec))
10,758✔
208
                        return nullptr;
×
209
        }
210
        if (toPy_arr(py_inst, "objs", o->objs))
39,294✔
211
                return nullptr;
×
212

213
        return toPy_fillHdlAttributes(py_inst, o);
13,098✔
214
}
215

216
PyObject* ToPy::toPy(const hdlAst::HdlCompInst *o) {
6,279✔
217
        PyObject *py_inst = PyObject_CallObject(HdlCompInstCls, NULL);
6,279✔
218
        if (py_inst == nullptr)
6,279✔
219
                return nullptr;
×
220
        if (toPy_property(py_inst, "name", o->name))
6,279✔
221
                return nullptr;
×
222
        if (toPy_property(py_inst, "module_name", o->module_name))
6,279✔
223
                return nullptr;
×
224
        if (toPy_arr(py_inst, "param_map", o->genericMap))
18,837✔
225
                return nullptr;
×
226
        if (toPy_arr(py_inst, "port_map", o->portMap))
18,837✔
227
                return nullptr;
×
228

229
        return toPy_fillHdlAttributes(py_inst, o);
6,279✔
230
}
231

232
PyObject* ToPy::toPy(const HdlModuleDec *o) {
13,313✔
233
        PyObject *py_inst = PyObject_CallObject(HdlModuleDecCls, NULL);
13,313✔
234
        if (py_inst == nullptr)
13,313✔
235
                return nullptr;
×
236
        int e = toPy(static_cast<const WithNameAndDoc*>(o), py_inst);
13,313✔
237
        if (e)
13,313✔
238
                return nullptr;
×
239

240
        if (toPy_arr(py_inst, "params", o->generics))
39,939✔
241
                return nullptr;
×
242

243
        if (toPy_arr(py_inst, "ports", o->ports))
39,939✔
244
                return nullptr;
×
245

246
        if (toPy_arr(py_inst, "objs", o->objs))
39,939✔
247
                return nullptr;
×
248

249
        return toPy_fillHdlAttributes(py_inst, o);
13,313✔
250
}
251

252
PyObject* ToPy::toPy(const HdlFunctionDef *o) {
19,048✔
253
        PyObject *py_inst = PyObject_CallObject(HdlFunctionDefCls, NULL);
19,048✔
254
        if (py_inst == nullptr)
19,048✔
255
                return nullptr;
×
256
        if (toPy(static_cast<const WithNameAndDoc*>(o), py_inst))
19,048✔
257
                return nullptr;
×
258
        if (toPy_property(py_inst, "is_declaration_only", o->is_declaration_only))
19,048✔
259
                return nullptr;
×
260
        if (toPy_property(py_inst, "is_operator", o->is_operator))
19,048✔
261
                return nullptr;
×
262
        if (toPy_property(py_inst, "is_static", o->is_static))
19,048✔
263
                return nullptr;
×
264
        if (toPy_property(py_inst, "is_task", o->is_task))
19,048✔
265
                return nullptr;
×
266
        if (toPy_property(py_inst, "is_virtual", o->is_virtual))
19,048✔
267
                return nullptr;
×
268
        if (toPy_property(py_inst, "is_impure", o->is_impure))
19,048✔
NEW
269
                return nullptr;
×
270
        if (o->params) {
19,048✔
271
                if (toPy_arr(py_inst, "params", *o->params))
55,887✔
272
                        return nullptr;
×
273
        }
274
        if (o->returnT) {
19,048✔
275
                if (toPy_property(py_inst, "return_t", o->returnT))
14,667✔
276
                        return nullptr;
×
277
        }
278
        if (toPy_arr(py_inst, "body", o->body))
57,144✔
279
                return nullptr;
×
280

281
        return toPy_fillHdlAttributes(py_inst, o);
19,048✔
282
}
283

284
PyObject* ToPy::toPy(const HdlDirection o) {
156,805✔
285
        const char *name;
286
        try {
287
                name = HdlDirection_toString(o);
156,805✔
288
        } catch (const std::runtime_error &e) {
×
289
                PyErr_SetString(PyExc_ValueError, e.what());
×
290
                return nullptr;
×
291
        }
×
292
        return PyObject_GetAttrString(HdlDirectionEnum, name);
156,805✔
293
}
294

295
PyObject* ToPy::toPy(const HdlOp *o) {
706,496✔
296
        auto fn = toPy(o->op);
706,496✔
297
        if (!fn) {
706,496✔
298
                return nullptr;
×
299
        }
300
        auto ops = PyList_New(0);
706,496✔
301
        if (!ops) {
706,496✔
302
                Py_DECREF(fn);
303
                return nullptr;
×
304
        }
305
        if (toPy_arr(ops, o->operands)) {
706,496✔
306
                Py_DECREF(fn);
307
                return nullptr;
×
308
        }
309

310
        auto res = PyObject_CallFunctionObjArgs(HdlOpCls, fn, ops, NULL);
706,496✔
311
        Py_DECREF(fn);
312
        Py_DECREF(ops);
313
        return res;
706,496✔
314
}
315

316
// [TODO] too similar with the code for HdlModuleDef
317
PyObject* ToPy::toPy(const HdlValueIdspace *o) {
961✔
318
        PyObject *py_inst = PyObject_CallObject(HdlValueIdspaceCls, NULL);
961✔
319
        if (py_inst == nullptr)
961✔
320
                return nullptr;
×
321
        if (toPy(static_cast<const WithNameAndDoc*>(o), py_inst))
961✔
322
                return nullptr;
×
323
        if (toPy_arr(py_inst, "objs", o->objs))
2,883✔
324
                return nullptr;
×
325

326
        auto dec_only = PyBool_FromLong(o->defs_only);
961✔
327
        if (!dec_only) {
961✔
328
                Py_DECREF(py_inst);
329
                return nullptr;
×
330
        }
331

332
        if (PyObject_SetAttrString(py_inst, "declaration_only", dec_only)) {
961✔
333
                Py_DECREF(py_inst);
334
                return nullptr;
×
335
        }
336
        Py_DECREF(dec_only);
337

338
        return toPy_fillHdlAttributes(py_inst, o);
961✔
339
}
340

341
PyObject* ToPy::toPy(const HdlIdDef *o) {
156,805✔
342
        PyObject *py_inst = PyObject_CallObject(HdlIdDefCls, NULL);
156,805✔
343
        if (!py_inst)
156,805✔
344
                return nullptr;
×
345
        if (toPy(static_cast<const WithNameAndDoc*>(o), py_inst))
156,805✔
346
                return nullptr;
×
347

348
        if (o->type) {
156,805✔
349
                if (toPy_property(py_inst, "type", o->type))
156,154✔
NEW
350
                        return nullptr;
×
351
        }
352
        if (o->value) {
156,805✔
353
                if (toPy_property(py_inst, "value", o->value))
43,563✔
354
                        return nullptr;
×
355
        } // else let it to be None
356
        if (toPy_property(py_inst, "is_latched", o->is_latched))
156,805✔
357
                return nullptr;
×
358
        if (toPy_property(py_inst, "is_const", o->is_const))
156,805✔
359
                return nullptr;
×
360
        if (toPy_property(py_inst, "is_static", o->is_static))
156,805✔
361
                return nullptr;
×
362
        if (toPy_property(py_inst, "is_shared", o->is_shared))
156,805✔
363
                return nullptr;
×
364
        if (toPy_property(py_inst, "is_alias", o->is_alias))
156,805✔
NEW
365
                return nullptr;
×
366
        if (toPy_property(py_inst, "direction", o->direction))
156,805✔
367
                return nullptr;
×
368
        return toPy_fillHdlAttributes(py_inst, o);
156,805✔
369
}
370

371
PyObject* ToPy::toPy(size_t o) {
1,924,160✔
372
        if (o == std::numeric_limits<size_t>::max()) {
1,924,160✔
373
                Py_RETURN_NONE;
7,196✔
374
        } else {
375
                return PyLong_FromLong((long) o);
1,916,964✔
376
        }
377
}
378

379
PyObject* ToPy::toPy(bool o) {
1,172,776✔
380
        return PyBool_FromLong((long) o);
1,172,776✔
381
}
382

383
PyObject* ToPy::toPy(const std::string &o) {
226,479✔
384
        return PyUnicode_FromString(o.c_str());
226,479✔
385
}
386

387
int ToPy::toPy_hdlAttributes(PyObject *parent, const iHdlObj *obj) {
486,443✔
388
        if (!obj->hdlAttributes)
486,443✔
389
                return 0;
485,726✔
390
        return toPy_arr(parent, "hdlAttributes", *obj->hdlAttributes);
2,151✔
391
}
392

393
PyObject* ToPy::toPy_fillHdlAttributes(PyObject *parent,
486,443✔
394
                const hdlAst::iHdlObj *obj) {
395
        if (toPy_hdlAttributes(parent, obj) < 0) {
486,443✔
396
                return nullptr;
×
397
        }
398
        return parent;
486,443✔
399
}
400

401
PyObject* ToPy::toPy(const hdlAst::iHdlObj::HdlAttribute &o) {
828✔
402
        auto id = toPy(o.id);
828✔
403
        if (!id)
828✔
404
                return nullptr;
×
405
        PyObject *val;
406
        if (o.value) {
828✔
407
                val = toPy(o.value);
230✔
408
                if (!val) {
230✔
409
                        Py_DECREF(id);
410
                        return nullptr;
×
411
                }
412
        } else {
413
                val = Py_None;
598✔
414
                Py_INCREF(val);
415
        }
416
        return PyTuple_Pack(2, id, val);
828✔
417
}
418

419
ToPy::~ToPy() {
18,372✔
420
        Py_XDECREF(HdlValueIdspaceCls);
18,372✔
421
        Py_XDECREF(HdlFunctionDefCls);
18,372✔
422
        Py_XDECREF(HdlCompInstCls);
18,372✔
423
        Py_XDECREF(HdlImportCls);
18,372✔
424
        Py_XDECREF(HdlLibraryCls);
18,372✔
425
        Py_XDECREF(HdlStmBlockCls);
18,372✔
426
        Py_XDECREF(HdlStmBlockJoinTypeCls);
18,372✔
427
        Py_XDECREF(HdlStmWaitCls);
18,372✔
428
        Py_XDECREF(HdlStmContinueCls);
18,372✔
429
        Py_XDECREF(HdlStmBreakCls);
18,372✔
430
        Py_XDECREF(HdlStmReturnCls);
18,372✔
431
        Py_XDECREF(HdlStmRepeatCls);
18,372✔
432
        Py_XDECREF(HdlStmNopCls);
18,372✔
433
        Py_XDECREF(HdlStmWhileCls);
18,372✔
434
        Py_XDECREF(HdlStmForCls);
18,372✔
435
        Py_XDECREF(HdlStmForInCls);
18,372✔
436
        Py_XDECREF(HdlStmCaseCls);
18,372✔
437
        Py_XDECREF(HdlStmCaseTypeEnum);
18,372✔
438
        Py_XDECREF(HdlStmCaseUniqConstrainEnum);
18,372✔
439
        Py_XDECREF(HdlStmProcessCls);
18,372✔
440
        Py_XDECREF(HdlStmProcessTriggerConstrainEnum);
18,372✔
441
        Py_XDECREF(HdlStmAssignCls);
18,372✔
442
        Py_XDECREF(HdlStmIfCls);
18,372✔
443
        Py_XDECREF(HdlOthersCls);
18,372✔
444
        Py_XDECREF(HdlAllCls);
18,372✔
445
        Py_XDECREF(HdlPhysicalDefCls);
18,372✔
446
        Py_XDECREF(HdlEnumDefCls);
18,372✔
447
        Py_XDECREF(HdlClassDefCls);
18,372✔
448
        Py_XDECREF(HdlClassTypeEnum);
18,372✔
449
        Py_XDECREF(HdlTypeSubtypeCls);
18,372✔
450
        Py_XDECREF(HdlTypeTypeCls);
18,372✔
451
        Py_XDECREF(HdlTypeAutoCls);
18,372✔
452
        Py_XDECREF(HdlDirectionEnum);
18,372✔
453
        Py_XDECREF(HdlValueIdCls);
18,372✔
454
        Py_XDECREF(HdlExprNotImplementedCls);
18,372✔
455
        Py_XDECREF(HdlValueIntCls);
18,372✔
456
        Py_XDECREF(HdlOpTypeEnum);
18,372✔
457
        Py_XDECREF(HdlOpCls);
18,372✔
458
        Py_XDECREF(HdlIdDefCls);
18,372✔
459
        Py_XDECREF(HdlModuleDecCls);
18,372✔
460
        Py_XDECREF(HdlModuleDefCls);
18,372✔
461
        Py_XDECREF(CodePositionCls);
18,372✔
462
        Py_XDECREF(ContextCls);
18,372✔
463
        Py_XDECREF(hdlAst_module);
18,372✔
464
}
18,372✔
465

466
const char* get_cpp_py_error_message() {
621✔
467
        try {
468
                throw;
621✔
469
        } catch (const ParseException &e) {
621✔
470
                return e.what();
619✔
471
        } catch (const std::exception &e) {
621✔
472
                return e.what();
2✔
473
        }
2✔
474
        return "<unknown C++ exception>";
475
}
476

477
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc