if ENV['COVERAGE'] then
  $stderr.puts "Loading coverage library"
  require 'rubygems'
  require 'coverage'
end

require 'test/unit'
require 'latex/diff'


class Array
  def firsts
    map { |a,b| a }
  end
end

module TestLaTeX
  class TestDiff < Test::Unit::TestCase

    def setup
      @begin_doc = [:BEGIN_DOCUMENT, "\\begin{document}\n"]
      @end_doc = [:END_DOCUMENT, "\\end{document}"]

      @ddb = '\DIFdelbegin' # LaTeX::Diff::DEFAULT_OPTIONS[:delbegin]
      @dde = '\DIFdelend' # LaTeX::Diff::DEFAULT_OPTIONS[:delend]
      @ddo = LaTeX::Diff::DEFAULT_OPTIONS[:delopen]
      @ddc = LaTeX::Diff::DEFAULT_OPTIONS[:delclose]

      @ddco = LaTeX::Diff::DEFAULT_OPTIONS[:delcmdopen]
      @ddcc = LaTeX::Diff::DEFAULT_OPTIONS[:delcmdclose]

      @dab = '\DIFaddbegin' # LaTeX::Diff::DEFAULT_OPTIONS[:addbegin]
      @dae = '\DIFaddend' # LaTeX::Diff::DEFAULT_OPTIONS[:addend]
      @dao = LaTeX::Diff::DEFAULT_OPTIONS[:addopen]
      @dac = LaTeX::Diff::DEFAULT_OPTIONS[:addclose]
    end

    def body_scanner
      scanner = LaTeX::Scanner.new
      scanner.start = :document
      scanner
    end

    def body_scan(str)
      s = body_scanner
      result = s.scan(str)
      s.check_stack
      result
    end

    def body_parse(tokens)
      parser = LaTeX::Parser.new
      tree = parser.parse([@begin_doc] + tokens + [@end_doc])
      tree[1][1...-1]
    end

    def body_parse_str(str)
      body_parse(body_scan(str))
    end

    def diff(t1,t2)
      LaTeX::Diff.new(t1,t2,{
	:addbegin => @dab,
	:addend => @dae,
	:delbegin => @ddb,
	:delend => @dde
      }).diff
    end

    def test_added_section
      t1 = body_parse_str("")
      t2 = body_parse_str("\\section{Hello}")

      diffs = diff(t1,t2)
      #assert_equal [@dab, @dao, "\\section{Hello}", @dac, @dae], diffs
      assert_equal [@dab, "\\section","{",@dao,"Hello",@dac,"}", @dae], diffs
    end

    def test_added_env
      t1 = body_parse_str("")
      t2 = body_parse_str("\\begin{someenv}text\\end{someenv}")

      diffs = diff(t1,t2)
      assert_equal [@dab, "\\begin{someenv}", @dao, 
	"text", @dac, "\\end{someenv}", @dae], diffs
    end

    def test_added_nontext
      t1 = body_parse_str("")
      t2 = body_parse_str("\\newcommand{\\cmd}{defn}")

      diffs = diff(t1,t2)
      assert_equal [@dab, "\\newcommand", "{\\cmd}","{defn}", @dae], diffs
    end

    def test_deleted_word
      t1 = body_parse_str("word")
      t2 = body_parse_str("")

      diffs = diff(t1,t2)
      assert_equal [@ddb, @ddo, "word", @ddc, @dde], diffs
    end

    def test_deleted_section
      t1 = body_parse_str("\\section{Hello}")
      t2 = body_parse_str("")

      diffs = diff(t1,t2)
      #assert_equal [@ddb, @ddo, "\\section*{Hello}", @ddc, @dde], diffs
      assert_equal [@ddb, "\\section*","{",@ddo,"Hello",@ddc,"}", @dde], diffs
    end

    def test_deleted_env
      t1 = body_parse_str("\\begin{env}text\\end{env}")
      t2 = body_parse_str("")
      diffs = diff(t1,t2)
      assert_equal [@ddb, "\\begin{env}", 
	@ddo, "text", @ddc, "\\end{env}", @dde], diffs
    end

    def test_deleted_command
      t1 = body_parse_str("\\unknowncommand{arg1}{arg2}")
      t2 = body_parse_str("")
      diffs = diff(t1,t2)
      assert_equal [@ddb, @ddco, "\\unknowncommand", "{arg1}", "{arg2}",
	@ddcc, @dde], diffs
    end

    # Check that newlines are commented out
    def test_deleted_command_newlines
      t1 = body_parse_str("\\unknowncommand{arg1\n\n}{arg2}")
      t2 = body_parse_str("")
      diffs = diff(t1,t2)
      assert_equal [@ddb, @ddco, "\\unknowncommand", "{arg1\n%\n%}", "{arg2}",
	@ddcc, @dde], diffs
    end

    def test_deleted_command_nested
      t1 = body_parse_str("\\unknowncommand{\\othercommand{arg}}")
      t2 = body_parse_str("")
      diffs = diff(t1,t2)
      assert_equal [@ddb, @ddco, "\\unknowncommand", 
	"{\\othercommand{arg}}", @ddcc, @dde], diffs
    end

    def test_identical
      t1 = body_parse_str("some text")
      t2 = body_parse_str("some text")
      diffs = diff(t1,t2)
      assert_equal ["some"," ","text"], diffs
    end

    def test_single_word
      t1 = body_parse_str("A B C D E F G")
      t2 = body_parse_str("A b c D e f G")
      diffs = diff(t1,t2)

      assert_equal [@ddb, @ddo, "A","B","C","D","E","F","G", @ddc,
	@dde, @dab, @dao, "A","b","c","D","e","f","G", @dac, @dae],
	diffs.reject { |e| e == " " }
    end

    def test_section_changed
      t1 = body_parse_str("\\section{Z A B}")
      t2 = body_parse_str("\\section{Z A C}")
      diffs = diff(t1,t2)
      assert_equal ["\\section","{","Z"," ","A",
	@ddb, " ", @ddo, "B", @ddc, @dde,
	@dab, " ", @dao, "C", @dac, @dae,
	"}"], diffs
    end

    def test_env_changed
      t1 = body_parse_str("\\begin{env}Z A B\\end{env}")
      t2 = body_parse_str("\\begin{env}Z A C\\end{env}")
      diffs = diff(t1,t2)
      assert_equal ["\\begin{env}","Z"," ","A",
	@ddb, " ", @ddo, "B", @ddc, @dde,
	@dab, " ", @dao, "C", @dac, @dae,
	"\\end{env}"], diffs
    end

    def test_nomarkup
      t1 = body_parse_str("\\begin{DIFnomarkup}A B\\end{DIFnomarkup}")
      t2 = body_parse_str("\\begin{DIFnomarkup}A C\\end{DIFnomarkup}")
      diffs = diff(t1,t2)
      assert_equal ["\\begin{DIFnomarkup}A C\\end{DIFnomarkup}"], diffs
    end

    def test_atomic
      t1 = body_parse_str("\\begin{DIFatomic}A B\\end{DIFatomic}")
      t2 = body_parse_str("\\begin{DIFatomic}A C\\end{DIFatomic}")
      diffs = diff(t1,t2)
      assert_equal [@ddb,"\\begin{DIFatomic}",
	@ddo,"A"," ","B",@ddc,
	"\\end{DIFatomic}",@dde,
	@dab,"\\begin{DIFatomic}",
	@dao,"A"," ","C",@dac,
	"\\end{DIFatomic}",@dae
      ], diffs
    end

    def test_simplify
      diffs = [
	["e", 0, 0, 0, 0], 
	["c", 1, 2, 1, 2], ["e", 3, 3, 3, 3], ["c", 4, 5, 4, 5], 
	["e", 6, 6, 6, 6]
      ]
      t1 = [""] + [LaTeX::Word.new("X")]*5 + [""]
      result = LaTeX::Diff.new(t1,t1).send(:simplify,diffs)

      assert_equal [["e",0,0,0,0], ["c",1,5,1,5], ["e",6,6,6,6]], result
    end

    def test_coalesce
      diffs = [["c",0,0,0,0],["c",1,3,1,3],["c",4,6,4,6]]
      result = LaTeX::Diff.new([],[]).send(:coalesce,diffs)

      assert_equal [["c",0,6,0,6]], result
    end

    def test_verbatim
      t1 = body_parse_str('')
      t2 = body_parse_str("\\begin{verbatim}\nfoo\n\\end{verbatim}\n\nbar\n")
      diffs = diff(t1,t2)

      assert_equal [@dab,"\\begin{verbatim}\nfoo\n\\end{verbatim}\n","\n",@dao,"bar",@dac,@dae],diffs
    end

    def test_amp
      t1 = body_parse_str('hello & there & bob')
      t2 = body_parse_str('foo & bar & bob')
      diffs = diff(t1,t2)
      assert_equal [    @ddb, @ddo, "hello", @ddc, @dde,
                        @dab, @dao, "foo", @dac, @dae,
                        " ", "&",
                        @ddb, " ", @ddo, "there", @ddc, @dde,
                        @dab, " ", @dao, "bar", @dac, @dae,
                        " ", "&", " ",
                        "bob"
      ], diffs
    end

    def test_difunwrap
      t1 = body_parse_str('hello 456 there 123')
      t2 = body_parse_str("hello 456\n\\begin{DIFunwrap}\nthis is added\n\\end{DIFunwrap}\n there 123")
      diffs = diff(t1,t2)
      assert_equal [ "hello"," ", "456", @dab, "\n", @dae, "\\begin{DIFunwrap}\nthis is added\n\\end{DIFunwrap}",
      @dab, @dae, "\n ", "there", " ", "123"], diffs
    end

    def test_lone_spaces
      t1 = body_parse_str('')
      t2 = body_parse_str("\\begin{enumerate}\n  \\item Foo\n  \\item Bar\n\\end{enumerate}\n")
      diffs = diff(t1,t2)
      assert_equal [@dab, "\\begin{enumerate}", "\n  ", 
        "\\item", " ", @dao, "Foo", "\n  ", @dac,
        "\\item", " ", @dao, "Bar", "\n", @dac,
        "\\end{enumerate}", @dae], diffs
    end

  end


end

