vhdl_doctest 0.0.4 → 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -14,6 +14,6 @@ bin_file = Pathname.new(__FILE__).realpath
14
14
  $:.unshift File.expand_path("../../lib", bin_file)
15
15
 
16
16
  require "vhdl_doctest"
17
- test = VhdlDoctest::DUT.parse(ARGV[0]).test_file
17
+ dut = VhdlDoctest::DUT.parse(ARGV[0])
18
18
 
19
- VhdlDoctest::TestRunner.new(STDOUT, ARGV[0], test).run
19
+ VhdlDoctest::TestRunner.new(STDOUT, ARGV[0], dut.test_file, dut.dependencies).run
@@ -0,0 +1,56 @@
1
+ library IEEE;
2
+ use IEEE.STD_LOGIC_1164.all;
3
+ use IEEE.STD_LOGIC_ARITH.all;
4
+ use IEEE.STD_LOGIC_UNSIGNED.all;
5
+
6
+ -- DOCTEST DEPENDENCIES: test.vhd
7
+ -- TEST
8
+ -- a |b |control b|output|zero
9
+ -- 18 |9 |000 |0 |1
10
+ -- | |001 |27 |0
11
+ -- | |010 |27 |0
12
+ -- | |110 |9 |0
13
+ -- | |111 |0 |1
14
+ -- 18 |18 |111 |0 |1
15
+ -- 18 |19 | |1 |0
16
+ -- 18 |100 | |1 |0
17
+ -- /TEST
18
+
19
+ entity alu is
20
+
21
+ port (
22
+ a, b : in std_logic_vector(31 downto 0);
23
+ control : in std_logic_vector(2 downto 0);
24
+ output : out std_logic_vector(31 downto 0);
25
+ zero : out std_logic);
26
+
27
+ end alu;
28
+
29
+ architecture behave of alu is
30
+
31
+ signal bb : std_logic_vector(31 downto 0);
32
+ signal c : std_logic;
33
+ signal o0, o1, o2, o3 : std_logic_vector(31 downto 0);
34
+
35
+ signal out_buf : std_logic_vector(31 downto 0);
36
+
37
+ begin -- behave
38
+
39
+ c <= control(2);
40
+
41
+ bb <= not b when control(2) = '1' else b;
42
+
43
+ o0 <= a and bb;
44
+ o1 <= a or b;
45
+ o2 <= a + bb + c;
46
+ o3 <= x"0000000" & "000" & o2(31);
47
+
48
+ out_buf <= o0 when control(1 downto 0) = "00" else
49
+ o1 when control(1 downto 0) = "01" else
50
+ o2 when control(1 downto 0) = "10" else
51
+ o3 when control(1 downto 0) = "11";
52
+
53
+ output <= out_buf;
54
+ zero <= '1' when out_buf = x"00000000" else '0';
55
+
56
+ end behave;
@@ -6,6 +6,7 @@ require "vhdl_doctest/test_file"
6
6
  require "vhdl_doctest/test_case"
7
7
  require "vhdl_doctest/dut"
8
8
  require "vhdl_doctest/test_parser"
9
+ require "vhdl_doctest/result_formatter"
9
10
 
10
11
  module VhdlDoctest
11
12
  # Your code goes here...
@@ -1,46 +1,54 @@
1
1
  module VhdlDoctest
2
2
  class DUT
3
3
  def self.parse(path)
4
- entity, ports, cases = DoctestParser.new(path).parse
5
- new(entity, ports, cases)
4
+ new(File.read(path))
6
5
  end
7
6
 
8
7
  attr_accessor :entity, :ports, :cases
9
- def initialize(entity, ports, cases)
10
- @entity, @ports, @cases = entity, ports, cases
8
+ def initialize(vhdl)
9
+ @vhdl = vhdl
11
10
  end
12
11
 
13
12
  def test_file
