[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kde-commits
Subject:    [kdev-ruby] parser/tests/assert_same: Better test suite: add my
From:       Alexander Dymo <adymo () kdevelop ! org>
Date:       2011-08-11 21:53:33
Message-ID: 20110811215333.8D982A60B9 () git ! kde ! org
[Download RAW message or body]

Git commit 88b7e0fc38b7aa31c3e897d1f49f5688f1e8d221 by Alexander Dymo.
Committed on 11/08/2011 at 23:45.
Pushed by dymo into branch 'master'.

Better test suite: add my assert_same library (to be used instead of suite.rb)

assert_same: assert which checks that two strings (expected and actual) are same
and which can "magically" replace expected value with the actual in case
the new behavior (and new actual value) is correct.

This library is taken from https://github.com/acunote/assert_same
branch master, revision 49995f5b1a9dbc6b700e

A  +18   -0    parser/tests/assert_same/test/assert_same_test.rb
A  +330  -0    parser/tests/assert_same/lib/array_diff.rb
A  +22   -0    parser/tests/assert_same/Rakefile
A  +1    -0    parser/tests/assert_same/.gitignore
A  +2    -0    parser/tests/assert_same/init.rb
A  +19   -0    parser/tests/assert_same/LICENSE
A  +254  -0    parser/tests/assert_same/lib/assert_same.rb
A  +1    -0    parser/tests/assert_same/test/logs/assert_same_with_files.log.ref
A  +5    -0    parser/tests/assert_same/README
A  +109  -0    parser/tests/assert_same/lib/text_diff.rb

http://commits.kde.org/kdev-ruby/88b7e0fc38b7aa31c3e897d1f49f5688f1e8d221

diff --git a/parser/tests/assert_same/.gitignore \
b/parser/tests/assert_same/.gitignore new file mode 100644
index 0000000..b25c15b
--- /dev/null
+++ b/parser/tests/assert_same/.gitignore
@@ -0,0 +1 @@
+*~
diff --git a/parser/tests/assert_same/LICENSE b/parser/tests/assert_same/LICENSE
new file mode 100644
index 0000000..56c70ae
--- /dev/null
+++ b/parser/tests/assert_same/LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2010-2011 Pluron, Inc.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/parser/tests/assert_same/README b/parser/tests/assert_same/README
new file mode 100644
index 0000000..02f4254
--- /dev/null
+++ b/parser/tests/assert_same/README
@@ -0,0 +1,5 @@
+assert_same
+===========
+
+Please read the API docs in lib/assert_same.rb
+
diff --git a/parser/tests/assert_same/Rakefile b/parser/tests/assert_same/Rakefile
new file mode 100644
index 0000000..1a35fb7
--- /dev/null
+++ b/parser/tests/assert_same/Rakefile
@@ -0,0 +1,22 @@
+require 'rake'
+require 'rake/testtask'
+require 'rake/rdoctask'
+
+desc 'Default: run unit tests.'
+task :default => :test
+
+desc 'Test assert_same.'
+Rake::TestTask.new(:test) do |t|
+  t.libs << 'lib'
+  t.pattern = 'test/**/*_test.rb'
+  t.verbose = true
+end
+
+desc 'Generate documentation for assert_same.'
+Rake::RDocTask.new(:rdoc) do |rdoc|
+  rdoc.rdoc_dir = 'rdoc'
+  rdoc.title    = 'assert_same'
+  rdoc.options << '--line-numbers' << '--inline-source'
+  rdoc.rdoc_files.include('README')
+  rdoc.rdoc_files.include('lib/**/*.rb')
+end
diff --git a/parser/tests/assert_same/init.rb b/parser/tests/assert_same/init.rb
new file mode 100644
index 0000000..d0f3288
--- /dev/null
+++ b/parser/tests/assert_same/init.rb
@@ -0,0 +1,2 @@
+$LOAD_PATH.unshift(File.dirname(__FILE__) + "/lib")
+require 'assert_same'
diff --git a/parser/tests/assert_same/lib/array_diff.rb \
b/parser/tests/assert_same/lib/array_diff.rb new file mode 100644
index 0000000..838b89f
--- /dev/null
+++ b/parser/tests/assert_same/lib/array_diff.rb
@@ -0,0 +1,330 @@
+class ArrayDiff
+
+  VERSION = 0.3
+
+  def ArrayDiff.lcs(a, b)
+    astart = 0
+    bstart = 0
+    afinish = a.length-1
+    bfinish = b.length-1
+    mvector = []
+    
+    # First we prune off any common elements at the beginning
+    while (astart <= afinish && bstart <= afinish && a[astart] == b[bstart])
+      mvector[astart] = bstart
+      astart += 1
+      bstart += 1
+    end
+    
+    # now the end
+    while (astart <= afinish && bstart <= bfinish && a[afinish] == b[bfinish])
+      mvector[afinish] = bfinish
+      afinish -= 1
+      bfinish -= 1
+    end
+
+    bmatches = b.reverse_hash(bstart..bfinish)
+    thresh = []
+    links = []
+    
+    (astart..afinish).each { |aindex|
+      aelem = a[aindex]
+      next unless bmatches.has_key? aelem
+      k = nil
+      bmatches[aelem].reverse.each { |bindex|
+    if k && (thresh[k] > bindex) && (thresh[k-1] < bindex)
+      thresh[k] = bindex
+    else
+      k = thresh.replacenextlarger(bindex, k)
+    end
+    links[k] = [ (k==0) ? nil : links[k-1], aindex, bindex ] if k
+      }
+    }
+
+    if !thresh.empty?
+      link = links[thresh.length-1]
+      while link
+    mvector[link[1]] = link[2]
+    link = link[0]
+      end
+    end
+
+    return mvector
+  end
+
+  def makediff(a, b)
+    mvector = ArrayDiff.lcs(a, b)
+    ai = bi = 0
+    while ai < mvector.length
+      bline = mvector[ai]
+      if bline
+    while bi < bline
+      discardb(bi, b[bi])
+      bi += 1
+    end
+    match(ai, bi)
+    bi += 1
+      else
+    discarda(ai, a[ai])
+      end
+      ai += 1
+    end
+    while ai < a.length
+      discarda(ai, a[ai])
+      ai += 1
+    end
+    while bi < b.length
+      discardb(bi, b[bi])
+      bi += 1
+    end
+    match(ai, bi)
+    1
+  end
+
+  def compactdiffs
+    diffs = []
+    @diffs.each { |df|
+      i = 0
+      curdiff = []
+      while i < df.length
+    whot = df[i][0]
+    s = @isstring ? df[i][2].chr : [df[i][2]]
+    p = df[i][1]
+    last = df[i][1]
+    i += 1
+    while df[i] && df[i][0] == whot && df[i][1] == last+1
+      s << df[i][2]
+      last  = df[i][1]
+      i += 1
+    end
+    curdiff.push [whot, p, s]
+      end
+      diffs.push curdiff
+    }
+    return diffs
+  end
+
+  attr_reader :diffs, :difftype
+
+  def initialize(diffs_or_a, b = nil, isstring = nil)
+    if b.nil?
+      @diffs = diffs_or_a
+      @isstring = isstring
+    else
+      @diffs = []
+      @curdiffs = []
+      makediff(diffs_or_a, b)
+      @difftype = diffs_or_a.class
+    end
+  end
+  
+  def match(ai, bi)
+    @diffs.push @curdiffs unless @curdiffs.empty?
+    @curdiffs = []
+  end
+
+  def discarda(i, elem)
+    @curdiffs.push ['-', i, elem]
+  end
+
+  def discardb(i, elem)
+    @curdiffs.push ['+', i, elem]
+  end
+
+  def compact
+    return Diff.new(compactdiffs)
+  end
+
+  def compact!
+    @diffs = compactdiffs
+  end
+
+  def inspect
+    @diffs.inspect
+  end
+
+  def diffrange(a, b)
+    if (a == b)
+      "#{a}"
+    else
+      "#{a},#{b}"
+    end
+  end
+
+  def to_diff
+    offset = 0
+    @diffs.each { |b|
+      first = b[0][1]
+      length = b.length
+      action = b[0][0]
+      addcount = 0
+      remcount = 0
+      b.each { |l| 
+        if l[0] == "+"
+          addcount += 1
+        elsif l[0] == "-"
+          remcount += 1
+        end
+      }
+      if addcount == 0
+        puts "#{diffrange(first+1, first+remcount)}d#{first+offset}"
+      elsif remcount == 0
+        puts "#{first-offset}a#{diffrange(first+1, first+addcount)}"
+      else
+        puts "#{diffrange(first+1, first+remcount)}c#{diffrange(first+offset+1, \
first+offset+addcount)}" +      end
+      lastdel = (b[0][0] == "-")
+      b.each { |l|
+        if l[0] == "-"
+          offset -= 1
+          print "< "
+        elsif l[0] == "+"
+          offset += 1
+      if lastdel
+        lastdel = false
+            puts "---"
+          end
+          print "> "
+        end
+    print l[2]
+    print "\n"
+      }
+    }
+  end
+
+
+end
+
+module Diffable
+  def diff(b)
+    ArrayDiff.new(self, b)
+  end
+
+  # Create a hash that maps elements of the array to arrays of indices
+  # where the elements are found.
+
+  def reverse_hash(range = (0...self.length))
+    revmap = {}
+    range.each { |i|
+      elem = self[i]
+      if revmap.has_key? elem
+    revmap[elem].push i
+      else
+    revmap[elem] = [i]
+      end
+    }
+    return revmap
+  end
+
+  def replacenextlarger(value, high = nil)
+    high ||= self.length
+    if self.empty? || value > self[-1]
+      push value
+      return high
+    end
+    # binary search for replacement point
+    low = 0
+    while low < high
+      index = (high+low)/2
+      found = self[index]
+      return nil if value == found
+      if value > found
+    low = index + 1
+      else
+    high = index
+      end
+    end
+
+    self[low] = value
+    # $stderr << "replace #{value} : 0/#{low}/#{init_high} (#{steps} steps) \
(#{init_high-low} off )\n" +    # $stderr.puts self.inspect
+    #gets
+    #p length - low
+    return low
+  end
+
+  def patch(diff)
+    newary = nil
+    if diff.difftype == String
+      newary = diff.difftype.new('')
+    else
+      newary = diff.difftype.new
+    end
+    ai = 0
+    bi = 0
+    diff.diffs.each { |d|
+      d.each { |mod|
+    case mod[0]
+    when '-'
+      while ai < mod[1]
+        newary << self[ai]
+        ai += 1
+        bi += 1
+      end
+      ai += 1
+    when '+'
+      while bi < mod[1]
+        newary << self[ai]
+        ai += 1
+        bi += 1
+      end
+      newary << mod[2]
+      bi += 1
+    else
+      raise "Unknown diff action"
+    end
+      }
+    }
+    while ai < self.length
+      newary << self[ai]
+      ai += 1
+      bi += 1
+    end
+    return newary
+  end
+end
+
+class Array
+  include Diffable
+end
+
+class String
+  include Diffable
+end
+
+=begin
+= ArrayDiff
+(({diff.rb})) - computes the differences between two arrays or
+strings. Copyright (C) 2001 Lars Christensen
+
+== Synopsis
+
+    diff = ArrayDiff.new(a, b)
+    b = a.patch(diff)
+
+== Class ArrayDiff
+=== Class Methods
+--- ArrayDiff.new(a, b)
+--- a.diff(b)
+      Creates a Diff object which represent the differences between
+      ((|a|)) and ((|b|)). ((|a|)) and ((|b|)) can be either be arrays
+      of any objects, strings, or object of any class that include
+      module ((|Diffable|))
+
+== Module Diffable
+The module ((|Diffable|)) is intended to be included in any class for
+which differences are to be computed. Diffable is included into String
+and Array when (({diff.rb})) is (({require}))'d.
+
+Classes including Diffable should implement (({[]})) to get element at
+integer indices, (({<<})) to append elements to the object and
+(({ClassName#new})) should accept 0 arguments to create a new empty
+object.
+
+=== Instance Methods
+--- Diffable#patch(diff)
+      Applies the differences from ((|diff|)) to the object ((|obj|))
+      and return the result. ((|obj|)) is not changed. ((|obj|)) and
+      can be either an array or a string, but must match the object
+      from which the ((|diff|)) was created.
+=end
diff --git a/parser/tests/assert_same/lib/assert_same.rb \
b/parser/tests/assert_same/lib/assert_same.rb new file mode 100644
index 0000000..ebed3e0
--- /dev/null
+++ b/parser/tests/assert_same/lib/assert_same.rb
@@ -0,0 +1,254 @@
+# Copyright (c) 2010-2011 Pluron, Inc.
+require 'test/unit'
+require 'text_diff'
+
+class Test::Unit::TestCase
+
+    #Hash[filename][line_number] = offset
+    #For each line in the original file we store its offset (+N or -N lines)
+    #relative to the actual file
+    @@file_offsets = Hash.new { |hash, key| hash[key] = {} }
+
+    # assert_same: assert which checks that two strings (expected and actual) are \
same +    # and which can "magically" replace expected value with the actual in case
+    # the new behavior (and new actual value) is correct
+    #
+    # == Usage ==
+    #
+    # Write this in the test source:
+    #     assert_same something, <<-END
+    #         foo
+    #         bar
+    #         zee
+    #     END
+    # 
+    # Then run tests as usual:
+    #    rake test:units
+    #    ruby test/unit/foo_test.rb
+    #    ...
+    #
+    # When assert_same fails, you'll be able to:
+    # - review diff
+    # - (optionally) accept new actual value (this modifies the test source file)
+    #
+    # Additional options for test runs:
+    # --no-interactive skips all questions and just reports failures
+    # --autoaccept prints diffs and automatically accepts all new actual values
+    # --no-canonicalize turns off expected and actual value canonicalization (see \
below for details) +    #
+    # Additional options can be passed during both single test file run and rake \
test run: +    #    ruby test/unit/foo_test.rb -- --autoaccept
+    #    ruby test/unit/foo_test.rb -- --no-interactive
+    #
+    #    rake test TESTOPTS="-- --autoaccept"
+    #    rake test:units TESTOPTS="-- --no-canonicalize --autoaccept"
+    #
+    #
+    #
+    # == Canonicalization ==
+    #
+    # Before comparing expected and actual strings, assert_same canonicalizes both \
using these rules: +    # - indentation is ignored (except for indentation
+    #   relative to the first line of the expected/actual string)
+    # - ruby-style comments after "#" are ignored: 
+    #   both whole-line and end-of-line comments are supported
+    # - empty lines are ignored
+    # - trailing whitespaces are ignored
+    #
+    # You can turn canonicalization off with --no-canonicalize option. This is \
useful +    # when you need to regenerate expected test strings.
+    # To regenerate the whole test suite, run:
+    #    rake test TESTOPTS="-- --no-canonicalize --autoaccept"
+    #
+    # Example of assert_same with comments:
+    #  assert_same something, <<-END
+    #      # some tree
+    #      foo 1
+    #        foo 1.1
+    #        foo 1.2    # some node
+    #      bar 2
+    #        bar 2.1
+    #  END
+    #
+    #
+    #
+    # == Umportant Usage Rules ==
+    #
+    # Restrictions:
+    # - only END and EOS are supported as end of string sequence
+    # - it's a requirement that you have <<-END at the same line as assert_same
+    # - assert_same can't be within a block
+    #
+    # Storing expected output in files:
+    # - assert_same something, :log => <path_to_file>
+    # - path to file is relative to:
+    #   - RAILS_ROOT (if that is defined)
+    #   - current dir (if no RAILS_ROOT is defined)
+    # - file doesn't have to exist, it will be created if necessary
+    #
+    # Misc:
+    # - it's ok to have several assert_same's in the same test method, assert_same.
+    #   correctly updates all assert_same's in the test file
+    # - it's ok to omit expected string, like this:
+    #       assert_same something
+    #   in fact, this is the preferred way to create assert_same tests - you write \
empty +    #   assert_same, run tests and they will fill expected values for you \
automatically +    def assert_same(actual, expected = :autofill_expected_value)
+        if expected.class == String
+            expected ||= ""
+            mode = :expecting_string
+        elsif expected == :autofill_expected_value
+            expected = ""
+            mode = :autofill_expected_value
+        elsif expected.class == Hash
+            raise ":log key is missing" unless expected.has_key? :log
+            mode = :expecting_file
+            log_file = expected[:log]
+            if defined? RAILS_ROOT
+                log_file = File.expand_path(log_file, RAILS_ROOT)
+            else
+                log_file = File.expand_path(log_file, Dir.pwd)
+            end
+            expected = File.exists?(log_file) ? File.read(log_file) : ""
+        else
+            internal_error("Incorrect expected argument for assert_same. It must be \
either String or Hash.") +        end
+
+        # interactive mode is turned on by default, except when
+        # - --no-interactive is given
+        # - STDIN is not a terminal device (i.e. we can't ask any questions)
+        interactive = !ARGV.include?("--no-interactive") && STDIN.tty?
+        canonicalize = !ARGV.include?("--no-canonicalize")
+        autoaccept = ARGV.include?("--autoaccept")
+
+        is_same_canonicalized, is_same, diff_canonicalized, diff = \
compare_for_assert_same(expected, actual) +
+        if (canonicalize and !is_same_canonicalized) or (!canonicalize and !is_same)
+            diff_to_report = canonicalize ? diff_canonicalized : diff
+            if interactive
+                # print method name and short backtrace
+                failure = Test::Unit::Failure.new(name, filter_backtrace(caller(0)), \
diff_to_report) +                puts "\n#{failure}"
+
+                if autoaccept
+                    accept = true
+                else
+                    print "Accept the new value: yes to all, no to all, yes, no? \
[Y/N/y/n] (y): " +                    STDOUT.flush
+                    response = STDIN.gets.strip
+                    accept = ["", "y", "Y"].include? response
+                    ARGV << "--autoaccept" if response == "Y"
+                    ARGV << "--no-interactive" if response == "N"
+                end
+
+                if accept
+                    if [:expecting_string, :autofill_expected_value].include? mode
+                        accept_string(actual, mode)
+                    elsif mode == :expecting_file
+                        accept_file(actual, log_file)
+                    end
+                end
+            end
+            if accept
+                # when change is accepted, we should not report it as a failure \
because +                # we want the test method to continue executing (in case \
there're more +                # assert_same's in the method)
+                add_assertion
+            else
+                raise Test::Unit::AssertionFailedError.new(diff_to_report)
+            end
+        else
+            add_assertion
+        end
+    end
+
+private
+
+    def accept_string(actual, mode)
+        file, method, line = get_caller_location(:depth => 3)
+
+        # read source file, construct the new source, replacing everything
+        # between "do" and "end" in assert_same's block
+        source = File.readlines(RAILS_ROOT + "/" + file)
+
+        # file may be changed by previous accepted assert_same's, adjust line \
numbers +        offset = @@file_offsets[file].keys.inject(0) do |sum, i|
+            line.to_i >= i ? sum + @@file_offsets[file][i] : sum
+        end
+
+        expected_text_end_line = expected_text_start_line = line.to_i + offset
+        unless mode == :autofill_expected_value
+            #if we're autofilling the value, END/EOS marker will not exist
+            #(second arg to assert_same is omitted)
+            #else we search for it
+            expected_text_end_line += 1 while !["END", \
"EOS"].include?(source[expected_text_end_line].strip) +        end
+
+        expected_length = expected_text_end_line - expected_text_start_line
+
+        # indentation is the indentation of assert_same call + 4
+        indentation = source[expected_text_start_line-1] =~ /^(\s+)/ ? $1.length : 0
+        indentation += 4
+
+        if mode == :autofill_expected_value
+            # add second argument to assert_same if it's omitted
+            source[expected_text_start_line-1] = \
"#{source[expected_text_start_line-1].chop}, <<-END\n" +        end
+        source = source[0, expected_text_start_line] +
+            actual.split("\n").map { |l| "#{" "*(indentation)}#{l}\n"} +
+            (mode == :autofill_expected_value ? ["#{" "*(indentation-4)}END\n"] : \
[])+ +            source[expected_text_end_line, source.length]
+
+        # recalculate line number adjustments
+        actual_length = actual.split("\n").length
+        actual_length += 1 if mode == :autofill_expected_value  # END marker after \
actual value +        @@file_offsets[file][line.to_i] = actual_length - \
expected_length +
+        source_file = File.open(RAILS_ROOT + "/" + file, "w+")
+        source_file.write(source)
+        source_file.fsync
+        source_file.close
+    end
+
+    def accept_file(actual, log_file)
+        log = File.open(log_file, "w+")
+        log.write(actual)
+        log.fsync
+        log.close
+    end
+
+    def compare_for_assert_same(expected_verbatim, actual_verbatim)
+        expected_canonicalized, expected = \
canonicalize_for_assert_same(expected_verbatim) +        actual_canonicalized, actual \
= canonicalize_for_assert_same(actual_verbatim) +        diff_canonicalized = \
AssertSame::TextDiff.array_diff(expected_canonicalized, actual_canonicalized) +       \
diff = AssertSame::TextDiff.array_diff(expected, actual) +        \
[expected_canonicalized == actual_canonicalized, expected == actual, \
diff_canonicalized, diff] +    end
+
+    def canonicalize_for_assert_same(text)
+        # make array of lines out of the text
+        result = text.split("\n")
+
+        # ignore leading newlines if any (trailing will be automatically ignored by \
split()) +        result.delete_at(0) if result[0] == ""
+
+        indentation = $1.length if result[0] and result[0] =~ /^(\s+)/
+
+        result.map! do |line|
+            # ignore indentation: we assume that the first line defines indentation
+            line.gsub!(/^\s{#{indentation}}/, '') if indentation
+            # ignore trailing spaces
+            line.gsub(/\s*$/, '')
+        end
+
+        # ignore comments
+        result_canonicalized= result.map do |line|
+            line.gsub(/\s*(#.*)?$/, '')
+        end
+        # ignore blank lines (usually they are lines with comments only)
+        result_canonicalized.delete_if { |line| line.nil? or line.empty? }
+
+        [result_canonicalized, result]
+    end
+
+end
diff --git a/parser/tests/assert_same/lib/text_diff.rb \
b/parser/tests/assert_same/lib/text_diff.rb new file mode 100644
index 0000000..ff5b353
--- /dev/null
+++ b/parser/tests/assert_same/lib/text_diff.rb
@@ -0,0 +1,109 @@
+# Copyright (c) 2008 Pluron, Inc.
+
+require 'array_diff'
+
+module AssertSame
+
+class TextDiff
+
+    def self.mapped_chunk(arr, from, to)
+        return [] if to < from
+        arr[from, to-from+1].map{|x| [' ', x]}
+    end
+
+    def self.chunk(arr, from, to)
+        result = []
+        if to - from > 2
+            result += self.mapped_chunk(arr, from, from+2) if from > 0
+            result << ['@', to-2]
+            result += self.mapped_chunk(arr, to-2, to)
+        else 
+            result << ['@', from] if from == 0
+            result += self.mapped_chunk(arr, from, to)
+        end
+    end
+
+    def self.record_stat(arr, at, remcount, addcount, linecount, offset)
+        index = arr[at][1]+1
+        ['', "@@ -#{index},#{linecount-addcount}, \
+#{index+offset},#{linecount-remcount} @@"] +    end
+
+    def self.diff(a_text, b_text)
+        a = a_text.split("\n")
+        b = b_text.split("\n")
+        self.array_diff(a, b)
+    end
+
+    def self.array_diff(a, b)
+        diff = ArrayDiff.new(a, b)
+
+        return nil if diff.diffs.empty?
+
+        result = []
+
+        from = to = nextfrom = 0
+        offset = 0
+        diff.diffs.each do |tuple|
+            first = tuple[0][1]
+            length = tuple.length
+            action = tuple[0][0]
+            addcount = 0
+            remcount = 0
+            tuple.each do |l| 
+                if l[0] == "+"
+                    addcount += 1
+                elsif l[0] == "-"
+                    remcount += 1
+                end
+            end
+            if remcount == 0
+                to = first-offset-1
+                nextfrom = to+1
+            else
+                to = first-1
+                nextfrom = to+remcount+1
+            end
+            result += self.chunk(a, from, to)
+            from = nextfrom
+            lastdel = (tuple[0][0] == "-")
+            tuple.each do |l|
+                if l[0] == "-"
+                    offset -= 1
+                else
+                    offset += 1
+                end
+                result << [l[0], l[2]]
+            end
+        end
+        if (a.length - from) > 2
+            result += self.chunk(a, from, from+2)
+        elsif a.length > 0
+            result += self.chunk(a, from, a.length-1)
+        end
+        linecount = addcount = remcount = offset = current_offset = 0
+        info_index = nil
+        result.each_with_index do |l, i|
+            if l[0] == '@'
+                result[info_index] = self.record_stat(result, info_index, remcount, \
addcount,  +                    linecount, offset) if info_index
+                info_index = i
+                offset += addcount - remcount
+                linecount = 0
+                addcount = remcount = 0
+            elsif l[0] == '-'
+                remcount += 1
+                linecount += 1
+            elsif l[0] == '+'
+                addcount += 1
+                linecount += 1
+            else
+                linecount += 1
+            end
+        end
+        result[info_index] = self.record_stat(result, info_index, remcount, \
addcount, linecount, offset) if info_index +        return result.map{|x| \
x.join('')}.join("\n") +    end
+
+end
+
+end
diff --git a/parser/tests/assert_same/test/assert_same_test.rb \
b/parser/tests/assert_same/test/assert_same_test.rb new file mode 100644
index 0000000..bb61204
--- /dev/null
+++ b/parser/tests/assert_same/test/assert_same_test.rb
@@ -0,0 +1,18 @@
+# Copyright (c) 2011 Pluron, Inc.
+
+require 'test/unit'
+require 'lib/assert_same'
+
+class AssertSameTest < Test::Unit::TestCase
+
+    def test_basic_assert_same
+        assert_same "foo", <<-END
+            foo
+        END
+    end
+
+    def test_assert_same_with_files
+        assert_same "foo", :log => 'test/logs/assert_same_with_files.log.ref'
+    end
+
+end
diff --git a/parser/tests/assert_same/test/logs/assert_same_with_files.log.ref \
b/parser/tests/assert_same/test/logs/assert_same_with_files.log.ref new file mode \
100644 index 0000000..257cc56
--- /dev/null
+++ b/parser/tests/assert_same/test/logs/assert_same_with_files.log.ref
@@ -0,0 +1 @@
+foo


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic