vhdl_doctest 0.0.4 → 0.0.5

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