lib/core/stream: LineIterator use CachedIterator
[nit.git] / lib / markdown2 / tests / commonmark_gen.nit
1 # This file is part of NIT ( http://www.nitlanguage.org ).
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 # http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14
15 # Generate Nitunit tests from commonmark specification.
16 #
17 # See the full specification and the test cases at <http://commonmark.org/>.
18 #
19 # Usage:
20 #
21 # ~~~sh
22 # commonmark_gen <commonmark_tests.json> <output directory>
23 # ~~~
24 module commonmark_gen
25
26 import json
27 import json::static
28 import template
29
30 # Generate the test cases from the JSON testfile.
31 class TestGenerator
32
33 # Input file in containing the tests in JSON format
34 var json_file: String
35
36 # Output directory where the Nitunit files will be generated
37 var output_dir: String
38
39 # Ignored tests
40 #
41 # We ignore some tests for two reasons:
42 # * because `nitmd` does not fully support UTF-8
43 # * because somes tests are wrong
44 var ignored_tests: Array[Int] do
45 var ignored = new Array[Int]
46 ignored.add_all([171, 304, 305, 306, 311, 312, 313, 477, 514]) # utf-8 tests
47 ignored.add_all([275, 276]) # spec is wrong compared to reference implementation
48 return ignored
49 end
50
51 # Load the tests files from the JSON input
52 fun load_tests: Map[String, Array[TestCase]] do
53 var json = json_file.to_path.read_all.parse_json
54 var tests = new HashMap[String, Array[TestCase]]
55
56 for obj in json.as(JsonArray) do
57 if not obj isa JsonObject then continue
58
59 var number = obj["example"].as(Int)
60 if ignored_tests.has(number) then continue
61
62 var name = "test{number}"
63
64 var section = obj["section"].as(String)
65 if not tests.has_key(section) then
66 tests[section] = new Array[TestCase]
67 end
68
69 var markdown = obj["markdown"].as(String)
70 markdown = markdown.replace("\\", "\\\\")
71 markdown = markdown.replace("\n", "\\n")
72 markdown = markdown.replace("\t", "\\t")
73
74 # fix missing chars in some tests
75 if number == 162 then
76 markdown = markdown.replace("my url", "my%20url")
77 else if number == 467 then
78 markdown = markdown.replace("my uri", "my%20uri")
79 end
80
81 var html = obj["html"].as(String)
82 html = html.replace("\\", "\\\\")
83 html = html.replace("\n", "\\n")
84 html = html.replace("\t", "\\t")
85
86 tests[section].add(new TestCase(name, markdown, html))
87 end
88
89 return tests
90 end
91
92 # Generate the Nitunit test files
93 fun gen_tests do
94 var tests = load_tests
95
96 for section, test_cases in tests do
97 var test_file = new TestFile("test_commonmark_{strip_module_name(section)}")
98 var test_class = new TestClass("TestCommonmark{strip_class_name(section)}")
99 test_class.test_cases.add_all test_cases
100 test_file.test_classes.add test_class
101 test_file.save(output_dir)
102 end
103 end
104
105 # Strip module name
106 #
107 # Used to create a Nitunit module name from a CommonMark section title.
108 fun strip_module_name(name: String): String do
109 var b = new FlatBuffer
110 for c in name do
111 if c == ' ' then
112 b.add '_'
113 else
114 if not c.is_letter and
115 not c.is_digit and
116 not allowed_id_chars.has(c) then continue
117 b.add c.to_lower
118 end
119 end
120 return b.to_s
121 end
122
123 # Strip class name
124 #
125 # Used to create a Nitunit test class name from a CommonMark section title.
126 fun strip_class_name(name: String): String do
127 var b = new FlatBuffer
128 var was_space = false
129 for c in name do
130 if c == ' ' then
131 was_space = true
132 else
133 if not c.is_letter and
134 not c.is_digit and
135 not allowed_id_chars.has(c) then continue
136 if was_space then
137 b.add c.to_upper
138 was_space = false
139 else
140 b.add c
141 end
142 end
143 end
144 return b.to_s
145 end
146
147 private var allowed_id_chars: Array[Char] = ['-', '_', ':', '.']
148 end
149
150 # A Nitunit test file
151 class TestFile
152
153 # Test module name
154 var test_file_name: String
155
156 # Test classes in this module
157 var test_classes = new Array[TestClass]
158
159 # Copyright header and module declaration
160 fun header: String do
161 return """
162 # This file is part of NIT ( http://www.nitlanguage.org ).
163 #
164 # Licensed under the Apache License, Version 2.0 (the "License");
165 # you may not use this file except in compliance with the License.
166 # You may obtain a copy of the License at
167 #
168 # http://www.apache.org/licenses/LICENSE-2.0
169 #
170 # Unless required by applicable law or agreed to in writing, software
171 # distributed under the License is distributed on an "AS IS" BASIS,
172 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
173 # See the License for the specific language governing permissions and
174 # limitations under the License.
175
176 module {{{test_file_name}}} is test
177
178 import test_markdown
179 """
180 end
181
182 # Render the test module as a Nit string
183 fun render: String do
184 var tpl = new Template
185 tpl.add header
186 for test_class in test_classes do
187 tpl.add test_class.render
188 end
189 return tpl.write_to_string
190 end
191
192 # Save the test module in `directory
193 fun save(directory: String) do
194 render.write_to_file(directory / "{test_file_name}.nit")
195 end
196 end
197
198 # A Nitunit test class
199 class TestClass
200
201 # Test class name
202 var test_class_name: String
203
204 # Test cases in this test class
205 var test_cases = new Array[TestCase]
206
207 # Render the test class as a Nit string
208 fun render: String do
209 var tpl = new Template
210 tpl.addn "\nclass {test_class_name}"
211 tpl.addn "\tsuper TestMarkdownHtml"
212 tpl.addn "\ttest"
213 for test_case in test_cases do
214 tpl.add test_case.render
215 end
216 tpl.addn "end"
217 return tpl.write_to_string
218 end
219 end
220
221 # A Nitunit test case
222 class TestCase
223
224 # Test method name
225 var test_name: String
226
227 # Markdown input
228 var markdown: String
229
230 # Expected html output
231 var html: String
232
233 # Render the test case as a Nit string
234 fun render: String do
235 var tpl = new Template
236 tpl.addn "\n\tfun {test_name} is test do"
237 tpl.addn "\t\tvar md = \"\"\"{markdown}\"\"\""
238 tpl.addn "\t\tvar html = \"\"\"{html}\"\"\""
239 tpl.addn "\t\tassert md_to_html(md) == html"
240 tpl.addn "\tend"
241 return tpl.write_to_string
242 end
243 end
244
245 if args.length != 2 then
246 print "Usage: commonmark_gen <tests.json> <output_dir>"
247 exit 1
248 end
249
250 var gen = new TestGenerator(args.first, args.last)
251 gen.gen_tests