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.
- data/bin/vhdl_doctest +2 -2
- data/examples/alu_depending.vhd +56 -0
- data/lib/vhdl_doctest.rb +1 -0
- data/lib/vhdl_doctest/dut.rb +42 -34
- data/lib/vhdl_doctest/result_formatter.rb +49 -0
- data/lib/vhdl_doctest/test_parser.rb +105 -72
- data/lib/vhdl_doctest/test_runner.rb +26 -12
- data/lib/vhdl_doctest/types/std_logic_vector.rb +1 -1
- data/lib/vhdl_doctest/version.rb +1 -1
- data/spec/dut_spec.rb +28 -4
- data/spec/result_formatter_spec.rb +62 -0
- data/spec/test_parser_spec.rb +50 -2
- data/spec/test_runner_spec.rb +32 -9
- metadata +8 -4
data/bin/vhdl_doctest
CHANGED
@@ -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
|
-
|
17
|
+
dut = VhdlDoctest::DUT.parse(ARGV[0])
|
18
18
|
|
19
|
-
VhdlDoctest::TestRunner.new(STDOUT, ARGV[0],
|
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;
|
data/lib/vhdl_doctest.rb
CHANGED
data/lib/vhdl_doctest/dut.rb
CHANGED
@@ -1,46 +1,54 @@
|
|
1
1
|
module VhdlDoctest
|
2
2
|
class DUT
|
3
3
|
def self.parse(path)
|
4
|
-
|
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(
|
10
|
-
@
|
8
|
+
def initialize(vhdl)
|
9
|
+
@vhdl = vhdl
|
11
10
|
end
|
12
11
|
|
13
12
|
def test_file
|
14
|
-
TestFile.new(
|
15
|
-
end
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
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(
|
4
|
-
|
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
|
-
|
14
|
-
|
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
|
-
|
19
|
-
|
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(
|
28
|
-
|
29
|
-
|
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
|
74
|
+
def test_block(vhdl)
|
55
75
|
lines = vhdl.match(/-- TEST\n(.*)-- \/TEST/m)[1].
|
56
|
-
gsub(/\#.*$/, '').
|
57
|
-
gsub(
|
76
|
+
gsub(/\#.*$/, ''). # remove comments
|
77
|
+
gsub(/^---*[ \t]*/, ''). # remove VHDL comments
|
78
|
+
gsub(/^\s*\n/m, ''). # remove blank lines
|
58
79
|
split("\n")
|
59
|
-
|
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
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
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
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
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
|
-
|
83
|
-
|
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,
|
143
|
+
port_name, decoder_name = h.split(' ', 2)
|
88
144
|
port_names << port_name
|
89
|
-
|
90
|
-
|
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
|
23
|
-
|
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
|
-
|
26
|
-
File.
|
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
|
-
|
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
|
-
|
43
|
-
@out << "\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
|
data/lib/vhdl_doctest/version.rb
CHANGED
data/spec/dut_spec.rb
CHANGED
@@ -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
|
-
|
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 {
|
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
|
data/spec/test_parser_spec.rb
CHANGED
@@ -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
|
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
|
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
|
data/spec/test_runner_spec.rb
CHANGED
@@ -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
|
+
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-
|
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:
|
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:
|
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
|