14
- TestFile.new(@entity, @ports, @cases)
15
- end
16
-
17
- class DoctestParser
18
- def initialize(path)
19
- @vhdl = File.read(path)
20
- end
21
-
22
- def parse
23
- entity = @vhdl.match(/entity\s+(.*)\s+is/)[1]
24
- ports = extract_ports
25
- cases = TestParser.parse(ports, @vhdl)
26
-
27
- [entity, ports, cases]
28
- end
29
-
30
- def extract_ports
31
- return @ports if @ports
32
- @ports = []
33
- definitions = @vhdl.match(/entity.*is\s+port\s*\((.*?)\);\s*end/m)[1]
34
- definitions.split("\n").each do |l|
35
- names, attributes = l.strip.gsub(/;$/, '').split(":")
36
- next unless attributes
37
- destination, type = attributes.strip.split(' ', 2)
38
- names.split(',').each do |name|
39
- @ports << Port.new(name.strip, destination.to_sym, VhdlDoctest::Types.parse(type))
40
- end
41
- end
42
- @ports
43
- end
13
+ TestFile.new(entity, ports, cases)
14
+ end
15
+
16
+ def ports
17
+ @ports ||=
18
+ remove_comments(port_block).split(";").
19
+ # "enable, push : in std_logic"
20
+ map { |line| line.strip.split(':') }.
21
+ # ["enable, push", "in std_logic"]
22
+ select { |names, attrs| ! attrs.nil? }.
23
+ map { |names, attrs| [names.split(','), *attrs.strip.split(' ', 2)] }.
24
+ # [["enable", " push"], in, std_logic]"
25
+ map { |names, destination, type|
26
+ names.map { |name| Port.new(name.strip, destination.to_sym, VhdlDoctest::Types.parse(type)) }
27
+ }.flatten
28
+ end
29
+
30
+ def port_block
31
+ @vhdl.match(/entity\s*(?<entity_name>[a-zA-Z_0-9]*)\s*is\s+port\s*\((?<ports>.*?)\);\s*end\s+\k<entity_name>\s*;/m)[:ports]
32
+ end
33
+
34
+ def remove_comments(vhdl)
35
+ vhdl.gsub(/--.*$/, '')
36
+ end
37
+
38
+ def entity
39
+ @vhdl.match(/entity\s+(.*)\s+is/)[1]
40
+ end
41
+
42
+ def cases
43
+ TestParser.new(@vhdl).parse(ports)
44
+ end
45
+
46
+ def dependencies
47
+ @vhdl.split("\n").
48
+ select { |line| line.include?('DOCTEST DEPENDENCIES') }.
49
+ map { |line| line.split(":")[1].split(",") }.
50
+ flatten.
51
+ map { |file| file.strip }
44
52
  end
45
53
  end
46
54
  end
@@ -0,0 +1,49 @@
1
+ module VhdlDoctest
2
+ class ResultFormatter
3
+ def initialize(output)
4
+ @output = output
5
+ end
6
+
7
+ # pretty print error message
8
+ def format
9
+ if compile_error?
10
+ "FAILED: Test did not run because of compilation error"
11
+ else
12
+ lines.reduce([]) do |formatted, l|
13
+ if l.match(/(FAILED: .*) expected to (.*), but (.*)/)
14
+ formatted << $1
15
+ formatted << " expected: " + $2
16
+ formatted << " actual: " + replace_binary($3)
17
+ end
18
+ formatted
19
+ end.join("\n")
20
+ end
21
+ end
22
+
23
+ def compile_error?
24
+ @output.include?("ghdl: compilation error")
25
+ end
26
+
27
+ def succeeded?
28
+ ! compile_error? && ! failed?
29
+ end
30
+
31
+ def failed?
32
+ @output.include?("FAILED")
33
+ end
34
+
35
+ def count_failure
36
+ lines.select{ |l| l.match(/FAILED/) }.count
37
+ end
38
+
39
+ # convert binary expression in a string to decimal
40
+ def replace_binary(str)
41
+ str.gsub(/[01]+/) { |bin| bin.to_i(2).to_s(10) }
42
+ end
43
+
44
+ private
45
+ def lines
46
+ @output.split("\n")
47
+ end
48
+ end
49
+ end
@@ -1,43 +1,63 @@
1
1
  module VhdlDoctest
2
2
  class OutOfRangeSymbolError < RuntimeError
