From 473a1692abf4d64e5df81cd19be214fe5bfa06ec Mon Sep 17 00:00:00 2001 From: Adriaan Moors Date: Fri, 19 Jul 2013 17:33:17 -0700 Subject: Move partest to https://github.com/scala/scala-partest As partest is now resolved from maven, `test/partest` uses `ant test.suite.init` to determine the classpath (serialized to build/pack/partest.properties) that's necessary to run `scala.tools.partest.nest.ConsoleRunner`. Thus, partest gets exactly the same classpath, whether run from the command line through `test/partest` or via `ant test`. The version of partest we're using is specified by properties defined in versions.properties (formerly `starr.number`). Currently, we're using: ``` scala.binary.version=2.11.0-M4 partest.version.number=1.0-RC3 ``` NOTES: - The version of Scala being tested must be backwards binary compatible with the version of Scala that was used to compile partest. - Once 2.11 goes final, `scala.binary.version=2.11`, and `starr.version=2.11.0`. - Need scalacheck on classpath for test/partest scalacheck tests. - Removed atrophied ant tests (haven't been run/changed for at least two years I checked 81d659141a as a "random" sample). - Removed scalacheck. It's resolved as a partest dependency. - For now, use a locally built scalap - Kept the trace macro in the main repo (partest-extras) - New targets for faster pr validation: test-core-opt, test-stab-opt - Reused partest eclipse/intellij project to partest-extras (note: the partest dependency is hard-coded) --- src/build/dbuild-meta-json-gen.scala | 11 +- src/build/maven/maven-deploy.xml | 1 - src/build/maven/scala-partest-pom.xml | 62 -- src/build/pack.xml | 5 - src/eclipse/partest/.classpath | 6 +- src/eclipse/partest/.project | 10 +- src/intellij/partest.iml.SAMPLE | 10 +- .../scala/tools/partest/ASMConverters.scala | 71 ++ .../scala/tools/partest/AsmNode.scala | 61 ++ .../scala/tools/partest/BytecodeTest.scala | 167 ++++ .../scala/tools/partest/JavapTest.scala | 26 + .../scala/tools/partest/ReplTest.scala | 43 + .../scala/tools/partest/SigTest.scala | 52 ++ src/partest-extras/scala/tools/partest/Util.scala | 52 ++ .../partest/instrumented/Instrumentation.scala | 93 +++ .../scala/tools/partest/instrumented/Profiler.java | 82 ++ .../tools/partest/javaagent/ASMTransformer.java | 49 ++ .../scala/tools/partest/javaagent/MANIFEST.MF | 1 + .../tools/partest/javaagent/ProfilerVisitor.java | 59 ++ .../tools/partest/javaagent/ProfilingAgent.java | 25 + src/partest/README | 31 - .../scala/tools/partest/ASMConverters.scala | 71 -- src/partest/scala/tools/partest/AsmNode.scala | 61 -- src/partest/scala/tools/partest/BytecodeTest.scala | 167 ---- src/partest/scala/tools/partest/CompilerTest.scala | 60 -- src/partest/scala/tools/partest/DirectTest.scala | 128 --- src/partest/scala/tools/partest/IcodeTest.scala | 43 - src/partest/scala/tools/partest/JavapTest.scala | 26 - src/partest/scala/tools/partest/MemoryTest.scala | 38 - .../scala/tools/partest/PartestDefaults.scala | 28 - src/partest/scala/tools/partest/PartestTask.scala | 207 ----- src/partest/scala/tools/partest/ReplTest.scala | 44 - src/partest/scala/tools/partest/SecurityTest.scala | 19 - src/partest/scala/tools/partest/SigTest.scala | 52 -- .../tools/partest/StoreReporterDirectTest.scala | 15 - src/partest/scala/tools/partest/TestKinds.scala | 66 -- src/partest/scala/tools/partest/TestState.scala | 64 -- src/partest/scala/tools/partest/TestUtil.scala | 38 - src/partest/scala/tools/partest/antlib.xml | 4 - .../partest/instrumented/Instrumentation.scala | 93 --- .../scala/tools/partest/instrumented/Profiler.java | 82 -- .../tools/partest/javaagent/ASMTransformer.java | 49 -- .../scala/tools/partest/javaagent/MANIFEST.MF | 1 - .../tools/partest/javaagent/ProfilerVisitor.java | 59 -- .../tools/partest/javaagent/ProfilingAgent.java | 25 - .../scala/tools/partest/nest/AntRunner.scala | 30 - .../tools/partest/nest/ConsoleFileManager.scala | 189 ----- .../scala/tools/partest/nest/ConsoleRunner.scala | 219 ----- .../tools/partest/nest/ConsoleRunnerSpec.scala | 54 -- .../scala/tools/partest/nest/DirectCompiler.scala | 105 --- .../scala/tools/partest/nest/FileManager.scala | 165 ---- .../scala/tools/partest/nest/NestRunner.scala | 15 - src/partest/scala/tools/partest/nest/NestUI.scala | 181 ----- .../scala/tools/partest/nest/PathSettings.scala | 88 -- .../tools/partest/nest/ReflectiveRunner.scala | 99 --- src/partest/scala/tools/partest/nest/Runner.scala | 883 --------------------- .../scala/tools/partest/nest/SBTRunner.scala | 85 -- .../scala/tools/partest/nest/StreamCapture.scala | 53 -- src/partest/scala/tools/partest/package.scala | 241 ------ .../scala/tools/partest/utils/Properties.scala | 18 - src/scalacheck/org/scalacheck/Arbitrary.scala | 447 ----------- src/scalacheck/org/scalacheck/Arg.scala | 20 - src/scalacheck/org/scalacheck/Commands.scala | 148 ---- .../org/scalacheck/ConsoleReporter.scala | 52 -- src/scalacheck/org/scalacheck/Gen.scala | 542 ------------- src/scalacheck/org/scalacheck/Pretty.scala | 127 --- src/scalacheck/org/scalacheck/Prop.scala | 818 ------------------- src/scalacheck/org/scalacheck/Properties.scala | 96 --- .../org/scalacheck/ScalaCheckFramework.scala | 92 --- src/scalacheck/org/scalacheck/Shrink.scala | 208 ----- src/scalacheck/org/scalacheck/Test.scala | 392 --------- src/scalacheck/org/scalacheck/util/Buildable.scala | 63 -- .../org/scalacheck/util/CmdLineParser.scala | 101 --- src/scalacheck/org/scalacheck/util/FreqMap.scala | 65 -- src/scalacheck/org/scalacheck/util/StdRand.scala | 12 - 75 files changed, 792 insertions(+), 7173 deletions(-) delete mode 100644 src/build/maven/scala-partest-pom.xml create mode 100644 src/partest-extras/scala/tools/partest/ASMConverters.scala create mode 100644 src/partest-extras/scala/tools/partest/AsmNode.scala create mode 100644 src/partest-extras/scala/tools/partest/BytecodeTest.scala create mode 100644 src/partest-extras/scala/tools/partest/JavapTest.scala create mode 100644 src/partest-extras/scala/tools/partest/ReplTest.scala create mode 100644 src/partest-extras/scala/tools/partest/SigTest.scala create mode 100644 src/partest-extras/scala/tools/partest/Util.scala create mode 100644 src/partest-extras/scala/tools/partest/instrumented/Instrumentation.scala create mode 100644 src/partest-extras/scala/tools/partest/instrumented/Profiler.java create mode 100644 src/partest-javaagent/scala/tools/partest/javaagent/ASMTransformer.java create mode 100644 src/partest-javaagent/scala/tools/partest/javaagent/MANIFEST.MF create mode 100644 src/partest-javaagent/scala/tools/partest/javaagent/ProfilerVisitor.java create mode 100644 src/partest-javaagent/scala/tools/partest/javaagent/ProfilingAgent.java delete mode 100644 src/partest/README delete mode 100644 src/partest/scala/tools/partest/ASMConverters.scala delete mode 100644 src/partest/scala/tools/partest/AsmNode.scala delete mode 100644 src/partest/scala/tools/partest/BytecodeTest.scala delete mode 100644 src/partest/scala/tools/partest/CompilerTest.scala delete mode 100644 src/partest/scala/tools/partest/DirectTest.scala delete mode 100644 src/partest/scala/tools/partest/IcodeTest.scala delete mode 100644 src/partest/scala/tools/partest/JavapTest.scala delete mode 100644 src/partest/scala/tools/partest/MemoryTest.scala delete mode 100644 src/partest/scala/tools/partest/PartestDefaults.scala delete mode 100644 src/partest/scala/tools/partest/PartestTask.scala delete mode 100644 src/partest/scala/tools/partest/ReplTest.scala delete mode 100644 src/partest/scala/tools/partest/SecurityTest.scala delete mode 100644 src/partest/scala/tools/partest/SigTest.scala delete mode 100644 src/partest/scala/tools/partest/StoreReporterDirectTest.scala delete mode 100644 src/partest/scala/tools/partest/TestKinds.scala delete mode 100644 src/partest/scala/tools/partest/TestState.scala delete mode 100644 src/partest/scala/tools/partest/TestUtil.scala delete mode 100644 src/partest/scala/tools/partest/antlib.xml delete mode 100644 src/partest/scala/tools/partest/instrumented/Instrumentation.scala delete mode 100644 src/partest/scala/tools/partest/instrumented/Profiler.java delete mode 100644 src/partest/scala/tools/partest/javaagent/ASMTransformer.java delete mode 100644 src/partest/scala/tools/partest/javaagent/MANIFEST.MF delete mode 100644 src/partest/scala/tools/partest/javaagent/ProfilerVisitor.java delete mode 100644 src/partest/scala/tools/partest/javaagent/ProfilingAgent.java delete mode 100644 src/partest/scala/tools/partest/nest/AntRunner.scala delete mode 100644 src/partest/scala/tools/partest/nest/ConsoleFileManager.scala delete mode 100644 src/partest/scala/tools/partest/nest/ConsoleRunner.scala delete mode 100644 src/partest/scala/tools/partest/nest/ConsoleRunnerSpec.scala delete mode 100644 src/partest/scala/tools/partest/nest/DirectCompiler.scala delete mode 100644 src/partest/scala/tools/partest/nest/FileManager.scala delete mode 100644 src/partest/scala/tools/partest/nest/NestRunner.scala delete mode 100644 src/partest/scala/tools/partest/nest/NestUI.scala delete mode 100644 src/partest/scala/tools/partest/nest/PathSettings.scala delete mode 100644 src/partest/scala/tools/partest/nest/ReflectiveRunner.scala delete mode 100644 src/partest/scala/tools/partest/nest/Runner.scala delete mode 100644 src/partest/scala/tools/partest/nest/SBTRunner.scala delete mode 100644 src/partest/scala/tools/partest/nest/StreamCapture.scala delete mode 100644 src/partest/scala/tools/partest/package.scala delete mode 100644 src/partest/scala/tools/partest/utils/Properties.scala delete mode 100644 src/scalacheck/org/scalacheck/Arbitrary.scala delete mode 100644 src/scalacheck/org/scalacheck/Arg.scala delete mode 100644 src/scalacheck/org/scalacheck/Commands.scala delete mode 100644 src/scalacheck/org/scalacheck/ConsoleReporter.scala delete mode 100644 src/scalacheck/org/scalacheck/Gen.scala delete mode 100644 src/scalacheck/org/scalacheck/Pretty.scala delete mode 100644 src/scalacheck/org/scalacheck/Prop.scala delete mode 100644 src/scalacheck/org/scalacheck/Properties.scala delete mode 100644 src/scalacheck/org/scalacheck/ScalaCheckFramework.scala delete mode 100644 src/scalacheck/org/scalacheck/Shrink.scala delete mode 100644 src/scalacheck/org/scalacheck/Test.scala delete mode 100644 src/scalacheck/org/scalacheck/util/Buildable.scala delete mode 100644 src/scalacheck/org/scalacheck/util/CmdLineParser.scala delete mode 100644 src/scalacheck/org/scalacheck/util/FreqMap.scala delete mode 100644 src/scalacheck/org/scalacheck/util/StdRand.scala (limited to 'src') diff --git a/src/build/dbuild-meta-json-gen.scala b/src/build/dbuild-meta-json-gen.scala index 42214dd191..73eee8ac3a 100644 --- a/src/build/dbuild-meta-json-gen.scala +++ b/src/build/dbuild-meta-json-gen.scala @@ -1,6 +1,6 @@ // use this script to generate dbuild-meta.json // make sure the version is specified correctly, -// update the dependency structura and +// update the dependency structure and // check out distributed-build and run `sbt console`: // TODO: also generate build.xml and eclipse config from a similar data-structure @@ -40,15 +40,6 @@ val meta = Seq(ProjectRef("scala-parser-combinators", "org.scala-lang")), Seq(ProjectRef("scala-library", "org.scala-lang"))), - Project("scalacheck", "org.scala-lang", - Seq(ProjectRef("scalacheck", "org.scala-lang")), - Seq(ProjectRef("scala-library", "org.scala-lang"), ProjectRef("scala-actors", "org.scala-lang"), ProjectRef("scala-parser-combinators", "org.scala-lang"))), - - Project("scala-partest", "org.scala-lang", - Seq(ProjectRef("scala-partest", "org.scala-lang")), - Seq(ProjectRef("scala-compiler", "org.scala-lang"), // TODO: refine to scala-repl - ProjectRef("scalap", "org.scala-lang"), ProjectRef("scala-xml", "org.scala-lang"), ProjectRef("scalacheck", "org.scala-lang"))), - Project("scaladoc", "org.scala-lang", Seq(ProjectRef("scaladoc", "org.scala-lang")), Seq(ProjectRef("scala-compiler", "org.scala-lang"),ProjectRef("scala-partest", "org.scala-lang"), ProjectRef("scala-xml", "org.scala-lang"), ProjectRef("scala-parser-combinators", "org.scala-lang"))), diff --git a/src/build/maven/maven-deploy.xml b/src/build/maven/maven-deploy.xml index 84a12066f5..f52a7888ce 100644 --- a/src/build/maven/maven-deploy.xml +++ b/src/build/maven/maven-deploy.xml @@ -110,7 +110,6 @@ - diff --git a/src/build/maven/scala-partest-pom.xml b/src/build/maven/scala-partest-pom.xml deleted file mode 100644 index ac05f242d5..0000000000 --- a/src/build/maven/scala-partest-pom.xml +++ /dev/null @@ -1,62 +0,0 @@ - - 4.0.0 - org.scala-lang - scala-partest - jar - @VERSION@ - Parallel Test Framework - testing framework for the Scala compiler. - http://www.scala-lang.org/ - 2002 - - LAMP/EPFL - http://lamp.epfl.ch/ - - - - BSD-like - http://www.scala-lang.org/downloads/license.html - - repo - - - - scm:git:git://github.com/scala/scala.git - https://github.com/scala/scala.git - - - JIRA - https://issues.scala-lang.org/ - - - - - org.scala-lang - scala-compiler - @VERSION@ - - - - - scala-tools.org - @RELEASE_REPOSITORY@ - - - scala-tools.org - @SNAPSHOT_REPOSITORY@ - false - - - - - lamp - EPFL LAMP - - - Typesafe - Typesafe, Inc. - - - diff --git a/src/build/pack.xml b/src/build/pack.xml index 6b6579ce12..fa030300ac 100644 --- a/src/build/pack.xml +++ b/src/build/pack.xml @@ -158,7 +158,6 @@ MAIN DISTRIBUTION PACKAGING - @@ -210,10 +209,6 @@ MAIN DISTRIBUTION PACKAGING basedir="${build-docs.dir}/scalap"> - - - diff --git a/src/eclipse/partest/.classpath b/src/eclipse/partest/.classpath index 462cbb9c94..5a4448e01a 100644 --- a/src/eclipse/partest/.classpath +++ b/src/eclipse/partest/.classpath @@ -1,14 +1,14 @@ - - + + - + diff --git a/src/eclipse/partest/.project b/src/eclipse/partest/.project index 45c24332ba..5f52d4bf8f 100644 --- a/src/eclipse/partest/.project +++ b/src/eclipse/partest/.project @@ -1,6 +1,6 @@ - partest + partest-extras @@ -17,9 +17,9 @@ - build-quick-partest + build-quick-partest-extras 2 - SCALA_BASEDIR/build/quick/classes/partest + SCALA_BASEDIR/build/quick/classes/partest-extras lib @@ -27,9 +27,9 @@ SCALA_BASEDIR/lib - partest + partest-extras 2 - SCALA_BASEDIR/src/partest + SCALA_BASEDIR/src/partest-extras diff --git a/src/intellij/partest.iml.SAMPLE b/src/intellij/partest.iml.SAMPLE index 5b8cfa3f38..893236b621 100644 --- a/src/intellij/partest.iml.SAMPLE +++ b/src/intellij/partest.iml.SAMPLE @@ -12,17 +12,11 @@ - - + + - - - - - - diff --git a/src/partest-extras/scala/tools/partest/ASMConverters.scala b/src/partest-extras/scala/tools/partest/ASMConverters.scala new file mode 100644 index 0000000000..d618e086f4 --- /dev/null +++ b/src/partest-extras/scala/tools/partest/ASMConverters.scala @@ -0,0 +1,71 @@ +package scala.tools.partest + +import scala.collection.JavaConverters._ +import scala.tools.asm +import asm.tree.{ClassNode, MethodNode, InsnList} + +/** Makes using ASM from ByteCodeTests more convenient. + * + * Wraps ASM instructions in case classes so that equals and toString work + * for the purpose of bytecode diffing and pretty printing. + */ +trait ASMConverters { + // wrap ASM's instructions so we get case class-style `equals` and `toString` + object instructions { + def fromMethod(meth: MethodNode): List[Instruction] = { + val insns = meth.instructions + val asmToScala = new AsmToScala{ def labelIndex(l: asm.tree.AbstractInsnNode) = insns.indexOf(l) } + + asmToScala.mapOver(insns.iterator.asScala.toList).asInstanceOf[List[Instruction]] + } + + sealed abstract class Instruction { def opcode: String } + case class Field (opcode: String, desc: String, name: String, owner: String) extends Instruction + case class Incr (opcode: String, incr: Int, `var`: Int) extends Instruction + case class Op (opcode: String) extends Instruction + case class IntOp (opcode: String, operand: Int) extends Instruction + case class Jump (opcode: String, label: Label) extends Instruction + case class Ldc (opcode: String, cst: Any) extends Instruction + case class LookupSwitch (opcode: String, dflt: Label, keys: List[Integer], labels: List[Label]) extends Instruction + case class TableSwitch (opcode: String, dflt: Label, max: Int, min: Int, labels: List[Label]) extends Instruction + case class Method (opcode: String, desc: String, name: String, owner: String) extends Instruction + case class NewArray (opcode: String, desc: String, dims: Int) extends Instruction + case class TypeOp (opcode: String, desc: String) extends Instruction + case class VarOp (opcode: String, `var`: Int) extends Instruction + case class Label (offset: Int) extends Instruction { def opcode: String = "" } + case class FrameEntry (local: List[Any], stack: List[Any]) extends Instruction { def opcode: String = "" } + case class LineNumber (line: Int, start: Label) extends Instruction { def opcode: String = "" } + } + + abstract class AsmToScala { + import instructions._ + + def labelIndex(l: asm.tree.AbstractInsnNode): Int + + def mapOver(is: List[Any]): List[Any] = is map { + case i: asm.tree.AbstractInsnNode => apply(i) + case x => x + } + + def op(i: asm.tree.AbstractInsnNode) = if (asm.util.Printer.OPCODES.isDefinedAt(i.getOpcode)) asm.util.Printer.OPCODES(i.getOpcode) else "?" + def lst[T](xs: java.util.List[T]): List[T] = if (xs == null) Nil else xs.asScala.toList + def apply(l: asm.tree.LabelNode): Label = this(l: asm.tree.AbstractInsnNode).asInstanceOf[Label] + def apply(x: asm.tree.AbstractInsnNode): Instruction = x match { + case i: asm.tree.FieldInsnNode => Field (op(i), i.desc: String, i.name: String, i.owner: String) + case i: asm.tree.IincInsnNode => Incr (op(i), i.incr: Int, i.`var`: Int) + case i: asm.tree.InsnNode => Op (op(i)) + case i: asm.tree.IntInsnNode => IntOp (op(i), i.operand: Int) + case i: asm.tree.JumpInsnNode => Jump (op(i), this(i.label)) + case i: asm.tree.LdcInsnNode => Ldc (op(i), i.cst: Any) + case i: asm.tree.LookupSwitchInsnNode => LookupSwitch (op(i), this(i.dflt), lst(i.keys), mapOver(lst(i.labels)).asInstanceOf[List[Label]]) + case i: asm.tree.TableSwitchInsnNode => TableSwitch (op(i), this(i.dflt), i.max: Int, i.min: Int, mapOver(lst(i.labels)).asInstanceOf[List[Label]]) + case i: asm.tree.MethodInsnNode => Method (op(i), i.desc: String, i.name: String, i.owner: String) + case i: asm.tree.MultiANewArrayInsnNode => NewArray (op(i), i.desc: String, i.dims: Int) + case i: asm.tree.TypeInsnNode => TypeOp (op(i), i.desc: String) + case i: asm.tree.VarInsnNode => VarOp (op(i), i.`var`: Int) + case i: asm.tree.LabelNode => Label (labelIndex(x)) + case i: asm.tree.FrameNode => FrameEntry (mapOver(lst(i.local)), mapOver(lst(i.stack))) + case i: asm.tree.LineNumberNode => LineNumber (i.line: Int, this(i.start): Label) + } + } +} \ No newline at end of file diff --git a/src/partest-extras/scala/tools/partest/AsmNode.scala b/src/partest-extras/scala/tools/partest/AsmNode.scala new file mode 100644 index 0000000000..e6a91498d1 --- /dev/null +++ b/src/partest-extras/scala/tools/partest/AsmNode.scala @@ -0,0 +1,61 @@ +package scala.tools.partest + +import scala.collection.JavaConverters._ +import scala.tools.asm +import asm._ +import asm.tree._ +import java.lang.reflect.Modifier + +sealed trait AsmNode[+T] { + def node: T + def access: Int + def desc: String + def name: String + def signature: String + def attrs: List[Attribute] + def visibleAnnotations: List[AnnotationNode] + def invisibleAnnotations: List[AnnotationNode] + def characteristics = f"$name%15s $desc%-30s$accessString$sigString" + def erasedCharacteristics = f"$name%15s $desc%-30s$accessString" + + private def accessString = if (access == 0) "" else " " + Modifier.toString(access) + private def sigString = if (signature == null) "" else " " + signature + override def toString = characteristics +} + +object AsmNode { + type AsmMethod = AsmNode[MethodNode] + type AsmField = AsmNode[FieldNode] + type AsmMember = AsmNode[_] + + implicit class ClassNodeOps(val node: ClassNode) { + def fieldsAndMethods: List[AsmMember] = { + val xs: List[AsmMember] = ( + node.methods.asScala.toList.map(x => (x: AsmMethod)) + ++ node.fields.asScala.toList.map(x => (x: AsmField)) + ) + xs sortBy (_.characteristics) + } + } + implicit class AsmMethodNode(val node: MethodNode) extends AsmNode[MethodNode] { + def access: Int = node.access + def desc: String = node.desc + def name: String = node.name + def signature: String = node.signature + def attrs: List[Attribute] = node.attrs.asScala.toList + def visibleAnnotations: List[AnnotationNode] = node.visibleAnnotations.asScala.toList + def invisibleAnnotations: List[AnnotationNode] = node.invisibleAnnotations.asScala.toList + } + implicit class AsmFieldNode(val node: FieldNode) extends AsmNode[FieldNode] { + def access: Int = node.access + def desc: String = node.desc + def name: String = node.name + def signature: String = node.signature + def attrs: List[Attribute] = node.attrs.asScala.toList + def visibleAnnotations: List[AnnotationNode] = node.visibleAnnotations.asScala.toList + def invisibleAnnotations: List[AnnotationNode] = node.invisibleAnnotations.asScala.toList + } + + def apply(node: MethodNode): AsmMethodNode = new AsmMethodNode(node) + def apply(node: FieldNode): AsmFieldNode = new AsmFieldNode(node) +} diff --git a/src/partest-extras/scala/tools/partest/BytecodeTest.scala b/src/partest-extras/scala/tools/partest/BytecodeTest.scala new file mode 100644 index 0000000000..7650a892fd --- /dev/null +++ b/src/partest-extras/scala/tools/partest/BytecodeTest.scala @@ -0,0 +1,167 @@ +package scala.tools.partest + +import scala.tools.nsc.util.JavaClassPath +import scala.collection.JavaConverters._ +import scala.tools.asm.{ClassWriter, ClassReader} +import scala.tools.asm.tree.{ClassNode, MethodNode, InsnList} +import java.io.{FileOutputStream, FileInputStream, File => JFile, InputStream} +import AsmNode._ + +/** + * Provides utilities for inspecting bytecode using ASM library. + * + * HOW TO USE + * 1. Create subdirectory in test/files/jvm for your test. Let's name it $TESTDIR. + * 2. Create $TESTDIR/BytecodeSrc_1.scala that contains Scala source file that you + * want to inspect the bytecode for. The '_1' suffix signals to partest that it + * should compile this file first. + * 3. Create $TESTDIR/Test.scala: + * import scala.tools.partest.BytecodeTest + * object Test extends BytecodeTest { + * def show { + * // your code that inspect ASM trees and prints values + * } + * } + * 4. Create corresponding check file. + * + * EXAMPLE + * See test/files/jvm/bytecode-test-example for an example of bytecode test. + * + */ +abstract class BytecodeTest extends ASMConverters { + import instructions._ + + /** produce the output to be compared against a checkfile */ + protected def show(): Unit + + def main(args: Array[String]): Unit = show + + // asserts + def sameBytecode(methA: MethodNode, methB: MethodNode) = { + val isa = instructions.fromMethod(methA) + val isb = instructions.fromMethod(methB) + if (isa == isb) println("bytecode identical") + else diffInstructions(isa, isb) + } + + // Do these classes have all the same methods, with the same names, access, + // descriptors and generic signatures? Method bodies are not considered, and + // the names of the classes containing the methods are substituted so they do + // not appear as differences. + def sameMethodAndFieldSignatures(clazzA: ClassNode, clazzB: ClassNode) = + sameCharacteristics(clazzA, clazzB)(_.characteristics) + + // Same as sameMethodAndFieldSignatures, but ignoring generic signatures. + // This allows for methods which receive the same descriptor but differing + // generic signatures. In particular, this happens with value classes, + // which get a generic signature where a method written in terms of the + // underlying values does not. + def sameMethodAndFieldDescriptors(clazzA: ClassNode, clazzB: ClassNode) = + sameCharacteristics(clazzA, clazzB)(_.erasedCharacteristics) + + private def sameCharacteristics(clazzA: ClassNode, clazzB: ClassNode)(f: AsmNode[_] => String): Boolean = { + val ms1 = clazzA.fieldsAndMethods.toIndexedSeq + val ms2 = clazzB.fieldsAndMethods.toIndexedSeq + val name1 = clazzA.name + val name2 = clazzB.name + + if (ms1.length != ms2.length) { + println(s"Different member counts in $name1 and $name2") + false + } + else (ms1, ms2).zipped forall { (m1, m2) => + val c1 = f(m1) + val c2 = f(m2).replaceAllLiterally(name2, name1) + if (c1 == c2) + println(s"[ok] $m1") + else + println(s"[fail]\n in $name1: $c1\n in $name2: $c2") + + c1 == c2 + } + } + + // bytecode is equal modulo local variable numbering + def equalsModuloVar(a: Instruction, b: Instruction) = (a, b) match { + case _ if a == b => true + case (VarOp(op1, _), VarOp(op2, _)) if op1 == op2 => true + case _ => false + } + + def similarBytecode(methA: MethodNode, methB: MethodNode, similar: (Instruction, Instruction) => Boolean) = { + val isa = fromMethod(methA) + val isb = fromMethod(methB) + if (isa == isb) println("bytecode identical") + else if ((isa, isb).zipped.forall { case (a, b) => similar(a, b) }) println("bytecode similar") + else diffInstructions(isa, isb) + } + + def diffInstructions(isa: List[Instruction], isb: List[Instruction]) = { + val len = Math.max(isa.length, isb.length) + if (len > 0 ) { + val width = isa.map(_.toString.length).max + val lineWidth = len.toString.length + (1 to len) foreach { line => + val isaPadded = isa.map(_.toString) orElse Stream.continually("") + val isbPadded = isb.map(_.toString) orElse Stream.continually("") + val a = isaPadded(line-1) + val b = isbPadded(line-1) + + println(s"""$line${" " * (lineWidth-line.toString.length)} ${if (a==b) "==" else "<>"} $a${" " * (width-a.length)} | $b""") + } + } + } + +// loading + protected def getMethod(classNode: ClassNode, name: String): MethodNode = + classNode.methods.asScala.find(_.name == name) getOrElse + sys.error(s"Didn't find method '$name' in class '${classNode.name}'") + + protected def loadClassNode(name: String, skipDebugInfo: Boolean = true): ClassNode = { + val classBytes: InputStream = (for { + classRep <- classpath.findClass(name) + binary <- classRep.binary + } yield binary.input) getOrElse sys.error(s"failed to load class '$name'; classpath = $classpath") + + val cr = new ClassReader(classBytes) + val cn = new ClassNode() + cr.accept(cn, if (skipDebugInfo) ClassReader.SKIP_DEBUG else 0) + cn + } + + protected lazy val classpath: JavaClassPath = { + import scala.tools.nsc.util.ClassPath.DefaultJavaContext + import scala.tools.util.PathResolver.Defaults + // logic inspired by scala.tools.util.PathResolver implementation + val containers = DefaultJavaContext.classesInExpandedPath(Defaults.javaUserClassPath) + new JavaClassPath(containers, DefaultJavaContext) + } +} + +object BytecodeTest { + /** Parse `file` as a class file, transforms the ASM representation with `f`, + * and overwrites the orginal file. + */ + def modifyClassFile(file: JFile)(f: ClassNode => ClassNode) { + val rfile = new reflect.io.File(file) + def readClass: ClassNode = { + val cr = new ClassReader(rfile.toByteArray()) + val cn = new ClassNode() + cr.accept(cn, 0) + cn + } + + def writeClass(cn: ClassNode) { + val writer = new ClassWriter(0) + cn.accept(writer) + val os = rfile.bufferedOutput() + try { + os.write(writer.toByteArray) + } finally { + os.close() + } + } + + writeClass(f(readClass)) + } +} diff --git a/src/partest-extras/scala/tools/partest/JavapTest.scala b/src/partest-extras/scala/tools/partest/JavapTest.scala new file mode 100644 index 0000000000..3cb3dc6ca8 --- /dev/null +++ b/src/partest-extras/scala/tools/partest/JavapTest.scala @@ -0,0 +1,26 @@ + +package scala.tools.partest + +import scala.util.{Try,Success,Failure} +import java.lang.System.{out => sysout} + +/** A trait for testing repl's javap command + * or possibly examining its output. + */ +abstract class JavapTest extends ReplTest { + + /** Your Assertion Here, whatever you want to bejahen. + * Assertions must be satisfied by all flavors of javap + * and should not be fragile with respect to compiler output. + */ + def yah(res: Seq[String]): Boolean + + def baddies = List(":javap unavailable", ":javap not yet working") + + // give it a pass if javap is broken + override def show() = try { + val res = eval().toSeq + val unsupported = res exists (s => baddies exists (s contains _)) + assert ((unsupported || yah(res)), res.mkString("","\n","\n")) + } catch { case ae: AssertionError => ae.printStackTrace(sysout) } +} diff --git a/src/partest-extras/scala/tools/partest/ReplTest.scala b/src/partest-extras/scala/tools/partest/ReplTest.scala new file mode 100644 index 0000000000..7cc2dd39a9 --- /dev/null +++ b/src/partest-extras/scala/tools/partest/ReplTest.scala @@ -0,0 +1,43 @@ +/* NSC -- new Scala compiler + * Copyright 2005-2013 LAMP/EPFL + * @author Paul Phillips + */ + +package scala.tools.partest + +import scala.tools.nsc.Settings +import scala.tools.nsc.interpreter.ILoop +import java.lang.reflect.{ Method => JMethod, Field => JField } + +/** A trait for testing repl code. It drops the first line + * of output because the real repl prints a version number. + */ +abstract class ReplTest extends DirectTest { + // override to transform Settings object immediately before the finish + def transformSettings(s: Settings): Settings = s + // final because we need to enforce the existence of a couple settings. + final override def settings: Settings = { + val s = super.settings + // s.Yreplsync.value = true + s.Xnojline.value = true + transformSettings(s) + } + def eval() = { + val s = settings + log("eval(): settings = " + s) + ILoop.runForTranscript(code, s).lines drop 1 + } + def show() = eval() foreach println +} + +abstract class SessionTest extends ReplTest { + def session: String + override final def code = expected filter (_.startsWith(prompt)) map (_.drop(prompt.length)) mkString "\n" + def expected = session.stripMargin.lines.toList + final def prompt = "scala> " + override def show() = { + val out = eval().toList + if (out.size != expected.size) Console println s"Expected ${expected.size} lines, got ${out.size}" + if (out != expected) Console print nest.FileManager.compareContents(expected, out, "expected", "actual") + } +} diff --git a/src/partest-extras/scala/tools/partest/SigTest.scala b/src/partest-extras/scala/tools/partest/SigTest.scala new file mode 100644 index 0000000000..fe233a4fb5 --- /dev/null +++ b/src/partest-extras/scala/tools/partest/SigTest.scala @@ -0,0 +1,52 @@ +/* NSC -- new Scala compiler + * Copyright 2005-2013 LAMP/EPFL + * @author Paul Phillips + */ + +package scala.tools.partest + +import scala.tools.nsc.Settings +import scala.tools.nsc.interpreter.ILoop +import java.lang.reflect.{ Method => JMethod, Field => JField } +import scala.reflect.{ClassTag, classTag} + +/** Support code for testing signatures. + */ +trait SigTest { + def mstr(m: JMethod) = " (m) %s%s".format( + m.toGenericString, + if (m.isBridge) " (bridge)" else "" + ) + def fstr(f: JField) = " (f) %s".format(f.toGenericString) + + def isObjectMethodName(name: String) = classOf[Object].getMethods exists (_.getName == name) + + def fields[T: ClassTag](p: JField => Boolean) = { + val cl = classTag[T].runtimeClass + val fs = (cl.getFields ++ cl.getDeclaredFields).distinct sortBy (_.getName) + + fs filter p + } + def methods[T: ClassTag](p: JMethod => Boolean) = { + val cl = classTag[T].runtimeClass + val ms = (cl.getMethods ++ cl.getDeclaredMethods).distinct sortBy (x => (x.getName, x.isBridge)) + + ms filter p + } + def allFields[T: ClassTag]() = fields[T](_ => true) + def allMethods[T: ClassTag]() = methods[T](m => !isObjectMethodName(m.getName)) + def fieldsNamed[T: ClassTag](name: String) = fields[T](_.getName == name) + def methodsNamed[T: ClassTag](name: String) = methods[T](_.getName == name) + + def allGenericStrings[T: ClassTag]() = + (allMethods[T]() map mstr) ++ (allFields[T]() map fstr) + + def genericStrings[T: ClassTag](name: String) = + (methodsNamed[T](name) map mstr) ++ (fieldsNamed[T](name) map fstr) + + def show[T: ClassTag](name: String = "") = { + println(classTag[T].runtimeClass.getName) + if (name == "") allGenericStrings[T]() foreach println + else genericStrings[T](name) foreach println + } +} diff --git a/src/partest-extras/scala/tools/partest/Util.scala b/src/partest-extras/scala/tools/partest/Util.scala new file mode 100644 index 0000000000..114658b0cd --- /dev/null +++ b/src/partest-extras/scala/tools/partest/Util.scala @@ -0,0 +1,52 @@ +package scala.tools.partest + +import scala.language.experimental.macros + +object Util { + /** + * `trace("".isEmpty)` will return `true` and as a side effect print the following to standard out. + * {{{ + * trace> "".isEmpty + * res: Boolean = true + * + * }}} + * + * An alternative to [[scala.tools.partest.ReplTest]] that avoids the inconvenience of embedding + * test code in a string. + */ + def trace[A](a: A) = macro traceImpl[A] + + import scala.reflect.macros.Context + def traceImpl[A: c.WeakTypeTag](c: Context)(a: c.Expr[A]): c.Expr[A] = { + import c.universe._ + import definitions._ + + // xeno.by: reify shouldn't be used explicitly before the final release of 2.10.0, + // because this impairs reflection refactorings + // + // val exprCode = c.literal(show(a.tree)) + // val exprType = c.literal(show(a.actualType)) + // reify { + // println(s"trace> ${exprCode.splice}\nres: ${exprType.splice} = ${a.splice}\n") + // a.splice + // } + + c.Expr(Block( + List(Apply( + Select(Ident(PredefModule), TermName("println")), + List(Apply( + Select(Apply( + Select(Ident(ScalaPackage), TermName("StringContext")), + List( + Literal(Constant("trace> ")), + Literal(Constant("\\nres: ")), + Literal(Constant(" = ")), + Literal(Constant("\\n")))), + TermName("s")), + List( + Literal(Constant(show(a.tree))), + Literal(Constant(show(a.actualType))), + a.tree))))), + a.tree)) + } +} \ No newline at end of file diff --git a/src/partest-extras/scala/tools/partest/instrumented/Instrumentation.scala b/src/partest-extras/scala/tools/partest/instrumented/Instrumentation.scala new file mode 100644 index 0000000000..18dd740208 --- /dev/null +++ b/src/partest-extras/scala/tools/partest/instrumented/Instrumentation.scala @@ -0,0 +1,93 @@ +/* NEST (New Scala Test) + * Copyright 2007-2013 LAMP/EPFL + * @author Grzegorz Kossakowski + */ + +package scala.tools.partest.instrumented + +import scala.collection.JavaConverters._ + +case class MethodCallTrace(className: String, methodName: String, methodDescriptor: String) { + override def toString(): String = className + "." + methodName + methodDescriptor +} +object MethodCallTrace { + implicit val ordering: Ordering[MethodCallTrace] = Ordering.by(x => (x.className, x.methodName, x.methodDescriptor)) +} + +/** + * An object that controls profiling of instrumented byte-code. The instrumentation is achieved + * by using `java.lang.instrument` package. The instrumentation agent can be found in + * `scala.tools.partest.javaagent` package. + * + * At the moment the following classes are being instrumented: + * * all classes with empty package + * * all classes from scala package (except for classes responsible for instrumentation) + * + * The canonical way of using instrumentation is have a test-case in `files/instrumented` directory. + * The following code in main: + * + * {{{ + * import scala.tools.partest.instrumented.Instrumentation._ + * def main(args: Array[String]): Unit = { + * startProfiling() + * // should box the boolean + println(true) + stopProfiling() + printStatistics() + * } + * }}} + * + * + * should print: + * + * {{{ + * true + * Method call statistics: + * scala/Predef$.println(Ljava/lang/Object;)V: 1 + * scala/runtime/BoxesRunTime.boxToBoolean(Z)Ljava/lang/Boolean;: 1 + * }}} + */ +object Instrumentation { + + type Statistics = Map[MethodCallTrace, Int] + + def startProfiling(): Unit = Profiler.startProfiling() + def stopProfiling(): Unit = Profiler.stopProfiling() + def resetProfiling(): Unit = Profiler.resetProfiling() + def isProfiling(): Boolean = Profiler.isProfiling() + + def getStatistics: Statistics = { + val isProfiling = Profiler.isProfiling() + if (isProfiling) { + Profiler.stopProfiling() + } + val stats = Profiler.getStatistics().asScala.toSeq.map { + case (trace, count) => MethodCallTrace(trace.className, trace.methodName, trace.methodDescriptor) -> count.intValue + } + val res = Map(stats: _*) + if (isProfiling) { + Profiler.startProfiling() + } + res + } + + val standardFilter: MethodCallTrace => Boolean = t => { + // ignore all calls to Console trigger by printing + t.className != "scala/Console$" && + // console accesses DynamicVariable, let's discard it too + !t.className.startsWith("scala/util/DynamicVariable") + } + + // Used in tests. + def printStatistics(stats: Statistics = getStatistics, filter: MethodCallTrace => Boolean = standardFilter): Unit = { + val stats = getStatistics + println("Method call statistics:") + val toBePrinted = stats.toSeq.filter(p => filter(p._1)).sortBy(_._1) + // + val format = "%5d %s\n" + toBePrinted foreach { + case (trace, count) => printf(format, count, trace) + } + } + +} diff --git a/src/partest-extras/scala/tools/partest/instrumented/Profiler.java b/src/partest-extras/scala/tools/partest/instrumented/Profiler.java new file mode 100644 index 0000000000..d6b62e1d9e --- /dev/null +++ b/src/partest-extras/scala/tools/partest/instrumented/Profiler.java @@ -0,0 +1,82 @@ +/* NEST (New Scala Test) + * Copyright 2007-2013 LAMP/EPFL + * @author Grzegorz Kossakowski + */ + +package scala.tools.partest.instrumented; + +import java.util.HashMap; +import java.util.Map; + +/** + * A simple profiler class that counts method invocations. It is being used in byte-code instrumentation by inserting + * call to {@link Profiler#methodCalled(String, String, String)} at the beginning of every instrumented class. + * + * WARANING: This class is INTERNAL implementation detail and should never be used directly. It's made public only + * because it must be universally accessible for instrumentation needs. If you want to profile your test use + * {@link Instrumentation} instead. + */ +public class Profiler { + + private static boolean isProfiling = false; + private static Map counts = new HashMap(); + + static public class MethodCallTrace { + final String className; + final String methodName; + final String methodDescriptor; + + public MethodCallTrace(final String className, final String methodName, final String methodDescriptor) { + this.className = className; + this.methodName = methodName; + this.methodDescriptor = methodDescriptor; + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof MethodCallTrace)) { + return false; + } else { + MethodCallTrace that = (MethodCallTrace) obj; + return that.className.equals(className) && that.methodName.equals(methodName) && that.methodDescriptor.equals(methodDescriptor); + } + } + @Override + public int hashCode() { + return className.hashCode() ^ methodName.hashCode() ^ methodDescriptor.hashCode(); + } + } + + public static void startProfiling() { + isProfiling = true; + } + + public static void stopProfiling() { + isProfiling = false; + } + + public static boolean isProfiling() { + return isProfiling; + } + + public static void resetProfiling() { + counts = new HashMap(); + } + + public static void methodCalled(final String className, final String methodName, final String methodDescriptor) { + if (isProfiling) { + MethodCallTrace trace = new MethodCallTrace(className, methodName, methodDescriptor); + Integer counter = counts.get(trace); + if (counter == null) { + counts.put(trace, 1); + } else { + counts.put(trace, counter+1); + } + } + } + + public static Map getStatistics() { + return new HashMap(counts); + } + +} diff --git a/src/partest-javaagent/scala/tools/partest/javaagent/ASMTransformer.java b/src/partest-javaagent/scala/tools/partest/javaagent/ASMTransformer.java new file mode 100644 index 0000000000..86f5e64516 --- /dev/null +++ b/src/partest-javaagent/scala/tools/partest/javaagent/ASMTransformer.java @@ -0,0 +1,49 @@ +/* NEST (New Scala Test) + * Copyright 2007-2013 LAMP/EPFL + * @author Grzegorz Kossakowski + */ + +package scala.tools.partest.javaagent; + +import java.lang.instrument.ClassFileTransformer; +import java.security.ProtectionDomain; + +import scala.tools.asm.ClassReader; +import scala.tools.asm.ClassWriter; + +public class ASMTransformer implements ClassFileTransformer { + + private boolean shouldTransform(String className) { + return + // do not instrument instrumentation logic (in order to avoid infinite recursion) + !className.startsWith("scala/tools/partest/instrumented/") && + !className.startsWith("scala/tools/partest/javaagent/") && + // we instrument all classes from empty package + (!className.contains("/") || + // we instrument all classes from scala package + className.startsWith("scala/") || + // we instrument all classes from `instrumented` package + className.startsWith("instrumented/")); + } + + public byte[] transform(final ClassLoader classLoader, final String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) { + if (shouldTransform(className)) { + ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_MAXS) { + @Override protected String getCommonSuperClass(final String type1, final String type2) { + // Since we are not recomputing stack frame map, this should never be called we override this method because + // default implementation uses reflection for implementation and might try to load the class that we are + // currently processing. That leads to weird results like swallowed exceptions and classes being not + // transformed. + throw new RuntimeException("Unexpected call to getCommonSuperClass(" + type1 + ", " + type2 + + ") while transforming " + className); + } + }; + ProfilerVisitor visitor = new ProfilerVisitor(writer); + ClassReader reader = new ClassReader(classfileBuffer); + reader.accept(visitor, 0); + return writer.toByteArray(); + } else { + return classfileBuffer; + } + } +} diff --git a/src/partest-javaagent/scala/tools/partest/javaagent/MANIFEST.MF b/src/partest-javaagent/scala/tools/partest/javaagent/MANIFEST.MF new file mode 100644 index 0000000000..be0fee46a2 --- /dev/null +++ b/src/partest-javaagent/scala/tools/partest/javaagent/MANIFEST.MF @@ -0,0 +1 @@ +Premain-Class: scala.tools.partest.javaagent.ProfilingAgent diff --git a/src/partest-javaagent/scala/tools/partest/javaagent/ProfilerVisitor.java b/src/partest-javaagent/scala/tools/partest/javaagent/ProfilerVisitor.java new file mode 100644 index 0000000000..b1b100fbb0 --- /dev/null +++ b/src/partest-javaagent/scala/tools/partest/javaagent/ProfilerVisitor.java @@ -0,0 +1,59 @@ +/* NEST (New Scala Test) + * Copyright 2007-2013 LAMP/EPFL + * @author Grzegorz Kossakowski + */ + +package scala.tools.partest.javaagent; + +import scala.tools.asm.ClassVisitor; +import scala.tools.asm.MethodVisitor; +import scala.tools.asm.Opcodes; + +public class ProfilerVisitor extends ClassVisitor implements Opcodes { + + private static String profilerClass = "scala/tools/partest/instrumented/Profiler"; + + public ProfilerVisitor(final ClassVisitor cv) { + super(ASM4, cv); + } + + private String className = null; + + @Override + public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) { + className = name; + super.visit(version, access, name, signature, superName, interfaces); + } + + public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { + // delegate the method call to the next + // chained visitor + MethodVisitor mv = cv.visitMethod(access, name, desc, signature, exceptions); + if (!profilerClass.equals(className)) { + // only instrument non-abstract methods + if((access & ACC_ABSTRACT) == 0) { + assert(className != null); + /* The following instructions do not modify compressed stack frame map so + * we don't need to worry about recalculating stack frame map. Specifically, + * let's quote "ASM 4.0, A Java bytecode engineering library" guide (p. 40): + * + * In order to save space, a compiled method does not contain one frame per + * instruction: in fact it contains only the frames for the instructions + * that correspond to jump targets or exception handlers, or that follow + * unconditional jump instructions. Indeed the other frames can be easily + * and quickly inferred from these ones. + * + * Instructions below are just loading constants and calling a method so according + * to definition above they do not contribute to compressed stack frame map. + */ + mv.visitLdcInsn(className); + mv.visitLdcInsn(name); + mv.visitLdcInsn(desc); + mv.visitMethodInsn(INVOKESTATIC, profilerClass, "methodCalled", + "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V"); + } + } + return mv; + } + +} diff --git a/src/partest-javaagent/scala/tools/partest/javaagent/ProfilingAgent.java b/src/partest-javaagent/scala/tools/partest/javaagent/ProfilingAgent.java new file mode 100644 index 0000000000..819a5cc39b --- /dev/null +++ b/src/partest-javaagent/scala/tools/partest/javaagent/ProfilingAgent.java @@ -0,0 +1,25 @@ +/* NEST (New Scala Test) + * Copyright 2007-2013 LAMP/EPFL + * @author Grzegorz Kossakowski + */ + +package scala.tools.partest.javaagent; + +import java.lang.instrument.Instrumentation; +import java.lang.instrument.UnmodifiableClassException; + +/** + * Profiling agent that instruments byte-code to insert calls to + * {@link scala.tools.partest.instrumented.Profiler#methodCalled(String, String, String)} + * by using ASM library for byte-code manipulation. + */ +public class ProfilingAgent { + public static void premain(String args, Instrumentation inst) throws UnmodifiableClassException { + // NOTE: we are adding transformer that won't be applied to classes that are already loaded + // This should be ok because premain should be executed before main is executed so Scala library + // and the test-case itself won't be loaded yet. We rely here on the fact that ASMTransformer does + // not depend on Scala library. In case our assumptions are wrong we can always insert call to + // inst.retransformClasses. + inst.addTransformer(new ASMTransformer(), false); + } +} diff --git a/src/partest/README b/src/partest/README deleted file mode 100644 index 17594dbb1e..0000000000 --- a/src/partest/README +++ /dev/null @@ -1,31 +0,0 @@ -How partest chooses the compiler / library: - - * ''-Dpartest.build=build/four-pack'' -> will search for libraries in - ''lib'' directory of given path - * ''--pack'' -> will set ''partest.build=build/pack'', and run all tests. - add ''--[kind]'' to run a selected set of tests. - * auto detection: - - partest.build property -> ''bin'' / ''lib'' directories - - distribution (''dists/latest'') - - supersabbus pack (''build/pack'') - - sabbus quick (''build/quick'') - - installed dist (test files in ''misc/scala-test/files'') - -How partest choses test files: the test files must be accessible from -the directory on which partest is run. So the test files must be either -at: - * ./test/files - * ./files (cwd is "test") - * ./misc/scala-test/files (installed scala distribution) - -Other arguments: - * --pos next files test a compilation success - * --neg next files test a compilation failure - * --run next files test the interpreter and all backends - * --jvm next files test the JVM backend - * --res next files test the resident compiler - * --shootout next files are shootout tests - * --script next files test the script runner - * ''-Dpartest.scalac_opts=...'' -> add compiler options - * ''--verbose'' -> print verbose messages - * ''-Dpartest.debug=true'' -> print debug messages diff --git a/src/partest/scala/tools/partest/ASMConverters.scala b/src/partest/scala/tools/partest/ASMConverters.scala deleted file mode 100644 index d618e086f4..0000000000 --- a/src/partest/scala/tools/partest/ASMConverters.scala +++ /dev/null @@ -1,71 +0,0 @@ -package scala.tools.partest - -import scala.collection.JavaConverters._ -import scala.tools.asm -import asm.tree.{ClassNode, MethodNode, InsnList} - -/** Makes using ASM from ByteCodeTests more convenient. - * - * Wraps ASM instructions in case classes so that equals and toString work - * for the purpose of bytecode diffing and pretty printing. - */ -trait ASMConverters { - // wrap ASM's instructions so we get case class-style `equals` and `toString` - object instructions { - def fromMethod(meth: MethodNode): List[Instruction] = { - val insns = meth.instructions - val asmToScala = new AsmToScala{ def labelIndex(l: asm.tree.AbstractInsnNode) = insns.indexOf(l) } - - asmToScala.mapOver(insns.iterator.asScala.toList).asInstanceOf[List[Instruction]] - } - - sealed abstract class Instruction { def opcode: String } - case class Field (opcode: String, desc: String, name: String, owner: String) extends Instruction - case class Incr (opcode: String, incr: Int, `var`: Int) extends Instruction - case class Op (opcode: String) extends Instruction - case class IntOp (opcode: String, operand: Int) extends Instruction - case class Jump (opcode: String, label: Label) extends Instruction - case class Ldc (opcode: String, cst: Any) extends Instruction - case class LookupSwitch (opcode: String, dflt: Label, keys: List[Integer], labels: List[Label]) extends Instruction - case class TableSwitch (opcode: String, dflt: Label, max: Int, min: Int, labels: List[Label]) extends Instruction - case class Method (opcode: String, desc: String, name: String, owner: String) extends Instruction - case class NewArray (opcode: String, desc: String, dims: Int) extends Instruction - case class TypeOp (opcode: String, desc: String) extends Instruction - case class VarOp (opcode: String, `var`: Int) extends Instruction - case class Label (offset: Int) extends Instruction { def opcode: String = "" } - case class FrameEntry (local: List[Any], stack: List[Any]) extends Instruction { def opcode: String = "" } - case class LineNumber (line: Int, start: Label) extends Instruction { def opcode: String = "" } - } - - abstract class AsmToScala { - import instructions._ - - def labelIndex(l: asm.tree.AbstractInsnNode): Int - - def mapOver(is: List[Any]): List[Any] = is map { - case i: asm.tree.AbstractInsnNode => apply(i) - case x => x - } - - def op(i: asm.tree.AbstractInsnNode) = if (asm.util.Printer.OPCODES.isDefinedAt(i.getOpcode)) asm.util.Printer.OPCODES(i.getOpcode) else "?" - def lst[T](xs: java.util.List[T]): List[T] = if (xs == null) Nil else xs.asScala.toList - def apply(l: asm.tree.LabelNode): Label = this(l: asm.tree.AbstractInsnNode).asInstanceOf[Label] - def apply(x: asm.tree.AbstractInsnNode): Instruction = x match { - case i: asm.tree.FieldInsnNode => Field (op(i), i.desc: String, i.name: String, i.owner: String) - case i: asm.tree.IincInsnNode => Incr (op(i), i.incr: Int, i.`var`: Int) - case i: asm.tree.InsnNode => Op (op(i)) - case i: asm.tree.IntInsnNode => IntOp (op(i), i.operand: Int) - case i: asm.tree.JumpInsnNode => Jump (op(i), this(i.label)) - case i: asm.tree.LdcInsnNode => Ldc (op(i), i.cst: Any) - case i: asm.tree.LookupSwitchInsnNode => LookupSwitch (op(i), this(i.dflt), lst(i.keys), mapOver(lst(i.labels)).asInstanceOf[List[Label]]) - case i: asm.tree.TableSwitchInsnNode => TableSwitch (op(i), this(i.dflt), i.max: Int, i.min: Int, mapOver(lst(i.labels)).asInstanceOf[List[Label]]) - case i: asm.tree.MethodInsnNode => Method (op(i), i.desc: String, i.name: String, i.owner: String) - case i: asm.tree.MultiANewArrayInsnNode => NewArray (op(i), i.desc: String, i.dims: Int) - case i: asm.tree.TypeInsnNode => TypeOp (op(i), i.desc: String) - case i: asm.tree.VarInsnNode => VarOp (op(i), i.`var`: Int) - case i: asm.tree.LabelNode => Label (labelIndex(x)) - case i: asm.tree.FrameNode => FrameEntry (mapOver(lst(i.local)), mapOver(lst(i.stack))) - case i: asm.tree.LineNumberNode => LineNumber (i.line: Int, this(i.start): Label) - } - } -} \ No newline at end of file diff --git a/src/partest/scala/tools/partest/AsmNode.scala b/src/partest/scala/tools/partest/AsmNode.scala deleted file mode 100644 index e6a91498d1..0000000000 --- a/src/partest/scala/tools/partest/AsmNode.scala +++ /dev/null @@ -1,61 +0,0 @@ -package scala.tools.partest - -import scala.collection.JavaConverters._ -import scala.tools.asm -import asm._ -import asm.tree._ -import java.lang.reflect.Modifier - -sealed trait AsmNode[+T] { - def node: T - def access: Int - def desc: String - def name: String - def signature: String - def attrs: List[Attribute] - def visibleAnnotations: List[AnnotationNode] - def invisibleAnnotations: List[AnnotationNode] - def characteristics = f"$name%15s $desc%-30s$accessString$sigString" - def erasedCharacteristics = f"$name%15s $desc%-30s$accessString" - - private def accessString = if (access == 0) "" else " " + Modifier.toString(access) - private def sigString = if (signature == null) "" else " " + signature - override def toString = characteristics -} - -object AsmNode { - type AsmMethod = AsmNode[MethodNode] - type AsmField = AsmNode[FieldNode] - type AsmMember = AsmNode[_] - - implicit class ClassNodeOps(val node: ClassNode) { - def fieldsAndMethods: List[AsmMember] = { - val xs: List[AsmMember] = ( - node.methods.asScala.toList.map(x => (x: AsmMethod)) - ++ node.fields.asScala.toList.map(x => (x: AsmField)) - ) - xs sortBy (_.characteristics) - } - } - implicit class AsmMethodNode(val node: MethodNode) extends AsmNode[MethodNode] { - def access: Int = node.access - def desc: String = node.desc - def name: String = node.name - def signature: String = node.signature - def attrs: List[Attribute] = node.attrs.asScala.toList - def visibleAnnotations: List[AnnotationNode] = node.visibleAnnotations.asScala.toList - def invisibleAnnotations: List[AnnotationNode] = node.invisibleAnnotations.asScala.toList - } - implicit class AsmFieldNode(val node: FieldNode) extends AsmNode[FieldNode] { - def access: Int = node.access - def desc: String = node.desc - def name: String = node.name - def signature: String = node.signature - def attrs: List[Attribute] = node.attrs.asScala.toList - def visibleAnnotations: List[AnnotationNode] = node.visibleAnnotations.asScala.toList - def invisibleAnnotations: List[AnnotationNode] = node.invisibleAnnotations.asScala.toList - } - - def apply(node: MethodNode): AsmMethodNode = new AsmMethodNode(node) - def apply(node: FieldNode): AsmFieldNode = new AsmFieldNode(node) -} diff --git a/src/partest/scala/tools/partest/BytecodeTest.scala b/src/partest/scala/tools/partest/BytecodeTest.scala deleted file mode 100644 index 7650a892fd..0000000000 --- a/src/partest/scala/tools/partest/BytecodeTest.scala +++ /dev/null @@ -1,167 +0,0 @@ -package scala.tools.partest - -import scala.tools.nsc.util.JavaClassPath -import scala.collection.JavaConverters._ -import scala.tools.asm.{ClassWriter, ClassReader} -import scala.tools.asm.tree.{ClassNode, MethodNode, InsnList} -import java.io.{FileOutputStream, FileInputStream, File => JFile, InputStream} -import AsmNode._ - -/** - * Provides utilities for inspecting bytecode using ASM library. - * - * HOW TO USE - * 1. Create subdirectory in test/files/jvm for your test. Let's name it $TESTDIR. - * 2. Create $TESTDIR/BytecodeSrc_1.scala that contains Scala source file that you - * want to inspect the bytecode for. The '_1' suffix signals to partest that it - * should compile this file first. - * 3. Create $TESTDIR/Test.scala: - * import scala.tools.partest.BytecodeTest - * object Test extends BytecodeTest { - * def show { - * // your code that inspect ASM trees and prints values - * } - * } - * 4. Create corresponding check file. - * - * EXAMPLE - * See test/files/jvm/bytecode-test-example for an example of bytecode test. - * - */ -abstract class BytecodeTest extends ASMConverters { - import instructions._ - - /** produce the output to be compared against a checkfile */ - protected def show(): Unit - - def main(args: Array[String]): Unit = show - - // asserts - def sameBytecode(methA: MethodNode, methB: MethodNode) = { - val isa = instructions.fromMethod(methA) - val isb = instructions.fromMethod(methB) - if (isa == isb) println("bytecode identical") - else diffInstructions(isa, isb) - } - - // Do these classes have all the same methods, with the same names, access, - // descriptors and generic signatures? Method bodies are not considered, and - // the names of the classes containing the methods are substituted so they do - // not appear as differences. - def sameMethodAndFieldSignatures(clazzA: ClassNode, clazzB: ClassNode) = - sameCharacteristics(clazzA, clazzB)(_.characteristics) - - // Same as sameMethodAndFieldSignatures, but ignoring generic signatures. - // This allows for methods which receive the same descriptor but differing - // generic signatures. In particular, this happens with value classes, - // which get a generic signature where a method written in terms of the - // underlying values does not. - def sameMethodAndFieldDescriptors(clazzA: ClassNode, clazzB: ClassNode) = - sameCharacteristics(clazzA, clazzB)(_.erasedCharacteristics) - - private def sameCharacteristics(clazzA: ClassNode, clazzB: ClassNode)(f: AsmNode[_] => String): Boolean = { - val ms1 = clazzA.fieldsAndMethods.toIndexedSeq - val ms2 = clazzB.fieldsAndMethods.toIndexedSeq - val name1 = clazzA.name - val name2 = clazzB.name - - if (ms1.length != ms2.length) { - println(s"Different member counts in $name1 and $name2") - false - } - else (ms1, ms2).zipped forall { (m1, m2) => - val c1 = f(m1) - val c2 = f(m2).replaceAllLiterally(name2, name1) - if (c1 == c2) - println(s"[ok] $m1") - else - println(s"[fail]\n in $name1: $c1\n in $name2: $c2") - - c1 == c2 - } - } - - // bytecode is equal modulo local variable numbering - def equalsModuloVar(a: Instruction, b: Instruction) = (a, b) match { - case _ if a == b => true - case (VarOp(op1, _), VarOp(op2, _)) if op1 == op2 => true - case _ => false - } - - def similarBytecode(methA: MethodNode, methB: MethodNode, similar: (Instruction, Instruction) => Boolean) = { - val isa = fromMethod(methA) - val isb = fromMethod(methB) - if (isa == isb) println("bytecode identical") - else if ((isa, isb).zipped.forall { case (a, b) => similar(a, b) }) println("bytecode similar") - else diffInstructions(isa, isb) - } - - def diffInstructions(isa: List[Instruction], isb: List[Instruction]) = { - val len = Math.max(isa.length, isb.length) - if (len > 0 ) { - val width = isa.map(_.toString.length).max - val lineWidth = len.toString.length - (1 to len) foreach { line => - val isaPadded = isa.map(_.toString) orElse Stream.continually("") - val isbPadded = isb.map(_.toString) orElse Stream.continually("") - val a = isaPadded(line-1) - val b = isbPadded(line-1) - - println(s"""$line${" " * (lineWidth-line.toString.length)} ${if (a==b) "==" else "<>"} $a${" " * (width-a.length)} | $b""") - } - } - } - -// loading - protected def getMethod(classNode: ClassNode, name: String): MethodNode = - classNode.methods.asScala.find(_.name == name) getOrElse - sys.error(s"Didn't find method '$name' in class '${classNode.name}'") - - protected def loadClassNode(name: String, skipDebugInfo: Boolean = true): ClassNode = { - val classBytes: InputStream = (for { - classRep <- classpath.findClass(name) - binary <- classRep.binary - } yield binary.input) getOrElse sys.error(s"failed to load class '$name'; classpath = $classpath") - - val cr = new ClassReader(classBytes) - val cn = new ClassNode() - cr.accept(cn, if (skipDebugInfo) ClassReader.SKIP_DEBUG else 0) - cn - } - - protected lazy val classpath: JavaClassPath = { - import scala.tools.nsc.util.ClassPath.DefaultJavaContext - import scala.tools.util.PathResolver.Defaults - // logic inspired by scala.tools.util.PathResolver implementation - val containers = DefaultJavaContext.classesInExpandedPath(Defaults.javaUserClassPath) - new JavaClassPath(containers, DefaultJavaContext) - } -} - -object BytecodeTest { - /** Parse `file` as a class file, transforms the ASM representation with `f`, - * and overwrites the orginal file. - */ - def modifyClassFile(file: JFile)(f: ClassNode => ClassNode) { - val rfile = new reflect.io.File(file) - def readClass: ClassNode = { - val cr = new ClassReader(rfile.toByteArray()) - val cn = new ClassNode() - cr.accept(cn, 0) - cn - } - - def writeClass(cn: ClassNode) { - val writer = new ClassWriter(0) - cn.accept(writer) - val os = rfile.bufferedOutput() - try { - os.write(writer.toByteArray) - } finally { - os.close() - } - } - - writeClass(f(readClass)) - } -} diff --git a/src/partest/scala/tools/partest/CompilerTest.scala b/src/partest/scala/tools/partest/CompilerTest.scala deleted file mode 100644 index df4a81dee2..0000000000 --- a/src/partest/scala/tools/partest/CompilerTest.scala +++ /dev/null @@ -1,60 +0,0 @@ -/* NSC -- new Scala compiler - * Copyright 2005-2013 LAMP/EPFL - * @author Paul Phillips - */ - -package scala.tools.partest - -import scala.reflect.runtime.{universe => ru} -import scala.tools.nsc._ - -/** For testing compiler internals directly. - * Each source code string in "sources" will be compiled, and - * the check function will be called with the source code and the - * resulting CompilationUnit. The check implementation should - * test for what it wants to test and fail (via assert or other - * exception) if it is not happy. - */ -abstract class CompilerTest extends DirectTest { - def check(source: String, unit: global.CompilationUnit): Unit - - lazy val global: Global = newCompiler() - lazy val units: List[global.CompilationUnit] = compilationUnits(global)(sources: _ *) - import global._ - import definitions.{ compilerTypeFromTag } - - override def extraSettings = "-usejavacp -d " + testOutput.path - - def show() = (sources, units).zipped foreach check - - // Override at least one of these... - def code = "" - def sources: List[String] = List(code) - - // Utility functions - class MkType(sym: Symbol) { - def apply[M](implicit t: ru.TypeTag[M]): Type = - if (sym eq NoSymbol) NoType - else appliedType(sym, compilerTypeFromTag(t)) - } - implicit def mkMkType(sym: Symbol) = new MkType(sym) - - def allMembers(root: Symbol): List[Symbol] = { - def loop(seen: Set[Symbol], roots: List[Symbol]): List[Symbol] = { - val latest = roots flatMap (_.info.members) filterNot (seen contains _) - if (latest.isEmpty) seen.toList.sortWith(_ isLess _) - else loop(seen ++ latest, latest) - } - loop(Set(), List(root)) - } - - class SymsInPackage(pkgName: String) { - def pkg = rootMirror.getPackage(pkgName) - def classes = allMembers(pkg) filter (_.isClass) - def modules = allMembers(pkg) filter (_.isModule) - def symbols = classes ++ terms filterNot (_ eq NoSymbol) - def terms = allMembers(pkg) filter (s => s.isTerm && !s.isConstructor) - def tparams = classes flatMap (_.info.typeParams) - def tpes = symbols map (_.tpe) distinct - } -} diff --git a/src/partest/scala/tools/partest/DirectTest.scala b/src/partest/scala/tools/partest/DirectTest.scala deleted file mode 100644 index 2e6c3baa02..0000000000 --- a/src/partest/scala/tools/partest/DirectTest.scala +++ /dev/null @@ -1,128 +0,0 @@ -/* NSC -- new Scala compiler - * Copyright 2005-2013 LAMP/EPFL - * @author Paul Phillips - */ - -package scala.tools.partest - -import scala.tools.nsc._ -import settings.ScalaVersion -import util.{ SourceFile, BatchSourceFile } -import reporters.{Reporter, ConsoleReporter} -import scala.tools.cmd.CommandLineParser - -/** A class for testing code which is embedded as a string. - * It allows for more complete control over settings, compiler - * configuration, sequence of events, etc. than does partest. - */ -abstract class DirectTest extends App { - // The program being tested in some fashion - def code: String - // produce the output to be compared against a checkfile - def show(): Unit - - // the test file or dir, and output directory - def testPath = SFile(sys.props("partest.test-path")) - def testOutput = Directory(sys.props("partest.output")) - - // override to add additional settings with strings - def extraSettings: String = "" - // a default Settings object - def settings: Settings = newSettings(CommandLineParser tokenize extraSettings) - // a custom Settings object - def newSettings(args: List[String]) = { - val s = new Settings - val allArgs = args ++ (CommandLineParser tokenize debugSettings) - log("newSettings: allArgs = " + allArgs) - s processArguments (allArgs, true) - s - } - // new compiler - def newCompiler(args: String*): Global = { - val settings = newSettings((CommandLineParser tokenize ("-d \"" + testOutput.path + "\" " + extraSettings)) ++ args.toList) - newCompiler(settings) - } - - def newCompiler(settings: Settings): Global = Global(settings, reporter(settings)) - - def reporter(settings: Settings): Reporter = new ConsoleReporter(settings) - - private def newSourcesWithExtension(ext: String)(codes: String*): List[BatchSourceFile] = - codes.toList.zipWithIndex map { - case (src, idx) => new BatchSourceFile(s"newSource${idx + 1}.$ext", src) - } - - def newJavaSources(codes: String*) = newSourcesWithExtension("java")(codes: _*) - def newSources(codes: String*) = newSourcesWithExtension("scala")(codes: _*) - - def compileString(global: Global)(sourceCode: String): Boolean = { - withRun(global)(_ compileSources newSources(sourceCode)) - !global.reporter.hasErrors - } - - def javaCompilationUnits(global: Global)(sourceCodes: String*) = { - sourceFilesToCompiledUnits(global)(newJavaSources(sourceCodes: _*)) - } - - def sourceFilesToCompiledUnits(global: Global)(files: List[SourceFile]) = { - withRun(global) { run => - run compileSources files - run.units.toList - } - } - - def compilationUnits(global: Global)(sourceCodes: String*): List[global.CompilationUnit] = { - val units = sourceFilesToCompiledUnits(global)(newSources(sourceCodes: _*)) - if (global.reporter.hasErrors) { - global.reporter.flush() - sys.error("Compilation failure.") - } - units - } - - def withRun[T](global: Global)(f: global.Run => T): T = { - global.reporter.reset() - f(new global.Run) - } - - // compile the code, optionally first adding to the settings - def compile(args: String*) = compileString(newCompiler(args: _*))(code) - - /** Constructor/main body **/ - try show() - catch { case t: Exception => println(t.getMessage) ; t.printStackTrace ; sys.exit(1) } - - /** Debugger interest only below this line **/ - protected def isDebug = (sys.props contains "partest.debug") || (sys.env contains "PARTEST_DEBUG") - protected def debugSettings = sys.props.getOrElse("partest.debug.settings", "") - - final def log(msg: => Any) { - if (isDebug) Console.err println msg - } - - /** - * Run a test only if the current java version is at least the version specified. - */ - def testUnderJavaAtLeast[A](version: String)(yesRun: =>A) = new TestUnderJavaAtLeast(version, { yesRun }) - - class TestUnderJavaAtLeast[A](version: String, yesRun: => A) { - val javaVersion = System.getProperty("java.specification.version") - - // the "ScalaVersion" class parses Java specification versions just fine - val requiredJavaVersion = ScalaVersion(version) - val executingJavaVersion = ScalaVersion(javaVersion) - val shouldRun = executingJavaVersion >= requiredJavaVersion - val preamble = if (shouldRun) "Attempting" else "Doing fallback for" - - def logInfo() = log(s"$preamble java $version specific test under java version $javaVersion") - - /* - * If the current java version is at least 'version' then 'yesRun' is evaluated - * otherwise 'fallback' is - */ - def otherwise(fallback: =>A): A = { - logInfo() - if (shouldRun) yesRun else fallback - } - } -} diff --git a/src/partest/scala/tools/partest/IcodeTest.scala b/src/partest/scala/tools/partest/IcodeTest.scala deleted file mode 100644 index b12ec0de61..0000000000 --- a/src/partest/scala/tools/partest/IcodeTest.scala +++ /dev/null @@ -1,43 +0,0 @@ -/* NSC -- new Scala compiler - * Copyright 2005-2013 LAMP/EPFL - * @author Paul Phillips - */ - -package scala.tools.partest - -import scala.tools.partest.nest.FileUtil.compareContents - -/** A trait for testing icode. All you need is this in a - * partest source file: - * {{{ - * object Test extends IcodeTest - * }}} - * And then the generated output will be the icode for everything - * in that file. See source for possible customizations. - */ -abstract class IcodeTest extends DirectTest { - // override to check icode at a different point. - def printIcodeAfterPhase = "icode" - // override to use source code other than the file being tested. - def code = testPath.slurp() - - override def extraSettings: String = "-usejavacp -Xprint-icode:" + printIcodeAfterPhase - - // Compile, read in all the *.icode files, delete them, and return their contents - def collectIcode(args: String*): List[String] = { - compile("-d" :: testOutput.path :: args.toList : _*) - val icodeFiles = testOutput.files.toList filter (_ hasExtension "icode") - - try icodeFiles sortBy (_.name) flatMap (f => f.lines.toList) - finally icodeFiles foreach (f => f.delete()) - } - - // Default show() compiles the code with and without optimization and - // outputs the diff. - def show() { - val lines1 = collectIcode("") - val lines2 = collectIcode("-optimise") - - println(compareContents(lines1, lines2)) - } -} diff --git a/src/partest/scala/tools/partest/JavapTest.scala b/src/partest/scala/tools/partest/JavapTest.scala deleted file mode 100644 index 3cb3dc6ca8..0000000000 --- a/src/partest/scala/tools/partest/JavapTest.scala +++ /dev/null @@ -1,26 +0,0 @@ - -package scala.tools.partest - -import scala.util.{Try,Success,Failure} -import java.lang.System.{out => sysout} - -/** A trait for testing repl's javap command - * or possibly examining its output. - */ -abstract class JavapTest extends ReplTest { - - /** Your Assertion Here, whatever you want to bejahen. - * Assertions must be satisfied by all flavors of javap - * and should not be fragile with respect to compiler output. - */ - def yah(res: Seq[String]): Boolean - - def baddies = List(":javap unavailable", ":javap not yet working") - - // give it a pass if javap is broken - override def show() = try { - val res = eval().toSeq - val unsupported = res exists (s => baddies exists (s contains _)) - assert ((unsupported || yah(res)), res.mkString("","\n","\n")) - } catch { case ae: AssertionError => ae.printStackTrace(sysout) } -} diff --git a/src/partest/scala/tools/partest/MemoryTest.scala b/src/partest/scala/tools/partest/MemoryTest.scala deleted file mode 100644 index 58d25d2f01..0000000000 --- a/src/partest/scala/tools/partest/MemoryTest.scala +++ /dev/null @@ -1,38 +0,0 @@ -package scala.tools.partest - -abstract class MemoryTest { - def maxDelta: Double - def calcsPerIter: Int - def calc(): Unit - - def main(args: Array[String]) { - val rt = Runtime.getRuntime() - def memUsage() = { - import java.lang.management._ - import scala.collection.JavaConverters._ - val pools = ManagementFactory.getMemoryPoolMXBeans.asScala - pools.map(_.getUsage.getUsed).sum / 1000000d - } - - val history = scala.collection.mutable.ListBuffer[Double]() - def stressTestIter() = { - var i = 0 - while (i < calcsPerIter) { calc(); i += 1 } - 1 to 5 foreach (_ => rt.gc()) - history += memUsage - } - - 1 to 5 foreach (_ => stressTestIter()) - val reference = memUsage() - 1 to 5 foreach (_ => stressTestIter()) - 1 to 5 foreach (_ => rt.gc()) - val result = memUsage() - history += result - - val delta = result - reference - if (delta > maxDelta) { - println("FAILED") - history foreach (mb => println(mb + " Mb")) - } - } -} diff --git a/src/partest/scala/tools/partest/PartestDefaults.scala b/src/partest/scala/tools/partest/PartestDefaults.scala deleted file mode 100644 index 8478edeb4d..0000000000 --- a/src/partest/scala/tools/partest/PartestDefaults.scala +++ /dev/null @@ -1,28 +0,0 @@ -package scala.tools -package partest - -import scala.concurrent.duration.Duration -import scala.tools.nsc.Properties.{ propOrElse, propOrNone, propOrEmpty } -import java.lang.Runtime.{ getRuntime => runtime } - -object PartestDefaults { - - def testRootName = propOrNone("partest.root") - def srcDirName = propOrElse("partest.srcdir", "files") - def testRootDir = testRootName map (x => Directory(x)) - - // def classPath = propOrElse("partest.classpath", "") - def classPath = PathResolver.Environment.javaUserClassPath // XXX - - def javaCmd = propOrElse("partest.javacmd", "java") - def javacCmd = propOrElse("partest.javac_cmd", "javac") - def javaOpts = propOrElse("partest.java_opts", "") - def scalacOpts = propOrElse("partest.scalac_opts", "") - - def testBuild = propOrNone("partest.build") - def errorCount = propOrElse("partest.errors", "0").toInt - def numThreads = propOrNone("partest.threads") map (_.toInt) getOrElse runtime.availableProcessors - def waitTime = propOrNone("partest.timeout") map (Duration.apply) getOrElse Duration("4 hours") - - //def timeout = "1200000" // per-test timeout -} diff --git a/src/partest/scala/tools/partest/PartestTask.scala b/src/partest/scala/tools/partest/PartestTask.scala deleted file mode 100644 index 8b88021dbf..0000000000 --- a/src/partest/scala/tools/partest/PartestTask.scala +++ /dev/null @@ -1,207 +0,0 @@ -/* __ *\ -** ________ ___ / / ___ Scala Parallel Testing ** -** / __/ __// _ | / / / _ | (c) 2007-2013, LAMP/EPFL ** -** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** -** /____/\___/_/ |_/____/_/ | | ** -** |/ ** -\* */ - -package scala.tools -package partest - -import scala.util.Properties.setProp -import scala.tools.ant.sabbus.CompilationPathProperty -import java.lang.reflect.Method -import org.apache.tools.ant.Task -import org.apache.tools.ant.types.{ Reference, FileSet} -import org.apache.tools.ant.types.Commandline.Argument -import scala.tools.ant.ScalaTask - -/** An Ant task to execute the Scala test suite (NSC). - * - * This task can take the following parameters as attributes: - * - `srcdir`, - * - `classpath`, - * - `classpathref`, - * - `erroronfailed`, - * - `javacmd`, - * - `javaccmd`, - * - `scalacopts`, - * - `debug`, - * - `junitreportdir`. - * - * It also takes the following parameters as nested elements: - * - `compilationpath`. - * - * @author Philippe Haller - */ -class PartestTask extends Task with CompilationPathProperty with ScalaTask { - type Path = org.apache.tools.ant.types.Path - - private var kinds: List[String] = Nil - private var classpath: Option[Path] = None - private var debug = false - private var errorOnFailed: Boolean = true - private var jUnitReportDir: Option[File] = None - private var javaccmd: Option[File] = None - private var javacmd: Option[File] = Option(sys.props("java.home")) map (x => new File(x, "bin/java")) - private var scalacArgs: Option[Seq[Argument]] = None - private var srcDir: Option[String] = None - private var colors: Int = 0 - - def setSrcDir(input: String) { - srcDir = Some(input) - } - - def setColors(input: String) { - try colors = input.toInt catch { case _: NumberFormatException => () } - if (colors > 0) - sys.props("partest.colors") = colors.toString - } - - def setClasspath(input: Path) { - if (classpath.isEmpty) - classpath = Some(input) - else - classpath.get.append(input) - } - - def createClasspath(): Path = { - if (classpath.isEmpty) classpath = Some(new Path(getProject())) - classpath.get.createPath() - } - - def setClasspathref(input: Reference) { - createClasspath().setRefid(input) - } - def setErrorOnFailed(input: Boolean) { - errorOnFailed = input - } - - def setJavaCmd(input: File) { - javacmd = Some(input) - } - - def setKinds(input: String) { - kinds = words(input) - } - - def setJavacCmd(input: File) { - javaccmd = Some(input) - } - - def setScalacOpts(input: String) { - val s = input.split(' ').map { s => val a = new Argument; a.setValue(s); a } - scalacArgs = Some(scalacArgs.getOrElse(Seq()) ++ s) - } - - def createCompilerArg(): Argument = { - val a = new Argument - scalacArgs = Some(scalacArgs.getOrElse(Seq()) :+ a) - a - } - - def setDebug(input: Boolean) { - debug = input - } - - def setJUnitReportDir(input: File) { - jUnitReportDir = Some(input) - } - - override def execute() { - if (debug || sys.props.contains("partest.debug")) { - nest.NestUI.setDebug() - } - - srcDir foreach (x => setProp("partest.srcdir", x)) - - val classpath = this.compilationPath getOrElse sys.error("Mandatory attribute 'compilationPath' is not set.") - val cpfiles = classpath.list map { fs => new File(fs) } toList - def findCp(name: String) = cpfiles find (f => - (f.getName == s"scala-$name.jar") - || (f.absolutePathSegments endsWith Seq("classes", name)) - ) getOrElse sys.error(s"Provided classpath does not contain a Scala $name element.") - - val scalaLibrary = findCp("library") - val scalaReflect = findCp("reflect") - val scalaCompiler = findCp("compiler") - val scalaPartest = findCp("partest") - val scalaActors = findCp("actors") - - def scalacArgsFlat: Option[Seq[String]] = scalacArgs map (_ flatMap { a => - val parts = a.getParts - if (parts eq null) Nil else parts.toSeq - }) - - val antRunner = new scala.tools.partest.nest.AntRunner - val antFileManager = antRunner.fileManager - - // antFileManager.failed = runFailed - antFileManager.CLASSPATH = ClassPath.join(classpath.list: _*) - antFileManager.LATEST_LIB = scalaLibrary.getAbsolutePath - antFileManager.LATEST_REFLECT = scalaReflect.getAbsolutePath - antFileManager.LATEST_COMP = scalaCompiler.getAbsolutePath - antFileManager.LATEST_PARTEST = scalaPartest.getAbsolutePath - antFileManager.LATEST_ACTORS = scalaActors.getAbsolutePath - - javacmd foreach (x => antFileManager.JAVACMD = x.getAbsolutePath) - javaccmd foreach (x => antFileManager.JAVAC_CMD = x.getAbsolutePath) - scalacArgsFlat foreach (antFileManager.SCALAC_OPTS ++= _) - - def runSet(kind: String, files: Array[File]): (Int, Int, List[String]) = { - if (files.isEmpty) (0, 0, List()) - else { - log(s"Running ${files.length} tests in '$kind' at $now") - // log(s"Tests: ${files.toList}") - val results = antRunner.reflectiveRunTestsForFiles(files, kind) - val (passed, failed) = results partition (_.isOk) - val numPassed = passed.size - val numFailed = failed.size - def failedMessages = failed map (_.longStatus) - - log(s"Completed '$kind' at $now") - - // create JUnit Report xml files if directory was specified - jUnitReportDir foreach { d => - d.mkdir - - val report = testReport(kind, results, numPassed, numFailed) - scala.xml.XML.save(d.getAbsolutePath+"/"+kind+".xml", report) - } - - (numPassed, numFailed, failedMessages) - } - } - - val _results = kinds map (k => runSet(k, TestKinds testsFor k map (_.jfile) toArray)) - val allSuccesses = _results map (_._1) sum - val allFailures = _results map (_._2) sum - val allFailedPaths = _results flatMap (_._3) - - def f = if (errorOnFailed && allFailures > 0) buildError(_: String) else log(_: String) - def s = if (allFailures > 1) "s" else "" - val msg = - if (allFailures > 0) - "Test suite finished with %d case%s failing:\n".format(allFailures, s)+ - allFailedPaths.mkString("\n") - else if (allSuccesses == 0) "There were no tests to run." - else "Test suite finished with no failures." - - f(msg) - } - - private def oneResult(res: TestState) = - { - if (res.isOk) scala.xml.NodeSeq.Empty - else - } - - private def testReport(kind: String, results: Iterable[TestState], succs: Int, fails: Int) = - - - { - results map oneResult - } - -} diff --git a/src/partest/scala/tools/partest/ReplTest.scala b/src/partest/scala/tools/partest/ReplTest.scala deleted file mode 100644 index 7381b8af54..0000000000 --- a/src/partest/scala/tools/partest/ReplTest.scala +++ /dev/null @@ -1,44 +0,0 @@ -/* NSC -- new Scala compiler - * Copyright 2005-2013 LAMP/EPFL - * @author Paul Phillips - */ - -package scala.tools.partest - -import scala.tools.nsc.Settings -import scala.tools.nsc.interpreter.ILoop -import scala.tools.partest.nest.FileUtil -import java.lang.reflect.{ Method => JMethod, Field => JField } - -/** A trait for testing repl code. It drops the first line - * of output because the real repl prints a version number. - */ -abstract class ReplTest extends DirectTest { - // override to transform Settings object immediately before the finish - def transformSettings(s: Settings): Settings = s - // final because we need to enforce the existence of a couple settings. - final override def settings: Settings = { - val s = super.settings - // s.Yreplsync.value = true - s.Xnojline.value = true - transformSettings(s) - } - def eval() = { - val s = settings - log("eval(): settings = " + s) - ILoop.runForTranscript(code, s).lines drop 1 - } - def show() = eval() foreach println -} - -abstract class SessionTest extends ReplTest with FileUtil { - def session: String - override final def code = expected filter (_.startsWith(prompt)) map (_.drop(prompt.length)) mkString "\n" - def expected = session.stripMargin.lines.toList - final def prompt = "scala> " - override def show() = { - val out = eval().toList - if (out.size != expected.size) Console println s"Expected ${expected.size} lines, got ${out.size}" - if (out != expected) Console print compareContents(expected, out, "expected", "actual") - } -} diff --git a/src/partest/scala/tools/partest/SecurityTest.scala b/src/partest/scala/tools/partest/SecurityTest.scala deleted file mode 100644 index 1f1c8a95ea..0000000000 --- a/src/partest/scala/tools/partest/SecurityTest.scala +++ /dev/null @@ -1,19 +0,0 @@ -/* NSC -- new Scala compiler - * Copyright 2005-2013 LAMP/EPFL - * @author Paul Phillips - */ - -package scala.tools.partest - -import java.security._ -import java.util._ - -abstract class SecurityTest extends App { - def throwIt(x: Any) = throw new AccessControlException("" + x) - def propertyCheck(p: PropertyPermission): Unit = throwIt(p) - - def check(perm: Permission): Unit = perm match { - case p: PropertyPermission => propertyCheck(p) - case _ => () - } -} diff --git a/src/partest/scala/tools/partest/SigTest.scala b/src/partest/scala/tools/partest/SigTest.scala deleted file mode 100644 index fe233a4fb5..0000000000 --- a/src/partest/scala/tools/partest/SigTest.scala +++ /dev/null @@ -1,52 +0,0 @@ -/* NSC -- new Scala compiler - * Copyright 2005-2013 LAMP/EPFL - * @author Paul Phillips - */ - -package scala.tools.partest - -import scala.tools.nsc.Settings -import scala.tools.nsc.interpreter.ILoop -import java.lang.reflect.{ Method => JMethod, Field => JField } -import scala.reflect.{ClassTag, classTag} - -/** Support code for testing signatures. - */ -trait SigTest { - def mstr(m: JMethod) = " (m) %s%s".format( - m.toGenericString, - if (m.isBridge) " (bridge)" else "" - ) - def fstr(f: JField) = " (f) %s".format(f.toGenericString) - - def isObjectMethodName(name: String) = classOf[Object].getMethods exists (_.getName == name) - - def fields[T: ClassTag](p: JField => Boolean) = { - val cl = classTag[T].runtimeClass - val fs = (cl.getFields ++ cl.getDeclaredFields).distinct sortBy (_.getName) - - fs filter p - } - def methods[T: ClassTag](p: JMethod => Boolean) = { - val cl = classTag[T].runtimeClass - val ms = (cl.getMethods ++ cl.getDeclaredMethods).distinct sortBy (x => (x.getName, x.isBridge)) - - ms filter p - } - def allFields[T: ClassTag]() = fields[T](_ => true) - def allMethods[T: ClassTag]() = methods[T](m => !isObjectMethodName(m.getName)) - def fieldsNamed[T: ClassTag](name: String) = fields[T](_.getName == name) - def methodsNamed[T: ClassTag](name: String) = methods[T](_.getName == name) - - def allGenericStrings[T: ClassTag]() = - (allMethods[T]() map mstr) ++ (allFields[T]() map fstr) - - def genericStrings[T: ClassTag](name: String) = - (methodsNamed[T](name) map mstr) ++ (fieldsNamed[T](name) map fstr) - - def show[T: ClassTag](name: String = "") = { - println(classTag[T].runtimeClass.getName) - if (name == "") allGenericStrings[T]() foreach println - else genericStrings[T](name) foreach println - } -} diff --git a/src/partest/scala/tools/partest/StoreReporterDirectTest.scala b/src/partest/scala/tools/partest/StoreReporterDirectTest.scala deleted file mode 100644 index 7f3604c86c..0000000000 --- a/src/partest/scala/tools/partest/StoreReporterDirectTest.scala +++ /dev/null @@ -1,15 +0,0 @@ -package scala.tools.partest - -import scala.tools.nsc.Settings -import scala.tools.nsc.reporters.StoreReporter -import scala.collection.mutable - -trait StoreReporterDirectTest extends DirectTest { - lazy val storeReporter: StoreReporter = new scala.tools.nsc.reporters.StoreReporter() - - /** Discards all but the first message issued at a given position. */ - def filteredInfos: Seq[storeReporter.Info] = storeReporter.infos.groupBy(_.pos).map(_._2.head).toList - - /** Hook into [[scala.tools.partest.DirectTest]] to install the custom reporter */ - override def reporter(settings: Settings) = storeReporter -} diff --git a/src/partest/scala/tools/partest/TestKinds.scala b/src/partest/scala/tools/partest/TestKinds.scala deleted file mode 100644 index b4e8afd0d2..0000000000 --- a/src/partest/scala/tools/partest/TestKinds.scala +++ /dev/null @@ -1,66 +0,0 @@ -package scala.tools -package partest - -import nest.PathSettings.srcDir - -object TestKinds { - val standardKinds = ("pos neg run jvm res scalacheck scalap specialized instrumented presentation ant" split "\\s+").toList - - def denotesTestFile(p: Path) = p.isFile && p.hasExtension("scala", "res", "xml") - def denotesTestDir(p: Path) = kindOf(p) match { - case "res" => false - case _ => p.isDirectory && p.extension == "" - } - def denotesTestPath(p: Path) = denotesTestDir(p) || denotesTestFile(p) - - // TODO - def isTestForPartest(p: Path) = ( - (p.name == "intentional-failure.scala") - || (p.path contains "test-for-partest") - ) - - def kindOf(p: Path) = { - p.toAbsolute.segments takeRight 2 head - - // (srcDir relativize p.toCanonical).segments match { - // case (".." :: "scaladoc" :: xs) => xs.head - // case xs => xs.head - // } - } - def logOf(p: Path) = { - p.parent / s"${p.stripExtension}-${kindOf(p)}.log" - // p.parent / s"${p.stripExtension}.log" - } - - // true if a test path matches the --grep expression. - private def pathMatchesExpr(path: Path, expr: String) = { - // Matches the expression if any source file contains the expr, - // or if the checkfile contains it, or if the filename contains - // it (the last is case-insensitive.) - def matches(p: Path) = ( - (p.path.toLowerCase contains expr.toLowerCase) - || (p.fileContents contains expr) - ) - def candidates = { - (path changeExtension "check") +: { - if (path.isFile) List(path) - else path.toDirectory.deepList() filter (_.isJavaOrScala) toList - } - } - - (candidates exists matches) - } - - def groupedTests(paths: List[Path]): List[(String, List[Path])] = - (paths.distinct groupBy kindOf).toList sortBy (standardKinds indexOf _._1) - - /** Includes tests for testing partest. */ - private def allTestsForKind(kind: String): List[Path] = - (srcDir / kind toDirectory).list.toList filter denotesTestPath - - def testsForPartest: List[Path] = standardKinds flatMap allTestsForKind filter isTestForPartest - def testsFor(kind: String): List[Path] = allTestsForKind(kind) filterNot isTestForPartest - def grepFor(expr: String): List[Path] = standardTests filter (t => pathMatchesExpr(t, expr)) - def standardTests: List[Path] = standardKinds flatMap testsFor - def failedTests: List[Path] = standardTests filter (p => logOf(p).isFile) -} diff --git a/src/partest/scala/tools/partest/TestState.scala b/src/partest/scala/tools/partest/TestState.scala deleted file mode 100644 index e58b479e54..0000000000 --- a/src/partest/scala/tools/partest/TestState.scala +++ /dev/null @@ -1,64 +0,0 @@ -package scala.tools.partest - -import scala.tools.nsc.FatalError -import scala.tools.nsc.util.stackTraceString - -sealed abstract class TestState { - def testFile: File - def what: String - def reason: String - def transcript: List[String] - - def isOk = false - def isSkipped = false - def testIdent = testFile.testIdent - def transcriptString = transcript mkString EOL - - def identAndReason = testIdent + reasonString - def status = s"$what - $identAndReason" - def longStatus = status + transcriptString - def reasonString = if (reason == "") "" else s" [$reason]" - - def shortStatus = if (isOk) "ok" else "!!" - - override def toString = status -} - -object TestState { - case class Uninitialized(testFile: File) extends TestState { - def what = "uninitialized" - def reason = what - def transcript = Nil - override def shortStatus = "??" - } - case class Pass(testFile: File) extends TestState { - def what = "pass" - override def isOk = true - def transcript: List[String] = Nil - def reason = "" - } - case class Updated(testFile: File) extends TestState { - def what = "updated" - override def isOk = true - def transcript: List[String] = Nil - def reason = "updated check file" - override def shortStatus = "++" - } - case class Skip(testFile: File, reason: String) extends TestState { - def what = "skip" - override def isOk = true - override def isSkipped = true - def transcript: List[String] = Nil - override def shortStatus = "--" - } - case class Fail(testFile: File, reason: String, transcript: List[String]) extends TestState { - def what = "fail" - } - case class Crash(testFile: File, caught: Throwable, transcript: List[String]) extends TestState { - def what = "crash" - def reason = s"caught $caught_s - ${caught.getMessage}" - - private def caught_s = (caught.getClass.getName split '.').last - override def transcriptString = nljoin(super.transcriptString, caught_s) - } -} diff --git a/src/partest/scala/tools/partest/TestUtil.scala b/src/partest/scala/tools/partest/TestUtil.scala deleted file mode 100644 index 5c177ac962..0000000000 --- a/src/partest/scala/tools/partest/TestUtil.scala +++ /dev/null @@ -1,38 +0,0 @@ -package scala.tools.partest - -import scala.reflect.{ classTag, ClassTag } - -trait TestUtil { - /** Given function and block of code, evaluates code block, - * calls function with nanoseconds elapsed, and returns block result. - */ - def timed[T](f: Long => Unit)(body: => T): T = { - val start = System.nanoTime - val result = body - val end = System.nanoTime - - f(end - start) - result - } - /** Times body and returns (nanos, result). - */ - def alsoNanos[T](body: => T): (Long, T) = { - var nanos = 0L - val result = timed(nanos = _)(body) - - (nanos, result) - } - def nanos(body: => Unit): Long = alsoNanos(body)._1 - - def intercept[T <: Exception : ClassTag](code: => Unit): Unit = - try { - code - assert(false, "did not throw " + classTag[T]) - } catch { - case ex: Exception if classTag[T].runtimeClass isInstance ex => - } -} - -// Used in tests. -object TestUtil extends TestUtil { -} diff --git a/src/partest/scala/tools/partest/antlib.xml b/src/partest/scala/tools/partest/antlib.xml deleted file mode 100644 index b3b98e853f..0000000000 --- a/src/partest/scala/tools/partest/antlib.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - diff --git a/src/partest/scala/tools/partest/instrumented/Instrumentation.scala b/src/partest/scala/tools/partest/instrumented/Instrumentation.scala deleted file mode 100644 index 18dd740208..0000000000 --- a/src/partest/scala/tools/partest/instrumented/Instrumentation.scala +++ /dev/null @@ -1,93 +0,0 @@ -/* NEST (New Scala Test) - * Copyright 2007-2013 LAMP/EPFL - * @author Grzegorz Kossakowski - */ - -package scala.tools.partest.instrumented - -import scala.collection.JavaConverters._ - -case class MethodCallTrace(className: String, methodName: String, methodDescriptor: String) { - override def toString(): String = className + "." + methodName + methodDescriptor -} -object MethodCallTrace { - implicit val ordering: Ordering[MethodCallTrace] = Ordering.by(x => (x.className, x.methodName, x.methodDescriptor)) -} - -/** - * An object that controls profiling of instrumented byte-code. The instrumentation is achieved - * by using `java.lang.instrument` package. The instrumentation agent can be found in - * `scala.tools.partest.javaagent` package. - * - * At the moment the following classes are being instrumented: - * * all classes with empty package - * * all classes from scala package (except for classes responsible for instrumentation) - * - * The canonical way of using instrumentation is have a test-case in `files/instrumented` directory. - * The following code in main: - * - * {{{ - * import scala.tools.partest.instrumented.Instrumentation._ - * def main(args: Array[String]): Unit = { - * startProfiling() - * // should box the boolean - println(true) - stopProfiling() - printStatistics() - * } - * }}} - * - * - * should print: - * - * {{{ - * true - * Method call statistics: - * scala/Predef$.println(Ljava/lang/Object;)V: 1 - * scala/runtime/BoxesRunTime.boxToBoolean(Z)Ljava/lang/Boolean;: 1 - * }}} - */ -object Instrumentation { - - type Statistics = Map[MethodCallTrace, Int] - - def startProfiling(): Unit = Profiler.startProfiling() - def stopProfiling(): Unit = Profiler.stopProfiling() - def resetProfiling(): Unit = Profiler.resetProfiling() - def isProfiling(): Boolean = Profiler.isProfiling() - - def getStatistics: Statistics = { - val isProfiling = Profiler.isProfiling() - if (isProfiling) { - Profiler.stopProfiling() - } - val stats = Profiler.getStatistics().asScala.toSeq.map { - case (trace, count) => MethodCallTrace(trace.className, trace.methodName, trace.methodDescriptor) -> count.intValue - } - val res = Map(stats: _*) - if (isProfiling) { - Profiler.startProfiling() - } - res - } - - val standardFilter: MethodCallTrace => Boolean = t => { - // ignore all calls to Console trigger by printing - t.className != "scala/Console$" && - // console accesses DynamicVariable, let's discard it too - !t.className.startsWith("scala/util/DynamicVariable") - } - - // Used in tests. - def printStatistics(stats: Statistics = getStatistics, filter: MethodCallTrace => Boolean = standardFilter): Unit = { - val stats = getStatistics - println("Method call statistics:") - val toBePrinted = stats.toSeq.filter(p => filter(p._1)).sortBy(_._1) - // - val format = "%5d %s\n" - toBePrinted foreach { - case (trace, count) => printf(format, count, trace) - } - } - -} diff --git a/src/partest/scala/tools/partest/instrumented/Profiler.java b/src/partest/scala/tools/partest/instrumented/Profiler.java deleted file mode 100644 index e267e197e7..0000000000 --- a/src/partest/scala/tools/partest/instrumented/Profiler.java +++ /dev/null @@ -1,82 +0,0 @@ -/* NEST (New Scala Test) - * Copyright 2007-2013 LAMP/EPFL - * @author Grzegorz Kossakowski - */ - -package scala.tools.partest.instrumented; - -import java.util.HashMap; -import java.util.Map; - -/** - * A simple profiler class that counts method invocations. It is being used in byte-code instrumentation by inserting - * call to {@link Profiler#methodCalled(String, String, String)} at the beginning of every instrumented class. - * - * WARANING: This class is INTERNAL implementation detail and should never be used directly. It's made public only - * because it must be universally accessible for instrumentation needs. If you want to profile your test use - * {@link Instrumentation} instead. - */ -public class Profiler { - - private static boolean isProfiling = false; - private static Map counts = new HashMap(); - - static public class MethodCallTrace { - final String className; - final String methodName; - final String methodDescriptor; - - public MethodCallTrace(final String className, final String methodName, final String methodDescriptor) { - this.className = className; - this.methodName = methodName; - this.methodDescriptor = methodDescriptor; - } - - @Override - public boolean equals(Object obj) { - if (!(obj instanceof MethodCallTrace)) { - return false; - } else { - MethodCallTrace that = (MethodCallTrace) obj; - return that.className.equals(className) && that.methodName.equals(methodName) && that.methodDescriptor.equals(methodDescriptor); - } - } - @Override - public int hashCode() { - return className.hashCode() ^ methodName.hashCode() ^ methodDescriptor.hashCode(); - } - } - - public static void startProfiling() { - isProfiling = true; - } - - public static void stopProfiling() { - isProfiling = false; - } - - public static boolean isProfiling() { - return isProfiling; - } - - public static void resetProfiling() { - counts = new HashMap(); - } - - public static void methodCalled(final String className, final String methodName, final String methodDescriptor) { - if (isProfiling) { - MethodCallTrace trace = new MethodCallTrace(className, methodName, methodDescriptor); - Integer counter = counts.get(trace); - if (counter == null) { - counts.put(trace, 1); - } else { - counts.put(trace, counter+1); - } - } - } - - public static Map getStatistics() { - return new HashMap(counts); - } - -} diff --git a/src/partest/scala/tools/partest/javaagent/ASMTransformer.java b/src/partest/scala/tools/partest/javaagent/ASMTransformer.java deleted file mode 100644 index 878c8613d5..0000000000 --- a/src/partest/scala/tools/partest/javaagent/ASMTransformer.java +++ /dev/null @@ -1,49 +0,0 @@ -/* NEST (New Scala Test) - * Copyright 2007-2013 LAMP/EPFL - * @author Grzegorz Kossakowski - */ - -package scala.tools.partest.javaagent; - -import java.lang.instrument.ClassFileTransformer; -import java.security.ProtectionDomain; - -import scala.tools.asm.ClassReader; -import scala.tools.asm.ClassWriter; - -public class ASMTransformer implements ClassFileTransformer { - - private boolean shouldTransform(String className) { - return - // do not instrument instrumentation logic (in order to avoid infinite recursion) - !className.startsWith("scala/tools/partest/instrumented/") && - !className.startsWith("scala/tools/partest/javaagent/") && - // we instrument all classes from empty package - (!className.contains("/") || - // we instrument all classes from scala package - className.startsWith("scala/") || - // we instrument all classes from `instrumented` package - className.startsWith("instrumented/")); - } - - public byte[] transform(final ClassLoader classLoader, final String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) { - if (shouldTransform(className)) { - ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_MAXS) { - @Override protected String getCommonSuperClass(final String type1, final String type2) { - // Since we are not recomputing stack frame map, this should never be called we override this method because - // default implementation uses reflection for implementation and might try to load the class that we are - // currently processing. That leads to weird results like swallowed exceptions and classes being not - // transformed. - throw new RuntimeException("Unexpected call to getCommonSuperClass(" + type1 + ", " + type2 + - ") while transforming " + className); - } - }; - ProfilerVisitor visitor = new ProfilerVisitor(writer); - ClassReader reader = new ClassReader(classfileBuffer); - reader.accept(visitor, 0); - return writer.toByteArray(); - } else { - return classfileBuffer; - } - } -} diff --git a/src/partest/scala/tools/partest/javaagent/MANIFEST.MF b/src/partest/scala/tools/partest/javaagent/MANIFEST.MF deleted file mode 100644 index be0fee46a2..0000000000 --- a/src/partest/scala/tools/partest/javaagent/MANIFEST.MF +++ /dev/null @@ -1 +0,0 @@ -Premain-Class: scala.tools.partest.javaagent.ProfilingAgent diff --git a/src/partest/scala/tools/partest/javaagent/ProfilerVisitor.java b/src/partest/scala/tools/partest/javaagent/ProfilerVisitor.java deleted file mode 100644 index 8306327b14..0000000000 --- a/src/partest/scala/tools/partest/javaagent/ProfilerVisitor.java +++ /dev/null @@ -1,59 +0,0 @@ -/* NEST (New Scala Test) - * Copyright 2007-2013 LAMP/EPFL - * @author Grzegorz Kossakowski - */ - -package scala.tools.partest.javaagent; - -import scala.tools.asm.ClassVisitor; -import scala.tools.asm.MethodVisitor; -import scala.tools.asm.Opcodes; - -public class ProfilerVisitor extends ClassVisitor implements Opcodes { - - private static String profilerClass = "scala/tools/partest/instrumented/Profiler"; - - public ProfilerVisitor(final ClassVisitor cv) { - super(ASM4, cv); - } - - private String className = null; - - @Override - public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) { - className = name; - super.visit(version, access, name, signature, superName, interfaces); - } - - public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { - // delegate the method call to the next - // chained visitor - MethodVisitor mv = cv.visitMethod(access, name, desc, signature, exceptions); - if (!profilerClass.equals(className)) { - // only instrument non-abstract methods - if((access & ACC_ABSTRACT) == 0) { - assert(className != null); - /* The following instructions do not modify compressed stack frame map so - * we don't need to worry about recalculating stack frame map. Specifically, - * let's quote "ASM 4.0, A Java bytecode engineering library" guide (p. 40): - * - * In order to save space, a compiled method does not contain one frame per - * instruction: in fact it contains only the frames for the instructions - * that correspond to jump targets or exception handlers, or that follow - * unconditional jump instructions. Indeed the other frames can be easily - * and quickly inferred from these ones. - * - * Instructions below are just loading constants and calling a method so according - * to definition above they do not contribute to compressed stack frame map. - */ - mv.visitLdcInsn(className); - mv.visitLdcInsn(name); - mv.visitLdcInsn(desc); - mv.visitMethodInsn(INVOKESTATIC, profilerClass, "methodCalled", - "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V"); - } - } - return mv; - } - -} diff --git a/src/partest/scala/tools/partest/javaagent/ProfilingAgent.java b/src/partest/scala/tools/partest/javaagent/ProfilingAgent.java deleted file mode 100644 index 3b18987040..0000000000 --- a/src/partest/scala/tools/partest/javaagent/ProfilingAgent.java +++ /dev/null @@ -1,25 +0,0 @@ -/* NEST (New Scala Test) - * Copyright 2007-2013 LAMP/EPFL - * @author Grzegorz Kossakowski - */ - -package scala.tools.partest.javaagent; - -import java.lang.instrument.Instrumentation; -import java.lang.instrument.UnmodifiableClassException; - -/** - * Profiling agent that instruments byte-code to insert calls to - * {@link scala.tools.partest.instrumented.Profiler#methodCalled(String, String, String)} - * by using ASM library for byte-code manipulation. - */ -public class ProfilingAgent { - public static void premain(String args, Instrumentation inst) throws UnmodifiableClassException { - // NOTE: we are adding transformer that won't be applied to classes that are already loaded - // This should be ok because premain should be executed before main is executed so Scala library - // and the test-case itself won't be loaded yet. We rely here on the fact that ASMTransformer does - // not depend on Scala library. In case our assumptions are wrong we can always insert call to - // inst.retransformClasses. - inst.addTransformer(new ASMTransformer(), false); - } -} diff --git a/src/partest/scala/tools/partest/nest/AntRunner.scala b/src/partest/scala/tools/partest/nest/AntRunner.scala deleted file mode 100644 index 1d3b79171b..0000000000 --- a/src/partest/scala/tools/partest/nest/AntRunner.scala +++ /dev/null @@ -1,30 +0,0 @@ -/* __ *\ -** ________ ___ / / ___ Scala Parallel Testing ** -** / __/ __// _ | / / / _ | (c) 2007-2013, LAMP/EPFL ** -** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** -** /____/\___/_/ |_/____/_/ | | ** -** |/ ** -\* */ - - -package scala.tools.partest -package nest - -class AntRunner extends DirectRunner { - - val fileManager = new FileManager { - var JAVACMD: String = "java" - var JAVAC_CMD: String = "javac" - var CLASSPATH: String = _ - var LATEST_LIB: String = _ - var LATEST_REFLECT: String = _ - var LATEST_COMP: String = _ - var LATEST_PARTEST: String = _ - var LATEST_ACTORS: String = _ - val testRootPath: String = "test" - val testRootDir: Directory = Directory(testRootPath) - } - - def reflectiveRunTestsForFiles(kindFiles: Array[File], kind: String): List[TestState] = - runTestsForFiles(kindFiles.toList, kind) -} diff --git a/src/partest/scala/tools/partest/nest/ConsoleFileManager.scala b/src/partest/scala/tools/partest/nest/ConsoleFileManager.scala deleted file mode 100644 index b436675d3a..0000000000 --- a/src/partest/scala/tools/partest/nest/ConsoleFileManager.scala +++ /dev/null @@ -1,189 +0,0 @@ -/* NEST (New Scala Test) - * Copyright 2007-2013 LAMP/EPFL - * @author Philipp Haller - */ - - - -package scala.tools.partest -package nest - -import java.io.{ FilenameFilter, IOException } -import java.net.URI -import scala.util.Properties.{ propOrElse, scalaCmd, scalacCmd } -import scala.tools.nsc.{ io, util } -import PathResolver.{ Environment, Defaults } - -class ConsoleFileManager extends FileManager { - var testBuild: Option[String] = PartestDefaults.testBuild - def testBuildFile = testBuild map (testParent / _) - - var testClasses: Option[String] = None - - def this(buildPath: String, rawClasses: Boolean) = { - this() - if (rawClasses) - testClasses = Some(buildPath) - else - testBuild = Some(buildPath) - // re-run because initialization of default - // constructor must be updated - findLatest() - } - - def this(buildPath: String) = { - this(buildPath, false) - } - - def this(buildPath: String, rawClasses: Boolean, moreOpts: String) = { - this(buildPath, rawClasses) - SCALAC_OPTS = SCALAC_OPTS ++ moreOpts.split(' ').toSeq.filter(_.length > 0) - } - - lazy val srcDir = PathSettings.srcDir - lazy val testRootDir = PathSettings.testRoot - lazy val testRootPath = testRootDir.toAbsolute.path - def testParent = testRootDir.parent - - var CLASSPATH = PartestDefaults.classPath - var JAVACMD = PartestDefaults.javaCmd - var JAVAC_CMD = PartestDefaults.javacCmd - - - vlog("CLASSPATH: "+CLASSPATH) - - if (!srcDir.isDirectory) { - NestUI.failure("Source directory \"" + srcDir.path + "\" not found") - sys.exit(1) - } - - CLASSPATH = { - val libs = (srcDir / Directory("lib")).files filter (_ hasExtension "jar") map (_.toCanonical.path) - - // add all jars in libs - (CLASSPATH :: libs.toList) mkString pathSeparator - } - - def findLatest() { - vlog("test parent: "+testParent) - - def prefixFileWith(parent: File, relPath: String) = (SFile(parent) / relPath).toCanonical - def prefixFile(relPath: String) = (testParent / relPath).toCanonical - - if (!testClasses.isEmpty) { - testClassesDir = Path(testClasses.get).toCanonical.toDirectory - vlog("Running with classes in "+testClassesDir) - - latestLibFile = testClassesDir / "library" - latestActorsFile = testClassesDir / "library" / "actors" - latestReflectFile = testClassesDir / "reflect" - latestCompFile = testClassesDir / "compiler" - latestPartestFile = testClassesDir / "partest" - } - else if (testBuild.isDefined) { - val dir = Path(testBuild.get) - vlog("Running on "+dir) - latestLibFile = dir / "lib/scala-library.jar" - latestActorsFile = dir / "lib/scala-actors.jar" - latestReflectFile = dir / "lib/scala-reflect.jar" - latestCompFile = dir / "lib/scala-compiler.jar" - latestPartestFile = dir / "lib/scala-partest.jar" - } - else { - def setupQuick() { - vlog("Running build/quick") - latestLibFile = prefixFile("build/quick/classes/library") - latestActorsFile = prefixFile("build/quick/classes/library/actors") - latestReflectFile = prefixFile("build/quick/classes/reflect") - latestCompFile = prefixFile("build/quick/classes/compiler") - latestPartestFile = prefixFile("build/quick/classes/partest") - } - - def setupInst() { - vlog("Running dist (installed)") - val p = testParent.getParentFile - latestLibFile = prefixFileWith(p, "lib/scala-library.jar") - latestActorsFile = prefixFileWith(p, "lib/scala-actors.jar") - latestReflectFile = prefixFileWith(p, "lib/scala-reflect.jar") - latestCompFile = prefixFileWith(p, "lib/scala-compiler.jar") - latestPartestFile = prefixFileWith(p, "lib/scala-partest.jar") - } - - def setupDist() { - vlog("Running dists/latest") - latestLibFile = prefixFile("dists/latest/lib/scala-library.jar") - latestActorsFile = prefixFile("dists/latest/lib/scala-actors.jar") - latestReflectFile = prefixFile("dists/latest/lib/scala-reflect.jar") - latestCompFile = prefixFile("dists/latest/lib/scala-compiler.jar") - latestPartestFile = prefixFile("dists/latest/lib/scala-partest.jar") - } - - def setupPack() { - vlog("Running build/pack") - latestLibFile = prefixFile("build/pack/lib/scala-library.jar") - latestActorsFile = prefixFile("build/pack/lib/scala-actors.jar") - latestReflectFile = prefixFile("build/pack/lib/scala-reflect.jar") - latestCompFile = prefixFile("build/pack/lib/scala-compiler.jar") - latestPartestFile = prefixFile("build/pack/lib/scala-partest.jar") - } - - def mostRecentOf(base: String, names: String*) = - names map (x => prefixFile(base + "/" + x).lastModified) reduceLeft (_ max _) - - // detect most recent build - val quickTime = mostRecentOf("build/quick/classes", "compiler/compiler.properties", "reflect/reflect.properties", "library/library.properties") - val packTime = mostRecentOf("build/pack/lib", "scala-compiler.jar", "scala-reflect.jar", "scala-library.jar") - val distTime = mostRecentOf("dists/latest/lib", "scala-compiler.jar", "scala-reflect.jar", "scala-library.jar") - val instTime = mostRecentOf("lib", "scala-compiler.jar", "scala-reflect.jar", "scala-library.jar") - - val pairs = Map( - (quickTime, () => setupQuick()), - (packTime, () => setupPack()), - (distTime, () => setupDist()), - (instTime, () => setupInst()) - ) - - // run setup based on most recent time - pairs(pairs.keys max)() - } - - LATEST_LIB = latestLibFile.getAbsolutePath - LATEST_REFLECT = latestReflectFile.getAbsolutePath - LATEST_COMP = latestCompFile.getAbsolutePath - LATEST_PARTEST = latestPartestFile.getAbsolutePath - LATEST_ACTORS = latestActorsFile.getAbsolutePath - } - - var LATEST_LIB: String = "" - var LATEST_REFLECT: String = "" - var LATEST_COMP: String = "" - var LATEST_PARTEST: String = "" - var LATEST_ACTORS: String = "" - - var latestLibFile: File = _ - var latestActorsFile: File = _ - var latestReflectFile: File = _ - var latestCompFile: File = _ - var latestPartestFile: File = _ - //def latestScalapFile: File = (latestLibFile.parent / "scalap.jar").jfile - //def latestScalapFile: File = new File(latestLibFile.getParentFile, "scalap.jar") - var testClassesDir: Directory = _ - // initialize above fields - findLatest() - - /* - def getFiles(kind: String, cond: Path => Boolean): List[File] = { - def ignoreDir(p: Path) = List("svn", "obj") exists (p hasExtension _) - - val dir = Directory(srcDir / kind) - - if (dir.isDirectory) NestUI.verbose("look in %s for tests" format dir) - else NestUI.failure("Directory '%s' not found" format dir) - - val files = dir.list filterNot ignoreDir filter cond toList - - ( if (failed) files filter (x => logFileExists(x, kind)) else files ) map (_.jfile) - } - */ - var latestFjbgFile: File = _ -} diff --git a/src/partest/scala/tools/partest/nest/ConsoleRunner.scala b/src/partest/scala/tools/partest/nest/ConsoleRunner.scala deleted file mode 100644 index 8189446162..0000000000 --- a/src/partest/scala/tools/partest/nest/ConsoleRunner.scala +++ /dev/null @@ -1,219 +0,0 @@ -/* NEST (New Scala Test) - * Copyright 2007-2013 LAMP/EPFL - * @author Philipp Haller - */ - -package scala.tools -package partest -package nest - -import utils.Properties._ -import scala.tools.nsc.Properties.{ versionMsg, setProp } -import scala.collection.{ mutable, immutable } -import PathSettings.srcDir -import TestKinds._ -import scala.reflect.internal.util.Collections.distinctBy -import scala.tools.cmd.{ CommandLine, CommandLineParser, Instance } - -class ConsoleRunner(argstr: String) extends { - val parsed = ConsoleRunnerSpec.creator(CommandLineParser tokenize argstr) -} with DirectRunner with ConsoleRunnerSpec with Instance { - import NestUI._ - import NestUI.color._ - - // So we can ctrl-C a test run and still hear all - // the buffered failure info. - scala.sys addShutdownHook issueSummaryReport() - - var fileManager: ConsoleFileManager = _ - - private var totalTests = 0 - private val passedTests = mutable.ListBuffer[TestState]() - private val failedTests = mutable.ListBuffer[TestState]() - - def comment(s: String) = echo(magenta("# " + s)) - def levyJudgment() = { - if (totalTests == 0) echoMixed("No tests to run.") - else if (elapsedMillis == 0) echoMixed("Test Run ABORTED") - else if (isSuccess) echoPassed("Test Run PASSED") - else echoFailed("Test Run FAILED") - } - - def passFailString(passed: Int, failed: Int, skipped: Int): String = { - val total = passed + failed + skipped - val isSuccess = failed == 0 - def p0 = s"$passed/$total" - def p = ( if (isSuccess) bold(green(p0)) else p0 ) + " passed" - def f = if (failed == 0) "" else bold(red("" + failed)) + " failed" - def s = if (skipped == 0) "" else bold(yellow("" + skipped)) + " skipped" - - oempty(p, f, s) mkString ", " - } - - private var summarizing = false - private var elapsedMillis = 0L - private var expectedFailures = 0 - private def isSuccess = failedTests.size == expectedFailures - - def issueSummaryReport() { - // Don't run twice - if (!summarizing) { - summarizing = true - - val passed0 = passedTests.toList - val failed0 = failedTests.toList - val passed = passed0.size - val failed = failed0.size - val skipped = totalTests - (passed + failed) - val passFail = passFailString(passed, failed, skipped) - val elapsed = if (elapsedMillis > 0) " (elapsed time: " + elapsedString(elapsedMillis) + ")" else "" - val message = passFail + elapsed - - if (failed0.nonEmpty) { - if (isPartestVerbose) { - echo(bold(cyan("##### Transcripts from failed tests #####\n"))) - failed0 foreach { state => - comment("partest " + state.testFile) - echo(state.transcriptString + "\n") - } - } - - def files_s = failed0.map(_.testFile).mkString(""" \""" + "\n ") - echo("# Failed test paths (this command will update checkfiles)") - echo("test/partest --update-check \\\n " + files_s + "\n") - } - - echo(message) - levyJudgment() - } - } - - def run(): Unit = { - // Early return on no args, version, or invalid args - if (optVersion) return echo(versionMsg) - if ((argstr == "") || optHelp) return NestUI.usage() - - val (individualTests, invalid) = parsed.residualArgs map (p => Path(p)) partition denotesTestPath - if (invalid.nonEmpty) { - if (isPartestVerbose) - invalid foreach (p => echoWarning(s"Discarding invalid test path " + p)) - else if (!isPartestTerse) - echoWarning(s"Discarding ${invalid.size} invalid test paths") - } - - optSourcePath foreach (x => setProp("partest.srcdir", x)) - optTimeout foreach (x => setProp("partest.timeout", x)) - - fileManager = - if (optBuildPath.isDefined) new ConsoleFileManager(optBuildPath.get) - else if (optClassPath.isDefined) new ConsoleFileManager(optClassPath.get, true) - else if (optPack) new ConsoleFileManager("build/pack") - else new ConsoleFileManager // auto detection, see ConsoleFileManager.findLatest - - fileManager.updateCheck = optUpdateCheck - fileManager.failed = optFailed - - val partestTests = ( - if (optSelfTest) TestKinds.testsForPartest - else Nil - ) - - val grepExpr = optGrep getOrElse "" - - // If --grep is given we suck in every file it matches. - val greppedTests = if (grepExpr == "") Nil else { - val paths = grepFor(grepExpr) - if (paths.isEmpty) - echoWarning(s"grep string '$grepExpr' matched no tests.\n") - - paths.sortBy(_.toString) - } - - val isRerun = optFailed - val rerunTests = if (isRerun) TestKinds.failedTests else Nil - def miscTests = partestTests ++ individualTests ++ greppedTests ++ rerunTests - - val givenKinds = standardKinds filter parsed.isSet - val kinds = ( - if (optAll) standardKinds - else if (givenKinds.nonEmpty) givenKinds - else if (invalid.isEmpty && miscTests.isEmpty && !isRerun) standardKinds // If no kinds, --grep, or individual tests were given, assume --all - else Nil - ) - val kindsTests = kinds flatMap testsFor - val dir = - if (fileManager.testClasses.isDefined) fileManager.testClassesDir - else fileManager.testBuildFile getOrElse { - fileManager.latestCompFile.getParentFile.getParentFile.getAbsoluteFile - } - - def testContributors = { - List( - if (partestTests.isEmpty) "" else "partest self-tests", - if (rerunTests.isEmpty) "" else "previously failed tests", - if (kindsTests.isEmpty) "" else s"${kinds.size} named test categories", - if (greppedTests.isEmpty) "" else s"${greppedTests.size} tests matching '$grepExpr'", - if (individualTests.isEmpty) "" else "specified tests" - ) filterNot (_ == "") mkString ", " - } - - def banner = { - val vmBin = javaHome + fileSeparator + "bin" - val vmName = "%s (build %s, %s)".format(javaVmName, javaVmVersion, javaVmInfo) - val vmOpts = fileManager.JAVA_OPTS - - s"""|Scala compiler classes in: $dir - |Scala version is: $versionMsg - |Scalac options are: ${fileManager.SCALAC_OPTS mkString " "} - |Java binaries in: $vmBin - |Java runtime is: $vmName - |Java options are: $vmOpts - |Source directory is: $srcDir - |Available processors: ${Runtime.getRuntime().availableProcessors()} - |Java Classpath: ${sys.props("java.class.path")} - """.stripMargin - } - - chatty(banner) - - val allTests: List[Path] = distinctBy(miscTests ++ kindsTests)(_.toCanonical) sortBy (_.toString) - val grouped = (allTests groupBy kindOf).toList sortBy (x => standardKinds indexOf x._1) - - totalTests = allTests.size - expectedFailures = propOrNone("partest.errors") match { - case Some(num) => num.toInt - case _ => 0 - } - val expectedFailureMessage = if (expectedFailures == 0) "" else s" (expecting $expectedFailures to fail)" - echo(s"Selected $totalTests tests drawn from $testContributors$expectedFailureMessage\n") - - val (_, millis) = timed { - for ((kind, paths) <- grouped) { - val num = paths.size - val ss = if (num == 1) "" else "s" - comment(s"starting $num test$ss in $kind") - val results = runTestsForFiles(paths map (_.jfile.getAbsoluteFile), kind) - val (passed, failed) = results partition (_.isOk) - - passedTests ++= passed - failedTests ++= failed - if (failed.nonEmpty) { - comment(passFailString(passed.size, failed.size, 0) + " in " + kind) - } - echo("") - } - } - this.elapsedMillis = millis - issueSummaryReport() - System exit ( if (isSuccess) 0 else 1 ) - } - - run() -} - -object ConsoleRunner { - def main(args: Array[String]): Unit = { - new ConsoleRunner(args mkString " ") - } -} - diff --git a/src/partest/scala/tools/partest/nest/ConsoleRunnerSpec.scala b/src/partest/scala/tools/partest/nest/ConsoleRunnerSpec.scala deleted file mode 100644 index bb831a4964..0000000000 --- a/src/partest/scala/tools/partest/nest/ConsoleRunnerSpec.scala +++ /dev/null @@ -1,54 +0,0 @@ -package scala.tools.partest.nest - -import language.postfixOps - -import scala.tools.cmd.{ CommandLine, Interpolation, Meta, Reference, Spec } - -trait ConsoleRunnerSpec extends Spec with Meta.StdOpts with Interpolation { - def referenceSpec = ConsoleRunnerSpec - def programInfo = Spec.Info( - "console-runner", - "Usage: NestRunner [options] [test test ...]", - "scala.tools.partest.nest.ConsoleRunner") - - heading("Test categories:") - val optAll = "all" / "run all tests" --? - val optPos = "pos" / "run compilation tests (success)" --? - val optNeg = "neg" / "run compilation tests (failure)" --? - val optRun = "run" / "run interpreter and backend tests" --? - val optJvm = "jvm" / "run JVM backend tests" --? - val optRes = "res" / "run resident compiler tests" --? - val optAnt = "ant" / "run Ant tests" --? - val optScalap = "scalap" / "run scalap tests" --? - val optSpecialized = "specialized" / "run specialization tests" --? - val optScalacheck = "scalacheck" / "run ScalaCheck tests" --? - val optInstrumented = "instrumented" / "run instrumented tests" --? - val optPresentation = "presentation" / "run presentation compiler tests" --? - - heading("Test runner options:") - val optFailed = "failed" / "run only those tests that failed during the last run" --? - val optTimeout = "timeout" / "aborts the test suite after the given amount of time" --| - val optPack = "pack" / "pick compiler/reflect/library in build/pack, and run all tests" --? - val optGrep = "grep" / "run all tests whose source file contains the expression given to grep" --| - val optUpdateCheck = "update-check" / "instead of failing tests with output change, update checkfile (use with care!)" --? - val optBuildPath = "buildpath" / "set (relative) path to build jars (ex.: --buildpath build/pack)" --| - val optClassPath = "classpath" / "set (absolute) path to build classes" --| - val optSourcePath = "srcpath" / "set (relative) path to test source files (ex.: --srcpath pending)" --| - - heading("Test output options:") - val optShowDiff = "show-diff" / "show diffs for failed tests" --> NestUI.setDiffOnFail() - val optVerbose = "verbose" / "show verbose progress information" --> NestUI.setVerbose() - val optTerse = "terse" / "show terse progress information" --> NestUI.setTerse() - val optDebug = "debug" / "enable debugging output" --> NestUI.setDebug() - - heading("Other options:") - val optVersion = "version" / "show Scala version and exit" --? - val optSelfTest = "self-test" / "run tests for partest itself" --? - val optHelp = "help" / "show this page and exit" --? - -} - -object ConsoleRunnerSpec extends ConsoleRunnerSpec with Reference { - type ThisCommandLine = CommandLine - def creator(args: List[String]): ThisCommandLine = new CommandLine(ConsoleRunnerSpec, args) -} diff --git a/src/partest/scala/tools/partest/nest/DirectCompiler.scala b/src/partest/scala/tools/partest/nest/DirectCompiler.scala deleted file mode 100644 index 8e5ff2abc4..0000000000 --- a/src/partest/scala/tools/partest/nest/DirectCompiler.scala +++ /dev/null @@ -1,105 +0,0 @@ -/* NEST (New Scala Test) - * Copyright 2007-2013 LAMP/EPFL - * @author Philipp Haller - */ - -package scala.tools.partest -package nest - -import scala.tools.nsc.{ Global, Settings, CompilerCommand, FatalError } -import scala.tools.nsc.reporters.{ Reporter, ConsoleReporter } -import scala.tools.nsc.util.{ FakePos, stackTraceString } -import scala.tools.nsc.Properties.{ setProp, propOrEmpty } -import scala.reflect.io.AbstractFile -import scala.reflect.internal.util.Position -import java.io.{ BufferedReader, PrintWriter, FileReader, Writer, FileWriter } - -class ExtConsoleReporter(settings: Settings, val writer: PrintWriter) extends ConsoleReporter(settings, Console.in, writer) { - shortname = true - // override def error(pos: Position, msg: String): Unit -} - -class TestSettings(cp: String, error: String => Unit) extends Settings(error) { - def this(cp: String) = this(cp, _ => ()) - - nowarnings.value = false - encoding.value = "UTF-8" - classpath.value = cp -} - -class PartestGlobal(settings: Settings, reporter: Reporter) extends Global(settings, reporter) { - // override def abort(msg: String): Nothing - // override def globalError(msg: String): Unit - // override def supplementErrorMessage(msg: String): String -} -class DirectCompiler(val fileManager: FileManager) { - def newGlobal(settings: Settings, reporter: Reporter): PartestGlobal = - new PartestGlobal(settings, reporter) - - def newGlobal(settings: Settings, logWriter: FileWriter): Global = - newGlobal(settings, new ExtConsoleReporter(settings, new PrintWriter(logWriter))) - - def newSettings(): TestSettings = new TestSettings(fileManager.LATEST_LIB) - def newSettings(outdir: String): TestSettings = { - val cp = ClassPath.join(fileManager.LATEST_LIB, outdir) - val s = new TestSettings(cp) - s.outdir.value = outdir - s - } - - def compile(runner: Runner, opts0: List[String], sources: List[File]): TestState = { - import runner.{ sources => _, _ } - - val testSettings = new TestSettings(ClassPath.join(fileManager.LATEST_LIB, outDir.getPath)) - val logWriter = new FileWriter(logFile) - val srcDir = if (testFile.isDirectory) testFile else Path(testFile).parent.jfile - val opts = fileManager.updatePluginPath(opts0, AbstractFile getDirectory outDir, AbstractFile getDirectory srcDir) - val command = new CompilerCommand(opts, testSettings) - val global = newGlobal(testSettings, logWriter) - val reporter = global.reporter.asInstanceOf[ExtConsoleReporter] - def errorCount = reporter.ERROR.count - - def defineSettings(s: Settings) = { - s.outputDirs setSingleOutput outDir.getPath - // adding codelib.jar to the classpath - // codelib provides the possibility to override standard reify - // this shields the massive amount of reification tests from changes in the API - prependToClasspaths(s, codelib) - s.classpath append fileManager.CLASSPATH // adding this why? - - // add the instrumented library version to classpath - if (kind == "specialized") - prependToClasspaths(s, speclib) - - // check that option processing succeeded - opts0.isEmpty || command.ok - } - - if (!defineSettings(testSettings)) - if (opts0.isEmpty) - reporter.error(null, s"bad settings: $testSettings") - else - reporter.error(null, opts0.mkString("bad options: ", space, "")) - - def ids = sources.map(_.testIdent) mkString space - vlog(s"% scalac $ids") - - def execCompile() = - if (command.shouldStopWithInfo) { - logWriter append (command getInfoMessage global) - runner genFail "compilation stopped with info" - } else { - new global.Run compile sources.map(_.getPath) - if (!reporter.hasErrors) runner.genPass() - else { - reporter.printSummary() - reporter.writer.close() - runner.genFail(s"compilation failed with $errorCount errors") - } - } - - try { execCompile() } - catch { case t: Throwable => reporter.error(null, t.getMessage) ; runner.genCrash(t) } - finally { logWriter.close() } - } -} diff --git a/src/partest/scala/tools/partest/nest/FileManager.scala b/src/partest/scala/tools/partest/nest/FileManager.scala deleted file mode 100644 index 208418047c..0000000000 --- a/src/partest/scala/tools/partest/nest/FileManager.scala +++ /dev/null @@ -1,165 +0,0 @@ -/* NEST (New Scala Test) - * Copyright 2007-2013 LAMP/EPFL - * @author Philipp Haller - */ - -// $Id$ - -package scala.tools.partest -package nest - -import java.io.{File, FilenameFilter, IOException, StringWriter, - FileInputStream, FileOutputStream, BufferedReader, - FileReader, PrintWriter, FileWriter} -import java.net.URI -import scala.reflect.io.AbstractFile -import scala.collection.mutable - -trait FileUtil { - /** - * Compares two files using difflib to produce a unified diff. - * - * @param f1 the first file to be compared - * @param f2 the second file to be compared - * @return the unified diff of the compared files or the empty string if they're equal - */ - def compareFiles(f1: File, f2: File): String = { - compareContents(io.Source.fromFile(f1).getLines.toSeq, io.Source.fromFile(f2).getLines.toSeq, f1.getName, f2.getName) - } - - /** - * Compares two lists of lines using difflib to produce a unified diff. - * - * @param origLines the first seq of lines to be compared - * @param newLines the second seq of lines to be compared - * @param origName file name to be used in unified diff for `origLines` - * @param newName file name to be used in unified diff for `newLines` - * @return the unified diff of the `origLines` and `newLines` or the empty string if they're equal - */ - def compareContents(origLines: Seq[String], newLines: Seq[String], origName: String = "a", newName: String = "b"): String = { - import collection.JavaConverters._ - - val diff = difflib.DiffUtils.diff(origLines.asJava, newLines.asJava) - if (diff.getDeltas.isEmpty) "" - else difflib.DiffUtils.generateUnifiedDiff(origName, newName, origLines.asJava, diff, 1).asScala.mkString("\n") - } -} -object FileUtil extends FileUtil { } - -trait FileManager extends FileUtil { - - def testRootDir: Directory - def testRootPath: String - - var JAVACMD: String - var JAVAC_CMD: String - - var CLASSPATH: String - var LATEST_LIB: String - var LATEST_REFLECT: String - var LATEST_COMP: String - var LATEST_PARTEST: String - var LATEST_ACTORS: String - - protected def relativeToLibrary(what: String): String = { - def jarname = if (what startsWith "scala") s"$what.jar" else s"scala-$what.jar" - if (LATEST_LIB endsWith ".jar") - (SFile(LATEST_LIB).parent / jarname).toAbsolute.path - else - (SFile(LATEST_LIB).parent.parent / "classes" / what).toAbsolute.path - } - def latestParserCBLib = relativeToLibrary("parser-combinators") - def latestXmlLib = relativeToLibrary("xml") - def latestScaladoc = relativeToLibrary("scaladoc") - def latestInteractive = relativeToLibrary("interactive") - def latestScalapFile = relativeToLibrary("scalap") - def latestPaths = List( - LATEST_LIB, LATEST_REFLECT, LATEST_COMP, LATEST_PARTEST, LATEST_ACTORS, - latestParserCBLib, latestXmlLib, latestScalapFile, latestScaladoc, latestInteractive - ) - def latestFiles = latestPaths map (p => new java.io.File(p)) - def latestUrls = latestFiles map (_.toURI.toURL) - - var showDiff = false - var updateCheck = false - var showLog = false - var failed = false - - var SCALAC_OPTS = PartestDefaults.scalacOpts.split(' ').toSeq - var JAVA_OPTS = PartestDefaults.javaOpts - - /** Only when --debug is given. */ - lazy val testTimings = new mutable.HashMap[String, Long] - def recordTestTiming(name: String, milliseconds: Long) = - synchronized { testTimings(name) = milliseconds } - - def getLogFile(dir: File, fileBase: String, kind: String): File = - new File(dir, fileBase + "-" + kind + ".log") - - def getLogFile(file: File, kind: String): File = { - val dir = file.getParentFile - val fileBase = basename(file.getName) - - getLogFile(dir, fileBase, kind) - } - - def logFileExists(file: File, kind: String) = - getLogFile(file, kind).canRead - - def overwriteFileWith(dest: File, file: File) = - dest.isFile && copyFile(file, dest) - - def copyFile(from: File, dest: File): Boolean = { - if (from.isDirectory) { - assert(dest.isDirectory, "cannot copy directory to file") - val subDir:Directory = Path(dest) / Directory(from.getName) - subDir.createDirectory() - from.listFiles.toList forall (copyFile(_, subDir)) - } - else { - val to = if (dest.isDirectory) new File(dest, from.getName) else dest - - try { - SFile(to) writeAll SFile(from).slurp() - true - } - catch { case _: IOException => false } - } - } - - def mapFile(file: File, replace: String => String) { - val f = SFile(file) - - f.printlnAll(f.lines.toList map replace: _*) - } - - /** Massage args to merge plugins and fix paths. - * Plugin path can be relative to test root, or cwd is out. - * While we're at it, mix in the baseline options, too. - * That's how ant passes in the plugins dir. - */ - def updatePluginPath(args: List[String], out: AbstractFile, srcdir: AbstractFile): List[String] = { - val dir = testRootDir - // The given path, or the output dir if ".", or a temp dir if output is virtual (since plugin loading doesn't like virtual) - def pathOrCwd(p: String) = - if (p == ".") { - val plugxml = "scalac-plugin.xml" - val pout = if (out.isVirtual) Directory.makeTemp() else Path(out.path) - val srcpath = Path(srcdir.path) - val pd = (srcpath / plugxml).toFile - if (pd.exists) pd copyTo (pout / plugxml) - pout.toAbsolute - } else Path(p) - def absolutize(path: String) = pathOrCwd(path) match { - case x if x.isAbsolute => x.path - case x => (dir / x).toAbsolute.path - } - - val xprefix = "-Xplugin:" - val (xplugs, others) = args partition (_ startsWith xprefix) - val Xplugin = if (xplugs.isEmpty) Nil else List(xprefix + - (xplugs map (_ stripPrefix xprefix) flatMap (_ split pathSeparator) map absolutize mkString pathSeparator) - ) - SCALAC_OPTS.toList ::: others ::: Xplugin - } -} diff --git a/src/partest/scala/tools/partest/nest/NestRunner.scala b/src/partest/scala/tools/partest/nest/NestRunner.scala deleted file mode 100644 index e398d2ead9..0000000000 --- a/src/partest/scala/tools/partest/nest/NestRunner.scala +++ /dev/null @@ -1,15 +0,0 @@ -/* NEST (New Scala Test) - * Copyright 2007-2013 LAMP/EPFL - * @author Philipp Haller - */ - -// $Id$ - -package scala.tools.partest -package nest - -object NestRunner { - def main(args: Array[String]) { - new ReflectiveRunner main (args mkString " ") - } -} diff --git a/src/partest/scala/tools/partest/nest/NestUI.scala b/src/partest/scala/tools/partest/nest/NestUI.scala deleted file mode 100644 index d063c17ac0..0000000000 --- a/src/partest/scala/tools/partest/nest/NestUI.scala +++ /dev/null @@ -1,181 +0,0 @@ -/* NEST (New Scala Test) - * Copyright 2007-2013 LAMP/EPFL - * @author Philipp Haller - */ - -package scala.tools.partest -package nest - -import java.io.PrintWriter - -class Colors(enabled: => Boolean) { - import Console._ - - val bold = colored(BOLD) - val yellow = colored(YELLOW) - val green = colored(GREEN) - val blue = colored(BLUE) - val red = colored(RED) - val red_b = colored(RED_B) - val green_b = colored(GREEN_B) - val cyan = colored(CYAN) - val magenta = colored(MAGENTA) - - private def colored(code: String): String => String = - s => if (enabled) code + s + RESET else s -} - -object NestUI { - private val testNum = new java.util.concurrent.atomic.AtomicInteger(1) - @volatile private var testNumberFmt = "%3d" - private def testNumber = testNumberFmt format testNum.getAndIncrement() - def resetTestNumber(max: Int = -1) { - testNum set 1 - val width = if (max > 0) max.toString.length else 3 - testNumberFmt = s"%${width}d" - } - - var colorEnabled = sys.props contains "partest.colors" - val color = new Colors(colorEnabled) - import color._ - - val NONE = 0 - val SOME = 1 - val MANY = 2 - - private var _outline = "" - private var _success = "" - private var _failure = "" - private var _warning = "" - private var _default = "" - - private var dotCount = 0 - private val DotWidth = 72 - - def leftFlush() { - if (dotCount != 0) { - normal("\n") - dotCount = 0 - } - } - - def statusLine(state: TestState) = { - import state._ - import TestState._ - val colorizer = state match { - case _: Skip => yellow - case _: Updated => cyan - case s if s.isOk => green - case _ => red - } - val word = bold(colorizer(state.shortStatus)) - f"$word $testNumber - $testIdent%-40s$reasonString" - } - - def reportTest(state: TestState) = { - if (isTerse && state.isOk) { - if (dotCount >= DotWidth) { - outline("\n.") - dotCount = 1 - } - else { - outline(".") - dotCount += 1 - } - } - else { - echo(statusLine(state)) - if (!state.isOk && isDiffy) { - val differ = bold(red("% ")) + "diff " - state.transcript find (_ startsWith differ) foreach (echo(_)) - } - } - } - - def echo(message: String): Unit = synchronized { - leftFlush() - print(message + "\n") - } - def chatty(msg: String) = if (isVerbose) echo(msg) - - def echoSkipped(msg: String) = echo(yellow(msg)) - def echoPassed(msg: String) = echo(bold(green(msg))) - def echoFailed(msg: String) = echo(bold(red(msg))) - def echoMixed(msg: String) = echo(bold(yellow(msg))) - def echoWarning(msg: String) = echo(bold(red(msg))) - - def initialize(number: Int) = number match { - case MANY => - _outline = Console.BOLD + Console.BLACK - _success = Console.BOLD + Console.GREEN - _failure = Console.BOLD + Console.RED - _warning = Console.BOLD + Console.YELLOW - _default = Console.RESET - case SOME => - _outline = Console.BOLD + Console.BLACK - _success = Console.RESET - _failure = Console.BOLD + Console.BLACK - _warning = Console.BOLD + Console.BLACK - _default = Console.RESET - case _ => - } - - def outline(msg: String) = print(_outline + msg + _default) - def outline(msg: String, wr: PrintWriter) = synchronized { - wr.print(_outline + msg + _default) - } - - def success(msg: String) = print(_success + msg + _default) - def success(msg: String, wr: PrintWriter) = synchronized { - wr.print(_success + msg + _default) - } - - def failure(msg: String) = print(_failure + msg + _default) - def failure(msg: String, wr: PrintWriter) = synchronized { - wr.print(_failure + msg + _default) - } - - def warning(msg: String) = print(_warning + msg + _default) - - def normal(msg: String) = print(_default + msg) - def normal(msg: String, wr: PrintWriter) = synchronized { - wr.print(_default + msg) - } - - def usage() { - println(ConsoleRunnerSpec.programInfo.usage) - println(ConsoleRunnerSpec.helpMsg) - sys.exit(1) - } - - var _verbose = false - var _debug = false - var _terse = false - var _diff = false - - def isVerbose = _verbose - def isDebug = _debug - def isTerse = _terse - def isDiffy = _diff - - def setVerbose() { - _verbose = true - } - def setDebug() { - _debug = true - } - def setTerse() { - _terse = true - } - def setDiffOnFail() { - _diff = true - } - def verbose(msg: String) { - if (isVerbose) - System.err.println(msg) - } - def debug(msg: String) { - if (isDebug) - System.err.println(msg) - } -} diff --git a/src/partest/scala/tools/partest/nest/PathSettings.scala b/src/partest/scala/tools/partest/nest/PathSettings.scala deleted file mode 100644 index 030c515947..0000000000 --- a/src/partest/scala/tools/partest/nest/PathSettings.scala +++ /dev/null @@ -1,88 +0,0 @@ -/* NEST (New Scala Test) - * Copyright 2007-2013 LAMP/EPFL - */ - -package scala.tools.partest -package nest - -import scala.tools.nsc.util.ClassPath -import scala.tools.nsc.io.{ Path, File, Directory } -import Path._ - -object PathSettings { - import PartestDefaults.{ testRootDir, srcDirName } - - private def cwd = Directory.Current getOrElse sys.error("user.dir property not set") - private def isPartestDir(d: Directory) = (d.name == "test") && (d / srcDirName isDirectory) - private def findJar(d: Directory, name: String): Option[File] = findJar(d.files, name) - private def findJar(files: Iterator[File], name: String): Option[File] = - files filter (_ hasExtension "jar") find { _.name startsWith name } - private def findJarOrFail(name: String, ds: Directory*): File = findJar(ds flatMap (_.files) iterator, name) getOrElse - sys.error(s"'${name}.jar' not found in '${ds map (_.path) mkString ", "}'.") - - // Directory /test - lazy val testRoot: Directory = testRootDir getOrElse { - val candidates: List[Directory] = (cwd :: cwd.parents) flatMap (d => List(d, Directory(d / "test"))) - - candidates find isPartestDir getOrElse sys.error("Directory 'test' not found.") - } - - // Directory /test/files or .../scaladoc - def srcDir = Directory(testRoot / srcDirName toCanonical) - - // Directory /test/files/lib - lazy val srcLibDir = Directory(srcDir / "lib") - - // Directory /test/files/speclib - lazy val srcSpecLibDir = Directory(srcDir / "speclib") - - lazy val srcSpecLib: File = findJar(srcSpecLibDir, "instrumented") getOrElse { - sys.error("No instrumented.jar found in %s".format(srcSpecLibDir)) - } - - // Directory /test/files/codelib - lazy val srcCodeLibDir = Directory(srcDir / "codelib") - - lazy val srcCodeLib: File = ( - findJar(srcCodeLibDir, "code") - orElse findJar(Directory(testRoot / "files" / "codelib"), "code") // work with --srcpath pending - getOrElse sys.error("No code.jar found in %s".format(srcCodeLibDir)) - ) - - lazy val instrumentationAgentLib: File = { - findJar(buildPackLibDir.files, "scala-partest-javaagent") getOrElse { - sys.error("No partest-javaagent jar found in '%s' or '%s'".format(buildPackLibDir, srcLibDir)) - } - } - - // Directory /build - lazy val buildDir: Directory = { - val bases = testRoot :: testRoot.parents - // In the classic "ant" build, the relevant subdirectory is called build, - // but in the postmodern "sbt" build, it is called target. Look for both. - val dirs = Path.onlyDirs(bases flatMap (x => List(x / "build", x / "target"))) - - dirs.headOption getOrElse sys.error("Neither 'build' nor 'target' dir found under test root " + testRoot + ".") - } - - // Directory /build/pack/lib - lazy val buildPackLibDir = Directory(buildDir / "pack" / "lib") - - lazy val scalaCheck: File = - findJar(buildPackLibDir.files ++ srcLibDir.files, "scalacheck") getOrElse { - sys.error("No scalacheck jar found in '%s' or '%s'".format(buildPackLibDir, srcLibDir)) - } - - lazy val testInterface: File = findJarOrFail("test-interface", buildPackLibDir, srcLibDir) - - lazy val diffUtils: File = - findJar(buildPackLibDir.files, "diffutils") getOrElse sys.error(s"No diffutils.jar found in '$buildPackLibDir'.") - - /** The platform-specific support jar, `tools.jar`. - */ - lazy val platformTools: Option[File] = PathResolver.SupplementalLocations.platformTools -} - -class PathSettings() { - // def classpathAsURLs: List[URL] -} diff --git a/src/partest/scala/tools/partest/nest/ReflectiveRunner.scala b/src/partest/scala/tools/partest/nest/ReflectiveRunner.scala deleted file mode 100644 index 3c77a03f1e..0000000000 --- a/src/partest/scala/tools/partest/nest/ReflectiveRunner.scala +++ /dev/null @@ -1,99 +0,0 @@ -/* NEST (New Scala Test) - * Copyright 2007-2013 LAMP/EPFL - * @author Philipp Haller - */ - -package scala.tools.partest -package nest - -import scala.tools.nsc.Properties.{ setProp, propOrEmpty } -import scala.tools.nsc.util.ClassPath -import scala.tools.nsc.io -import io.Path -import java.net.URLClassLoader - -/* This class is used to load an instance of DirectRunner using - * a custom class loader. - * The purpose is to "auto-detect" a good classpath for the - * rest of the classes (Worker, CompileManager etc.), so that - * the main NestRunner can be started merely by putting its - * class on the classpath (ideally). - */ -class ReflectiveRunner { - // TODO: we might also use fileManager.CLASSPATH - // to use the same classes as used by `scala` that - // was used to start the runner. - val sepRunnerClassName = "scala.tools.partest.nest.ConsoleRunner" - - private def searchPath(option: String, as: List[String]): Option[String] = as match { - case `option` :: r :: _ => Some(r) - case _ :: rest => searchPath(option, rest) - case Nil => None - } - - def main(args: String) { - val argList = (args.split("\\s")).toList - - if (isPartestDebug) - showAllJVMInfo - - // find out which build to test - val buildPath = searchPath("--buildpath", argList) - val classPath = searchPath("--classpath", argList) - val fileManager = - if (!buildPath.isEmpty) - new ConsoleFileManager(buildPath.get) - else if (!classPath.isEmpty) - new ConsoleFileManager(classPath.get, true) - else if (argList contains "--pack") - new ConsoleFileManager("build/pack") - else // auto detection - new ConsoleFileManager - - // this is a workaround for https://issues.scala-lang.org/browse/SI-5433 - // when that bug is fixed, the addition of PathSettings.srcCodeLib can be removed - // we hack into the classloader that will become parent classloader for scalac - // this way we ensure that reflective macro lookup will pick correct Code.lift - // it's also used to inject diffutils into the classpath when running partest from the test/partest script - val srcCodeLibAndDiff = List(PathSettings.srcCodeLib, PathSettings.diffUtils, PathSettings.testInterface) - val sepUrls = srcCodeLibAndDiff.map(_.toURI.toURL) ::: fileManager.latestUrls - // this seems to be the core classloader that determines which classes can be found when running partest from the test/partest script - val sepLoader = new URLClassLoader(sepUrls.toArray, null) - - if (isPartestDebug) - println("Loading classes from:\n " + fileManager.latestUrls.mkString("\n ")) - - // @partest maintainer: it seems to me that commented lines are incorrect - // if classPath is not empty, then it has been provided by the --classpath option - // which points to the root of Scala home (see ConsoleFileManager's testClasses and the true flag in the ctor for more information) - // this doesn't mean that we had custom Java classpath set, so we don't have to override latestXXXFiles from the file manager - // - //val paths = classPath match { - // case Some(cp) => Nil - // case _ => files.toList map (_.path) - //} - - setProp("java.class.path", ClassPath.join(fileManager.latestPaths: _*)) - - // don't let partest find pluginsdir; in ant build, standard plugin has dedicated test suite - //setProp("scala.home", latestLibFile.parent.parent.path) - setProp("scala.home", "") - - if (isPartestDebug) - for (prop <- List("java.class.path", "sun.boot.class.path", "java.ext.dirs")) - println(prop + ": " + propOrEmpty(prop)) - - try { - val sepRunnerClass = sepLoader loadClass sepRunnerClassName - val sepMainMethod = sepRunnerClass.getMethod("main", classOf[Array[String]]) - val cargs: Array[AnyRef] = Array(Array(args)) - sepMainMethod.invoke(null, cargs: _*) - } - catch { - case cnfe: ClassNotFoundException => - cnfe.printStackTrace() - NestUI.failure(sepRunnerClassName +" could not be loaded from:\n") - sepUrls foreach (x => NestUI.failure(x + "\n")) - } - } -} diff --git a/src/partest/scala/tools/partest/nest/Runner.scala b/src/partest/scala/tools/partest/nest/Runner.scala deleted file mode 100644 index 470a2188de..0000000000 --- a/src/partest/scala/tools/partest/nest/Runner.scala +++ /dev/null @@ -1,883 +0,0 @@ -/* NEST (New Scala Test) - * Copyright 2007-2013 LAMP/EPFL - * @author Paul Phillips - */ -package scala.tools.partest -package nest - -import java.io.{ Console => _, _ } -import java.net.URL -import java.nio.charset.{ Charset, CharsetDecoder, CharsetEncoder, CharacterCodingException, CodingErrorAction => Action } -import java.util.concurrent.Executors -import java.util.concurrent.TimeUnit.NANOSECONDS -import scala.collection.mutable.ListBuffer -import scala.concurrent.duration.Duration -import scala.io.Codec -import scala.reflect.internal.FatalError -import scala.sys.process.{ Process, ProcessLogger } -import scala.tools.nsc.Properties.{ envOrElse, isWin, jdkHome, javaHome, propOrElse, propOrEmpty, setProp } -import scala.tools.nsc.{ Settings, CompilerCommand, Global } -import scala.tools.nsc.reporters.ConsoleReporter -import scala.tools.nsc.util.{ Exceptional, ScalaClassLoader, stackTraceString } -import scala.tools.scalap.Main.decompileScala -import scala.tools.scalap.scalasig.ByteCode -import scala.util.{ Try, Success, Failure } -import ClassPath.{ join, split } -import PartestDefaults.{ javaCmd, javacCmd } -import TestState.{ Pass, Fail, Crash, Uninitialized, Updated } - -trait PartestRunSettings { - def gitPath: Path - def reportPath: Path - def logPath: Path - - def testPaths: List[Path] - - def gitDiffOptions: List[String] - def extraScalacOptions: List[String] - def extraJavaOptions: List[String] -} - -class TestTranscript { - import NestUI.color._ - private val buf = ListBuffer[String]() - private def pass(s: String) = bold(green("% ")) + s - private def fail(s: String) = bold(red("% ")) + s - - def add(action: String): this.type = { buf += action ; this } - def append(text: String) { val s = buf.last ; buf.trimEnd(1) ; buf += (s + text) } - - // Colorize prompts according to pass/fail - def fail: List[String] = buf.toList match { - case Nil => Nil - case xs => (xs.init map pass) :+ fail(xs.last) - } -} - -/** Run a single test. Rubber meets road. */ -class Runner(val testFile: File, fileManager: FileManager, val testRunParams: TestRunParams) { - import fileManager._ - - // Override to true to have the outcome of this test displayed - // whether it passes or not; in general only failures are reported, - // except for a . per passing test to show progress. - def isEnumeratedTest = false - - private var _lastState: TestState = null - private var _transcript = new TestTranscript - - def lastState = if (_lastState == null) Uninitialized(testFile) else _lastState - def setLastState(s: TestState) = _lastState = s - def transcript: List[String] = _transcript.fail ++ logFile.fileLines - def pushTranscript(msg: String) = _transcript add msg - - val parentFile = testFile.getParentFile - val kind = parentFile.getName - val fileBase = basename(testFile.getName) - val logFile = new File(parentFile, s"$fileBase-$kind.log") - val outFile = logFile changeExtension "obj" - val checkFile = testFile changeExtension "check" - val flagsFile = testFile changeExtension "flags" - val testIdent = testFile.testIdent // e.g. pos/t1234 - - lazy val outDir = { outFile.mkdirs() ; outFile } - - type RanOneTest = (Boolean, LogContext) - - def showCrashInfo(t: Throwable) { - System.err.println(s"Crashed running test $testIdent: $t") - if (!isPartestTerse) - System.err.println(stackTraceString(t)) - } - protected def crashHandler: PartialFunction[Throwable, TestState] = { - case t: InterruptedException => - genTimeout() - case t: Throwable => - showCrashInfo(t) - logFile.appendAll(stackTraceString(t)) - genCrash(t) - } - - def genPass() = Pass(testFile) - def genFail(reason: String) = Fail(testFile, reason, _transcript.fail) - def genTimeout() = Fail(testFile, "timed out", _transcript.fail) - def genCrash(caught: Throwable) = Crash(testFile, caught, _transcript.fail) - def genUpdated() = Updated(testFile) - - def speclib = PathSettings.srcSpecLib.toString // specialization lib - def codelib = PathSettings.srcCodeLib.toString // reify lib - - // Prepend to a classpath, but without incurring duplicate entries - def prependTo(classpath: String, path: String): String = { - val segments = ClassPath split classpath - - if (segments startsWith path) classpath - else ClassPath.join(path :: segments distinct: _*) - } - - def prependToJavaClasspath(path: String) { - val jcp = sys.props.getOrElse("java.class.path", "") - prependTo(jcp, path) match { - case `jcp` => - case cp => sys.props("java.class.path") = cp - } - } - def prependToClasspaths(s: Settings, path: String) { - prependToJavaClasspath(path) - val scp = s.classpath.value - prependTo(scp, path) match { - case `scp` => - case cp => s.classpath.value = cp - } - } - - private def workerError(msg: String): Unit = System.err.println("Error: " + msg) - - def javac(files: List[File]): TestState = { - // compile using command-line javac compiler - val args = Seq( - javacCmd, - "-d", - outDir.getAbsolutePath, - "-classpath", - join(outDir.toString, CLASSPATH) - ) ++ files.map(_.getAbsolutePath) - - pushTranscript(args mkString " ") - val captured = StreamCapture(runCommand(args, logFile)) - if (captured.result) genPass() else { - logFile appendAll captured.stderr - genFail("java compilation failed") - } - } - - def testPrompt = kind match { - case "res" => "nsc> " - case _ => "% " - } - - /** Evaluate an action body and update the test state. - * @param failFn optionally map a result to a test state. - */ - def nextTestAction[T](body: => T)(failFn: PartialFunction[T, TestState]): T = { - val result = body - setLastState( if (failFn isDefinedAt result) failFn(result) else genPass() ) - result - } - def nextTestActionExpectTrue(reason: String, body: => Boolean): Boolean = ( - nextTestAction(body) { case false => genFail(reason) } - ) - def nextTestActionFailing(reason: String): Boolean = nextTestActionExpectTrue(reason, false) - - private def assembleTestCommand(outDir: File, logFile: File): List[String] = { - // check whether there is a ".javaopts" file - val argsFile = testFile changeExtension "javaopts" - val argString = file2String(argsFile) - if (argString != "") - NestUI.verbose("Found javaopts file '%s', using options: '%s'".format(argsFile, argString)) - - val testFullPath = testFile.getAbsolutePath - - // Note! As this currently functions, JAVA_OPTS must precede argString - // because when an option is repeated to java only the last one wins. - // That means until now all the .javaopts files were being ignored because - // they all attempt to change options which are also defined in - // partest.java_opts, leading to debug output like: - // - // debug: Found javaopts file 'files/shootout/message.scala-2.javaopts', using options: '-Xss32k' - // debug: java -Xss32k -Xss2m -Xms256M -Xmx1024M -classpath [...] - val extras = if (isPartestDebug) List("-Dpartest.debug=true") else Nil - val propertyOptions = List( - "-Dfile.encoding=UTF-8", - "-Djava.library.path="+logFile.getParentFile.getAbsolutePath, - "-Dpartest.output="+outDir.getAbsolutePath, - "-Dpartest.lib="+LATEST_LIB, - "-Dpartest.reflect="+LATEST_REFLECT, - "-Dpartest.cwd="+outDir.getParent, - "-Dpartest.test-path="+testFullPath, - "-Dpartest.testname="+fileBase, - "-Djavacmd="+javaCmd, - "-Djavaccmd="+javacCmd, - "-Duser.language=en", - "-Duser.country=US" - ) ++ extras - - val classpath = if (extraClasspath != "") join(extraClasspath, CLASSPATH) else CLASSPATH - - javaCmd +: ( - (JAVA_OPTS.split(' ') ++ extraJavaOptions.split(' ') ++ argString.split(' ')).map(_.trim).filter(_ != "").toList ++ Seq( - "-classpath", - join(outDir.toString, classpath) - ) ++ propertyOptions ++ Seq( - "scala.tools.nsc.MainGenericRunner", - "-usejavacp", - "Test", - "jvm" - ) - ) - } - - /** Runs command redirecting standard out and - * error out to output file. - */ - private def runCommand(args: Seq[String], outFile: File): Boolean = { - //(Process(args) #> outFile !) == 0 or (Process(args) ! pl) == 0 - val pl = ProcessLogger(outFile) - val nonzero = 17 // rounding down from 17.3 - def run: Int = { - val p = Process(args) run pl - try p.exitValue - catch { - case e: InterruptedException => - NestUI verbose s"Interrupted waiting for command to finish (${args mkString " "})" - p.destroy - nonzero - case t: Throwable => - NestUI verbose s"Exception waiting for command to finish: $t (${args mkString " "})" - p.destroy - throw t - } - finally pl.close() - } - (pl buffer run) == 0 - } - - private def execTest(outDir: File, logFile: File): Boolean = { - val cmd = assembleTestCommand(outDir, logFile) - - pushTranscript((cmd mkString s" \\$EOL ") + " > " + logFile.getName) - nextTestAction(runCommand(cmd, logFile)) { - case false => - _transcript append EOL + logFile.fileContents - genFail("non-zero exit code") - } - } - - override def toString = s"""Test($testIdent, lastState = $lastState)""" - - // result is unused - def newTestWriters() = { - val swr = new StringWriter - val wr = new PrintWriter(swr, true) - // diff = "" - - ((swr, wr)) - } - - def fail(what: Any) = { - NestUI.verbose("scalac: compilation of "+what+" failed\n") - false - } - - /** Filter the check file for conditional blocks. - * The check file can contain lines of the form: - * `#partest java7` - * where the line contains a conventional flag name. - * If the flag tests true, succeeding lines are retained - * (removed on false) until the next #partest flag. - * A missing flag evaluates the same as true. - */ - def filteredCheck: Seq[String] = { - import scala.util.Properties.{javaVersion, isAvian} - // use lines in block so labeled? Default to sorry, Charlie. - def retainOn(expr: String) = { - val f = expr.trim - def flagWasSet(f: String) = fileManager.SCALAC_OPTS contains f - val (invert, token) = - if (f startsWith "!") (true, f drop 1) else (false, f) - val cond = token.trim match { - case "java7" => javaVersion startsWith "1.7" - case "java6" => javaVersion startsWith "1.6" - case "avian" => isAvian - case "true" => true - case "-optimise" | "-optimize" - => flagWasSet("-optimise") || flagWasSet("-optimize") - case flag if flag startsWith "-" - => flagWasSet(flag) - case rest => rest.isEmpty - } - if (invert) !cond else cond - } - val prefix = "#partest" - val b = new ListBuffer[String]() - var on = true - for (line <- file2String(checkFile).lines) { - if (line startsWith prefix) { - on = retainOn(line stripPrefix prefix) - } else if (on) { - b += line - } - } - b.toList - } - - def currentDiff = { - val logged = augmentString(file2String(logFile)).lines.toList - val (other, othername) = - if (checkFile.canRead) (filteredCheck, checkFile.getName) else (Nil, "empty") - compareContents(logged, other, logFile.getName, othername) - } - - val gitRunner = List("/usr/local/bin/git", "/usr/bin/git") map (f => new java.io.File(f)) find (_.canRead) - val gitDiffOptions = "--ignore-space-at-eol --no-index " + propOrEmpty("partest.git_diff_options") - // --color=always --word-diff - - def gitDiff(f1: File, f2: File): Option[String] = { - try gitRunner map { git => - val cmd = s"$git diff $gitDiffOptions $f1 $f2" - val diff = Process(cmd).lines_!.drop(4).map(_ + "\n").mkString - - "\n" + diff - } - catch { case t: Exception => None } - } - - /** Normalize the log output by applying test-specific filters - * and fixing filesystem-specific paths. - * - * Line filters are picked up from `filter: pattern` at the top of sources. - * The filtered line is detected with a simple "contains" test, - * and yes, "filter" means "filter out" in this context. - * - * File paths are detected using the absolute path of the test root. - * A string that looks like a file path is normalized by replacing - * the leading segments (the root) with "$ROOT" and by replacing - * any Windows backslashes with the one true file separator char. - */ - def normalizeLog() { - // Apply judiciously; there are line comments in the "stub implementations" error output. - val slashes = """[/\\]+""".r - def squashSlashes(s: String) = slashes replaceAllIn (s, "/") - - // this string identifies a path and is also snipped from log output. - // to preserve more of the path, could use fileManager.testRootPath - val elided = parentFile.getAbsolutePath - - // something to mark the elision in the log file (disabled) - val ellipsis = "" //".../" // using * looks like a comment - - // no spaces in test file paths below root, because otherwise how to detect end of path string? - val pathFinder = raw"""(?i)\Q${elided}${File.separator}\E([\${File.separator}\S]*)""".r - def canonicalize(s: String): String = ( - pathFinder replaceAllIn (s, m => ellipsis + squashSlashes(m group 1)) - ) - - def masters = { - val files = List(new File(parentFile, "filters"), new File(PathSettings.srcDir.path, "filters")) - files filter (_.exists) flatMap (_.fileLines) map (_.trim) filter (s => !(s startsWith "#")) - } - val filters = toolArgs("filter", split = false) ++ masters - val elisions = ListBuffer[String]() - //def lineFilter(s: String): Boolean = !(filters exists (s contains _)) - def lineFilter(s: String): Boolean = ( - filters map (_.r) forall { r => - val res = (r findFirstIn s).isEmpty - if (!res) elisions += s - res - } - ) - - logFile.mapInPlace(canonicalize)(lineFilter) - if (isPartestVerbose && elisions.nonEmpty) { - import NestUI.color._ - val emdash = bold(yellow("--")) - pushTranscript(s"filtering ${logFile.getName}$EOL${elisions mkString (emdash, EOL + emdash, EOL)}") - } - } - - def diffIsOk: Boolean = { - // always normalize the log first - normalizeLog() - val diff = currentDiff - // if diff is not empty, is update needed? - val updating: Option[Boolean] = ( - if (diff == "") None - else Some(fileManager.updateCheck) - ) - pushTranscript(s"diff $logFile $checkFile") - nextTestAction(updating) { - case Some(true) => - NestUI.verbose("Updating checkfile " + checkFile) - checkFile writeAll file2String(logFile) - genUpdated() - case Some(false) => - // Get a word-highlighted diff from git if we can find it - val bestDiff = if (updating.isEmpty) "" else { - if (checkFile.canRead) - gitDiff(logFile, checkFile) getOrElse { - s"diff $logFile $checkFile\n$diff" - } - else diff - } - _transcript append bestDiff - genFail("output differs") - // TestState.fail("output differs", "output differs", - // genFail("output differs") - // TestState.Fail("output differs", bestDiff) - case None => genPass() // redundant default case - } getOrElse true - } - - /** 1. Creates log file and output directory. - * 2. Runs script function, providing log file and output directory as arguments. - * 2b. or, just run the script without context and return a new context - */ - def runInContext(body: => Boolean): (Boolean, LogContext) = { - val (swr, wr) = newTestWriters() - val succeeded = body - (succeeded, LogContext(logFile, swr, wr)) - } - - /** Grouped files in group order, and lex order within each group. */ - def groupedFiles(sources: List[File]): List[List[File]] = ( - if (sources.tail.nonEmpty) { - val grouped = sources groupBy (_.group) - grouped.keys.toList.sorted map (k => grouped(k) sortBy (_.getName)) - } - else List(sources) - ) - - /** Source files for the given test file. */ - def sources(file: File): List[File] = ( - if (file.isDirectory) - file.listFiles.toList filter (_.isJavaOrScala) - else - List(file) - ) - - def newCompiler = new DirectCompiler(fileManager) - - def attemptCompile(sources: List[File]): TestState = { - val state = newCompiler.compile(this, flagsForCompilation(sources), sources) - if (!state.isOk) - _transcript append ("\n" + file2String(logFile)) - - state - } - - // snort or scarf all the contributing flags files - def flagsForCompilation(sources: List[File]): List[String] = { - def argsplitter(s: String) = words(s) filter (_.nonEmpty) - val perTest = argsplitter(flagsFile.fileContents) - val perGroup = if (testFile.isDirectory) { - sources flatMap { f => SFile(Path(f) changeExtension "flags").safeSlurp map argsplitter getOrElse Nil } - } else Nil - perTest ++ perGroup - } - - def toolArgs(tool: String, split: Boolean = true): List[String] = { - def argsplitter(s: String) = if (split) words(s) filter (_.nonEmpty) else List(s) - def argsFor(f: File): List[String] = { - import scala.util.matching.Regex - val p = new Regex(s"(?:.*\\s)?${tool}:(?:\\s*)(.*)?", "args") - val max = 10 - val src = Path(f).toFile.chars(codec) - val args = try { - src.getLines take max collectFirst { - case s if (p findFirstIn s).nonEmpty => for (m <- p findFirstMatchIn s) yield m group "args" - } - } finally src.close() - args.flatten map argsplitter getOrElse Nil - } - sources(testFile) flatMap argsFor - } - - abstract class CompileRound { - def fs: List[File] - def result: TestState - def description: String - - def fsString = fs map (_.toString stripPrefix parentFile.toString + "/") mkString " " - def isOk = result.isOk - def mkScalacString(): String = s"""scalac $fsString""" - override def toString = description + ( if (result.isOk) "" else "\n" + result.status ) - } - case class OnlyJava(fs: List[File]) extends CompileRound { - def description = s"""javac $fsString""" - lazy val result = { pushTranscript(description) ; javac(fs) } - } - case class OnlyScala(fs: List[File]) extends CompileRound { - def description = mkScalacString() - lazy val result = { pushTranscript(description) ; attemptCompile(fs) } - } - case class ScalaAndJava(fs: List[File]) extends CompileRound { - def description = mkScalacString() - lazy val result = { pushTranscript(description) ; attemptCompile(fs) } - } - - def compilationRounds(file: File): List[CompileRound] = ( - (groupedFiles(sources(file)) map mixedCompileGroup).flatten - ) - def mixedCompileGroup(allFiles: List[File]): List[CompileRound] = { - val (scalaFiles, javaFiles) = allFiles partition (_.isScala) - val isMixed = javaFiles.nonEmpty && scalaFiles.nonEmpty - val round1 = if (scalaFiles.isEmpty) None else Some(ScalaAndJava(allFiles)) - val round2 = if (javaFiles.isEmpty) None else Some(OnlyJava(javaFiles)) - val round3 = if (!isMixed) None else Some(OnlyScala(scalaFiles)) - - List(round1, round2, round3).flatten - } - - def runNegTest() = runInContext { - val rounds = compilationRounds(testFile) - - // failing means Does Not Compile - val failing = rounds find (x => nextTestActionExpectTrue("compilation failed", x.isOk) == false) - - // which means passing if it checks and didn't crash the compiler - // or, OK, we'll let you crash the compiler with a FatalError if you supply a check file - def checked(r: CompileRound) = r.result match { - case Crash(_, t, _) if !checkFile.canRead || !t.isInstanceOf[FatalError] => false - case _ => diffIsOk - } - - failing map (checked) getOrElse nextTestActionFailing("expected compilation failure") - } - - def runTestCommon(andAlso: => Boolean): (Boolean, LogContext) = runInContext { - compilationRounds(testFile).forall(x => nextTestActionExpectTrue("compilation failed", x.isOk)) && andAlso - } - - // Apache Ant 1.6 or newer - def ant(args: Seq[String], output: File): Boolean = { - val antDir = Directory(envOrElse("ANT_HOME", "/opt/ant/")) - val antLibDir = Directory(antDir / "lib") - val antLauncherPath = SFile(antLibDir / "ant-launcher.jar").path - val antOptions = - if (NestUI._verbose) List("-verbose", "-noinput") - else List("-noinput") - val cmd = javaCmd +: ( - JAVA_OPTS.split(' ').map(_.trim).filter(_ != "") ++ Seq( - "-classpath", - antLauncherPath, - "org.apache.tools.ant.launch.Launcher" - ) ++ antOptions ++ args - ) - - runCommand(cmd, output) - } - - def runAntTest(): (Boolean, LogContext) = { - val (swr, wr) = newTestWriters() - - val succeeded = try { - val binary = "-Dbinary="+( - if (fileManager.LATEST_LIB endsWith "build/quick/classes/library") "quick" - else if (fileManager.LATEST_LIB endsWith "build/pack/lib/scala-library.jar") "pack" - else if (fileManager.LATEST_LIB endsWith "dists/latest/lib/scala-library.jar/") "latest" - else "installed" - ) - val args = Array(binary, "-logfile", logFile.getPath, "-file", testFile.getPath) - NestUI.verbose("ant "+args.mkString(" ")) - - pushTranscript(s"ant ${args.mkString(" ")}") - nextTestActionExpectTrue("ant failed", ant(args, logFile)) && diffIsOk - } - catch { // *catch-all* - case e: Exception => - NestUI.warning("caught "+e) - false - } - - (succeeded, LogContext(logFile, swr, wr)) - } - - def extraClasspath = kind match { - case "specialized" => PathSettings.srcSpecLib.toString - case _ => "" - } - def extraJavaOptions = kind match { - case "instrumented" => "-javaagent:"+PathSettings.instrumentationAgentLib - case _ => "" - } - - def runScalacheckTest() = runTestCommon { - NestUI verbose f"compilation of $testFile succeeded%n" - - // this classloader is test specific: its parent contains library classes and others - val loader = { - import PathSettings.scalaCheck - val locations = List(outDir, scalaCheck.jfile) map (_.getAbsoluteFile.toURI.toURL) - ScalaClassLoader.fromURLs(locations, getClass.getClassLoader) - } - val logWriter = new PrintStream(new FileOutputStream(logFile), true) - - def runInFramework(): Boolean = { - import org.scalatools.testing._ - val f: Framework = loader.instantiate[Framework]("org.scalacheck.ScalaCheckFramework") - val logger = new Logger { - def ansiCodesSupported = false //params.env.isSet("colors") - def error(msg: String) = logWriter println msg - def warn(msg: String) = logWriter println msg - def info(msg: String) = logWriter println msg - def debug(msg: String) = logWriter println msg - def trace(t: Throwable) = t printStackTrace logWriter - } - var bad = 0 - val handler = new EventHandler { - // testName, description, result, error - // Result = Success, Failure, Error, Skipped - def handle(event: Event): Unit = event.result match { - case Result.Success => - //case Result.Skipped => // an exhausted test is skipped, therefore bad - case _ => bad += 1 - } - } - val loggers = Array(logger) - val r = f.testRunner(loader, loggers).asInstanceOf[Runner2] // why? - val claas = "Test" - val fingerprint = f.tests collectFirst { case x: SubclassFingerprint if x.isModule => x } - val args = toolArgs("scalacheck") - vlog(s"Run $testFile with args $args") - // set the context class loader for scaladoc/scalacheck tests (FIX ME) - ScalaClassLoader(testRunParams.scalaCheckParentClassLoader).asContext { - r.run(claas, fingerprint.get, handler, args.toArray) // synchronous? - } - val ok = (bad == 0) - if (!ok) _transcript append logFile.fileContents - ok - } - try nextTestActionExpectTrue("ScalaCheck test failed", runInFramework()) finally logWriter.close() - } - - def runResidentTest() = { - // simulate resident compiler loop - val prompt = "\nnsc> " - val (swr, wr) = newTestWriters() - - NestUI.verbose(this+" running test "+fileBase) - val dir = parentFile - val resFile = new File(dir, fileBase + ".res") - - // run compiler in resident mode - // $SCALAC -d "$os_dstbase".obj -Xresident -sourcepath . "$@" - val sourcedir = logFile.getParentFile.getAbsoluteFile - val sourcepath = sourcedir.getAbsolutePath+File.separator - NestUI.verbose("sourcepath: "+sourcepath) - - val argList = List( - "-d", outDir.getAbsoluteFile.getPath, - "-Xresident", - "-sourcepath", sourcepath) - - // configure input/output files - val logOut = new FileOutputStream(logFile) - val logWriter = new PrintStream(logOut, true) - val resReader = new BufferedReader(new FileReader(resFile)) - val logConsoleWriter = new PrintWriter(new OutputStreamWriter(logOut), true) - - // create compiler - val settings = new Settings(workerError) - settings.sourcepath.value = sourcepath - settings.classpath.value = fileManager.CLASSPATH - val reporter = new ConsoleReporter(settings, scala.Console.in, logConsoleWriter) - val command = new CompilerCommand(argList, settings) - object compiler extends Global(command.settings, reporter) - - def resCompile(line: String): Boolean = { - // NestUI.verbose("compiling "+line) - val cmdArgs = (line split ' ').toList map (fs => new File(dir, fs).getAbsolutePath) - // NestUI.verbose("cmdArgs: "+cmdArgs) - val sett = new Settings(workerError) - sett.sourcepath.value = sourcepath - val command = new CompilerCommand(cmdArgs, sett) - // "scalac " + command.files.mkString(" ") - pushTranscript("scalac " + command.files.mkString(" ")) - nextTestActionExpectTrue( - "compilation failed", - command.ok && { - (new compiler.Run) compile command.files - !reporter.hasErrors - } - ) - } - def loop(): Boolean = { - logWriter.print(prompt) - resReader.readLine() match { - case null | "" => logWriter.close() ; true - case line => resCompile(line) && loop() - } - } - // res/t687.res depends on ignoring its compilation failure - // and just looking at the diff, so I made them all do that - // because this is long enough. - if (!Output.withRedirected(logWriter)(try loop() finally resReader.close())) - setLastState(genPass()) - - (diffIsOk, LogContext(logFile, swr, wr)) - } - - def run(): TestState = { - // javac runner, for one, would merely append to an existing log file, so just delete it before we start - logFile.delete() - - if (kind == "neg" || (kind endsWith "-neg")) runNegTest() - else kind match { - case "pos" => runTestCommon(true) - case "ant" => runAntTest() - case "scalacheck" => runScalacheckTest() - case "res" => runResidentTest() - case "scalap" => runScalapTest() - case "script" => runScriptTest() - case _ => runTestCommon(execTest(outDir, logFile) && diffIsOk) - } - - lastState - } - - def runScalapTest() = runTestCommon { - val isPackageObject = testFile.getName startsWith "package" - val className = testFile.getName.stripSuffix(".scala").capitalize + (if (!isPackageObject) "" else ".package") - val loader = ScalaClassLoader.fromURLs(List(outDir.toURI.toURL), this.getClass.getClassLoader) - val byteCode = ByteCode forClass (loader loadClass className) - val result = decompileScala(byteCode.bytes, isPackageObject) - - logFile writeAll result - diffIsOk - } - def runScriptTest() = { - import scala.sys.process._ - val (swr, wr) = newTestWriters() - - val args = file2String(testFile changeExtension "args") - val cmdFile = if (isWin) testFile changeExtension "bat" else testFile - val succeeded = (((cmdFile + " " + args) #> logFile !) == 0) && diffIsOk - - (succeeded, LogContext(logFile, swr, wr)) - } - - def cleanup() { - if (lastState.isOk) - logFile.delete() - if (!isPartestDebug) - Directory(outDir).deleteRecursively() - } -} - -case class TestRunParams(val scalaCheckParentClassLoader: ScalaClassLoader) - -/** Extended by Ant- and ConsoleRunner for running a set of tests. */ -trait DirectRunner { - def fileManager: FileManager - - import PartestDefaults.{ numThreads, waitTime } - - setUncaughtHandler - - def runTestsForFiles(kindFiles: List[File], kind: String): List[TestState] = { - - NestUI.resetTestNumber(kindFiles.size) - - // this special class loader is for the benefit of scaladoc tests, which need a class path - import PathSettings.{ testInterface, scalaCheck } - val allUrls = scalaCheck.toURL :: testInterface.toURL :: fileManager.latestUrls - val parentClassLoader = ScalaClassLoader fromURLs allUrls - // add scalacheck.jar to a special classloader, but use our loader as parent with test-interface - //val parentClassLoader = ScalaClassLoader fromURLs (List(scalaCheck.toURL), getClass().getClassLoader) - val pool = Executors newFixedThreadPool numThreads - val manager = new RunnerManager(kind, fileManager, TestRunParams(parentClassLoader)) - val futures = kindFiles map (f => pool submit callable(manager runTest f.getAbsoluteFile)) - - pool.shutdown() - Try (pool.awaitTermination(waitTime) { - throw TimeoutException(waitTime) - }) match { - case Success(_) => futures map (_.get) - case Failure(e) => - e match { - case TimeoutException(d) => - NestUI warning "Thread pool timeout elapsed before all tests were complete!" - case ie: InterruptedException => - NestUI warning "Thread pool was interrupted" - ie.printStackTrace() - } - pool.shutdownNow() // little point in continuing - // try to get as many completions as possible, in case someone cares - val results = for (f <- futures) yield { - try { - Some(f.get(0, NANOSECONDS)) - } catch { - case _: Throwable => None - } - } - results.flatten - } - } -} - -case class TimeoutException(duration: Duration) extends RuntimeException - -class LogContext(val file: File, val writers: Option[(StringWriter, PrintWriter)]) - -object LogContext { - def apply(file: File, swr: StringWriter, wr: PrintWriter): LogContext = { - require (file != null) - new LogContext(file, Some((swr, wr))) - } - def apply(file: File): LogContext = new LogContext(file, None) -} - -object Output { - object outRedirect extends Redirecter(out) - object errRedirect extends Redirecter(err) - - System.setOut(outRedirect) - System.setErr(errRedirect) - - import scala.util.DynamicVariable - private def out = java.lang.System.out - private def err = java.lang.System.err - private val redirVar = new DynamicVariable[Option[PrintStream]](None) - - class Redirecter(stream: PrintStream) extends PrintStream(new OutputStream { - def write(b: Int) = withStream(_ write b) - - private def withStream(f: PrintStream => Unit) = f(redirVar.value getOrElse stream) - - override def write(b: Array[Byte]) = withStream(_ write b) - override def write(b: Array[Byte], off: Int, len: Int) = withStream(_.write(b, off, len)) - override def flush = withStream(_.flush) - override def close = withStream(_.close) - }) - - // this supports thread-safe nested output redirects - def withRedirected[T](newstream: PrintStream)(func: => T): T = { - // note down old redirect destination - // this may be None in which case outRedirect and errRedirect print to stdout and stderr - val saved = redirVar.value - // set new redirecter - // this one will redirect both out and err to newstream - redirVar.value = Some(newstream) - - try func - finally { - newstream.flush() - redirVar.value = saved - } - } -} - -/** Use a Runner to run a test. */ -class RunnerManager(kind: String, fileManager: FileManager, params: TestRunParams) { - fileManager.CLASSPATH += File.pathSeparator + PathSettings.scalaCheck - fileManager.CLASSPATH += File.pathSeparator + PathSettings.diffUtils // needed to put diffutils on test/partest's classpath - - def runTest(testFile: File): TestState = { - val runner = new Runner(testFile, fileManager, params) - - // when option "--failed" is provided execute test only if log - // is present (which means it failed before) - if (fileManager.failed && !runner.logFile.canRead) - runner.genPass() - else { - val (state, _) = - try timed(runner.run()) - catch { - case t: Throwable => throw new RuntimeException(s"Error running $testFile", t) - } - NestUI.reportTest(state) - runner.cleanup() - state - } - } -} diff --git a/src/partest/scala/tools/partest/nest/SBTRunner.scala b/src/partest/scala/tools/partest/nest/SBTRunner.scala deleted file mode 100644 index 1cf3aa858f..0000000000 --- a/src/partest/scala/tools/partest/nest/SBTRunner.scala +++ /dev/null @@ -1,85 +0,0 @@ -/* NEST (New Scala Test) - * Copyright 2007-2013 LAMP/EPFL - */ -package scala.tools.partest -package nest - -import java.io.File -import scala.tools.nsc.io.{ Directory } -import scala.util.Properties.setProp -import scala.collection.JavaConverters._ - -object SBTRunner extends DirectRunner { - - val fileManager = new FileManager { - var JAVACMD: String = "java" - var JAVAC_CMD: String = "javac" - var CLASSPATH: String = _ - var LATEST_LIB: String = _ - var LATEST_REFLECT: String = _ - var LATEST_COMP: String = _ - var LATEST_PARTEST: String = _ - var LATEST_ACTORS: String = _ - val testRootPath: String = "test" - val testRootDir: Directory = Directory(testRootPath) - } - - def reflectiveRunTestsForFiles(kindFiles: Array[File], kind: String): java.util.List[TestState] = { - def failedOnlyIfRequired(files:List[File]):List[File]={ - if (fileManager.failed) files filter (x => fileManager.logFileExists(x, kind)) else files - } - runTestsForFiles(failedOnlyIfRequired(kindFiles.toList), kind).asJava - } - - case class CommandLineOptions(classpath: Option[String] = None, - tests: Map[String, Array[File]] = Map(), - scalacOptions: Seq[String] = Seq(), - justFailedTests: Boolean = false) - - def mainReflect(args: Array[String]): java.util.List[TestState] = { - setProp("partest.debug", "true") - - val Argument = new scala.util.matching.Regex("-(.*)") - def parseArgs(args: Seq[String], data: CommandLineOptions): CommandLineOptions = args match { - case Seq("--failed", rest @ _*) => parseArgs(rest, data.copy(justFailedTests = true)) - case Seq("-cp", cp, rest @ _*) => parseArgs(rest, data.copy(classpath=Some(cp))) - case Seq("-scalacoption", opt, rest @ _*) => parseArgs(rest, data.copy(scalacOptions= data.scalacOptions :+ opt)) - case Seq(Argument(name), runFiles, rest @ _*) => parseArgs(rest, data.copy(tests=data.tests + (name -> runFiles.split(",").map(new File(_))))) - case Seq() => data - case x => sys.error("Unknown command line options: " + x) - } - val config = parseArgs(args, CommandLineOptions()) - fileManager.SCALAC_OPTS = config.scalacOptions - fileManager.CLASSPATH = config.classpath getOrElse sys.error("No classpath set") - - def findClasspath(jar: String, name: String): Option[String] = { - val optJar = (fileManager.CLASSPATH split File.pathSeparator filter (_ matches (".*"+jar+".*\\.jar"))).headOption - val optClassDir = (fileManager.CLASSPATH split File.pathSeparator filter (_ matches (".*"+name+File.separator+"classes"))).headOption - optJar orElse optClassDir - } - // Find scala library jar file... - fileManager.LATEST_LIB = findClasspath("scala-library", "scala-library") getOrElse sys.error("No scala-library found! Classpath = " + fileManager.CLASSPATH) - fileManager.LATEST_REFLECT = findClasspath("scala-reflect", "scala-reflect") getOrElse sys.error("No scala-reflect found! Classpath = " + fileManager.CLASSPATH) - fileManager.LATEST_COMP = findClasspath("scala-compiler", "scala-compiler") getOrElse sys.error("No scala-compiler found! Classpath = " + fileManager.CLASSPATH) - fileManager.LATEST_PARTEST = findClasspath("scala-partest", "partest") getOrElse sys.error("No scala-partest found! Classpath = " + fileManager.CLASSPATH) - fileManager.LATEST_ACTORS = findClasspath("scala-actors", "actors") getOrElse sys.error("No scala-actors found! Classpath = " + fileManager.CLASSPATH) - - // TODO - Do something useful here!!! - fileManager.JAVAC_CMD = "javac" - fileManager.failed = config.justFailedTests - // TODO - Make this a flag? - //fileManager.updateCheck = true - // Now run and report... - val runs = config.tests.filterNot(_._2.isEmpty) - val result = runs.toList flatMap { case (kind, files) => reflectiveRunTestsForFiles(files, kind).asScala } - - result.asJava - } - - def main(args: Array[String]): Unit = { - val failures = mainReflect(args).asScala collect { case s if !s.isOk => s.longStatus } - // Re-list all failures so we can go figure out what went wrong. - failures foreach System.err.println - if(!failures.isEmpty) sys.exit(1) - } -} diff --git a/src/partest/scala/tools/partest/nest/StreamCapture.scala b/src/partest/scala/tools/partest/nest/StreamCapture.scala deleted file mode 100644 index dc155b1787..0000000000 --- a/src/partest/scala/tools/partest/nest/StreamCapture.scala +++ /dev/null @@ -1,53 +0,0 @@ -/* NEST (New Scala Test) - * Copyright 2007-2013 LAMP/EPFL - * @author Paul Phillips - */ -package scala.tools.partest -package nest - -import java.io.{ Console => _, _ } - -object StreamCapture { - case class Captured[T](stdout: String, stderr: String, result: T) { - override def toString = s""" - |result: $result - |[stdout] - |$stdout - |[stderr] - |$stderr""".stripMargin.trim - } - - private def mkStream = { - val swr = new StringWriter - val wr = new PrintWriter(swr, true) - val ostream = new PrintStream(new OutputStream { def write(b: Int): Unit = wr write b }, true) // autoFlush = true - - (ostream, () => { ostream.close() ; swr.toString }) - } - - def savingSystem[T](body: => T): T = { - val savedOut = System.out - val savedErr = System.err - try body - finally { - System setErr savedErr - System setOut savedOut - } - } - - def apply[T](body: => T): Captured[T] = { - val (outstream, stdoutFn) = mkStream - val (errstream, stderrFn) = mkStream - - val result = savingSystem { - System setOut outstream - System setErr errstream - Console.withOut(outstream) { - Console.withErr(errstream) { - body - } - } - } - Captured(stdoutFn(), stderrFn(), result) - } -} diff --git a/src/partest/scala/tools/partest/package.scala b/src/partest/scala/tools/partest/package.scala deleted file mode 100644 index 77400b1b9c..0000000000 --- a/src/partest/scala/tools/partest/package.scala +++ /dev/null @@ -1,241 +0,0 @@ -/* NEST (New Scala Test) - * Copyright 2007-2013 LAMP/EPFL - */ - -package scala.tools - -import java.util.concurrent.{ Callable, ExecutorService } -import scala.concurrent.duration.Duration -import scala.sys.process.javaVmArguments -import scala.tools.partest.nest.NestUI -import scala.tools.nsc.util.{ ScalaClassLoader, Exceptional } - -package object partest { - type File = java.io.File - type SFile = scala.reflect.io.File - type Directory = scala.reflect.io.Directory - type Path = scala.reflect.io.Path - type PathResolver = scala.tools.util.PathResolver - type ClassPath[T] = scala.tools.nsc.util.ClassPath[T] - type StringWriter = java.io.StringWriter - - val SFile = scala.reflect.io.File - val Directory = scala.reflect.io.Directory - val Path = scala.reflect.io.Path - val PathResolver = scala.tools.util.PathResolver - val ClassPath = scala.tools.nsc.util.ClassPath - - val space = "\u0020" - val EOL = scala.compat.Platform.EOL - def onull(s: String) = if (s == null) "" else s - def oempty(xs: String*) = xs filterNot (x => x == null || x == "") - def ojoin(xs: String*): String = oempty(xs: _*) mkString space - def nljoin(xs: String*): String = oempty(xs: _*) mkString EOL - - implicit val codec = scala.io.Codec.UTF8 - - def setUncaughtHandler() = { - Thread.setDefaultUncaughtExceptionHandler( - new Thread.UncaughtExceptionHandler { - def uncaughtException(thread: Thread, t: Throwable) { - val t1 = Exceptional unwrap t - System.err.println(s"Uncaught exception on thread $thread: $t1") - t1.printStackTrace() - } - } - ) - } - - /** Sources have a numerical group, specified by name_7 and so on. */ - private val GroupPattern = """.*_(\d+)""".r - - implicit class FileOps(val f: File) { - private def sf = SFile(f) - - def testIdent = { - f.toString split """[/\\]+""" takeRight 2 mkString "/" // e.g. pos/t1234 - } - - def mapInPlace(mapFn: String => String)(filterFn: String => Boolean = _ => true): Unit = - writeAll(fileLines filter filterFn map (x => mapFn(x) + EOL): _*) - - def appendAll(strings: String*): Unit = sf.appendAll(strings: _*) - def writeAll(strings: String*): Unit = sf.writeAll(strings: _*) - def absolutePathSegments: List[String] = f.getAbsolutePath split """[/\\]+""" toList - - def isJava = f.isFile && (sf hasExtension "java") - def isScala = f.isFile && (sf hasExtension "scala") - def isJavaOrScala = isJava || isScala - - def extension = sf.extension - def hasExtension(ext: String) = sf hasExtension ext - def changeExtension(ext: String): File = (sf changeExtension ext).jfile - - /** The group number for this source file, or -1 for no group. */ - def group: Int = - sf.stripExtension match { - case GroupPattern(g) if g.toInt >= 0 => g.toInt - case _ => -1 - } - - def fileContents: String = try sf.slurp() catch { case _: java.io.FileNotFoundException => "" } - def fileLines: List[String] = augmentString(fileContents).lines.toList - } - - implicit class PathOps(p: Path) extends FileOps(p.jfile) { } - - implicit class Copier(val f: SFile) extends AnyVal { - def copyTo(dest: Path): Unit = dest.toFile writeAll f.slurp(scala.io.Codec.UTF8) - } - - implicit class LoaderOps(val loader: ClassLoader) extends AnyVal { - import scala.util.control.Exception.catching - /** Like ScalaClassLoader.create for the case where the result type is - * available to the current class loader, implying that the current - * loader is a parent of `loader`. - */ - def instantiate[A >: Null](name: String): A = ( - catching(classOf[ClassNotFoundException], classOf[SecurityException]) opt - (loader loadClass name).newInstance.asInstanceOf[A] orNull - ) - } - - implicit class ExecutorOps(val executor: ExecutorService) { - def awaitTermination[A](wait: Duration)(failing: => A = ()): Option[A] = ( - if (executor awaitTermination (wait.length, wait.unit)) None - else Some(failing) - ) - } - - implicit def temporaryPath2File(x: Path): File = x.jfile - implicit def stringPathToJavaFile(path: String): File = new File(path) - - implicit lazy val postfixOps = scala.language.postfixOps - implicit lazy val implicitConversions = scala.language.implicitConversions - - def fileSeparator = java.io.File.separator - def pathSeparator = java.io.File.pathSeparator - - def pathToTestIdent(path: Path) = path.jfile.testIdent - - def canonicalizeSlashes(line: String) = line.replaceAll("""[/\\]+""", "/") - - def words(s: String): List[String] = (s.trim split "\\s+").toList - - def timed[T](body: => T): (T, Long) = { - val t1 = System.currentTimeMillis - val result = body - val t2 = System.currentTimeMillis - - (result, t2 - t1) - } - - def callable[T](body: => T): Callable[T] = new Callable[T] { override def call() = body } - - def file2String(f: File): String = f.fileContents - - def basename(name: String): String = Path(name).stripExtension - - /** In order to allow for spaces in flags/options, this - * parses .flags, .javaopts, javacopts etc files as follows: - * If it is exactly one line, it is split (naively) on spaces. - * If it contains more than one line, each line is its own - * token, spaces and all. - */ - def readOptionsFile(file: File): List[String] = { - file.fileLines match { - case x :: Nil => words(x) - case xs => xs map (_.trim) - } - } - - def findProgram(name: String): Option[File] = { - val pathDirs = sys.env("PATH") match { - case null => List("/usr/local/bin", "/usr/bin", "/bin") - case path => path split "[:;]" filterNot (_ == "") toList - } - pathDirs.iterator map (d => new File(d, name)) find (_.canExecute) - } - - def now = (new java.util.Date).toString - def elapsedString(millis: Long): String = { - val elapsedSecs = millis/1000 - val elapsedMins = elapsedSecs/60 - val elapsedHrs = elapsedMins/60 - val dispMins = elapsedMins - elapsedHrs * 60 - val dispSecs = elapsedSecs - elapsedMins * 60 - - "%02d:%02d:%02d".format(elapsedHrs, dispMins, dispSecs) - } - - def vmArgString = javaVmArguments.mkString( - "Java VM started with arguments: '", - " ", - "'" - ) - - def allPropertiesString = { - import scala.collection.JavaConversions._ - System.getProperties.toList.sorted map { case (k, v) => "%s -> %s\n".format(k, v) } mkString "" - } - - def showAllJVMInfo() { - vlog(vmArgString) - vlog(allPropertiesString) - } - - import scala.language.experimental.macros - - /** - * `trace("".isEmpty)` will return `true` and as a side effect print the following to standard out. - * {{{ - * trace> "".isEmpty - * res: Boolean = true - * - * }}} - * - * An alternative to [[scala.tools.partest.ReplTest]] that avoids the inconvenience of embedding - * test code in a string. - */ - def trace[A](a: A) = macro traceImpl[A] - - import scala.reflect.macros.Context - def traceImpl[A: c.WeakTypeTag](c: Context)(a: c.Expr[A]): c.Expr[A] = { - import c.universe._ - import definitions._ - - // xeno.by: reify shouldn't be used explicitly before the final release of 2.10.0, - // because this impairs reflection refactorings - // - // val exprCode = c.literal(show(a.tree)) - // val exprType = c.literal(show(a.actualType)) - // reify { - // println(s"trace> ${exprCode.splice}\nres: ${exprType.splice} = ${a.splice}\n") - // a.splice - // } - - c.Expr(Block( - List(Apply( - Select(Ident(PredefModule), TermName("println")), - List(Apply( - Select(Apply( - Select(Ident(ScalaPackage), TermName("StringContext")), - List( - Literal(Constant("trace> ")), - Literal(Constant("\\nres: ")), - Literal(Constant(" = ")), - Literal(Constant("\\n")))), - TermName("s")), - List( - Literal(Constant(show(a.tree))), - Literal(Constant(show(a.actualType))), - a.tree))))), - a.tree)) - } - - def isPartestTerse = NestUI.isTerse - def isPartestDebug = NestUI.isDebug - def isPartestVerbose = NestUI.isVerbose - - def vlog(msg: => String) = if (isPartestVerbose) System.err.println(msg) -} diff --git a/src/partest/scala/tools/partest/utils/Properties.scala b/src/partest/scala/tools/partest/utils/Properties.scala deleted file mode 100644 index b9394b50c9..0000000000 --- a/src/partest/scala/tools/partest/utils/Properties.scala +++ /dev/null @@ -1,18 +0,0 @@ -/* __ *\ -** ________ ___ / / ___ Scala Parallel Testing ** -** / __/ __// _ | / / / _ | (c) 2007-2013, LAMP/EPFL ** -** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** -** /____/\___/_/ |_/____/_/ | | ** -** |/ ** -\* */ - - -package scala.tools.partest -package utils - -/** Loads partest.properties from the jar. */ -object Properties extends scala.util.PropertiesTrait { - protected def propCategory = "partest" - protected def pickJarBasedOn = classOf[nest.RunnerManager] - override def isAvian = super.isAvian -} diff --git a/src/scalacheck/org/scalacheck/Arbitrary.scala b/src/scalacheck/org/scalacheck/Arbitrary.scala deleted file mode 100644 index db4163c8af..0000000000 --- a/src/scalacheck/org/scalacheck/Arbitrary.scala +++ /dev/null @@ -1,447 +0,0 @@ -/*-------------------------------------------------------------------------*\ -** ScalaCheck ** -** Copyright (c) 2007-2013 Rickard Nilsson. All rights reserved. ** -** http://www.scalacheck.org ** -** ** -** This software is released under the terms of the Revised BSD License. ** -** There is NO WARRANTY. See the file LICENSE for the full text. ** -\*------------------------------------------------------------------------ */ - -package org.scalacheck - -import util.{FreqMap,Buildable} - -sealed abstract class Arbitrary[T] { - val arbitrary: Gen[T] -} - -/** Defines implicit [[org.scalacheck.Arbitrary]] instances for common types. - *

- * ScalaCheck - * uses implicit [[org.scalacheck.Arbitrary]] instances when creating properties - * out of functions with the `Prop.property` method, and when - * the `Arbitrary.arbitrary` method is used. For example, the - * following code requires that there exists an implicit - * `Arbitrary[MyClass]` instance: - *

- * - * {{{ - * val myProp = Prop.forAll { myClass: MyClass => - * ... - * } - * - * val myGen = Arbitrary.arbitrary[MyClass] - * }}} - * - *

- * The required implicit definition could look like this: - *

- * - * {{{ - * implicit val arbMyClass: Arbitrary[MyClass] = Arbitrary(...) - * }}} - * - *

- * The factory method `Arbitrary(...)` takes a generator of type - * `Gen[T]` and returns an instance of `Arbitrary[T]`. - *

- * - *

- * The `Arbitrary` module defines implicit [[org.scalacheck.Arbitrary]] - * instances for common types, for convenient use in your properties and - * generators. - *

- */ -object Arbitrary { - - import Gen.{value, choose, sized, listOf, listOf1, - frequency, oneOf, containerOf, resize} - import util.StdRand - import scala.collection.{immutable, mutable} - import java.util.Date - - /** Creates an Arbitrary instance */ - def apply[T](g: => Gen[T]): Arbitrary[T] = new Arbitrary[T] { - lazy val arbitrary = g - } - - /** Returns an arbitrary generator for the type T. */ - def arbitrary[T](implicit a: Arbitrary[T]): Gen[T] = a.arbitrary - - /**** Arbitrary instances for each AnyVal ****/ - - /** Arbitrary AnyVal */ - implicit lazy val arbAnyVal: Arbitrary[AnyVal] = Arbitrary(oneOf( - arbitrary[Unit], arbitrary[Boolean], arbitrary[Char], arbitrary[Byte], - arbitrary[Short], arbitrary[Int], arbitrary[Long], arbitrary[Float], - arbitrary[Double] - )) - - /** Arbitrary instance of Boolean */ - implicit lazy val arbBool: Arbitrary[Boolean] = - Arbitrary(oneOf(true, false)) - - /** Arbitrary instance of Int */ - implicit lazy val arbInt: Arbitrary[Int] = Arbitrary( - Gen.chooseNum(Int.MinValue, Int.MaxValue) - ) - - /** Arbitrary instance of Long */ - implicit lazy val arbLong: Arbitrary[Long] = Arbitrary( - Gen.chooseNum(Long.MinValue, Long.MaxValue) - ) - - /** Arbitrary instance of Float */ - implicit lazy val arbFloat: Arbitrary[Float] = Arbitrary( - Gen.chooseNum( - Float.MinValue, Float.MaxValue - // I find that including these by default is a little TOO testy. - // Float.Epsilon, Float.NaN, Float.PositiveInfinity, Float.NegativeInfinity - ) - ) - - /** Arbitrary instance of Double */ - implicit lazy val arbDouble: Arbitrary[Double] = Arbitrary( - Gen.chooseNum( - Double.MinValue / 2, Double.MaxValue / 2 - // As above. Perhaps behind some option? - // Double.Epsilon, Double.NaN, Double.PositiveInfinity, Double.NegativeInfinity - ) - ) - - /** Arbitrary instance of Char */ - implicit lazy val arbChar: Arbitrary[Char] = Arbitrary( - Gen.frequency( - (0xD800-Char.MinValue, Gen.choose(Char.MinValue,0xD800-1)), - (Char.MaxValue-0xDFFF, Gen.choose(0xDFFF+1,Char.MaxValue)) - ) - ) - - /** Arbitrary instance of Byte */ - implicit lazy val arbByte: Arbitrary[Byte] = Arbitrary( - Gen.chooseNum(Byte.MinValue, Byte.MaxValue) - ) - - /** Arbitrary instance of Short */ - implicit lazy val arbShort: Arbitrary[Short] = Arbitrary( - Gen.chooseNum(Short.MinValue, Short.MaxValue) - ) - - /** Absolutely, totally, 100% arbitrarily chosen Unit. */ - implicit lazy val arbUnit: Arbitrary[Unit] = Arbitrary(value(())) - - /**** Arbitrary instances of other common types ****/ - - /** Arbitrary instance of String */ - implicit lazy val arbString: Arbitrary[String] = - Arbitrary(arbitrary[List[Char]] map (_.mkString)) - - /** Arbitrary instance of Date */ - implicit lazy val arbDate: Arbitrary[Date] = Arbitrary(for { - l <- arbitrary[Long] - d = new Date - } yield new Date(d.getTime + l)) - - /** Arbitrary instance of Throwable */ - implicit lazy val arbThrowable: Arbitrary[Throwable] = - Arbitrary(value(new Exception)) - - /** Arbitrary BigInt */ - implicit lazy val arbBigInt: Arbitrary[BigInt] = { - def chooseBigInt: Gen[BigInt] = sized((s: Int) => choose(-s, s)) map (x => BigInt(x)) - def chooseReallyBigInt = chooseBigInt.combine(choose(32, 128))((x, y) => Some(x.get << y.get)) - - Arbitrary( - frequency( - (5, chooseBigInt), - (10, chooseReallyBigInt), - (1, BigInt(0)), - (1, BigInt(1)), - (1, BigInt(-1)), - (1, BigInt(Int.MaxValue) + 1), - (1, BigInt(Int.MinValue) - 1), - (1, BigInt(Long.MaxValue)), - (1, BigInt(Long.MinValue)), - (1, BigInt(Long.MaxValue) + 1), - (1, BigInt(Long.MinValue) - 1) - ) - ) - } - - /** Arbitrary BigDecimal */ - implicit lazy val arbBigDecimal: Arbitrary[BigDecimal] = { - import java.math.MathContext._ - val mcGen = oneOf(UNLIMITED, DECIMAL32, DECIMAL64, DECIMAL128) - val bdGen = for { - x <- arbBigInt.arbitrary - mc <- mcGen - limit <- value(if(mc == UNLIMITED) 0 else math.max(x.abs.toString.length - mc.getPrecision, 0)) - scale <- Gen.chooseNum(Int.MinValue + limit , Int.MaxValue) - } yield { - try { - BigDecimal(x, scale, mc) - } catch { - case ae: java.lang.ArithmeticException => BigDecimal(x, scale, UNLIMITED) // Handle the case where scale/precision conflict - } - } - Arbitrary(bdGen) - } - - /** Arbitrary java.lang.Number */ - implicit lazy val arbNumber: Arbitrary[Number] = { - val gen = Gen.oneOf( - arbitrary[Byte], arbitrary[Short], arbitrary[Int], arbitrary[Long], - arbitrary[Float], arbitrary[Double] - ) - Arbitrary(gen map (_.asInstanceOf[Number])) - // XXX TODO - restore BigInt and BigDecimal - // Arbitrary(oneOf(arbBigInt.arbitrary :: (arbs map (_.arbitrary) map toNumber) : _*)) - } - - /** Generates an arbitrary property */ - implicit lazy val arbProp: Arbitrary[Prop] = { - import Prop._ - val undecidedOrPassed = forAll { b: Boolean => - b ==> true - } - Arbitrary(frequency( - (4, falsified), - (4, passed), - (3, proved), - (3, undecidedOrPassed), - (2, undecided), - (1, exception(null)) - )) - } - - /** Arbitrary instance of test params - * @deprecated (in 1.10.0) Use `arbTestParameters` instead. - */ - @deprecated("Use 'arbTestParameters' instead", "1.10.0") - implicit lazy val arbTestParams: Arbitrary[Test.Params] = - Arbitrary(for { - minSuccTests <- choose(10,200) - maxDiscTests <- choose(100,500) - mnSize <- choose(0,500) - sizeDiff <- choose(0,500) - mxSize <- choose(mnSize, mnSize + sizeDiff) - ws <- choose(1,4) - } yield Test.Params( - minSuccessfulTests = minSuccTests, - maxDiscardedTests = maxDiscTests, - minSize = mnSize, - maxSize = mxSize, - workers = ws - )) - - /** Arbitrary instance of test parameters */ - implicit lazy val arbTestParameters: Arbitrary[Test.Parameters] = - Arbitrary(for { - _minSuccTests <- choose(10,200) - _maxDiscardRatio <- choose(0.2f,10f) - _minSize <- choose(0,500) - sizeDiff <- choose(0,500) - _maxSize <- choose(_minSize, _minSize + sizeDiff) - _workers <- choose(1,4) - } yield new Test.Parameters.Default { - override val minSuccessfulTests = _minSuccTests - override val maxDiscardRatio = _maxDiscardRatio - override val minSize = _minSize - override val maxSize = _maxSize - override val workers = _workers - }) - - /** Arbitrary instance of gen params */ - implicit lazy val arbGenParams: Arbitrary[Gen.Params] = - Arbitrary(for { - size <- arbitrary[Int] suchThat (_ >= 0) - } yield Gen.Params(size, StdRand)) - - /** Arbitrary instance of prop params */ - implicit lazy val arbPropParams: Arbitrary[Prop.Params] = - Arbitrary(for { - genPrms <- arbitrary[Gen.Params] - } yield Prop.Params(genPrms, FreqMap.empty[immutable.Set[Any]])) - - - // Higher-order types // - - /** Arbitrary instance of Gen */ - implicit def arbGen[T](implicit a: Arbitrary[T]): Arbitrary[Gen[T]] = - Arbitrary(frequency( - (5, arbitrary[T] map (value(_))), - (1, Gen.fail) - )) - - /** Arbitrary instance of option type */ - implicit def arbOption[T](implicit a: Arbitrary[T]): Arbitrary[Option[T]] = - Arbitrary(sized(n => if(n == 0) value(None) else resize(n - 1, arbitrary[T]).map(Some(_)))) - - implicit def arbEither[T, U](implicit at: Arbitrary[T], au: Arbitrary[U]): Arbitrary[Either[T, U]] = - Arbitrary(oneOf(arbitrary[T].map(Left(_)), arbitrary[U].map(Right(_)))) - - /** Arbitrary instance of immutable map */ - implicit def arbImmutableMap[T,U](implicit at: Arbitrary[T], au: Arbitrary[U] - ): Arbitrary[immutable.Map[T,U]] = Arbitrary( - for(seq <- arbitrary[Stream[(T,U)]]) yield immutable.Map(seq: _*) - ) - - /** Arbitrary instance of mutable map */ - implicit def arbMutableMap[T,U](implicit at: Arbitrary[T], au: Arbitrary[U] - ): Arbitrary[mutable.Map[T,U]] = Arbitrary( - for(seq <- arbitrary[Stream[(T,U)]]) yield mutable.Map(seq: _*) - ) - - /** Arbitrary instance of any buildable container (such as lists, arrays, - * streams, etc). The maximum size of the container depends on the size - * generation parameter. */ - implicit def arbContainer[C[_],T](implicit a: Arbitrary[T], b: Buildable[T,C] - ): Arbitrary[C[T]] = Arbitrary(containerOf[C,T](arbitrary[T])) - - /** Arbitrary instance of any array. */ - implicit def arbArray[T](implicit a: Arbitrary[T], c: ClassManifest[T] - ): Arbitrary[Array[T]] = Arbitrary(containerOf[Array,T](arbitrary[T])) - - - // Functions // - - /** Arbitrary instance of Function1 */ - implicit def arbFunction1[T1,R](implicit a: Arbitrary[R] - ): Arbitrary[T1 => R] = Arbitrary( - for(r <- arbitrary[R]) yield (t1: T1) => r - ) - - /** Arbitrary instance of Function2 */ - implicit def arbFunction2[T1,T2,R](implicit a: Arbitrary[R] - ): Arbitrary[(T1,T2) => R] = Arbitrary( - for(r <- arbitrary[R]) yield (t1: T1, t2: T2) => r - ) - - /** Arbitrary instance of Function3 */ - implicit def arbFunction3[T1,T2,T3,R](implicit a: Arbitrary[R] - ): Arbitrary[(T1,T2,T3) => R] = Arbitrary( - for(r <- arbitrary[R]) yield (t1: T1, t2: T2, t3: T3) => r - ) - - /** Arbitrary instance of Function4 */ - implicit def arbFunction4[T1,T2,T3,T4,R](implicit a: Arbitrary[R] - ): Arbitrary[(T1,T2,T3,T4) => R] = Arbitrary( - for(r <- arbitrary[R]) yield (t1: T1, t2: T2, t3: T3, t4: T4) => r - ) - - /** Arbitrary instance of Function5 */ - implicit def arbFunction5[T1,T2,T3,T4,T5,R](implicit a: Arbitrary[R] - ): Arbitrary[(T1,T2,T3,T4,T5) => R] = Arbitrary( - for(r <- arbitrary[R]) yield (t1: T1, t2: T2, t3: T3, t4: T4, t5: T5) => r - ) - - - // Tuples // - - /** Arbitrary instance of 2-tuple */ - implicit def arbTuple2[T1,T2](implicit - a1: Arbitrary[T1], a2: Arbitrary[T2] - ): Arbitrary[(T1,T2)] = - Arbitrary(for { - t1 <- arbitrary[T1] - t2 <- arbitrary[T2] - } yield (t1,t2)) - - /** Arbitrary instance of 3-tuple */ - implicit def arbTuple3[T1,T2,T3](implicit - a1: Arbitrary[T1], a2: Arbitrary[T2], a3: Arbitrary[T3] - ): Arbitrary[(T1,T2,T3)] = - Arbitrary(for { - t1 <- arbitrary[T1] - t2 <- arbitrary[T2] - t3 <- arbitrary[T3] - } yield (t1,t2,t3)) - - /** Arbitrary instance of 4-tuple */ - implicit def arbTuple4[T1,T2,T3,T4](implicit - a1: Arbitrary[T1], a2: Arbitrary[T2], a3: Arbitrary[T3], a4: Arbitrary[T4] - ): Arbitrary[(T1,T2,T3,T4)] = - Arbitrary(for { - t1 <- arbitrary[T1] - t2 <- arbitrary[T2] - t3 <- arbitrary[T3] - t4 <- arbitrary[T4] - } yield (t1,t2,t3,t4)) - - /** Arbitrary instance of 5-tuple */ - implicit def arbTuple5[T1,T2,T3,T4,T5](implicit - a1: Arbitrary[T1], a2: Arbitrary[T2], a3: Arbitrary[T3], a4: Arbitrary[T4], - a5: Arbitrary[T5] - ): Arbitrary[(T1,T2,T3,T4,T5)] = - Arbitrary(for { - t1 <- arbitrary[T1] - t2 <- arbitrary[T2] - t3 <- arbitrary[T3] - t4 <- arbitrary[T4] - t5 <- arbitrary[T5] - } yield (t1,t2,t3,t4,t5)) - - /** Arbitrary instance of 6-tuple */ - implicit def arbTuple6[T1,T2,T3,T4,T5,T6](implicit - a1: Arbitrary[T1], a2: Arbitrary[T2], a3: Arbitrary[T3], a4: Arbitrary[T4], - a5: Arbitrary[T5], a6: Arbitrary[T6] - ): Arbitrary[(T1,T2,T3,T4,T5,T6)] = - Arbitrary(for { - t1 <- arbitrary[T1] - t2 <- arbitrary[T2] - t3 <- arbitrary[T3] - t4 <- arbitrary[T4] - t5 <- arbitrary[T5] - t6 <- arbitrary[T6] - } yield (t1,t2,t3,t4,t5,t6)) - - /** Arbitrary instance of 7-tuple */ - implicit def arbTuple7[T1,T2,T3,T4,T5,T6,T7](implicit - a1: Arbitrary[T1], a2: Arbitrary[T2], a3: Arbitrary[T3], a4: Arbitrary[T4], - a5: Arbitrary[T5], a6: Arbitrary[T6], a7: Arbitrary[T7] - ): Arbitrary[(T1,T2,T3,T4,T5,T6,T7)] = - Arbitrary(for { - t1 <- arbitrary[T1] - t2 <- arbitrary[T2] - t3 <- arbitrary[T3] - t4 <- arbitrary[T4] - t5 <- arbitrary[T5] - t6 <- arbitrary[T6] - t7 <- arbitrary[T7] - } yield (t1,t2,t3,t4,t5,t6,t7)) - - /** Arbitrary instance of 8-tuple */ - implicit def arbTuple8[T1,T2,T3,T4,T5,T6,T7,T8](implicit - a1: Arbitrary[T1], a2: Arbitrary[T2], a3: Arbitrary[T3], a4: Arbitrary[T4], - a5: Arbitrary[T5], a6: Arbitrary[T6], a7: Arbitrary[T7], a8: Arbitrary[T8] - ): Arbitrary[(T1,T2,T3,T4,T5,T6,T7,T8)] = - Arbitrary(for { - t1 <- arbitrary[T1] - t2 <- arbitrary[T2] - t3 <- arbitrary[T3] - t4 <- arbitrary[T4] - t5 <- arbitrary[T5] - t6 <- arbitrary[T6] - t7 <- arbitrary[T7] - t8 <- arbitrary[T8] - } yield (t1,t2,t3,t4,t5,t6,t7,t8)) - - /** Arbitrary instance of 9-tuple */ - implicit def arbTuple9[T1,T2,T3,T4,T5,T6,T7,T8,T9](implicit - a1: Arbitrary[T1], a2: Arbitrary[T2], a3: Arbitrary[T3], a4: Arbitrary[T4], - a5: Arbitrary[T5], a6: Arbitrary[T6], a7: Arbitrary[T7], a8: Arbitrary[T8], - a9: Arbitrary[T9] - ): Arbitrary[(T1,T2,T3,T4,T5,T6,T7,T8,T9)] = - Arbitrary(for { - t1 <- arbitrary[T1] - t2 <- arbitrary[T2] - t3 <- arbitrary[T3] - t4 <- arbitrary[T4] - t5 <- arbitrary[T5] - t6 <- arbitrary[T6] - t7 <- arbitrary[T7] - t8 <- arbitrary[T8] - t9 <- arbitrary[T9] - } yield (t1,t2,t3,t4,t5,t6,t7,t8,t9)) - -} diff --git a/src/scalacheck/org/scalacheck/Arg.scala b/src/scalacheck/org/scalacheck/Arg.scala deleted file mode 100644 index 4961c78a26..0000000000 --- a/src/scalacheck/org/scalacheck/Arg.scala +++ /dev/null @@ -1,20 +0,0 @@ -/*-------------------------------------------------------------------------*\ -** ScalaCheck ** -** Copyright (c) 2007-2013 Rickard Nilsson. All rights reserved. ** -** http://www.scalacheck.org ** -** ** -** This software is released under the terms of the Revised BSD License. ** -** There is NO WARRANTY. See the file LICENSE for the full text. ** -\*------------------------------------------------------------------------ */ - -package org.scalacheck - -case class Arg[+T]( - label: String, - arg: T, - shrinks: Int, - origArg: T -)(implicit prettyPrinter: T => Pretty) { - lazy val prettyArg: Pretty = prettyPrinter(arg) - lazy val prettyOrigArg: Pretty = prettyPrinter(origArg) -} diff --git a/src/scalacheck/org/scalacheck/Commands.scala b/src/scalacheck/org/scalacheck/Commands.scala deleted file mode 100644 index 604b68cb36..0000000000 --- a/src/scalacheck/org/scalacheck/Commands.scala +++ /dev/null @@ -1,148 +0,0 @@ -/*-------------------------------------------------------------------------*\ -** ScalaCheck ** -** Copyright (c) 2007-2013 Rickard Nilsson. All rights reserved. ** -** http://www.scalacheck.org ** -** ** -** This software is released under the terms of the Revised BSD License. ** -** There is NO WARRANTY. See the file LICENSE for the full text. ** -\*------------------------------------------------------------------------ */ - -package org.scalacheck - -import Gen._ -import Prop._ -import Shrink._ - -/** See User Guide for usage examples */ -trait Commands extends Prop { - - /** The abstract state data type. This type must be immutable. - * The state type that encodes the abstract state. The abstract state - * should model all the features we need from the real state, the system - * under test. We should leave out all details that aren't needed for - * specifying our pre- and postconditions. The state type must be called - * State and be immutable. */ - type State <: AnyRef - - class Binding(private val key: State) { - def get: Any = bindings.find(_._1 eq key) match { - case None => sys.error("No value bound") - case Some(x) => x._2 - } - } - - /** Abstract commands are defined as subtypes of the traits Command or SetCommand. - * Each command must have a run method and a method that returns the new abstract - * state, as it should look after the command has been run. - * A command can also define a precondition that states how the current - * abstract state must look if the command should be allowed to run. - * Finally, we can also define a postcondition which verifies that the - * system under test is in a correct state after the command exectution. */ - trait Command { - - /** Used internally. */ - protected[Commands] def run_(s: State) = run(s) - - def run(s: State): Any - def nextState(s: State): State - - /** Returns all preconditions merged into a single function */ - def preCondition: (State => Boolean) = s => preConditions.toList.forall(_.apply(s)) - - /** A precondition is a function that - * takes the current abstract state as parameter and returns a boolean - * that says if the precondition is fulfilled or not. You can add several - * conditions to the precondition list */ - val preConditions = new collection.mutable.ListBuffer[State => Boolean] - - /** Returns all postconditions merged into a single function */ - def postCondition: (State,State,Any) => Prop = (s0,s1,r) => all(postConditions.map(_.apply(s0,s1,r)): _*) - - /** A postcondition is a function that - * takes three parameters, s0, s1 and r. s0 is the abstract state before - * the command was run, s1 is the abstract state after the command was - * run, and r is the result from the command's run - * method. The postcondition function should return a Boolean (or - * a Prop instance) that says if the condition holds or not. You can add several - * conditions to the postConditions list. */ - val postConditions = new collection.mutable.ListBuffer[(State,State,Any) => Prop] - } - - /** A command that binds its result for later use */ - trait SetCommand extends Command { - /** Used internally. */ - protected[Commands] final override def run_(s: State) = { - val r = run(s) - bindings += ((s,r)) - r - } - - final def nextState(s: State) = nextState(s, new Binding(s)) - def nextState(s: State, b: Binding): State - } - - private case class Cmds(cs: List[Command], ss: List[State]) { - override def toString = cs.map(_.toString).mkString(", ") - } - - private val bindings = new scala.collection.mutable.ListBuffer[(State,Any)] - - private def initState() = { - bindings.clear() - initialState() - } - - private def genCmds: Gen[Cmds] = { - def sizedCmds(s: State)(sz: Int): Gen[Cmds] = - if(sz <= 0) value(Cmds(Nil, Nil)) else for { - c <- genCommand(s) suchThat (_.preCondition(s)) - Cmds(cs,ss) <- sizedCmds(c.nextState(s))(sz-1) - } yield Cmds(c::cs, s::ss) - - for { - s0 <- wrap(value(initialState())) - cmds <- sized(sizedCmds(s0)) - } yield cmds - } - - private def validCmds(s: State, cs: List[Command]): Option[Cmds] = - cs match { - case Nil => Some(Cmds(Nil, s::Nil)) - case c::_ if !c.preCondition(s) => None - case c::cmds => for { - Cmds(_, ss) <- validCmds(c.nextState(s), cmds) - } yield Cmds(cs, s::ss) - } - - private def runCommands(cmds: Cmds): Prop = cmds match { - case Cmds(Nil, _) => proved - case Cmds(c::cs, s::ss) => - c.postCondition(s,c.nextState(s),c.run_(s)) && runCommands(Cmds(cs,ss)) - case _ => sys.error("Should not be here") - } - - private def commandsProp: Prop = { - def shrinkCmds(cmds: Cmds) = cmds match { case Cmds(cs,_) => - shrink(cs)(shrinkContainer).flatMap(cs => validCmds(initialState(), cs).toList) - } - - forAllShrink(genCmds label "COMMANDS", shrinkCmds)(runCommands _) - } - - def apply(p: Prop.Params) = commandsProp(p) - - /** initialState should reset the system under test to a well defined - * initial state, and return the abstract version of that state. */ - def initialState(): State - - /** The command generator. Given an abstract state, the generator - * should return a command that is allowed to run in that state. Note that - * it is still neccessary to define preconditions on the commands if there - * are any. The generator is just giving a hint of which commands that are - * suitable for a given state, the preconditions will still be checked before - * a command runs. Sometimes you maybe want to adjust the distribution of - * your command generator according to the state, or do other calculations - * based on the state. */ - def genCommand(s: State): Gen[Command] - -} diff --git a/src/scalacheck/org/scalacheck/ConsoleReporter.scala b/src/scalacheck/org/scalacheck/ConsoleReporter.scala deleted file mode 100644 index d565322d99..0000000000 --- a/src/scalacheck/org/scalacheck/ConsoleReporter.scala +++ /dev/null @@ -1,52 +0,0 @@ -/*-------------------------------------------------------------------------*\ -** ScalaCheck ** -** Copyright (c) 2007-2013 Rickard Nilsson. All rights reserved. ** -** http://www.scalacheck.org ** -** ** -** This software is released under the terms of the Revised BSD License. ** -** There is NO WARRANTY. See the file LICENSE for the full text. ** -\*------------------------------------------------------------------------ */ - -package org.scalacheck - -import Pretty._ -import util.FreqMap - -class ConsoleReporter(val verbosity: Int) extends Test.TestCallback { - - private val prettyPrms = Params(verbosity) - - override def onTestResult(name: String, res: Test.Result) = { - if(verbosity > 0) { - if(name == "") { - val s = (if(res.passed) "+ " else "! ") + pretty(res, prettyPrms) - printf("\r%s\n", format(s, "", "", 75)) - } else { - val s = (if(res.passed) "+ " else "! ") + name + ": " + - pretty(res, prettyPrms) - printf("\r%s\n", format(s, "", "", 75)) - } - } - } - -} - -object ConsoleReporter { - - /** Factory method, creates a ConsoleReporter with the - * the given verbosity */ - def apply(verbosity: Int = 0) = new ConsoleReporter(verbosity) - - def testStatsEx(msg: String, res: Test.Result) = { - lazy val m = if(msg.length == 0) "" else msg + ": " - res.status match { - case Test.Proved(_) => {} - case Test.Passed => {} - case f @ Test.Failed(_, _) => sys.error(m + f) - case Test.Exhausted => {} - case f @ Test.GenException(_) => sys.error(m + f) - case f @ Test.PropException(_, _, _) => sys.error(m + f) - } - } - -} diff --git a/src/scalacheck/org/scalacheck/Gen.scala b/src/scalacheck/org/scalacheck/Gen.scala deleted file mode 100644 index aec67159f1..0000000000 --- a/src/scalacheck/org/scalacheck/Gen.scala +++ /dev/null @@ -1,542 +0,0 @@ -/*-------------------------------------------------------------------------*\ -** ScalaCheck ** -** Copyright (c) 2007-2013 Rickard Nilsson. All rights reserved. ** -** http://www.scalacheck.org ** -** ** -** This software is released under the terms of the Revised BSD License. ** -** There is NO WARRANTY. See the file LICENSE for the full text. ** -\*------------------------------------------------------------------------ */ - -package org.scalacheck - -import scala.collection.mutable.ListBuffer -import util.Buildable -import Prop._ -import Arbitrary._ - -trait Choose[T] { - def choose(min: T, max: T): Gen[T] -} - -object Choose { - import Gen.{fail, parameterized, value} - - implicit val chooseLong: Choose[Long] = new Choose[Long] { - def choose(low: Long, high: Long) = - if (low > high) fail - else parameterized(prms => value(prms.choose(low,high))) - } - - implicit val chooseDouble: Choose[Double] = new Choose[Double] { - def choose(low: Double, high: Double) = - if (low > high || (high-low > Double.MaxValue)) fail - else parameterized(prms => value(prms.choose(low,high))) - } - - implicit val chooseInt: Choose[Int] = new Choose[Int] { - def choose(low: Int, high: Int) = - chooseLong.choose(low, high).map(_.toInt) - } - - implicit val chooseByte: Choose[Byte] = new Choose[Byte] { - def choose(low: Byte, high: Byte) = - chooseLong.choose(low, high).map(_.toByte) - } - - implicit val chooseShort: Choose[Short] = new Choose[Short] { - def choose(low: Short, high: Short) = - chooseLong.choose(low, high).map(_.toShort) - } - - implicit val chooseChar: Choose[Char] = new Choose[Char] { - def choose(low: Char, high: Char) = - chooseLong.choose(low, high).map(_.toChar) - } - - implicit val chooseFloat: Choose[Float] = new Choose[Float] { - def choose(low: Float, high: Float) = - chooseDouble.choose(low, high).map(_.toFloat) - } -} - -case class FiniteGenRes[+T]( - r: T -) - -sealed trait FiniteGen[+T] extends Gen[FiniteGenRes[T]] - - -/** Class that represents a generator. */ -sealed trait Gen[+T] { - - import Gen.choose - - var label = "" // TODO: Ugly mutable field - - /** Put a label on the generator to make test reports clearer */ - def label(l: String): Gen[T] = { - label = l - this - } - - /** Put a label on the generator to make test reports clearer */ - def :|(l: String) = label(l) - - /** Put a label on the generator to make test reports clearer */ - def |:(l: String) = label(l) - - /** Put a label on the generator to make test reports clearer */ - def :|(l: Symbol) = label(l.toString.drop(1)) - - /** Put a label on the generator to make test reports clearer */ - def |:(l: Symbol) = label(l.toString.drop(1)) - - def apply(prms: Gen.Params): Option[T] - - def map[U](f: T => U): Gen[U] = Gen(prms => this(prms).map(f)).label(label) - - def map2[U, V](g: Gen[U])(f: (T, U) => V) = - combine(g)((t, u) => t.flatMap(t => u.flatMap(u => Some(f(t, u))))) - - def map3[U, V, W](gu: Gen[U], gv: Gen[V])(f: (T, U, V) => W) = - combine3(gu, gv)((t, u, v) => t.flatMap(t => u.flatMap(u => v.flatMap(v => Some(f(t, u, v)))))) - - def map4[U, V, W, X](gu: Gen[U], gv: Gen[V], gw: Gen[W])(f: (T, U, V, W) => X) = - combine4(gu, gv, gw)((t, u, v, w) => t.flatMap(t => u.flatMap(u => v.flatMap(v => w.flatMap(w => Some(f(t, u, v, w))))))) - - def map5[U, V, W, X, Y](gu: Gen[U], gv: Gen[V], gw: Gen[W], gx: Gen[X])(f: (T, U, V, W, X) => Y) = - combine5(gu, gv, gw, gx)((t, u, v, w, x) => t.flatMap(t => u.flatMap(u => v.flatMap(v => w.flatMap(w => x.flatMap(x => Some(f(t, u, v, w, x)))))))) - - def map6[U, V, W, X, Y, Z](gu: Gen[U], gv: Gen[V], gw: Gen[W], gx: Gen[X], gy: Gen[Y])(f: (T, U, V, W, X, Y) => Z) = - combine6(gu, gv, gw, gx, gy)((t, u, v, w, x, y) => t.flatMap(t => u.flatMap(u => v.flatMap(v => w.flatMap(w => x.flatMap(x => y.flatMap(y => Some(f(t, u, v, w, x, y))))))))) - - def flatMap[U](f: T => Gen[U]): Gen[U] = Gen(prms => for { - t <- this(prms) - u <- f(t)(prms) - } yield u) - - def filter(p: T => Boolean): Gen[T] = Gen(prms => for { - t <- this(prms) - u <- if (p(t)) Some(t) else None - } yield u).label(label) - - def withFilter(p: T => Boolean) = new GenWithFilter[T](this, p) - - final class GenWithFilter[+A](self: Gen[A], p: A => Boolean) { - def map[B](f: A => B): Gen[B] = self filter p map f - def flatMap[B](f: A => Gen[B]): Gen[B] = self filter p flatMap f - def withFilter(q: A => Boolean): GenWithFilter[A] = new GenWithFilter[A](self, x => p(x) && q(x)) - } - - def suchThat(p: T => Boolean): Gen[T] = filter(p) - - def combine[U,V](g: Gen[U])(f: (Option[T],Option[U]) => Option[V]): Gen[V] = - Gen(prms => f(this(prms), g(prms))) - - def combine3[U, V, W](gu: Gen[U], gv: Gen[V]) - (f: (Option[T], Option[U], Option[V]) => Option[W]) = - Gen(prms => f(this(prms), gu(prms), gv(prms))) - - def combine4[U, V, W, X](gu: Gen[U], gv: Gen[V], gw: Gen[W]) - (f: (Option[T], Option[U], Option[V], Option[W]) => Option[X]) = - Gen(prms => f(this(prms), gu(prms), gv(prms), gw(prms))) - - def combine5[U, V, W, X, Y](gu: Gen[U], gv: Gen[V], gw: Gen[W], gx: Gen[X]) - (f: (Option[T], Option[U], Option[V], Option[W], Option[X]) => Option[Y]) = - Gen(prms => f(this(prms), gu(prms), gv(prms), gw(prms), gx(prms))) - - def combine6[U, V, W, X, Y, Z](gu: Gen[U], gv: Gen[V], gw: Gen[W], gx: Gen[X], gy: Gen[Y]) - (f: (Option[T], Option[U], Option[V], Option[W], Option[X], Option[Y]) => Option[Z]) = - Gen(prms => f(this(prms), gu(prms), gv(prms), gw(prms), gx(prms), gy(prms))) - - def ap[U](g: Gen[T => U]) = flatMap(t => g.flatMap(u => Gen(p => Some(u(t))))) - - override def toString = - if(label.length == 0) "Gen()" else "Gen(\"" + label + "\")" - - /** Returns a new property that holds if and only if both this - * and the given generator generates the same result, or both - * generators generate no result. */ - def ==[U](g: Gen[U]) = Prop(prms => - (this(prms.genPrms), g(prms.genPrms)) match { - case (None,None) => proved(prms) - case (Some(r1),Some(r2)) if r1 == r2 => proved(prms) - case _ => falsified(prms) - } - ) - - def !=[U](g: Gen[U]) = forAll(this)(r => forAll(g)(_ != r)) - - def !==[U](g: Gen[U]) = Prop(prms => - (this(prms.genPrms), g(prms.genPrms)) match { - case (None,None) => falsified(prms) - case (Some(r1),Some(r2)) if r1 == r2 => falsified(prms) - case _ => proved(prms) - } - ) - - private var freq = 1 - def |[U >: T](g: Gen[U]): Gen[U] = { - val h = Gen.frequency((freq, this), (1, g)) - h.freq = freq+1 - h - } - - /** Generates a sample value by using default parameters */ - def sample: Option[T] = apply(Gen.Params()) - -} - - -/** Contains combinators for building generators. */ -object Gen { - - import Arbitrary._ - import Shrink._ - - /** Record that encapsulates all parameters required for data generation */ - case class Params( - size: Int = 100, - rng: java.util.Random = util.StdRand - ) { - def resize(newSize: Int) = this.copy(size = newSize) - - /** @throws IllegalArgumentException if l is greater than h, or if - * the range between l and h doesn't fit in a Long. */ - def choose(l: Long, h: Long): Long = { - if (h < l) throw new IllegalArgumentException("Invalid range") - val d = h - l + 1 - if (d <= 0) { - var n = rng.nextLong - while (n < l || n > h) { - n = rng.nextLong - } - n - } else { - l + math.abs(rng.nextLong % d) - } - } - - /** @throws IllegalArgumentException if l is greater than h, or if - * the range between l and h doesn't fit in a Double. */ - def choose(l: Double, h: Double) = { - val d = h-l - if (d < 0 || d > Double.MaxValue) - throw new IllegalArgumentException("Invalid range") - else if (d == 0) l - else rng.nextDouble * (h-l) + l - } - } - - /* Generator factory method */ - def apply[T](g: Gen.Params => Option[T]) = new Gen[T] { - def apply(p: Gen.Params) = g(p) - } - - /* Convenience method for using the `frequency` method like this: - * {{{ - * frequency((1, "foo"), (3, "bar")) - * }}} - */ - implicit def freqTuple[T](t: (Int, T)): (Int, Gen[T]) = (t._1, value(t._2)) - - - //// Various Generator Combinators //// - - /** Sequences generators. If any of the given generators fails, the - * resulting generator will also fail. */ - def sequence[C[_],T](gs: Iterable[Gen[T]])(implicit b: Buildable[T,C]): Gen[C[T]] = Gen(prms => { - val builder = b.builder - var none = false - val xs = gs.iterator - while(xs.hasNext && !none) xs.next.apply(prms) match { - case None => none = true - case Some(x) => builder += x - } - if(none) None else Some(builder.result()) - }) - - /** Wraps a generator lazily. The given parameter is only evalutated once, - * and not until the wrapper generator is evaluated. */ - def lzy[T](g: => Gen[T]) = new Gen[T] { - lazy val h = g - def apply(prms: Params) = h(prms) - } - - /** Wraps a generator for later evaluation. The given parameter is - * evaluated each time the wrapper generator is evaluated. */ - def wrap[T](g: => Gen[T]) = Gen(p => g(p)) - - /** A generator that always generates the given value */ - implicit def value[T](x: T) = Gen(p => Some(x)) - - /** A generator that never generates a value */ - def fail[T]: Gen[T] = Gen(p => None) - - /** A generator that generates a random value in the given (inclusive) - * range. If the range is invalid, the generator will not generate any value. - */ - def choose[T](min: T, max: T)(implicit c: Choose[T]): Gen[T] = { - c.choose(min, max) - } - - /** Creates a generator that can access its generation parameters */ - def parameterized[T](f: Params => Gen[T]): Gen[T] = Gen(prms => f(prms)(prms)) - - /** Creates a generator that can access its generation size */ - def sized[T](f: Int => Gen[T]) = parameterized(prms => f(prms.size)) - - /** Creates a resized version of a generator */ - def resize[T](s: Int, g: Gen[T]) = Gen(prms => g(prms.resize(s))) - - /** Chooses one of the given generators with a weighted random distribution */ - def frequency[T](gs: (Int,Gen[T])*): Gen[T] = { - lazy val tot = (gs.map(_._1) :\ 0) (_+_) - - def pick(n: Int, l: List[(Int,Gen[T])]): Gen[T] = l match { - case Nil => fail - case (k,g)::gs => if(n <= k) g else pick(n-k, gs) - } - - for { - n <- choose(1,tot) - x <- pick(n,gs.toList) - } yield x - } - - /** Picks a random value from a list */ - def oneOf[T](xs: Seq[T]): Gen[T] = if(xs.isEmpty) fail else for { - i <- choose(0, xs.size-1) - } yield xs(i) - - /** Picks a random generator from a list */ - def oneOf[T](g1: Gen[T], g2: Gen[T], gs: Gen[T]*) = for { - i <- choose(0, gs.length+1) - x <- if(i == 0) g1 else if(i == 1) g2 else gs(i-2) - } yield x - - - //// List Generators //// - - /** Generates a container of any type for which there exists an implicit - * [[org.scalacheck.util.Buildable]] instance. The elements in the container will - * be generated by the given generator. The size of the generated container - * is given by `n`. */ - def containerOfN[C[_],T](n: Int, g: Gen[T])(implicit b: Buildable[T,C] - ): Gen[C[T]] = sequence[C,T](new Iterable[Gen[T]] { - def iterator = new Iterator[Gen[T]] { - var i = 0 - def hasNext = i < n - def next = { i += 1; g } - } - }) - - /** Generates a container of any type for which there exists an implicit - * [[org.scalacheck.util.Buildable]] instance. The elements in the container - * will be generated by the given generator. The size of the container is - * bounded by the size parameter used when generating values. */ - def containerOf[C[_],T](g: Gen[T])(implicit b: Buildable[T,C]): Gen[C[T]] = - sized(size => for(n <- choose(0,size); c <- containerOfN[C,T](n,g)) yield c) - - /** Generates a non-empty container of any type for which there exists an - * implicit [[org.scalacheck.util.Buildable]] instance. The elements in the container - * will be generated by the given generator. The size of the container is - * bounded by the size parameter used when generating values. */ - def containerOf1[C[_],T](g: Gen[T])(implicit b: Buildable[T,C]): Gen[C[T]] = - sized(size => for(n <- choose(1,size); c <- containerOfN[C,T](n,g)) yield c) - - /** Generates a list of random length. The maximum length depends on the - * size parameter. This method is equal to calling - * `containerOf[List,T](g)`. */ - def listOf[T](g: => Gen[T]) = containerOf[List,T](g) - - /** Generates a non-empty list of random length. The maximum length depends - * on the size parameter. This method is equal to calling - * `containerOf1[List,T](g)`. */ - def listOf1[T](g: => Gen[T]) = containerOf1[List,T](g) - - /** Generates a list of the given length. This method is equal to calling - * `containerOfN[List,T](n,g)`. */ - def listOfN[T](n: Int, g: Gen[T]) = containerOfN[List,T](n,g) - - /** A generator that picks a random number of elements from a list */ - def someOf[T](l: Iterable[T]) = choose(0,l.size) flatMap (pick(_,l)) - - /** A generator that picks a random number of elements from a list */ - def someOf[T](g1: Gen[T], g2: Gen[T], gs: Gen[T]*) = for { - n <- choose(0, gs.length+2) - x <- pick(n, g1, g2, gs: _*) - } yield x - - /** A generator that picks a given number of elements from a list, randomly */ - def pick[T](n: Int, l: Iterable[T]): Gen[Seq[T]] = - if(n > l.size || n < 0) fail - else Gen(prms => { - val buf = new ListBuffer[T] - buf ++= l - while(buf.length > n) { - val g = choose(0, buf.length-1) - buf.remove(g(prms).get) - } - Some(buf) - }) - - /** A generator that picks a given number of elements from a list, randomly */ - def pick[T](n: Int, g1: Gen[T], g2: Gen[T], gs: Gen[T]*): Gen[Seq[T]] = for { - is <- pick(n, 0 until (gs.size+2)) - allGs = gs ++ (g1::g2::Nil) - xs <- sequence[List,T](is.toList.map(allGs(_))) - } yield xs - - - //// Character Generators //// - - /* Generates a numerical character */ - def numChar: Gen[Char] = choose(48,57) map (_.toChar) - - /* Generates an upper-case alpha character */ - def alphaUpperChar: Gen[Char] = choose(65,90) map (_.toChar) - - /* Generates a lower-case alpha character */ - def alphaLowerChar: Gen[Char] = choose(97,122) map (_.toChar) - - /* Generates an alpha character */ - def alphaChar = frequency((1,alphaUpperChar), (9,alphaLowerChar)) - - /* Generates an alphanumerical character */ - def alphaNumChar = frequency((1,numChar), (9,alphaChar)) - - //// String Generators //// - - /* Generates a string that starts with a lower-case alpha character, - * and only contains alphanumerical characters */ - def identifier: Gen[String] = for { - c <- alphaLowerChar - cs <- listOf(alphaNumChar) - } yield (c::cs).mkString - - /* Generates a string of alpha characters */ - def alphaStr: Gen[String] = for(cs <- listOf(Gen.alphaChar)) yield cs.mkString - - /* Generates a string of digits */ - def numStr: Gen[String] = for(cs <- listOf(Gen.numChar)) yield cs.mkString - - //// Number Generators //// - - /** Generates positive numbers of uniform distribution, with an - * upper bound of the generation size parameter. */ - def posNum[T](implicit num: Numeric[T], c: Choose[T]): Gen[T] = { - import num._ - sized(max => c.choose(one, fromInt(max))) - } - - /** Generates negative numbers of uniform distribution, with an - * lower bound of the negated generation size parameter. */ - def negNum[T](implicit num: Numeric[T], c: Choose[T]): Gen[T] = { - import num._ - sized(max => c.choose(-fromInt(max), -one)) - } - - /** Generates numbers within the given inclusive range, with - * extra weight on zero, +/- unity, both extremities, and any special - * numbers provided. The special numbers must lie within the given range, - * otherwise they won't be included. */ - def chooseNum[T](minT: T, maxT: T, specials: T*)( - implicit num: Numeric[T], c: Choose[T] - ): Gen[T] = { - import num._ - val basics = List(minT, maxT, zero, one, -one) - val basicsAndSpecials = for { - t <- specials ++ basics if t >= minT && t <= maxT - } yield (1, value(t)) - val allGens = basicsAndSpecials ++ List( - (basicsAndSpecials.length, c.choose(minT, maxT)) - ) - frequency(allGens: _*) - } - - /** Takes a function and returns a generator that generates arbitrary - * results of that function by feeding it with arbitrarily generated input - * parameters. */ - def resultOf[T,R](f: T => R)(implicit a: Arbitrary[T]): Gen[R] = - arbitrary[T] map f - - /** Takes a function and returns a generator that generates arbitrary - * results of that function by feeding it with arbitrarily generated input - * parameters. */ - def resultOf[T1,T2,R](f: (T1,T2) => R)(implicit - a1: Arbitrary[T1], a2: Arbitrary[T2] - ): Gen[R] = arbitrary[T1] flatMap { t => resultOf(f(t, _:T2)) } - - /** Takes a function and returns a generator that generates arbitrary - * results of that function by feeding it with arbitrarily generated input - * parameters. */ - def resultOf[T1,T2,T3,R](f: (T1,T2,T3) => R)(implicit - a1: Arbitrary[T1], a2: Arbitrary[T2], a3: Arbitrary[T3] - ): Gen[R] = arbitrary[T1] flatMap { t => resultOf(f(t, _:T2, _:T3)) } - - /** Takes a function and returns a generator that generates arbitrary - * results of that function by feeding it with arbitrarily generated input - * parameters. */ - def resultOf[T1,T2,T3,T4,R](f: (T1,T2,T3,T4) => R)(implicit - a1: Arbitrary[T1], a2: Arbitrary[T2], a3: Arbitrary[T3], a4: Arbitrary[T4] - ): Gen[R] = arbitrary[T1] flatMap { - t => resultOf(f(t, _:T2, _:T3, _:T4)) - } - - /** Takes a function and returns a generator that generates arbitrary - * results of that function by feeding it with arbitrarily generated input - * parameters. */ - def resultOf[T1,T2,T3,T4,T5,R](f: (T1,T2,T3,T4,T5) => R)(implicit - a1: Arbitrary[T1], a2: Arbitrary[T2], a3: Arbitrary[T3], a4: Arbitrary[T4], - a5: Arbitrary[T5] - ): Gen[R] = arbitrary[T1] flatMap { - t => resultOf(f(t, _:T2, _:T3, _:T4, _:T5)) - } - - /** Takes a function and returns a generator that generates arbitrary - * results of that function by feeding it with arbitrarily generated input - * parameters. */ - def resultOf[T1,T2,T3,T4,T5,T6,R]( - f: (T1,T2,T3,T4,T5,T6) => R)(implicit - a1: Arbitrary[T1], a2: Arbitrary[T2], a3: Arbitrary[T3], - a4: Arbitrary[T4], a5: Arbitrary[T5], a6: Arbitrary[T6] - ): Gen[R] = arbitrary[T1] flatMap { - t => resultOf(f(t, _:T2, _:T3, _:T4, _:T5, _:T6)) - } - - /** Takes a function and returns a generator that generates arbitrary - * results of that function by feeding it with arbitrarily generated input - * parameters. */ - def resultOf[T1,T2,T3,T4,T5,T6,T7,R]( - f: (T1,T2,T3,T4,T5,T6,T7) => R)(implicit - a1: Arbitrary[T1], a2: Arbitrary[T2], a3: Arbitrary[T3], - a4: Arbitrary[T4], a5: Arbitrary[T5], a6: Arbitrary[T6], a7: Arbitrary[T7] - ): Gen[R] = arbitrary[T1] flatMap { - t => resultOf(f(t, _:T2, _:T3, _:T4, _:T5, _:T6, _:T7)) - } - - /** Takes a function and returns a generator that generates arbitrary - * results of that function by feeding it with arbitrarily generated input - * parameters. */ - def resultOf[T1,T2,T3,T4,T5,T6,T7,T8,R]( - f: (T1,T2,T3,T4,T5,T6,T7,T8) => R)(implicit - a1: Arbitrary[T1], a2: Arbitrary[T2], a3: Arbitrary[T3], a4: Arbitrary[T4], - a5: Arbitrary[T5], a6: Arbitrary[T6], a7: Arbitrary[T7], a8: Arbitrary[T8] - ): Gen[R] = arbitrary[T1] flatMap { - t => resultOf(f(t, _:T2, _:T3, _:T4, _:T5, _:T6, _:T7, _:T8)) - } - - /** Takes a function and returns a generator that generates arbitrary - * results of that function by feeding it with arbitrarily generated input - * parameters. */ - def resultOf[T1,T2,T3,T4,T5,T6,T7,T8,T9,R]( - f: (T1,T2,T3,T4,T5,T6,T7,T8,T9) => R)(implicit - a1: Arbitrary[T1], a2: Arbitrary[T2], a3: Arbitrary[T3], a4: Arbitrary[T4], - a5: Arbitrary[T5], a6: Arbitrary[T6], a7: Arbitrary[T7], a8: Arbitrary[T8], - a9: Arbitrary[T9] - ): Gen[R] = arbitrary[T1] flatMap { - t => resultOf(f(t, _:T2, _:T3, _:T4, _:T5, _:T6, _:T7, _:T8, _:T9)) - } - -} diff --git a/src/scalacheck/org/scalacheck/Pretty.scala b/src/scalacheck/org/scalacheck/Pretty.scala deleted file mode 100644 index 3e8f6de5f6..0000000000 --- a/src/scalacheck/org/scalacheck/Pretty.scala +++ /dev/null @@ -1,127 +0,0 @@ -/*-------------------------------------------------------------------------*\ -** ScalaCheck ** -** Copyright (c) 2007-2013 Rickard Nilsson. All rights reserved. ** -** http://www.scalacheck.org ** -** ** -** This software is released under the terms of the Revised BSD License. ** -** There is NO WARRANTY. See the file LICENSE for the full text. ** -\*------------------------------------------------------------------------ */ - -package org.scalacheck - -import math.round - - -sealed trait Pretty { - def apply(prms: Pretty.Params): String - - def map(f: String => String) = Pretty(prms => f(Pretty.this(prms))) - - def flatMap(f: String => Pretty) = Pretty(prms => f(Pretty.this(prms))(prms)) -} - -object Pretty { - - case class Params(verbosity: Int) - - val defaultParams = Params(0) - - def apply(f: Params => String) = new Pretty { def apply(p: Params) = f(p) } - - def pretty[T <% Pretty](t: T, prms: Params): String = t(prms) - - def pretty[T <% Pretty](t: T): String = t(defaultParams) - - implicit def strBreak(s1: String) = new { - def /(s2: String) = if(s2 == "") s1 else s1+"\n"+s2 - } - - def pad(s: String, c: Char, length: Int) = - if(s.length >= length) s - else s + List.fill(length-s.length)(c).mkString - - def break(s: String, lead: String, length: Int): String = - if(s.length <= length) s - else s.substring(0, length) / break(lead+s.substring(length), lead, length) - - def format(s: String, lead: String, trail: String, width: Int) = - s.lines.map(l => break(lead+l+trail, " ", width)).mkString("\n") - - implicit def prettyAny(t: Any) = Pretty { p => t.toString } - - implicit def prettyString(t: String) = Pretty { p => "\""++t++"\"" } - - implicit def prettyList(l: List[Any]) = Pretty { p => - l.map("\""+_+"\"").mkString("List(", ", ", ")") - } - - implicit def prettyThrowable(e: Throwable) = Pretty { prms => - val strs = e.getStackTrace.map { st => - import st._ - getClassName+"."+getMethodName + "("+getFileName+":"+getLineNumber+")" - } - - val strs2 = - if(prms.verbosity <= 0) Array[String]() - else if(prms.verbosity <= 1) strs.take(5) - else strs - - e.getClass.getName + ": " + e.getMessage / strs2.mkString("\n") - } - - implicit def prettyArgs(args: List[Arg[Any]]): Pretty = Pretty { prms => - if(args.isEmpty) "" else { - for((a,i) <- args.zipWithIndex) yield { - val l = if(a.label == "") "ARG_"+i else a.label - val s = - if(a.shrinks == 0 || prms.verbosity <= 1) "" - else " (orig arg: "+a.prettyOrigArg(prms)+")" - - "> "+l+": "+a.prettyArg(prms)+""+s - } - }.mkString("\n") - } - - implicit def prettyFreqMap(fm: Prop.FM) = Pretty { prms => - if(fm.total == 0) "" - else { - "> Collected test data: " / { - for { - (xs,r) <- fm.getRatios - ys = xs - () - if !ys.isEmpty - } yield round(r*100)+"% " + ys.mkString(", ") - }.mkString("\n") - } - } - - implicit def prettyTestRes(res: Test.Result) = Pretty { prms => - def labels(ls: collection.immutable.Set[String]) = - if(ls.isEmpty) "" - else "> Labels of failing property: " / ls.mkString("\n") - val s = res.status match { - case Test.Proved(args) => "OK, proved property."/pretty(args,prms) - case Test.Passed => "OK, passed "+res.succeeded+" tests." - case Test.Failed(args, l) => - "Falsified after "+res.succeeded+" passed tests."/labels(l)/pretty(args,prms) - case Test.Exhausted => - "Gave up after only "+res.succeeded+" passed tests. " + - res.discarded+" tests were discarded." - case Test.PropException(args,e,l) => - "Exception raised on property evaluation."/labels(l)/pretty(args,prms)/ - "> Exception: "+pretty(e,prms) - case Test.GenException(e) => - "Exception raised on argument generation."/ - "> Exception: "+pretty(e,prms) - } - val t = if(prms.verbosity <= 1) "" else "Elapsed time: "+prettyTime(res.time) - s/t/pretty(res.freqMap,prms) - } - - def prettyTime(millis: Long): String = { - val min = millis/(60*1000) - val sec = (millis-(60*1000*min)) / 1000d - if(min <= 0) "%.3f sec ".format(sec) - else "%d min %.3f sec ".format(min, sec) - } -} diff --git a/src/scalacheck/org/scalacheck/Prop.scala b/src/scalacheck/org/scalacheck/Prop.scala deleted file mode 100644 index 38e00f260f..0000000000 --- a/src/scalacheck/org/scalacheck/Prop.scala +++ /dev/null @@ -1,818 +0,0 @@ -/*-------------------------------------------------------------------------*\ -** ScalaCheck ** -** Copyright (c) 2007-2013 Rickard Nilsson. All rights reserved. ** -** http://www.scalacheck.org ** -** ** -** This software is released under the terms of the Revised BSD License. ** -** There is NO WARRANTY. See the file LICENSE for the full text. ** -\*------------------------------------------------------------------------ */ - -package org.scalacheck - -import util.{FreqMap,Buildable} -import scala.collection._ -import scala.annotation.tailrec - -/** A property is a generator that generates a property result */ -trait Prop { - - import Prop.{Result,Params,Proof,True,False,Exception,Undecided,provedToTrue} - import Test.cmdLineParser.{Success, NoSuccess} - import Result.merge - - def apply(prms: Params): Result - - def map(f: Result => Result): Prop = Prop(prms => f(this(prms))) - - def flatMap(f: Result => Prop): Prop = Prop(prms => f(this(prms))(prms)) - - def combine(p: Prop)(f: (Result, Result) => Result) = - for(r1 <- this; r2 <- p) yield f(r1,r2) - - /** Convenience method that checks this property with the given parameters - * and reports the result on the console. If you need to get the results - * from the test use the `check` methods in [[org.scalacheck.Test]] - * instead. - * @deprecated (in 1.10.0) Use `check(Test.Parameters)` instead. - */ - @deprecated("Use 'check(Test.Parameters)' instead", "1.10.0") - def check(prms: Test.Params): Unit = Test.check( - prms copy (testCallback = ConsoleReporter(1) chain prms.testCallback), this - ) - - /** Convenience method that checks this property with the given parameters - * and reports the result on the console. If you need to get the results - * from the test use the `check` methods in [[org.scalacheck.Test]] - * instead. */ - def check(prms: Test.Parameters): Unit = Test.check( - prms copy (_testCallback = ConsoleReporter(1) chain prms.testCallback), this - ) - - /** Convenience method that checks this property and reports the - * result on the console. If you need to get the results from the test use - * the `check` methods in [[org.scalacheck.Test]] instead. */ - def check: Unit = check(Test.Parameters.default) - - /** The logic for main, separated out to make it easier to - * avoid System.exit calls. Returns exit code. - */ - def mainRunner(args: Array[String]): Int = { - Test.cmdLineParser.parseParams(args) match { - case Success(params, _) => - if (Test.check(params, this).passed) 0 - else 1 - case e: NoSuccess => - println("Incorrect options:"+"\n"+e+"\n") - Test.cmdLineParser.printHelp - -1 - } - } - - /** Whether main should call System.exit with an exit code. - * Defaults to true; override to change. - */ - def mainCallsExit = true - - /** Convenience method that makes it possible to use this property - * as an application that checks itself on execution */ - def main(args: Array[String]): Unit = { - val code = mainRunner(args) - if (mainCallsExit) - System exit code - } - - /** Returns a new property that holds if and only if both this - * and the given property hold. If one of the properties doesn't - * generate a result, the new property will generate false. */ - def &&(p: Prop) = combine(p)(_ && _) - - /** Returns a new property that holds if either this - * or the given property (or both) hold. */ - def ||(p: Prop) = combine(p)(_ || _) - - /** Returns a new property that holds if and only if both this - * and the given property hold. If one of the properties doesn't - * generate a result, the new property will generate the same result - * as the other property. */ - def ++(p: Prop): Prop = combine(p)(_ ++ _) - - /** Combines two properties through implication */ - def ==>(p: => Prop): Prop = flatMap { r1 => - if(r1.proved) p map { r2 => merge(r1,r2,r2.status) } - else if(r1.success) p map { r2 => provedToTrue(merge(r1,r2,r2.status)) } - else Prop(r1.copy(status = Undecided)) - } - - /** Returns a new property that holds if and only if both this - * and the given property generates a result with the exact - * same status. Note that this means that if one of the properties is - * proved, and the other one passed, then the resulting property - * will fail. */ - def ==(p: Prop) = this.flatMap { r1 => - p.map { r2 => - Result.merge(r1, r2, if(r1.status == r2.status) True else False) - } - } - - override def toString = "Prop" - - /** Put a label on the property to make test reports clearer */ - def label(l: String) = map(_.label(l)) - - /** Put a label on the property to make test reports clearer */ - def :|(l: String) = label(l) - - /** Put a label on the property to make test reports clearer */ - def |:(l: String) = label(l) - - /** Put a label on the property to make test reports clearer */ - def :|(l: Symbol) = label(l.toString.drop(1)) - - /** Put a label on the property to make test reports clearer */ - def |:(l: Symbol) = label(l.toString.drop(1)) - -} - -object Prop { - - import Gen.{value, fail, frequency, oneOf} - import Arbitrary._ - import Shrink._ - - - // Types - - type Args = List[Arg[Any]] - type FM = FreqMap[immutable.Set[Any]] - - /** Property parameters */ - case class Params(val genPrms: Gen.Params, val freqMap: FM) - - object Result { - def apply(st: Status) = new Result( - st, - Nil, - immutable.Set.empty[Any], - immutable.Set.empty[String] - ) - - def merge(x: Result, y: Result, status: Status) = new Result( - status, - x.args ++ y.args, - (x.collected.asInstanceOf[Set[AnyRef]] ++ y.collected).asInstanceOf[immutable.Set[Any]], - x.labels ++ y.labels - ) - } - - /** The result of evaluating a property */ - case class Result( - status: Status, - args: Args, - collected: immutable.Set[Any], - labels: immutable.Set[String] - ) { - def success = status match { - case True => true - case Proof => true - case _ => false - } - - def failure = status match { - case False => true - case Exception(_) => true - case _ => false - } - - def proved = status == Proof - - def addArg(a: Arg[Any]) = copy(args = a::args) - - def collect(x: Any) = copy(collected = collected+x) - - def label(l: String) = copy(labels = labels+l) - - import Result.merge - - def &&(r: Result) = (this.status, r.status) match { - case (Exception(_),_) => this - case (_,Exception(_)) => r - - case (False,_) => this - case (_,False) => r - - case (Undecided,_) => this - case (_,Undecided) => r - - case (_,Proof) => merge(this, r, this.status) - case (Proof,_) => merge(this, r, r.status) - - case (True,True) => merge(this, r, True) - } - - def ||(r: Result) = (this.status, r.status) match { - case (Exception(_),_) => this - case (_,Exception(_)) => r - - case (False,False) => merge(this, r, False) - case (False,_) => r - case (_,False) => this - - case (Proof,_) => this - case (_,Proof) => r - - case (True,_) => this - case (_,True) => r - - case (Undecided,Undecided) => merge(this, r, Undecided) - } - - def ++(r: Result) = (this.status, r.status) match { - case (Exception(_),_) => this - case (_,Exception(_)) => r - - case (_, Undecided) => this - case (Undecided, _) => r - - case (_, Proof) => this - case (Proof, _) => r - - case (_, True) => this - case (True, _) => r - - case (False, _) => this - case (_, False) => r - } - - def ==>(r: Result) = (this.status, r.status) match { - case (Exception(_),_) => this - case (_,Exception(_)) => r - - case (False,_) => merge(this, r, Undecided) - - case (Undecided,_) => this - - case (Proof,_) => merge(this, r, r.status) - case (True,_) => merge(this, r, r.status) - } - - } - - sealed trait Status - - /** The property was proved */ - case object Proof extends Status - - /** The property was true */ - case object True extends Status - - /** The property was false */ - case object False extends Status - - /** The property could not be falsified or proved */ - case object Undecided extends Status - - /** Evaluating the property raised an exception */ - sealed case class Exception(e: Throwable) extends Status { - override def equals(o: Any) = o match { - case Exception(_) => true - case _ => false - } - } - - def apply(f: Params => Result): Prop = new Prop { - def apply(prms: Params) = f(prms) - } - - def apply(r: Result): Prop = Prop(prms => r) - - def apply(b: Boolean): Prop = if(b) proved else falsified - - - // Implicits - - /** A collection of property operators on [[Any]] values. - * Import [[Prop.AnyOperators]] to make the operators available. */ - class ExtendedAny[T <% Pretty](x: => T) { - /** See [[Prop.imply]] */ - def imply(f: PartialFunction[T,Prop]) = Prop.imply(x,f) - /** See [[Prop.iff]] */ - def iff(f: PartialFunction[T,Prop]) = Prop.iff(x,f) - @deprecated("Use 'Prop.throws' instead", "1.10.1") - def throws[U <: Throwable](c: Class[U]): Prop = Prop.throws(c)(x) - /** See [[Prop.?=]] */ - def ?=(y: T) = Prop.?=(x, y) - /** See [[Prop.=?]] */ - def =?(y: T) = Prop.=?(x, y) - } - - /** A collection of property operators on [[Boolean]] values. - * Import [[Prop.BooleanOperators]] to make the operators available. */ - class ExtendedBoolean(b: => Boolean) { - /** See [[Prop.==>]] */ - def ==>(p: => Prop) = Prop(b) ==> p - } - - /** Implicit method that makes a number of property operators on values of - * type [[Any]] available in the current scope. See [[Prop.ExtendedAny]] for - * documentation on the operators. */ - @deprecated("Use 'Prop.AnyOperators' instead", "1.10.1") - implicit def extendedAny[T <% Pretty](x: => T) = new ExtendedAny[T](x) - - /** Implicit method that makes a number of property operators on values of - * type [[Any]] available in the current scope. See [[Prop.ExtendedAny]] for - * documentation on the operators. */ - implicit def AnyOperators[T <% Pretty](x: => T) = new ExtendedAny[T](x) - - /** Implicit method that makes a number of property operators on boolean - * values available in the current scope. See [[Prop.ExtendedBoolean]] for - * documentation on the operators. */ - implicit def BooleanOperators(b: => Boolean) = new ExtendedBoolean(b) - - /** Implicit conversion of Boolean values to Prop values. */ - implicit def propBoolean(b: Boolean): Prop = Prop(b) - - - // Private support functions - - private def provedToTrue(r: Result) = r.status match { - case Proof => new Result(True, r.args, r.collected, r.labels) - case _ => r - } - - - // Property combinators - - /** A property that never is proved or falsified */ - lazy val undecided = Prop(Result(Undecided)) - - /** A property that always is false */ - lazy val falsified = Prop(Result(False)) - - /** A property that always is proved */ - lazy val proved = Prop(Result(Proof)) - - /** A property that always is passed */ - lazy val passed = Prop(Result(True)) - - /** A property that denotes an exception */ - def exception(e: Throwable): Prop = Prop(Result(Exception(e))) - - /** A property that denotes an exception */ - lazy val exception: Prop = exception(null) - - /** Create a property that compares to values. If the values aren't equal, - * the property will fail and report that first value doesn't match the - * expected (second) value. */ - def ?=[T](x: T, y: T)(implicit pp: T => Pretty): Prop = - if(x == y) proved else falsified :| { - val exp = Pretty.pretty[T](y, Pretty.Params(0)) - val act = Pretty.pretty[T](x, Pretty.Params(0)) - "Expected "+exp+" but got "+act - } - - /** Create a property that compares to values. If the values aren't equal, - * the property will fail and report that second value doesn't match the - * expected (first) value. */ - def =?[T](x: T, y: T)(implicit pp: T => Pretty): Prop = ?=(y, x) - - /** A property that depends on the generator size */ - def sizedProp(f: Int => Prop): Prop = Prop { prms => - // provedToTrue since if the property is proved for - // one size, it shouldn't be regarded as proved for - // all sizes. - provedToTrue(f(prms.genPrms.size)(prms)) - } - - /** Implication with several conditions */ - def imply[T](x: T, f: PartialFunction[T,Prop]): Prop = - secure(if(f.isDefinedAt(x)) f(x) else undecided) - - /** Property holds only if the given partial function is defined at - * `x`, and returns a property that holds */ - def iff[T](x: T, f: PartialFunction[T,Prop]): Prop = - secure(if(f.isDefinedAt(x)) f(x) else falsified) - - /** Combines properties into one, which is true if and only if all the - * properties are true */ - def all(ps: Prop*) = if(ps.isEmpty) proved else Prop(prms => - ps.map(p => p(prms)).reduceLeft(_ && _) - ) - - /** Combines properties into one, which is true if at least one of the - * properties is true */ - def atLeastOne(ps: Prop*) = if(ps.isEmpty) falsified else Prop(prms => - ps.map(p => p(prms)).reduceLeft(_ || _) - ) - - /** A property that holds if at least one of the given generators - * fails generating a value */ - def someFailing[T](gs: Seq[Gen[T]]) = atLeastOne(gs.map(_ == fail):_*) - - /** A property that holds iff none of the given generators - * fails generating a value */ - def noneFailing[T](gs: Seq[Gen[T]]) = all(gs.map(_ !== fail):_*) - - /** A property that holds if the given statement throws an exception - * of the specified type - * @deprecated (in 1.10.1) Use `throws(...): Boolean` instead. - */ - @deprecated("Use 'throws(...): Boolean' instead", "1.10.1") - def throws[T <: Throwable](x: => Any, c: Class[T]): Prop = throws(c)(x) - - /** Returns true if the given statement throws an exception - * of the specified type */ - def throws[T <: Throwable](c: Class[T])(x: => Any): Boolean = - try { x; false } catch { case e if c.isInstance(e) => true } - - /** Collect data for presentation in test report */ - def collect[T, P <% Prop](f: T => P): T => Prop = t => Prop { prms => - val prop = f(t) - prop(prms).collect(t) - } - - /** Collect data for presentation in test report */ - def collect[T](t: T)(prop: Prop) = Prop { prms => - prop(prms).collect(t) - } - - /** Collect data for presentation in test report */ - def classify(c: => Boolean, ifTrue: Any)(prop: Prop): Prop = - if(c) collect(ifTrue)(prop) else collect(())(prop) - - /** Collect data for presentation in test report */ - def classify(c: => Boolean, ifTrue: Any, ifFalse: Any)(prop: Prop): Prop = - if(c) collect(ifTrue)(prop) else collect(ifFalse)(prop) - - /** Wraps and protects a property */ - def secure[P <% Prop](p: => P): Prop = - try { p: Prop } catch { case e: Throwable => exception(e) } - - /** Existential quantifier for an explicit generator. */ - def exists[A,P](f: A => P)(implicit - pv: P => Prop, - pp: A => Pretty, - aa: Arbitrary[A] - ): Prop = exists(aa.arbitrary)(f) - - /** Existential quantifier for an explicit generator. */ - def exists[A,P](g: Gen[A])(f: A => P)(implicit - pv: P => Prop, - pp: A => Pretty - ): Prop = Prop { prms => - g(prms.genPrms) match { - case None => undecided(prms) - case Some(x) => - val p = secure(f(x)) - val r = p(prms).addArg(Arg(g.label,x,0,x)) - r.status match { - case True => new Result(Proof, r.args, r.collected, r.labels) - case False => new Result(Undecided, r.args, r.collected, r.labels) - case _ => r - } - } - } - - /** Universal quantifier for an explicit generator. Does not shrink failed - * test cases. */ - def forAllNoShrink[T1,P]( - g1: Gen[T1])( - f: T1 => P)(implicit - pv: P => Prop, - pp1: T1 => Pretty - ): Prop = Prop { prms => - g1(prms.genPrms) match { - case None => undecided(prms) - case Some(x) => - val p = secure(f(x)) - provedToTrue(p(prms)).addArg(Arg(g1.label,x,0,x)) - } - } - - /** Universal quantifier for two explicit generators. - * Does not shrink failed test cases. */ - def forAllNoShrink[T1,T2,P]( - g1: Gen[T1], g2: Gen[T2])( - f: (T1,T2) => P)(implicit - p: P => Prop, - pp1: T1 => Pretty, - pp2: T2 => Pretty - ): Prop = forAllNoShrink(g1)(t => forAllNoShrink(g2)(f(t, _:T2))) - - /** Universal quantifier for three explicit generators. - * Does not shrink failed test cases. */ - def forAllNoShrink[T1,T2,T3,P]( - g1: Gen[T1], g2: Gen[T2], g3: Gen[T3])( - f: (T1,T2,T3) => P)(implicit - p: P => Prop, - pp1: T1 => Pretty, - pp2: T2 => Pretty, - pp3: T3 => Pretty - ): Prop = forAllNoShrink(g1)(t => forAllNoShrink(g2,g3)(f(t, _:T2, _:T3))) - - /** Universal quantifier for four explicit generators. - * Does not shrink failed test cases. */ - def forAllNoShrink[T1,T2,T3,T4,P]( - g1: Gen[T1], g2: Gen[T2], g3: Gen[T3], g4: Gen[T4])( - f: (T1,T2,T3,T4) => P)(implicit - p: P => Prop, - pp1: T1 => Pretty, - pp2: T2 => Pretty, - pp3: T3 => Pretty, - pp4: T4 => Pretty - ): Prop = forAllNoShrink(g1)(t => forAllNoShrink(g2,g3,g4)(f(t, _:T2, _:T3, _:T4))) - - /** Universal quantifier for five explicit generators. - * Does not shrink failed test cases. */ - def forAllNoShrink[T1,T2,T3,T4,T5,P]( - g1: Gen[T1], g2: Gen[T2], g3: Gen[T3], g4: Gen[T4], g5: Gen[T5])( - f: (T1,T2,T3,T4,T5) => P)(implicit - p: P => Prop, - pp1: T1 => Pretty, - pp2: T2 => Pretty, - pp3: T3 => Pretty, - pp4: T4 => Pretty, - pp5: T5 => Pretty - ): Prop = forAllNoShrink(g1)(t => forAllNoShrink(g2,g3,g4,g5)(f(t, _:T2, _:T3, _:T4, _:T5))) - - /** Universal quantifier for six explicit generators. - * Does not shrink failed test cases. */ - def forAllNoShrink[T1,T2,T3,T4,T5,T6,P]( - g1: Gen[T1], g2: Gen[T2], g3: Gen[T3], g4: Gen[T4], g5: Gen[T5], g6: Gen[T6])( - f: (T1,T2,T3,T4,T5,T6) => P)(implicit - p: P => Prop, - pp1: T1 => Pretty, - pp2: T2 => Pretty, - pp3: T3 => Pretty, - pp4: T4 => Pretty, - pp5: T5 => Pretty, - pp6: T6 => Pretty - ): Prop = forAllNoShrink(g1)(t => forAllNoShrink(g2,g3,g4,g5,g6)(f(t, _:T2, _:T3, _:T4, _:T5, _:T6))) - - /** Universal quantifier for seven explicit generators. - * Does not shrink failed test cases. */ - def forAllNoShrink[T1,T2,T3,T4,T5,T6,T7,P]( - g1: Gen[T1], g2: Gen[T2], g3: Gen[T3], g4: Gen[T4], g5: Gen[T5], g6: Gen[T6], g7: Gen[T7])( - f: (T1,T2,T3,T4,T5,T6,T7) => P)(implicit - p: P => Prop, - pp1: T1 => Pretty, - pp2: T2 => Pretty, - pp3: T3 => Pretty, - pp4: T4 => Pretty, - pp5: T5 => Pretty, - pp6: T6 => Pretty, - pp7: T7 => Pretty - ): Prop = forAllNoShrink(g1)(t => forAllNoShrink(g2,g3,g4,g5,g6,g7)(f(t, _:T2, _:T3, _:T4, _:T5, _:T6, _:T7))) - - /** Universal quantifier for eight explicit generators. - * Does not shrink failed test cases. */ - def forAllNoShrink[T1,T2,T3,T4,T5,T6,T7,T8,P]( - g1: Gen[T1], g2: Gen[T2], g3: Gen[T3], g4: Gen[T4], g5: Gen[T5], g6: Gen[T6], g7: Gen[T7], g8: Gen[T8])( - f: (T1,T2,T3,T4,T5,T6,T7,T8) => P)(implicit - p: P => Prop, - pp1: T1 => Pretty, - pp2: T2 => Pretty, - pp3: T3 => Pretty, - pp4: T4 => Pretty, - pp5: T5 => Pretty, - pp6: T6 => Pretty, - pp7: T7 => Pretty, - pp8: T8 => Pretty - ): Prop = forAllNoShrink(g1)(t => forAllNoShrink(g2,g3,g4,g5,g6,g7,g8)(f(t, _:T2, _:T3, _:T4, _:T5, _:T6, _:T7, _:T8))) - - /** Universal quantifier for an explicit generator. Shrinks failed arguments - * with the given shrink function */ - def forAllShrink[T <% Pretty, P <% Prop](g: Gen[T], - shrink: T => Stream[T])(f: T => P - ): Prop = Prop { prms => - - /** Returns the first failed result in Left or success in Right */ - def getFirstFailure(xs: Stream[T]): Either[(T,Result),(T,Result)] = { - assert(!xs.isEmpty, "Stream cannot be empty") - val results = xs.map { x => - val p = secure(f(x)) - (x, provedToTrue(p(prms))) - } - results.dropWhile(!_._2.failure).headOption match { - case None => Right(results.head) - case Some(xr) => Left(xr) - } - } - - def shrinker(x: T, r: Result, shrinks: Int, orig: T): Result = { - val xs = shrink(x) - val res = r.addArg(Arg(g.label,x,shrinks,orig)) - if(xs.isEmpty) res else getFirstFailure(xs) match { - case Right(_) => res - case Left((x2,r2)) => shrinker(x2, r2, shrinks+1, orig) - } - } - - g(prms.genPrms) match { - case None => undecided(prms) - case Some(x) => getFirstFailure(Stream.cons(x, Stream.empty)) match { - case Right((x,r)) => r.addArg(Arg(g.label,x,0,x)) - case Left((x,r)) => shrinker(x,r,0,x) - } - } - - } - - /** Universal quantifier for an explicit generator. Shrinks failed arguments - * with the default shrink function for the type */ - def forAll[T1,P]( - g1: Gen[T1])( - f: T1 => P)(implicit - p: P => Prop, - s1: Shrink[T1], - pp1: T1 => Pretty - ): Prop = forAllShrink(g1, shrink[T1])(f) - - /** Universal quantifier for two explicit generators. Shrinks failed arguments - * with the default shrink function for the type */ - def forAll[T1,T2,P]( - g1: Gen[T1], g2: Gen[T2])( - f: (T1,T2) => P)(implicit - p: P => Prop, - s1: Shrink[T1], pp1: T1 => Pretty, - s2: Shrink[T2], pp2: T2 => Pretty - ): Prop = forAll(g1)(t => forAll(g2)(f(t, _:T2))) - - /** Universal quantifier for three explicit generators. Shrinks failed arguments - * with the default shrink function for the type */ - def forAll[T1,T2,T3,P]( - g1: Gen[T1], g2: Gen[T2], g3: Gen[T3])( - f: (T1,T2,T3) => P)(implicit - p: P => Prop, - s1: Shrink[T1], pp1: T1 => Pretty, - s2: Shrink[T2], pp2: T2 => Pretty, - s3: Shrink[T3], pp3: T3 => Pretty - ): Prop = forAll(g1)(t => forAll(g2,g3)(f(t, _:T2, _:T3))) - - /** Universal quantifier for four explicit generators. Shrinks failed arguments - * with the default shrink function for the type */ - def forAll[T1,T2,T3,T4,P]( - g1: Gen[T1], g2: Gen[T2], g3: Gen[T3], g4: Gen[T4])( - f: (T1,T2,T3,T4) => P)(implicit - p: P => Prop, - s1: Shrink[T1], pp1: T1 => Pretty, - s2: Shrink[T2], pp2: T2 => Pretty, - s3: Shrink[T3], pp3: T3 => Pretty, - s4: Shrink[T4], pp4: T4 => Pretty - ): Prop = forAll(g1)(t => forAll(g2,g3,g4)(f(t, _:T2, _:T3, _:T4))) - - /** Universal quantifier for five explicit generators. Shrinks failed arguments - * with the default shrink function for the type */ - def forAll[T1,T2,T3,T4,T5,P]( - g1: Gen[T1], g2: Gen[T2], g3: Gen[T3], g4: Gen[T4], g5: Gen[T5])( - f: (T1,T2,T3,T4,T5) => P)(implicit - p: P => Prop, - s1: Shrink[T1], pp1: T1 => Pretty, - s2: Shrink[T2], pp2: T2 => Pretty, - s3: Shrink[T3], pp3: T3 => Pretty, - s4: Shrink[T4], pp4: T4 => Pretty, - s5: Shrink[T5], pp5: T5 => Pretty - ): Prop = forAll(g1)(t => forAll(g2,g3,g4,g5)(f(t, _:T2, _:T3, _:T4, _:T5))) - - /** Universal quantifier for six explicit generators. Shrinks failed arguments - * with the default shrink function for the type */ - def forAll[T1,T2,T3,T4,T5,T6,P]( - g1: Gen[T1], g2: Gen[T2], g3: Gen[T3], g4: Gen[T4], g5: Gen[T5], g6: Gen[T6])( - f: (T1,T2,T3,T4,T5,T6) => P)(implicit - p: P => Prop, - s1: Shrink[T1], pp1: T1 => Pretty, - s2: Shrink[T2], pp2: T2 => Pretty, - s3: Shrink[T3], pp3: T3 => Pretty, - s4: Shrink[T4], pp4: T4 => Pretty, - s5: Shrink[T5], pp5: T5 => Pretty, - s6: Shrink[T6], pp6: T6 => Pretty - ): Prop = forAll(g1)(t => forAll(g2,g3,g4,g5,g6)(f(t, _:T2, _:T3, _:T4, _:T5, _:T6))) - - /** Universal quantifier for seven explicit generators. Shrinks failed arguments - * with the default shrink function for the type */ - def forAll[T1,T2,T3,T4,T5,T6,T7,P]( - g1: Gen[T1], g2: Gen[T2], g3: Gen[T3], g4: Gen[T4], g5: Gen[T5], g6: Gen[T6], g7: Gen[T7])( - f: (T1,T2,T3,T4,T5,T6,T7) => P)(implicit - p: P => Prop, - s1: Shrink[T1], pp1: T1 => Pretty, - s2: Shrink[T2], pp2: T2 => Pretty, - s3: Shrink[T3], pp3: T3 => Pretty, - s4: Shrink[T4], pp4: T4 => Pretty, - s5: Shrink[T5], pp5: T5 => Pretty, - s6: Shrink[T6], pp6: T6 => Pretty, - s7: Shrink[T7], pp7: T7 => Pretty - ): Prop = forAll(g1)(t => forAll(g2,g3,g4,g5,g6,g7)(f(t, _:T2, _:T3, _:T4, _:T5, _:T6, _:T7))) - - /** Universal quantifier for eight explicit generators. Shrinks failed arguments - * with the default shrink function for the type */ - def forAll[T1,T2,T3,T4,T5,T6,T7,T8,P]( - g1: Gen[T1], g2: Gen[T2], g3: Gen[T3], g4: Gen[T4], g5: Gen[T5], g6: Gen[T6], g7: Gen[T7], g8: Gen[T8])( - f: (T1,T2,T3,T4,T5,T6,T7,T8) => P)(implicit - p: P => Prop, - s1: Shrink[T1], pp1: T1 => Pretty, - s2: Shrink[T2], pp2: T2 => Pretty, - s3: Shrink[T3], pp3: T3 => Pretty, - s4: Shrink[T4], pp4: T4 => Pretty, - s5: Shrink[T5], pp5: T5 => Pretty, - s6: Shrink[T6], pp6: T6 => Pretty, - s7: Shrink[T7], pp7: T7 => Pretty, - s8: Shrink[T8], pp8: T8 => Pretty - ): Prop = forAll(g1)(t => forAll(g2,g3,g4,g5,g6,g7,g8)(f(t, _:T2, _:T3, _:T4, _:T5, _:T6, _:T7, _:T8))) - - /** Converts a function into a universally quantified property */ - def forAll[A1,P] ( - f: A1 => P)(implicit - p: P => Prop, - a1: Arbitrary[A1], s1: Shrink[A1], pp1: A1 => Pretty - ): Prop = forAllShrink(arbitrary[A1],shrink[A1])(f andThen p) - - /** Converts a function into a universally quantified property */ - def forAll[A1,A2,P] ( - f: (A1,A2) => P)(implicit - p: P => Prop, - a1: Arbitrary[A1], s1: Shrink[A1], pp1: A1 => Pretty, - a2: Arbitrary[A2], s2: Shrink[A2], pp2: A2 => Pretty - ): Prop = forAll((a: A1) => forAll(f(a, _:A2))) - - /** Converts a function into a universally quantified property */ - def forAll[A1,A2,A3,P] ( - f: (A1,A2,A3) => P)(implicit - p: P => Prop, - a1: Arbitrary[A1], s1: Shrink[A1], pp1: A1 => Pretty, - a2: Arbitrary[A2], s2: Shrink[A2], pp2: A2 => Pretty, - a3: Arbitrary[A3], s3: Shrink[A3], pp3: A3 => Pretty - ): Prop = forAll((a: A1) => forAll(f(a, _:A2, _:A3))) - - /** Converts a function into a universally quantified property */ - def forAll[A1,A2,A3,A4,P] ( - f: (A1,A2,A3,A4) => P)(implicit - p: P => Prop, - a1: Arbitrary[A1], s1: Shrink[A1], pp1: A1 => Pretty, - a2: Arbitrary[A2], s2: Shrink[A2], pp2: A2 => Pretty, - a3: Arbitrary[A3], s3: Shrink[A3], pp3: A3 => Pretty, - a4: Arbitrary[A4], s4: Shrink[A4], pp4: A4 => Pretty - ): Prop = forAll((a: A1) => forAll(f(a, _:A2, _:A3, _:A4))) - - /** Converts a function into a universally quantified property */ - def forAll[A1,A2,A3,A4,A5,P] ( - f: (A1,A2,A3,A4,A5) => P)(implicit - p: P => Prop, - a1: Arbitrary[A1], s1: Shrink[A1], pp1: A1 => Pretty, - a2: Arbitrary[A2], s2: Shrink[A2], pp2: A2 => Pretty, - a3: Arbitrary[A3], s3: Shrink[A3], pp3: A3 => Pretty, - a4: Arbitrary[A4], s4: Shrink[A4], pp4: A4 => Pretty, - a5: Arbitrary[A5], s5: Shrink[A5], pp5: A5 => Pretty - ): Prop = forAll((a: A1) => forAll(f(a, _:A2, _:A3, _:A4, _:A5))) - - /** Converts a function into a universally quantified property */ - def forAll[A1,A2,A3,A4,A5,A6,P] ( - f: (A1,A2,A3,A4,A5,A6) => P)(implicit - p: P => Prop, - a1: Arbitrary[A1], s1: Shrink[A1], pp1: A1 => Pretty, - a2: Arbitrary[A2], s2: Shrink[A2], pp2: A2 => Pretty, - a3: Arbitrary[A3], s3: Shrink[A3], pp3: A3 => Pretty, - a4: Arbitrary[A4], s4: Shrink[A4], pp4: A4 => Pretty, - a5: Arbitrary[A5], s5: Shrink[A5], pp5: A5 => Pretty, - a6: Arbitrary[A6], s6: Shrink[A6], pp6: A6 => Pretty - ): Prop = forAll((a: A1) => forAll(f(a, _:A2, _:A3, _:A4, _:A5, _:A6))) - - /** Converts a function into a universally quantified property */ - def forAll[A1,A2,A3,A4,A5,A6,A7,P] ( - f: (A1,A2,A3,A4,A5,A6,A7) => P)(implicit - p: P => Prop, - a1: Arbitrary[A1], s1: Shrink[A1], pp1: A1 => Pretty, - a2: Arbitrary[A2], s2: Shrink[A2], pp2: A2 => Pretty, - a3: Arbitrary[A3], s3: Shrink[A3], pp3: A3 => Pretty, - a4: Arbitrary[A4], s4: Shrink[A4], pp4: A4 => Pretty, - a5: Arbitrary[A5], s5: Shrink[A5], pp5: A5 => Pretty, - a6: Arbitrary[A6], s6: Shrink[A6], pp6: A6 => Pretty, - a7: Arbitrary[A7], s7: Shrink[A7], pp7: A7 => Pretty - ): Prop = forAll((a: A1) => forAll(f(a, _:A2, _:A3, _:A4, _:A5, _:A6, _:A7))) - - /** Converts a function into a universally quantified property */ - def forAll[A1,A2,A3,A4,A5,A6,A7,A8,P] ( - f: (A1,A2,A3,A4,A5,A6,A7,A8) => P)(implicit - p: P => Prop, - a1: Arbitrary[A1], s1: Shrink[A1], pp1: A1 => Pretty, - a2: Arbitrary[A2], s2: Shrink[A2], pp2: A2 => Pretty, - a3: Arbitrary[A3], s3: Shrink[A3], pp3: A3 => Pretty, - a4: Arbitrary[A4], s4: Shrink[A4], pp4: A4 => Pretty, - a5: Arbitrary[A5], s5: Shrink[A5], pp5: A5 => Pretty, - a6: Arbitrary[A6], s6: Shrink[A6], pp6: A6 => Pretty, - a7: Arbitrary[A7], s7: Shrink[A7], pp7: A7 => Pretty, - a8: Arbitrary[A8], s8: Shrink[A8], pp8: A8 => Pretty - ): Prop = forAll((a: A1) => forAll(f(a, _:A2, _:A3, _:A4, _:A5, _:A6, _:A7, _:A8))) - - /** Ensures that the property expression passed in completes within the given space of time. */ - def within(maximumMs: Long)(wrappedProp: => Prop): Prop = new Prop { - @tailrec private def attempt(prms: Params, endTime: Long): Result = { - val result = wrappedProp.apply(prms) - if (System.currentTimeMillis > endTime) { - (if (result.failure) result else Result(False)).label("Timeout") - } else { - if (result.success) result - else attempt(prms, endTime) - } - } - def apply(prms: Params) = attempt(prms, System.currentTimeMillis + maximumMs) - } -} diff --git a/src/scalacheck/org/scalacheck/Properties.scala b/src/scalacheck/org/scalacheck/Properties.scala deleted file mode 100644 index d4836d7420..0000000000 --- a/src/scalacheck/org/scalacheck/Properties.scala +++ /dev/null @@ -1,96 +0,0 @@ -/*-------------------------------------------------------------------------*\ -** ScalaCheck ** -** Copyright (c) 2007-2013 Rickard Nilsson. All rights reserved. ** -** http://www.scalacheck.org ** -** ** -** This software is released under the terms of the Revised BSD License. ** -** There is NO WARRANTY. See the file LICENSE for the full text. ** -\*------------------------------------------------------------------------ */ - -package org.scalacheck - -/** Represents a collection of properties, with convenient methods - * for checking all properties at once. This class is itself a property, which - * holds if and only if all of the contained properties hold. - *

Properties are added in the following way:

- * - * {{{ - * object MyProps extends Properties("MyProps") { - * property("myProp1") = forAll { (n:Int, m:Int) => - * n+m == m+n - * } - * - * property("myProp2") = ((0/1) throws classOf[ArithmeticException]) - * } - * }}} - */ -class Properties(val name: String) extends Prop { - - import Test.cmdLineParser.{Success, NoSuccess} - - private val props = new scala.collection.mutable.ListBuffer[(String,Prop)] - - /** Returns one property which holds if and only if all of the - * properties in this property collection hold */ - private def oneProperty: Prop = Prop.all((properties map (_._2)):_*) - - /** Returns all properties of this collection in a list of name/property - * pairs. */ - def properties: Seq[(String,Prop)] = props - - def apply(p: Prop.Params) = oneProperty(p) - - /** Convenience method that checks the properties with the given parameters - * and reports the result on the console. If you need to get the results - * from the test use the `check` methods in [[org.scalacheck.Test]] - * instead. */ - override def check(prms: Test.Parameters): Unit = Test.checkProperties( - prms copy (_testCallback = ConsoleReporter(1) chain prms.testCallback), this - ) - - /** Convenience method that checks the properties with the given parameters - * and reports the result on the console. If you need to get the results - * from the test use the `check` methods in [[org.scalacheck.Test]] - * instead. - * @deprecated (in 1.10.0) Use `check(Test.Parameters)` instead. - */ - @deprecated("Use 'check(Test.Parameters)' instead", "1.10.0") - override def check(prms: Test.Params): Unit = Test.checkProperties( - prms copy (testCallback = ConsoleReporter(1) chain prms.testCallback), this - ) - - /** Convenience method that checks the properties and reports the - * result on the console. If you need to get the results from the test use - * the `check` methods in [[org.scalacheck.Test]] instead. */ - override def check: Unit = check(Test.Parameters.default) - - /** The logic for main, separated out to make it easier to - * avoid System.exit calls. Returns exit code. - */ - override def mainRunner(args: Array[String]): Int = { - Test.cmdLineParser.parseParams(args) match { - case Success(params, _) => - val res = Test.checkProperties(params, this) - val failed = res.filter(!_._2.passed).size - failed - case e: NoSuccess => - println("Incorrect options:"+"\n"+e+"\n") - Test.cmdLineParser.printHelp - -1 - } - } - - /** Adds all properties from another property collection to this one. */ - def include(ps: Properties) = for((n,p) <- ps.properties) property(n) = p - - /** Used for specifying properties. Usage: - * {{{ - * property("myProp") = ... - * }}} - */ - class PropertySpecifier() { - def update(propName: String, p: Prop) = props += ((name+"."+propName, p)) - } - - lazy val property = new PropertySpecifier() -} diff --git a/src/scalacheck/org/scalacheck/ScalaCheckFramework.scala b/src/scalacheck/org/scalacheck/ScalaCheckFramework.scala deleted file mode 100644 index 7764101844..0000000000 --- a/src/scalacheck/org/scalacheck/ScalaCheckFramework.scala +++ /dev/null @@ -1,92 +0,0 @@ -/*-------------------------------------------------------------------------*\ -** ScalaCheck ** -** Copyright (c) 2007-2013 Rickard Nilsson. All rights reserved. ** -** http://www.scalacheck.org ** -** ** -** This software is released under the terms of the Revised BSD License. ** -** There is NO WARRANTY. See the file LICENSE for the full text. ** -\*------------------------------------------------------------------------ */ - -// vim: set ts=2 sw=2 et: - -package org.scalacheck - -import org.scalatools.testing._ - -class ScalaCheckFramework extends Framework { - - private case object PropFingerprint extends TestFingerprint { - val superClassName = "org.scalacheck.Prop" - val isModule = false - } - - private case object PropsFingerprint extends TestFingerprint { - val superClassName = "org.scalacheck.Properties" - val isModule = true - } - - val name = "ScalaCheck" - - val tests = Array[Fingerprint](PropsFingerprint, PropsFingerprint) - - def testRunner(loader: ClassLoader, loggers: Array[Logger]) = new Runner2 { - - private def asEvent(nr: (String, Test.Result)) = nr match { - case (n: String, r: Test.Result) => new Event { - val testName = n - val description = n - val result = r.status match { - case Test.Passed => Result.Success - case _:Test.Proved => Result.Success - case _:Test.Failed => Result.Failure - case Test.Exhausted => Result.Skipped - case _:Test.PropException | _:Test.GenException => Result.Error - } - val error = r.status match { - case Test.PropException(_, e, _) => e - case _:Test.Failed => new Exception(Pretty.pretty(r,Pretty.Params(0))) - case _ => null - } - } - } - - def run(testClassName: String, fingerprint: Fingerprint, handler: EventHandler, args: Array[String]) { - - val testCallback = new Test.TestCallback { - override def onPropEval(n: String, w: Int, s: Int, d: Int) = {} - - override def onTestResult(n: String, r: Test.Result) = { - for (l <- loggers) { - import Pretty._ - l.info( - (if (r.passed) "+ " else "! ") + n + ": " + pretty(r, Params(0)) - ) - } - handler.handle(asEvent((n,r))) - } - } - - import Test.cmdLineParser.{Success, NoSuccess} - val prms = Test.cmdLineParser.parseParams(args) match { - case Success(params, _) => - params.copy(_testCallback = testCallback, _customClassLoader = Some(loader)) - // TODO: Maybe handle this a bit better than throwing exception? - case e: NoSuccess => throw new Exception(e.toString) - } - - fingerprint match { - case fp: SubclassFingerprint => - if(fp.isModule) { - val obj = Class.forName(testClassName + "$", true, loader) - val ps = obj.getField("MODULE$").get(null).asInstanceOf[Properties] - Test.checkProperties(prms, ps) - } else { - val p = Class.forName(testClassName, true, loader).newInstance.asInstanceOf[Prop] - handler.handle(asEvent((testClassName, Test.check(prms, p)))) - } - } - } - - } - -} diff --git a/src/scalacheck/org/scalacheck/Shrink.scala b/src/scalacheck/org/scalacheck/Shrink.scala deleted file mode 100644 index 4895171a35..0000000000 --- a/src/scalacheck/org/scalacheck/Shrink.scala +++ /dev/null @@ -1,208 +0,0 @@ -/*-------------------------------------------------------------------------*\ -** ScalaCheck ** -** Copyright (c) 2007-2013 Rickard Nilsson. All rights reserved. ** -** http://www.scalacheck.org ** -** ** -** This software is released under the terms of the Revised BSD License. ** -** There is NO WARRANTY. See the file LICENSE for the full text. ** -\*------------------------------------------------------------------------ */ - -package org.scalacheck - -import util.Buildable -import scala.collection.{ JavaConversions => jcl } - -sealed abstract class Shrink[T] { - def shrink(x: T): Stream[T] -} - -object Shrink { - - import Stream.{cons, empty} - import scala.collection._ - import java.util.ArrayList - - /** Interleaves to streams */ - private def interleave[T](xs: Stream[T], ys: Stream[T]): Stream[T] = - if(xs.isEmpty) ys - else if(ys.isEmpty) xs - else Stream(xs.head, ys.head) append interleave(xs.tail, ys.tail) - - /** Shrink instance factory */ - def apply[T](s: T => Stream[T]): Shrink[T] = new Shrink[T] { - override def shrink(x: T) = s(x) - } - - /** Shrink a value */ - def shrink[T](x: T)(implicit s: Shrink[T]): Stream[T] = s.shrink(x) - - /** Default shrink instance */ - implicit def shrinkAny[T]: Shrink[T] = Shrink(x => empty) - - /** Shrink instance of container */ - implicit def shrinkContainer[C[_],T](implicit v: C[T] => Traversable[T], s: Shrink[T], - b: Buildable[T,C] - ): Shrink[C[T]] = Shrink { xs: C[T] => - - def removeChunks(n: Int, xs: Stream[T]): Stream[Stream[T]] = - if(xs.isEmpty) empty - else if(xs.tail.isEmpty) cons(empty, empty) - else { - val n1 = n / 2 - val n2 = n - n1 - lazy val xs1 = xs.take(n1) - lazy val xs2 = xs.drop(n1) - lazy val xs3 = - for(ys1 <- removeChunks(n1,xs1) if !ys1.isEmpty) yield ys1 append xs2 - lazy val xs4 = - for(ys2 <- removeChunks(n2,xs2) if !ys2.isEmpty) yield xs1 append ys2 - - cons(xs1, cons(xs2, interleave(xs3,xs4))) - } - - def shrinkOne(zs: Stream[T]): Stream[Stream[T]] = - if(zs.isEmpty) empty - else { - val x = zs.head - val xs = zs.tail - (for(y <- shrink(x)) yield cons(y,xs)) append - (for(ys <- shrinkOne(xs)) yield cons(x,ys)) - } - - val ys = v(xs) - val zs = ys.toStream - removeChunks(ys.size,zs).append(shrinkOne(zs)).map(b.fromIterable) - - } - - /** Shrink instance of integer */ - implicit lazy val shrinkInt: Shrink[Int] = Shrink { n => - - def halfs(n: Int): Stream[Int] = - if(n == 0) empty else cons(n, halfs(n/2)) - - if(n == 0) empty else { - val ns = halfs(n/2).map(n - _) - cons(0, interleave(ns, ns.map(-1 * _))) - } - } - - /** Shrink instance of String */ - implicit lazy val shrinkString: Shrink[String] = Shrink { s => - shrinkContainer[List,Char].shrink(s.toList).map(_.mkString) - } - - /** Shrink instance of Option */ - implicit def shrinkOption[T](implicit s: Shrink[T]): Shrink[Option[T]] = - Shrink { - case None => empty - case Some(x) => cons(None, for(y <- shrink(x)) yield Some(y)) - } - - /** Shrink instance of 2-tuple */ - implicit def shrinkTuple2[T1,T2](implicit - s1: Shrink[T1], s2: Shrink[T2] - ): Shrink[(T1,T2)] = - Shrink { case (t1,t2) => - (for(x1 <- shrink(t1)) yield (x1, t2)) append - (for(x2 <- shrink(t2)) yield (t1, x2)) - } - - /** Shrink instance of 3-tuple */ - implicit def shrinkTuple3[T1,T2,T3](implicit - s1: Shrink[T1], s2: Shrink[T2], s3: Shrink[T3] - ): Shrink[(T1,T2,T3)] = - Shrink { case (t1,t2,t3) => - (for(x1 <- shrink(t1)) yield (x1, t2, t3)) append - (for(x2 <- shrink(t2)) yield (t1, x2, t3)) append - (for(x3 <- shrink(t3)) yield (t1, t2, x3)) - } - - /** Shrink instance of 4-tuple */ - implicit def shrinkTuple4[T1,T2,T3,T4](implicit - s1: Shrink[T1], s2: Shrink[T2], s3: Shrink[T3], s4: Shrink[T4] - ): Shrink[(T1,T2,T3,T4)] = - Shrink { case (t1,t2,t3,t4) => - (for(x1 <- shrink(t1)) yield (x1, t2, t3, t4)) append - (for(x2 <- shrink(t2)) yield (t1, x2, t3, t4)) append - (for(x3 <- shrink(t3)) yield (t1, t2, x3, t4)) append - (for(x4 <- shrink(t4)) yield (t1, t2, t3, x4)) - } - - /** Shrink instance of 5-tuple */ - implicit def shrinkTuple5[T1,T2,T3,T4,T5](implicit - s1: Shrink[T1], s2: Shrink[T2], s3: Shrink[T3], s4: Shrink[T4], - s5: Shrink[T5] - ): Shrink[(T1,T2,T3,T4,T5)] = - Shrink { case (t1,t2,t3,t4,t5) => - (for(x1 <- shrink(t1)) yield (x1, t2, t3, t4, t5)) append - (for(x2 <- shrink(t2)) yield (t1, x2, t3, t4, t5)) append - (for(x3 <- shrink(t3)) yield (t1, t2, x3, t4, t5)) append - (for(x4 <- shrink(t4)) yield (t1, t2, t3, x4, t5)) append - (for(x5 <- shrink(t5)) yield (t1, t2, t3, t4, x5)) - } - - /** Shrink instance of 6-tuple */ - implicit def shrinkTuple6[T1,T2,T3,T4,T5,T6](implicit - s1: Shrink[T1], s2: Shrink[T2], s3: Shrink[T3], s4: Shrink[T4], - s5: Shrink[T5], s6: Shrink[T6] - ): Shrink[(T1,T2,T3,T4,T5,T6)] = - Shrink { case (t1,t2,t3,t4,t5,t6) => - (for(x1 <- shrink(t1)) yield (x1, t2, t3, t4, t5, t6)) append - (for(x2 <- shrink(t2)) yield (t1, x2, t3, t4, t5, t6)) append - (for(x3 <- shrink(t3)) yield (t1, t2, x3, t4, t5, t6)) append - (for(x4 <- shrink(t4)) yield (t1, t2, t3, x4, t5, t6)) append - (for(x5 <- shrink(t5)) yield (t1, t2, t3, t4, x5, t6)) append - (for(x6 <- shrink(t6)) yield (t1, t2, t3, t4, t5, x6)) - } - - /** Shrink instance of 7-tuple */ - implicit def shrinkTuple7[T1,T2,T3,T4,T5,T6,T7](implicit - s1: Shrink[T1], s2: Shrink[T2], s3: Shrink[T3], s4: Shrink[T4], - s5: Shrink[T5], s6: Shrink[T6], s7: Shrink[T7] - ): Shrink[(T1,T2,T3,T4,T5,T6,T7)] = - Shrink { case (t1,t2,t3,t4,t5,t6,t7) => - (for(x1 <- shrink(t1)) yield (x1, t2, t3, t4, t5, t6, t7)) append - (for(x2 <- shrink(t2)) yield (t1, x2, t3, t4, t5, t6, t7)) append - (for(x3 <- shrink(t3)) yield (t1, t2, x3, t4, t5, t6, t7)) append - (for(x4 <- shrink(t4)) yield (t1, t2, t3, x4, t5, t6, t7)) append - (for(x5 <- shrink(t5)) yield (t1, t2, t3, t4, x5, t6, t7)) append - (for(x6 <- shrink(t6)) yield (t1, t2, t3, t4, t5, x6, t7)) append - (for(x7 <- shrink(t7)) yield (t1, t2, t3, t4, t5, t6, x7)) - } - - /** Shrink instance of 8-tuple */ - implicit def shrinkTuple8[T1,T2,T3,T4,T5,T6,T7,T8](implicit - s1: Shrink[T1], s2: Shrink[T2], s3: Shrink[T3], s4: Shrink[T4], - s5: Shrink[T5], s6: Shrink[T6], s7: Shrink[T7], s8: Shrink[T8] - ): Shrink[(T1,T2,T3,T4,T5,T6,T7,T8)] = - Shrink { case (t1,t2,t3,t4,t5,t6,t7,t8) => - (for(x1 <- shrink(t1)) yield (x1, t2, t3, t4, t5, t6, t7, t8)) append - (for(x2 <- shrink(t2)) yield (t1, x2, t3, t4, t5, t6, t7, t8)) append - (for(x3 <- shrink(t3)) yield (t1, t2, x3, t4, t5, t6, t7, t8)) append - (for(x4 <- shrink(t4)) yield (t1, t2, t3, x4, t5, t6, t7, t8)) append - (for(x5 <- shrink(t5)) yield (t1, t2, t3, t4, x5, t6, t7, t8)) append - (for(x6 <- shrink(t6)) yield (t1, t2, t3, t4, t5, x6, t7, t8)) append - (for(x7 <- shrink(t7)) yield (t1, t2, t3, t4, t5, t6, x7, t8)) append - (for(x8 <- shrink(t8)) yield (t1, t2, t3, t4, t5, t6, t7, x8)) - } - - /** Shrink instance of 9-tuple */ - implicit def shrinkTuple9[T1,T2,T3,T4,T5,T6,T7,T8,T9](implicit - s1: Shrink[T1], s2: Shrink[T2], s3: Shrink[T3], s4: Shrink[T4], - s5: Shrink[T5], s6: Shrink[T6], s7: Shrink[T7], s8: Shrink[T8], - s9: Shrink[T9] - ): Shrink[(T1,T2,T3,T4,T5,T6,T7,T8,T9)] = - Shrink { case (t1,t2,t3,t4,t5,t6,t7,t8,t9) => - (for(x1 <- shrink(t1)) yield (x1, t2, t3, t4, t5, t6, t7, t8, t9)) append - (for(x2 <- shrink(t2)) yield (t1, x2, t3, t4, t5, t6, t7, t8, t9)) append - (for(x3 <- shrink(t3)) yield (t1, t2, x3, t4, t5, t6, t7, t8, t9)) append - (for(x4 <- shrink(t4)) yield (t1, t2, t3, x4, t5, t6, t7, t8, t9)) append - (for(x5 <- shrink(t5)) yield (t1, t2, t3, t4, x5, t6, t7, t8, t9)) append - (for(x6 <- shrink(t6)) yield (t1, t2, t3, t4, t5, x6, t7, t8, t9)) append - (for(x7 <- shrink(t7)) yield (t1, t2, t3, t4, t5, t6, x7, t8, t9)) append - (for(x8 <- shrink(t8)) yield (t1, t2, t3, t4, t5, t6, t7, x8, t9)) append - (for(x9 <- shrink(t9)) yield (t1, t2, t3, t4, t5, t6, t7, t8, x9)) - } - -} diff --git a/src/scalacheck/org/scalacheck/Test.scala b/src/scalacheck/org/scalacheck/Test.scala deleted file mode 100644 index 6e9b6b88fd..0000000000 --- a/src/scalacheck/org/scalacheck/Test.scala +++ /dev/null @@ -1,392 +0,0 @@ -/*-------------------------------------------------------------------------*\ -** ScalaCheck ** -** Copyright (c) 2007-2013 Rickard Nilsson. All rights reserved. ** -** http://www.scalacheck.org ** -** ** -** This software is released under the terms of the Revised BSD License. ** -** There is NO WARRANTY. See the file LICENSE for the full text. ** -\*------------------------------------------------------------------------ */ - -package org.scalacheck - -object Test { - - import util.FreqMap - import scala.collection.immutable - import Prop.FM - import util.CmdLineParser - - /** Test parameters used by the `Test.check` method. - */ - trait Parameters { - /** The minimum number of tests that must succeed for ScalaCheck to - * consider a property passed. */ - def minSuccessfulTests: Int - - /** The starting size given as parameter to the generators. */ - def minSize: Int - - /** The maximum size given as parameter to the generators. */ - def maxSize: Int - - /** The random numbe generator used. */ - def rng: java.util.Random - - /** The number of tests run in parallell. */ - def workers: Int - - /** A callback that ScalaCheck calls each time a test is executed. */ - def testCallback: TestCallback - - /** The maximum ratio between discarded and passed tests allowed before - * ScalaCheck gives up and discards the property. At least - * `minSuccesfulTests` will always be run, though. */ - def maxDiscardRatio: Float - - /** A custom class loader that should be used during test execution. */ - def customClassLoader: Option[ClassLoader] - - // private since we can't guarantee binary compatibility for this one - private[scalacheck] def copy( - _minSuccessfulTests: Int = Parameters.this.minSuccessfulTests, - _minSize: Int = Parameters.this.minSize, - _maxSize: Int = Parameters.this.maxSize, - _rng: java.util.Random = Parameters.this.rng, - _workers: Int = Parameters.this.workers, - _testCallback: TestCallback = Parameters.this.testCallback, - _maxDiscardRatio: Float = Parameters.this.maxDiscardRatio, - _customClassLoader: Option[ClassLoader] = Parameters.this.customClassLoader - ): Parameters = new Parameters { - val minSuccessfulTests: Int = _minSuccessfulTests - val minSize: Int = _minSize - val maxSize: Int = _maxSize - val rng: java.util.Random = _rng - val workers: Int = _workers - val testCallback: TestCallback = _testCallback - val maxDiscardRatio: Float = _maxDiscardRatio - val customClassLoader: Option[ClassLoader] = _customClassLoader - } - } - - /** Test parameters used by the `Test.check` method. - * - * To override default values, extend the - * [[org.scalacheck.Test.Parameters.Default]] trait: - * - * {{{ - * val myParams = new Parameters.Default { - * override val minSuccesfulTests = 600 - * override val maxDiscardRatio = 8 - * } - * }}} - */ - object Parameters { - /** Default test parameters trait. This can be overriden if you need to - * tweak the parameters. */ - trait Default extends Parameters { - val minSuccessfulTests: Int = 100 - val minSize: Int = 0 - val maxSize: Int = Gen.Params().size - val rng: java.util.Random = Gen.Params().rng - val workers: Int = 1 - val testCallback: TestCallback = new TestCallback {} - val maxDiscardRatio: Float = 5 - val customClassLoader: Option[ClassLoader] = None - } - - /** Default test parameters instance. */ - val default: Parameters = new Default {} - } - - /** Test parameters - * @deprecated (in 1.10.0) Use [[org.scalacheck.Test.Parameters]] instead. - */ - @deprecated("Use [[org.scalacheck.Test.Parameters]] instead", "1.10.0") - case class Params( - minSuccessfulTests: Int = 100, - maxDiscardedTests: Int = -1, - minSize: Int = 0, - maxSize: Int = Gen.Params().size, - rng: java.util.Random = Gen.Params().rng, - workers: Int = 1, - testCallback: TestCallback = new TestCallback {} - ) - - @deprecated("Use [[org.scalacheck.Test.Parameters]] instead", "1.10.0") - private def paramsToParameters(params: Params) = new Parameters { - val minSuccessfulTests = params.minSuccessfulTests - val minSize = params.minSize - val maxSize = params.maxSize - val rng = params.rng - val workers = params.workers - val testCallback = params.testCallback - - // maxDiscardedTests is deprecated, but if someone - // uses it let it override maxDiscardRatio - val maxDiscardRatio = - if(params.maxDiscardedTests < 0) Parameters.default.maxDiscardRatio - else (params.maxDiscardedTests: Float)/(params.minSuccessfulTests: Float) - - val customClassLoader = Parameters.default.customClassLoader - } - - /** Test statistics */ - case class Result(status: Status, succeeded: Int, discarded: Int, freqMap: FM, time: Long = 0) { - def passed = status match { - case Passed => true - case Proved(_) => true - case _ => false - } - } - - /** Test status */ - sealed trait Status - - /** ScalaCheck found enough cases for which the property holds, so the - * property is considered correct. (It is not proved correct, though). */ - case object Passed extends Status - - /** ScalaCheck managed to prove the property correct */ - sealed case class Proved(args: Prop.Args) extends Status - - /** The property was proved wrong with the given concrete arguments. */ - sealed case class Failed(args: Prop.Args, labels: Set[String]) extends Status - - /** The property test was exhausted, it wasn't possible to generate enough - * concrete arguments satisfying the preconditions to get enough passing - * property evaluations. */ - case object Exhausted extends Status - - /** An exception was raised when trying to evaluate the property with the - * given concrete arguments. */ - sealed case class PropException(args: Prop.Args, e: Throwable, - labels: Set[String]) extends Status - - /** An exception was raised when trying to generate concrete arguments - * for evaluating the property. */ - sealed case class GenException(e: Throwable) extends Status - - trait TestCallback { self => - /** Called each time a property is evaluated */ - def onPropEval(name: String, threadIdx: Int, succeeded: Int, - discarded: Int): Unit = () - - /** Called whenever a property has finished testing */ - def onTestResult(name: String, result: Result): Unit = () - - def chain(testCallback: TestCallback) = new TestCallback { - override def onPropEval(name: String, threadIdx: Int, - succeeded: Int, discarded: Int - ): Unit = { - self.onPropEval(name,threadIdx,succeeded,discarded) - testCallback.onPropEval(name,threadIdx,succeeded,discarded) - } - - override def onTestResult(name: String, result: Result): Unit = { - self.onTestResult(name,result) - testCallback.onTestResult(name,result) - } - } - } - - private def assertParams(prms: Parameters) = { - import prms._ - if( - minSuccessfulTests <= 0 || - maxDiscardRatio <= 0 || - minSize < 0 || - maxSize < minSize || - workers <= 0 - ) throw new IllegalArgumentException("Invalid test parameters") - } - - private def secure[T](x: => T): Either[T,Throwable] = - try { Left(x) } catch { case e: Throwable => Right(e) } - - private[scalacheck] lazy val cmdLineParser = new CmdLineParser { - object OptMinSuccess extends IntOpt { - val default = Parameters.default.minSuccessfulTests - val names = Set("minSuccessfulTests", "s") - val help = "Number of tests that must succeed in order to pass a property" - } - object OptMaxDiscarded extends IntOpt { - val default = -1 - val names = Set("maxDiscardedTests", "d") - val help = - "Number of tests that can be discarded before ScalaCheck stops " + - "testing a property. NOTE: this option is deprecated, please use " + - "the option maxDiscardRatio (-r) instead." - } - object OptMaxDiscardRatio extends FloatOpt { - val default = Parameters.default.maxDiscardRatio - val names = Set("maxDiscardRatio", "r") - val help = - "The maximum ratio between discarded and succeeded tests " + - "allowed before ScalaCheck stops testing a property. At " + - "least minSuccessfulTests will always be tested, though." - } - object OptMinSize extends IntOpt { - val default = Parameters.default.minSize - val names = Set("minSize", "n") - val help = "Minimum data generation size" - } - object OptMaxSize extends IntOpt { - val default = Parameters.default.maxSize - val names = Set("maxSize", "x") - val help = "Maximum data generation size" - } - object OptWorkers extends IntOpt { - val default = Parameters.default.workers - val names = Set("workers", "w") - val help = "Number of threads to execute in parallel for testing" - } - object OptVerbosity extends IntOpt { - val default = 1 - val names = Set("verbosity", "v") - val help = "Verbosity level" - } - - val opts = Set[Opt[_]]( - OptMinSuccess, OptMaxDiscarded, OptMaxDiscardRatio, OptMinSize, - OptMaxSize, OptWorkers, OptVerbosity - ) - - def parseParams(args: Array[String]) = parseArgs(args) { - optMap => Parameters.default.copy( - _minSuccessfulTests = optMap(OptMinSuccess), - _maxDiscardRatio = - if (optMap(OptMaxDiscarded) < 0) optMap(OptMaxDiscardRatio) - else optMap(OptMaxDiscarded).toFloat / optMap(OptMinSuccess), - _minSize = optMap(OptMinSize), - _maxSize = optMap(OptMaxSize), - _workers = optMap(OptWorkers), - _testCallback = ConsoleReporter(optMap(OptVerbosity)) - ) - } - } - - /** Tests a property with the given testing parameters, and returns - * the test results. - * @deprecated (in 1.10.0) Use - * `check(Parameters, Properties)` instead. - */ - @deprecated("Use 'checkProperties(Parameters, Properties)' instead", "1.10.0") - def check(params: Params, p: Prop): Result = { - check(paramsToParameters(params), p) - } - - /** Tests a property with the given testing parameters, and returns - * the test results. */ - def check(params: Parameters, p: Prop): Result = { - import params._ - - assertParams(params) - if(workers > 1) { - assert(!p.isInstanceOf[Commands], "Commands cannot be checked multi-threaded") - } - - val iterations = math.ceil(minSuccessfulTests / (workers: Double)) - val sizeStep = (maxSize-minSize) / (iterations*workers) - var stop = false - - def worker(workerIdx: Int) = - if (workers < 2) () => workerFun(workerIdx) - else actors.Futures.future { - params.customClassLoader.map(Thread.currentThread.setContextClassLoader(_)) - workerFun(workerIdx) - } - - def workerFun(workerIdx: Int) = { - var n = 0 // passed tests - var d = 0 // discarded tests - var res: Result = null - var fm = FreqMap.empty[immutable.Set[Any]] - while(!stop && res == null && n < iterations) { - val size = (minSize: Double) + (sizeStep * (workerIdx + (workers*(n+d)))) - val propPrms = Prop.Params(Gen.Params(size.round.toInt, params.rng), fm) - secure(p(propPrms)) match { - case Right(e) => res = - Result(GenException(e), n, d, FreqMap.empty[immutable.Set[Any]]) - case Left(propRes) => - fm = - if(propRes.collected.isEmpty) fm - else fm + propRes.collected - propRes.status match { - case Prop.Undecided => - d += 1 - testCallback.onPropEval("", workerIdx, n, d) - // The below condition is kind of hacky. We have to have - // some margin, otherwise workers might stop testing too - // early because they have been exhausted, but the overall - // test has not. - if (n+d > minSuccessfulTests && 1+workers*maxDiscardRatio*n < d) - res = Result(Exhausted, n, d, fm) - case Prop.True => - n += 1 - testCallback.onPropEval("", workerIdx, n, d) - case Prop.Proof => - n += 1 - res = Result(Proved(propRes.args), n, d, fm) - stop = true - case Prop.False => - res = Result(Failed(propRes.args,propRes.labels), n, d, fm) - stop = true - case Prop.Exception(e) => - res = Result(PropException(propRes.args,e,propRes.labels), n, d, fm) - stop = true - } - } - } - if (res == null) { - if (maxDiscardRatio*n > d) Result(Passed, n, d, fm) - else Result(Exhausted, n, d, fm) - } else res - } - - def mergeResults(r1: () => Result, r2: () => Result) = { - val Result(st1, s1, d1, fm1, _) = r1() - val Result(st2, s2, d2, fm2, _) = r2() - if (st1 != Passed && st1 != Exhausted) - () => Result(st1, s1+s2, d1+d2, fm1++fm2, 0) - else if (st2 != Passed && st2 != Exhausted) - () => Result(st2, s1+s2, d1+d2, fm1++fm2, 0) - else { - if (s1+s2 >= minSuccessfulTests && maxDiscardRatio*(s1+s2) >= (d1+d2)) - () => Result(Passed, s1+s2, d1+d2, fm1++fm2, 0) - else - () => Result(Exhausted, s1+s2, d1+d2, fm1++fm2, 0) - } - } - - val start = System.currentTimeMillis - val results = for(i <- 0 until workers) yield worker(i) - val r = results.reduceLeft(mergeResults)() - stop = true - results foreach (_.apply()) - val timedRes = r.copy(time = System.currentTimeMillis-start) - params.testCallback.onTestResult("", timedRes) - timedRes - } - - /** Check a set of properties. - * @deprecated (in 1.10.0) Use - * `checkProperties(Parameters, Properties)` instead. - */ - @deprecated("Use 'checkProperties(Parameters, Properties)' instead", "1.10.0") - def checkProperties(prms: Params, ps: Properties): Seq[(String,Result)] = - checkProperties(paramsToParameters(prms), ps) - - /** Check a set of properties. */ - def checkProperties(prms: Parameters, ps: Properties): Seq[(String,Result)] = - ps.properties.map { case (name,p) => - val testCallback = new TestCallback { - override def onPropEval(n: String, t: Int, s: Int, d: Int) = - prms.testCallback.onPropEval(name,t,s,d) - override def onTestResult(n: String, r: Result) = - prms.testCallback.onTestResult(name,r) - } - val res = check(prms copy (_testCallback = testCallback), p) - (name,res) - } - -} diff --git a/src/scalacheck/org/scalacheck/util/Buildable.scala b/src/scalacheck/org/scalacheck/util/Buildable.scala deleted file mode 100644 index 140c541a95..0000000000 --- a/src/scalacheck/org/scalacheck/util/Buildable.scala +++ /dev/null @@ -1,63 +0,0 @@ -/*-------------------------------------------------------------------------*\ -** ScalaCheck ** -** Copyright (c) 2007-2013 Rickard Nilsson. All rights reserved. ** -** http://www.scalacheck.org ** -** ** -** This software is released under the terms of the Revised BSD License. ** -** There is NO WARRANTY. See the file LICENSE for the full text. ** -\*------------------------------------------------------------------------ */ - -package org.scalacheck.util - -import scala.collection._ - -trait Buildable[T,C[_]] { - def builder: mutable.Builder[T,C[T]] - def fromIterable(it: Traversable[T]): C[T] = { - val b = builder - b ++= it - b.result() - } -} - -object Buildable { - - implicit def buildableList[T] = new Buildable[T,List] { - def builder = new mutable.ListBuffer[T] - } - - implicit def buildableStream[T] = new Buildable[T,Stream] { - def builder = (new mutable.ListBuffer[T]).mapResult(_.toStream) - } - - implicit def buildableArray[T](implicit cm: ClassManifest[T]) = - new Buildable[T,Array] { - def builder = mutable.ArrayBuilder.make[T] - } - - implicit def buildableMutableSet[T] = new Buildable[T,mutable.Set] { - def builder = new mutable.SetBuilder(mutable.Set.empty[T]) - } - - implicit def buildableImmutableSet[T] = new Buildable[T,immutable.Set] { - def builder = new mutable.SetBuilder(immutable.Set.empty[T]) - } - - implicit def buildableSet[T] = new Buildable[T,Set] { - def builder = new mutable.SetBuilder(Set.empty[T]) - } - - import java.util.ArrayList - implicit def buildableArrayList[T] = new Buildable[T,ArrayList] { - def builder = new mutable.Builder[T,ArrayList[T]] { - val al = new ArrayList[T] - def +=(x: T) = { - al.add(x) - this - } - def clear() = al.clear() - def result() = al - } - } - -} diff --git a/src/scalacheck/org/scalacheck/util/CmdLineParser.scala b/src/scalacheck/org/scalacheck/util/CmdLineParser.scala deleted file mode 100644 index eb3a91fe59..0000000000 --- a/src/scalacheck/org/scalacheck/util/CmdLineParser.scala +++ /dev/null @@ -1,101 +0,0 @@ -/*-------------------------------------------------------------------------*\ -** ScalaCheck ** -** Copyright (c) 2007-2013 Rickard Nilsson. All rights reserved. ** -** http://www.scalacheck.org ** -** ** -** This software is released under the terms of the Revised BSD License. ** -** There is NO WARRANTY. See the file LICENSE for the full text. ** -\*------------------------------------------------------------------------ */ - -package org.scalacheck.util - -import scala.util.parsing.combinator.Parsers -import scala.util.parsing.input.Reader -import scala.util.parsing.input.Position -import scala.collection.Set -import org.scalacheck.Test - -trait CmdLineParser extends Parsers { - - type Elem = String - - trait Opt[+T] { - val default: T - val names: Set[String] - val help: String - } - trait Flag extends Opt[Unit] - trait IntOpt extends Opt[Int] - trait FloatOpt extends Opt[Float] - trait StrOpt extends Opt[String] - - class OptMap { - private val opts = new collection.mutable.HashMap[Opt[_], Any] - def apply(flag: Flag): Boolean = opts.contains(flag) - def apply[T](opt: Opt[T]): T = opts.get(opt) match { - case None => opt.default - case Some(v) => v.asInstanceOf[T] - } - def update[T](opt: Opt[T], optVal: T) = opts.update(opt, optVal) - } - - val opts: Set[Opt[_]] - - private class ArgsReader(args: Array[String], i: Int) extends Reader[String] { - val pos = new Position { - val column = (args take i).foldLeft(1)(_ + _.length + 1) - val line = 1 - val lineContents = args.mkString(" ") - } - val atEnd = i >= args.length - def first = if(atEnd) null else args(i) - def rest = if(atEnd) this else new ArgsReader(args, i+1) - } - - private def getOpt(s: String) = { - if(s == null || s.length == 0 || s.charAt(0) != '-') None - else opts.find(_.names.contains(s.drop(1))) - } - - private val opt: Parser[Opt[Any]] = accept("option name", { - case s if getOpt(s).isDefined => getOpt(s).get - }) - - private val strVal: Parser[String] = accept("string", { - case s if s != null => s - }) - - private val intVal: Parser[Int] = accept("integer", { - case s if s != null && s.length > 0 && s.forall(_.isDigit) => s.toInt - }) - - private val floatVal: Parser[Float] = accept("float", { - case s if s != null && s.matches("[0987654321]+\\.?[0987654321]*") - => s.toFloat - }) - - private case class OptVal[T](o: Opt[T], v: T) - - private val optVal: Parser[OptVal[Any]] = opt into { - case o: Flag => success(OptVal(o, ())) - case o: IntOpt => intVal ^^ (v => OptVal(o, v)) - case o: FloatOpt => floatVal ^^ (v => OptVal(o, v)) - case o: StrOpt => strVal ^^ (v => OptVal(o, v)) - } - - val options: Parser[OptMap] = rep(optVal) ^^ { xs => - val map = new OptMap - xs.foreach { case OptVal(o,v) => map(o) = v } - map - } - - def printHelp = { - println("Available options:") - opts.foreach { opt => - println(" " + opt.names.map("-"+_).mkString(", ") + ": " + opt.help) - } - } - - def parseArgs[T](args: Array[String])(f: OptMap => T) = - phrase(options map f)(new ArgsReader(args,0)) -} diff --git a/src/scalacheck/org/scalacheck/util/FreqMap.scala b/src/scalacheck/org/scalacheck/util/FreqMap.scala deleted file mode 100644 index d0686aec72..0000000000 --- a/src/scalacheck/org/scalacheck/util/FreqMap.scala +++ /dev/null @@ -1,65 +0,0 @@ -/*-------------------------------------------------------------------------*\ -** ScalaCheck ** -** Copyright (c) 2007-2013 Rickard Nilsson. All rights reserved. ** -** http://www.scalacheck.org ** -** ** -** This software is released under the terms of the Revised BSD License. ** -** There is NO WARRANTY. See the file LICENSE for the full text. ** -\*------------------------------------------------------------------------ */ - -package org.scalacheck.util - -trait FreqMap[T] { - protected val underlying: scala.collection.immutable.Map[T,Int] - val total: Int - - def +(t: T) = new FreqMap[T] { - private val n = FreqMap.this.underlying.get(t) match { - case None => 1 - case Some(n) => n+1 - } - val underlying = FreqMap.this.underlying + (t -> n) - val total = FreqMap.this.total + 1 - } - - def -(t: T) = new FreqMap[T] { - val underlying = FreqMap.this.underlying.get(t) match { - case None => FreqMap.this.underlying - case Some(n) => FreqMap.this.underlying + (t -> (n-1)) - } - val total = FreqMap.this.total + 1 - } - - def ++(fm: FreqMap[T]) = new FreqMap[T] { - private val keys = FreqMap.this.underlying.keySet ++ fm.underlying.keySet - private val mappings = keys.toStream.map { x => - (x, fm.getCount(x).getOrElse(0) + FreqMap.this.getCount(x).getOrElse(0)) - } - val underlying = scala.collection.immutable.Map(mappings: _*) - val total = FreqMap.this.total + fm.total - } - - def --(fm: FreqMap[T]) = new FreqMap[T] { - val underlying = FreqMap.this.underlying transform { - case (x,n) => n - fm.getCount(x).getOrElse(0) - } - lazy val total = (0 /: underlying.valuesIterator) (_ + _) - } - - def getCount(t: T) = underlying.get(t) - - def getCounts: List[(T,Int)] = underlying.toList.sortBy(-_._2) - - def getRatio(t: T) = for(c <- getCount(t)) yield (c: Float)/total - - def getRatios = for((t,c) <- getCounts) yield (t, (c: Float)/total) - - override def toString = underlying.toString -} - -object FreqMap { - def empty[T] = new FreqMap[T] { - val underlying = scala.collection.immutable.Map.empty[T,Int] - val total = 0 - } -} diff --git a/src/scalacheck/org/scalacheck/util/StdRand.scala b/src/scalacheck/org/scalacheck/util/StdRand.scala deleted file mode 100644 index 7c1dc8dcc4..0000000000 --- a/src/scalacheck/org/scalacheck/util/StdRand.scala +++ /dev/null @@ -1,12 +0,0 @@ -/*-------------------------------------------------------------------------*\ -** ScalaCheck ** -** Copyright (c) 2007-2013 Rickard Nilsson. All rights reserved. ** -** http://www.scalacheck.org ** -** ** -** This software is released under the terms of the Revised BSD License. ** -** There is NO WARRANTY. See the file LICENSE for the full text. ** -\*------------------------------------------------------------------------ */ - -package org.scalacheck.util - -object StdRand extends java.util.Random -- cgit v1.2.3