pwl 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +10 -12
- data/Gemfile.lock +19 -14
- data/README.md +1 -1
- data/VERSION +1 -1
- data/bin/pwl +51 -43
- data/lib/pwl.rb +6 -2
- data/lib/pwl/{store.rb → locker.rb} +19 -21
- data/lib/pwl/presenter/html.rb +19 -0
- data/lib/pwl/presenter/json.rb +22 -0
- data/lib/pwl/presenter/yaml.rb +23 -0
- data/pwl.gemspec +35 -23
- data/templates/export.html.erb +2 -2
- data/test/acceptance/test_add.rb +19 -0
- data/test/acceptance/test_delete.rb +1 -1
- data/test/acceptance/test_export.rb +4 -4
- data/test/acceptance/test_export_json.rb +59 -0
- data/test/acceptance/test_export_yaml.rb +59 -0
- data/test/acceptance/test_get.rb +1 -1
- data/test/acceptance/test_init.rb +6 -6
- data/test/acceptance/test_list.rb +3 -3
- data/test/acceptance/test_passwd.rb +2 -2
- data/test/fixtures/test_all.json +19 -0
- data/test/fixtures/test_all.yaml +11 -0
- data/test/fixtures/test_empty.json +7 -0
- data/test/fixtures/test_empty.yaml +5 -0
- data/test/helper.rb +8 -8
- data/test/unit/test_store_construction.rb +26 -26
- data/test/unit/test_store_crud.rb +35 -35
- data/test/unit/test_store_metadata.rb +16 -16
- data/test/unit/test_store_password_policy.rb +6 -6
- data/test/unit/test_store_security.rb +13 -13
- metadata +82 -27
- data/test/acceptance/test_put.rb +0 -19
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'erb'
|
2
|
+
|
3
|
+
module Pwl
|
4
|
+
module Presenter
|
5
|
+
class Html
|
6
|
+
attr_reader :locker # used by the ERB template
|
7
|
+
DEFAULT_EXPORT_TEMPLATE = File.join(File.dirname(__FILE__), *%w[.. .. .. templates export.html.erb])
|
8
|
+
|
9
|
+
def initialize(locker)
|
10
|
+
@locker = locker
|
11
|
+
@template = ERB.new(File.read(DEFAULT_EXPORT_TEMPLATE))
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_s
|
15
|
+
@template.result(binding)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'jbuilder'
|
2
|
+
|
3
|
+
module Pwl
|
4
|
+
module Presenter
|
5
|
+
class Json
|
6
|
+
def initialize(locker)
|
7
|
+
@locker = locker
|
8
|
+
end
|
9
|
+
|
10
|
+
def to_s
|
11
|
+
Jbuilder.encode do |json|
|
12
|
+
json.(@locker, :created, :last_accessed, :last_modified)
|
13
|
+
|
14
|
+
json.entries @locker.all do |json, entry|
|
15
|
+
json.key entry.first
|
16
|
+
json.value entry.last
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
3
|
+
module Pwl
|
4
|
+
module Presenter
|
5
|
+
class Yaml
|
6
|
+
def initialize(locker)
|
7
|
+
@locker = locker
|
8
|
+
end
|
9
|
+
|
10
|
+
def to_s
|
11
|
+
result = {}
|
12
|
+
result[:created] = @locker.created.to_s
|
13
|
+
result[:last_accessed] = @locker.last_accessed.to_s
|
14
|
+
result[:last_modified] = @locker.last_modified.to_s
|
15
|
+
result[:entries] = []
|
16
|
+
@locker.all.each{|entry|
|
17
|
+
result[:entries] << {:key => entry.first, :value => entry.last}
|
18
|
+
}
|
19
|
+
result.to_yaml
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
data/pwl.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = "pwl"
|
8
|
-
s.version = "0.0.
|
8
|
+
s.version = "0.0.2"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Nicholas E. Rabenau"]
|
12
|
-
s.date = "2012-
|
12
|
+
s.date = "2012-05-02"
|
13
13
|
s.description = "pwl is a secure password locker for the commandline"
|
14
14
|
s.email = "nerab@gmx.net"
|
15
15
|
s.executables = ["pwl", "pwl"]
|
@@ -33,22 +33,31 @@ Gem::Specification.new do |s|
|
|
33
33
|
"lib/pwl/dialog/cocoa.rb",
|
34
34
|
"lib/pwl/dialog/console.rb",
|
35
35
|
"lib/pwl/dialog/gnome.rb",
|
36
|
+
"lib/pwl/locker.rb",
|
36
37
|
"lib/pwl/message.rb",
|
37
38
|
"lib/pwl/password_policy.rb",
|
38
|
-
"lib/pwl/
|
39
|
+
"lib/pwl/presenter/html.rb",
|
40
|
+
"lib/pwl/presenter/json.rb",
|
41
|
+
"lib/pwl/presenter/yaml.rb",
|
39
42
|
"pwl.gemspec",
|
40
43
|
"templates/export.html.erb",
|
44
|
+
"test/acceptance/test_add.rb",
|
41
45
|
"test/acceptance/test_basics.rb",
|
42
46
|
"test/acceptance/test_delete.rb",
|
43
47
|
"test/acceptance/test_dialogs.rb",
|
44
48
|
"test/acceptance/test_export.rb",
|
49
|
+
"test/acceptance/test_export_json.rb",
|
50
|
+
"test/acceptance/test_export_yaml.rb",
|
45
51
|
"test/acceptance/test_get.rb",
|
46
52
|
"test/acceptance/test_init.rb",
|
47
53
|
"test/acceptance/test_list.rb",
|
48
54
|
"test/acceptance/test_passwd.rb",
|
49
|
-
"test/acceptance/test_put.rb",
|
50
55
|
"test/fixtures/test_all.html",
|
56
|
+
"test/fixtures/test_all.json",
|
57
|
+
"test/fixtures/test_all.yaml",
|
51
58
|
"test/fixtures/test_empty.html",
|
59
|
+
"test/fixtures/test_empty.json",
|
60
|
+
"test/fixtures/test_empty.yaml",
|
52
61
|
"test/helper.rb",
|
53
62
|
"test/unit/test_error.rb",
|
54
63
|
"test/unit/test_message.rb",
|
@@ -61,34 +70,37 @@ Gem::Specification.new do |s|
|
|
61
70
|
s.homepage = "http://github.com/nerab/pwl"
|
62
71
|
s.licenses = ["MIT"]
|
63
72
|
s.require_paths = ["lib"]
|
64
|
-
s.rubygems_version = "1.8.
|
73
|
+
s.rubygems_version = "1.8.24"
|
65
74
|
s.summary = "Command-line password locker"
|
66
75
|
|
67
76
|
if s.respond_to? :specification_version then
|
68
77
|
s.specification_version = 3
|
69
78
|
|
70
79
|
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
71
|
-
s.add_runtime_dependency(%q<encryptor>, ["
|
72
|
-
s.add_runtime_dependency(%q<commander>, ["
|
73
|
-
s.add_runtime_dependency(%q<activesupport>, ["
|
74
|
-
s.
|
75
|
-
s.add_development_dependency(%q<
|
76
|
-
s.add_development_dependency(%q<
|
80
|
+
s.add_runtime_dependency(%q<encryptor>, ["~> 1.1"])
|
81
|
+
s.add_runtime_dependency(%q<commander>, ["~> 4.1"])
|
82
|
+
s.add_runtime_dependency(%q<activesupport>, ["~> 3.2"])
|
83
|
+
s.add_runtime_dependency(%q<jbuilder>, ["~> 0.4"])
|
84
|
+
s.add_development_dependency(%q<rdoc>, ["~> 3.1"])
|
85
|
+
s.add_development_dependency(%q<bundler>, ["~> 1.1"])
|
86
|
+
s.add_development_dependency(%q<jeweler>, ["~> 1.8"])
|
77
87
|
else
|
78
|
-
s.add_dependency(%q<encryptor>, ["
|
79
|
-
s.add_dependency(%q<commander>, ["
|
80
|
-
s.add_dependency(%q<activesupport>, ["
|
81
|
-
s.add_dependency(%q<
|
82
|
-
s.add_dependency(%q<
|
83
|
-
s.add_dependency(%q<
|
88
|
+
s.add_dependency(%q<encryptor>, ["~> 1.1"])
|
89
|
+
s.add_dependency(%q<commander>, ["~> 4.1"])
|
90
|
+
s.add_dependency(%q<activesupport>, ["~> 3.2"])
|
91
|
+
s.add_dependency(%q<jbuilder>, ["~> 0.4"])
|
92
|
+
s.add_dependency(%q<rdoc>, ["~> 3.1"])
|
93
|
+
s.add_dependency(%q<bundler>, ["~> 1.1"])
|
94
|
+
s.add_dependency(%q<jeweler>, ["~> 1.8"])
|
84
95
|
end
|
85
96
|
else
|
86
|
-
s.add_dependency(%q<encryptor>, ["
|
87
|
-
s.add_dependency(%q<commander>, ["
|
88
|
-
s.add_dependency(%q<activesupport>, ["
|
89
|
-
s.add_dependency(%q<
|
90
|
-
s.add_dependency(%q<
|
91
|
-
s.add_dependency(%q<
|
97
|
+
s.add_dependency(%q<encryptor>, ["~> 1.1"])
|
98
|
+
s.add_dependency(%q<commander>, ["~> 4.1"])
|
99
|
+
s.add_dependency(%q<activesupport>, ["~> 3.2"])
|
100
|
+
s.add_dependency(%q<jbuilder>, ["~> 0.4"])
|
101
|
+
s.add_dependency(%q<rdoc>, ["~> 3.1"])
|
102
|
+
s.add_dependency(%q<bundler>, ["~> 1.1"])
|
103
|
+
s.add_dependency(%q<jeweler>, ["~> 1.8"])
|
92
104
|
end
|
93
105
|
end
|
94
106
|
|
data/templates/export.html.erb
CHANGED
@@ -44,12 +44,12 @@
|
|
44
44
|
<td colspan="2">
|
45
45
|
This <a href="http://rdoc.info/github/nerab/pwl/master/frames">pwl</a> export was created on <%= DateTime.now.strftime('%F %R') %>.
|
46
46
|
<br/>
|
47
|
-
The database at <%=
|
47
|
+
The database at <%= locker.path %> was <%= "last modified #{locker.last_modified.strftime('%F %R')}" rescue 'never modified' %>.
|
48
48
|
</td>
|
49
49
|
</tr>
|
50
50
|
</tfoot>
|
51
51
|
<tbody>
|
52
|
-
<%
|
52
|
+
<% locker.all.each{|key, value|%>
|
53
53
|
<tr>
|
54
54
|
<td><%= key %></td>
|
55
55
|
<td><%= value %></td>
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
# Tests `pwl add`
|
4
|
+
class TestAdd < Test::Pwl::AppTestCase
|
5
|
+
def test_add_blank_key
|
6
|
+
assert_error('may not be blank', 'add')
|
7
|
+
end
|
8
|
+
|
9
|
+
def test_add_simple
|
10
|
+
assert_successful('', 'add foo bar')
|
11
|
+
assert_successful('^bar$', 'get foo')
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_add_update
|
15
|
+
assert_successful('', 'add foo bar')
|
16
|
+
assert_successful('', 'add foo baz') # just do it twice
|
17
|
+
assert_successful('^baz$', 'get foo')
|
18
|
+
end
|
19
|
+
end
|
@@ -4,23 +4,23 @@ require 'nokogiri/diff'
|
|
4
4
|
# Tests `pwl export`
|
5
5
|
class TestExport < Test::Pwl::AppTestCase
|
6
6
|
def test_empty
|
7
|
-
fixture = fixture("test_empty.html").gsub('CREATED_STAMP', DateTime.now.strftime('%F %R')).gsub('MODIFIED_STAMP', 'never').gsub('DATABASE_FILE',
|
7
|
+
fixture = fixture("test_empty.html").gsub('CREATED_STAMP', DateTime.now.strftime('%F %R')).gsub('MODIFIED_STAMP', 'never').gsub('DATABASE_FILE', locker_file)
|
8
8
|
assert_successful_html(fixture, 'export')
|
9
9
|
end
|
10
10
|
|
11
11
|
def test_all
|
12
12
|
test_vector = Hash['foo', 'one', 'bar', 'two', 'Chuck Norris', 'Roundhouse Kick']
|
13
13
|
test_vector.each{|k,v|
|
14
|
-
assert_successful('', "
|
14
|
+
assert_successful('', "add '#{k}' '#{v}'")
|
15
15
|
}
|
16
16
|
|
17
17
|
now = DateTime.now.strftime('%F %R')
|
18
|
-
fixture = fixture("test_all.html").gsub('CREATED_STAMP', now).gsub('MODIFIED_STAMP', now).gsub('DATABASE_FILE',
|
18
|
+
fixture = fixture("test_all.html").gsub('CREATED_STAMP', now).gsub('MODIFIED_STAMP', now).gsub('DATABASE_FILE', locker_file)
|
19
19
|
|
20
20
|
assert_successful_html(fixture, 'export')
|
21
21
|
end
|
22
22
|
|
23
|
-
def assert_successful_html(expected_out, cmd, password =
|
23
|
+
def assert_successful_html(expected_out, cmd, password = locker_password)
|
24
24
|
out, err, rc = execute(cmd, password)
|
25
25
|
assert_equal(0, rc.exitstatus, "Expected exit status 0, but it was #{rc.exitstatus}. STDERR was: #{err}")
|
26
26
|
assert(err.empty?, "Expected empty STDERR, but it yielded #{err}")
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'helper'
|
2
|
+
require 'json'
|
3
|
+
|
4
|
+
# Tests `pwl export --format json`
|
5
|
+
class TestExportJSON < Test::Pwl::AppTestCase
|
6
|
+
def test_empty
|
7
|
+
fixture = fixture("test_empty.json")
|
8
|
+
assert_successful_json(fixture, 'export --format json')
|
9
|
+
end
|
10
|
+
|
11
|
+
def test_all
|
12
|
+
test_vector = Hash['foo', 'one', 'bar', 'two', 'Chuck Norris', 'Roundhouse Kick']
|
13
|
+
test_vector.each{|k,v|
|
14
|
+
assert_successful('', "add '#{k}' '#{v}'")
|
15
|
+
}
|
16
|
+
|
17
|
+
now = DateTime.now.strftime('%F %R')
|
18
|
+
fixture = fixture("test_all.json")
|
19
|
+
|
20
|
+
assert_successful_json(fixture, 'export --format json')
|
21
|
+
end
|
22
|
+
|
23
|
+
def assert_successful_json(expected_out, cmd, password = locker_password)
|
24
|
+
out, err, rc = execute(cmd, password)
|
25
|
+
assert_equal(0, rc.exitstatus, "Expected exit status 0, but it was #{rc.exitstatus}. STDERR was: #{err}")
|
26
|
+
assert(err.empty?, "Expected empty STDERR, but it yielded #{err}")
|
27
|
+
|
28
|
+
actual = JSON.parse(out)
|
29
|
+
expected = JSON.parse(expected_out)
|
30
|
+
|
31
|
+
# fix up actuals to match expectations
|
32
|
+
actual["created"] = "2012-03-28T21:54:21+02:00"
|
33
|
+
actual["last_accessed"] = "2012-03-28T22:01:49+02:00"
|
34
|
+
actual["last_modified"] = "2012-03-29T22:46:29+02:00"
|
35
|
+
|
36
|
+
# This is essentially the same as
|
37
|
+
# assert_equal(expected, actual)
|
38
|
+
# but it provides better diagnostic output on error
|
39
|
+
json_diff(expected, actual)
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
def json_diff(expected, actual, context = nil)
|
44
|
+
assert_equal(expected.class, actual.class)
|
45
|
+
|
46
|
+
case expected
|
47
|
+
when Hash
|
48
|
+
actual.keys.each do |key|
|
49
|
+
json_diff(expected[key], actual[key], "#{context}/#{String == expected[key].class ? '@' : ''}#{key}")
|
50
|
+
end
|
51
|
+
when Array
|
52
|
+
actual.each_with_index do |e, i|
|
53
|
+
json_diff(expected[i], actual[i], "#{context}[#{i}]")
|
54
|
+
end
|
55
|
+
else
|
56
|
+
assert_equal(expected, actual, "#{context} is not the same:")
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'helper'
|
2
|
+
require 'yaml'
|
3
|
+
|
4
|
+
# Tests `pwl export --format yaml`
|
5
|
+
class TestExportYAML < Test::Pwl::AppTestCase
|
6
|
+
def test_empty
|
7
|
+
fixture = fixture("test_empty.yaml")
|
8
|
+
assert_successful_yaml(fixture, 'export --format yaml')
|
9
|
+
end
|
10
|
+
|
11
|
+
def test_all
|
12
|
+
test_vector = Hash['foo', 'one', 'bar', 'two', 'Chuck Norris', 'Roundhouse Kick']
|
13
|
+
test_vector.each{|k,v|
|
14
|
+
assert_successful('', "add '#{k}' '#{v}'")
|
15
|
+
}
|
16
|
+
|
17
|
+
now = DateTime.now.strftime('%F %R')
|
18
|
+
fixture = fixture("test_all.yaml")
|
19
|
+
|
20
|
+
assert_successful_yaml(fixture, 'export --format yaml')
|
21
|
+
end
|
22
|
+
|
23
|
+
def assert_successful_yaml(expected_out, cmd, password = locker_password)
|
24
|
+
out, err, rc = execute(cmd, password)
|
25
|
+
assert_equal(0, rc.exitstatus, "Expected exit status 0, but it was #{rc.exitstatus}. STDERR was: #{err}")
|
26
|
+
assert(err.empty?, "Expected empty STDERR, but it yielded #{err}")
|
27
|
+
|
28
|
+
actual = YAML.load(out)
|
29
|
+
expected = YAML.load(expected_out)
|
30
|
+
|
31
|
+
# fix up actuals to match expectations
|
32
|
+
actual[:created] = "2012-03-28T21:54:21+02:00"
|
33
|
+
actual[:last_accessed] = "2012-03-28T22:01:49+02:00"
|
34
|
+
actual[:last_modified] = "2012-03-29T22:46:29+02:00"
|
35
|
+
|
36
|
+
# This is essentially the same as
|
37
|
+
# assert_equal(expected, actual)
|
38
|
+
# but it provides better diagnostic output on error
|
39
|
+
yaml_diff(expected, actual)
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
def yaml_diff(expected, actual, context = nil)
|
44
|
+
#assert_equal(expected.class, actual.class)
|
45
|
+
|
46
|
+
case expected
|
47
|
+
when Hash
|
48
|
+
actual.keys.each do |key|
|
49
|
+
yaml_diff(expected[key], actual[key], "#{context}/#{String == expected[key].class ? '@' : ''}#{key}")
|
50
|
+
end
|
51
|
+
when Array
|
52
|
+
actual.each_with_index do |e, i|
|
53
|
+
yaml_diff(expected[i], actual[i], "#{context}[#{i}]")
|
54
|
+
end
|
55
|
+
else
|
56
|
+
assert_equal(expected, actual, "#{context} is not the same:")
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
data/test/acceptance/test_get.rb
CHANGED
@@ -11,7 +11,7 @@ class TestGet < Test::Pwl::AppTestCase
|
|
11
11
|
end
|
12
12
|
|
13
13
|
def test_get_known_key
|
14
|
-
assert_successful('', '
|
14
|
+
assert_successful('', 'add foo bar') # TODO Use a fixture instead of add
|
15
15
|
assert_successful('^bar$', 'get foo')
|
16
16
|
end
|
17
17
|
end
|
@@ -13,11 +13,11 @@ class TestInit < Test::Pwl::AppTestCase
|
|
13
13
|
# **************
|
14
14
|
# Enter master password again:
|
15
15
|
# **************
|
16
|
-
# Successfully initialized new
|
16
|
+
# Successfully initialized new locker at ...
|
17
17
|
# $
|
18
18
|
#
|
19
19
|
def test_matching_passwords
|
20
|
-
cmd = "bin/pwl init --force --verbose --file \"#{@
|
20
|
+
cmd = "bin/pwl init --force --verbose --file \"#{@locker_file}\""
|
21
21
|
|
22
22
|
PTY.spawn(cmd){|pwl_out, pwl_in, pid|
|
23
23
|
assert_response('Enter new master password:', pwl_out)
|
@@ -26,7 +26,7 @@ class TestInit < Test::Pwl::AppTestCase
|
|
26
26
|
assert_response('Enter master password again:', pwl_out)
|
27
27
|
pwl_in.puts("secr3tPassw0rd")
|
28
28
|
|
29
|
-
assert_response('Successfully initialized new
|
29
|
+
assert_response('Successfully initialized new locker', pwl_out)
|
30
30
|
}
|
31
31
|
end
|
32
32
|
|
@@ -44,7 +44,7 @@ class TestInit < Test::Pwl::AppTestCase
|
|
44
44
|
# $
|
45
45
|
#
|
46
46
|
def test_unmatching_passwords
|
47
|
-
cmd = "bin/pwl init --force --verbose --file \"#{
|
47
|
+
cmd = "bin/pwl init --force --verbose --file \"#{locker_file}\""
|
48
48
|
|
49
49
|
PTY.spawn(cmd){|pwl_out, pwl_in, pid|
|
50
50
|
assert_response('Enter new master password:', pwl_out)
|
@@ -58,14 +58,14 @@ class TestInit < Test::Pwl::AppTestCase
|
|
58
58
|
end
|
59
59
|
|
60
60
|
#
|
61
|
-
# Tests that initing an existing
|
61
|
+
# Tests that initing an existing locker without --force does not touch the existing locker
|
62
62
|
#
|
63
63
|
def test_exists
|
64
64
|
assert_error('already exists', "init")
|
65
65
|
end
|
66
66
|
|
67
67
|
#
|
68
|
-
# Tests that cancelling a forced re-init does not change the
|
68
|
+
# Tests that cancelling a forced re-init does not change the locker file
|
69
69
|
#
|
70
70
|
def test_cancel
|
71
71
|
# TODO
|
@@ -3,7 +3,7 @@ require 'helper'
|
|
3
3
|
# Tests `pwl list`
|
4
4
|
class TestList < Test::Pwl::AppTestCase
|
5
5
|
def test_list_empty
|
6
|
-
assert_empty(
|
6
|
+
assert_empty(locker.list)
|
7
7
|
assert_error('^$', 'list')
|
8
8
|
assert_error('^List is empty\.$', 'list --verbose')
|
9
9
|
end
|
@@ -11,7 +11,7 @@ class TestList < Test::Pwl::AppTestCase
|
|
11
11
|
def test_list_all
|
12
12
|
test_vector = Hash['foo', 'one', 'bar', 'two', 'Chuck Norris', 'Roundhouse Kick']
|
13
13
|
test_vector.each{|k,v|
|
14
|
-
assert_successful('', "
|
14
|
+
assert_successful('', "add '#{k}' '#{v}'")
|
15
15
|
}
|
16
16
|
|
17
17
|
assert_successful(test_vector.keys.join('-'), 'list -s "-"')
|
@@ -20,7 +20,7 @@ class TestList < Test::Pwl::AppTestCase
|
|
20
20
|
def test_list_filter
|
21
21
|
test_vector = Hash['foo', 'one', 'foot', 'two', 'Homer Simpson', 'Apu Nahasapeemapetilon']
|
22
22
|
test_vector.each{|k,v|
|
23
|
-
assert_successful('', "
|
23
|
+
assert_successful('', "add '#{k}' '#{v}'")
|
24
24
|
}
|
25
25
|
|
26
26
|
filter = 'foo'
|