3
- def initialize(port, radix, bad_value)
4
- @port, @bad_value = port, bad_value
5
-
6
- @radix = case radix
7
- when 2; 'binary'
8
- when 10; 'decimal'
9
- when 16; 'hex'
10
- end
3
+ def initialize(bad_value, allowed)
4
+ super("#{ bad_value } includes not allowed symbol(s): #{ allowed }")
11
5
  end
6
+ end
7
+
8
+ class TestParser
9
+ def initialize(vhdl)
10
+ @vhdl = vhdl
11
+ d = lambda do |x|
12
+ assert_in_range(("0".."9").to_a + %w{ - }, x)
13
+ x.to_i
14
+ end
15
+
16
+ h = lambda do |x|
17
+ assert_in_range(("0".."9").to_a + ("a".."f").to_a, x)
18
+ x.to_i(16)
19
+ end
12
20
 
13
- def to_s
14
- "#@port expects #@radix, but received #@bad_value"
21
+ b = lambda do |x|
22
+ assert_in_range(%w{ 0 1 }, x)
23
+ x.to_i(2)
24
+ end
25
+ @decoders = { 'd' => d, 'h' => h, 'x' => h, 'b' => b }
15
26
  end
16
- end
17
27
 
18
- module TestParser
19
- extend self
20
- def parse(ports, vhdl)
21
- names, vectors = extract_values(vhdl)
28
+ def parse(ports)
29
+ names, vectors = extract_values(@vhdl)
22
30
  defined_ports = names.map { |name| ports.find { |p| p.name == name } }
23
31
  vectors.map { |v| TestCase.new(Hash[defined_ports.zip(v)]) }
24
32
  end
25
33
 
34
+ # find decoder to decode given value
35
+ def decode(decoder, value)
36
+ if fun = @decoders[decoder || 'd']
37
+ fun.call(value)
38
+ else
39
+ raise "Cannot decode #{value} with decoder #{decoder}. Unknown decoder."
40
+ end
41
+ end
42
+
43
+ # convert decoder definition string to lambda
44
+ # Example:
45
+ # def f { |x| x.include?(".") ? [x.to_f].pack('f').unpack('I').first : x.to_i }
46
+ # => #<Proc>
47
+ def def_to_lambda(def_string)
48
+ if def_string.match(/def\s+([[:alnum:]]*)\s+{([^}]*)}/)
49
+ [$1, eval("lambda { #{ $2 } }")]
50
+ end
51
+ end
52
+
53
+ def register_decoder(defs)
54
+ @decoders.merge! Hash[defs.map{ |d| def_to_lambda(d) }]
55
+ end
56
+
26
57
  private
