1 | if typeof process isnt 'undefined' and process.execPath and process.execPath.indexOf('node') isnt -1
|
2 | chai = require 'chai' unless chai
|
3 | parser = require '../lib/fbp'
|
4 | else
|
5 | parser = require 'fbp'
|
6 |
|
7 | describe 'FBP parser', ->
|
8 | it 'should provide a parse method', ->
|
9 | chai.expect(parser.parse).to.be.a 'function'
|
10 | describe 'with simple FBP string', ->
|
11 | fbpData = "'somefile' -> SOURCE Read(ReadFile)"
|
12 | graphData = null
|
13 | it 'should produce a graph JSON object', ->
|
14 | graphData = parser.parse fbpData
|
15 | chai.expect(graphData).to.be.an 'object'
|
16 | describe 'the generated graph', ->
|
17 | it 'should contain one node', ->
|
18 | chai.expect(graphData.processes).to.eql
|
19 | Read:
|
20 | component: 'ReadFile'
|
21 | it 'should contain an IIP', ->
|
22 | chai.expect(graphData.connections).to.be.an 'array'
|
23 | chai.expect(graphData.connections.length).to.equal 1
|
24 |
|
25 | describe 'with three-statement FBP string', ->
|
26 | fbpData = """
|
27 | 'somefile.txt' -> SOURCE Read(ReadFile) OUT -> IN Display(Output)
|
28 | """
|
29 | graphData = null
|
30 | it 'should produce a graph JSON object', ->
|
31 | graphData = parser.parse fbpData
|
32 | chai.expect(graphData).to.be.an 'object'
|
33 | describe 'the generated graph', ->
|
34 | it 'should contain two nodes', ->
|
35 | chai.expect(graphData.processes).to.eql
|
36 | Read:
|
37 | component: 'ReadFile'
|
38 | Display:
|
39 | component: 'Output'
|
40 | it 'should contain an edge and an IIP', ->
|
41 | chai.expect(graphData.connections).to.be.an 'array'
|
42 | chai.expect(graphData.connections.length).to.equal 2
|
43 | it 'should contain no exports', ->
|
44 | chai.expect(graphData.exports).to.be.an 'undefined'
|
45 | chai.expect(graphData.inports).to.be.an 'undefined'
|
46 | chai.expect(graphData.outports).to.be.an 'undefined'
|
47 |
|
48 | describe 'with a more complex FBP string', ->
|
49 | fbpData = """
|
50 | '8003' -> LISTEN WebServer(HTTP/Server) REQUEST -> IN Profiler(HTTP/Profiler) OUT -> IN Authentication(HTTP/BasicAuth)
|
51 | Authentication() OUT -> IN GreetUser(HelloController) OUT -> IN WriteResponse(HTTP/WriteResponse) OUT -> IN Send(HTTP/SendResponse)
|
52 | 'hello.jade' -> SOURCE ReadTemplate(ReadFile) OUT -> TEMPLATE Render(Template)
|
53 | GreetUser() DATA -> OPTIONS Render() OUT -> STRING WriteResponse()
|
54 | """
|
55 | graphData = null
|
56 | it 'should produce a graph JSON object', ->
|
57 | graphData = parser.parse fbpData
|
58 | chai.expect(graphData).to.be.an 'object'
|
59 | describe 'the generated graph', ->
|
60 | it 'should contain eight nodes', ->
|
61 | chai.expect(graphData.processes).to.be.an 'object'
|
62 | chai.expect(graphData.processes).to.have.keys [
|
63 | 'WebServer'
|
64 | 'Profiler'
|
65 | 'Authentication'
|
66 | 'GreetUser'
|
67 | 'WriteResponse'
|
68 | 'Send'
|
69 | 'ReadTemplate'
|
70 | 'Render'
|
71 | ]
|
72 | it 'should contain ten edges and IIPs', ->
|
73 | chai.expect(graphData.connections).to.be.an 'array'
|
74 | chai.expect(graphData.connections.length).to.equal 10
|
75 | it 'should contain no exports', ->
|
76 | chai.expect(graphData.exports).to.be.an 'undefined'
|
77 |
|
78 | describe 'with FBP string containing an IIP with whitespace', ->
|
79 | fbpData = """
|
80 | 'foo Bar BAZ' -> IN Display(Output)
|
81 | """
|
82 | graphData = null
|
83 | it 'should produce a graph JSON object', ->
|
84 | graphData = parser.parse fbpData
|
85 | chai.expect(graphData).to.be.an 'object'
|
86 | describe 'the generated graph', ->
|
87 | it 'should contain a node', ->
|
88 | chai.expect(graphData.processes).to.eql
|
89 | Display:
|
90 | component: 'Output'
|
91 | it 'should contain an IIP', ->
|
92 | chai.expect(graphData.connections).to.be.an 'array'
|
93 | chai.expect(graphData.connections.length).to.equal 1
|
94 | chai.expect(graphData.connections[0].data).to.equal 'foo Bar BAZ'
|
95 | it 'should contain no exports', ->
|
96 | chai.expect(graphData.exports).to.be.an 'undefined'
|
97 | chai.expect(graphData.inports).to.be.an 'undefined'
|
98 | chai.expect(graphData.outports).to.be.an 'undefined'
|
99 |
|
100 | describe 'with FBP string containing an empty IIP string', ->
|
101 | fbpData = """
|
102 | '' -> IN Display(Output)
|
103 | """
|
104 | graphData = null
|
105 | it 'should produce a graph JSON object', ->
|
106 | graphData = parser.parse fbpData
|
107 | chai.expect(graphData).to.be.an 'object'
|
108 | describe 'the generated graph', ->
|
109 | it 'should contain a node', ->
|
110 | chai.expect(graphData.processes).to.eql
|
111 | Display:
|
112 | component: 'Output'
|
113 | it 'should contain an IIP', ->
|
114 | chai.expect(graphData.connections).to.be.an 'array'
|
115 | chai.expect(graphData.connections.length).to.equal 1
|
116 | chai.expect(graphData.connections[0].data).to.equal ''
|
117 | it 'should contain no exports', ->
|
118 | chai.expect(graphData.exports).to.be.an 'undefined'
|
119 | chai.expect(graphData.inports).to.be.an 'undefined'
|
120 | chai.expect(graphData.outports).to.be.an 'undefined'
|
121 |
|
122 | describe 'with FBP string containing comments', ->
|
123 | fbpData = """
|
124 | # Do stuff
|
125 | 'foo bar' -> IN Display(Output) # Here we show the string
|
126 | """
|
127 | graphData = null
|
128 | it 'should produce a graph JSON object', ->
|
129 | graphData = parser.parse fbpData
|
130 | chai.expect(graphData).to.be.an 'object'
|
131 | describe 'the generated graph', ->
|
132 | it 'should contain a node', ->
|
133 | chai.expect(graphData.processes).to.eql
|
134 | Display:
|
135 | component: 'Output'
|
136 | it 'should contain an IIP', ->
|
137 | chai.expect(graphData.connections).to.be.an 'array'
|
138 | chai.expect(graphData.connections.length).to.equal 1
|
139 | chai.expect(graphData.connections[0].data).to.equal 'foo bar'
|
140 | it 'should contain no exports', ->
|
141 | chai.expect(graphData.exports).to.be.an 'undefined'
|
142 | chai.expect(graphData.inports).to.be.an 'undefined'
|
143 | chai.expect(graphData.outports).to.be.an 'undefined'
|
144 |
|
145 | describe 'with FBP string containing URL as IIP', ->
|
146 | fbpData = """
|
147 | 'http://localhost:5984/default' -> URL Conn(couchdb/OpenDatabase)
|
148 | """
|
149 | graphData = null
|
150 | it 'should produce a graph JSON object', ->
|
151 | graphData = parser.parse fbpData
|
152 | chai.expect(graphData).to.be.an 'object'
|
153 | describe 'the generated graph', ->
|
154 | it 'should contain a node', ->
|
155 | chai.expect(graphData.processes).to.eql
|
156 | Conn:
|
157 | component: 'couchdb/OpenDatabase'
|
158 | it 'should contain an IIP', ->
|
159 | chai.expect(graphData.connections).to.be.an 'array'
|
160 | chai.expect(graphData.connections.length).to.equal 1
|
161 | chai.expect(graphData.connections[0].data).to.equal 'http://localhost:5984/default'
|
162 | it 'should contain no exports', ->
|
163 | chai.expect(graphData.exports).to.be.an 'undefined'
|
164 | chai.expect(graphData.inports).to.be.an 'undefined'
|
165 | chai.expect(graphData.outports).to.be.an 'undefined'
|
166 |
|
167 | describe 'with FBP string containing RegExp as IIP', ->
|
168 | fbpData = """
|
169 | '_id=(\d+\.\d+\.\d*)=http://iks-project.eu/%deliverable/$1' -> REGEXP MapDeliverableUri(MapPropertyValue)
|
170 | 'path=/_(?!(includes|layouts)' -> REGEXP MapDeliverableUri(MapPropertyValue)
|
171 | '@type=deliverable' -> PROPERTY SetDeliverableProps(SetProperty)
|
172 | '#foo' -> SELECTOR Get(dom/GetElement)
|
173 | 'Hi, {{ name }}' -> TEMPLATE Get
|
174 | """
|
175 | graphData = null
|
176 | it 'should produce a graph JSON object', ->
|
177 | graphData = parser.parse fbpData
|
178 | chai.expect(graphData).to.be.an 'object'
|
179 | describe 'the generated graph', ->
|
180 | it 'should contain two nodes', ->
|
181 | chai.expect(graphData.processes).to.eql
|
182 | MapDeliverableUri:
|
183 | component: 'MapPropertyValue'
|
184 | SetDeliverableProps:
|
185 | component: 'SetProperty'
|
186 | Get:
|
187 | component: 'dom/GetElement'
|
188 | it 'should contain IIPs', ->
|
189 | chai.expect(graphData.connections).to.be.an 'array'
|
190 | chai.expect(graphData.connections.length).to.equal 5
|
191 | chai.expect(graphData.connections[0].data).to.be.a 'string'
|
192 | it 'should contain no exports', ->
|
193 | chai.expect(graphData.exports).to.be.an 'undefined'
|
194 | chai.expect(graphData.inports).to.be.an 'undefined'
|
195 | chai.expect(graphData.outports).to.be.an 'undefined'
|
196 |
|
197 | describe 'with FBP string with inports and outports', ->
|
198 | fbpData = """
|
199 | INPORT=Read.IN:FILENAME
|
200 | INPORT=Display.OPTIONS:OPTIONS
|
201 | OUTPORT=Display.OUT:OUT
|
202 | Read(ReadFile) OUT -> IN Display(Output)
|
203 | """
|
204 | graphData = null
|
205 | it 'should produce a graph JSON object', ->
|
206 | graphData = parser.parse fbpData
|
207 | chai.expect(graphData).to.be.an 'object'
|
208 | describe 'the generated graph', ->
|
209 | it 'should contain two nodes', ->
|
210 | chai.expect(graphData.processes).to.eql
|
211 | Read:
|
212 | component: 'ReadFile'
|
213 | Display:
|
214 | component: 'Output'
|
215 | it 'should contain no legacy exports', ->
|
216 | chai.expect(graphData.exports).to.be.an 'undefined'
|
217 | it 'should contain a single connection', ->
|
218 | chai.expect(graphData.connections).to.be.an 'array'
|
219 | chai.expect(graphData.connections.length).to.equal 1
|
220 | chai.expect(graphData.connections[0]).to.eql
|
221 | src:
|
222 | process: 'Read'
|
223 | port: 'out'
|
224 | tgt:
|
225 | process: 'Display'
|
226 | port: 'in'
|
227 | it 'should contain two inports', ->
|
228 | chai.expect(graphData.inports).to.be.an 'object'
|
229 | chai.expect(graphData.inports.filename).to.eql
|
230 | process: 'Read'
|
231 | port: 'in'
|
232 | chai.expect(graphData.inports.options).to.eql
|
233 | process: 'Display'
|
234 | port: 'options'
|
235 | it 'should contain an outport', ->
|
236 | chai.expect(graphData.outports).to.be.an 'object'
|
237 | chai.expect(graphData.outports.out).to.eql
|
238 | process: 'Display'
|
239 | port: 'out'
|
240 |
|
241 | describe 'with FBP string with legacy EXPORTs', ->
|
242 | fbpData = """
|
243 | EXPORT=READ.IN:FILENAME
|
244 | Read(ReadFile) OUT -> IN Display(Output)
|
245 | """
|
246 | graphData = null
|
247 | it 'should produce a graph JSON object', ->
|
248 | graphData = parser.parse fbpData
|
249 | chai.expect(graphData).to.be.an 'object'
|
250 | describe 'the generated graph', ->
|
251 | it 'should contain two nodes', ->
|
252 | chai.expect(graphData.processes).to.eql
|
253 | Read:
|
254 | component: 'ReadFile'
|
255 | Display:
|
256 | component: 'Output'
|
257 | it 'should contain a single connection', ->
|
258 | chai.expect(graphData.connections).to.be.an 'array'
|
259 | chai.expect(graphData.connections.length).to.equal 1
|
260 | chai.expect(graphData.connections[0]).to.eql
|
261 | src:
|
262 | process: 'Read'
|
263 | port: 'out'
|
264 | tgt:
|
265 | process: 'Display'
|
266 | port: 'in'
|
267 | it 'should contain an export', ->
|
268 | chai.expect(graphData.exports).to.be.an 'array'
|
269 | chai.expect(graphData.exports.length).to.equal 1
|
270 | chai.expect(graphData.exports[0]).to.eql
|
271 | private: 'read.in'
|
272 | public: 'filename'
|
273 |
|
274 | describe 'with FBP string containing node metadata', ->
|
275 | fbpData = """
|
276 | Read(ReadFile) OUT -> IN Display(Output:foo=bar)
|
277 |
|
278 | # And we drop the rest
|
279 | Display OUT -> IN Drop(Drop:foo=baz,baz=/foo/bar)
|
280 | """
|
281 | graphData = null
|
282 | it 'should produce a graph JSON object', ->
|
283 | graphData = parser.parse fbpData
|
284 | chai.expect(graphData).to.be.an 'object'
|
285 | it 'should contain nodes with named routes', ->
|
286 | chai.expect(graphData.processes).to.eql
|
287 | Read:
|
288 | component: 'ReadFile'
|
289 | Display:
|
290 | component: 'Output'
|
291 | metadata:
|
292 | foo: 'bar'
|
293 | Drop:
|
294 | component: 'Drop'
|
295 | metadata:
|
296 | foo: 'baz'
|
297 | baz: '/foo/bar'
|
298 | it 'should contain two edges', ->
|
299 | chai.expect(graphData.connections).to.be.an 'array'
|
300 | chai.expect(graphData.connections.length).to.equal 2
|
301 | it 'should contain no exports', ->
|
302 | chai.expect(graphData.exports).to.be.an 'undefined'
|
303 | chai.expect(graphData.inports).to.be.an 'undefined'
|
304 | chai.expect(graphData.outports).to.be.an 'undefined'
|
305 |
|
306 | describe 'with an invalid FBP string', ->
|
307 | fbpData = """
|
308 | 'foo' -> Display(Output)
|
309 | """
|
310 | it 'should fail with an Exception', ->
|
311 | chai.expect(-> parser.parse fbpData).to.throw Error
|
312 |
|
313 | describe 'with a component that contains dashes in name', ->
|
314 | fbpData = "'somefile' -> SOURCE Read(my-cool-component/ReadFile)"
|
315 | graphData = null
|
316 | it 'should produce a graph JSON object', ->
|
317 | graphData = parser.parse fbpData
|
318 | chai.expect(graphData).to.be.an 'object'
|
319 | describe 'the generated graph', ->
|
320 | it 'should contain one node', ->
|
321 | chai.expect(graphData.processes).to.eql
|
322 | Read:
|
323 | component: 'my-cool-component/ReadFile'
|
324 | it 'should contain an IIP', ->
|
325 | chai.expect(graphData.connections).to.be.an 'array'
|
326 | chai.expect(graphData.connections.length).to.equal 1
|
327 |
|
328 | describe 'with commas to separate statements', ->
|
329 | fbpData = "'Hello' -> IN Foo(Component), 'World' -> IN Bar(OtherComponent), Foo OUT -> DATA Bar"
|
330 | graphData = null
|
331 | it 'should produce a graph JSON object', ->
|
332 | graphData = parser.parse fbpData
|
333 | chai.expect(graphData).to.be.an 'object'
|
334 | describe 'the generated graph', ->
|
335 | it 'should contain two nodes', ->
|
336 | chai.expect(graphData.processes).to.eql
|
337 | Foo:
|
338 | component: 'Component'
|
339 | Bar:
|
340 | component: 'OtherComponent'
|
341 | it 'should contain two IIPs and one edge', ->
|
342 | chai.expect(graphData.connections).to.eql [
|
343 | data: 'Hello'
|
344 | tgt:
|
345 | process: 'Foo'
|
346 | port: 'in'
|
347 | ,
|
348 | data: 'World'
|
349 | tgt:
|
350 | process: 'Bar'
|
351 | port: 'in'
|
352 | ,
|
353 | src:
|
354 | process: 'Foo'
|
355 | port: 'out'
|
356 | tgt:
|
357 | process: 'Bar'
|
358 | port: 'data'
|
359 |
|
360 | ]
|
361 |
|
362 | describe 'with underscores and numbers in ports, nodes, and components', ->
|
363 | fbpData = "'Hello 09' -> IN_2 Foo_Node_42(Component_15)"
|
364 | graphData = null
|
365 | it 'should produce a graph JSON object', ->
|
366 | graphData = parser.parse fbpData
|
367 | chai.expect(graphData).to.be.an 'object'
|
368 | describe 'the generated graph', ->
|
369 | it 'should contain one node', ->
|
370 | chai.expect(graphData.processes).to.eql
|
371 | Foo_Node_42:
|
372 | component: 'Component_15'
|
373 | it 'should contain an IIP', ->
|
374 | chai.expect(graphData.connections).to.be.an 'array'
|
375 | chai.expect(graphData.connections.length).to.equal 1
|
376 | chai.expect(graphData.connections[0]).to.eql
|
377 | data: 'Hello 09'
|
378 | tgt:
|
379 | process: 'Foo_Node_42'
|
380 | port: 'in_2'
|