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