27
- def assert_in_range(port_name, radix, string)
28
- symbols = case radix
29
- when 2
30
- %w{ 0 1 }
31
- when 10
32
- ("0".."9").to_a + %w{ - }
33
- when 16
34
- ("0".."9").to_a + ("a".."f").to_a
35
- else
36
- []
37
- end
38
-
39
- unless string.split(//).all? { |s| symbols.include? s }
40
- raise OutOfRangeSymbolError.new(port_name, radix, string)
58
+ def assert_in_range(allowed, string)
59
+ unless string.split(//).all? { |s| allowed.include? s }
60
+ raise OutOfRangeSymbolError.new(string, allowed)
41
61
  end
42
62
  end
43
63
 
@@ -51,66 +71,79 @@ module VhdlDoctest
51
71
  line.split("|").map(&:strip)
52
72
  end
53
73
 
54
- def test_definitions(vhdl)
74
+ def test_block(vhdl)
55
75
  lines = vhdl.match(/-- TEST\n(.*)-- \/TEST/m)[1].
56
- gsub(/\#.*$/, ''). # remove comments
57
- gsub(/--\s*\n/m, ''). # remove blank lines
76
+ gsub(/\#.*$/, ''). # remove comments
77
+ gsub(/^---*[ \t]*/, ''). # remove VHDL comments
78
+ gsub(/^\s*\n/m, ''). # remove blank lines
58
79
  split("\n")
59
- lines.partition { |l| l.include? 'alias' }
80
+ end
81
+
82
+ def test_definition(vhdl)
83
+ empty = { aliases: [], decoders: [], cases: [] }
84
+ test_block(vhdl).reduce(empty) do |m, l|
85
+ case l
86
+ when /^alias/; m[:aliases] << l
87
+ when /^def/; m[:decoders] << l
88
+ else; m[:cases] << l
89
+ end
90
+ m
91
+ end
60
92
  rescue
61
93
  raise "Test definition not found"
62
94
  end
63
95
 
64
- def radix(attr)
65
- if attr
66
- case attr[-1]
67
- when 'b'; 2
68
- when 'h', 'x'; 16
96
+ def replace_aliases(aliases, case_table)
97
+ pairs = aliases.map { |l| l.match(/alias\s+([^ \t]*)\s+([^ \t]*)\s*$/)[1..2] }
98
+ pairs.sort_by! { |k,v| -k.length } # use longer alias first
99
+ case_table.each { |l| pairs.each { |p| l.gsub!(p[0], p[1]) } }
100
+ case_table
101
+ end
102
+
103
+ def remove_invalid_lines(body, idx)
104
+ body.select do |l|
105
+ if l.empty?
106
+ false
107
+ elsif ! l[idx]
108
+ warn l.join(" | ") + " does not have enough columns"
109
+ false
110
+ else
111
+ true
69
112
  end
70
- else
71
- 10
72
113
  end
73
114
  end
74
115
 
75
- def replace_aliases(defs, table)
76
- pairs = defs.map { |l| l.match(/alias\s+(.*)\s+(.*)$/)[1..2] }
77
- table.each { |l| pairs.each { |p| l.gsub!(p[0], p[1]) } }
78
- table
116
+ # fill empty cells inheriting the above value
117
+ # decode string into :dont_care or integer
118
+ # destructively change body
119
+ def normalize_testcases(body, idx, decoder)
120
+ prev = ''
121
+ body.each do |l|
122
+ if l[idx].empty?
123
+ l[idx] = prev
124
+ else
125
+ if l[idx].strip.match(/^-+$/)
126
+ l[idx] = :dont_care
127
+ else
128
+ l[idx] = decode(decoder, l[idx])
129
+ end
130
+ prev = l[idx]
131
+ end
132
+ end
79
133
  end
80
134
 
81
135
  def extract_values(vhdl)
82
- table = replace_aliases(*test_definitions(vhdl))
83
- header, *body = table.map { |l| extract_fields remove_comment l }
136
+ definition = test_definition(vhdl)
137
+ register_decoder(definition[:decoders])
138
+ table = replace_aliases(definition[:aliases], definition[:cases])
139
+ header, *body = table.map { |l| extract_fields l }
84
140
  port_names = []
85
141
 
86
142
  header.each_with_index do |h, idx|
87
- port_name, attr = h.split(' ', 2)
143
+ port_name, decoder_name = h.split(' ', 2)
88
144
  port_names << port_name
89
- prev = ''
90
- radix = radix(attr)
91
- body.select! do |l|
92
- if l.empty?
93
- false
94
- elsif ! l[idx]
95
- warn l.join(" | ") + " does not have enough columns"
96
- false
97
- else
98
- true
99
- end
100
- end
101
- body.each do |l|
102
- if l[idx].empty?
103
- l[idx] = prev
104
- else
105
- if l[idx].strip.match(/^-+$/)
106
- l[idx] = :dont_care
107
- else
108
- assert_in_range(port_name, radix, l[idx])
109
- l[idx] = l[idx].to_i(radix)
110
- end
111
- prev = l[idx]
112
- end
113
- end
145
+ body = remove_invalid_lines(body, idx)
146
+ normalize_testcases(body, idx, decoder_name)
114
147
  end
115
148
  [port_names, body]
116
149
  end
@@ -1,9 +1,13 @@
1
1
  module VhdlDoctest
2
2
  class TestRunner
3
- def initialize(out, dut_path, test_file)
3
+ def initialize(out, dut_path, test_file, dependencies = [])
4
4
  @out = out
5
5
  @dut_path = File.expand_path(dut_path)
6
6
  @test_file = test_file
7
+ @dependencies = dependencies
8
+
9
+ require 'tmpdir'
10
+ @dir = Dir.mktmpdir
7
11
  end
8
12
 
9
13
  def run
@@ -12,26 +16,32 @@ module VhdlDoctest
12
16
  report_result
13
17
  end
14
18
 
15
- private
16
19
  def create_files
17
- require 'tmpdir'
18
- @dir = Dir.mktmpdir
19
20
  @test_file.create(@dir)
21
+ create_runner_script
20
22
  end
21
23
 
22
- def run_test
23
- @result = ""
24
+ def dependencies
25
+ dut_dir = File.dirname(@dut_path)
26
+ @dependencies.map { |path| File.expand_path(path, dut_dir) }
27
+ end
24
28
 
25
- sh = File.join(@dir, "run.sh")
26
- File.open(sh, 'w') do |f|
29
+ def create_runner_script
30
+ @sh = File.join(@dir, "run.sh")
31
+ File.open(@sh, 'w') do |f|
27
32
  f << "#!/bin/sh -e\n\n"
28
33
  f << "cd #{@dir}\n"
29
- f << "ghdl -a --ieee=synopsys -fexplicit --warn-default-binding --warn-binding --warn-library --warn-body --warn-specs --warn-unused #{@dut_path} #{@test_file.path}\n"
34
+ f << "ghdl -a --ieee=synopsys -fexplicit --warn-default-binding --warn-binding --warn-library --warn-body --warn-specs --warn-unused #{dependencies.join(" ")} #{@dut_path} #{@test_file.path}\n"
30
35
  f << "ghdl -e -Plibs/unisim --ieee=synopsys -fexplicit #{@test_file.test_name}\n"
31
36
  f << "ghdl -r #{@test_file.test_name} --vcd=out.vcd --stop-time=10ms\n"
32
37
  end
38
+ end
33
39
 
34
- IO.popen("sh #{sh} 2>&1") do |f|
40
+ private
41
+ def run_test
42
+ @result = ""
43
+
44
+ IO.popen("sh #{@sh} 2>&1") do |f|
35
45
  output = f.read
36
46
  @result << output
37
47
  @out << output
@@ -39,8 +49,12 @@ module VhdlDoctest
39
49
  end
40
50
 
41
51
  def report_result
42
- failures = @result.split("\n").select { |l| l.include?('FAILED') }
43
- @out << "\n#{@test_file.cases.size} examples, #{failures.size} failures\n"
52
+ formatter = ResultFormatter.new(@result)
53
+ @out << "\n\n\n"
54
+ @out << formatter.format
55
+ unless formatter.compile_error?
56
+ @out << "\n#{@test_file.cases.size} examples, #{formatter.count_failure} failures\n"
57
+ end
44
58
  @out << "\nTest directory: #{@dir}\n"
45
59
  end
46
60
  end
@@ -9,7 +9,7 @@ module VhdlDoctest::Types
9
9
  end
10
10
 
11
11
  def format(v)
12
- '"' + v.to_s(2).rjust(@length, '0')+ '"'
12
+ '"' + (2**@length + v).to_s(2)[-@length.. -1]+ '"'
13
13
  end
14
14
 
15
15
  def self.parse(str)
@@ -1,3 +1,3 @@
1
1
  module VhdlDoctest
2
- VERSION = "0.0.4"
2
+ VERSION = "0.0.5"
3
3
  end
@@ -1,8 +1,8 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  module VhdlDoctest
4
- sample_vhdl = 'examples/alu.vhd'
5
4
  describe DUT do
5
+ let(:sample_vhdl) { 'examples/alu.vhd' }
6
6
  subject { DUT.parse(sample_vhdl) }
7
7
 
8
8
  its(:entity) { should == "alu" }
@@ -11,11 +11,35 @@ module VhdlDoctest
11
11
 
12
12
  its('test_file.test_name') { should == 'testbench_alu' }
13
13
  its(:test_file) { should have(8).cases }
14
- end
15
14
 
16
- describe DUT::DoctestParser do
15
+ describe 'dependencies' do
16
+ subject(:dut) { DUT.new(vhdl) }
17
+
18
+ context 'actual file' do
19
+ let(:vhdl) { File.read('examples/alu_depending.vhd') }
20
+ its(:dependencies) { should == ['test.vhd'] }
21
+ end
22
+
23
+ context 'multi files' do
24
+ let(:vhdl) { %q{
25
+ -- DOCTEST DEPENDENCIES: test.vhd, another.vhd
26
+ } }
27
+
28
+ its(:dependencies) { should == ['test.vhd', 'another.vhd'] }
29
+ end
30
+
31
+ context 'multi definition lines' do
32
+ let(:vhdl) { %q{
33
+ -- DOCTEST DEPENDENCIES: test.vhd
34
+ -- DOCTEST DEPENDENCIES: another.vhd
35
+ } }
36
+
37
+ its(:dependencies) { should == ['test.vhd', 'another.vhd'] }
38
+ end
39
+ end
40
+
17
41
  describe 'ports' do
18
- subject { described_class.new(sample_vhdl).extract_ports }
42
+ subject(:ports) { DUT.parse(sample_vhdl).ports }
19
43
 
20
44
  it { should have(5).items }
21
45
  its('first.port_definition') { should == "a : in std_logic_vector(31 downto 0)" }
@@ -0,0 +1,62 @@
1
+ require 'spec_helper'
2
+
3
+ module VhdlDoctest
4
+ describe ResultFormatter do
5
+ let(:dut_file) { "examples/alu.vhd/" }
6
+ subject(:formatted_result) { described_class.new(output) }
7
+
8
+ context "test did not run" do
9
+ let(:output) { %q{
10
+ /tmp/main_decoder.vhd:193:27: ')' expected at end of interface list
11
+ /tmp/main_decoder.vhd:193:29: missing ";" at end of port clause
12
+ /tmp/main_decoder.vhd:193:29: 'end' is expected instead of 'out'
13
+ ghdl: compilation error
14
+ error: cannot find entity or configuration testbench_main_decoder
15
+ ghdl: compilation error
16
+ ghdl: file 'testbench_main_decoder' does not exists
17
+ ghdl: Please elaborate your design.
18
+ }}
19
+
20
+ it { should be_compile_error }
21
+ it { should_not be_succeeded }
22
+ its(:format) { should match /FAIL/ }
23
+ its(:format) { should match /Test did not run/ }
24
+ end
25
+
26
+ context "test run, but one case failed" do
27
+ let(:output) { %q{/tmp/d20120910-14672-k0mvgz/testbench_main_decoder.vhd:587:1:@790ns:(assertion warning): FAILED: op = 44, rx_done = 0, stage = 1 expected to next_stage = 2, bus_to_reg = 0, alu_src = 0, pc_src = 0, reg_dst = 1, alu_control = 0, mem_write = 0, send_enable = 0, reg_write = 0, rx_enable = 0, but next_stage = 0010, bus_to_reg = 0, alu_src = 1, pc_src = 000, reg_dst = 0, alu_control = 0000, mem_write = 0, send_enable = 0, reg_write = 0, rx_enable = 0} }
28
+
29
+ it { should_not be_compile_error }
30
+ it { should_not be_succeeded }
31
+ it "should pretty print the result" do
32
+ subject.format.should include %q{
33
+ FAILED: op = 44, rx_done = 0, stage = 1
34
+ expected: next_stage = 2, bus_to_reg = 0, alu_src = 0, pc_src = 0, reg_dst = 1, alu_control = 0, mem_write = 0, send_enable = 0, reg_write = 0, rx_enable = 0
35
+ actual: next_stage = 2, bus_to_reg = 0, alu_src = 1, pc_src = 0, reg_dst = 0, alu_control = 0, mem_write = 0, send_enable = 0, reg_write = 0, rx_enable = 0
36
+ }.strip
37
+ end
38
+ its(:count_failure) { should == 1 }
39
+ end
40
+
41
+ context "test succeeded, output nothing" do
42
+ let(:output) { "" }
43
+
44
+ it { should be_succeeded }
45
+ end
46
+
47
+ describe '#replace_binary' do
48
+ def replace_binary(str)
49
+ ResultFormatter.new('').replace_binary(str)
50
+ end
51
+
52
+ specify do
53
+ expect(replace_binary('next_stage = 0010')).to eq('next_stage = 2')
54
+ end
55
+
56
+ specify do
57
+ expect(replace_binary('next_stage = 0010, alu_control = 0000')).
58
+ to eq('next_stage = 2, alu_control = 0')
59
+ end
60
+ end
61
+ end
62
+ end
@@ -25,7 +25,7 @@ module VhdlDoctest
25
25
  Port.new("output", :out, Types::StdLogicVector.new(32)),
26
26
  Port.new("zero", :out, Types::StdLogic.new)
27
27
  ]}
28
- subject(:cases) { TestParser.parse(ports, input) }
28
+ subject(:cases) { TestParser.new(input).parse(ports) }
29
29
 
30
30
  describe 'header only' do
31
31
  let(:input) { %q{
@@ -83,7 +83,7 @@ module VhdlDoctest
83
83
  -- /TEST
84
84
  }}
85
85
 
86
- it { expect{ cases }.to raise_error(OutOfRangeSymbolError, /control.*binary.*012/) }
86
+ it { expect{ cases }.to raise_error(OutOfRangeSymbolError) }
87
87
  end
88
88
 
89
89
  describe 'dont care in assertion' do
@@ -164,6 +164,21 @@ module VhdlDoctest
164
164
  specify { cases.last.should assert(zero: 0) }
165
165
  end
166
166
 
167
+ describe 'use a longer alias first' do
168
+ let(:input) { %q{
169
+ -- TEST
170
+ -- alias FOO 1
171
+ -- alias FOOBAR 0
172
+ -- a | b | control | zero
173
+ -- 10 | -10 | 2 | FOO
174
+ -- 10 | 10 | 2 | FOOBAR
175
+ -- /TEST
176
+ }}
177
+
178
+ specify { cases.first.should assert(zero: 1) }
179
+ specify { cases.last.should assert(zero: 0) }
180
+ end
181
+
167
182
  describe 'not enough fields' do
168
183
  let(:input) { %q{
169
184
  -- TEST
@@ -175,5 +190,38 @@ module VhdlDoctest
175
190
 
176
191
  specify { cases.should have(1).item }
177
192
  end
193
+
194
+ describe 'custom field style' do
195
+ let(:input) { %q{
196
+ -- TEST
197
+ -- def f { |x| x.include?(".") ? [x.to_f].pack('f').unpack('I').first : x.to_i }
198
+ -- a f | b | control | zero
199
+ -- 10 | 1 | 0 | 0
200
+ -- 10.0 | 0 | 0 | 0
201
+ -- /TEST
202
+ }}
203
+
204
+ its(:first) { should set(a: 10) }
205
+ its(:last) { should set(a: 1092616192) }
206
+ end
207
+
208
+ describe '#decode' do
209
+ def decode(*args)
210
+ described_class.new(nil).decode(*args)
211
+ end
212
+ describe 'd' do
213
+ specify { decode('d', '10').should == 10 }
214
+ specify { decode('d', '-10').should == -10 }
215
+ specify { expect{ decode('d', 'hoge') }.to raise_error(OutOfRangeSymbolError) }
216
+ end
217
+ end
218
+
219
+ describe 'create lambda from def' do
220
+ it 'should define lambda with given name' do
221
+ name, proc = described_class.new(nil).def_to_lambda("def f { |x| x }")
222
+ name.should == 'f'
223
+ proc.call(3).should == 3
224
+ end
225
+ end
178
226
  end
179
227
  end
@@ -4,31 +4,54 @@ module VhdlDoctest
4
4
  describe TestRunner do
5
5
  let(:dut_file) { "examples/alu.vhd/" }
6
6
  describe "#run" do
7
+ let(:out) { StringIO.new }
8
+ subject { out.rewind; out.read }
9
+ before { described_class.new(out, dut_file, file).run }
10
+
7
11
  context "3 successful examples" do
8
- let(:out) { StringIO.new }
9
12
  let(:file) { test_file([[18, 9, 0, 0, 1], [18, 18, 7, 0, 1], [18, 19, 7, 1, 0]]) }
10
- subject { out.rewind; out.read }
11
- before { described_class.new(out, dut_file, file).run }
12
13
 
13
14
  it { should match "3 examples, 0 failures" }
14
15
  end
15
16
 
16
17
  context "1 successful examples" do
17
- let(:out) { StringIO.new }
18
18
  let(:file) { test_file([[18, 9, 0, 0, 1]]) }
19
- subject { out.rewind; out.read }
20
- before { described_class.new(out, dut_file, file).run }
21
19
 
22
20
  it { should match "1 examples, 0 failures" }
23
21
  end
24
22
 
25
23
  context "1 failing examples" do
26
- let(:out) { StringIO.new }
27
24
  let(:file) { test_file([[18, 9, 0, 0, 0]]) }
28
- subject { out.rewind; out.read }
29
- before { described_class.new(out, dut_file, file).run }
30
25
 
31
26
  it { should match "1 examples, 1 failures" }
27
+ it { should match "actual:" }
28
+ end
29
+
30
+ context "stimuli including minus" do
31
+ let(:file) { test_file([[18, -9, 2, 9, 0]]) }
32
+
33
+ it { should match "1 examples, 0 failures" }
34
+ end
35
+
36
+ context "result including minus" do
37
+ let(:file) { test_file([[-18, -9, 2, -27, 0]]) }
38
+
39
+ it { should match "1 examples, 0 failures" }
40
+ end
41
+ end
42
+
43
+ describe '#create_runner_script' do
44
+ context 'a dependent module comparator.vhd is specified' do
45
+ before do
46
+ dir = nil
47
+ test_file = double(TestFile, path: '/test_file/path/test.vhd', test_name: 'test')
48
+ test_file.stub(:create) { |d| dir = d }
49
+ runner = described_class.new(nil, "/path/to/dut.vhd", test_file, %w{ ./comparator.vhd })
50
+ runner.create_files
51
+ @sh = File.join(dir, 'run.sh')
52
+ end
53
+ subject { File.read(@sh) }
54
+ it { should include '/path/to/comparator.vhd' }
32
55
  end
33
56
  end
34
57
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: vhdl_doctest
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.4
4
+ version: 0.0.5
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-09-09 00:00:00.000000000 Z
12
+ date: 2012-09-14 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rspec
@@ -59,9 +59,11 @@ files:
59
59
  - Rakefile
60
60
  - bin/vhdl_doctest
61
61
  - examples/alu.vhd
62
+ - examples/alu_depending.vhd
62
63
  - lib/vhdl_doctest.rb
63
64
  - lib/vhdl_doctest/dut.rb
64
65
  - lib/vhdl_doctest/port.rb
66
+ - lib/vhdl_doctest/result_formatter.rb
65
67
  - lib/vhdl_doctest/test_case.rb
66
68
  - lib/vhdl_doctest/test_file.rb
67
69
  - lib/vhdl_doctest/test_parser.rb
@@ -72,6 +74,7 @@ files:
72
74
  - lib/vhdl_doctest/version.rb
73
75
  - spec/dut_spec.rb
74
76
  - spec/port_spec.rb
77
+ - spec/result_formatter_spec.rb
75
78
  - spec/spec_helper.rb
76
79
  - spec/test_parser_spec.rb
77
80
  - spec/test_runner_spec.rb
@@ -91,7 +94,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
91
94
  version: '0'
92
95
  segments:
93
96
  - 0
94
- hash: -47820915
97
+ hash: 765515069
95
98
  required_rubygems_version: !ruby/object:Gem::Requirement
96
99
  none: false
97
100
  requirements:
@@ -100,7 +103,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
100
103
  version: '0'
101
104
  segments:
102
105
  - 0
103
- hash: -47820915
106
+ hash: 765515069
104
107
  requirements: []
105
108
  rubyforge_project:
106
109
  rubygems_version: 1.8.24
@@ -110,6 +113,7 @@ summary: Run parameterized test for VHDL written in doctest-like format.
110
113
  test_files:
111
114
  - spec/dut_spec.rb
112
115
  - spec/port_spec.rb
116
+ - spec/result_formatter_spec.rb
113
117
  - spec/spec_helper.rb
114
118
  - spec/test_parser_spec.rb
115
119
  - spec/test_runner_spec.rb