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.
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