cauterize 0.0.1.pre1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. data/.gitignore +24 -0
  2. data/.rspec +1 -0
  3. data/.travisci.yml +4 -0
  4. data/Gemfile +4 -0
  5. data/LICENSE.txt +22 -0
  6. data/README.md +152 -0
  7. data/Rakefile +38 -0
  8. data/bin/cauterize +53 -0
  9. data/c/src/cauterize.c +74 -0
  10. data/c/src/cauterize.h +46 -0
  11. data/c/src/cauterize_debug.h +29 -0
  12. data/c/src/cauterize_util.h +7 -0
  13. data/c/test/greatest.h +536 -0
  14. data/c/test/test.c +166 -0
  15. data/cauterize.gemspec +26 -0
  16. data/example/Cauterize +44 -0
  17. data/example/build.sh +4 -0
  18. data/lib/cauterize/base_type.rb +96 -0
  19. data/lib/cauterize/builders.rb +27 -0
  20. data/lib/cauterize/builders/c/buildable.rb +59 -0
  21. data/lib/cauterize/builders/c/composite.rb +55 -0
  22. data/lib/cauterize/builders/c/enumeration.rb +41 -0
  23. data/lib/cauterize/builders/c/fixed_array.rb +62 -0
  24. data/lib/cauterize/builders/c/group.rb +95 -0
  25. data/lib/cauterize/builders/c/scalar.rb +31 -0
  26. data/lib/cauterize/builders/c/variable_array.rb +90 -0
  27. data/lib/cauterize/c_builder.rb +63 -0
  28. data/lib/cauterize/cauterize.rb +33 -0
  29. data/lib/cauterize/composite.rb +50 -0
  30. data/lib/cauterize/enumeration.rb +77 -0
  31. data/lib/cauterize/fixed_array.rb +43 -0
  32. data/lib/cauterize/formatter.rb +59 -0
  33. data/lib/cauterize/group.rb +56 -0
  34. data/lib/cauterize/scalar.rb +38 -0
  35. data/lib/cauterize/snake_case.rb +21 -0
  36. data/lib/cauterize/variable_array.rb +56 -0
  37. data/lib/cauterize/version.rb +3 -0
  38. data/spec/base_type_spec.rb +167 -0
  39. data/spec/builders/c/buildable_spec.rb +25 -0
  40. data/spec/builders/c/composite_spec.rb +46 -0
  41. data/spec/builders/c/enumeration_spec.rb +32 -0
  42. data/spec/builders/c/fixed_array_spec.rb +36 -0
  43. data/spec/builders/c/group_spec.rb +112 -0
  44. data/spec/builders/c/scalar_spec.rb +8 -0
  45. data/spec/builders/c/variable_array_spec.rb +50 -0
  46. data/spec/builders_spec.rb +51 -0
  47. data/spec/c_builder_spec.rb +133 -0
  48. data/spec/cauterize_spec.rb +8 -0
  49. data/spec/composite_spec.rb +62 -0
  50. data/spec/enumeration_spec.rb +104 -0
  51. data/spec/fixed_array_spec.rb +62 -0
  52. data/spec/group_spec.rb +104 -0
  53. data/spec/scalar_spec.rb +36 -0
  54. data/spec/spec_helper.rb +115 -0
  55. data/spec/support/shared_examples_for_array_buildables.rb +22 -0
  56. data/spec/support/shared_examples_for_c_buildables.rb +91 -0
  57. data/spec/support/shared_examples_for_sane_c_buildables.rb +22 -0
  58. data/spec/support/shared_examples_for_stubbed_functions.rb +18 -0
  59. data/spec/test_main.c +13 -0
  60. data/spec/variable_array_spec.rb +92 -0
  61. 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,8 @@
1
+ describe Cauterize::Builders::C::Scalar do
2
+ let(:type_constructor) { lambda {|name| scalar(name)}}
3
+
4
+ it_behaves_like "a buildable"
5
+ it_behaves_like "a sane buildable"
6
+ include_examples "no enum"
7
+ include_examples "no struct"
8
+ 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