mathml 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,780 @@
1
+ # Test for math_ml.rb
2
+ #
3
+ # Copyright (C) 2005, KURODA Hiraku <hiraku@hinet.mydns.jp>
4
+ # You can redistribute it and/or modify it under GPL2.
5
+
6
+ require "test/unit"
7
+ require "math_ml"
8
+ require "math_ml_test_util"
9
+
10
+ class TC_Mathml_rb < Test::Unit::TestCase
11
+ def test_double_require
12
+ assert(require("lib/math_ml"))
13
+ assert_nothing_raised do
14
+ MathML::LaTeX::Parser.new
15
+ end
16
+ end
17
+ end
18
+
19
+ class TC_MathML_Element < Test::Unit::TestCase
20
+ include Util4TC_MathML
21
+ include MathML
22
+
23
+ def test_display_style
24
+ e = Element.new("test")
25
+ assert(!e.display_style)
26
+
27
+ e = Element.new("test").as_display_style
28
+ assert_equal(MathML::Element, e.class)
29
+ assert(e.display_style)
30
+ end
31
+
32
+ def test_pop
33
+ e = Element.new("super")
34
+ assert_equal(nil, e.pop)
35
+
36
+ s = Element.new("sub")
37
+ e << s
38
+ assert_equal(s, e.pop)
39
+ assert_equal(nil, e.pop)
40
+
41
+ e << "text"
42
+ assert_equal(MathML.pcstring("text"), e.pop)
43
+ assert_equal(nil, e.pop)
44
+ end
45
+
46
+ def test_pcstring
47
+ assert_equal("&lt;&gt;&amp;&quot;&apos;", MathML.pcstring('<>&"\'').to_s)
48
+ assert_equal('<tag>&amp;"\'</tag>', MathML.pcstring('<tag>&amp;"\'</tag>', true).to_s)
49
+ end
50
+ end
51
+
52
+ class TC_MathML_LaTeX_Scanner < Test::Unit::TestCase
53
+ include MathML::LaTeX
54
+
55
+ def test_done
56
+ s = Scanner.new("0123")
57
+ s.pos = 2
58
+ assert_equal("01", s.done)
59
+ assert_equal("23", s.rest)
60
+ end
61
+
62
+ def test__scan
63
+ s = Scanner.new(" ")
64
+ assert_equal(" ", s._scan(/\s/))
65
+ assert_equal(1, s.pos)
66
+ end
67
+
68
+ def test__check
69
+ s = Scanner.new(" ")
70
+ assert_equal(" ", s._check(/\s/))
71
+ assert_equal(0, s.pos)
72
+ end
73
+
74
+ def test_scan
75
+ s = Scanner.new(" a")
76
+ assert_equal("a", s.scan(/a/))
77
+ assert_equal(2, s.pos)
78
+
79
+ s.reset
80
+ assert_equal(nil, s.scan(/b/))
81
+ assert_equal(0, s.pos)
82
+
83
+ s = Scanner.new(" %comment\na")
84
+ assert_equal("a", s.scan(/a/))
85
+ assert_equal(11, s.pos)
86
+
87
+ s.reset
88
+ assert_equal(nil, s.scan(/b/))
89
+ assert_equal(0, s.pos)
90
+ end
91
+
92
+ def test_check
93
+ s = Scanner.new(" a")
94
+ assert_equal("a", s.check(/a/))
95
+ assert_equal(0, s.pos)
96
+
97
+ s.reset
98
+ assert_equal(nil, s.check(/b/))
99
+ assert_equal(0, s.pos)
100
+ end
101
+
102
+ def test_eos
103
+ assert(Scanner.new("").eos?)
104
+ assert(Scanner.new(" ").eos?)
105
+ assert(Scanner.new(" %test\n%test").eos?)
106
+ assert(!Scanner.new(" a").eos?)
107
+ assert(!Scanner.new(" \\command").eos?)
108
+ end
109
+
110
+
111
+ def test_check_command
112
+ assert_equal(nil, Scanner.new("test").check_command)
113
+ s = Scanner.new(' \test')
114
+ assert_equal('\test', s.check_command)
115
+ assert_equal("test", s[1])
116
+ assert_equal('\test', Scanner.new(' \test next').check_command)
117
+ assert_equal('\test', Scanner.new(' \test_a').check_command)
118
+ end
119
+
120
+ def test_scan_command
121
+ assert_equal(nil, Scanner.new("test").scan_command)
122
+
123
+ s = Scanner.new(' \test')
124
+ assert_equal('\test', s.scan_command)
125
+ assert_equal("test", s[1])
126
+ assert_equal(6, s.pos)
127
+
128
+ s = Scanner.new(' \test rest')
129
+ assert_equal('\test', s.scan_command)
130
+ assert_equal(6, s.pos)
131
+
132
+ s = Scanner.new(' \test_a')
133
+ assert_equal('\test', s.scan_command)
134
+ assert_equal(6, s.pos)
135
+
136
+ s = Scanner.new(' \_test')
137
+ assert_equal('\_', s.check_command)
138
+ assert_equal('\_', s.scan_command)
139
+ assert_equal("test", s.rest)
140
+
141
+ end
142
+
143
+ def test_scan_block
144
+ assert_equal(nil, Scanner.new(" a").scan_block)
145
+ assert_equal(nil, Scanner.new(" a").check_block)
146
+
147
+ i = " {{}{}{{}{}}} "
148
+ e = "{#{i}}"
149
+ s = Scanner.new(" #{e} test")
150
+ assert_equal(e, s.check_block)
151
+ assert_equal(e, s.matched)
152
+ assert_equal(i, s[1])
153
+ assert_equal(e, s.scan_block)
154
+ assert_equal(e, s.matched)
155
+ assert_equal(i, s[1])
156
+ assert_equal(" test", s.rest)
157
+
158
+ assert_equal(nil, Scanner.new(' \command test').scan_block)
159
+ assert_equal(nil, Scanner.new(' \command test').check_block)
160
+
161
+ assert_equal(nil, Scanner.new("").scan_block)
162
+ assert_equal(nil, Scanner.new("").check_block)
163
+
164
+ assert_equal(nil, Scanner.new(" ").scan_block)
165
+ assert_equal(nil, Scanner.new(" ").check_block)
166
+
167
+ s = Scanner.new("{test")
168
+ e = assert_raises(BlockNotClosed){s.scan_block}
169
+ end
170
+
171
+ def test_scan_any
172
+ s0 = " %comment\n "
173
+ s1 = "{}"
174
+ s = Scanner.new(s0+s1)
175
+ assert_equal(s1, s.scan_any)
176
+ s.reset
177
+ assert_equal(s0+s1, s.scan_any(true))
178
+ assert_equal(s1, s.matched)
179
+
180
+ s1 = '\command'
181
+ s = Scanner.new(s0+s1)
182
+ assert_equal(s1, s.scan_any)
183
+ s.reset
184
+ assert_equal(s0+s1, s.scan_any(true))
185
+
186
+ s1 = 'a'
187
+ s = Scanner.new(s0+s1)
188
+ assert_equal(s1, s.scan_any)
189
+ s.reset
190
+ assert_equal(s0+s1, s.scan_any(true))
191
+
192
+ s = Scanner.new(" ")
193
+ assert_equal(nil, s.scan_any)
194
+ s.reset
195
+ assert_equal(" ", s.scan_any(true))
196
+
197
+ s = Scanner.new('\begin{env}test\end{env}')
198
+ assert_equal('\begin', s.scan_any)
199
+ end
200
+
201
+ def test_peek_command
202
+ assert_equal("test", Scanner.new(' \test').peek_command)
203
+ assert_equal(nil, Scanner.new("").peek_command)
204
+ assert_equal(nil, Scanner.new(" ").peek_command)
205
+ assert_equal(nil, Scanner.new(" a").peek_command)
206
+ end
207
+
208
+ def test_scan_option
209
+ s = Scanner.new(" []")
210
+ assert_equal("[]", s.scan_option)
211
+ assert_equal("", s[1])
212
+ assert_equal(3, s.pos)
213
+
214
+ s = Scanner.new(" [ opt ]")
215
+ assert_equal("[ opt ]", s.scan_option)
216
+ assert_equal(" opt ", s[1])
217
+ assert_equal(8, s.pos)
218
+
219
+ s = Scanner.new(" [[]]")
220
+ assert_equal("[[]", s.scan_option)
221
+ assert_equal("[", s[1])
222
+
223
+ s = Scanner.new(" [{[]}]")
224
+ assert_equal("[{[]}]", s.scan_option)
225
+ assert_equal("{[]}", s[1])
226
+
227
+ assert_raises(OptionNotClosed){Scanner.new("[").scan_option}
228
+ end
229
+
230
+ def test_check_option
231
+ s = Scanner.new(" []")
232
+ assert_equal("[]", s.check_option)
233
+ assert_equal("", s[1])
234
+ assert_equal(0, s.pos)
235
+
236
+ s = Scanner.new(" [ opt ]")
237
+ assert_equal("[ opt ]", s.check_option)
238
+ assert_equal(" opt ", s[1])
239
+ assert_equal(0, s.pos)
240
+
241
+ s = Scanner.new(" [[]]")
242
+ assert_equal("[[]", s.check_option)
243
+ assert_equal("[", s[1])
244
+
245
+ s = Scanner.new(" [{[]}]")
246
+ assert_equal("[{[]}]", s.check_option)
247
+ assert_equal("{[]}", s[1])
248
+
249
+ assert_raises(OptionNotClosed){Scanner.new("[").check_option}
250
+ end
251
+ end
252
+
253
+ class TC_MathML_LaTeX_Macro < Test::Unit::TestCase
254
+ include Util4TC_MathML
255
+ include MathML::LaTeX
256
+
257
+ def setup
258
+ @src = <<'EOS'
259
+ \newcommand{\newcom}{test}
260
+ \newcommand{\paramcom}[2]{param2 #2, param1 #1.}
261
+ \newcommand\ALPHA\alpha
262
+ \newcommand\BETA[1]\beta
263
+ \newcommand{\nothing}{}
264
+ \newenvironment{newenv}{begin_newenv}{end_newenv}
265
+ \newenvironment{paramenv}[2]{begin 1:#1, 2:#2}{end 2:#2 1:#1}
266
+ \newenvironment{nothing}{}{}
267
+ \newenvironment{separated environment}{sep}{env}
268
+ \newenvironment ENV
269
+ EOS
270
+ super
271
+ end
272
+
273
+ def test_parse
274
+ m = Macro.new
275
+ assert_nothing_raised{m.parse(@src)}
276
+
277
+ assert_parse_error("Need newcommand.", '\\newcommand{', "notcommand}{}"){m.parse('\newcommand{notcommand}{}')}
278
+ assert_parse_error("Syntax error.", '\newcommand{\separated', " command}{}"){m.parse('\newcommand{\separated command}{}')}
279
+ assert_parse_error("Need parameter.", '\newcommand{\nobody}', ""){m.parse('\newcommand{\nobody}')}
280
+ assert_parse_error("Parameter \# too large.", '\newcommand{\noparam}{#', "1}"){m.parse('\newcommand{\noparam}{#1}')}
281
+ assert_parse_error("Parameter \# too large.", '\newcommand{\overopt}[1]{#1#', "2}"){m.parse('\newcommand{\overopt}[1]{#1#2}')}
282
+ assert_parse_error("Need positive number.", '\newcommand{\strangeopt}[', "-1]"){m.parse('\newcommand{\strangeopt}[-1]')}
283
+ assert_parse_error("Need positive number.", '\newcommand{\strangeopt}[', "a]"){m.parse('\newcommand{\strangeopt}[a]')}
284
+
285
+ assert_parse_error("Syntax error.", '\newenvironment{', '\command}{}{}'){m.parse('\newenvironment{\command}{}{}')}
286
+ assert_parse_error("Need begin block.", '\newenvironment{nobegin}', ""){m.parse('\newenvironment{nobegin}')}
287
+ assert_parse_error("Need end block.", '\newenvironment{noend}{}', ""){m.parse('\newenvironment{noend}{}')}
288
+ assert_parse_error("Parameter \# too large.", '\newenvironment{noparam}{#', "1}{}"){m.parse('\newenvironment{noparam}{#1}{}')}
289
+ assert_parse_error("Parameter \# too large.", '\newenvironment{overparam}[1]{#1#', "2}{}"){m.parse('\newenvironment{overparam}[1]{#1#2}{}')}
290
+ assert_parse_error("Need positive number.", '\newenvironment{strangeparam}[', "-1]{}{}"){m.parse('\newenvironment{strangeparam}[-1]{}{}')}
291
+ assert_parse_error("Need positive number.", '\newenvironment{strangeparam}[', "a]{}{}"){m.parse('\newenvironment{strangeparam}[a]{}{}')}
292
+
293
+ assert_parse_error("Syntax error.", '\newcommand{\valid}{OK} ', '\invalid{\test}{NG}'){m.parse('\newcommand{\valid}{OK} \invalid{\test}{NG}')}
294
+ assert_parse_error("Syntax error.", '\newcommand{\valid}{OK} ', 'invalid{\test}{NG}'){m.parse('\newcommand{\valid}{OK} invalid{\test}{NG}')}
295
+
296
+ assert_parse_error("Option not closed.", '\newcommand{\newcom}', '[test'){m.parse('\newcommand{\newcom}[test')}
297
+ assert_parse_error("Option not closed.", '\newcommand{\newcom}[1]', '[test'){m.parse('\newcommand{\newcom}[1][test')}
298
+ assert_parse_error("Parameter \# too large.", '\newcommand{\newcom}[1][]{#1#', '2}'){m.parse('\newcommand{\newcom}[1][]{#1#2}')}
299
+ assert_parse_error("Option not closed.", '\newenvironment{newenv}[1]', '[test'){m.parse('\newenvironment{newenv}[1][test')}
300
+ assert_parse_error("Option not closed.", '\newenvironment{newenv}[1]', '[test'){m.parse('\newenvironment{newenv}[1][test')}
301
+
302
+ assert_parse_error("Block not closed.", '\newcommand', '{\newcom'){m.parse('\newcommand{\newcom')}
303
+ assert_parse_error("Block not closed.", '\newcommand{\newcom}', '{test1{test2}{test3'){m.parse('\newcommand{\newcom}{test1{test2}{test3')}
304
+
305
+ assert_parse_error("Parameter \# too large.", '\newenvironment{newenv}[1][]{#1 #', '2}'){m.parse('\newenvironment{newenv}[1][]{#1 #2}')}
306
+ end
307
+
308
+ def test_commands
309
+ m = Macro.new
310
+ m.parse(@src)
311
+
312
+ assert_equal(0, m.commands("newcom").num)
313
+ assert_equal(2, m.commands("paramcom").num)
314
+ assert_equal(nil, m.commands("no"))
315
+ end
316
+
317
+ def test_expand_command
318
+ m = Macro.new
319
+ m.parse(@src)
320
+
321
+ assert_equal(nil, m.expand_command("not coommand", []))
322
+
323
+ assert_equal("test", m.expand_command("newcom", []))
324
+ assert_equal("test", m.expand_command("newcom", ["dummy_param"]))
325
+ assert_equal("param2 2, param1 1.", m.expand_command("paramcom", ["1", "2"]))
326
+ assert_equal("param2 34, param1 12.", m.expand_command("paramcom", ["12", "34"]))
327
+ assert_parse_error("Need more parameter.", "", ""){m.expand_command("paramcom", ["12"])}
328
+ assert_parse_error("Need more parameter.", "", ""){m.expand_command("paramcom", [])}
329
+ end
330
+
331
+ def test_environments
332
+ m = Macro.new
333
+ m.parse(@src)
334
+
335
+ assert_equal(0, m.environments("newenv").num)
336
+ assert_equal(2, m.environments("paramenv").num)
337
+ assert_equal(nil, m.environments("not_env"))
338
+ assert_equal(0, m.environments("separated environment").num)
339
+ end
340
+
341
+ def test_expand_environment
342
+ m = Macro.new
343
+ m.parse(@src)
344
+
345
+ assert_equal(nil, m.expand_environment('notregistered', "dummy", []))
346
+ assert_equal(' begin_newenv body end_newenv ', m.expand_environment("newenv", "body", []))
347
+ assert_equal(' begin 1:1, 2:2 body end 2:2 1:1 ', m.expand_environment("paramenv", "body", ["1", "2"]))
348
+ assert_equal(' begin 1:12, 2:34 body end 2:34 1:12 ', m.expand_environment("paramenv", "body", ["12", "34"]))
349
+ assert_parse_error("Need more parameter.", "", ""){m.expand_environment("paramenv", "body", ["1"])}
350
+ assert_parse_error("Need more parameter.", "", ""){m.expand_environment("paramenv", "body", [])}
351
+ assert_equal(' body ', m.expand_environment("nothing", "body", []))
352
+ assert_equal(' sep body env ', m.expand_environment("separated environment", "body", []))
353
+ assert_equal(' N body V ', m.expand_environment("E", "body", []))
354
+ end
355
+
356
+ def test_expand_with_options
357
+
358
+ src = <<'EOS'
359
+ \newcommand{\opt}[1][x]{#1}
360
+ \newcommand{\optparam}[2][]{#1#2}
361
+ \newenvironment{newenv}[1][x]{s:#1}{e:#1}
362
+ \newenvironment{optenv}[2][]{s:#1}{e:#2}
363
+ EOS
364
+
365
+ m = Macro.new
366
+ m.parse(src)
367
+
368
+ assert_equal('x', m.expand_command("opt", []))
369
+ assert_equal('1', m.expand_command("opt", [], "1"))
370
+
371
+ assert_equal('1', m.expand_command("optparam", ["1"]))
372
+ assert_equal('21', m.expand_command("optparam", ["1"], "2"))
373
+
374
+ assert_equal(" s:x test e:x ", m.expand_environment("newenv", "test", []))
375
+ assert_equal(" s:1 test e:1 ", m.expand_environment("newenv", "test", [], "1"))
376
+
377
+ assert_equal(" s: test e:1 ", m.expand_environment("optenv", "test", ["1"]))
378
+ assert_equal(" s:2 test e:1 ", m.expand_environment("optenv", "test", ["1"], "2"))
379
+ end
380
+ end
381
+
382
+ class TC_MathML_LaTeX_Parser < Test::Unit::TestCase
383
+ include MathML::LaTeX
384
+ include Util4TC_MathML
385
+
386
+ ### Sub routines ###
387
+
388
+ def check_chr(stag, etag, str, print=false)
389
+ str.each_byte do |b|
390
+ assert_equal("#{stag}#{b.chr}#{etag}", smml(b.chr))
391
+ puts smml(b.chr) if print
392
+ end
393
+ end
394
+
395
+ def check_hash(stag, etag, hash, print=false)
396
+ hash.each do |k, v|
397
+ e = "#{stag}#{v}#{etag}"
398
+ s = smml(k)
399
+ assert_equal(e, s)
400
+ puts "#{k} => #{s}" if print
401
+ end
402
+ end
403
+
404
+ def check_entity(stag, etag, hash, print=false)
405
+ h = Hash.new
406
+ hash.each do |k, v|
407
+ h[k] = "&#{v};"
408
+ end
409
+ check_hash(stag, etag, h, print)
410
+ end
411
+
412
+ ### Tests ###
413
+
414
+ def test_nobody
415
+ p = Parser.new
416
+ assert_equal("<math display='inline' xmlns='http://www.w3.org/1998/Math/MathML' />", p.parse("").to_s)
417
+ assert_equal("<math display='block' xmlns='http://www.w3.org/1998/Math/MathML' />", p.parse("", true).to_s)
418
+ assert_equal("<math display='inline' xmlns='http://www.w3.org/1998/Math/MathML' />", p.parse("", false).to_s)
419
+ end
420
+
421
+ def test_ignore_space
422
+ assert_equal("<mrow><mi>a</mi></mrow>", smml("{ a }"))
423
+ end
424
+
425
+ def test_block
426
+ assert_parse_error("Block not closed.", "test {test} ", "{test"){smml("test {test} {test")}
427
+ end
428
+
429
+ def test_parse_error
430
+ src = 'a\hoge c'
431
+ e = assert_raises(ParseError){smml(src)}
432
+ assert_equal(["Undefined command.", "a", '\hoge c'], parse_error(e))
433
+
434
+ src = '\sqrt\sqrt1'
435
+ e = assert_raises(ParseError){smml(src)}
436
+ assert_equal(["Syntax error.", '\sqrt\sqrt', "1"], parse_error(e))
437
+
438
+ src = "a{b"
439
+ e = assert_raises(ParseError){smml(src)}
440
+ assert_equal(["Block not closed.", "a", "{b"], parse_error(e))
441
+ end
442
+
443
+ def test_numerics
444
+ assert_equal("<mn>1234567890</mn>", smml('1234567890'))
445
+ assert_equal("<mn>1.2</mn>", smml('1.2'))
446
+ assert_equal("<mn>1</mn><mo>.</mo>", smml('1.'))
447
+ assert_equal("<mn>.2</mn>", smml('.2'))
448
+ assert_equal("<mn>1.2</mn><mn>.3</mn>", smml('1.2.3'))
449
+ end
450
+
451
+ def test_alphabets
452
+ check_chr("<mi>", "</mi>", "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
453
+ end
454
+
455
+ def test_non_alphabet_command
456
+ assert_equal("<mspace width='0.167em' />", smml('\,'))
457
+ assert_equal("<mo>&DoubleVerticalBar;</mo>", smml('\|'))
458
+ end
459
+
460
+ def test_operators
461
+ check_chr("<mo>", "</mo>", ",.+-*=/()[]|;:!")
462
+ check_entity("<mo>", "</mo>", {"<"=>"lt", ">"=>"gt", '"'=>"quot", "'"=>"apos"})
463
+ check_hash("<mo>", "</mo>", {'\backslash'=>'\\', '\%'=>'%', '\{'=>'{', '\}'=>'}', '\$'=>'$', '\#'=>'#'})
464
+ end
465
+
466
+ def test_sqrt
467
+ assert_equal("<msqrt><mi>a</mi></msqrt>", smml('\sqrt a'))
468
+ assert_equal("<mroot><mn>3</mn><mn>2</mn></mroot>", smml('\sqrt[2]3'))
469
+ assert_equal("<mroot><mn>3</mn><mrow><mn>2</mn><mi>a</mi></mrow></mroot>", smml('\sqrt[2a]3'))
470
+ e = assert_raises(ParseError){smml('\sqrt[12')}
471
+ assert_equal(["Option not closed.", '\sqrt', "[12"], parse_error(e))
472
+ end
473
+
474
+ def test_subsup
475
+ assert_equal("<msubsup><mi>a</mi><mi>b</mi><mi>c</mi></msubsup>", smml("a_b^c"))
476
+ assert_equal("<msub><mi>a</mi><mi>b</mi></msub>", smml("a_b"))
477
+ assert_equal("<msup><mi>a</mi><mi>b</mi></msup>", smml("a^b"))
478
+ assert_equal("<msubsup><none /><mi>a</mi><mi>b</mi></msubsup>", smml("_a^b"))
479
+
480
+ e = assert_raises(ParseError){smml("a_b_c")}
481
+ assert_equal(["Double subscript.", "a_b", "_c"], parse_error(e))
482
+ e = assert_raises(ParseError){smml("a^b^c")}
483
+ assert_equal(["Double superscript.", "a^b", "^c"], parse_error(e))
484
+ e = assert_raises(ParseError){smml("a_")}
485
+ assert_equal(["Subscript not exist.", "a_", ""], parse_error(e))
486
+ e = assert_raises(ParseError){smml("a^")}
487
+ assert_equal(["Superscript not exist.", "a^", ""], parse_error(e))
488
+ end
489
+
490
+ def test_underover
491
+ assert_equal("<munderover><mo>&sum;</mo><mi>a</mi><mi>b</mi></munderover>", smml('\sum_a^b', true))
492
+ assert_equal("<msubsup><mo>&sum;</mo><mi>a</mi><mi>b</mi></msubsup>", smml('\sum_a^b'))
493
+ assert_equal("<munder><mo>&sum;</mo><mi>a</mi></munder>", smml('\sum_a', true))
494
+ assert_equal("<mover><mo>&sum;</mo><mi>a</mi></mover>", smml('\sum^a', true))
495
+ assert_equal("<msub><mo>&sum;</mo><mi>a</mi></msub>", smml('\sum_a'))
496
+ assert_equal("<msup><mo>&sum;</mo><mi>a</mi></msup>", smml('\sum^a'))
497
+ e = assert_raises(ParseError){smml('\sum_b_c')}
498
+ assert_equal(["Double subscript.", '\sum_b', "_c"], parse_error(e))
499
+ e = assert_raises(ParseError){smml('\sum^b^c')}
500
+ assert_equal(["Double superscript.", '\sum^b', "^c"], parse_error(e))
501
+ e = assert_raises(ParseError){smml('\sum_')}
502
+ assert_equal(["Subscript not exist.", '\sum_', ""], parse_error(e))
503
+ e = assert_raises(ParseError){smml('\sum^')}
504
+ assert_equal(["Superscript not exist.", '\sum^', ""], parse_error(e))
505
+ end
506
+
507
+ def test_fonts
508
+ assert_equal("<mi>a</mi><mrow><mi mathvariant='bold'>b</mi><mi mathvariant='bold'>c</mi></mrow><mi>d</mi>", smml('a{\bf b c}d'))
509
+ assert_equal("<mi mathvariant='bold'>a</mi><mrow><mi>b</mi><mi>c</mi></mrow><mi mathvariant='bold'>d</mi>", smml('\bf a{\it b c}d'))
510
+ assert_equal("<mi>a</mi><mrow><mi mathvariant='normal'>b</mi><mi mathvariant='normal'>c</mi></mrow><mi>d</mi>", smml('a{\rm b c}d'))
511
+
512
+ assert_equal("<mi>a</mi><mrow><mrow><mi mathvariant='bold'>b</mi><mi mathvariant='bold'>c</mi></mrow></mrow><mi>d</mi>", smml('a \mathbf{bc}d'))
513
+ assert_equal("<mrow><mn mathvariant='bold'>1</mn></mrow><mn>2</mn>", smml('\mathbf12'))
514
+ assert_equal("<mi mathvariant='bold'>a</mi><mrow><mrow><mi>b</mi><mi>c</mi></mrow></mrow><mi mathvariant='bold'>d</mi>", smml('\bf a \mathit{bc} d'))
515
+ assert_equal("<mi>a</mi><mrow><mrow><mi mathvariant='normal'>b</mi><mi mathvariant='normal'>c</mi></mrow></mrow><mi>d</mi>", smml('a\mathrm{bc}d'))
516
+
517
+ assert_equal("<mi>a</mi><mrow><mrow><mi>&bopf;</mi><mi>&copf;</mi></mrow></mrow><mi>d</mi>", smml('a \mathbb{b c} d'))
518
+ assert_equal("<mi>a</mi><mrow><mrow><mi>&bscr;</mi><mi>&cscr;</mi></mrow></mrow><mi>d</mi>", smml('a \mathscr{b c} d'))
519
+ assert_equal("<mi>a</mi><mrow><mrow><mi>&bfr;</mi><mi>&cfr;</mi></mrow></mrow><mi>d</mi>", smml('a \mathfrak{b c} d'))
520
+ assert_equal("<mi>a</mi><mrow><mrow><mi mathvariant='bold-italic'>b</mi><mi mathvariant='bold-italic'>c</mi></mrow></mrow><mi>d</mi>", smml('a \bm{bc}d'))
521
+ assert_equal("<mrow><mi mathvariant='bold-italic'>a</mi></mrow><mi>b</mi>", smml('\bm ab'))
522
+ e = assert_raises(ParseError){smml('\mathit')}
523
+ assert_equal(["Syntax error.", '\mathit', ""], parse_error(e))
524
+ e = assert_raises(ParseError){smml('\mathrm')}
525
+ assert_equal(["Syntax error.", '\mathrm', ""], parse_error(e))
526
+ e = assert_raises(ParseError){smml('\mathbf')}
527
+ assert_equal(["Syntax error.", '\mathbf', ""], parse_error(e))
528
+ e = assert_raises(ParseError){smml('\mathbb')}
529
+ assert_equal(["Syntax error.", '\mathbb', ""], parse_error(e))
530
+ e = assert_raises(ParseError){smml('\mathscr')}
531
+ assert_equal(["Syntax error.", '\mathscr', ""], parse_error(e))
532
+ e = assert_raises(ParseError){smml('\mathfrak')}
533
+ assert_equal(["Syntax error.", '\mathfrak', ""], parse_error(e))
534
+ end
535
+
536
+ def test_mbox
537
+ assert_equal("<mi>a</mi><mtext>b c</mtext><mi>d</mi>", smml('a\mbox{b c}d'))
538
+ assert_equal('<mtext>&lt;&gt;&apos;&quot;&amp;</mtext>', smml('\mbox{<>\'"&}'))
539
+ end
540
+
541
+ def test_frac
542
+ assert_equal("<mfrac><mi>a</mi><mi>b</mi></mfrac>", smml('\frac ab'))
543
+ assert_equal("<mfrac><mn>1</mn><mn>2</mn></mfrac>", smml('\frac12'))
544
+
545
+ e = assert_raises(ParseError){smml('\frac a')}
546
+ assert_equal(["Syntax error.", '\frac a', ""], parse_error(e))
547
+ end
548
+
549
+ def test_environment
550
+ e = assert_raises(ParseError){smml('{\begin}rest')}
551
+ assert_equal(["Environment name not exist.", '{\begin', '}rest'], parse_error(e))
552
+
553
+ e = assert_raises(ParseError){smml('{\begin{array}{c}dummy}rest')}
554
+ assert_equal(['Matching \end not exist.', '{\begin{array}{c}dummy', '}rest'], parse_error(e))
555
+
556
+ e = assert_raises(ParseError){smml('\begin{array}c dummy\end{test}')}
557
+ assert_equal(["Environment mismatched.", '\begin{array}c dummy\end', "{test}"], parse_error(e))
558
+
559
+ e = assert_raises(ParseError){smml('\left(\begin{array}\right)')}
560
+ assert_equal(["Syntax error.", '\left(\begin{array}', '\right)'], parse_error(e))
561
+ end
562
+
563
+ def test_array_env
564
+ assert_equal("<mtable columnalign='left right center'><mtr><mtd><mi>a</mi></mtd><mtd><mi>b</mi></mtd><mtd><mi>c</mi></mtd></mtr><mtr><mtd><mi>d</mi></mtd><mtd><mi>e</mi></mtd><mtd><mi>f</mi></mtd></mtr></mtable>", smml('\begin{array}{lrc} a & b & c \\\\ d & e & f \\\\ \end{array}'))
565
+
566
+ assert_equal("<mtable columnalign='left right center'><mtr><mtd><mi>a</mi></mtd><mtd><mi>b</mi></mtd><mtd><mi>c</mi></mtd></mtr><mtr><mtd><mi>d</mi></mtd><mtd><mi>e</mi></mtd><mtd><mi>f</mi></mtd></mtr></mtable>", smml('\begin{array}{lrc}a&b&c\\\\d&e&f \end{array}'))
567
+
568
+ assert_equal("<mtable />", smml('\begin{array}{c}\end{array}'))
569
+
570
+ e = assert_raises(ParseError){smml('\begin{array}\end{array}')}
571
+ assert_equal(['Syntax error.', '\begin{array}', '\end{array}'], parse_error(e))
572
+
573
+ e = assert_raises(ParseError){smml('\begin{array}{a}\end{array}')}
574
+ assert_equal(["Syntax error.", '\begin{array}{', 'a}\end{array}'], parse_error(e))
575
+
576
+ e = assert_raises(ParseError){smml('\begin{array}{cc}a\\\\b&c\end{array}')}
577
+ assert_equal(["Need more column.", '\begin{array}{cc}a', '\\\\b&c\end{array}'], parse_error(e))
578
+
579
+ e = assert_raises(ParseError){smml('\begin{array}{cc}a\end{array}')}
580
+ assert_equal(["Need more column.", '\begin{array}{cc}a', '\end{array}'], parse_error(e))
581
+
582
+ e = assert_raises(ParseError){smml('\begin{array}{c}a&\end{array}')}
583
+ assert_equal(["Too many column.", '\begin{array}{c}a', '&\end{array}'], parse_error(e))
584
+
585
+ assert_equal("<mtable><mtr><mtd /><mtd /></mtr></mtable>", smml('\begin{array}{cc}&\end{array}'))
586
+
587
+ assert_equal("<mfenced close='}' open='{'><mrow><mtable><mtr><mtd><msub><mi>a</mi><mi>b</mi></msub></mtd></mtr></mtable></mrow></mfenced>", smml('\left\{\begin{array}ca_b\end{array}\right\}'))
588
+
589
+ assert_equal("<mtable columnalign='center left center center center right center'><mtr><mtd><mrow><msub><mi>a</mi><mn>1</mn></msub></mrow></mtd><mtd><mi>A</mi></mtd><mtd><mi>b</mi></mtd><mtd><mi>B</mi></mtd><mtd><mi>c</mi></mtd><mtd><mi>C</mi></mtd><mtd><mi>d</mi></mtd></mtr></mtable>", smml('\begin{array}{@{a_1}l@bc@cr@d}A&B&C\end{array}'))
590
+
591
+ assert_equal("<mfenced close='}' open='{'><mrow><mtable><mtr><mtd><msub><mi>a</mi><mi>b</mi></msub></mtd></mtr></mtable></mrow></mfenced>", smml('\left\{\begin{array}ca_b\end{array}\right\}'))
592
+
593
+ assert_equal("<mtable columnlines='solid'><mtr><mtd><mi>a</mi></mtd><mtd><mi>b</mi></mtd></mtr><mtr><mtd><mi>c</mi></mtd><mtd><mi>d</mi></mtd></mtr></mtable>", smml('\begin{array}{c|c}a&b\\\\c&d\end{array}'))
594
+ assert_equal("<mtable columnlines='solid solid'><mtr><mtd /><mtd><mi>a</mi></mtd><mtd /></mtr><mtr><mtd /><mtd><mi>c</mi></mtd><mtd /></mtr></mtable>", smml('\begin{array}{|c|}a\\\\c\end{array}'))
595
+ assert_equal("<mtable rowlines='solid'><mtr /><mtr><mtd><mi>c</mi></mtd></mtr></mtable>", smml('\begin{array}{c}\hline c\end{array}'))
596
+ assert_equal("<mtable rowlines='solid'><mtr><mtd><mi>c</mi></mtd><mtd><mi>a</mi></mtd><mtd><mi>c</mi></mtd><mtd><mi>c</mi></mtd></mtr><mtr><mtd /><mtd /><mtd /><mtd /></mtr></mtable>", smml('\begin{array}{c@acc}c&c&c\\\\\hline\end{array}'))
597
+ assert_equal("<mtable rowlines='solid none solid'><mtr /><mtr><mtd><mi>a</mi></mtd></mtr><mtr><mtd><mi>b</mi></mtd></mtr><mtr><mtd /></mtr></mtable>", smml('\begin{array}{c}\hline a\\\\b\\\\\hline\end{array}'))
598
+ end
599
+
600
+ def test_leftright
601
+ assert_equal("<mfenced close=')' open='('><mrow><mfrac><mn>1</mn><mn>2</mn></mfrac></mrow></mfenced>", smml('\left(\frac12\right)'))
602
+
603
+ assert_equal("<mfenced close='&rfloor;' open='&lfloor;'><mrow><mi>a</mi></mrow></mfenced>", smml('\left \lfloor a\right \rfloor'))
604
+
605
+ assert_equal("<mfenced close='}' open='{'><mrow><mi>a</mi></mrow></mfenced>", smml('\left \{ a \right \}'))
606
+
607
+ assert_equal("<mfenced close='}' open='{'><mrow><mtable><mtr><mtd><mtable><mtr><mtd><mi>a</mi></mtd></mtr></mtable></mtd></mtr></mtable></mrow></mfenced>", smml('\left\{\begin{array}c\begin{array}ca\end{array}\end{array}\right\}'))
608
+
609
+ assert_equal("<mfenced close=')' open='('><mrow><msub><mo>&sum;</mo><mi>a</mi></msub></mrow></mfenced>", smml('\left(\sum_a\right)'))
610
+ assert_equal("<mfenced close=')' open='('><mrow><munder><mo>&sum;</mo><mi>a</mi></munder></mrow></mfenced>", smml('\left(\sum_a\right)', true))
611
+
612
+ e = assert_raises(ParseError){smml('\left(test')}
613
+ assert_equal(["Brace not closed.", '\left', '(test'], parse_error(e))
614
+
615
+ assert_equal("<mfenced close='&DoubleVerticalBar;' open='&DoubleVerticalBar;'><mrow><mi>a</mi></mrow></mfenced>", smml('\left\|a\right\|'))
616
+
617
+ e = assert_raises(ParseError){smml('\left')}
618
+ assert_equal(["Need brace here.", '\left', ""], parse_error(e))
619
+ end
620
+
621
+ def test_over
622
+ assert_equal("<mover><mi>a</mi><mo>&circ;</mo></mover>", smml('\hat a'))
623
+ assert_equal("<mover><mn>1</mn><mo>&circ;</mo></mover><mn>2</mn>", smml('\hat12'))
624
+ e = assert_raises(ParseError){smml('{\hat}a')}
625
+ assert_equal(["Syntax error.", '{\hat', '}a'], parse_error(e))
626
+ end
627
+
628
+ def test_under
629
+ assert_equal("<munder><mi>a</mi><mo>&macr;</mo></munder>", smml('\underline a'))
630
+ assert_equal("<munder><mn>1</mn><mo>&macr;</mo></munder><mn>2</mn>", smml('\underline12'))
631
+ e = assert_raises(ParseError){smml('{\underline}a')}
632
+ assert_equal(["Syntax error.", '{\underline', '}a'], parse_error(e))
633
+ end
634
+
635
+ def test_stackrel
636
+ assert_equal("<mover><mo>=</mo><mo>&rightarrow;</mo></mover>", smml('\stackrel\to='))
637
+ assert_equal("<mover><mn>2</mn><mn>1</mn></mover>", smml('\stackrel12'))
638
+ end
639
+
640
+ def test_comment
641
+ assert_equal("<mi>a</mi>", smml('a%b'))
642
+ end
643
+
644
+ def test_entity
645
+ p = Parser.new
646
+ e = assert_raises(ParseError){smml('\entity{therefore}', false, p)}
647
+ assert_equal(["Unregistered entity.", '\entity{', "therefore}"], parse_error(e))
648
+
649
+ p.unsecure_entity = true
650
+ assert_equal("<mo>&therefore;</mo>", smml('\entity{therefore}', false, p))
651
+
652
+ p.unsecure_entity = false
653
+ e = assert_raises(ParseError){smml('\entity{therefore}', false, p)}
654
+ assert_equal(["Unregistered entity.", '\entity{', "therefore}"], parse_error(e))
655
+
656
+ p.add_entity(['therefore'])
657
+ assert_equal("<mo>&therefore;</mo>", smml('\entity{therefore}', false, p))
658
+ end
659
+
660
+ def test_backslash
661
+ assert_equal("<br xmlns='http://www.w3.org/1999/xhtml' />", smml('\\\\'))
662
+ end
663
+
664
+ def test_macro
665
+ macro = <<'EOS'
666
+ \newcommand{\root}[2]{\sqrt[#1]{#2}}
667
+ \newcommand{\ROOT}[2]{\sqrt[#1]#2}
668
+ \newenvironment{braced}[2]{\left#1}{\right#2}
669
+ \newenvironment{sq}[2]{\sqrt[#2]{#1}}{\sqrt#2}
670
+ \newcommand{\R}{\mathbb R}
671
+ \newenvironment{BB}{\mathbb A}{\mathbb B}
672
+ EOS
673
+ p = Parser.new
674
+ p.macro.parse(macro)
675
+
676
+ assert_equal("<mroot><mrow><mn>2</mn></mrow><mn>1</mn></mroot>", smml('\root12', false, p))
677
+ assert_equal("<mroot><mrow><mn>34</mn></mrow><mn>12</mn></mroot>", smml('\root{12}{34}', false, p))
678
+ assert_equal("<mroot><mn>3</mn><mn>12</mn></mroot><mn>4</mn>", smml('\ROOT{12}{34}', false, p))
679
+ assert_parse_error('Error in macro(Need more parameter. "").', '', '\root'){smml('\root', false, p)}
680
+
681
+ assert_equal("<mfenced close=')' open='|'><mrow><mfrac><mn>1</mn><mn>2</mn></mfrac></mrow></mfenced>", smml('\begin{braced}{|}{)}\frac12\end{braced}', false, p))
682
+ assert_equal("<mroot><mrow><mn>12</mn></mrow><mn>34</mn></mroot><mi>a</mi><msqrt><mn>3</mn></msqrt><mn>4</mn>", smml('\begin{sq}{12}{34}a\end{sq}', false, p))
683
+ assert_parse_error("Need more parameter.", '\begin{braced}', ""){smml('\begin{braced}', false, p)}
684
+ assert_parse_error('Matching \end not exist.', '\begin{braced}', "123"){smml('\begin{braced}123', false, p)}
685
+ assert_parse_error("Environment mismatched.", '\begin{braced}123\end', '{brace}'){smml('\begin{braced}123\end{brace}', false, p)}
686
+ assert_equal("<mrow><mi>&Ropf;</mi></mrow>", smml('\R', false, p))
687
+ assert_equal("<mrow><mi>&Aopf;</mi></mrow><mrow><mi>&Bopf;</mi></mrow>", smml('\begin{BB}\end{BB}', false, p))
688
+ end
689
+
690
+ def test_macro_circular_reference
691
+ macro = <<'EOT'
692
+ \newcommand{\C}{\C}
693
+ \newenvironment{E}{\begin{E}}{\end{E}}
694
+ \newcommand{\D}{\begin{F}\end{F}}
695
+ \newenvironment{F}{\D}{}
696
+ EOT
697
+ ps = Parser.new
698
+ ps.macro.parse(macro)
699
+
700
+ e = assert_raises(ParseError){smml('\C', false, ps)}
701
+ assert_equal(["Circular reference.", "", '\C'], parse_error(e))
702
+
703
+ e = assert_raises(ParseError){smml('\begin{E}\end{E}', false, ps)}
704
+ assert_equal(["Circular reference.", "", '\begin{E}\end{E}'], parse_error(e))
705
+
706
+ e = assert_raises(ParseError){smml('\D', false, ps)}
707
+ assert_equal(["Circular reference.", "", '\D'], parse_error(e))
708
+
709
+ e = assert_raises(ParseError){smml('\begin{F}\end{F}', false, ps)}
710
+ assert_equal(["Circular reference.", "", '\begin{F}\end{F}'], parse_error(e))
711
+ end
712
+
713
+ def test_macro_non_circular_reference
714
+ macro = <<'EOT'
715
+ \newcommand{\C}{\dummy}
716
+ \newenvironment{E}{\dummy}{}
717
+ EOT
718
+ ps = Parser.new
719
+ ps.macro.parse(macro)
720
+
721
+ e = assert_raises(ParseError){smml('\C', false, ps)}
722
+ assert_equal(['Error in macro(Undefined command. "\dummy").', "", '\C'], parse_error(e))
723
+ e = assert_raises(ParseError){smml('\C', false, ps)}
724
+ assert_equal(['Error in macro(Undefined command. "\dummy").', "", '\C'], parse_error(e))
725
+
726
+ e = assert_raises(ParseError){smml('\begin{E}\end{E}', false, ps)}
727
+ assert_equal(['Error in macro(Undefined command. "\dummy").', '', '\begin{E}\end{E}'], parse_error(e))
728
+ e = assert_raises(ParseError){smml('\begin{E}\end{E}', false, ps)}
729
+ assert_equal(['Error in macro(Undefined command. "\dummy").', "", '\begin{E}\end{E}'], parse_error(e))
730
+ end
731
+
732
+ def test_macro_with_option
733
+ macro = <<'EOS'
734
+ \newcommand{\opt}[1][x]{#1}
735
+ \newcommand{\optparam}[2][]{#1#2}
736
+ \newenvironment{newenv}[1][x]{#1}{#1}
737
+ \newenvironment{optenv}[2][]{#1}{#2}
738
+ EOS
739
+
740
+ p = Parser.new
741
+ p.macro.parse(macro)
742
+
743
+ assert_equal("<mi>x</mi><mi>a</mi>", smml('\opt a', false, p))
744
+ assert_equal("<mn>0</mn><mi>a</mi>", smml('\opt[0] a', false, p))
745
+ assert_equal("<mi>a</mi>", smml('\optparam a', false, p))
746
+ assert_equal("<mn>0</mn><mi>a</mi>", smml('\optparam[0] a', false, p))
747
+
748
+ assert_equal("<mi>x</mi><mi>a</mi><mi>x</mi>", smml('\begin{newenv}a\end{newenv}', false, p))
749
+ assert_equal("<mn>0</mn><mi>a</mi><mn>0</mn>", smml('\begin{newenv}[0]a\end{newenv}', false, p))
750
+ assert_equal("<mi>a</mi><mn>0</mn>", smml('\begin{optenv}0a\end{optenv}', false, p))
751
+ assert_equal("<mn>0</mn><mi>a</mi><mn>1</mn>", smml('\begin{optenv}[0]1a\end{optenv}', false, p))
752
+ end
753
+
754
+ def test_matrix_env
755
+ assert_equal("<mtable><mtr><mtd /><mtd /><mtd /></mtr><mtr><mtd /><mtd /></mtr></mtable>", smml('\begin{matrix}&&\\\\&\end{matrix}'))
756
+ assert_parse_error("Environment mismatched.", '\begin{matrix}&&\\\\&\end', "{mat}"){smml('\begin{matrix}&&\\\\&\end{mat}')}
757
+ assert_parse_error("Matching \\end not exist.", '\begin{matrix}&&\\\\&', ''){smml('\begin{matrix}&&\\\\&')}
758
+ assert_equal("<mtable><mtr><mtd><mtable><mtr><mtd><mi>a</mi></mtd><mtd><mi>b</mi></mtd></mtr><mtr><mtd><mi>c</mi></mtd><mtd><mi>d</mi></mtd></mtr></mtable></mtd><mtd><mn>1</mn></mtd></mtr><mtr><mtd><mn>0</mn></mtd><mtd><mn>1</mn></mtd></mtr></mtable>", smml('\begin{matrix}\begin{matrix}a&b\\\\c&d\end{matrix}&1\\\\0&1\\\\\end{matrix}'))
759
+ assert_equal("<mtable />", smml('\begin{matrix}\end{matrix}'))
760
+ assert_equal("<mtable rowlines='solid none solid'><mtr /><mtr><mtd><mi>a</mi></mtd></mtr><mtr><mtd><mi>b</mi></mtd></mtr><mtr /></mtable>", smml('\begin{matrix}\hline a\\\\b\\\\\hline\end{matrix}'))
761
+
762
+ assert_equal("<mtable />", smml('\begin{smallmatrix}\end{smallmatrix}'))
763
+ assert_equal("<mfenced close=')' open='('><mrow><mtable /></mrow></mfenced>", smml('\begin{pmatrix}\end{pmatrix}'))
764
+ assert_equal("<mfenced close=']' open='['><mrow><mtable /></mrow></mfenced>", smml('\begin{bmatrix}\end{bmatrix}'))
765
+ assert_equal("<mfenced close='}' open='{'><mrow><mtable /></mrow></mfenced>", smml('\begin{Bmatrix}\end{Bmatrix}'))
766
+ assert_equal("<mfenced close='|' open='|'><mrow><mtable /></mrow></mfenced>", smml('\begin{vmatrix}\end{vmatrix}'))
767
+ assert_equal("<mfenced close='&DoubleVerticalBar;' open='&DoubleVerticalBar;'><mrow><mtable /></mrow></mfenced>", smml('\begin{Vmatrix}\end{Vmatrix}'))
768
+ end
769
+
770
+ def test_safe_mode
771
+ Thread.start do
772
+ $SAFE=1
773
+ assert_nothing_raised{smml('\alpha'.taint)}
774
+ end.join
775
+ end
776
+
777
+ def test_symbol
778
+ assert_equal("<mo><mfrac linethickness='0' mathsize='1%'><mo>&prec;</mo><mo>&ne;</mo></mfrac></mo>", smml('\precneqq'))
779
+ end
780
+ end