');
				assert.deepStrictEqual(tokens, [
					leaf('url', { url: 'https://大石泉すき.example.com' })
				]);
			});
		});
		describe('link', () => {
			it('simple', () => {
				const tokens = parse('[foo](https://example.com)');
				assert.deepStrictEqual(tokens, [
					tree('link', [
						text('foo')
					], { url: 'https://example.com', silent: false })
				]);
			});
			it('simple (with silent flag)', () => {
				const tokens = parse('?[foo](https://example.com)');
				assert.deepStrictEqual(tokens, [
					tree('link', [
						text('foo')
					], { url: 'https://example.com', silent: true })
				]);
			});
			it('in text', () => {
				const tokens = parse('before[foo](https://example.com)after');
				assert.deepStrictEqual(tokens, [
					text('before'),
					tree('link', [
						text('foo')
					], { url: 'https://example.com', silent: false }),
					text('after'),
				]);
			});
			it('with brackets', () => {
				const tokens = parse('[foo](https://example.com/foo(bar))');
				assert.deepStrictEqual(tokens, [
					tree('link', [
						text('foo')
					], { url: 'https://example.com/foo(bar)', silent: false })
				]);
			});
			it('with parent brackets', () => {
				const tokens = parse('([foo](https://example.com/foo(bar)))');
				assert.deepStrictEqual(tokens, [
					text('('),
					tree('link', [
						text('foo')
					], { url: 'https://example.com/foo(bar)', silent: false }),
					text(')')
				]);
			});
		});
		it('emoji', () => {
			const tokens1 = parse(':cat:');
			assert.deepStrictEqual(tokens1, [
				leaf('emoji', { name: 'cat' })
			]);
			const tokens2 = parse(':cat::cat::cat:');
			assert.deepStrictEqual(tokens2, [
				leaf('emoji', { name: 'cat' }),
				leaf('emoji', { name: 'cat' }),
				leaf('emoji', { name: 'cat' })
			]);
			const tokens3 = parse('🍎');
			assert.deepStrictEqual(tokens3, [
				leaf('emoji', { emoji: '🍎' })
			]);
		});
		describe('block code', () => {
			it('simple', () => {
				const tokens = parse('```\nvar x = "Strawberry Pasta";\n```');
				assert.deepStrictEqual(tokens, [
					leaf('blockCode', { code: 'var x = "Strawberry Pasta";', lang: null })
				]);
			});
			it('can specify language', () => {
				const tokens = parse('``` json\n{ "x": 42 }\n```');
				assert.deepStrictEqual(tokens, [
					leaf('blockCode', { code: '{ "x": 42 }', lang: 'json' })
				]);
			});
			it('require line break before "```"', () => {
				const tokens = parse('before```\nfoo\n```');
				assert.deepStrictEqual(tokens, [
					text('before'),
					leaf('inlineCode', { code: '`' }),
					text('\nfoo\n'),
					leaf('inlineCode', { code: '`' })
				]);
			});
			it('series', () => {
				const tokens = parse('```\nfoo\n```\n```\nbar\n```\n```\nbaz\n```');
				assert.deepStrictEqual(tokens, [
					leaf('blockCode', { code: 'foo', lang: null }),
					leaf('blockCode', { code: 'bar', lang: null }),
					leaf('blockCode', { code: 'baz', lang: null }),
				]);
			});
			it('ignore internal marker', () => {
				const tokens = parse('```\naaa```bbb\n```');
				assert.deepStrictEqual(tokens, [
					leaf('blockCode', { code: 'aaa```bbb', lang: null })
				]);
			});
			it('trim after line break', () => {
				const tokens = parse('```\nfoo\n```\nbar');
				assert.deepStrictEqual(tokens, [
					leaf('blockCode', { code: 'foo', lang: null }),
					text('bar')
				]);
			});
		});
		describe('inline code', () => {
			it('simple', () => {
				const tokens = parse('`var x = "Strawberry Pasta";`');
				assert.deepStrictEqual(tokens, [
					leaf('inlineCode', { code: 'var x = "Strawberry Pasta";' })
				]);
			});
			it('disallow line break', () => {
				const tokens = parse('`foo\nbar`');
				assert.deepStrictEqual(tokens, [
					text('`foo\nbar`')
				]);
			});
			it('disallow ´', () => {
				const tokens = parse('`foo´bar`');
				assert.deepStrictEqual(tokens, [
					text('`foo´bar`')
				]);
			});
		});
		it('mathInline', () => {
			const fomula = 'x = {-b \\pm \\sqrt{b^2-4ac} \\over 2a}';
			const content = `\\(${fomula}\\)`;
			const tokens = parse(content);
			assert.deepStrictEqual(tokens, [
				leaf('mathInline', { formula: fomula })
			]);
		});
		describe('mathBlock', () => {
			it('simple', () => {
				const fomula = 'x = {-b \\pm \\sqrt{b^2-4ac} \\over 2a}';
				const content = `\\[\n${fomula}\n\\]`;
				const tokens = parse(content);
				assert.deepStrictEqual(tokens, [
					leaf('mathBlock', { formula: fomula })
				]);
			});
		});
		it('search', () => {
			const tokens1 = parse('a b c 検索');
			assert.deepStrictEqual(tokens1, [
				leaf('search', { content: 'a b c 検索', query: 'a b c' })
			]);
			const tokens2 = parse('a b c Search');
			assert.deepStrictEqual(tokens2, [
				leaf('search', { content: 'a b c Search', query: 'a b c' })
			]);
			const tokens3 = parse('a b c search');
			assert.deepStrictEqual(tokens3, [
				leaf('search', { content: 'a b c search', query: 'a b c' })
			]);
			const tokens4 = parse('a b c SEARCH');
			assert.deepStrictEqual(tokens4, [
				leaf('search', { content: 'a b c SEARCH', query: 'a b c' })
			]);
		});
		describe('center', () => {
			it('simple', () => {
				const tokens = parse('foo');
				assert.deepStrictEqual(tokens, [
					tree('center', [
						text('foo')
					], {}),
				]);
			});
		});
		describe('strike', () => {
			it('simple', () => {
				const tokens = parse('~~foo~~');
				assert.deepStrictEqual(tokens, [
					tree('strike', [
						text('foo')
					], {}),
				]);
			});
			// https://misskey.io/notes/7u1kv5dmia
			it('ignore internal tilde', () => {
				const tokens = parse('~~~~~');
				assert.deepStrictEqual(tokens, [
					text('~~~~~')
				]);
			});
		});
		describe('italic', () => {
			it('', () => {
				const tokens = parse('foo');
				assert.deepStrictEqual(tokens, [
					tree('italic', [
						text('foo')
					], {}),
				]);
			});
			it('underscore', () => {
				const tokens = parse('_foo_');
				assert.deepStrictEqual(tokens, [
					tree('italic', [
						text('foo')
					], {}),
				]);
			});
			it('simple with asterix', () => {
				const tokens = parse('*foo*');
				assert.deepStrictEqual(tokens, [
					tree('italic', [
						text('foo')
					], {}),
				]);
			});
			it('exlude emotes', () => {
				const tokens = parse('*.*');
				assert.deepStrictEqual(tokens, [
					text('*.*'),
				]);
			});
			it('mixed', () => {
				const tokens = parse('_foo*');
				assert.deepStrictEqual(tokens, [
					text('_foo*'),
				]);
			});
			it('mixed', () => {
				const tokens = parse('*foo_');
				assert.deepStrictEqual(tokens, [
					text('*foo_'),
				]);
			});
			it('ignore snake_case string', () => {
				const tokens = parse('foo_bar_baz');
				assert.deepStrictEqual(tokens, [
					text('foo_bar_baz'),
				]);
			});
			it('require spaces', () => {
				const tokens = parse('4日目_L38b a_b');
				assert.deepStrictEqual(tokens, [
					text('4日目_L38b a_b'),
				]);
			});
			it('newline sandwich', () => {
				const tokens = parse('foo\n_bar_\nbaz');
				assert.deepStrictEqual(tokens, [
					text('foo\n'),
					tree('italic', [
						text('bar')
					], {}),
					text('\nbaz'),
				]);
			});
		});
	});
	describe('plainText', () => {
		it('text', () => {
			const tokens = parsePlain('foo');
			assert.deepStrictEqual(tokens, [
				text('foo'),
			]);
		});
		it('emoji', () => {
			const tokens = parsePlain(':foo:');
			assert.deepStrictEqual(tokens, [
				leaf('emoji', { name: 'foo' })
			]);
		});
		it('emoji in text', () => {
			const tokens = parsePlain('foo:bar:baz');
			assert.deepStrictEqual(tokens, [
				text('foo'),
				leaf('emoji', { name: 'bar' }),
				text('baz'),
			]);
		});
		it('disallow other syntax', () => {
			const tokens = parsePlain('foo **bar** baz');
			assert.deepStrictEqual(tokens, [
				text('foo **bar** baz'),
			]);
		});
	});
	describe('toHtml', () => {
		it('br', () => {
			const input = 'foo\nbar\nbaz';
			const output = 'foo
bar
baz
';
			assert.equal(toHtml(parse(input)), output);
		});
		it('br alt', () => {
			const input = 'foo\r\nbar\rbaz';
			const output = 'foo
bar
baz
';
			assert.equal(toHtml(parse(input)), output);
		});
	});
	it('code block with quote', () => {
		const tokens = parse('> foo\n```\nbar\n```');
		assert.deepStrictEqual(tokens, [
			tree('quote', [
				text('foo')
			], {}),
			leaf('blockCode', { code: 'bar', lang: null })
		]);
	});
	it('quote between two code blocks', () => {
		const tokens = parse('```\nbefore\n```\n> foo\n```\nafter\n```');
		assert.deepStrictEqual(tokens, [
			leaf('blockCode', { code: 'before', lang: null }),
			tree('quote', [
				text('foo')
			], {}),
			leaf('blockCode', { code: 'after', lang: null })
		]);
	});
	describe('toString', () => {
		it('太字', () => {
			assert.deepStrictEqual(toString(parse('**太字**')), '**太字**');
		});
		it('中央揃え', () => {
			assert.deepStrictEqual(toString(parse('中央揃え')), '中央揃え');
		});
		it('打ち消し線', () => {
			assert.deepStrictEqual(toString(parse('~~打ち消し線~~')), '~~打ち消し線~~');
		});
		it('小さい字', () => {
			assert.deepStrictEqual(toString(parse('小さい字')), '小さい字');
		});
		it('コードブロック', () => {
			assert.deepStrictEqual(toString(parse('```\nコードブロック\n```')), '```\nコードブロック\n```');
		});
		it('インラインコード', () => {
			assert.deepStrictEqual(toString(parse('`インラインコード`')), '`インラインコード`');
		});
		it('引用行', () => {
			assert.deepStrictEqual(toString(parse('>引用行')), '>引用行');
		});
		it('検索', () => {
			assert.deepStrictEqual(toString(parse('検索 [search]')), '検索 [search]');
		});
		it('リンク', () => {
			assert.deepStrictEqual(toString(parse('[リンク](http://example.com)')), '[リンク](http://example.com)');
		});
		it('詳細なしリンク', () => {
			assert.deepStrictEqual(toString(parse('?[詳細なしリンク](http://example.com)')), '?[詳細なしリンク](http://example.com)');
		});
		it('インライン数式', () => {
			assert.deepStrictEqual(toString(parse('\\(インライン数式\\)')), '\\(インライン数式\\)');
		});
		it('ブロック数式', () => {
			assert.deepStrictEqual(toString(parse('\\\[\nブロック数式\n\]\\')), '\\\[\nブロック数式\n\]\\');
		});
	});
});
describe('fromHtml', () => {
	it('br', () => {
		assert.deepStrictEqual(fromHtml('abc
d
'), 'abc\n\nd');
	});
	it('link with different text', () => {
		assert.deepStrictEqual(fromHtml('a c d
'), 'a [c](https://example.com/b) d');
	});
	it('link with same text', () => {
		assert.deepStrictEqual(fromHtml('a https://example.com/b d
'), 'a https://example.com/b d');
	});
	it('link with same text, but not encoded', () => {
		assert.deepStrictEqual(fromHtml('a https://example.com/ä d
'), 'a  d');
	});
	it('link with no url', () => {
		assert.deepStrictEqual(fromHtml('a c d
'), 'a [c](b) d');
	});
	it('link without href', () => {
		assert.deepStrictEqual(fromHtml('a c d
'), 'a c d');
	});
	it('mention', () => {
		assert.deepStrictEqual(fromHtml('a @user d
'), 'a @user@example.com d');
	});
	it('hashtag', () => {
		assert.deepStrictEqual(fromHtml('a #a d
', ['#a']), 'a #a d');
	});
});