puppet-lint-halyard 1.1.0.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.
- checksums.yaml +7 -0
- data/.gitignore +9 -0
- data/.travis.yml +10 -0
- data/Gemfile +3 -0
- data/LICENSE +20 -0
- data/README.md +210 -0
- data/Rakefile +14 -0
- data/bin/puppet-lint +7 -0
- data/lib/puppet-lint.rb +214 -0
- data/lib/puppet-lint/bin.rb +79 -0
- data/lib/puppet-lint/checkplugin.rb +176 -0
- data/lib/puppet-lint/checks.rb +91 -0
- data/lib/puppet-lint/configuration.rb +153 -0
- data/lib/puppet-lint/data.rb +521 -0
- data/lib/puppet-lint/lexer.rb +373 -0
- data/lib/puppet-lint/lexer/token.rb +101 -0
- data/lib/puppet-lint/monkeypatches.rb +2 -0
- data/lib/puppet-lint/monkeypatches/string_percent.rb +52 -0
- data/lib/puppet-lint/monkeypatches/string_prepend.rb +13 -0
- data/lib/puppet-lint/optparser.rb +118 -0
- data/lib/puppet-lint/plugins.rb +74 -0
- data/lib/puppet-lint/plugins/check_classes.rb +285 -0
- data/lib/puppet-lint/plugins/check_comments.rb +55 -0
- data/lib/puppet-lint/plugins/check_conditionals.rb +65 -0
- data/lib/puppet-lint/plugins/check_documentation.rb +31 -0
- data/lib/puppet-lint/plugins/check_nodes.rb +29 -0
- data/lib/puppet-lint/plugins/check_resources.rb +194 -0
- data/lib/puppet-lint/plugins/check_strings.rb +174 -0
- data/lib/puppet-lint/plugins/check_variables.rb +19 -0
- data/lib/puppet-lint/plugins/check_whitespace.rb +170 -0
- data/lib/puppet-lint/tasks/puppet-lint.rb +91 -0
- data/lib/puppet-lint/version.rb +3 -0
- data/puppet-lint.gemspec +24 -0
- data/spec/fixtures/test/manifests/fail.pp +2 -0
- data/spec/fixtures/test/manifests/ignore.pp +1 -0
- data/spec/fixtures/test/manifests/ignore_multiple_block.pp +6 -0
- data/spec/fixtures/test/manifests/ignore_multiple_line.pp +2 -0
- data/spec/fixtures/test/manifests/ignore_reason.pp +1 -0
- data/spec/fixtures/test/manifests/init.pp +3 -0
- data/spec/fixtures/test/manifests/malformed.pp +1 -0
- data/spec/fixtures/test/manifests/url_interpolation.pp +12 -0
- data/spec/fixtures/test/manifests/warning.pp +2 -0
- data/spec/puppet-lint/bin_spec.rb +326 -0
- data/spec/puppet-lint/configuration_spec.rb +56 -0
- data/spec/puppet-lint/ignore_overrides_spec.rb +109 -0
- data/spec/puppet-lint/lexer/token_spec.rb +18 -0
- data/spec/puppet-lint/lexer_spec.rb +783 -0
- data/spec/puppet-lint/plugins/check_classes/autoloader_layout_spec.rb +105 -0
- data/spec/puppet-lint/plugins/check_classes/class_inherits_from_params_class_spec.rb +35 -0
- data/spec/puppet-lint/plugins/check_classes/inherits_across_namespaces_spec.rb +33 -0
- data/spec/puppet-lint/plugins/check_classes/names_containing_dash_spec.rb +45 -0
- data/spec/puppet-lint/plugins/check_classes/nested_classes_or_defines_spec.rb +76 -0
- data/spec/puppet-lint/plugins/check_classes/parameter_order_spec.rb +73 -0
- data/spec/puppet-lint/plugins/check_classes/right_to_left_relationship_spec.rb +25 -0
- data/spec/puppet-lint/plugins/check_classes/variable_scope_spec.rb +196 -0
- data/spec/puppet-lint/plugins/check_comments/slash_comments_spec.rb +45 -0
- data/spec/puppet-lint/plugins/check_comments/star_comments_spec.rb +84 -0
- data/spec/puppet-lint/plugins/check_conditionals/case_without_default_spec.rb +98 -0
- data/spec/puppet-lint/plugins/check_conditionals/selector_inside_resource_spec.rb +36 -0
- data/spec/puppet-lint/plugins/check_documentation/documentation_spec.rb +52 -0
- data/spec/puppet-lint/plugins/check_nodes/unquoted_node_name_spec.rb +146 -0
- data/spec/puppet-lint/plugins/check_resources/duplicate_params_spec.rb +100 -0
- data/spec/puppet-lint/plugins/check_resources/ensure_first_param_spec.rb +55 -0
- data/spec/puppet-lint/plugins/check_resources/ensure_not_symlink_target_spec.rb +89 -0
- data/spec/puppet-lint/plugins/check_resources/file_mode_spec.rb +113 -0
- data/spec/puppet-lint/plugins/check_resources/unquoted_file_mode_spec.rb +45 -0
- data/spec/puppet-lint/plugins/check_resources/unquoted_resource_title_spec.rb +216 -0
- data/spec/puppet-lint/plugins/check_strings/double_quoted_strings_spec.rb +199 -0
- data/spec/puppet-lint/plugins/check_strings/only_variable_string_spec.rb +114 -0
- data/spec/puppet-lint/plugins/check_strings/puppet_url_without_modules_spec.rb +62 -0
- data/spec/puppet-lint/plugins/check_strings/quoted_booleans_spec.rb +129 -0
- data/spec/puppet-lint/plugins/check_strings/single_quote_string_with_variables_spec.rb +17 -0
- data/spec/puppet-lint/plugins/check_strings/variables_not_enclosed_spec.rb +73 -0
- data/spec/puppet-lint/plugins/check_variables/variable_contains_dash_spec.rb +37 -0
- data/spec/puppet-lint/plugins/check_whitespace/2sp_soft_tabs_spec.rb +21 -0
- data/spec/puppet-lint/plugins/check_whitespace/80chars_spec.rb +54 -0
- data/spec/puppet-lint/plugins/check_whitespace/arrow_alignment_spec.rb +524 -0
- data/spec/puppet-lint/plugins/check_whitespace/hard_tabs_spec.rb +45 -0
- data/spec/puppet-lint/plugins/check_whitespace/trailing_whitespace_spec.rb +101 -0
- data/spec/puppet-lint_spec.rb +20 -0
- data/spec/spec_helper.rb +129 -0
- metadata +229 -0
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe PuppetLint::Configuration do
|
4
|
+
subject { PuppetLint::Configuration.new }
|
5
|
+
|
6
|
+
it 'should create check methods on the fly' do
|
7
|
+
klass = Class.new
|
8
|
+
subject.add_check('foo', klass)
|
9
|
+
|
10
|
+
expect(subject).to respond_to(:foo_enabled?)
|
11
|
+
expect(subject).to_not respond_to(:bar_enabled?)
|
12
|
+
expect(subject).to respond_to(:enable_foo)
|
13
|
+
expect(subject).to respond_to(:disable_foo)
|
14
|
+
|
15
|
+
subject.disable_foo
|
16
|
+
expect(subject.settings['foo_disabled']).to be_truthy
|
17
|
+
expect(subject.foo_enabled?).to be_falsey
|
18
|
+
|
19
|
+
subject.enable_foo
|
20
|
+
expect(subject.settings['foo_disabled']).to be_falsey
|
21
|
+
expect(subject.foo_enabled?).to be_truthy
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'should know what checks have been added' do
|
25
|
+
klass = Class.new
|
26
|
+
subject.add_check('foo', klass)
|
27
|
+
expect(subject.checks).to include('foo')
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'should respond nil to unknown config options' do
|
31
|
+
expect(subject.foobarbaz).to be_nil
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'should create options on the fly' do
|
35
|
+
subject.add_option('bar')
|
36
|
+
|
37
|
+
expect(subject.bar).to be_nil
|
38
|
+
|
39
|
+
subject.bar = 'aoeui'
|
40
|
+
expect(subject.bar).to eq('aoeui')
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'should be able to set sane defaults' do
|
44
|
+
subject.defaults
|
45
|
+
|
46
|
+
expect(subject.settings).to eq({
|
47
|
+
'with_filename' => false,
|
48
|
+
'fail_on_warnings' => false,
|
49
|
+
'error_level' => :all,
|
50
|
+
'log_format' => '',
|
51
|
+
'with_context' => false,
|
52
|
+
'fix' => false,
|
53
|
+
'show_ignored' => false,
|
54
|
+
})
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,109 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'quoted_booleans', :type => :lint do
|
4
|
+
let(:msg) { 'quoted boolean value found' }
|
5
|
+
|
6
|
+
context 'with a single line ignore' do
|
7
|
+
let(:code) { "
|
8
|
+
'true'
|
9
|
+
'true' # lint:ignore:quoted_booleans
|
10
|
+
'false'
|
11
|
+
" }
|
12
|
+
|
13
|
+
it 'should detect three problems' do
|
14
|
+
expect(problems).to have(3).problems
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'should have two warnings' do
|
18
|
+
expect(problems).to contain_warning(msg).on_line(2).in_column(7)
|
19
|
+
expect(problems).to contain_warning(msg).on_line(4).in_column(7)
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'should have one ignored problem' do
|
23
|
+
expect(problems).to contain_ignored(msg).on_line(3).in_column(7)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
context 'with a single line ignore and a reason' do
|
28
|
+
let(:code) { "
|
29
|
+
'true'
|
30
|
+
'true' # lint:ignore:quoted_booleans some good reason
|
31
|
+
'false'
|
32
|
+
" }
|
33
|
+
|
34
|
+
it 'should detect three problems' do
|
35
|
+
expect(problems).to have(3).problems
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'should have two warnings' do
|
39
|
+
expect(problems).to contain_warning(msg).on_line(2).in_column(7)
|
40
|
+
expect(problems).to contain_warning(msg).on_line(4).in_column(7)
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'should have one ignored problem with a reason' do
|
44
|
+
expect(problems).to contain_ignored(msg).on_line(3).in_column(7).with_reason('some good reason')
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
context 'with a block ignore' do
|
49
|
+
let(:code) { "
|
50
|
+
'true'
|
51
|
+
# lint:ignore:quoted_booleans
|
52
|
+
'false'
|
53
|
+
'true'
|
54
|
+
# lint:endignore
|
55
|
+
'true'
|
56
|
+
" }
|
57
|
+
|
58
|
+
it 'should detect four problems' do
|
59
|
+
expect(problems).to have(4).problems
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'should have two warnings' do
|
63
|
+
expect(problems).to contain_warning(msg).on_line(2).in_column(7)
|
64
|
+
expect(problems).to contain_warning(msg).on_line(7).in_column(7)
|
65
|
+
end
|
66
|
+
|
67
|
+
it 'should have two ignored problems' do
|
68
|
+
expect(problems).to contain_ignored(msg).on_line(4).in_column(7)
|
69
|
+
expect(problems).to contain_ignored(msg).on_line(5).in_column(7)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
context 'with a block ignore and a reason' do
|
74
|
+
let(:code) { "
|
75
|
+
'true'
|
76
|
+
# lint:ignore:quoted_booleans another reason
|
77
|
+
'false'
|
78
|
+
'true'
|
79
|
+
# lint:endignore
|
80
|
+
'true'
|
81
|
+
" }
|
82
|
+
|
83
|
+
it 'should detect four problems' do
|
84
|
+
expect(problems).to have(4).problems
|
85
|
+
end
|
86
|
+
|
87
|
+
it 'should have two warnings' do
|
88
|
+
expect(problems).to contain_warning(msg).on_line(2).in_column(7)
|
89
|
+
expect(problems).to contain_warning(msg).on_line(7).in_column(7)
|
90
|
+
end
|
91
|
+
|
92
|
+
it 'should have two ignored problems with a reason' do
|
93
|
+
expect(problems).to contain_ignored(msg).on_line(4).in_column(7).with_reason('another reason')
|
94
|
+
expect(problems).to contain_ignored(msg).on_line(5).in_column(7).with_reason('another reason')
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
context 'disable multiple checks on a line with a reason' do
|
99
|
+
let(:code) { '"true" # lint:ignore:quoted_booleans lint:ignore:double_quoted_string a reason' }
|
100
|
+
|
101
|
+
it 'should detect 1 problems' do
|
102
|
+
expect(problems).to have(1).problems
|
103
|
+
end
|
104
|
+
|
105
|
+
it 'should have one ignored problems' do
|
106
|
+
expect(problems).to contain_ignored(msg).on_line(1).in_column(1).with_reason('a reason')
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe PuppetLint::Lexer::Token do
|
4
|
+
subject do
|
5
|
+
PuppetLint::Lexer::Token.new(:NAME, 'foo', 1, 2)
|
6
|
+
end
|
7
|
+
|
8
|
+
it { is_expected.to respond_to(:type) }
|
9
|
+
it { is_expected.to respond_to(:value) }
|
10
|
+
it { is_expected.to respond_to(:line) }
|
11
|
+
it { is_expected.to respond_to(:column) }
|
12
|
+
|
13
|
+
its(:type) { is_expected.to eq(:NAME) }
|
14
|
+
its(:value) { is_expected.to eq('foo') }
|
15
|
+
its(:line) { is_expected.to eq(1) }
|
16
|
+
its(:column) { is_expected.to eq(2) }
|
17
|
+
its(:inspect) { is_expected.to eq("<Token :NAME (foo) @1:2>") }
|
18
|
+
end
|
@@ -0,0 +1,783 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe PuppetLint::Lexer do
|
4
|
+
before do
|
5
|
+
@lexer = PuppetLint::Lexer.new
|
6
|
+
end
|
7
|
+
|
8
|
+
context 'invalid code' do
|
9
|
+
it 'should bork' do
|
10
|
+
expect { @lexer.tokenise('^') }.to raise_error(PuppetLint::LexerError)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
context '#new_token' do
|
15
|
+
it 'should calculate the line number for an empty string' do
|
16
|
+
token = @lexer.new_token(:TEST, 'test', 4)
|
17
|
+
expect(token.line).to eq(1)
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'should calculate the line number for a multi line string' do
|
21
|
+
@lexer.instance_variable_set('@line_no', 2)
|
22
|
+
token = @lexer.new_token(:TEST, 'test', 4)
|
23
|
+
expect(token.line).to eq(2)
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'should calculate the column number for an empty string' do
|
27
|
+
token = @lexer.new_token(:TEST, 'test', 4)
|
28
|
+
expect(token.column).to eq(1)
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'should calculate the column number for a single line string' do
|
32
|
+
@lexer.instance_variable_set('@column', 'this is a test'.size)
|
33
|
+
token = @lexer.new_token(:TEST, 'test', 4)
|
34
|
+
expect(token.column).to eq(14)
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'should calculate the column number for a multi line string' do
|
38
|
+
@lexer.instance_variable_set('@line_no', 4)
|
39
|
+
@lexer.instance_variable_set('@column', "gronk".size)
|
40
|
+
token = @lexer.new_token(:TEST, 'test', 4)
|
41
|
+
expect(token.column).to eq(5)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
context '#get_string_segment' do
|
46
|
+
it 'should get a segment with a single terminator' do
|
47
|
+
data = StringScanner.new('foo"bar')
|
48
|
+
value, terminator = @lexer.get_string_segment(data, '"')
|
49
|
+
expect(value).to eq('foo')
|
50
|
+
expect(terminator).to eq('"')
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'should get a segment with multiple terminators' do
|
54
|
+
data = StringScanner.new('foo"bar$baz')
|
55
|
+
value, terminator = @lexer.get_string_segment(data, "'$")
|
56
|
+
expect(value).to eq('foo"bar')
|
57
|
+
expect(terminator).to eq('$')
|
58
|
+
end
|
59
|
+
|
60
|
+
it 'should not get a segment with an escaped terminator' do
|
61
|
+
data = StringScanner.new('foo"bar')
|
62
|
+
value, terminator = @lexer.get_string_segment(data, '$')
|
63
|
+
expect(value).to be_nil
|
64
|
+
expect(terminator).to be_nil
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
context '#interpolate_string' do
|
69
|
+
it 'should handle a string with no variables' do
|
70
|
+
@lexer.interpolate_string('foo bar baz"',1, 1)
|
71
|
+
token = @lexer.tokens.first
|
72
|
+
|
73
|
+
expect(@lexer.tokens.length).to eq(1)
|
74
|
+
expect(token.type).to eq(:STRING)
|
75
|
+
expect(token.value).to eq('foo bar baz')
|
76
|
+
expect(token.line).to eq(1)
|
77
|
+
expect(token.column).to eq(1)
|
78
|
+
end
|
79
|
+
|
80
|
+
it 'should handle a string with a newline' do
|
81
|
+
@lexer.interpolate_string(%{foo\nbar"}, 1, 1)
|
82
|
+
token = @lexer.tokens.first
|
83
|
+
|
84
|
+
expect(@lexer.tokens.length).to eq(1)
|
85
|
+
expect(token.type).to eq(:STRING)
|
86
|
+
expect(token.value).to eq("foo\nbar")
|
87
|
+
expect(token.line).to eq(1)
|
88
|
+
expect(token.column).to eq(1)
|
89
|
+
end
|
90
|
+
|
91
|
+
it 'should handle a string with a single variable and suffix' do
|
92
|
+
@lexer.interpolate_string('${foo}bar"', 1, 1)
|
93
|
+
tokens = @lexer.tokens
|
94
|
+
|
95
|
+
expect(tokens.length).to eq(3)
|
96
|
+
|
97
|
+
expect(tokens[0].type).to eq(:DQPRE)
|
98
|
+
expect(tokens[0].value).to eq('')
|
99
|
+
expect(tokens[0].line).to eq(1)
|
100
|
+
expect(tokens[0].column).to eq(1)
|
101
|
+
|
102
|
+
expect(tokens[1].type).to eq(:VARIABLE)
|
103
|
+
expect(tokens[1].value).to eq('foo')
|
104
|
+
expect(tokens[1].line).to eq(1)
|
105
|
+
expect(tokens[1].column).to eq(3)
|
106
|
+
|
107
|
+
expect(tokens[2].type).to eq(:DQPOST)
|
108
|
+
expect(tokens[2].value).to eq('bar')
|
109
|
+
expect(tokens[2].line).to eq(1)
|
110
|
+
expect(tokens[2].column).to eq(8)
|
111
|
+
end
|
112
|
+
|
113
|
+
it 'should handle a string with a single variable and surrounding text' do
|
114
|
+
@lexer.interpolate_string('foo${bar}baz"', 1, 1)
|
115
|
+
tokens = @lexer.tokens
|
116
|
+
|
117
|
+
expect(tokens.length).to eq(3)
|
118
|
+
|
119
|
+
expect(tokens[0].type).to eq(:DQPRE)
|
120
|
+
expect(tokens[0].value).to eq('foo')
|
121
|
+
expect(tokens[0].line).to eq(1)
|
122
|
+
expect(tokens[0].column).to eq(1)
|
123
|
+
|
124
|
+
expect(tokens[1].type).to eq(:VARIABLE)
|
125
|
+
expect(tokens[1].value).to eq('bar')
|
126
|
+
expect(tokens[1].line).to eq(1)
|
127
|
+
expect(tokens[1].column).to eq(6)
|
128
|
+
|
129
|
+
expect(tokens[2].type).to eq(:DQPOST)
|
130
|
+
expect(tokens[2].value).to eq('baz')
|
131
|
+
expect(tokens[2].line).to eq(1)
|
132
|
+
expect(tokens[2].column).to eq(11)
|
133
|
+
end
|
134
|
+
|
135
|
+
it 'should handle a string with multiple variables and surrounding text' do
|
136
|
+
@lexer.interpolate_string('foo${bar}baz${gronk}meh"', 1, 1)
|
137
|
+
tokens = @lexer.tokens
|
138
|
+
|
139
|
+
expect(tokens.length).to eq(5)
|
140
|
+
|
141
|
+
expect(tokens[0].type).to eq(:DQPRE)
|
142
|
+
expect(tokens[0].value).to eq('foo')
|
143
|
+
expect(tokens[0].line).to eq(1)
|
144
|
+
expect(tokens[0].column).to eq(1)
|
145
|
+
|
146
|
+
expect(tokens[1].type).to eq(:VARIABLE)
|
147
|
+
expect(tokens[1].value).to eq('bar')
|
148
|
+
expect(tokens[1].line).to eq(1)
|
149
|
+
expect(tokens[1].column).to eq(6)
|
150
|
+
|
151
|
+
expect(tokens[2].type).to eq(:DQMID)
|
152
|
+
expect(tokens[2].value).to eq('baz')
|
153
|
+
expect(tokens[2].line).to eq(1)
|
154
|
+
expect(tokens[2].column).to eq(11)
|
155
|
+
|
156
|
+
expect(tokens[3].type).to eq(:VARIABLE)
|
157
|
+
expect(tokens[3].value).to eq('gronk')
|
158
|
+
expect(tokens[3].line).to eq(1)
|
159
|
+
expect(tokens[3].column).to eq(15)
|
160
|
+
|
161
|
+
expect(tokens[4].type).to eq(:DQPOST)
|
162
|
+
expect(tokens[4].value).to eq('meh')
|
163
|
+
expect(tokens[4].line).to eq(1)
|
164
|
+
expect(tokens[4].column).to eq(22)
|
165
|
+
end
|
166
|
+
|
167
|
+
it 'should handle a string with only a single variable' do
|
168
|
+
@lexer.interpolate_string('${bar}"', 1, 1)
|
169
|
+
tokens = @lexer.tokens
|
170
|
+
|
171
|
+
expect(tokens.length).to eq(3)
|
172
|
+
|
173
|
+
expect(tokens[0].type).to eq(:DQPRE)
|
174
|
+
expect(tokens[0].value).to eq('')
|
175
|
+
expect(tokens[0].line).to eq(1)
|
176
|
+
expect(tokens[0].column).to eq(1)
|
177
|
+
|
178
|
+
expect(tokens[1].type).to eq(:VARIABLE)
|
179
|
+
expect(tokens[1].value).to eq('bar')
|
180
|
+
expect(tokens[1].line).to eq(1)
|
181
|
+
expect(tokens[1].column).to eq(3)
|
182
|
+
|
183
|
+
expect(tokens[2].type).to eq(:DQPOST)
|
184
|
+
expect(tokens[2].value).to eq('')
|
185
|
+
expect(tokens[2].line).to eq(1)
|
186
|
+
expect(tokens[2].column).to eq(8)
|
187
|
+
end
|
188
|
+
|
189
|
+
it 'should handle a variable with an array reference' do
|
190
|
+
@lexer.interpolate_string('${foo[bar][baz]}"', 1, 1)
|
191
|
+
tokens = @lexer.tokens
|
192
|
+
|
193
|
+
expect(tokens.length).to eq(3)
|
194
|
+
|
195
|
+
expect(tokens[0].type).to eq(:DQPRE)
|
196
|
+
expect(tokens[0].value).to eq('')
|
197
|
+
expect(tokens[0].line).to eq(1)
|
198
|
+
expect(tokens[0].column).to eq(1)
|
199
|
+
|
200
|
+
expect(tokens[1].type).to eq(:VARIABLE)
|
201
|
+
expect(tokens[1].value).to eq('foo[bar][baz]')
|
202
|
+
expect(tokens[1].line).to eq(1)
|
203
|
+
expect(tokens[1].column).to eq(3)
|
204
|
+
|
205
|
+
expect(tokens[2].type).to eq(:DQPOST)
|
206
|
+
expect(tokens[2].value).to eq('')
|
207
|
+
expect(tokens[2].line).to eq(1)
|
208
|
+
expect(tokens[2].column).to eq(18)
|
209
|
+
end
|
210
|
+
|
211
|
+
it 'should handle a string with only many variables' do
|
212
|
+
@lexer.interpolate_string('${bar}${gronk}"', 1, 1)
|
213
|
+
tokens = @lexer.tokens
|
214
|
+
|
215
|
+
expect(tokens.length).to eq(5)
|
216
|
+
|
217
|
+
expect(tokens[0].type).to eq(:DQPRE)
|
218
|
+
expect(tokens[0].value).to eq('')
|
219
|
+
expect(tokens[0].line).to eq(1)
|
220
|
+
expect(tokens[0].column).to eq(1)
|
221
|
+
|
222
|
+
expect(tokens[1].type).to eq(:VARIABLE)
|
223
|
+
expect(tokens[1].value).to eq('bar')
|
224
|
+
expect(tokens[1].line).to eq(1)
|
225
|
+
expect(tokens[1].column).to eq(3)
|
226
|
+
|
227
|
+
expect(tokens[2].type).to eq(:DQMID)
|
228
|
+
expect(tokens[2].value).to eq('')
|
229
|
+
expect(tokens[2].line).to eq(1)
|
230
|
+
expect(tokens[2].column).to eq(8)
|
231
|
+
|
232
|
+
expect(tokens[3].type).to eq(:VARIABLE)
|
233
|
+
expect(tokens[3].value).to eq('gronk')
|
234
|
+
expect(tokens[3].line).to eq(1)
|
235
|
+
expect(tokens[3].column).to eq(9)
|
236
|
+
|
237
|
+
expect(tokens[4].type).to eq(:DQPOST)
|
238
|
+
expect(tokens[4].value).to eq('')
|
239
|
+
expect(tokens[4].line).to eq(1)
|
240
|
+
expect(tokens[4].column).to eq(16)
|
241
|
+
end
|
242
|
+
|
243
|
+
it 'should handle a string with only an unenclosed variable' do
|
244
|
+
@lexer.interpolate_string('$foo"', 1, 1)
|
245
|
+
tokens = @lexer.tokens
|
246
|
+
|
247
|
+
expect(tokens.length).to eq(3)
|
248
|
+
|
249
|
+
expect(tokens[0].type).to eq(:DQPRE)
|
250
|
+
expect(tokens[0].value).to eq('')
|
251
|
+
expect(tokens[0].line).to eq(1)
|
252
|
+
expect(tokens[0].column).to eq(1)
|
253
|
+
|
254
|
+
expect(tokens[1].type).to eq(:UNENC_VARIABLE)
|
255
|
+
expect(tokens[1].value).to eq('foo')
|
256
|
+
expect(tokens[1].line).to eq(1)
|
257
|
+
expect(tokens[1].column).to eq(2)
|
258
|
+
|
259
|
+
expect(tokens[2].type).to eq(:DQPOST)
|
260
|
+
expect(tokens[2].value).to eq('')
|
261
|
+
expect(tokens[2].line).to eq(1)
|
262
|
+
expect(tokens[2].column).to eq(6)
|
263
|
+
end
|
264
|
+
|
265
|
+
it 'should handle a string with a nested string inside it' do
|
266
|
+
@lexer.interpolate_string(%q{string with ${'a nested single quoted string'} inside it"}, 1, 1)
|
267
|
+
tokens = @lexer.tokens
|
268
|
+
|
269
|
+
expect(tokens.length).to eq(3)
|
270
|
+
|
271
|
+
expect(tokens[0].type).to eq(:DQPRE)
|
272
|
+
expect(tokens[0].value).to eq('string with ')
|
273
|
+
expect(tokens[0].line).to eq(1)
|
274
|
+
expect(tokens[0].column).to eq(1)
|
275
|
+
|
276
|
+
expect(tokens[1].type).to eq(:SSTRING)
|
277
|
+
expect(tokens[1].value).to eq('a nested single quoted string')
|
278
|
+
expect(tokens[1].line).to eq(1)
|
279
|
+
expect(tokens[1].column).to eq(16)
|
280
|
+
|
281
|
+
expect(tokens[2].type).to eq(:DQPOST)
|
282
|
+
expect(tokens[2].value).to eq(' inside it')
|
283
|
+
expect(tokens[2].line).to eq(1)
|
284
|
+
expect(tokens[2].column).to eq(48)
|
285
|
+
end
|
286
|
+
|
287
|
+
it 'should handle a string with nested math' do
|
288
|
+
@lexer.interpolate_string(%q{string with ${(3+5)/4} nested math"}, 1, 1)
|
289
|
+
tokens = @lexer.tokens
|
290
|
+
|
291
|
+
expect(tokens.length).to eq(9)
|
292
|
+
|
293
|
+
expect(tokens[0].type).to eq(:DQPRE)
|
294
|
+
expect(tokens[0].value).to eq('string with ')
|
295
|
+
expect(tokens[0].line).to eq(1)
|
296
|
+
expect(tokens[0].column).to eq(1)
|
297
|
+
|
298
|
+
expect(tokens[1].type).to eq(:LPAREN)
|
299
|
+
expect(tokens[1].line).to eq(1)
|
300
|
+
expect(tokens[1].column).to eq(16)
|
301
|
+
|
302
|
+
expect(tokens[2].type).to eq(:NUMBER)
|
303
|
+
expect(tokens[2].value).to eq('3')
|
304
|
+
expect(tokens[2].line).to eq(1)
|
305
|
+
expect(tokens[2].column).to eq(17)
|
306
|
+
|
307
|
+
expect(tokens[3].type).to eq(:PLUS)
|
308
|
+
expect(tokens[3].line).to eq(1)
|
309
|
+
expect(tokens[3].column).to eq(18)
|
310
|
+
|
311
|
+
expect(tokens[4].type).to eq(:NUMBER)
|
312
|
+
expect(tokens[4].value).to eq('5')
|
313
|
+
expect(tokens[4].line).to eq(1)
|
314
|
+
expect(tokens[4].column).to eq(19)
|
315
|
+
|
316
|
+
expect(tokens[5].type).to eq(:RPAREN)
|
317
|
+
expect(tokens[5].line).to eq(1)
|
318
|
+
expect(tokens[5].column).to eq(20)
|
319
|
+
|
320
|
+
expect(tokens[6].type).to eq(:DIV)
|
321
|
+
expect(tokens[6].line).to eq(1)
|
322
|
+
expect(tokens[6].column).to eq(21)
|
323
|
+
|
324
|
+
expect(tokens[7].type).to eq(:NUMBER)
|
325
|
+
expect(tokens[7].value).to eq('4')
|
326
|
+
expect(tokens[7].line).to eq(1)
|
327
|
+
expect(tokens[7].column).to eq(22)
|
328
|
+
|
329
|
+
expect(tokens[8].type).to eq(:DQPOST)
|
330
|
+
expect(tokens[8].value).to eq(' nested math')
|
331
|
+
expect(tokens[8].line).to eq(1)
|
332
|
+
expect(tokens[8].column).to eq(24)
|
333
|
+
end
|
334
|
+
|
335
|
+
it 'should handle a string with a nested array' do
|
336
|
+
@lexer.interpolate_string(%q{string with ${['an array ', $v2]} in it"}, 1, 1)
|
337
|
+
tokens = @lexer.tokens
|
338
|
+
|
339
|
+
expect(tokens.length).to eq(8)
|
340
|
+
|
341
|
+
expect(tokens[0].type).to eq(:DQPRE)
|
342
|
+
expect(tokens[0].value).to eq('string with ')
|
343
|
+
expect(tokens[0].line).to eq(1)
|
344
|
+
expect(tokens[0].column).to eq(1)
|
345
|
+
|
346
|
+
expect(tokens[1].type).to eq(:LBRACK)
|
347
|
+
expect(tokens[1].line).to eq(1)
|
348
|
+
expect(tokens[1].column).to eq(16)
|
349
|
+
|
350
|
+
expect(tokens[2].type).to eq(:SSTRING)
|
351
|
+
expect(tokens[2].value).to eq('an array ')
|
352
|
+
expect(tokens[2].line).to eq(1)
|
353
|
+
expect(tokens[2].column).to eq(17)
|
354
|
+
|
355
|
+
expect(tokens[3].type).to eq(:COMMA)
|
356
|
+
expect(tokens[3].line).to eq(1)
|
357
|
+
expect(tokens[3].column).to eq(28)
|
358
|
+
|
359
|
+
expect(tokens[4].type).to eq(:WHITESPACE)
|
360
|
+
expect(tokens[4].value).to eq(' ')
|
361
|
+
expect(tokens[4].line).to eq(1)
|
362
|
+
expect(tokens[4].column).to eq(29)
|
363
|
+
|
364
|
+
expect(tokens[5].type).to eq(:VARIABLE)
|
365
|
+
expect(tokens[5].value).to eq('v2')
|
366
|
+
expect(tokens[5].line).to eq(1)
|
367
|
+
expect(tokens[5].column).to eq(30)
|
368
|
+
|
369
|
+
expect(tokens[6].type).to eq(:RBRACK)
|
370
|
+
expect(tokens[6].line).to eq(1)
|
371
|
+
expect(tokens[6].column).to eq(33)
|
372
|
+
|
373
|
+
expect(tokens[7].type).to eq(:DQPOST)
|
374
|
+
expect(tokens[7].value).to eq(' in it')
|
375
|
+
expect(tokens[7].line).to eq(1)
|
376
|
+
expect(tokens[7].column).to eq(35)
|
377
|
+
end
|
378
|
+
|
379
|
+
it 'should handle a string of $s' do
|
380
|
+
@lexer.interpolate_string(%q{$$$$"}, 1, 1)
|
381
|
+
tokens = @lexer.tokens
|
382
|
+
|
383
|
+
expect(tokens.length).to eq(1)
|
384
|
+
|
385
|
+
expect(tokens[0].type).to eq(:STRING)
|
386
|
+
expect(tokens[0].value).to eq('$$$$')
|
387
|
+
expect(tokens[0].line).to eq(1)
|
388
|
+
expect(tokens[0].column).to eq(1)
|
389
|
+
end
|
390
|
+
|
391
|
+
it 'should handle "$foo$bar"' do
|
392
|
+
@lexer.interpolate_string(%q{$foo$bar"}, 1, 1)
|
393
|
+
tokens = @lexer.tokens
|
394
|
+
|
395
|
+
expect(tokens.length).to eq(5)
|
396
|
+
|
397
|
+
expect(tokens[0].type).to eq(:DQPRE)
|
398
|
+
expect(tokens[0].value).to eq('')
|
399
|
+
expect(tokens[0].line).to eq(1)
|
400
|
+
expect(tokens[0].column).to eq(1)
|
401
|
+
|
402
|
+
expect(tokens[1].type).to eq(:UNENC_VARIABLE)
|
403
|
+
expect(tokens[1].value).to eq('foo')
|
404
|
+
expect(tokens[1].line).to eq(1)
|
405
|
+
expect(tokens[1].column).to eq(2)
|
406
|
+
|
407
|
+
expect(tokens[2].type).to eq(:DQMID)
|
408
|
+
expect(tokens[2].value).to eq('')
|
409
|
+
expect(tokens[2].line).to eq(1)
|
410
|
+
expect(tokens[2].column).to eq(6)
|
411
|
+
|
412
|
+
expect(tokens[3].type).to eq(:UNENC_VARIABLE)
|
413
|
+
expect(tokens[3].value).to eq('bar')
|
414
|
+
expect(tokens[3].line).to eq(1)
|
415
|
+
expect(tokens[3].column).to eq(6)
|
416
|
+
|
417
|
+
expect(tokens[4].type).to eq(:DQPOST)
|
418
|
+
expect(tokens[4].value).to eq('')
|
419
|
+
expect(tokens[4].line).to eq(1)
|
420
|
+
expect(tokens[4].column).to eq(10)
|
421
|
+
end
|
422
|
+
|
423
|
+
it 'should handle "foo$bar$"' do
|
424
|
+
@lexer.interpolate_string(%q{foo$bar$"}, 1, 1)
|
425
|
+
tokens = @lexer.tokens
|
426
|
+
|
427
|
+
expect(tokens.length).to eq(3)
|
428
|
+
|
429
|
+
expect(tokens[0].type).to eq(:DQPRE)
|
430
|
+
expect(tokens[0].value).to eq('foo')
|
431
|
+
expect(tokens[0].line).to eq(1)
|
432
|
+
expect(tokens[0].column).to eq(1)
|
433
|
+
|
434
|
+
expect(tokens[1].type).to eq(:UNENC_VARIABLE)
|
435
|
+
expect(tokens[1].value).to eq('bar')
|
436
|
+
expect(tokens[1].line).to eq(1)
|
437
|
+
expect(tokens[1].column).to eq(5)
|
438
|
+
|
439
|
+
expect(tokens[2].type).to eq(:DQPOST)
|
440
|
+
expect(tokens[2].value).to eq('$')
|
441
|
+
expect(tokens[2].line).to eq(1)
|
442
|
+
expect(tokens[2].column).to eq(9)
|
443
|
+
end
|
444
|
+
|
445
|
+
it 'should handle "foo$$bar"' do
|
446
|
+
@lexer.interpolate_string(%q{foo$$bar"}, 1, 1)
|
447
|
+
tokens = @lexer.tokens
|
448
|
+
|
449
|
+
expect(tokens.length).to eq(3)
|
450
|
+
|
451
|
+
expect(tokens[0].type).to eq(:DQPRE)
|
452
|
+
expect(tokens[0].value).to eq('foo$')
|
453
|
+
expect(tokens[0].line).to eq(1)
|
454
|
+
expect(tokens[0].column).to eq(1)
|
455
|
+
|
456
|
+
expect(tokens[1].type).to eq(:UNENC_VARIABLE)
|
457
|
+
expect(tokens[1].value).to eq('bar')
|
458
|
+
expect(tokens[1].line).to eq(1)
|
459
|
+
expect(tokens[1].column).to eq(6)
|
460
|
+
|
461
|
+
expect(tokens[2].type).to eq(:DQPOST)
|
462
|
+
expect(tokens[2].value).to eq('')
|
463
|
+
expect(tokens[2].line).to eq(1)
|
464
|
+
expect(tokens[2].column).to eq(10)
|
465
|
+
end
|
466
|
+
|
467
|
+
it 'should handle an empty string' do
|
468
|
+
@lexer.interpolate_string(%q{"}, 1, 1)
|
469
|
+
tokens = @lexer.tokens
|
470
|
+
|
471
|
+
expect(tokens.length).to eq(1)
|
472
|
+
|
473
|
+
expect(tokens[0].type).to eq(:STRING)
|
474
|
+
expect(tokens[0].value).to eq('')
|
475
|
+
expect(tokens[0].line).to eq(1)
|
476
|
+
expect(tokens[0].column).to eq(1)
|
477
|
+
end
|
478
|
+
|
479
|
+
it 'should handle "$foo::::bar"' do
|
480
|
+
@lexer.interpolate_string(%q{$foo::::bar"}, 1, 1)
|
481
|
+
tokens = @lexer.tokens
|
482
|
+
|
483
|
+
expect(tokens.length).to eq(3)
|
484
|
+
|
485
|
+
expect(tokens[0].type).to eq(:DQPRE)
|
486
|
+
expect(tokens[0].value).to eq('')
|
487
|
+
expect(tokens[0].line).to eq(1)
|
488
|
+
expect(tokens[0].column).to eq(1)
|
489
|
+
|
490
|
+
expect(tokens[1].type).to eq(:UNENC_VARIABLE)
|
491
|
+
expect(tokens[1].value).to eq('foo')
|
492
|
+
expect(tokens[1].line).to eq(1)
|
493
|
+
expect(tokens[1].column).to eq(2)
|
494
|
+
|
495
|
+
expect(tokens[2].type).to eq(:DQPOST)
|
496
|
+
expect(tokens[2].value).to eq('::::bar')
|
497
|
+
expect(tokens[2].line).to eq(1)
|
498
|
+
expect(tokens[2].column).to eq(6)
|
499
|
+
end
|
500
|
+
end
|
501
|
+
|
502
|
+
[
|
503
|
+
'case',
|
504
|
+
'class',
|
505
|
+
'default',
|
506
|
+
'define',
|
507
|
+
'import',
|
508
|
+
'if',
|
509
|
+
'elsif',
|
510
|
+
'else',
|
511
|
+
'inherits',
|
512
|
+
'node',
|
513
|
+
'and',
|
514
|
+
'or',
|
515
|
+
'undef',
|
516
|
+
'true',
|
517
|
+
'false',
|
518
|
+
'in',
|
519
|
+
'unless',
|
520
|
+
].each do |keyword|
|
521
|
+
it "should handle '#{keyword}' as a keyword" do
|
522
|
+
token = @lexer.tokenise(keyword).first
|
523
|
+
expect(token.type).to eq(keyword.upcase.to_sym)
|
524
|
+
expect(token.value).to eq(keyword)
|
525
|
+
end
|
526
|
+
end
|
527
|
+
|
528
|
+
[
|
529
|
+
[:LBRACK, '['],
|
530
|
+
[:RBRACK, ']'],
|
531
|
+
[:LBRACE, '{'],
|
532
|
+
[:RBRACE, '}'],
|
533
|
+
[:LPAREN, '('],
|
534
|
+
[:RPAREN, ')'],
|
535
|
+
[:EQUALS, '='],
|
536
|
+
[:ISEQUAL, '=='],
|
537
|
+
[:GREATEREQUAL, '>='],
|
538
|
+
[:GREATERTHAN, '>'],
|
539
|
+
[:LESSTHAN, '<'],
|
540
|
+
[:LESSEQUAL, '<='],
|
541
|
+
[:NOTEQUAL, '!='],
|
542
|
+
[:NOT, '!'],
|
543
|
+
[:COMMA, ','],
|
544
|
+
[:DOT, '.'],
|
545
|
+
[:COLON, ':'],
|
546
|
+
[:AT, '@'],
|
547
|
+
[:LLCOLLECT, '<<|'],
|
548
|
+
[:RRCOLLECT, '|>>'],
|
549
|
+
[:LCOLLECT, '<|'],
|
550
|
+
[:RCOLLECT, '|>'],
|
551
|
+
[:SEMIC, ';'],
|
552
|
+
[:QMARK, '?'],
|
553
|
+
[:BACKSLASH, '\\'],
|
554
|
+
[:FARROW, '=>'],
|
555
|
+
[:PARROW, '+>'],
|
556
|
+
[:APPENDS, '+='],
|
557
|
+
[:PLUS, '+'],
|
558
|
+
[:MINUS, '-'],
|
559
|
+
[:DIV, '/'],
|
560
|
+
[:TIMES, '*'],
|
561
|
+
[:MODULO, '%'],
|
562
|
+
[:PIPE, '|'],
|
563
|
+
[:LSHIFT, '<<'],
|
564
|
+
[:RSHIFT, '>>'],
|
565
|
+
[:MATCH, '=~'],
|
566
|
+
[:NOMATCH, '!~'],
|
567
|
+
[:IN_EDGE, '->'],
|
568
|
+
[:OUT_EDGE, '<-'],
|
569
|
+
[:IN_EDGE_SUB, '~>'],
|
570
|
+
[:OUT_EDGE_SUB, '<~'],
|
571
|
+
[:NEWLINE, "\r"],
|
572
|
+
[:NEWLINE, "\n"],
|
573
|
+
[:NEWLINE, "\r\n"],
|
574
|
+
].each do |name, string|
|
575
|
+
it "should have a token named '#{name.to_s}'" do
|
576
|
+
token = @lexer.tokenise(string).first
|
577
|
+
expect(token.type).to eq(name)
|
578
|
+
expect(token.value).to eq(string)
|
579
|
+
end
|
580
|
+
end
|
581
|
+
|
582
|
+
context ':CLASSREF' do
|
583
|
+
it 'should match single capitalised alphanumeric term' do
|
584
|
+
token = @lexer.tokenise('One').first
|
585
|
+
expect(token.type).to eq(:CLASSREF)
|
586
|
+
expect(token.value).to eq('One')
|
587
|
+
end
|
588
|
+
|
589
|
+
it 'should match two capitalised alphanumeric terms sep by ::' do
|
590
|
+
token = @lexer.tokenise('One::Two').first
|
591
|
+
expect(token.type).to eq(:CLASSREF)
|
592
|
+
expect(token.value).to eq('One::Two')
|
593
|
+
end
|
594
|
+
|
595
|
+
it 'should match many capitalised alphanumeric terms sep by ::' do
|
596
|
+
token = @lexer.tokenise('One::Two::Three::Four::Five').first
|
597
|
+
expect(token.type).to eq(:CLASSREF)
|
598
|
+
expect(token.value).to eq('One::Two::Three::Four::Five')
|
599
|
+
end
|
600
|
+
|
601
|
+
it 'should match capitalised terms prefixed by ::' do
|
602
|
+
token = @lexer.tokenise('::One').first
|
603
|
+
expect(token.type).to eq(:CLASSREF)
|
604
|
+
expect(token.value).to eq('::One')
|
605
|
+
end
|
606
|
+
end
|
607
|
+
|
608
|
+
context ':NAME' do
|
609
|
+
it 'should match lowercase alphanumeric terms' do
|
610
|
+
token = @lexer.tokenise('one-two').first
|
611
|
+
expect(token.type).to eq(:NAME)
|
612
|
+
expect(token.value).to eq('one-two')
|
613
|
+
end
|
614
|
+
|
615
|
+
it 'should match lowercase alphanumeric terms sep by ::' do
|
616
|
+
token = @lexer.tokenise('one::two').first
|
617
|
+
expect(token.type).to eq(:NAME)
|
618
|
+
expect(token.value).to eq('one::two')
|
619
|
+
end
|
620
|
+
|
621
|
+
it 'should match many lowercase alphanumeric terms sep by ::' do
|
622
|
+
token = @lexer.tokenise('one::two::three::four::five').first
|
623
|
+
expect(token.type).to eq(:NAME)
|
624
|
+
expect(token.value).to eq('one::two::three::four::five')
|
625
|
+
end
|
626
|
+
|
627
|
+
it 'should match lowercase alphanumeric terms prefixed by ::' do
|
628
|
+
token = @lexer.tokenise('::1one::2two::3three').first
|
629
|
+
expect(token.type).to eq(:NAME)
|
630
|
+
expect(token.value).to eq('::1one::2two::3three')
|
631
|
+
end
|
632
|
+
end
|
633
|
+
|
634
|
+
context ':NUMBER' do
|
635
|
+
it 'should match numeric terms' do
|
636
|
+
token = @lexer.tokenise('1234567890').first
|
637
|
+
expect(token.type).to eq(:NUMBER)
|
638
|
+
expect(token.value).to eq('1234567890')
|
639
|
+
end
|
640
|
+
|
641
|
+
it 'should match float terms' do
|
642
|
+
token = @lexer.tokenise('12345.6789').first
|
643
|
+
expect(token.type).to eq(:NUMBER)
|
644
|
+
expect(token.value).to eq('12345.6789')
|
645
|
+
end
|
646
|
+
|
647
|
+
it 'should match hexadecimal terms' do
|
648
|
+
token = @lexer.tokenise('0xCAFE1029').first
|
649
|
+
expect(token.type).to eq(:NUMBER)
|
650
|
+
expect(token.value).to eq('0xCAFE1029')
|
651
|
+
end
|
652
|
+
|
653
|
+
it 'should match float with exponent terms' do
|
654
|
+
token = @lexer.tokenise('10e23').first
|
655
|
+
expect(token.type).to eq(:NUMBER)
|
656
|
+
expect(token.value).to eq('10e23')
|
657
|
+
end
|
658
|
+
|
659
|
+
it 'should match float with negative exponent terms' do
|
660
|
+
token = @lexer.tokenise('10e-23').first
|
661
|
+
expect(token.type).to eq(:NUMBER)
|
662
|
+
expect(token.value).to eq('10e-23')
|
663
|
+
end
|
664
|
+
|
665
|
+
it 'should match float with exponent terms' do
|
666
|
+
token = @lexer.tokenise('1.234e5').first
|
667
|
+
expect(token.type).to eq(:NUMBER)
|
668
|
+
expect(token.value).to eq('1.234e5')
|
669
|
+
end
|
670
|
+
end
|
671
|
+
|
672
|
+
context ':COMMENT' do
|
673
|
+
it 'should match everything on a line after #' do
|
674
|
+
token = @lexer.tokenise('foo # bar baz')[2]
|
675
|
+
expect(token.type).to eq(:COMMENT)
|
676
|
+
expect(token.value).to eq(' bar baz')
|
677
|
+
end
|
678
|
+
end
|
679
|
+
|
680
|
+
context ':MLCOMMENT' do
|
681
|
+
it 'should match comments on a single line' do
|
682
|
+
token = @lexer.tokenise('/* foo bar */').first
|
683
|
+
expect(token.type).to eq(:MLCOMMENT)
|
684
|
+
expect(token.value).to eq('foo bar')
|
685
|
+
end
|
686
|
+
|
687
|
+
it 'should match comments on multiple lines' do
|
688
|
+
token = @lexer.tokenise("/* foo\n * bar\n*/").first
|
689
|
+
expect(token.type).to eq(:MLCOMMENT)
|
690
|
+
expect(token.value).to eq("foo\n bar\n")
|
691
|
+
end
|
692
|
+
end
|
693
|
+
|
694
|
+
context ':SLASH_COMMENT' do
|
695
|
+
it 'should match everyone on a line after //' do
|
696
|
+
token = @lexer.tokenise('foo // bar baz')[2]
|
697
|
+
expect(token.type).to eq(:SLASH_COMMENT)
|
698
|
+
expect(token.value).to eq(' bar baz')
|
699
|
+
end
|
700
|
+
end
|
701
|
+
|
702
|
+
context ':SSTRING' do
|
703
|
+
it 'should match a single quoted string' do
|
704
|
+
token = @lexer.tokenise("'single quoted string'").first
|
705
|
+
expect(token.type).to eq(:SSTRING)
|
706
|
+
expect(token.value).to eq('single quoted string')
|
707
|
+
end
|
708
|
+
|
709
|
+
it "should match a single quoted string with an escaped '" do
|
710
|
+
token = @lexer.tokenise(%q{'single quoted string with "\\'"'}).first
|
711
|
+
expect(token.type).to eq(:SSTRING)
|
712
|
+
expect(token.value).to eq('single quoted string with "\\\'"')
|
713
|
+
end
|
714
|
+
|
715
|
+
it "should match a single quoted string with an escaped $" do
|
716
|
+
token = @lexer.tokenise(%q{'single quoted string with "\$"'}).first
|
717
|
+
expect(token.type).to eq(:SSTRING)
|
718
|
+
expect(token.value).to eq('single quoted string with "\\$"')
|
719
|
+
end
|
720
|
+
|
721
|
+
it "should match a single quoted string with an escaped ." do
|
722
|
+
token = @lexer.tokenise(%q{'single quoted string with "\."'}).first
|
723
|
+
expect(token.type).to eq(:SSTRING)
|
724
|
+
expect(token.value).to eq('single quoted string with "\\."')
|
725
|
+
end
|
726
|
+
|
727
|
+
it "should match a single quoted string with an escaped \\n" do
|
728
|
+
token = @lexer.tokenise(%q{'single quoted string with "\n"'}).first
|
729
|
+
expect(token.type).to eq(:SSTRING)
|
730
|
+
expect(token.value).to eq('single quoted string with "\\n"')
|
731
|
+
end
|
732
|
+
|
733
|
+
it "should match a single quoted string with an escaped \\" do
|
734
|
+
token = @lexer.tokenise(%q{'single quoted string with "\\\\"'}).first
|
735
|
+
expect(token.type).to eq(:SSTRING)
|
736
|
+
expect(token.value).to eq('single quoted string with "\\\\"')
|
737
|
+
end
|
738
|
+
|
739
|
+
it "should match an empty string" do
|
740
|
+
token = @lexer.tokenise("''").first
|
741
|
+
expect(token.type).to eq(:SSTRING)
|
742
|
+
expect(token.value).to eq('')
|
743
|
+
end
|
744
|
+
|
745
|
+
it "should match an empty string ending with \\\\" do
|
746
|
+
token = @lexer.tokenise("'foo\\\\'").first
|
747
|
+
expect(token.type).to eq(:SSTRING)
|
748
|
+
expect(token.value).to eq(%{foo\\\\})
|
749
|
+
end
|
750
|
+
end
|
751
|
+
|
752
|
+
context ':REGEX' do
|
753
|
+
it 'should match anything enclosed in //' do
|
754
|
+
token = @lexer.tokenise('/this is a regex/').first
|
755
|
+
expect(token.type).to eq(:REGEX)
|
756
|
+
expect(token.value).to eq('this is a regex')
|
757
|
+
end
|
758
|
+
|
759
|
+
it 'should not match if there is \n in the regex' do
|
760
|
+
token = @lexer.tokenise("/this is \n a regex/").first
|
761
|
+
expect(token.type).to_not eq(:REGEX)
|
762
|
+
end
|
763
|
+
|
764
|
+
it 'should not consider \/ to be the end of the regex' do
|
765
|
+
token = @lexer.tokenise('/this is \/ a regex/').first
|
766
|
+
expect(token.type).to eq(:REGEX)
|
767
|
+
expect(token.value).to eq('this is \\/ a regex')
|
768
|
+
end
|
769
|
+
|
770
|
+
it 'should not match chained division' do
|
771
|
+
tokens = @lexer.tokenise('$x = $a/$b/$c')
|
772
|
+
expect(tokens.select { |r| r.type == :REGEX }).to be_empty
|
773
|
+
end
|
774
|
+
end
|
775
|
+
|
776
|
+
context ':STRING' do
|
777
|
+
it 'should parse strings with \\\\\\' do
|
778
|
+
expect {
|
779
|
+
@lexer.tokenise("exec { \"/bin/echo \\\\\\\"${environment}\\\\\\\"\": }")
|
780
|
+
}.to_not raise_error
|
781
|
+
end
|
782
|
+
end
|
783
|
+
end
|