codemodels-html 0.1.0-java

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,272 @@
1
+ require 'jars/jericho-html-3.3.jar'
2
+ require 'codemodels'
3
+ require 'codemodels/html/monkey_patching'
4
+
5
+ module CodeModels
6
+ module Html
7
+
8
+ class TextBlock
9
+ attr_accessor :source
10
+ attr_accessor :value
11
+
12
+ def begin_point=(data)
13
+ @source = SourceInfo.new unless @source
14
+ @source.begin_point= data
15
+ end
16
+
17
+ def end_point=(data)
18
+ @source = SourceInfo.new unless @source
19
+ @source.end_point= data
20
+ end
21
+ end
22
+
23
+ class Java::NetHtmlparserJericho::Element
24
+
25
+ def text_blocks(code)
26
+ blocks = []
27
+ break_content(self,code).each do |s,e|
28
+ text = code[s,e-s]
29
+ unless text==nil or text.strip.empty?
30
+ #puts "<<<#{text}>>>"
31
+ block = TextBlock.new
32
+ block.value = text
33
+ block.source = SourceInfo.new
34
+ block.source.position = SourcePosition.from_code_indexes(code,s,e-1)
35
+
36
+ blocks << block
37
+ end
38
+ end
39
+ blocks
40
+ end
41
+
42
+ private
43
+
44
+ def break_content(node,code)
45
+ text_inside = code[(node.begin)...(node.end)]
46
+ #puts "Text inside #{node.name} ^#{text_inside}^ It has child elements #{node.child_elements}"
47
+ i = text_inside.first_index('>')
48
+ raise "No '>' found in node #{node}, text inside: '#{text_inside}'" unless i
49
+ #puts "Index i: #{i}"
50
+ raise "No Fixnum" unless node.begin.is_a?(Fixnum)
51
+ raise "No Fixnum" unless i.is_a?(Fixnum)
52
+ start_index = node.begin+i+1
53
+ li = text_inside.last_index('<')
54
+ #puts "Index li: #{li}"
55
+ end_index = node.begin+li
56
+ #puts "Indexes #{start_index} #{end_index}"
57
+ #puts "Content of #{node.name} ^#{code[start_index,end_index-start_index]}^"
58
+
59
+ # no content
60
+ return [] if start_index==end_index
61
+
62
+ if node.child_elements.count==0
63
+ return [[start_index,end_index]]
64
+ else
65
+ segments = []
66
+ # before the first
67
+ segments << [start_index,node.child_elements.first.begin]
68
+ # between children
69
+ for i in 0...(node.child_elements.count-1)
70
+ s = node.child_elements[i].end
71
+ e = node.child_elements[i+1].begin
72
+ segments << [s,e]
73
+ end
74
+ # after the last
75
+ i_last = node.child_elements.size-1
76
+ last_child = node.child_elements[i_last]
77
+ segments << [last_child.end,end_index]
78
+ end
79
+ segments
80
+ end
81
+
82
+ end
83
+
84
+ class Parser < CodeModels::Parser
85
+
86
+ def initialize
87
+ @embedded_parsers = Hash.new do |h,k|
88
+ h[k] = []
89
+ end
90
+ end
91
+
92
+ def parse_file(path)
93
+ code = IO.read(path)
94
+ parse_artifact(FileArtifact.new(path,code))
95
+ end
96
+
97
+ def raw_node_tree(code)
98
+ Java::net.htmlparser.jericho.Config.IsHTMLEmptyElementTagRecognised = true
99
+ xhtml = Java::net.htmlparser.jericho.Config::CompatibilityMode::XHTML
100
+ Java::net.htmlparser.jericho.Config.CurrentCompatibilityMode = xhtml
101
+ reader = java.io.StringReader.new code
102
+ source = Java::net.htmlparser.jericho.Source.new reader
103
+ source
104
+ end
105
+
106
+ def parse_code(code)
107
+ parse_artifact(FileArtifact.new('<code>',code))
108
+ end
109
+
110
+ def parse_artifact(artifact)
111
+ source = raw_node_tree(artifact.code)
112
+ node_to_model(source,artifact.code,artifact)
113
+ end
114
+
115
+ # It operates on original node, not on the model obtained because
116
+ # it could have less information. For example in parsing scripts I need the
117
+ # raw content
118
+ def register_embedded_parser(node_class,embedded_parser,&selector)
119
+ @embedded_parsers[node_class] << {embedded_parser: embedded_parser, selector: selector}
120
+ end
121
+
122
+ def self.node_content(node,code)
123
+ pos = node_content_pos(node,code)
124
+ code[pos[0]..pos[1]]
125
+ end
126
+
127
+ def self.node_content_pos(node,code)
128
+ text_inside = code[(node.begin)...(node.end)]
129
+ i = text_inside.first_index('>')
130
+ start_index = node.begin+i+1
131
+ li = text_inside.last_index('<')
132
+ end_index = node.begin+li-1
133
+ raise "problem" if start_index>end_index
134
+ #content = code[start_index,end_index-start_index]
135
+ [start_index,end_index]
136
+ end
137
+
138
+ private
139
+
140
+ def add_source_info(node,model,code,artifact)
141
+ return if model==nil
142
+ model.language = LANGUAGE
143
+ model.source = CodeModels::SourceInfo.new
144
+ model.source.artifact = artifact
145
+ model.source.position = SourcePosition.from_code_indexes(code,node.begin,node.end)
146
+ end
147
+
148
+ def analyze_content(model,node,code,artifact)
149
+ node.text_blocks(code).each do |tb|
150
+ raise "GOTCHA #{node.name} TEXT INSIDE '#{code[(node.begin)..(node.end)]}'" if (tb.value=='</head>')
151
+ t = Html::Text.new
152
+ t.value = tb.value
153
+
154
+ t.language = LANGUAGE
155
+ t.source = tb.source
156
+ t.source.artifact = artifact
157
+
158
+ model.addChildren(t)
159
+ end
160
+ end
161
+
162
+ def node_to_model(node,code,artifact)
163
+ if node.is_a? Java::NetHtmlparserJericho::Source
164
+ model = Html::HtmlDocument.new
165
+ translate_many(code,node,model,:children,node.child_elements,artifact)
166
+ model
167
+ elsif node.is_a? Java::NetHtmlparserJericho::Element
168
+ if node.name=='!doctype'
169
+ model = Html::DTD.new
170
+ # I am naughty... and waiting for the Jericho parser to fix
171
+ # how they parse doctypes
172
+ model.name = 'html'
173
+ model
174
+ elsif node.name=='script'
175
+ model = Html::Script.new
176
+ model.name = node.name
177
+ # something is obfuscating the attributes method... damn...
178
+ attributes_method = node.java_method(:getAttributes)
179
+ attributes = attributes_method.call
180
+ raise "Error, Attributes expected, instead it is '#{attributes.class}'. Node class #{node.class}" unless attributes.is_a?(Java::NetHtmlparserJericho::Attributes)
181
+ if attributes.get('type') && attributes.get('type').value=='text/ng-template'
182
+ content_pos = Parser.node_content_pos(node,code)
183
+ #raise "mismatch" unless content==embedded_artifact.code
184
+ embedded_artifact = EmbeddedArtifact.new
185
+ embedded_artifact.host_artifact = artifact
186
+ si = content_pos[0]
187
+ while code[si]==' '||code[si]=="\t"||code[si]=="\r"||code[si]=="\n"
188
+ si+=1
189
+ end
190
+ embedded_artifact.position_in_host = SourcePosition.from_code_indexes(code,si,content_pos[1])
191
+ script_doc = parse_artifact(embedded_artifact)
192
+ model.addForeign_asts script_doc
193
+ end
194
+ else
195
+ model = Html::Node.new
196
+ analyze_content(model,node,code,artifact)
197
+ model.name = node.name
198
+ translate_many(code,node,model,:children,node.child_elements,artifact)
199
+ end
200
+ translate_many(code,node,model,:attributes,artifact)
201
+ model
202
+ elsif node.is_a? Java::NetHtmlparserJericho::Attribute
203
+ model = Html::Attribute.new
204
+ model.name = node.name
205
+ model.value = node.value
206
+ model
207
+ else
208
+ raise "Unknown node class: #{node.class}"
209
+ end
210
+
211
+ add_source_info(node,model,code,artifact)
212
+ check_foreign_parser(node,code,model,artifact)
213
+ model
214
+ end
215
+
216
+ def check_foreign_parser(node,code,model,artifact)
217
+ @embedded_parsers[node.class].each do |ep|
218
+ selector = ep[:selector]
219
+ embedded_parser = ep[:embedded_parser]
220
+ embedded_position = selector.call(node,code)
221
+ if embedded_position
222
+ unless embedded_position.is_a?(Array)
223
+ embedded_position = [embedded_position]
224
+ end
225
+ embedded_position.each do |ep|
226
+ embedded_artifact = EmbeddedArtifact.new
227
+ embedded_artifact.host_artifact = artifact
228
+ embedded_artifact.position_in_host = ep
229
+ #puts "<<<#{embedded_code}>>> #{ep}"
230
+ begin
231
+ embedded_root = embedded_parser.parse_artifact(embedded_artifact)
232
+ rescue Exception => e
233
+ raise "Problem embedded in '#{node}' at #{model.source.position} parsing '#{embedded_artifact.code}', from position #{ep}: #{e.inspect}"
234
+ end
235
+ model.addForeign_asts(embedded_root)
236
+ end
237
+ end
238
+ end
239
+ end
240
+
241
+ def translate_many(code,node,model,dest,node_value=(node.send(dest)),artifact)
242
+ return unless node_value!=nil
243
+ #puts "Considering #{model.class}.#{dest} (#{node_value.class})"
244
+ node_value.each do |el|
245
+ #puts "\t* #{el.class}"
246
+ model_el = node_to_model(el,code,artifact)
247
+ model.send(:"add#{dest.to_s.proper_capitalize}", model_el) if model_el!=nil
248
+ end
249
+ end
250
+
251
+ end # class Parser
252
+
253
+ DefaultParser = Parser.new
254
+
255
+ def self.parse_artifact(artifact)
256
+ DefaultParser.parse_artifact(artifact)
257
+ end
258
+
259
+ def self.parse_code(code)
260
+ parse_file(code,'<code>')
261
+ end
262
+
263
+ def self.parse_file(code,filename)
264
+ parse_artifact(FileArtifact.new(filename,code))
265
+ end
266
+
267
+ def self.raw_node_tree(code)
268
+ DefaultParser.raw_node_tree(code)
269
+ end
270
+
271
+ end
272
+ end
@@ -0,0 +1,5 @@
1
+ module CodeModels
2
+ module Html
3
+ VERSION = "0.1.0"
4
+ end
5
+ end
@@ -0,0 +1,8 @@
1
+ require 'jars/jericho-html-3.3.jar'
2
+
3
+ require "codemodels/html/version"
4
+ require "codemodels/html/metamodel"
5
+ require "codemodels/html/parser"
6
+ require "codemodels/html/model_building"
7
+ require "codemodels/html/language"
8
+ require "codemodels/html/angular_embedding_rules"
Binary file
@@ -0,0 +1,67 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>AngularJS puzzle</title>
5
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
6
+ <script type="text/javascript" src="js/lib/angular/angular.js"></script>
7
+ <script type="text/javascript" src="js/puzzle/slidingPuzzle.js"></script>
8
+ <script type="text/javascript" src="js/puzzle/wordSearchPuzzle.js"></script>
9
+ <script type="text/javascript" src="js/app.js"></script>
10
+ <link rel="stylesheet" type="text/css" href="css/styles.css"/>
11
+ </head>
12
+ <body ng-app="puzzleApp">
13
+ <ul id="types">
14
+ <li ng-repeat="t in types" ng-class="{'selected': t.id == type}">
15
+ <a ng-href="#/{{t.id}}">{{t.title}}</a>
16
+ </li>
17
+ </ul>
18
+
19
+ <div ng-include="type"></div>
20
+
21
+ <a id="fork" href="https://github.com/pdanis/angular-puzzle" title="Fork me on GitHub"></a>
22
+ <a id="powered" href="http://angularjs.org" title="powered by AngularJS"><img src="http://www.angularjs.org/img/AngularJS-large.png"/></a>
23
+
24
+ <script type="text/ng-template" id="sliding-puzzle">
25
+ <fieldset id="sliding-simple">
26
+ <legend>Basic</legend>
27
+ <sliding-puzzle size="3x3" src="img/angular.png"></sliding-puzzle>
28
+ </fieldset><br/>
29
+
30
+ <fieldset id="sliding-advanced" ng-controller="slidingAdvancedCtrl">
31
+ <legend>Advanced</legend>
32
+ <div ng-repeat="puzzle in puzzles">
33
+ <h2>{{puzzle.title}}</h2>
34
+ <div class="src">
35
+ <input type="text" ng-model="puzzle.src"/>
36
+ </div>
37
+ <div class="status">
38
+ moves: <strong>{{puzzle.api.moves}}</strong><br/>
39
+ solved: <strong>{{puzzle.api.isSolved()}}</strong>
40
+ </div>
41
+ <div class="size">
42
+ rows: <input type="text" ng-model="puzzle.rows" size="2"/>
43
+ cols: <input type="text" ng-model="puzzle.cols" size="2"/><br/>
44
+ <button ng-click="puzzle.api.shuffle()">shuffle</button>
45
+ <button ng-click="puzzle.api.solve()">solve</button>
46
+ </div>
47
+ <sliding-puzzle api="puzzle.api" size="{{puzzle.rows}}x{{puzzle.cols}}" src="{{puzzle.src}}"></sliding-puzzle>
48
+ </div>
49
+ </fieldset>
50
+ </script>
51
+
52
+ <script type="text/ng-template" id="word-search-puzzle">
53
+ <div id="word-search" ng-controller="wordSearchCtrl">
54
+ <ul class="words">
55
+ <li ng-repeat="word in puzzle.words" ng-class="{'found': word.found}">
56
+ {{word.name}}
57
+ </li>
58
+ </ul>
59
+ <word-search-puzzle matrix="matrix" words="words" api="puzzle"></word-search-puzzle>
60
+ <div class="status">
61
+ <button ng-click="puzzle.solve()" ng-show="!puzzle.solved" class="solve">solve</button>
62
+ <strong ng-show="puzzle.solved" ng-show="puzzle.solved">Solved!</strong>
63
+ </div>
64
+ </div>
65
+ </script>
66
+ </body>
67
+ </html>
@@ -0,0 +1,67 @@
1
+ require 'test_helper'
2
+
3
+ class TestBasicInfo < Test::Unit::TestCase
4
+
5
+ include TestHelper
6
+ include CodeModels
7
+ include CodeModels::Html
8
+
9
+ def test_source_line
10
+ code = %q{<html>
11
+ <body>
12
+ <p>ciao
13
+ come
14
+ stai?</p>
15
+ <p>io bene</p>
16
+ <div><p>
17
+ <span></span>
18
+ </p></div>
19
+ </body>
20
+ </html>}
21
+ r = Html.parse_code(code)
22
+ assert_class HtmlDocument, r
23
+ span = nil
24
+ r.traverse {|n| span = n if n.is_a?(Node) && n.name=='span'}
25
+ assert_not_nil span
26
+ assert_equal 8,span.source.position.begin_point.line
27
+ assert_class Node, span.eContainer
28
+ assert_equal 'p',span.eContainer.name
29
+ assert_equal 7,span.eContainer.source.position.begin_point.line # p
30
+ assert_equal 'div',span.eContainer.eContainer.name
31
+ assert_equal 7,span.eContainer.eContainer.source.position.begin_point.line # div
32
+ assert_equal 'body',span.eContainer.eContainer.eContainer.name
33
+ assert_equal 2,span.eContainer.eContainer.eContainer.source.position.begin_point.line # body
34
+ end
35
+
36
+ def test_source_line_of_text_elements
37
+ code = %q{<html>
38
+ <body>
39
+ <p>ciao
40
+ come
41
+ stai?</p>
42
+ <p>io bene</p>
43
+ <div><p>
44
+ <span></span>
45
+ </p></div>
46
+ </body>
47
+ </html>}
48
+ r = Html.parse_code(code)
49
+ assert_class HtmlDocument, r
50
+ body = nil
51
+ r.traverse {|n| body = n if n.is_a?(Node) && n.name=='body'}
52
+ assert_not_nil body
53
+ first_p = body.all_children[0]
54
+ first_p_text = first_p.all_children[0]
55
+ assert_class Text,first_p_text
56
+ assert_equal 3,first_p_text.source.position.begin_point.line
57
+ assert_equal 5,first_p_text.source.position.end_point.line
58
+ end
59
+
60
+ def test_artifact_final_host_is_set_correctly_for_all
61
+ r = AngularJs.parser_considering_angular_embedded_code.parse_file('test/data/puzzle.html')
62
+ r.traverse(:also_foreign) do |n|
63
+ assert_equal 'test/data/puzzle.html',n.source.artifact.final_host.filename, "Node with wrong final_host: #{n}"
64
+ end
65
+ end
66
+
67
+ end
@@ -0,0 +1,79 @@
1
+ require 'test_helper'
2
+
3
+ class TestBasicParsing < Test::Unit::TestCase
4
+
5
+ include TestHelper
6
+ include CodeModels
7
+ include CodeModels::Html
8
+
9
+ def test_basic_document
10
+ code = "<html></html>"
11
+ r = Html.parse_code(code)
12
+ assert_class HtmlDocument, r
13
+ assert_equal 1, r.children.count
14
+ assert_class Node, r.children[0]
15
+ assert_equal 'html', r.children[0].name
16
+ end
17
+
18
+ def test_basic_attributes
19
+ code = "<html id='ciao'></html>"
20
+ r = Html.parse_code(code)
21
+ html = r.children[0]
22
+ assert_equal 1, html.attributes.count
23
+ assert_equal "id", html.attributes[0].name
24
+ assert_equal "ciao", html.attributes[0].value
25
+ end
26
+
27
+ def test_basic_text
28
+ code = "<html>ciao</html>"
29
+ r = Html.parse_code(code)
30
+ html = r.children[0]
31
+ assert_equal 1, html.children.count
32
+ assert_class Text, html.children[0]
33
+ assert_equal 'ciao', html.children[0].value
34
+ end
35
+
36
+ def test_basic_dtd
37
+ code = "<!DOCTYPE html>"
38
+ r = Html.parse_code(code)
39
+ dtd = r.children[0]
40
+ assert_class DTD, dtd
41
+ assert_equal 'html', dtd.name
42
+ end
43
+
44
+ def test_no_text_blocks
45
+ code = "<head><script type='text/ng-template' id='sliding-puzzle'>\n<a/>\n</script></head>"
46
+ r = Html.raw_node_tree(code)
47
+ assert_equal 0,r.child_elements[0].text_blocks(code).count
48
+ end
49
+
50
+ def test_parse_scripts
51
+ code = "<html><head><script type='text/ng-template' id='sliding-puzzle'>\n<a/>\n</script></head></html>"
52
+ r = Html.parse_code(code)
53
+ script = r.children[0].children[0].children[0]
54
+ assert_class Script, script
55
+ assert_class HtmlDocument, script.foreign_asts[0]
56
+ assert_class Node, script.foreign_asts[0].children[0]
57
+ assert_equal 'a', script.foreign_asts[0].children[0].name
58
+ end
59
+
60
+ def test_node_content
61
+ code = "<html><head><script type='text/ng-template' id='sliding-puzzle'>\n<a/>\n</script></head></html>"
62
+ r = Html.raw_node_tree(code)
63
+ script = r.child_elements[0].child_elements[0].child_elements[0]
64
+ assert_equal "<head><script type='text/ng-template' id='sliding-puzzle'>\n<a/>\n</script></head>",Parser.node_content(r,code)
65
+ assert_equal "\n<a/>\n",Parser.node_content(script,code)
66
+ end
67
+
68
+ def test_text_blocks
69
+ code = "<html><head><div type='text/ng-template' id='sliding-puzzle'>ciao<a/>come</div></head></html>"
70
+ r = Html.raw_node_tree(code)
71
+ assert_equal 0,r.child_elements[0].text_blocks(code).count
72
+ assert_equal 0,r.child_elements[0].child_elements[0].text_blocks(code).count
73
+ div = r.child_elements[0].child_elements[0].child_elements[0]
74
+ assert_equal 2,div.text_blocks(code).count
75
+ assert_equal "ciao",div.text_blocks(code)[0].value
76
+ assert_equal "come",div.text_blocks(code)[1].value
77
+ end
78
+
79
+ end
@@ -0,0 +1,74 @@
1
+ require 'simplecov'
2
+ SimpleCov.start do
3
+ add_filter "/test/"
4
+ end
5
+
6
+ require 'json'
7
+ require 'test/unit'
8
+ require 'codemodels'
9
+ require 'codemodels/html'
10
+
11
+ module TestHelper
12
+
13
+ include CodeModels
14
+
15
+ def assert_metamodel(name,attrs,refs)
16
+ assert Html.const_defined?(name), "Metaclass '#{name}' not found"
17
+ c = Html.const_get name
18
+
19
+ assert_all_attrs attrs, c
20
+ assert_all_refs refs, c
21
+ c
22
+ end
23
+
24
+ def assert_class(expected_class,node)
25
+ assert node.class==expected_class, "Node expected to have class #{expected_class} instead it has class #{node.class}"
26
+ end
27
+
28
+ def relative_path(path)
29
+ File.join(File.dirname(__FILE__),path)
30
+ end
31
+
32
+ def assert_all_attrs(expected,c)
33
+ actual = c.ecore.eAllAttributes
34
+ assert_equal expected.count,actual.count,"Expected #{expected.count} attrs, found #{actual.count}. They are #{actual.name}"
35
+ expected.each do |e|
36
+ assert actual.find {|a| a.name==e}, "Attribute #{e} not found"
37
+ end
38
+ end
39
+
40
+ def assert_all_refs(expected,c)
41
+ actual = c.ecore.eAllReferences
42
+ assert_equal expected.count,actual.count,"Expected #{expected.count} refs, found #{actual.count}. They are #{actual.name}"
43
+ expected.each do |e|
44
+ assert actual.find {|a| a.name==e}, "Reference #{e} not found"
45
+ end
46
+ end
47
+
48
+ def assert_ref(c,name,type,many=false)
49
+ ref = c.ecore.eAllReferences.find {|r| r.name==name}
50
+ assert ref, "Reference '#{name}' not found"
51
+ assert_equal type.ecore.name,ref.eType.name
52
+ assert_equal many, ref.many
53
+ end
54
+
55
+ def assert_attr(c,name,type,many=false)
56
+ att = c.ecore.eAllAttributes.find {|a| a.name==name}
57
+ assert_equal type.name,att.eType.name
58
+ assert_equal many, att.many
59
+ end
60
+
61
+ def assert_map(exp,map)
62
+ assert_equal exp.count,map.count, "Expected to have keys: #{exp.keys}, it has #{map}"
63
+ exp.each do |k,v|
64
+ assert_equal exp[k],map[k], "Expected #{k} to have #{exp[k]} instances, it has #{map[k.to_s]}. Map: #{map}"
65
+ end
66
+ end
67
+
68
+ def assert_code_map_to(code,exp)
69
+ r = Html.parse_code(code)
70
+ map = r.values_map
71
+ assert_map(exp,map)
72
+ end
73
+
74
+ end
@@ -0,0 +1,37 @@
1
+ require 'test_helper'
2
+
3
+ class TestInfoExtraction < Test::Unit::TestCase
4
+
5
+ include TestHelper
6
+ include CodeModels
7
+
8
+ def test_snippet_1
9
+ code = %q{
10
+ <html>
11
+ <body>
12
+ <p>ciao!</p>
13
+ </body>
14
+ </html>
15
+ }
16
+ assert_code_map_to(code, {
17
+ 'html' =>1,
18
+ 'body' =>1,
19
+ 'p' => 1,
20
+ 'ciao!'=> 1
21
+ })
22
+ end
23
+
24
+ def test_no_extraneous_values
25
+ code = IO.read('test/data/puzzle.html')
26
+ r = Html::AngularJs.parser_considering_angular_embedded_code.parse_code(code)
27
+ r.traverse(:also_foreign) do |node|
28
+ node.collect_values_with_count.each do |value,count|
29
+ node_code = node.source.code
30
+ unless node_code.include?(value.to_s)
31
+ fail("Value '#{value}' expected in #{node}. Artifact: #{node.source.artifact}, abspos: #{node.source.position(:absolute)}, code: '#{node_code}'")
32
+ end
33
+ end
34
+ end
35
+ end
36
+
37
+ end
@@ -0,0 +1,20 @@
1
+ require 'test_helper'
2
+ require 'codemodels/js'
3
+
4
+ class TestParsingEmbeddedLanguages < Test::Unit::TestCase
5
+
6
+ include TestHelper
7
+ include CodeModels
8
+ include CodeModels::Html
9
+
10
+
11
+ def test_begin_index
12
+ code = "<sliding-puzzle api />"
13
+ assert_equal 0,code.first_index('<')
14
+ assert_equal 1,code.first_index('s')
15
+ assert_equal 8,code.first_index('-')
16
+ assert_equal 20,code.first_index('/')
17
+ assert_equal 21,code.first_index('>')
18
+ end
19
+
20
+ end
@@ -0,0 +1,54 @@
1
+ require 'test_helper'
2
+ require 'codemodels/js'
3
+
4
+ class TestParsingEmbeddedLanguages < Test::Unit::TestCase
5
+
6
+ include TestHelper
7
+ include CodeModels
8
+ include CodeModels::Html
9
+
10
+ def setup
11
+ @p = AngularJs.parser_considering_angular_embedded_code
12
+ end
13
+
14
+ def test_source_line
15
+ code =
16
+ %q{<html>
17
+ <body ng-app="puzzleApp">
18
+ <ul id="types">
19
+ <li ng-repeat="t in types" ng-class="{'selected': t.id == type}">
20
+ <a ng-href="#/{{t.id}}">{{t.title}}</a>
21
+ </li>
22
+ </ul>
23
+ </body>
24
+ </html>}
25
+
26
+ r = @p.parse_code(code)
27
+ li = r.all_children_deep.find {|n| n.is_a?(Node) && n.name=='li'}
28
+ assert_not_nil li
29
+ a = li.attributes.find {|a| a.name=='ng-repeat'}
30
+ assert_not_nil a
31
+ assert_equal 1,a.foreign_asts.count
32
+ assert_class CodeModels::Js::InInfixExpression,a.foreign_asts[0]
33
+ end
34
+
35
+ def test_multiple_angular_expressions_in_attr
36
+ code = %q{<sliding-puzzle api="puzzle.api" size="{{puzzle.rows}}x{{puzzle.cols}}" src="{{puzzle.src}}"></sliding-puzzle>}
37
+
38
+ r = @p.parse_code(code)
39
+ assert_class HtmlDocument,r
40
+ assert_class Node,r.children[0]
41
+ att_size = r.children[0].attributes.find {|a| a.name=='size'}
42
+ att_src = r.children[0].attributes.find {|a| a.name=='src'}
43
+ assert_equal 2,att_size.foreign_asts.count
44
+ assert_equal 1,att_src.foreign_asts.count
45
+ end
46
+
47
+ def test_parsing_empty_attr
48
+ code = %q{<sliding-puzzle api />}
49
+
50
+ r = @p.parse_code(code)
51
+ # it does not crash? It is ok!
52
+ end
53
+
54
+ end