From 817dd1030269d8cc0895008e3664ceb562eecdd2 Mon Sep 17 00:00:00 2001
From: "Emmanouil (Manos) Koukoutos" <emmanouil.koukoutos@epfl.ch>
Date: Fri, 13 Feb 2015 15:53:21 +0100
Subject: [PATCH] Repair regression tests

---
 .../regression/repair/Compiler1.scala         | 176 ++++++++
 .../resources/regression/repair/Heap4.scala   | 113 +++++
 .../resources/regression/repair/List1.scala   | 420 ++++++++++++++++++
 .../regression/repair/MergeSort2.scala        |  54 +++
 .../regression/repair/Numerical1.scala        |  53 +++
 .../scala/leon/test/repair/RepairSuite.scala  |  40 ++
 6 files changed, 856 insertions(+)
 create mode 100644 src/test/resources/regression/repair/Compiler1.scala
 create mode 100644 src/test/resources/regression/repair/Heap4.scala
 create mode 100644 src/test/resources/regression/repair/List1.scala
 create mode 100644 src/test/resources/regression/repair/MergeSort2.scala
 create mode 100644 src/test/resources/regression/repair/Numerical1.scala
 create mode 100644 src/test/scala/leon/test/repair/RepairSuite.scala

diff --git a/src/test/resources/regression/repair/Compiler1.scala b/src/test/resources/regression/repair/Compiler1.scala
new file mode 100644
index 000000000..2971855c7
--- /dev/null
+++ b/src/test/resources/regression/repair/Compiler1.scala
@@ -0,0 +1,176 @@
+import leon.lang._
+import leon.annotation._
+import leon.collection._
+import leon._
+
+object Trees {
+  abstract class Expr
+  case class Plus(lhs: Expr, rhs: Expr) extends Expr
+  case class Minus(lhs: Expr, rhs: Expr) extends Expr
+  case class LessThan(lhs: Expr, rhs: Expr) extends Expr
+  case class And(lhs: Expr, rhs: Expr) extends Expr
+  case class Or(lhs: Expr, rhs: Expr) extends Expr
+  case class Not(e : Expr) extends Expr
+  case class Eq(lhs: Expr, rhs: Expr) extends Expr
+  case class Ite(cond: Expr, thn: Expr, els: Expr) extends Expr
+  case class IntLiteral(v: Int) extends Expr
+  case class BoolLiteral(b : Boolean) extends Expr
+}
+
+object Types {
+  abstract class Type
+  case object IntType extends Type
+  case object BoolType extends Type
+}
+
+
+object TypeChecker {
+  import Trees._
+  import Types._
+
+  def typeOf(e :Expr) : Option[Type] = e match {
+    case Plus(l,r) => (typeOf(l), typeOf(r)) match {
+      case (Some(IntType), Some(IntType)) => Some(IntType)
+      case _ => None()
+    }
+    case Minus(l,r) => (typeOf(l), typeOf(r)) match {
+      case (Some(IntType), Some(IntType)) => Some(IntType)
+      case _ => None()
+    }
+    case LessThan(l,r) => ( typeOf(l), typeOf(r)) match {
+      case (Some(IntType), Some(IntType)) => Some(BoolType)
+      case _ => None()
+    }
+    case And(l,r) => ( typeOf(l), typeOf(r)) match {
+      case (Some(BoolType), Some(BoolType)) => Some(BoolType)
+      case _ => None()
+    }
+    case Or(l,r) => ( typeOf(l), typeOf(r)) match {
+      case (Some(BoolType), Some(BoolType)) => Some(BoolType)
+      case _ => None()
+    }
+    case Not(e) => typeOf(e) match {
+      case Some(BoolType) => Some(BoolType)
+      case _ => None()
+    }
+    case Eq(lhs, rhs) => (typeOf(lhs), typeOf(rhs)) match {
+      case (Some(t1), Some(t2)) if t1 == t2 => Some(BoolType)
+      case _ => None()
+    }
+    case Ite(c, th, el) => (typeOf(c), typeOf(th), typeOf(el)) match {
+      case (Some(BoolType), Some(t1), Some(t2)) if t1 == t2 => Some(t1)
+      case _ => None()
+    }
+    case IntLiteral(_) => Some(IntType)
+    case BoolLiteral(_) => Some(BoolType)
+  }
+
+  def typeChecks(e : Expr) = typeOf(e).isDefined
+}
+
+
+object Semantics {
+  import Trees._
+  import Types._
+  import TypeChecker._
+  
+  def semI(t : Expr) : Int = {
+    require( typeOf(t) == ( Some(IntType) : Option[Type] ))
+    t match {
+      case Plus(lhs , rhs) => semI(lhs) + semI(rhs)
+      case Minus(lhs , rhs) => semI(lhs) - semI(rhs)
+      case Ite(cond, thn, els) => 
+        if (semB(cond)) semI(thn) else semI(els)
+      case IntLiteral(v)   => v 
+    }
+  }
+
+  def semB(t : Expr) : Boolean = {
+    require( (Some(BoolType): Option[Type]) == typeOf(t))
+    t match {
+      case And(lhs, rhs ) => semB(lhs) && semB(rhs)
+      case Or(lhs , rhs ) => semB(lhs) || semB(rhs)
+      case Not(e) => !semB(e)
+      case LessThan(lhs, rhs) => semI(lhs) < semI(rhs)
+      case Ite(cond, thn, els) => 
+        if (semB(cond)) semB(thn) else semB(els)
+      case Eq(lhs, rhs) => (typeOf(lhs), typeOf(rhs)) match {
+        case ( Some(IntType),  Some(IntType)  ) => semI(lhs) == semI(rhs)
+        case ( Some(BoolType), Some(BoolType) ) => semB(lhs) == semB(rhs)
+      }
+      case BoolLiteral(b) => b
+    }
+  }
+ 
+  def b2i(b : Boolean) = if (b) 1 else 0
+
+  @induct
+  def semUntyped( t : Expr) : Int = { t match {
+    case Plus (lhs, rhs) => semUntyped(lhs) + semUntyped(rhs)
+    case Minus(lhs, rhs) => semUntyped(lhs) - semUntyped(rhs)
+    case And  (lhs, rhs) => if (semUntyped(lhs)!=0) semUntyped(rhs) else 0
+    case Or(lhs, rhs ) =>
+      if (semUntyped(lhs) == 0) semUntyped(rhs) else 1
+    case Not(e) =>
+      b2i(semUntyped(e) == 0)
+    case LessThan(lhs, rhs) => 
+      b2i(semUntyped(lhs) < semUntyped(rhs))
+    case Eq(lhs, rhs) => 
+      b2i(semUntyped(lhs) == semUntyped(rhs))
+    case Ite(cond, thn, els) => 
+      if (semUntyped(cond) == 0) semUntyped(els) else semUntyped(thn)
+    case IntLiteral(v)  => v 
+    case BoolLiteral(b) => b2i(b)
+  }} ensuring { res => typeOf(t) match {
+    case Some(IntType)  => res == semI(t)
+    case Some(BoolType) => res == b2i(semB(t))
+    case None() => true
+  }}
+
+}
+
+
+object Desugar {
+  import Types._
+  import TypeChecker._
+  import Semantics.b2i
+
+  abstract class SimpleE 
+  case class Plus(lhs : SimpleE, rhs : SimpleE) extends SimpleE
+  case class Neg(arg : SimpleE) extends SimpleE
+  case class Ite(cond : SimpleE, thn : SimpleE, els : SimpleE) extends SimpleE
+  case class Eq(lhs : SimpleE, rhs : SimpleE) extends SimpleE
+  case class LessThan(lhs : SimpleE, rhs : SimpleE) extends SimpleE
+  case class Literal(i : Int) extends SimpleE
+
+  @induct
+  def desugar(e : Trees.Expr) : SimpleE = { e match {
+    case Trees.Plus (lhs, rhs) => Neg(desugar(lhs)) // FIXME: Complete nonsense. Leon can't disprove it, uses example...
+    case Trees.Minus(lhs, rhs) => Plus(desugar(lhs), Neg(desugar(rhs)))
+    case Trees.LessThan(lhs, rhs) => LessThan(desugar(lhs), desugar(rhs))
+    case Trees.And  (lhs, rhs) => Ite(desugar(lhs), desugar(rhs), Literal(0)) 
+    case Trees.Or   (lhs, rhs) => Ite(desugar(lhs), Literal(1), desugar(rhs))
+    case Trees.Not(e) => Ite(desugar(e), Literal(0), Literal(1))
+    case Trees.Eq(lhs, rhs) =>
+      Eq(desugar(lhs), desugar(rhs))
+    case Trees.Ite(cond, thn, els) => Ite(desugar(cond), desugar(thn), desugar(els))
+    case Trees.IntLiteral(v)  => Literal(v)
+    case Trees.BoolLiteral(b) => Literal(b2i(b))
+  }} ensuring { res =>
+    ((e, res) passes {
+      case Trees.Plus(Trees.IntLiteral(i), Trees.Minus(Trees.IntLiteral(j), Trees.IntLiteral(42))) =>
+        Plus(Literal(i), Plus(Literal(j), Neg(Literal(42))))
+    }) &&
+    sem(res) == Semantics.semUntyped(e)
+  }
+
+  def sem(e : SimpleE) : Int = e match {
+    case Plus (lhs, rhs) => sem(lhs) + sem(rhs)
+    case Ite(cond, thn, els) => if (sem(cond) != 0) sem(thn) else sem(els)
+    case Neg(arg) => -sem(arg) 
+    case Eq(lhs,rhs) => b2i(sem(lhs) == sem(rhs))
+    case LessThan(lhs, rhs) => b2i(sem(lhs) < sem(rhs))
+    case Literal(i) => i
+  }
+
+}
diff --git a/src/test/resources/regression/repair/Heap4.scala b/src/test/resources/regression/repair/Heap4.scala
new file mode 100644
index 000000000..a19ff6c20
--- /dev/null
+++ b/src/test/resources/regression/repair/Heap4.scala
@@ -0,0 +1,113 @@
+/* Copyright 2009-2013 EPFL, Lausanne
+ *
+ * Author: Ravi
+ * Date: 20.11.2013
+ **/
+
+import leon.collection._
+import leon._ 
+
+object HeapSort {
+ 
+  sealed abstract class Heap {
+    val rank : Int = this match {
+      case Leaf() => 0
+      case Node(_, l, r) => 
+        1 + max(l.rank, r.rank)
+    }
+    def content : Set[Int] = this match {
+      case Leaf() => Set[Int]()
+      case Node(v,l,r) => l.content ++ Set(v) ++ r.content
+    }
+  }
+  case class Leaf() extends Heap
+  case class Node(value:Int, left: Heap, right: Heap) extends Heap
+
+  def max(i1 : Int, i2 : Int) = if (i1 >= i2) i1 else i2
+
+  def hasHeapProperty(h : Heap) : Boolean = h match {
+    case Leaf() => true
+    case Node(v, l, r) => 
+      ( l match {
+        case Leaf() => true
+        case n@Node(v2,_,_) => v >= v2 && hasHeapProperty(n)
+      }) && 
+      ( r match {
+        case Leaf() => true
+        case n@Node(v2,_,_) => v >= v2 && hasHeapProperty(n)
+      })
+  }
+
+  def hasLeftistProperty(h: Heap) : Boolean = h match {
+    case Leaf() => true
+    case Node(_,l,r) => 
+      hasLeftistProperty(l) && 
+      hasLeftistProperty(r) && 
+      l.rank >= r.rank 
+  }
+
+  def heapSize(t: Heap): Int = { t match {
+    case Leaf() => 0
+    case Node(v, l, r) => heapSize(l) + 1 + heapSize(r)
+  }} ensuring(_ >= 0)
+
+  private def merge(h1: Heap, h2: Heap) : Heap = {
+    require(
+      hasLeftistProperty(h1) && hasLeftistProperty(h2) && 
+      hasHeapProperty(h1) && hasHeapProperty(h2)
+    )
+    (h1,h2) match {
+      case (Leaf(), _) => h2
+      case (_, Leaf()) => h2 // FIXME h2 instead of h1
+      case (Node(v1, l1, r1), Node(v2, l2, r2)) =>
+        if(v1 >= v2)
+          makeN(v1, l1, merge(r1, h2))
+        else
+          makeN(v2, l2, merge(h1, r2))
+    }
+  } ensuring { res => 
+    hasLeftistProperty(res) && hasHeapProperty(res) &&
+    heapSize(h1) + heapSize(h2) == heapSize(res) &&
+    h1.content ++ h2.content == res.content 
+  }
+
+  private def makeN(value: Int, left: Heap, right: Heap) : Heap = {
+    require(
+      hasLeftistProperty(left) && hasLeftistProperty(right)
+    )
+    if(left.rank >= right.rank)
+      Node(value, left, right)
+    else
+      Node(value, right, left)
+  } ensuring { res =>
+    hasLeftistProperty(res)  }
+
+  def insert(element: Int, heap: Heap) : Heap = {
+    require(hasLeftistProperty(heap) && hasHeapProperty(heap))
+
+    merge(Node(element, Leaf(), Leaf()), heap)
+
+  } ensuring { res =>
+    hasLeftistProperty(res) && hasHeapProperty(res) &&
+    heapSize(res) == heapSize(heap) + 1 &&
+    res.content == heap.content ++ Set(element)
+  }
+
+  def findMax(h: Heap) : Option[Int] = {
+    h match {
+      case Node(m,_,_) => Some(m)
+      case Leaf() => None()
+    }
+  }
+
+  def removeMax(h: Heap) : Heap = {
+    require(hasLeftistProperty(h) && hasHeapProperty(h))
+    h match {
+      case Node(_,l,r) => merge(l, r)
+      case l => l
+    }
+  } ensuring { res =>
+    hasLeftistProperty(res) && hasHeapProperty(res)
+  }
+
+} 
diff --git a/src/test/resources/regression/repair/List1.scala b/src/test/resources/regression/repair/List1.scala
new file mode 100644
index 000000000..1e18ca898
--- /dev/null
+++ b/src/test/resources/regression/repair/List1.scala
@@ -0,0 +1,420 @@
+/* Copyright 2009-2014 EPFL, Lausanne */
+
+package leon.custom
+
+import leon._
+import leon.lang._
+import leon.annotation._
+
+sealed abstract class List0[T] {
+  def size: Int = (this match {
+    case Nil0() => 0
+    case Cons0(h, t) => 1 + t.size
+  }) ensuring (_ >= 0)
+
+  def content: Set[T] = this match {
+    case Nil0() => Set()
+    case Cons0(h, t) => Set(h) ++ t.content
+  }
+
+  def contains(v: T): Boolean = (this match {
+    case Cons0(h, t) if h == v => true
+    case Cons0(_, t) => t.contains(v)
+    case Nil0() => false
+  }) ensuring { res => res == (content contains v) }
+
+  def ++(that: List0[T]): List0[T] = (this match {
+    case Nil0() => that
+    case Cons0(x, xs) => Cons0(x, xs ++ that)
+  }) ensuring { res => (res.content == this.content ++ that.content) && (res.size == this.size + that.size)}
+
+  def head: T = {
+    require(this != Nil0[T]())
+    this match {
+      case Cons0(h, t) => h
+    }
+  }
+
+  def tail: List0[T] = {
+    require(this != Nil0[T]())
+    this match {
+      case Cons0(h, t) => t
+    }
+  }
+
+  def apply(index: Int): T = {
+    require(0 <= index && index < size)
+    if (index == 0) {
+      head
+    } else {
+       tail(index-1)
+    }
+  }
+
+  def ::(t:T): List0[T] = Cons0(t, this)
+
+  def :+(t:T): List0[T] = {
+    this match {
+      case Nil0() => Cons0(t, this)
+      case Cons0(x, xs) => Cons0(x, xs :+ (t))
+    }
+  } ensuring(res => (res.size == size + 1) && (res.content == content ++ Set(t)))
+
+  def reverse: List0[T] = {
+    this match {
+      case Nil0() => this
+      case Cons0(x,xs) => xs.reverse :+ x
+    }
+  } ensuring (res => (res.size == size) && (res.content == content))
+
+  def take(i: Int): List0[T] = (this, i) match {
+    case (Nil0(), _) => Nil0()
+    case (Cons0(h, t), i) =>
+      if (i == 0) {
+        Nil0()
+      } else {
+        Cons0(h, t.take(i-1))
+      }
+  }
+
+  def drop(i: Int): List0[T] = (this, i) match {
+    case (Nil0(), _) => Nil0()
+    case (Cons0(h, t), i) =>
+      if (i == 0) {
+        Cons0(h, t)
+      } else {
+        t.drop(i-1)
+      }
+  }
+
+  def slice(from: Int, to: Int): List0[T] = {
+    require(from < to && to < size && from >= 0)
+    drop(from).take(to-from)
+  }
+
+  def replace(from: T, to: T): List0[T] = this match {
+    case Nil0() => Nil0()
+    case Cons0(h, t) =>
+      val r = t.replace(from, to)
+      if (h == from) {
+        Cons0(to, r)
+      } else {
+        Cons0(h, r)
+      }
+  }
+
+  private def chunk0(s: Int, l: List0[T], acc: List0[T], res: List0[List0[T]], s0: Int): List0[List0[T]] = l match {
+    case Nil0() =>
+      if (acc.size > 0) {
+        res :+ acc
+      } else {
+        res
+      }
+    case Cons0(h, t) =>
+      if (s0 == 0) {
+        chunk0(s, l, Nil0(), res :+ acc, s)
+      } else {
+        chunk0(s, t, acc :+ h, res, s0-1)
+      }
+  }
+
+  def chunks(s: Int): List0[List0[T]] = {
+    require(s > 0)
+
+    chunk0(s, this, Nil0(), Nil0(), s)
+  }
+
+  def zip[B](that: List0[B]): List0[(T, B)] = (this, that) match {
+    case (Cons0(h1, t1), Cons0(h2, t2)) =>
+      Cons0((h1, h2), t1.zip(t2))
+    case (_) =>
+      Nil0()
+  }
+
+  def -(e: T): List0[T] = this match {
+    case Cons0(h, t) =>
+      if (e == h) {
+        t - e
+      } else {
+        Cons0(h, t - e)
+      }
+    case Nil0() =>
+      Nil0()
+  }
+
+  def --(that: List0[T]): List0[T] = this match {
+    case Cons0(h, t) =>
+      if (that.contains(h)) {
+        t -- that
+      } else {
+        Cons0(h, t -- that)
+      }
+    case Nil0() =>
+      Nil0()
+  }
+
+  def &(that: List0[T]): List0[T] = this match {
+    case Cons0(h, t) =>
+      if (that.contains(h)) {
+        Cons0(h, t & that)
+      } else {
+        t & that
+      }
+    case Nil0() =>
+      Nil0()
+  }
+
+  def pad(s: Int, e: T): List0[T] = { (this, s) match {
+    case (_, s) if s <= 0 =>
+      this
+    case (Nil0(), s) =>
+      Cons0(e, Nil0().pad(s-1, e))
+    case (Cons0(h, t), s) =>
+      Cons0(h, t.pad(s-1, e)) // FIXME should be s
+  }} ensuring { res =>
+    ((this,s,e), res) passes {
+      case (Cons0(a,Nil0()), 2, x) => Cons0(a, Cons0(x, Cons0(x, Nil0())))
+    }
+  }
+
+  def find(e: T): Option[Int] = this match {
+    case Nil0() => None()
+    case Cons0(h, t) =>
+      if (h == e) {
+        Some(0)
+      } else {
+        t.find(e) match {
+          case None()  => None()
+          case Some(i) => Some(i+1)
+        }
+      }
+  }
+
+  def init: List0[T] = (this match {
+    case Cons0(h, Nil0()) =>
+      Nil0[T]()
+    case Cons0(h, t) =>
+      Cons0[T](h, t.init)
+    case Nil0() =>
+      Nil0[T]()
+  }) ensuring ( (r: List0[T]) => ((r.size < this.size) || (this.size == 0)) )
+
+  def lastOption: Option[T] = this match {
+    case Cons0(h, t) =>
+      t.lastOption.orElse(Some(h))
+    case Nil0() =>
+      None()
+  }
+
+  def firstOption: Option[T] = this match {
+    case Cons0(h, t) =>
+      Some(h)
+    case Nil0() =>
+      None()
+  }
+
+  def unique: List0[T] = this match {
+    case Nil0() => Nil0()
+    case Cons0(h, t) =>
+      Cons0(h, t.unique - h)
+  }
+
+  def splitAt(e: T): List0[List0[T]] =  split(Cons0(e, Nil0()))
+
+  def split(seps: List0[T]): List0[List0[T]] = this match {
+    case Cons0(h, t) =>
+      if (seps.contains(h)) {
+        Cons0(Nil0(), t.split(seps))
+      } else {
+        val r = t.split(seps)
+        Cons0(Cons0(h, r.head), r.tail)
+      }
+    case Nil0() =>
+      Cons0(Nil0(), Nil0())
+  }
+
+  def count(e: T): Int = this match {
+    case Cons0(h, t) =>
+      if (h == e) {
+        1 + t.count(e)
+      } else {
+        t.count(e)
+      }
+    case Nil0() =>
+      0
+  }
+
+  def evenSplit: (List0[T], List0[T]) = {
+    val c = size/2
+    (take(c), drop(c))
+  }
+
+  def insertAt(pos: Int, l: List0[T]): List0[T] = {
+    if(pos < 0) {
+      insertAt(size + pos, l)
+    } else if(pos == 0) {
+      l ++ this
+    } else {
+      this match {
+        case Cons0(h, t) =>
+          Cons0(h, t.insertAt(pos-1, l))
+        case Nil0() =>
+          l
+      }
+    }
+  }
+
+  def replaceAt(pos: Int, l: List0[T]): List0[T] = {
+    if(pos < 0) {
+      replaceAt(size + pos, l)
+    } else if(pos == 0) {
+      l ++ this.drop(l.size)
+    } else {
+      this match {
+        case Cons0(h, t) =>
+          Cons0(h, t.replaceAt(pos-1, l))
+        case Nil0() =>
+          l
+      }
+    }
+  }
+
+  def rotate(s: Int): List0[T] = {
+    if (s < 0) {
+      rotate(size+s)
+    } else {
+      val s2 = s % size
+      drop(s2) ++ take(s2)
+    }
+  }
+
+  def isEmpty = this match { 
+    case Nil0() => true
+    case _ => false 
+  }
+
+}
+
+@ignore
+object List0 {
+  def apply[T](elems: T*): List0[T] = ???
+}
+
+@library
+object List0Ops {
+  def flatten[T](ls: List0[List0[T]]): List0[T] = ls match {
+    case Cons0(h, t) => h ++ flatten(t)
+    case Nil0() => Nil0()
+  }
+
+  def isSorted(ls: List0[Int]): Boolean = ls match {
+    case Nil0() => true
+    case Cons0(_, Nil0()) => true
+    case Cons0(h1, Cons0(h2, _)) if(h1 > h2) => false
+    case Cons0(_, t) => isSorted(t)
+  }
+
+  def sorted(ls: List0[Int]): List0[Int] = ls match {
+    case Cons0(h, t) => insSort(sorted(t), h)
+    case Nil0() => Nil0()
+  }
+
+  def insSort(ls: List0[Int], v: Int): List0[Int] = ls match {
+    case Nil0() => Cons0(v, Nil0())
+    case Cons0(h, t) =>
+      if (v <= h) {
+        Cons0(v, t)
+      } else {
+        Cons0(h, insSort(t, v))
+      }
+  }
+}
+
+
+case class Cons0[T](h: T, t: List0[T]) extends List0[T]
+case class Nil0[T]() extends List0[T]
+
+@library
+object List0Specs {
+  def snocIndex[T](l : List0[T], t : T, i : Int) : Boolean = {
+    require(0 <= i && i < l.size + 1)
+    // proof:
+    (l match {
+      case Nil0() => true
+      case Cons0(x, xs) => if (i > 0) snocIndex[T](xs, t, i-1) else true
+    }) &&
+    // claim:
+    ((l :+ t).apply(i) == (if (i < l.size) l(i) else t))
+  }.holds
+
+  def reverseIndex[T](l : List0[T], i : Int) : Boolean = {
+    require(0 <= i && i < l.size)
+    (l match {
+      case Nil0() => true
+      case Cons0(x,xs) => snocIndex(l, x, i) && reverseIndex[T](l,i)
+    }) &&
+    (l.reverse.apply(i) == l.apply(l.size - 1 - i))
+  }.holds
+
+  def appendIndex[T](l1 : List0[T], l2 : List0[T], i : Int) : Boolean = {
+    require(0 <= i && i < l1.size + l2.size)
+    (l1 match {
+      case Nil0() => true
+      case Cons0(x,xs) => if (i==0) true else appendIndex[T](xs,l2,i-1)
+    }) &&
+    ((l1 ++ l2).apply(i) == (if (i < l1.size) l1(i) else l2(i - l1.size)))
+  }.holds
+
+  def appendAssoc[T](l1 : List0[T], l2 : List0[T], l3 : List0[T]) : Boolean = {
+    (l1 match {
+      case Nil0() => true
+      case Cons0(x,xs) => appendAssoc(xs,l2,l3)
+    }) &&
+    (((l1 ++ l2) ++ l3) == (l1 ++ (l2 ++ l3)))
+  }.holds
+
+  def snocIsAppend[T](l : List0[T], t : T) : Boolean = {
+    (l match {
+      case Nil0() => true
+      case Cons0(x,xs) =>  snocIsAppend(xs,t)
+    }) &&
+    ((l :+ t) == l ++ Cons0[T](t, Nil0()))
+  }.holds
+
+  def snocAfterAppend[T](l1 : List0[T], l2 : List0[T], t : T) : Boolean = {
+    (l1 match {
+      case Nil0() => true
+      case Cons0(x,xs) =>  snocAfterAppend(xs,l2,t)
+    }) &&
+    ((l1 ++ l2) :+ t == (l1 ++ (l2 :+ t)))
+  }.holds
+
+  def snocReverse[T](l : List0[T], t : T) : Boolean = {
+    (l match {
+      case Nil0() => true
+      case Cons0(x,xs) => snocReverse(xs,t)
+    }) &&
+    ((l :+ t).reverse == Cons0(t, l.reverse))
+  }.holds
+
+  def reverseReverse[T](l : List0[T]) : Boolean = {
+    (l match {
+      case Nil0() => true
+      case Cons0(x,xs) => reverseReverse[T](xs) && snocReverse[T](xs.reverse, x)
+    }) &&
+    (l.reverse.reverse == l)
+  }.holds
+
+  //// my hand calculation shows this should work, but it does not seem to be found
+  //def reverseAppend[T](l1 : List0[T], l2 : List0[T]) : Boolean = {
+  //  (l1 match {
+  //    case Nil0() => true
+  //    case Cons0(x,xs) => {
+  //      reverseAppend(xs,l2) &&
+  //      snocAfterAppend[T](l2.reverse, xs.reverse, x) &&
+  //      l1.reverse == (xs.reverse :+ x)
+  //    }
+  //  }) &&
+  //  ((l1 ++ l2).reverse == (l2.reverse ++ l1.reverse))
+  //}.holds
+}
diff --git a/src/test/resources/regression/repair/MergeSort2.scala b/src/test/resources/regression/repair/MergeSort2.scala
new file mode 100644
index 000000000..d9966ecdc
--- /dev/null
+++ b/src/test/resources/regression/repair/MergeSort2.scala
@@ -0,0 +1,54 @@
+import leon.collection._
+
+object MergeSort {
+
+  def split(l : List[Int]) : (List[Int],List[Int]) = { l match {
+    case Cons(a, Cons(b, t)) => 
+      val (rec1, rec2) = split(t)
+      (Cons(a, rec1), Cons(b, rec2))
+    case other => (other, Nil())
+  }} ensuring { res =>
+    val (l1, l2) = res
+    l1.size >= l2.size &&
+    l1.size <= l2.size + 1 &&
+    l1.size + l2.size == l.size &&
+    l1.content ++ l2.content == l.content
+  }
+
+  def isSorted(l : List[Int]) : Boolean = l match {
+    case Cons(x, t@Cons(y, _)) => x <= y && isSorted(t)
+    case _ => true
+  }
+
+  def merge(l1 : List[Int], l2 : List[Int]) : List[Int] = {
+    require(isSorted(l1) && isSorted(l2))
+    (l1, l2) match {
+      case (Cons(h1, t1), Cons(h2,t2)) => 
+        if (h1 <= h2) 
+          Cons(h1, merge(t1, l2))
+        else 
+          Cons(h1, merge(l1, t2)) // FIXME h1 instead of h2
+      case (Nil(), _) => l2
+      case (_, Nil()) => l1
+    }
+  } ensuring { res =>
+    isSorted(res) &&
+    res.size == l1.size + l2.size  &&
+    res.content == l1.content ++ l2.content
+  }
+
+  def mergeSort(l : List[Int]) : List[Int] = { l match {
+    case Nil() => l
+    case Cons(_, Nil()) => l
+    case other =>
+      val (l1, l2) = split(other)
+      merge(mergeSort(l1), mergeSort(l2))
+  }} ensuring { res =>
+    isSorted(res) &&
+    res.content == l.content &&
+    res.size == l.size
+  }
+}
+
+
+
diff --git a/src/test/resources/regression/repair/Numerical1.scala b/src/test/resources/regression/repair/Numerical1.scala
new file mode 100644
index 000000000..4f1a32f8b
--- /dev/null
+++ b/src/test/resources/regression/repair/Numerical1.scala
@@ -0,0 +1,53 @@
+/* Copyright 2009-2014 EPFL, Lausanne */
+
+import leon._
+import leon.lang._
+import leon.annotation._
+
+object Numerical {
+  def power(base: Int, p: Int): Int = {
+    require(p >= 0)
+    if (p == 0) {
+      1
+    } else if (p%2 == 0) {
+      power(base*base, p/2)
+    } else {
+      power(base, p-1) // fixme: Missing base*
+    }
+  } ensuring {
+    res => ((base, p), res) passes {
+      case (_, 0) => 1
+      case (b, 1) => b
+      case (2, 7) => 128
+      case (2, 10) => 1024
+    }
+  }
+
+  def gcd(a: Int, b: Int): Int = {
+    require(a > 0 && b > 0);
+
+    if (a == b) {
+      a
+    } else if (a > b) {
+      gcd(a-b, b)
+    } else {
+      gcd(a, b-a)
+    }
+  } ensuring {
+    res => (a%res == 0) && (b%res == 0) && (((a,b), res) passes {
+      case (468, 24) => 12
+    })
+  }
+
+  def moddiv(a: Int, b: Int): (Int, Int) = {
+    require(a >= 0 && b > 0);
+    if (b > a) {
+      (a, 0)
+    } else {
+      val (r1, r2) = moddiv(a-b, b)
+      (r1, r2+1)
+    }
+  } ensuring {
+    res =>  b*res._2 + res._1 == a
+  }
+}
diff --git a/src/test/scala/leon/test/repair/RepairSuite.scala b/src/test/scala/leon/test/repair/RepairSuite.scala
new file mode 100644
index 000000000..a68249dcf
--- /dev/null
+++ b/src/test/scala/leon/test/repair/RepairSuite.scala
@@ -0,0 +1,40 @@
+package leon.test.repair
+
+import leon.test._
+import leon._
+import leon.utils._
+import leon.frontends.scalac.ExtractionPhase
+import leon.repair._
+
+class RepairSuite extends LeonTestSuite {
+  val pipeline = ExtractionPhase andThen 
+    PreprocessingPhase andThen
+    RepairPhase
+    
+  val settings = Settings(verify = false, repair = true)
+  val reporter = new DefaultReporter(settings)
+  val ctx0 = LeonContext(
+    reporter,
+    new InterruptManager(reporter)
+  )
+  
+  val fileToFun = Map(
+    "Compiler1.scala"   -> "desugar",
+    "Heap4.scala"       -> "merge",
+    "List1.scala"       -> "_pad",
+    "Numerical1.scala"  -> "power",
+    "MergeSort2.scala"  -> "merge"
+  )
+  
+  for (file <- filesInResourceDir("regression/repair/")) {
+    val path = file.getAbsoluteFile().toString
+    val name = file.getName()
+    val option = LeonValueOption("functions", fileToFun(name))
+    val ctx = ctx0.copy(options = option +: ctx0.options)
+    test(name) {
+      pipeline.run(ctx)(List(path))
+    }
+  }
+    
+  
+}
\ No newline at end of file
-- 
GitLab