ios_parser 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,231 @@
1
+ require_relative '../../spec_helper'
2
+ require 'ios_parser'
3
+ require 'ios_parser/lexer'
4
+
5
+ module IOSParser
6
+ describe Lexer do
7
+ describe '#call' do
8
+ subject { klass.new.call(input) }
9
+
10
+ let(:subject_pure) do
11
+ IOSParser::PureLexer.new.call(input)
12
+ end
13
+
14
+ context 'indented region' do
15
+ let(:input) { <<-END }
16
+ policy-map mypolicy_in
17
+ class myservice_service
18
+ police 300000000 1000000 exceed-action policed-dscp-transmit
19
+ set dscp cs1
20
+ class other_service
21
+ police 600000000 1000000 exceed-action policed-dscp-transmit
22
+ set dscp cs2
23
+ END
24
+
25
+ let(:output) do
26
+ ['policy-map', 'mypolicy_in', :EOL,
27
+ :INDENT,
28
+ 'class', 'myservice_service', :EOL,
29
+ :INDENT,
30
+ 'police', 300_000_000, 1_000_000, 'exceed-action',
31
+ 'policed-dscp-transmit', :EOL,
32
+ :INDENT,
33
+ 'set', 'dscp', 'cs1', :EOL,
34
+ :DEDENT, :DEDENT,
35
+ 'class', 'other_service', :EOL,
36
+ :INDENT,
37
+ 'police', 600_000_000, 1_000_000, 'exceed-action',
38
+ 'policed-dscp-transmit', :EOL,
39
+ :INDENT,
40
+ 'set', 'dscp', 'cs2', :EOL, :DEDENT, :DEDENT, :DEDENT
41
+ ]
42
+ end
43
+
44
+ subject { klass.new.call(input).map(&:last) }
45
+ it('enclosed in symbols') { should == output }
46
+
47
+ it('enclosed in symbols (using the pure ruby lexer)') do
48
+ expect(subject_pure.map(&:last)).to eq output
49
+ end
50
+ end
51
+
52
+ context 'ASR indented regions' do
53
+ context 'indented region' do
54
+ let(:input) { <<-END }
55
+ router static
56
+ vrf MGMT
57
+ address-family ipv4 unicast
58
+ 0.0.0.0/0 1.2.3.4
59
+ !
60
+ !
61
+ !
62
+ router ospf 12345
63
+ nsr
64
+ END
65
+
66
+ let(:expectation) do
67
+ ['router', 'static', :EOL,
68
+ :INDENT, 'vrf', 'MGMT', :EOL,
69
+ :INDENT, 'address-family', 'ipv4', 'unicast', :EOL,
70
+ :INDENT, '0.0.0.0/0', '1.2.3.4', :EOL,
71
+ :DEDENT, :DEDENT, :DEDENT,
72
+ 'router', 'ospf', 12_345, :EOL,
73
+ :INDENT, 'nsr', :EOL,
74
+ :DEDENT
75
+ ]
76
+ end
77
+
78
+ it 'pure' do
79
+ tokens = IOSParser::PureLexer.new.call(input)
80
+ expect(tokens.map(&:last)).to eq expectation
81
+ end # it 'pure' do
82
+
83
+ it 'c' do
84
+ tokens = IOSParser::CLexer.new.call(input)
85
+ expect(tokens.map(&:last)).to eq expectation
86
+ end # it 'c' do
87
+ end # context 'indented region' do
88
+ end # context 'ASR indented regions' do
89
+
90
+ context 'banners' do
91
+ let(:input) do
92
+ <<-END
93
+ banner foobar ^
94
+ asdf 1234 9786 asdf
95
+ line 2
96
+ line 3
97
+ ^
98
+ END
99
+ end
100
+
101
+ let(:output) do
102
+ [[0, 'banner'], [7, 'foobar'], [14, :BANNER_BEGIN],
103
+ [16, "asdf 1234 9786 asdf\nline 2\nline 3\n "],
104
+ [52, :BANNER_END], [53, :EOL]]
105
+ end
106
+
107
+ it('tokenized and enclosed in symbols') { should == output }
108
+
109
+ it('tokenized and enclodes in symbols (using the pure ruby lexer)') do
110
+ expect(subject_pure).to eq output
111
+ end
112
+ end
113
+
114
+ context 'decimal number' do
115
+ let(:input) { 'boson levels at 93.2' }
116
+ let(:output) { ['boson', 'levels', 'at', 93.2] }
117
+ subject { klass.new.call(input).map(&:last) }
118
+ it('converts to Float') { should == output }
119
+ end
120
+
121
+ context 'cryptographic certificate' do
122
+ let(:input) do
123
+ <<END
124
+ crypto pki certificate chain TP-self-signed-0123456789
125
+ certificate self-signed 01
126
+ FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF
127
+ EEEEEEEE EEEEEEEE EEEEEEEE EEEEEEEE EEEEEEEE EEEEEEEE EEEEEEEE EEEEEEEE
128
+ DDDDDDDD DDDDDDDD DDDDDDDD DDDDDDDD DDDDDDDD DDDDDDDD DDDDDDDD DDDDDDDD AAAA
129
+ quit
130
+ !
131
+ END
132
+ end
133
+
134
+ let(:output) do
135
+ [[0, 'crypto'],
136
+ [7, 'pki'],
137
+ [11, 'certificate'],
138
+ [23, 'chain'],
139
+ [29, 'TP-self-signed-0123456789'],
140
+ [54, :EOL],
141
+ [56, :INDENT],
142
+ [56, 'certificate'],
143
+ [68, 'self-signed'],
144
+ [80, '01'],
145
+ [85, :CERTIFICATE_BEGIN],
146
+ [85,
147
+ 'FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF '\
148
+ 'FFFFFFFF EEEEEEEE EEEEEEEE EEEEEEEE EEEEEEEE EEEEEEEE EEEEEEEE '\
149
+ 'EEEEEEEE EEEEEEEE DDDDDDDD DDDDDDDD DDDDDDDD DDDDDDDD DDDDDDDD '\
150
+ 'DDDDDDDD DDDDDDDD DDDDDDDD AAAA'],
151
+ [323, :CERTIFICATE_END],
152
+ [323, :EOL],
153
+ [323, :DEDENT]
154
+ ]
155
+ end
156
+
157
+ subject { klass.new.call(input) }
158
+ it('tokenized') { expect(subject).to eq output }
159
+
160
+ it('tokenized (using the pure ruby lexer)') do
161
+ expect(subject_pure).to eq output
162
+ end
163
+ end
164
+
165
+ context 'comments' do
166
+ let(:input) { 'ip addr 127.0.0.0.1 ! asdfsdf' }
167
+ let(:output) { ['ip', 'addr', '127.0.0.0.1'] }
168
+ subject { klass.new.call(input).map(&:last) }
169
+ it('dropped') { should == output }
170
+ end
171
+
172
+ context 'quoted octothorpe' do
173
+ let(:input) { <<-EOS }
174
+ vlan 1
175
+ name "a #"
176
+ vlan 2
177
+ name d
178
+ EOS
179
+
180
+ let(:output) do
181
+ [
182
+ 'vlan', 1, :EOL,
183
+ :INDENT, 'name', '"a #"', :EOL,
184
+ :DEDENT,
185
+ 'vlan', 2, :EOL,
186
+ :INDENT, 'name', 'd', :EOL,
187
+ :DEDENT
188
+ ]
189
+ end
190
+
191
+ it { expect(subject_pure.map(&:last)).to eq output }
192
+ it { expect(subject.map(&:last)).to eq output }
193
+ end # context 'quoted octothorpe' do
194
+
195
+ context 'vlan range' do
196
+ let(:input) { 'switchport trunk allowed vlan 50-90' }
197
+ let(:output) do
198
+ [
199
+ [0, 'switchport'],
200
+ [11, 'trunk'],
201
+ [17, 'allowed'],
202
+ [25, 'vlan'],
203
+ [30, '50-90']
204
+ ]
205
+ end
206
+ it { should == output }
207
+ end # context 'vlan range' do
208
+
209
+ context 'partial dedent' do
210
+ let(:input) do
211
+ <<END
212
+ class-map match-any foobar
213
+ description blahblahblah
214
+ match access-group fred
215
+ END
216
+ end
217
+
218
+ let(:output) do
219
+ [
220
+ 'class-map', 'match-any', 'foobar', :EOL,
221
+ :INDENT, 'description', 'blahblahblah', :EOL,
222
+ 'match', 'access-group', 'fred', :EOL,
223
+ :DEDENT
224
+ ]
225
+ end
226
+
227
+ it { expect(subject_pure.map(&:last)).to eq output }
228
+ end
229
+ end
230
+ end
231
+ end
@@ -0,0 +1,101 @@
1
+ require_relative '../spec_helper'
2
+ require 'ios_parser'
3
+
4
+ describe IOSParser do
5
+ describe '.parse' do
6
+ context 'indented region' do
7
+ let(:input) { <<-END }
8
+ policy-map mypolicy_in
9
+ class myservice_service
10
+ police 300000000 1000000 exceed-action policed-dscp-transmit
11
+ set dscp cs1
12
+ class other_service
13
+ police 600000000 1000000 exceed-action policed-dscp-transmit
14
+ set dscp cs2
15
+ command_with_no_args
16
+ END
17
+
18
+ let(:output) do
19
+ {
20
+ commands:
21
+ [{ args: ['policy-map', 'mypolicy_in'],
22
+ commands:
23
+ [{ args: %w(class myservice_service),
24
+ commands: [{ args: ['police', 300_000_000, 1_000_000,
25
+ 'exceed-action',
26
+ 'policed-dscp-transmit'],
27
+ commands: [{ args: %w(set dscp cs1),
28
+ commands: [], pos: 114 }],
29
+ pos: 50
30
+ }],
31
+ pos: 24
32
+ },
33
+
34
+ { args: %w(class other_service),
35
+ commands: [{ args: ['police', 600_000_000, 1_000_000,
36
+ 'exceed-action',
37
+ 'policed-dscp-transmit'],
38
+ commands: [{ args: %w(set dscp cs2),
39
+ commands: [], pos: 214 },
40
+ { args: ['command_with_no_args'],
41
+ commands: [], pos: 230 }],
42
+ pos: 150
43
+ }],
44
+ pos: 128
45
+ }],
46
+ pos: 0
47
+ }]
48
+ }
49
+ end
50
+
51
+ subject { described_class.parse(input) }
52
+
53
+ it('constructs the right AST') do
54
+ should be_a IOSParser::IOS::Document
55
+ expect(subject.to_hash).to eq output
56
+ end
57
+ end # context 'indented region'
58
+
59
+ context 'partial outdent' do
60
+ let(:input) do
61
+ <<END
62
+ class-map match-any foobar
63
+ description blah blah blah
64
+ match access-group fred
65
+ END
66
+ end
67
+
68
+ let(:output) do
69
+ {
70
+ commands:
71
+ [
72
+ {
73
+ args: ['class-map', 'match-any', 'foobar'],
74
+ commands: [
75
+ {
76
+ args: %w(description blah blah blah),
77
+ commands: [],
78
+ pos: 29
79
+ },
80
+ {
81
+ args: ['match', 'access-group', 'fred'],
82
+ commands: [],
83
+ pos: 57
84
+ }
85
+ ],
86
+ pos: 0
87
+ }
88
+ ]
89
+ }
90
+ end
91
+
92
+ subject { described_class.parse(input) }
93
+
94
+ it 'constructs the right AST' do
95
+ should be_a IOSParser::IOS::Document
96
+ actual = subject.to_hash
97
+ expect(actual).to eq(output)
98
+ end
99
+ end # context "partial outdent" do
100
+ end # describe '.parse'
101
+ end # describe IOSParser
@@ -0,0 +1,5 @@
1
+ $LOAD_PATH << File.dirname(__FILE__) + '/../lib'
2
+
3
+ def klass
4
+ described_class
5
+ end
metadata ADDED
@@ -0,0 +1,164 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ios_parser
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.3.0
5
+ platform: ruby
6
+ authors:
7
+ - Ben Miller
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-03-05 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rspec
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '3.2'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '3.2'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rubocop
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '0.37'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '0.37'
41
+ - !ruby/object:Gem::Dependency
42
+ name: guard
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '2.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '2.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: guard-rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '4.5'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '4.5'
69
+ - !ruby/object:Gem::Dependency
70
+ name: guard-rubocop
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '1.2'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '1.2'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rake-compiler
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '0.9'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '0.9'
97
+ description:
98
+ email: bjmllr@gmail.com
99
+ executables: []
100
+ extensions:
101
+ - ext/ios_parser/c_lexer/extconf.rb
102
+ extra_rdoc_files: []
103
+ files:
104
+ - ".gitignore"
105
+ - ".rubocop.yml"
106
+ - ".travis.yml"
107
+ - CHANGELOG.md
108
+ - CODE_OF_CONDUCT.md
109
+ - Gemfile
110
+ - Guardfile
111
+ - LICENSE.txt
112
+ - README.md
113
+ - Rakefile
114
+ - bin/console
115
+ - bin/setup
116
+ - doc/state_machine.graphviz
117
+ - doc/state_machine.png
118
+ - ext/ios_parser/c_lexer/extconf.rb
119
+ - ext/ios_parser/c_lexer/lexer.c
120
+ - ios_parser.gemspec
121
+ - lib/ios_parser.rb
122
+ - lib/ios_parser/ios.rb
123
+ - lib/ios_parser/ios/command.rb
124
+ - lib/ios_parser/ios/document.rb
125
+ - lib/ios_parser/ios/queryable.rb
126
+ - lib/ios_parser/lexer.rb
127
+ - lib/ios_parser/pure.rb
128
+ - lib/ios_parser/version.rb
129
+ - spec/lib/ios_parser/ios/queryable_spec.rb
130
+ - spec/lib/ios_parser/ios_spec.rb
131
+ - spec/lib/ios_parser/lexer_spec.rb
132
+ - spec/lib/ios_parser_spec.rb
133
+ - spec/spec_helper.rb
134
+ homepage: https://github.com/bjmllr/ios_parser
135
+ licenses:
136
+ - GPL-3.0
137
+ metadata: {}
138
+ post_install_message:
139
+ rdoc_options: []
140
+ require_paths:
141
+ - lib
142
+ required_ruby_version: !ruby/object:Gem::Requirement
143
+ requirements:
144
+ - - ">="
145
+ - !ruby/object:Gem::Version
146
+ version: '0'
147
+ required_rubygems_version: !ruby/object:Gem::Requirement
148
+ requirements:
149
+ - - ">="
150
+ - !ruby/object:Gem::Version
151
+ version: '0'
152
+ requirements: []
153
+ rubyforge_project:
154
+ rubygems_version: 2.5.1
155
+ signing_key:
156
+ specification_version: 4
157
+ summary: convert network switch and router config files to structured data
158
+ test_files:
159
+ - spec/lib/ios_parser/ios/queryable_spec.rb
160
+ - spec/lib/ios_parser/ios_spec.rb
161
+ - spec/lib/ios_parser/lexer_spec.rb
162
+ - spec/lib/ios_parser_spec.rb
163
+ - spec/spec_helper.rb
164
+ has_rdoc: