# encoding=utf-8
require 'spec_helper'
describe Polytexnic::Pipeline do
before(:all) do
FileUtils.rm('.highlight_cache') if File.exist?('.highlight_cache')
end
describe '#to_polytex' do
subject(:processed_text) do
Polytexnic::Pipeline.new(source, source: :markdown).polytex
end
context "for vanilla Markdown" do
let(:source) { '*foo* **bar**' }
it { should include '\emph{foo} \textbf{bar}' }
it { should_not include '\begin{document}' }
end
context "with a manual break" do
let(:source) { '[Michael Hartl](http://www.michaelhartl.com/) \\\\ Author, [*The Ruby on Rails Tutorial*](http://railstutorial.org/)' }
it { should include '\\\\' }
it { should_not include '\textbackslash' }
end
context "for multiline Markdown" do
let(:source) do <<-EOS
# A chapter
Hello, *world*!
## A section
Lorem ipsum
EOS
end
it { should include '\chapter{A chapter}' }
it { should include '\section{A section}' }
it { should_not include '\hypertarget' }
end
context "hyphenation" do
let(:source) { 'profes\-sional' }
it { should include source }
end
context "links" do
context "with normal text" do
let(:source) { '[foo](http://example.com/)' }
it { should include '\href{http://example.com/}{foo}' }
end
context "with a percent" do
let(:source) { '[foo bar](http://example.com/foo%20bar)' }
it { should include '\href{http://example.com/foo%20bar}{foo bar}' }
end
end
describe "with math" do
context "inline math" do
let(:source) do <<-'EOS'
This is inline math: {$$} x^2 {/$$}.
EOS
end
it { should include '\( x^2 \)' }
end
context "block math" do
let(:source) do <<-'EOS'
This is block math:
{$$}
x^2
{/$$}.
EOS
end
it { should resemble '\[x^2\]' }
end
end
context "asides with internal lists" do
let(:source) do <<-'EOS'
\begin{aside}
\label{aside:softcover_uses}
\heading{How to use Softcover}
* Producing ebooks with `softcover` and giving them away
* Producing ebooks with `softcover` and selling them from your own website
\end{aside}
EOS
end
it { should include '\begin{aside}' }
it { should_not include "\\end{aside}\n\\end{itemize}" }
end
describe "tables" do
let(:source) do <<-'EOS'
\begin{table}
|**option**|**size**|**actual size**|
| k | kilobytes | (1024 bytes) |
| M | megabytes | (1024 kilobytes) |
| G | gigabytes | (1024 megabytes) |
| T | terabytes | (1024 gigabytes) |
| P | petabytes | (1024 terabytes) |
\end{table}
\begin{table}
|**option**|**size**|**actual size**|
| k | kilobytes | (1024 bytes) |
| M | megabytes | (1024 kilobytes) |
| G | gigabytes | (1024 megabytes) |
| T | terabytes | (1024 gigabytes) |
| P | petabytes | (1024 terabytes) |
\caption{A caption.}
\end{table}
EOS
end
it { should include '\begin{table}' }
it { should include '\begin{longtable}' }
it { should_not include '\textbar' }
end
describe "footnotes" do
subject do
Polytexnic::Pipeline.new(markdown, source: :markdown).polytex
end
context "first chapter with footnotes" do
let(:markdown) do <<-'EOS'
To add a footnote, you insert a footnote tag like this.[^foo]
Then you add the footnote content later in the text, using the same tag,
with a colon and a space:[^foo2]
[^foo]: This is the footnote content.
That is it. You can keep writing your text after the footnote content.
[^foo2]: This is the footnote text. We are now going to add a second line
after typing in four spaces.
EOS
end
it { should include '\footnote{This is the footnote content.}' }
it { should include 'after typing in four spaces.}' }
end
end
describe "images" do
subject do
Polytexnic::Pipeline.new(markdown, source: :markdown).polytex
end
context "inline" do
let(:markdown) { 'Inline ![Caption](img.png) image' }
it { should include '\includegraphics{img.png}' }
it { should_not include '\image' }
end
context "with only a label" do
let(:markdown) do <<-'EOS'
![\label{fig:softcover_server}](images/figures/softcover_server.png)
EOS
end
it { should include '\begin{figure}[H]' }
it { should include '\caption' }
end
context "with alt text but no label" do
let(:markdown) do <<-'EOS'
![Running the Softcover server in a separate tab.](images/figures/softcover_server.png)
EOS
end
it { should_not include '\begin{figure}' }
it { should_not include '\caption' }
it { should include '\image' }
end
context "with a caption and a label" do
let(:markdown) do <<-'EOS'
![Running the Softcover server in a separate tab.\label{fig:softcover_server}](images/figures/softcover_server.png)
EOS
end
it { should include '\caption{Running the Softcover server in a separate tab.\label{fig:softcover_server}}' }
it { should include '\image' }
it { should_not include '\includegraphics' }
end
context "using an example that failed" do
let(:markdown) do <<-'EOS'
a screenshot from [Lowdown](http://lowdownapp.com/), a web
application that developers use for organizing user stories.
![Lowdown for user stories\label{fig:lowdown}](https://tutorials.railsapps.org/assets/learn-rails-lowdown-partial.png)
Just like Rails provides a structure for building a web application,
user stories provide a structure for organizing your product plan.
EOS
end
it { should include '\caption{Lowdown for user stories' }
it { should include '\image{https://tutorials.railsapps.org' }
end
end
context "with LaTeX containing" do
context "a normal command" do
let(:source) { 'This is a command: \foobar' }
it { should include source }
end
context "backslash space" do
let(:source) { 'Dr.\ No' }
it { should include source }
end
context "escaped special characters" do
let(:source) { '\% \& \$ \# \@ \_' }
it { should include source }
end
context "an accented character" do
let(:source) { "\\`{e}" }
it { should include source }
end
context "a label and cross-reference" do
let(:source) do <<-'EOS'
# Chapter One
\label{cha:one}
Chapter~\ref{cha:one}
EOS
end
it { should include '\label{cha:one}' }
it { should include 'Chapter~\ref{cha:one}' }
end
context "inline math" do
let(:source) { '\( x \) is a variable' }
it { should include source }
end
context "inline math with a newline" do
let(:source) { '\( x' + "\n" + ' + y \) is a sum' }
it { should include source }
end
context "an inline math with no spaces" do
let(:source) { '\(\mathbb{R}\)'}
it { should include source }
end
context "a centered equation" do
let(:source) { '\[ x^2 - 2 = 0 \] is an equation' }
it { should resemble source }
end
context "a centered equation with a newline" do
let(:source) do <<-'EOS'
\[
\left(\frac{p}{q}\right) \left(\frac{q}{p}\right) = (-1)^{[(p-1)/2][(q-1)/2]} \quad\text{($p$, $q$ distinct odd primes)}
\]
EOS
end
it { should include source.chomp }
end
context "an equation environment" do
let(:source) do <<-'EOS'
foo
\begin{equation}
\label{eq:maxwell}
\left.\begin{aligned}
\nabla\cdot\mathbf{E} & = \rho \\
\nabla\cdot\mathbf{B} & = 0 \\
\nabla\times\mathbf{E} & = -\dot{\mathbf{B}} \\
\nabla\times\mathbf{B} & = \mathbf{J} + \dot{\mathbf{E}}
\end{aligned}
\right\}
\quad\text{Maxwell equations}
\end{equation}
bar
EOS
end
it { should resemble source }
end
context "a codelisting environment, including a nested command" do
let(:source) do <<-'EOS'
\begin{codelisting}
\codecaption{Lorem \emph{ipsum}.}
\label{code:lorem}
```ruby
def foo; "bar"; end
```
\end{codelisting}
EOS
end
it { should resemble '\begin{codelisting}' }
it { should resemble '\codecaption{Lorem \emph{ipsum}.}' }
it { should resemble '\label{code:lorem}' }
it { should resemble '\end{codelisting}' }
end
context "a commented-out codelisting" do
let(:source) do <<-'EOS'
%= foo:bar
EOS
end
it { should include '%= foo:bar' }
it { should_not match /^\\begin\{code\}/ }
end
context "code inclusion inside codelisting" do
let(:source) do <<-'EOS'
\begin{codelisting}
\codecaption{Lorem ipsum.}
\label{code:lorem}
<<(/path/to/code)
\end{codelisting}
EOS
end
it { should resemble '%= <<(/path/to/code)' }
end
context "codelisting followed by a section" do
let(:source) do <<-'EOS'
\begin{codelisting}
\codecaption{Lorem ipsum.}
\label{code:lorem}
<<(/path/to/code)
\end{codelisting}
# Foo
EOS
end
it { should resemble '\chapter{Foo}' }
end
context "a tabular LaTeX environment" do
let(:source) do <<-'EOS'
\begin{tabularx}
a & b \\
c & d
\end{tabularx}
EOS
end
it { should resemble source }
end
context "a raw longtable environment" do
let(:source) do <<-'EOS'
\begin{longtable}{|c|c|}
a & b \\
c & d \\
\hline
\caption{Foo bar.}
\end{longtable}
EOS
end
it { should resemble source }
end
end
describe "source code" do
context "inline" do
let(:source) { '`foo bar`' }
it { should include '\kode{foo bar}' }
end
context "inline with a newline" do
let(:source) { "`foo\nbar`" }
it { should include "\\kode{foo\nbar}" }
end
context "without highlighting" do
let(:source) do <<-EOS
def foo
"bar"
end
EOS
end
let(:output) do <<-'EOS'
\begin{verbatim}
def foo
"bar"
end
\end{verbatim}
EOS
end
it { should resemble output }
end
context "with highlighting" do
let(:source) do <<-EOS
{lang="ruby"}
def foo
"bar"
end
lorem
EOS
end
let(:output) do <<-'EOS'
%= lang:ruby
\begin{code}
def foo
"bar"
end
\end{code}
lorem
EOS
end
it { should resemble output }
end
describe "code inclusion" do
let(:source) { '<<(/path/to/code)' }
it { should resemble '%= <<(/path/to/code)' }
context "with an alternate lang and options" do
let(:source) { '<<(/path/to/code.md, lang: text, options: "hl_lines": [1, 2], "linenos": true)' }
it { should resemble '%= <<(/path/to/code.md, lang: text, options: "hl_lines": [1, 2], "linenos": true)' }
end
end
describe "GitHub-flavored code fencing" do
context "without highlighting" do
let(:source) do <<-EOS
```
def foo
"bar"
end
```
lorem
EOS
end
let(:output) do <<-'EOS'
%= lang:text
\begin{code}
def foo
"bar"
end
\end{code}
lorem
EOS
end
it { should resemble output }
end
context "with a compound language" do
let(:source) do <<-EOS
# Softcover-flavored Markdown
HTML and PHP:
```html+php
Name:
```
As a final enhancement
EOS
end
let(:output) do <<-'EOS'
%= lang:html+php
\begin{code}
Name:
\end{code}
EOS
end
it { should resemble output }
end
context "with highlighting and options" do
let(:source) do <<-EOS
```ruby, options: "hl_lines": [1, 2], "linenos": true
def foo
"bar"
end
```
lorem
EOS
end
let(:output) do <<-'EOS'
%= lang:ruby, options: "hl_lines": [1, 2], "linenos": true
\begin{code}
def foo
"bar"
end
\end{code}
lorem
EOS
end
it { should resemble output }
end
context "with a code listing from Urbit that broke" do
let(:source) do <<-'EOS'
```text
'Foo \'bar'
0x27
```
foo
EOS
end
it { should_not include "\\begin{code}\n'Foo \n"}
end
context "with nested fencing" do
let(:source) do <<-'EOS'
```text
```ruby, options: "hl_lines": [1, 2], "linenos": true
def hello; puts 'hello'; end
```
```
EOS
end
let(:output) do <<-'EOS'
%= lang:text
\begin{code}
```ruby, options: "hl_lines": [1, 2], "linenos": true
def hello; puts 'hello'; end
```
\end{code}
EOS
end
it { should resemble output }
end
end
end
describe '\input command' do
let(:external_file) { 'foo.md' }
let(:nested_external_file) { 'bar.md' }
let(:input) do <<-'EOS'
Lorem ipsum
```ruby
def foo; 'foo'; end
```
Lorem *ipsum* dolor sit amet
\input{bar}
EOS
end
let(:nested_input) do <<-'EOS'
Lorem ipsum
```python
def bar(): return "bar"
```
EOS
end
before do
File.write(external_file, input)
File.write(nested_external_file, nested_input)
end
after do
File.unlink(external_file)
File.unlink(nested_external_file)
end
let(:output) do
Polytexnic::Pipeline.new(input, source: :markdown).polytex
end
let(:source) { "# Foo\n\n \\input{foo} " }
it { should include output }
end
end
end