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