codesake 0.0.1 → 0.15.1
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/.gitignore +2 -0
- data/History.md +40 -0
- data/README.md +25 -3
- data/Rakefile +22 -2
- data/bin/codesake +36 -0
- data/codesake.gemspec +3 -0
- data/features/codesake_complains_if_missing_target.feature +8 -0
- data/features/codesake_process_jsp_file.feature +88 -0
- data/features/codesake_process_text_file.feature +23 -0
- data/features/step_definition/codesake_steps.rb +164 -0
- data/features/support/env.rb +1 -0
- data/lib/codesake.rb +8 -3
- data/lib/codesake/cli.rb +90 -0
- data/lib/codesake/engine/core.rb +10 -0
- data/lib/codesake/engine/generic.rb +12 -0
- data/lib/codesake/engine/jsp.rb +165 -0
- data/lib/codesake/engine/text.rb +36 -0
- data/lib/codesake/kernel.rb +39 -0
- data/lib/codesake/utils/files.rb +25 -0
- data/lib/codesake/utils/secrets.rb +45 -0
- data/lib/codesake/version.rb +2 -1
- data/spec/cli_spec.rb +65 -0
- data/spec/engine_core_spec.rb +45 -0
- data/spec/file_utils_spec.rb +59 -0
- data/spec/jsp_engine_spec.rb +114 -0
- data/spec/kernel_spec.rb +63 -0
- data/spec/secrets_utils_spec.rb +79 -0
- data/spec/spec_helper.rb +3 -0
- data/spec/text_engine_spec.rb +72 -0
- metadata +92 -3
data/lib/codesake/version.rb
CHANGED
data/spec/cli_spec.rb
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "codesake command line interface" do
|
4
|
+
before(:all) do
|
5
|
+
@cli = Codesake::Cli.new
|
6
|
+
end
|
7
|
+
it "has a parse method" do
|
8
|
+
@cli.should respond_to(:parse)
|
9
|
+
end
|
10
|
+
|
11
|
+
it "returns an empty has if no command line is given" do
|
12
|
+
@cli.parse(nil).should == {:vulnerabilities=>:all}
|
13
|
+
@cli.parse("").should == {:vulnerabilities=>:all}
|
14
|
+
end
|
15
|
+
|
16
|
+
|
17
|
+
it "understands --version flag" do
|
18
|
+
@cli.parse("--version").should == {:version=>true, :vulnerabilities=>:all}
|
19
|
+
end
|
20
|
+
it "understands --output flag" do
|
21
|
+
@cli.parse("-o file").should == {:output=>:file, :vulnerabilities=>:all}
|
22
|
+
@cli.parse("-o json").should == {:output=>:json, :vulnerabilities=>:all}
|
23
|
+
@cli.parse("-o db").should == {:output=>:db, :vulnerabilities=>:all}
|
24
|
+
|
25
|
+
end
|
26
|
+
it "understands --verbose flag" do
|
27
|
+
@cli.parse("--verbose").should == {:verbose=>true, :vulnerabilities=>:all}
|
28
|
+
@cli.parse("-V").should == {:verbose=>true, :vulnerabilities=>:all}
|
29
|
+
end
|
30
|
+
|
31
|
+
it "saves targets" do
|
32
|
+
@cli.parse("file1")
|
33
|
+
@cli.targets.should == [{:target=>"file1", :valid=>false}]
|
34
|
+
@cli.parse("file1 file2")
|
35
|
+
@cli.targets.should == [{:target=>"file1", :valid=>false}, {:target=>"file2", :valid=>false}]
|
36
|
+
@cli.parse("Gemfile")
|
37
|
+
@cli.targets.should == [{:target=>"Gemfile", :valid=>true}]
|
38
|
+
end
|
39
|
+
|
40
|
+
it "the target should be either a file or a directory" do
|
41
|
+
@cli.is_good_target?("Gemfile").should be_true
|
42
|
+
@cli.is_good_target?("file1").should be_false
|
43
|
+
end
|
44
|
+
it "must produce a non nil option Hash" do
|
45
|
+
@cli.parse("").should_not be_nil
|
46
|
+
@cli.parse("-nonsense").should_not be_nil
|
47
|
+
@cli.parse("-v -h").should_not be_nil
|
48
|
+
@cli.parse("-j drift").should_not be_nil
|
49
|
+
end
|
50
|
+
|
51
|
+
it "understand --keys flag" do
|
52
|
+
ret = {:keywords => ["a","b","c"], :vulnerabilities=>:all}
|
53
|
+
@cli.parse("-k a,b,c").should == ret
|
54
|
+
end
|
55
|
+
|
56
|
+
it "understand --all-vulnerabilities" do
|
57
|
+
ret = {:vulnerabilities=>:all}
|
58
|
+
@cli.parse("-A").should == ret
|
59
|
+
end
|
60
|
+
it "understand --confirmed-vulnerabilities" do
|
61
|
+
ret = {:vulnerabilities=>:confirmed}
|
62
|
+
@cli.parse("-C").should == ret
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
dummy_text = <<EOT
|
4
|
+
This is a text
|
5
|
+
This is a text
|
6
|
+
This is a text
|
7
|
+
This is a text
|
8
|
+
secret
|
9
|
+
This is a text
|
10
|
+
This is a text
|
11
|
+
This is a text
|
12
|
+
EOT
|
13
|
+
|
14
|
+
class Test
|
15
|
+
include Codesake::Utils::Files
|
16
|
+
include Codesake::Engine::Core
|
17
|
+
end
|
18
|
+
|
19
|
+
shared_examples_for Codesake::Engine::Core do
|
20
|
+
before(:all) do
|
21
|
+
@mock = Test.new
|
22
|
+
File.open("test_secrets.txt", "w") do |f|
|
23
|
+
f.puts(dummy_text)
|
24
|
+
end
|
25
|
+
|
26
|
+
@mock.filename="test_secrets.txt"
|
27
|
+
@mock.read_file
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
after(:all) do
|
32
|
+
File.delete("test_secrets.txt")
|
33
|
+
end
|
34
|
+
|
35
|
+
it "provide an analyse method" do
|
36
|
+
@mock.should respond_to(:analyse)
|
37
|
+
end
|
38
|
+
|
39
|
+
context "has an analyse method returning an empty array if the input is" do
|
40
|
+
it "null" do
|
41
|
+
@mock.analyse.class.should == Array
|
42
|
+
@mock.analyse.should be_empty
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
dummy_text = <<EOT
|
4
|
+
This is a text
|
5
|
+
This is a text
|
6
|
+
This is a text
|
7
|
+
This is a text
|
8
|
+
EOT
|
9
|
+
|
10
|
+
class Test
|
11
|
+
include Codesake::Utils::Files
|
12
|
+
end
|
13
|
+
|
14
|
+
shared_examples_for Codesake::Utils::Files do
|
15
|
+
before(:all) do
|
16
|
+
@mock = Test.new
|
17
|
+
File.open("test_utils.txt", "w") do |f|
|
18
|
+
f.puts(dummy_text)
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
after(:all) do
|
23
|
+
File.delete("test_utils.txt")
|
24
|
+
end
|
25
|
+
|
26
|
+
## Reading the file
|
27
|
+
|
28
|
+
it "has a read_file method" do
|
29
|
+
@mock.should respond_to(:read_file)
|
30
|
+
end
|
31
|
+
|
32
|
+
it "complains if we request to read a non existing file" do
|
33
|
+
@mock.filename = "test"
|
34
|
+
@mock.read_file.should be_false
|
35
|
+
@mock.file_content.should be_empty
|
36
|
+
end
|
37
|
+
|
38
|
+
it "read an existing file" do
|
39
|
+
@mock.filename = "test_utils.txt"
|
40
|
+
@mock.read_file.should be_true
|
41
|
+
@mock.file_content.should_not be_empty
|
42
|
+
end
|
43
|
+
|
44
|
+
|
45
|
+
it "has a loc method" do
|
46
|
+
@mock.should respond_to(:loc)
|
47
|
+
end
|
48
|
+
it "has a lines method" do
|
49
|
+
@mock.should respond_to(:lines)
|
50
|
+
end
|
51
|
+
|
52
|
+
it "has a lines_of_comment method" do
|
53
|
+
@mock.should respond_to(:lines_of_comment)
|
54
|
+
end
|
55
|
+
|
56
|
+
|
57
|
+
|
58
|
+
end
|
59
|
+
|
@@ -0,0 +1,114 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
jsp_content =<<EOS
|
4
|
+
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
|
5
|
+
pageEncoding="ISO-8859-1"%>
|
6
|
+
<%@page import="com.codesake.test"%>
|
7
|
+
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
|
8
|
+
<html>
|
9
|
+
<head>
|
10
|
+
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
11
|
+
<link rel="stylesheet" type="text/CSS" href="<%=request.getContextPath()%>/css/style.css" />
|
12
|
+
<title>Hello World</title>
|
13
|
+
|
14
|
+
<script type="text/javascript">
|
15
|
+
function confirmSubmit(name) {
|
16
|
+
return alert("test here'"+ cacheName +"'");
|
17
|
+
}
|
18
|
+
|
19
|
+
</script>
|
20
|
+
|
21
|
+
</head>
|
22
|
+
<body>
|
23
|
+
|
24
|
+
<div id="header">
|
25
|
+
<h1>Hello World</h1>
|
26
|
+
|
27
|
+
<a href="<%=request.getContextPath()%>/jsp/link1.jsp">Link 1</a>
|
28
|
+
<a href="<%=request.getContextPath()%>/jsp/link2.jsp">Link 2</a>
|
29
|
+
<a href="<%=request.getContextPath()%>/jsp/link3.jsp">Link 3</a>
|
30
|
+
<a href="<%=request.getContextPath()%>/jsp/link4.jsp">Link 4</a>
|
31
|
+
<a href="<%=request.getContextPath()%>/servlet">servlet</a>
|
32
|
+
</div>
|
33
|
+
|
34
|
+
<%
|
35
|
+
String message = (String) request.getAttribute("message");
|
36
|
+
if(message != null)
|
37
|
+
{
|
38
|
+
%>
|
39
|
+
<h4 id="message"><%=message%></h4>
|
40
|
+
<% }
|
41
|
+
else
|
42
|
+
{
|
43
|
+
%>
|
44
|
+
<h4 id="message"></h4>
|
45
|
+
<% } %>
|
46
|
+
<div id="content">
|
47
|
+
<form action="<%=request.getContextPath()%>/postHandler" method="post">
|
48
|
+
<label for="message">message:</label>
|
49
|
+
<input type="text" name="message" id="message" size="40" value="<%=request.getLocalName()%>" />
|
50
|
+
<input type="submit" value="submit" onclick="javascript: return confirmSubmit('Clienti');" />
|
51
|
+
</form>
|
52
|
+
</div>
|
53
|
+
<%
|
54
|
+
Cookie c = new Cookie("name", "a_value")
|
55
|
+
Cookie cc = new Cookie("second", 12)
|
56
|
+
%>
|
57
|
+
</body>
|
58
|
+
EOS
|
59
|
+
|
60
|
+
describe Codesake::Engine::Jsp do
|
61
|
+
before(:all) do
|
62
|
+
File.open("test.jsp", "w") do |f|
|
63
|
+
f.write(jsp_content)
|
64
|
+
end
|
65
|
+
@jsp = Codesake::Engine::Jsp.new("test.jsp", {})
|
66
|
+
@jsp.analyse
|
67
|
+
end
|
68
|
+
|
69
|
+
after(:all) do
|
70
|
+
File.delete("test.jsp") if File.exists?("test.jsp")
|
71
|
+
end
|
72
|
+
|
73
|
+
it_behaves_like Codesake::Utils::Files
|
74
|
+
# it_behaves_like Codesake::Utils::Secrets
|
75
|
+
it_behaves_like Codesake::Engine::Core
|
76
|
+
|
77
|
+
it "takes a filename as input" do
|
78
|
+
@jsp.filename.should_not be_nil
|
79
|
+
@jsp.filename.should_not be_empty
|
80
|
+
end
|
81
|
+
|
82
|
+
it "analyses a jsp for imported packages" do
|
83
|
+
expected_result = [{:package=>"com.codesake.test", :line=>3}]
|
84
|
+
@jsp.imports.should == expected_result
|
85
|
+
end
|
86
|
+
|
87
|
+
it "analyses a jsp file for attack entrypoints" do
|
88
|
+
expected_result = [{:line=>32, :param=>"message", :var=>"message"}]
|
89
|
+
@jsp.attack_entrypoints.should == expected_result
|
90
|
+
end
|
91
|
+
it "analyses a jsp file for reflected variables" do
|
92
|
+
expected_result = [{:line=>8, :var=>"request.getContextPath()", :false_positive=>true},
|
93
|
+
{:line=>24, :var=>"request.getContextPath()", :false_positive=>true},
|
94
|
+
{:line=>25, :var=>"request.getContextPath()", :false_positive=>true},
|
95
|
+
{:line=>26, :var=>"request.getContextPath()", :false_positive=>true},
|
96
|
+
{:line=>27, :var=>"request.getContextPath()", :false_positive=>true},
|
97
|
+
{:line=>28, :var=>"request.getContextPath()", :false_positive=>true},
|
98
|
+
{:line=>36, :var=>"message", :false_positive=>false},
|
99
|
+
{:line=>44, :var=>"request.getContextPath()", :false_positive=>true},
|
100
|
+
{:line=>46, :var=>"request.getLocalName()", :false_positive=>true}
|
101
|
+
]
|
102
|
+
@jsp.reflected_xss.should == expected_result
|
103
|
+
end
|
104
|
+
|
105
|
+
it "analyses a jsp file for cookies" do
|
106
|
+
expected_result = [{:line=>51, :name=>"name", :value=>"a_value", :var=>"c"}, {:line=>52, :name=>"second", :value=>"12", :var=>"cc"}]
|
107
|
+
@jsp.cookies.should == expected_result
|
108
|
+
end
|
109
|
+
|
110
|
+
|
111
|
+
|
112
|
+
|
113
|
+
|
114
|
+
end
|
data/spec/kernel_spec.rb
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Codesake::Kernel do
|
4
|
+
before(:all) do
|
5
|
+
@kernel = Codesake::Kernel.instance
|
6
|
+
end
|
7
|
+
|
8
|
+
it "has a choose_engine method" do
|
9
|
+
@kernel.should respond_to(:choose_engine)
|
10
|
+
end
|
11
|
+
|
12
|
+
it "has a detect method" do
|
13
|
+
@kernel.should respond_to(:detect)
|
14
|
+
end
|
15
|
+
|
16
|
+
it "detects a text file from its extension" do
|
17
|
+
@kernel.detect("Gemfile").should == Codesake::Kernel::TEXT
|
18
|
+
@kernel.detect("foo.txt").should == Codesake::Kernel::TEXT
|
19
|
+
end
|
20
|
+
|
21
|
+
it "detects a jsp file from its extension" do
|
22
|
+
@kernel.detect("test.jsp").should == Codesake::Kernel::JSP
|
23
|
+
end
|
24
|
+
|
25
|
+
|
26
|
+
#
|
27
|
+
# TODO: I plan to add specialized engines for those languages before
|
28
|
+
# reaching 1.0 - 20121211
|
29
|
+
#
|
30
|
+
|
31
|
+
it "detects a java file from its extension"
|
32
|
+
it "detects a c file from its extension"
|
33
|
+
it "detects a shell script from its extension"
|
34
|
+
it "detects an html file from its extension"
|
35
|
+
it "detects an haml file from its extension"
|
36
|
+
it "detects a markdown file from its extension"
|
37
|
+
it "detects a ruby file from its extension"
|
38
|
+
it "detects a php file from its extension"
|
39
|
+
it "detects a js file from its extension"
|
40
|
+
it "detects a perl file from its extension"
|
41
|
+
|
42
|
+
# Engine choosing tests
|
43
|
+
|
44
|
+
it "chooses Codesake::Engine::Text for a text file" do
|
45
|
+
@kernel.choose_engine("a_text_file", {}).class.should == Codesake::Engine::Text
|
46
|
+
end
|
47
|
+
|
48
|
+
it "chooses Codesake::Engine::Jsp for a jsp file" do
|
49
|
+
@kernel.choose_engine("test.jsp", {}).class.should == Codesake::Engine::Jsp
|
50
|
+
end
|
51
|
+
|
52
|
+
it "chooses Codesake::Engine::Java for a java file"
|
53
|
+
it "chooses Codesake::Engine::Text for a c file"
|
54
|
+
it "chooses Codesake::Engine::Text for a shell script"
|
55
|
+
it "chooses Codesake::Engine::Text for a html file"
|
56
|
+
it "chooses Codesake::Engine::Text for a haml file"
|
57
|
+
it "chooses Codesake::Engine::Text for a markdown file"
|
58
|
+
it "chooses Codesake::Engine::Text for a ruby file"
|
59
|
+
it "chooses Codesake::Engine::Text for a php file"
|
60
|
+
it "chooses Codesake::Engine::Text for a js file"
|
61
|
+
it "chooses Codesake::Engine::Text for a perl file"
|
62
|
+
|
63
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
|
4
|
+
dummy_text = <<EOT
|
5
|
+
This is a text
|
6
|
+
This is a text
|
7
|
+
This is a text
|
8
|
+
This is a text
|
9
|
+
secret
|
10
|
+
This is a text
|
11
|
+
This is a text
|
12
|
+
This is a text
|
13
|
+
EOT
|
14
|
+
|
15
|
+
class Test
|
16
|
+
include Codesake::Utils::Files
|
17
|
+
include Codesake::Utils::Secrets
|
18
|
+
end
|
19
|
+
|
20
|
+
|
21
|
+
shared_examples_for Codesake::Utils::Secrets do
|
22
|
+
before(:all) do
|
23
|
+
@mock = Test.new
|
24
|
+
File.open("test_secrets.txt", "w") do |f|
|
25
|
+
f.puts(dummy_text)
|
26
|
+
end
|
27
|
+
|
28
|
+
@mock.filename="test_secrets.txt"
|
29
|
+
@mock.read_file
|
30
|
+
end
|
31
|
+
after(:all) do
|
32
|
+
File.delete("test_secrets.txt")
|
33
|
+
end
|
34
|
+
|
35
|
+
context "has a list of reserved words containing" do
|
36
|
+
it "password" do
|
37
|
+
@mock.reserved?("password").should be_true
|
38
|
+
end
|
39
|
+
it "username" do
|
40
|
+
@mock.reserved?("username").should be_true
|
41
|
+
end
|
42
|
+
it "login" do
|
43
|
+
@mock.reserved?("login").should be_true
|
44
|
+
end
|
45
|
+
it "fixme" do
|
46
|
+
@mock.reserved?("fixme").should be_true
|
47
|
+
end
|
48
|
+
it "xxx" do
|
49
|
+
@mock.reserved?("xxx").should be_true
|
50
|
+
end
|
51
|
+
it "fix" do
|
52
|
+
@mock.reserved?("fix").should be_true
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
it "let user add a reserver word" do
|
57
|
+
@mock.reserved?("foo").should be_false
|
58
|
+
@mock.add("foo")
|
59
|
+
@mock.reserved?("foo").should be_true
|
60
|
+
|
61
|
+
end
|
62
|
+
context "has a find method" do
|
63
|
+
it "that is public" do
|
64
|
+
@mock.should respond_to(:find_reserved_keywords)
|
65
|
+
end
|
66
|
+
it "returns an empty array if 'secret' is not a reserved word in the example source" do
|
67
|
+
@mock.secrets=["noodle", "compain", "foo"]
|
68
|
+
@mock.find_reserved_keywords.should be_empty
|
69
|
+
end
|
70
|
+
it "returns true if 'secret' is a reserved word in the example source" do
|
71
|
+
@mock.secrets=["secret"]
|
72
|
+
@mock.find_reserved_keywords.should == [{:line=>5, :matcher=>"secret"}]
|
73
|
+
end
|
74
|
+
|
75
|
+
|
76
|
+
end
|
77
|
+
|
78
|
+
|
79
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -0,0 +1,72 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
lorem_ipsum = <<EOS
|
4
|
+
Lorem ipsum dolor sit amet, secret consectetuer adipiscing elit, sed diam nonummy nibh
|
5
|
+
euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim
|
6
|
+
ad minim veniam, quis nostrud secret exerci tation ullamcorper suscipit lobortis nisl
|
7
|
+
ut aliquip ex ea commodo consequat. Duis splople autem vel eum iriure dolor in
|
8
|
+
hendrerit in vulputate velit esse secret molestie consequat, vel illum dolore eu
|
9
|
+
feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui
|
10
|
+
blandit praesent luptatum zzril password delenit augue duis dolore te feugait nulla
|
11
|
+
facilisi.
|
12
|
+
|
13
|
+
Pellentesque at dolor non lectus sagittis semper. Donec quis mi. Duis eget
|
14
|
+
pede. Phasellus arcu tellus, ultricies id, consequat id, lobortis nec, diam.
|
15
|
+
Suspendisse sed nunc. Pellentesque id magna. Morbi interdum quam at est.
|
16
|
+
Maecenas eleifend mi in urna. Praesent et lectus ac nibh luctus viverra. In vel
|
17
|
+
dolor sed nibh sollicitudin tincidunt. Ut consequat nisi sit amet nibh. Nunc mi
|
18
|
+
tortor, tristique sit amet, rhoncus porta, malesuada elementum, nisi. Integer
|
19
|
+
vitae enim quis risus aliquet gravida. Curabitur vel lorem vel erat dapibus
|
20
|
+
lobortis. Donec dignissim tellus at arcu. Quisque molestie pulvinar sem.
|
21
|
+
|
22
|
+
Nulla magna neque, ullamcorper tempus, luctus eget, malesuada ut, velit. Morbi
|
23
|
+
felis. Praesent in purus at ipsum cursus posuere. Morbi bibendum facilisis
|
24
|
+
eros. Phasellus aliquam sapien in erat. Praesent venenatis diam dignissim dui.
|
25
|
+
Praesent risus erat, iaculis ac, dapibus sed, imperdiet ac, erat. Nullam sed
|
26
|
+
ipsum. Phasellus non dolor. Donec ut elit.
|
27
|
+
EOS
|
28
|
+
|
29
|
+
describe Codesake::Engine::Text do
|
30
|
+
before(:all) do
|
31
|
+
File.open("lorem.txt", "w") do |f|
|
32
|
+
f.write(lorem_ipsum)
|
33
|
+
end
|
34
|
+
@text = Codesake::Engine::Text.new("lorem.txt")
|
35
|
+
end
|
36
|
+
after(:all) do
|
37
|
+
File.delete("lorem.txt") if File.exists?("lorem.txt")
|
38
|
+
end
|
39
|
+
|
40
|
+
it_behaves_like Codesake::Utils::Files
|
41
|
+
it_behaves_like Codesake::Utils::Secrets
|
42
|
+
it_behaves_like Codesake::Engine::Core
|
43
|
+
|
44
|
+
it "takes a filename as input" do
|
45
|
+
@text.filename.should_not be_nil
|
46
|
+
@text.filename.should_not be_empty
|
47
|
+
end
|
48
|
+
|
49
|
+
context "has a is_txt? method" do
|
50
|
+
it "and this method is public" do
|
51
|
+
Codesake::Engine::Text.should respond_to(:is_txt?)
|
52
|
+
end
|
53
|
+
it "returns false if file extension is not .txt" do
|
54
|
+
Codesake::Engine::Text.is_txt?("text.jsp").should be_false
|
55
|
+
end
|
56
|
+
it "returns true if file extension is .txt" do
|
57
|
+
Codesake::Engine::Text.is_txt?("text.txt").should be_true
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
it "analyse the file for reserved words" do
|
62
|
+
|
63
|
+
# secret @1, 3, 5
|
64
|
+
# password @7
|
65
|
+
expected_result = [{:line=>1, :matcher=>"secret"}, {:line=>3, :matcher=>"secret"}, {:line=>5, :matcher=>"secret"}, {:line=>7, :matcher=>"password"}]
|
66
|
+
@text.analyse.should_not be_nil
|
67
|
+
@text.reserved_keywords.size.should == 4
|
68
|
+
@text.reserved_keywords.should == expected_result
|
69
|
+
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|