jdzak-cf_case_check 0.1.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 +3 -0
- data/History.txt +19 -0
- data/Manifest.txt +26 -0
- data/README.txt +75 -0
- data/Rakefile +40 -0
- data/bin/cf_case_check +27 -0
- data/lib/case_check/coldfusion_source.rb +92 -0
- data/lib/case_check/commands.rb +127 -0
- data/lib/case_check/configuration.rb +51 -0
- data/lib/case_check/core-ext.rb +51 -0
- data/lib/case_check/reference.rb +78 -0
- data/lib/case_check/references/cfc.rb +51 -0
- data/lib/case_check/references/cfinclude.rb +20 -0
- data/lib/case_check/references/cfmodule.rb +48 -0
- data/lib/case_check/references/custom_tag.rb +50 -0
- data/lib/case_check.rb +60 -0
- data/spec/coldfusion_source_spec.rb +161 -0
- data/spec/commands_spec.rb +130 -0
- data/spec/configuration_spec.rb +61 -0
- data/spec/core_ext_spec.rb +99 -0
- data/spec/reference_spec.rb +67 -0
- data/spec/references/cfc_spec.rb +77 -0
- data/spec/references/cfinclude_spec.rb +74 -0
- data/spec/references/cfmodule_spec.rb +156 -0
- data/spec/references/custom_tag_spec.rb +143 -0
- data/spec/spec_helper.rb +38 -0
- metadata +98 -0
@@ -0,0 +1,48 @@
|
|
1
|
+
module CaseCheck
|
2
|
+
|
3
|
+
# Reference as <cfmodule name= or <cfmodule template=
|
4
|
+
class Cfmodule < Reference
|
5
|
+
attr_reader :expected_path, :resolved_to
|
6
|
+
|
7
|
+
class << self
|
8
|
+
def search(source)
|
9
|
+
source.scan_for_tag('cfmodule') do |text, attributes, line_number|
|
10
|
+
if attributes.keys.include?(:name)
|
11
|
+
Name.new(source, attributes[:name], line_number)
|
12
|
+
elsif attributes.keys.include?(:template)
|
13
|
+
Template.new(source, attributes[:template], line_number)
|
14
|
+
else
|
15
|
+
$stderr.puts "Neither name nor template for cfmodule on line #{line_number} of #{source.filename}"
|
16
|
+
end
|
17
|
+
end.compact
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
class Name < Cfmodule
|
22
|
+
def initialize(source, text, line)
|
23
|
+
super
|
24
|
+
@expected_path = substituted_text.gsub('.', '/') + ".cfm"
|
25
|
+
@resolved_to = CustomTag.directories.inject(nil) do |resolved, dir|
|
26
|
+
resolved || resolve_in(dir)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def type_name
|
31
|
+
"cfmodule with name"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
class Template < Cfmodule
|
36
|
+
def initialize(source, text, line)
|
37
|
+
super
|
38
|
+
@expected_path = substituted_text
|
39
|
+
@resolved_to = resolve_in(File.dirname(source.filename))
|
40
|
+
end
|
41
|
+
|
42
|
+
def type_name
|
43
|
+
"cfmodule with template"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module CaseCheck
|
2
|
+
|
3
|
+
# Reference as cf_name (or CF_name)
|
4
|
+
class CustomTag < Reference
|
5
|
+
attr_reader :expected_path, :resolved_to
|
6
|
+
|
7
|
+
class << self
|
8
|
+
attr_writer :directories
|
9
|
+
|
10
|
+
def directories
|
11
|
+
@directories ||= []
|
12
|
+
end
|
13
|
+
|
14
|
+
def search(source)
|
15
|
+
source.scan(/<(CF_(\w+))/i) do |match_data, line_number|
|
16
|
+
self.new(source, match_data[1], line_number)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def recursive_directories
|
21
|
+
directories + directories.collect do |dir|
|
22
|
+
collect_subdirs(dir)
|
23
|
+
end.flatten
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def collect_subdirs(start)
|
29
|
+
[start] + Dir[File.join(start, '*')].select { |f| File.directory?(f) }.collect do |dir|
|
30
|
+
collect_subdirs(dir)
|
31
|
+
end.flatten
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def initialize(source, text, line)
|
36
|
+
super
|
37
|
+
@expected_path = text[3, text.size] + ".cfm"
|
38
|
+
@resolved_to = resolve
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def resolve
|
44
|
+
[File.dirname(source.filename), self.class.recursive_directories].flatten.inject(nil) do |resolved, dir|
|
45
|
+
resolved || resolve_in(dir)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
data/lib/case_check.rb
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
|
2
|
+
module CaseCheck
|
3
|
+
# :stopdoc:
|
4
|
+
VERSION = '0.1.0'.freeze
|
5
|
+
LIBPATH = ::File.expand_path(::File.dirname(__FILE__)) + ::File::SEPARATOR
|
6
|
+
PATH = ::File.dirname(LIBPATH) + ::File::SEPARATOR
|
7
|
+
# :startdoc:
|
8
|
+
|
9
|
+
# Returns the version string for the library.
|
10
|
+
#
|
11
|
+
def self.version
|
12
|
+
VERSION
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.status_stream
|
16
|
+
@stderr ||= $stderr
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.status_stream=(err)
|
20
|
+
@stderr = err
|
21
|
+
end
|
22
|
+
|
23
|
+
# Returns the library path for the module. If any arguments are given,
|
24
|
+
# they will be joined to the end of the libray path using
|
25
|
+
# <tt>File.join</tt>.
|
26
|
+
#
|
27
|
+
def self.libpath( *args )
|
28
|
+
args.empty? ? LIBPATH : ::File.join(LIBPATH, args.flatten)
|
29
|
+
end
|
30
|
+
|
31
|
+
# Returns the lpath for the module. If any arguments are given,
|
32
|
+
# they will be joined to the end of the path using
|
33
|
+
# <tt>File.join</tt>.
|
34
|
+
#
|
35
|
+
def self.path( *args )
|
36
|
+
args.empty? ? PATH : ::File.join(PATH, args.flatten)
|
37
|
+
end
|
38
|
+
|
39
|
+
# Utility method used to rquire all files ending in .rb that lie in the
|
40
|
+
# directory below this file that has the same name as the filename passed
|
41
|
+
# in. Optionally, a specific _directory_ name can be passed in such that
|
42
|
+
# the _filename_ does not have to be equivalent to the directory.
|
43
|
+
#
|
44
|
+
def self.require_all_libs_relative_to( fname, dir = nil )
|
45
|
+
dir ||= ::File.basename(fname, '.*')
|
46
|
+
search_me = ::File.expand_path(
|
47
|
+
::File.join(::File.dirname(fname), dir, '*.rb'))
|
48
|
+
|
49
|
+
Dir.glob(search_me).sort.each {|rb| require rb}
|
50
|
+
end
|
51
|
+
|
52
|
+
def self.exit
|
53
|
+
Kernel::exit
|
54
|
+
end
|
55
|
+
|
56
|
+
end # module CaseCheck
|
57
|
+
|
58
|
+
CaseCheck.require_all_libs_relative_to(__FILE__)
|
59
|
+
|
60
|
+
# EOF
|
@@ -0,0 +1,161 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), %w[spec_helper])
|
2
|
+
|
3
|
+
module CaseCheck
|
4
|
+
|
5
|
+
describe ColdfusionSource do
|
6
|
+
describe "line_of" do
|
7
|
+
def actual_line_of(content, i)
|
8
|
+
ColdfusionSource.new("dc", content).line_of(i)
|
9
|
+
end
|
10
|
+
|
11
|
+
it "is always line 1 for a single line file" do
|
12
|
+
actual_line_of("some text", 3).should == 1
|
13
|
+
end
|
14
|
+
|
15
|
+
it "can find something on the last line" do
|
16
|
+
actual_line_of("some\ntext\nhere", 13).should == 3
|
17
|
+
end
|
18
|
+
|
19
|
+
it "is 1 for character 0" do
|
20
|
+
actual_line_of("some text", 0).should == 1
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
describe "scan" do
|
25
|
+
def perform_scan(content, re)
|
26
|
+
ColdfusionSource.new("dc", content).scan(re) do |md, l|
|
27
|
+
[md[0], l]
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
it "finds one instance" do
|
32
|
+
actual = perform_scan("123 abc", /[a-z]+/)
|
33
|
+
actual.should have(1).match
|
34
|
+
actual.first.should == ['abc', 1]
|
35
|
+
end
|
36
|
+
|
37
|
+
it "finds multiple instances" do
|
38
|
+
actual = perform_scan("abc def 123 four", /[a-z]+/)
|
39
|
+
actual.should have(3).matches
|
40
|
+
actual[0].should == ['abc', 1]
|
41
|
+
actual[1].should == ['def', 1]
|
42
|
+
actual[2].should == ['four', 1]
|
43
|
+
end
|
44
|
+
|
45
|
+
it "finds instances on multiple lines" do
|
46
|
+
actual = perform_scan(<<-TEXT, /[a-z]+/)
|
47
|
+
for
|
48
|
+
23
|
49
|
+
answers
|
50
|
+
TEXT
|
51
|
+
actual.should have(2).matches
|
52
|
+
actual[0].should == ['for', 1]
|
53
|
+
actual[1].should == ['answers', 3]
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
describe "scan for tag" do
|
58
|
+
def perform_scan(content, tag)
|
59
|
+
ColdfusionSource.new("dc", content).scan_for_tag(tag) do |text, attributes, l|
|
60
|
+
{ :text => text, :attributes => attributes, :line_number => l }
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
it "finds a tag with no attributes" do
|
65
|
+
actual = perform_scan("text <cfabort>more text", "cfabort")
|
66
|
+
actual.should have(1).match
|
67
|
+
actual.first[:text].should == "<cfabort>"
|
68
|
+
actual.first[:attributes].should == { }
|
69
|
+
actual.first[:line_number].should == 1
|
70
|
+
end
|
71
|
+
|
72
|
+
it "finds an XML-style self-closing tag with no attributes" do
|
73
|
+
actual = perform_scan("text <cfabort/>more text", "cfabort")
|
74
|
+
actual.should have(1).match
|
75
|
+
actual.first[:text].should == "<cfabort/>"
|
76
|
+
actual.first[:attributes].should == { }
|
77
|
+
actual.first[:line_number].should == 1
|
78
|
+
end
|
79
|
+
|
80
|
+
it "finds a single-line tag with attributes" do
|
81
|
+
actual = perform_scan("and then <cflog text='in the middle'> something happens", 'cflog')
|
82
|
+
actual.should have(1).match
|
83
|
+
actual.first[:text].should == "<cflog text='in the middle'>"
|
84
|
+
actual.first[:attributes].should have(1).attribute
|
85
|
+
actual.first[:attributes][:text].should == 'in the middle'
|
86
|
+
actual.first[:line_number].should == 1
|
87
|
+
end
|
88
|
+
|
89
|
+
it "finds a single-line self-closing tag with attributes" do
|
90
|
+
actual = perform_scan("and then <cflog text='in the middle'/> something happens", 'cflog')
|
91
|
+
actual.should have(1).match
|
92
|
+
actual.first[:text].should == "<cflog text='in the middle'/>"
|
93
|
+
actual.first[:attributes].should have(1).attribute
|
94
|
+
actual.first[:attributes][:text].should == 'in the middle'
|
95
|
+
actual.first[:line_number].should == 1
|
96
|
+
end
|
97
|
+
|
98
|
+
it "finds attributes which are surrounded by single quotes" do
|
99
|
+
actual = perform_scan("and then <cflog text='in the middle'/> something happens", 'cflog')
|
100
|
+
actual.should have(1).match
|
101
|
+
actual.first[:attributes].should have(1).attribute
|
102
|
+
actual.first[:attributes][:text].should == 'in the middle'
|
103
|
+
end
|
104
|
+
|
105
|
+
it "finds attributes which are surrounded by double quotes" do
|
106
|
+
actual = perform_scan(%q(and then <cflog text="in the middle"/> something happens), 'cflog')
|
107
|
+
actual.should have(1).match
|
108
|
+
actual.first[:attributes].should have(1).attribute
|
109
|
+
actual.first[:attributes][:text].should == 'in the middle'
|
110
|
+
end
|
111
|
+
|
112
|
+
it "finds multiple tags" do
|
113
|
+
actual = perform_scan(<<-CFM, "cfparam")
|
114
|
+
<cfparam name="foo" default="42">
|
115
|
+
<cfparam name="bar" default="11">
|
116
|
+
CFM
|
117
|
+
actual.should have(2).matches
|
118
|
+
actual[0][:attributes].should == { :name => 'foo', :default => '42' }
|
119
|
+
actual[1][:attributes].should == { :name => 'bar', :default => '11' }
|
120
|
+
actual[1][:line_number].should == 2
|
121
|
+
end
|
122
|
+
|
123
|
+
it "finds tags that are spread over multiple lines" do
|
124
|
+
actual = perform_scan(<<-CFM, "cfmodule")
|
125
|
+
<html>
|
126
|
+
<title>
|
127
|
+
<cfmodule
|
128
|
+
name="whatever"
|
129
|
+
>
|
130
|
+
</title></html>
|
131
|
+
CFM
|
132
|
+
actual.should have(1).match
|
133
|
+
actual.first[:attributes].should == { :name => 'whatever' }
|
134
|
+
end
|
135
|
+
|
136
|
+
it "is flexible about whitespace around '='" do
|
137
|
+
actual = perform_scan(<<-CFM, "cfparam")
|
138
|
+
<cfparam name ="foo" default= "42">
|
139
|
+
<cfparam name="bar" default = "11">
|
140
|
+
CFM
|
141
|
+
actual.should have(2).matches
|
142
|
+
actual[0][:attributes].should == { :name => 'foo', :default => '42' }
|
143
|
+
actual[1][:attributes].should == { :name => 'bar', :default => '11' }
|
144
|
+
actual[1][:line_number].should == 2
|
145
|
+
end
|
146
|
+
|
147
|
+
it "downcases attribute keys" do
|
148
|
+
actual = perform_scan(%q(<cfabort NOW='later'>), 'cfabort')
|
149
|
+
actual.first[:attributes].keys.should include(:now)
|
150
|
+
end
|
151
|
+
|
152
|
+
it "matches tags without regard to case" do
|
153
|
+
actual = perform_scan(%q(Time to go <CFABORT/>), 'cfAbort')
|
154
|
+
actual.should have(1).matches
|
155
|
+
actual.first[:text].should == '<CFABORT/>'
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
end # module
|
161
|
+
|
@@ -0,0 +1,130 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), %w[spec_helper])
|
2
|
+
|
3
|
+
describe CaseCheck::Params do
|
4
|
+
def config_file(filename, contents)
|
5
|
+
FileUtils.mkdir_p File.dirname(filename)
|
6
|
+
File.open(filename, 'w') { |f| f.write contents }
|
7
|
+
end
|
8
|
+
|
9
|
+
def actual_params(*argv)
|
10
|
+
CaseCheck::Params.new(argv.flatten)
|
11
|
+
end
|
12
|
+
|
13
|
+
describe "--dir directory" do
|
14
|
+
before do
|
15
|
+
@dirname = "/tmp/cftest"
|
16
|
+
FileUtils.mkdir_p @dirname
|
17
|
+
end
|
18
|
+
|
19
|
+
after do
|
20
|
+
FileUtils.rm_rf @dirname
|
21
|
+
end
|
22
|
+
|
23
|
+
it "makes the directory available" do
|
24
|
+
actual = actual_params('--dir', @dirname)
|
25
|
+
actual.source_directory.should == @dirname
|
26
|
+
end
|
27
|
+
|
28
|
+
it "defaults the directory to the current" do
|
29
|
+
actual_params.source_directory.should == '.'
|
30
|
+
end
|
31
|
+
|
32
|
+
it "reads the configuration directory/cf_case_check.yml" do
|
33
|
+
config_file File.join(@dirname, "cf_case_check.yml"), <<-YAML
|
34
|
+
cfc_directories:
|
35
|
+
- /tmp/baz
|
36
|
+
YAML
|
37
|
+
actual_params('--dir', @dirname)
|
38
|
+
CaseCheck::Cfc.directories.should == %w(/tmp/baz)
|
39
|
+
end
|
40
|
+
|
41
|
+
it "prefers an explicitly named configuration file if both are available" do
|
42
|
+
config_file File.join(@dirname, "cf_case_check.yml"), <<-YAML
|
43
|
+
cfc_directories:
|
44
|
+
- /tmp/quux
|
45
|
+
YAML
|
46
|
+
config_file File.join(@dirname, "another.yml"), <<-YAML
|
47
|
+
cfc_directories:
|
48
|
+
- /tmp/qurt
|
49
|
+
YAML
|
50
|
+
actual_params('--dir', @dirname, '--config', File.join(@dirname, 'another.yml'))
|
51
|
+
CaseCheck::Cfc.directories.should == %w(/tmp/qurt)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
describe "--config filename" do
|
56
|
+
before do
|
57
|
+
@filename = "/tmp/foo.yml"
|
58
|
+
config_file @filename, <<-YAML
|
59
|
+
cfc_directories:
|
60
|
+
- /tmp/bar
|
61
|
+
YAML
|
62
|
+
CaseCheck::Cfc.directories = nil
|
63
|
+
end
|
64
|
+
|
65
|
+
after do
|
66
|
+
FileUtils.rm_rf @filename
|
67
|
+
end
|
68
|
+
|
69
|
+
it "loads the configuration" do
|
70
|
+
actual_params('--config', @filename)
|
71
|
+
CaseCheck::Cfc.directories.should == %w(/tmp/bar)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
describe "--auto-configure directory" do
|
76
|
+
class Coldfusion8ConfigStub
|
77
|
+
def initialize(root)
|
78
|
+
apply
|
79
|
+
end
|
80
|
+
|
81
|
+
def apply
|
82
|
+
CaseCheck::Cfc.directories = %w(/mock/cfc/directory)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
before do
|
87
|
+
@cf_root = '/coldfusion_root'
|
88
|
+
|
89
|
+
File.should_receive(:exist?).with(@cf_root).any_number_of_times.and_return(true)
|
90
|
+
|
91
|
+
@config = Coldfusion8ConfigStub.new(@cf_root)
|
92
|
+
end
|
93
|
+
|
94
|
+
it "load the coldfusion 8 configuration" do
|
95
|
+
CaseCheck::Coldfusion8Configuration.should_receive(:new).and_return(@config)
|
96
|
+
actual_params('--auto-configure', @cf_root)
|
97
|
+
CaseCheck::Cfc.directories.should == %w(/mock/cfc/directory)
|
98
|
+
end
|
99
|
+
|
100
|
+
end
|
101
|
+
|
102
|
+
describe "--version" do
|
103
|
+
it "prints to configured stderr" do
|
104
|
+
CaseCheck.should_receive(:exit)
|
105
|
+
actual_params('--version')
|
106
|
+
CaseCheck.status_stream.string.should == "cf_case_check #{CaseCheck.version}\n"
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
describe "--help" do
|
111
|
+
it "prints to configured stderr" do
|
112
|
+
CaseCheck.should_receive(:exit)
|
113
|
+
actual_params('--help')
|
114
|
+
CaseCheck.status_stream.string.should include("cf_case_check")
|
115
|
+
CaseCheck.status_stream.string.should include("config")
|
116
|
+
CaseCheck.status_stream.string.should include("dir")
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
describe "--verbose" do
|
121
|
+
it "sets the verbose flag" do
|
122
|
+
actual_params('--verbose').should be_verbose
|
123
|
+
actual_params('-v').should be_verbose
|
124
|
+
end
|
125
|
+
|
126
|
+
it "does not set the verbose flag when omitted" do
|
127
|
+
actual_params.should_not be_verbose
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
require File.join(File.dirname(__FILE__), %w[spec_helper])
|
3
|
+
|
4
|
+
describe CaseCheck::Configuration do
|
5
|
+
before do
|
6
|
+
@filename = "/tmp/cf_case_check/config.yml"
|
7
|
+
end
|
8
|
+
|
9
|
+
after do
|
10
|
+
if File.exist?(@filename)
|
11
|
+
FileUtils.rm_rf @filename
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def config_file(contents)
|
16
|
+
FileUtils.mkdir_p File.dirname(@filename)
|
17
|
+
File.open(@filename, 'w') { |f| f.write contents }
|
18
|
+
end
|
19
|
+
|
20
|
+
def read_config
|
21
|
+
CaseCheck::Configuration.new(@filename)
|
22
|
+
end
|
23
|
+
|
24
|
+
it "reads custom tag directories" do
|
25
|
+
config_file <<-YAML
|
26
|
+
custom_tag_directories:
|
27
|
+
- /var/www/customtags
|
28
|
+
- /home/cf/customtags
|
29
|
+
YAML
|
30
|
+
read_config
|
31
|
+
CaseCheck::CustomTag.directories.should == %w(/var/www/customtags /home/cf/customtags)
|
32
|
+
end
|
33
|
+
|
34
|
+
it "resolves relative custom tag directories against the config file directory" do
|
35
|
+
config_file <<-YAML
|
36
|
+
custom_tag_directories:
|
37
|
+
- zappo/customtags
|
38
|
+
YAML
|
39
|
+
read_config
|
40
|
+
CaseCheck::CustomTag.directories.should == %w(/tmp/cf_case_check/zappo/customtags)
|
41
|
+
end
|
42
|
+
|
43
|
+
it "reads substitutions" do
|
44
|
+
config_file <<-YAML
|
45
|
+
substitutions:
|
46
|
+
'#application.cfcPath#': /var/www/cfcs
|
47
|
+
YAML
|
48
|
+
read_config
|
49
|
+
CaseCheck::Reference.should have(1).substitutions
|
50
|
+
end
|
51
|
+
|
52
|
+
it "interprets substitution patterns as case insensitive REs" do
|
53
|
+
config_file <<-YAML
|
54
|
+
substitutions:
|
55
|
+
'#application.cfcPath#': /var/www/cfcs
|
56
|
+
YAML
|
57
|
+
read_config
|
58
|
+
CaseCheck::Reference.substitutions.first.should == [/#application.cfcPath#/i, '/var/www/cfcs']
|
59
|
+
CaseCheck::Reference.substitutions.first.first.should be_casefold
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,99 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
|
3
|
+
require File.join(File.dirname(__FILE__), %w[spec_helper])
|
4
|
+
|
5
|
+
describe File, ' extensions ' do
|
6
|
+
before do
|
7
|
+
@tmpdir = "/tmp/case_check_spec"
|
8
|
+
FileUtils.mkdir_p(File.dirname(@tmpdir))
|
9
|
+
end
|
10
|
+
|
11
|
+
after do
|
12
|
+
FileUtils.rm_rf(@tmpdir)
|
13
|
+
end
|
14
|
+
|
15
|
+
def touch(filename)
|
16
|
+
full = testfile(filename)
|
17
|
+
FileUtils.mkdir_p(File.dirname(full))
|
18
|
+
File.open(full, 'w') { }
|
19
|
+
full
|
20
|
+
end
|
21
|
+
|
22
|
+
def testfile(filename)
|
23
|
+
File.join(@tmpdir, filename)
|
24
|
+
end
|
25
|
+
|
26
|
+
describe "#exists_exactly?" do
|
27
|
+
it "does not include insensitive file matches" do
|
28
|
+
touch("some_file")
|
29
|
+
File.exists_exactly?(testfile("some_File")).should be_false
|
30
|
+
end
|
31
|
+
|
32
|
+
it "does not include insensitive directory matches" do
|
33
|
+
touch("Bar/quUx")
|
34
|
+
File.exists_exactly?(testfile("bAr/quUx")).should be_false
|
35
|
+
end
|
36
|
+
|
37
|
+
it "does not have a problem with files that don't exist at all" do
|
38
|
+
File.exists_exactly?(testfile("nope")).should be_false
|
39
|
+
end
|
40
|
+
|
41
|
+
it "does match exact file paths" do
|
42
|
+
touch("qUuX/foo")
|
43
|
+
File.exists_exactly?(testfile("qUuX/foo")).should be_true
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
describe "#case_insensitive_canonical_name" do
|
48
|
+
it "finds exact matches" do
|
49
|
+
touch("baz/bar.foo")
|
50
|
+
File.case_insensitive_canonical_name(testfile("baz/bar.foo")).should == testfile("baz/bar.foo")
|
51
|
+
end
|
52
|
+
|
53
|
+
it "finds matches with case-insensitive matching directories" do
|
54
|
+
touch("baZ/baR/foo")
|
55
|
+
File.case_insensitive_canonical_name(testfile("baz/bar/foo")).should == testfile("baZ/baR/foo")
|
56
|
+
end
|
57
|
+
|
58
|
+
it "finds matches with case-insensitive matching filenames" do
|
59
|
+
touch("baz/bar/fOz")
|
60
|
+
File.case_insensitive_canonical_name(testfile("baz/bar/FOZ")).should == testfile("baz/bar/fOz")
|
61
|
+
end
|
62
|
+
|
63
|
+
it "finds no match for non-existent files" do
|
64
|
+
File.case_insensitive_canonical_name(testfile("quux")).should be_nil
|
65
|
+
end
|
66
|
+
|
67
|
+
it "handles path navigation" do
|
68
|
+
touch("baz/bar/foo/quux")
|
69
|
+
File.case_insensitive_canonical_name(testfile("baz/bar/quod/../fOO/quux")).should == testfile("baz/bar/foo/quux")
|
70
|
+
end
|
71
|
+
|
72
|
+
describe "with symlinks" do
|
73
|
+
before do
|
74
|
+
@actual_dir = File.join(@tmpdir, "A")
|
75
|
+
FileUtils.mkdir_p @actual_dir
|
76
|
+
@linked_dir = File.join(@tmpdir, "B")
|
77
|
+
FileUtils.ln_s(@actual_dir, @linked_dir)
|
78
|
+
end
|
79
|
+
|
80
|
+
it "finds exact matches" do
|
81
|
+
expected = File.join(@linked_dir, "foo.cfm")
|
82
|
+
FileUtils.touch expected
|
83
|
+
File.case_insensitive_canonical_name(expected).should == expected
|
84
|
+
end
|
85
|
+
|
86
|
+
it "finds case-insensitive matches where the filename case differs" do
|
87
|
+
expected = File.join(@linked_dir, "Foo.cfm")
|
88
|
+
FileUtils.touch expected
|
89
|
+
File.case_insensitive_canonical_name(File.join(@linked_dir, "foo.cfm")).should == expected
|
90
|
+
end
|
91
|
+
|
92
|
+
it "finds case-insensitive matches where the symlink case differs" do
|
93
|
+
expected = File.join(@linked_dir, "foo.cfm")
|
94
|
+
FileUtils.touch expected
|
95
|
+
File.case_insensitive_canonical_name(File.join(@tmpdir, 'b', "foo.cfm")).should == expected
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
|
3
|
+
require File.join(File.dirname(__FILE__), %w[spec_helper])
|
4
|
+
|
5
|
+
describe CaseCheck::Reference do
|
6
|
+
class SampleReference < CaseCheck::Reference
|
7
|
+
attr_accessor :expected_path, :resolved_to
|
8
|
+
|
9
|
+
def initialize(expected_path, resolved_to, line=0, text=nil)
|
10
|
+
self.expected_path = expected_path
|
11
|
+
self.resolved_to = resolved_to
|
12
|
+
self.line = line
|
13
|
+
self.text = text
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
describe 'default resolution' do
|
18
|
+
it 'is exact when resolved_to ends with expected_path' do
|
19
|
+
SampleReference.new("/foo/patient.cfm", "/home/cfcode/apps/notis/foo/patient.cfm").resolution.should == :exact
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'is exact when resolved_to ends with expected_path, disregarding ../.' do
|
23
|
+
SampleReference.new(".././foo/patient.cfm", "/home/cfcode/apps/notis/foo/patient.cfm").resolution.should == :exact
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'is case sensitive when resolved_to ends with something else' do
|
27
|
+
SampleReference.new("/foo/Patient.cfm", "/home/cfcode/apps/notis/foo/patient.cfm").resolution.should == :case_insensitive
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'is unresolved without resolved_to' do
|
31
|
+
SampleReference.new("/foo/patient.cfm", nil).resolution.should be_nil
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
describe "text substitution" do
|
36
|
+
it "has none by default" do
|
37
|
+
CaseCheck::Reference.substitutions.should == []
|
38
|
+
end
|
39
|
+
|
40
|
+
it "subs in the first matching option" do
|
41
|
+
CaseCheck::Reference.substitutions << [/#application#/i, 'foo'] << [/#app.*?#/i, 'bar']
|
42
|
+
SampleReference.new(nil, nil, 0, "#application#/quux").substituted_text.should == "foo/quux"
|
43
|
+
end
|
44
|
+
|
45
|
+
it "returns the original text if there are no matching subs" do
|
46
|
+
SampleReference.new(nil, nil, 0, "#application#/quux").substituted_text.should == "#application#/quux"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
describe 'default message' do
|
51
|
+
it "indicates when it is unresolved" do
|
52
|
+
SampleReference.new("/foo/patient.cfm", nil, 11, "FOO_Patient").message.should ==
|
53
|
+
"Unresolved sample reference on line 11: FOO_Patient"
|
54
|
+
end
|
55
|
+
|
56
|
+
it "indicates when it is exactly resolved" do
|
57
|
+
SampleReference.new("/foo/patient.cfm", "/home/cfcode/apps/notis/foo/patient.cfm", 11, "foo_patient").message.should ==
|
58
|
+
"Exactly resolved sample reference on line 11 from foo_patient to /home/cfcode/apps/notis/foo/patient.cfm"
|
59
|
+
end
|
60
|
+
|
61
|
+
it "indicates when it is only case-insensitively resolved" do
|
62
|
+
SampleReference.new("/foo/Patient.cfm", "/home/cfcode/apps/notis/foo/patient.cfm", 11, "foo_Patient").message.should ==
|
63
|
+
"Case-insensitively resolved sample reference on line 11 from foo_Patient to /home/cfcode/apps/notis/foo/patient.cfm"
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|