cauterize 0.0.1.pre1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +24 -0
- data/.rspec +1 -0
- data/.travisci.yml +4 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +152 -0
- data/Rakefile +38 -0
- data/bin/cauterize +53 -0
- data/c/src/cauterize.c +74 -0
- data/c/src/cauterize.h +46 -0
- data/c/src/cauterize_debug.h +29 -0
- data/c/src/cauterize_util.h +7 -0
- data/c/test/greatest.h +536 -0
- data/c/test/test.c +166 -0
- data/cauterize.gemspec +26 -0
- data/example/Cauterize +44 -0
- data/example/build.sh +4 -0
- data/lib/cauterize/base_type.rb +96 -0
- data/lib/cauterize/builders.rb +27 -0
- data/lib/cauterize/builders/c/buildable.rb +59 -0
- data/lib/cauterize/builders/c/composite.rb +55 -0
- data/lib/cauterize/builders/c/enumeration.rb +41 -0
- data/lib/cauterize/builders/c/fixed_array.rb +62 -0
- data/lib/cauterize/builders/c/group.rb +95 -0
- data/lib/cauterize/builders/c/scalar.rb +31 -0
- data/lib/cauterize/builders/c/variable_array.rb +90 -0
- data/lib/cauterize/c_builder.rb +63 -0
- data/lib/cauterize/cauterize.rb +33 -0
- data/lib/cauterize/composite.rb +50 -0
- data/lib/cauterize/enumeration.rb +77 -0
- data/lib/cauterize/fixed_array.rb +43 -0
- data/lib/cauterize/formatter.rb +59 -0
- data/lib/cauterize/group.rb +56 -0
- data/lib/cauterize/scalar.rb +38 -0
- data/lib/cauterize/snake_case.rb +21 -0
- data/lib/cauterize/variable_array.rb +56 -0
- data/lib/cauterize/version.rb +3 -0
- data/spec/base_type_spec.rb +167 -0
- data/spec/builders/c/buildable_spec.rb +25 -0
- data/spec/builders/c/composite_spec.rb +46 -0
- data/spec/builders/c/enumeration_spec.rb +32 -0
- data/spec/builders/c/fixed_array_spec.rb +36 -0
- data/spec/builders/c/group_spec.rb +112 -0
- data/spec/builders/c/scalar_spec.rb +8 -0
- data/spec/builders/c/variable_array_spec.rb +50 -0
- data/spec/builders_spec.rb +51 -0
- data/spec/c_builder_spec.rb +133 -0
- data/spec/cauterize_spec.rb +8 -0
- data/spec/composite_spec.rb +62 -0
- data/spec/enumeration_spec.rb +104 -0
- data/spec/fixed_array_spec.rb +62 -0
- data/spec/group_spec.rb +104 -0
- data/spec/scalar_spec.rb +36 -0
- data/spec/spec_helper.rb +115 -0
- data/spec/support/shared_examples_for_array_buildables.rb +22 -0
- data/spec/support/shared_examples_for_c_buildables.rb +91 -0
- data/spec/support/shared_examples_for_sane_c_buildables.rb +22 -0
- data/spec/support/shared_examples_for_stubbed_functions.rb +18 -0
- data/spec/test_main.c +13 -0
- data/spec/variable_array_spec.rb +92 -0
- metadata +212 -0
@@ -0,0 +1,25 @@
|
|
1
|
+
include Cauterize::Builders::C
|
2
|
+
|
3
|
+
describe Cauterize::Builders::C do
|
4
|
+
describe Buildable do
|
5
|
+
subject { Buildable.new(:some_blueprint) }
|
6
|
+
|
7
|
+
describe "required methods" do
|
8
|
+
it "raises errors on required interfaces" do
|
9
|
+
lambda {
|
10
|
+
REQUIRED_METHODS.each do |m|
|
11
|
+
subject.send(m)
|
12
|
+
end
|
13
|
+
}.should raise_error /must implement/
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
describe :method_missing do
|
18
|
+
it "calls the original if method not required" do
|
19
|
+
lambda {
|
20
|
+
subject.is_not_defined
|
21
|
+
}.should raise_error NoMethodError
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
describe Cauterize::Builders::C::Composite do
|
2
|
+
let(:type_constructor) do
|
3
|
+
lambda do |name|
|
4
|
+
scalar(:int32)
|
5
|
+
composite(name) do |c|
|
6
|
+
c.field :an_int, :int32
|
7
|
+
c.field :another_int, :int32
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
it_behaves_like "a buildable"
|
13
|
+
it_behaves_like "a sane buildable"
|
14
|
+
include_examples "no enum"
|
15
|
+
|
16
|
+
context "structure definition" do
|
17
|
+
let(:comp) do
|
18
|
+
scalar(:int32)
|
19
|
+
_c = composite(:foo) do |c|
|
20
|
+
c.field(:an_int, :int32)
|
21
|
+
end
|
22
|
+
|
23
|
+
Builders.get(:c, _c)
|
24
|
+
end
|
25
|
+
|
26
|
+
describe ".struct_proto" do
|
27
|
+
it "defines a structure prototype" do
|
28
|
+
f = default_formatter
|
29
|
+
comp.struct_proto(f)
|
30
|
+
f.to_s.should == "struct foo;"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
describe ".struct_defn" do
|
35
|
+
it "defines a structure definition" do
|
36
|
+
f = default_formatter
|
37
|
+
comp.struct_defn(f)
|
38
|
+
fs = f.to_s
|
39
|
+
|
40
|
+
fs.should match /struct foo/
|
41
|
+
fs.should match /int32 an_int;/
|
42
|
+
fs.should match /};/
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
describe Cauterize::Builders::C::Enumeration do
|
2
|
+
let(:type_constructor) { lambda {|name| enumeration(name)}}
|
3
|
+
|
4
|
+
it_behaves_like "a buildable"
|
5
|
+
it_behaves_like "a sane buildable"
|
6
|
+
include_examples "no struct"
|
7
|
+
|
8
|
+
describe ".enum_defn" do
|
9
|
+
let(:en) do
|
10
|
+
_e = enumeration(:foo) do |e|
|
11
|
+
e.value :aaa
|
12
|
+
e.value :bbb
|
13
|
+
e.value "QuickBrownFox".to_sym
|
14
|
+
end
|
15
|
+
|
16
|
+
f = default_formatter
|
17
|
+
Builders.get(:c, _e).enum_defn(f)
|
18
|
+
f.to_s
|
19
|
+
end
|
20
|
+
|
21
|
+
it "contains the enum name" do
|
22
|
+
en.should match /enum foo/
|
23
|
+
end
|
24
|
+
|
25
|
+
it "contains an entry for each value" do
|
26
|
+
en.should match /AAA = 0,/
|
27
|
+
en.should match /BBB = 1,/
|
28
|
+
en.should match /QUICK_BROWN_FOX = 2,/
|
29
|
+
en.should match /};/
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
describe Cauterize::Builders::C::FixedArray do
|
2
|
+
let(:type_constructor) do
|
3
|
+
scalar(:uint32_t)
|
4
|
+
lambda do |name|
|
5
|
+
fixed_array(name) do |a|
|
6
|
+
a.array_type :uint32_t
|
7
|
+
a.array_size 16
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
it_behaves_like "a buildable"
|
13
|
+
include_examples "no enum"
|
14
|
+
include_examples "no struct"
|
15
|
+
|
16
|
+
context "an array buildable" do
|
17
|
+
let(:desc_instance) { type_constructor.call(:some_type_name) }
|
18
|
+
let(:formatter) { default_formatter }
|
19
|
+
subject { described_class.new(desc_instance) }
|
20
|
+
|
21
|
+
describe :render do
|
22
|
+
it "contains the name" do
|
23
|
+
t_name = subject.instance_variable_get(:@blueprint).array_type.name
|
24
|
+
subject.render.should match /#{t_name}/
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
describe :declare do
|
29
|
+
before { subject.declare(formatter, :some_sym) }
|
30
|
+
|
31
|
+
it "contains the name and a ;" do
|
32
|
+
formatter.to_s.should match /uint32_t some_sym\[16\]; \/\* some_type_name \*\//
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,112 @@
|
|
1
|
+
describe Cauterize::Builders::C::Group do
|
2
|
+
let(:type_constructor) { lambda {|name| group(name)}}
|
3
|
+
|
4
|
+
it_behaves_like "a buildable"
|
5
|
+
it_behaves_like "a sane buildable"
|
6
|
+
include_examples "no enum"
|
7
|
+
|
8
|
+
context "enumeration for type tag" do
|
9
|
+
before do
|
10
|
+
scalar(:uint8_t)
|
11
|
+
@g = group!(:some_name) do |_g|
|
12
|
+
_g.field(:a, :uint8_t)
|
13
|
+
_g.field(:b, :uint8_t)
|
14
|
+
end
|
15
|
+
@b = Cauterize::Builders::C::Group.new(@g)
|
16
|
+
end
|
17
|
+
|
18
|
+
describe ".initialize" do
|
19
|
+
it "creates the enumeration tag" do
|
20
|
+
@b.instance_variable_get(:@tag_enum).class.name.should == "Cauterize::Enumeration"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
describe "@tag_enum" do
|
25
|
+
it "contains a entry for each field in the group" do
|
26
|
+
e = @b.instance_variable_get(:@tag_enum)
|
27
|
+
e.values.keys.should =~ [ :GROUP_SOME_NAME_TYPE_A,
|
28
|
+
:GROUP_SOME_NAME_TYPE_B ]
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe ".packer_defn" do
|
33
|
+
before do
|
34
|
+
f = default_formatter
|
35
|
+
@b.packer_defn(f)
|
36
|
+
@fs = f.to_s
|
37
|
+
end
|
38
|
+
|
39
|
+
it "contains the enum packer" do
|
40
|
+
@fs.should match /Pack_group_some_name_type/
|
41
|
+
end
|
42
|
+
|
43
|
+
it "contains each tag" do
|
44
|
+
@fs.should match /GROUP_SOME_NAME_TYPE_A/
|
45
|
+
@fs.should match /GROUP_SOME_NAME_TYPE_B/
|
46
|
+
end
|
47
|
+
|
48
|
+
it "contains each field" do
|
49
|
+
@fs.should match /src->data\.a/
|
50
|
+
@fs.should match /src->data\.b/
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
describe ".unpacker_defn" do
|
55
|
+
before do
|
56
|
+
f = default_formatter
|
57
|
+
@b.unpacker_defn(f)
|
58
|
+
@fs = f.to_s
|
59
|
+
end
|
60
|
+
|
61
|
+
it "contains the enum unpacker" do
|
62
|
+
@fs.should match /Unpack_group_some_name_type/
|
63
|
+
end
|
64
|
+
|
65
|
+
it "contains each tag" do
|
66
|
+
@fs.should match /GROUP_SOME_NAME_TYPE_A/
|
67
|
+
@fs.should match /GROUP_SOME_NAME_TYPE_B/
|
68
|
+
end
|
69
|
+
|
70
|
+
it "contains each field" do
|
71
|
+
@fs.should match /dst->data\.a/
|
72
|
+
@fs.should match /dst->data\.b/
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
context "structure definition" do
|
78
|
+
let(:grp) do
|
79
|
+
scalar(:int32)
|
80
|
+
_g = group(:oof) do |g|
|
81
|
+
g.field(:aaa, :int32)
|
82
|
+
g.field(:bbb, :int32)
|
83
|
+
end
|
84
|
+
|
85
|
+
Builders.get(:c, _g)
|
86
|
+
end
|
87
|
+
|
88
|
+
describe ".struct_proto" do
|
89
|
+
it "defines a structure prototype" do
|
90
|
+
f = default_formatter
|
91
|
+
grp.struct_proto(f)
|
92
|
+
f.to_s.should == "struct oof;"
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
describe ".struct_defn" do
|
97
|
+
it "defines a structure definition" do
|
98
|
+
f = default_formatter
|
99
|
+
grp.struct_defn(f)
|
100
|
+
fs = f.to_s
|
101
|
+
|
102
|
+
fs.should match /struct oof/
|
103
|
+
fs.should match /enum group_oof_type tag;/
|
104
|
+
fs.should match /union/
|
105
|
+
fs.should match /int32 aaa;/
|
106
|
+
fs.should match /int32 bbb;/
|
107
|
+
fs.should match /} data;/
|
108
|
+
fs.should match /};/
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
describe Cauterize::Builders::C::VariableArray do
|
2
|
+
let(:type_constructor) do
|
3
|
+
lambda do |name|
|
4
|
+
scalar(:uint8_t)
|
5
|
+
variable_array(name) do |a|
|
6
|
+
a.array_type(:uint8_t)
|
7
|
+
a.array_size(8)
|
8
|
+
a.size_type(:uint8_t)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
it_behaves_like "a buildable"
|
14
|
+
it_behaves_like "a sane buildable"
|
15
|
+
include_examples "no enum"
|
16
|
+
|
17
|
+
context "structure definition" do
|
18
|
+
let(:vara) do
|
19
|
+
scalar(:int32)
|
20
|
+
_a = variable_array(:va) do |a|
|
21
|
+
a.array_size(8)
|
22
|
+
a.array_type(:int32)
|
23
|
+
a.size_type(:int32)
|
24
|
+
end
|
25
|
+
|
26
|
+
Builders.get(:c, _a)
|
27
|
+
end
|
28
|
+
|
29
|
+
describe ".struct_proto" do
|
30
|
+
it "defines a structure prototype" do
|
31
|
+
f = default_formatter
|
32
|
+
vara.struct_proto(f)
|
33
|
+
f.to_s.should == "struct va;"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
describe ".struct_defn" do
|
38
|
+
it "defines a structure definition" do
|
39
|
+
f = default_formatter
|
40
|
+
vara.struct_defn(f)
|
41
|
+
fs = f.to_s
|
42
|
+
|
43
|
+
fs.should match /struct va/
|
44
|
+
fs.should match /int32 length;/
|
45
|
+
fs.should match /int32 data\[8\];/
|
46
|
+
fs.should match /};/
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
describe Cauterize::Builders do
|
2
|
+
describe "#register and #get" do
|
3
|
+
let(:s) { scalar(:uint8_t) }
|
4
|
+
before do
|
5
|
+
class X; def initialize(i); end; end
|
6
|
+
class Y; def initialize(i); end; end
|
7
|
+
|
8
|
+
# save the old list so that we can restore it later.
|
9
|
+
old_builders = nil
|
10
|
+
Cauterize::Builders.module_exec do
|
11
|
+
old_builders = @builders
|
12
|
+
@builders = nil
|
13
|
+
end
|
14
|
+
@old_builders = old_builders
|
15
|
+
end
|
16
|
+
|
17
|
+
after do
|
18
|
+
# restore the builders so as not to break any other tests
|
19
|
+
old_builders = @old_builders
|
20
|
+
Cauterize::Builders.module_exec do
|
21
|
+
@builders = old_builders
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
it "saves and retrieves classes" do
|
26
|
+
Cauterize::Builders.register(:c, Cauterize::Scalar, X)
|
27
|
+
Cauterize::Builders.get(:c, s).class.should be X
|
28
|
+
end
|
29
|
+
|
30
|
+
it "handles multiple languages" do
|
31
|
+
Cauterize::Builders.register(:c, Cauterize::Scalar, X)
|
32
|
+
Cauterize::Builders.get(:c, s).class.should be X
|
33
|
+
|
34
|
+
Cauterize::Builders.register(:cs, Cauterize::Scalar, Y)
|
35
|
+
Cauterize::Builders.get(:cs, s).class.should be Y
|
36
|
+
end
|
37
|
+
|
38
|
+
it "raises an error on duplicate registrations" do
|
39
|
+
Cauterize::Builders.register(:c, Cauterize::Scalar, X)
|
40
|
+
lambda {
|
41
|
+
Cauterize::Builders.register(:c, Cauterize::Scalar, X)
|
42
|
+
}.should raise_error /already registered/
|
43
|
+
end
|
44
|
+
|
45
|
+
it "raises an error if no builder is registered" do
|
46
|
+
lambda {
|
47
|
+
Cauterize::Builders.get(:c, s)
|
48
|
+
}.should raise_error /unregistered/
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,133 @@
|
|
1
|
+
require 'tmpdir'
|
2
|
+
require 'fileutils'
|
3
|
+
|
4
|
+
describe Cauterize::CBuilder do
|
5
|
+
before do
|
6
|
+
@tempdir = Dir.mktmpdir
|
7
|
+
@h_path = File.join(@tempdir, "testing.h")
|
8
|
+
@c_path = File.join(@tempdir, "testing.c")
|
9
|
+
|
10
|
+
@cb = CBuilder.new(@h_path, @c_path, "testing")
|
11
|
+
end
|
12
|
+
after { FileUtils.rm_rf @tempdir }
|
13
|
+
|
14
|
+
describe :initialize do
|
15
|
+
it "saves the h and c paths" do
|
16
|
+
@cb.h.should == @h_path
|
17
|
+
@cb.c.should == @c_path
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
describe :build do
|
22
|
+
before do
|
23
|
+
scalar(:uint8_t)
|
24
|
+
scalar(:uint16_t)
|
25
|
+
scalar(:uint32_t)
|
26
|
+
|
27
|
+
fixed_array(:mac_address) do |fa|
|
28
|
+
fa.array_type :uint8_t
|
29
|
+
fa.array_size 6
|
30
|
+
end
|
31
|
+
|
32
|
+
variable_array(:mac_table) do |t|
|
33
|
+
t.array_type :mac_address
|
34
|
+
t.array_size 64
|
35
|
+
t.size_type :uint8_t
|
36
|
+
end
|
37
|
+
|
38
|
+
variable_array(:name) do |va|
|
39
|
+
va.array_type :uint8_t
|
40
|
+
va.size_type :uint8_t
|
41
|
+
va.array_size 32
|
42
|
+
end
|
43
|
+
|
44
|
+
enumeration(:gender) do |e|
|
45
|
+
e.value :male
|
46
|
+
e.value :female
|
47
|
+
end
|
48
|
+
|
49
|
+
composite(:place) do |c|
|
50
|
+
c.field :name, :name
|
51
|
+
c.field :elevation, :uint32_t
|
52
|
+
end
|
53
|
+
|
54
|
+
composite(:person) do |c|
|
55
|
+
c.field :first_name, :name
|
56
|
+
c.field :last_name, :name
|
57
|
+
c.field :gender, :gender
|
58
|
+
end
|
59
|
+
|
60
|
+
composite(:dog) do |c|
|
61
|
+
c.field :name, :name
|
62
|
+
c.field :gender, :gender
|
63
|
+
c.field :leg_count, :uint8_t
|
64
|
+
end
|
65
|
+
|
66
|
+
group(:creature) do |g|
|
67
|
+
g.field :person, :person
|
68
|
+
g.field :dog, :dog
|
69
|
+
end
|
70
|
+
|
71
|
+
@cb.build
|
72
|
+
@h_text = File.read(@cb.h)
|
73
|
+
@h_lines = @h_text.lines.to_a
|
74
|
+
@c_text = File.read(@cb.c)
|
75
|
+
@c_lines = @c_text.lines.to_a
|
76
|
+
end
|
77
|
+
|
78
|
+
describe "header generation" do
|
79
|
+
it "prevents multiple inclusion in headers" do
|
80
|
+
@h_lines[0].should match /#ifndef TESTING_H_\d+/
|
81
|
+
@h_lines[1].should match /#define TESTING_H_\d+/
|
82
|
+
@h_lines.last.should match /#endif \/\* TESTING_H_\d+ \*\//
|
83
|
+
end
|
84
|
+
|
85
|
+
it "includes prototype information for all defined types" do
|
86
|
+
@h_text.should match "struct name;"
|
87
|
+
@h_text.should match "struct person;"
|
88
|
+
@h_text.should match "struct place;"
|
89
|
+
end
|
90
|
+
|
91
|
+
it "includes enumeration and structure definitions" do
|
92
|
+
@h_text.should match /gender/
|
93
|
+
@h_text.should match /MALE = 0/
|
94
|
+
@h_text.should match /FEMALE = 1/
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
describe "c body generation" do
|
99
|
+
it "includes the generated header file" do
|
100
|
+
@c_text.should match /#include "testing.h"/
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
describe "compilation" do
|
105
|
+
it "can be built" do
|
106
|
+
caut_dir = "#{File.dirname(__FILE__)}/../c/src"
|
107
|
+
|
108
|
+
res = Dir.chdir @tempdir do
|
109
|
+
File.open("test_main.c", "wb") do |fh|
|
110
|
+
syms = BaseType.all_instances.map do |i|
|
111
|
+
b = Builders.get(:c, i)
|
112
|
+
[b.packer_sym, b.unpacker_sym]
|
113
|
+
end.flatten
|
114
|
+
fh.write(gen_test_main(syms))
|
115
|
+
end
|
116
|
+
|
117
|
+
cmd = %W{
|
118
|
+
clang -Wall -Wextra -Werror
|
119
|
+
-I#{caut_dir}
|
120
|
+
#{@cb.c}
|
121
|
+
#{caut_dir}/cauterize.c
|
122
|
+
test_main.c
|
123
|
+
-o testing.bin 2>&1
|
124
|
+
}.join(" ")
|
125
|
+
|
126
|
+
`#{cmd}`
|
127
|
+
end
|
128
|
+
|
129
|
+
res.should == ""
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|