summaryrefslogtreecommitdiff
path: root/test/pending/scalacheck/process.scala
blob: f3aa8723617565174b7895b28b620b2684ac4644 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
/** process tests. 
 */

import java.io.{ File, FileNotFoundException, IOException, InputStream, OutputStream, FileInputStream }
import java.net.{ URI, URISyntaxException, URL }
import org.scalacheck._
import Prop._
import sys.process._
import scala.tools.nsc.io.{ File => SFile }

/** This has scrounged bits of sbt to flesh it out enough to run.
 */
package processtest {
  
  object exit
  {
    def fn(code: Int) = System.exit(code)
  	def main(args: Array[String]) = exit.fn(java.lang.Integer.parseInt(args(0)))
  }
  object cat
  {
  	def main(args: Array[String])
  	{
      try {
       if (args.length == 0)
         IO.transfer(System.in, System.out)
       else
         catFiles(args.toList)
       exit.fn(0)
      } catch {
       case e =>
         e.printStackTrace()
         System.err.println("Error: " + e.toString)
         exit.fn(1)
      }
  	}
  	private def catFiles(filenames: List[String]): Option[String] = filenames match {
       case head :: tail =>
         val file = new File(head)
         if (file.isDirectory)
           throw new IOException("Is directory: " + file)
         else if (file.exists) {
           IO.transfer(file, System.out)
           catFiles(tail)
         }
         else
           throw new FileNotFoundException("No such file or directory: " + file)
       case Nil => None
  	}
  }
  object echo
  {
  	def main(args: Array[String])
  	{
  		System.out.println(args.mkString(" "))
  	}
  }
}

object IO {
  def transfer(in: InputStream, out: OutputStream): Unit = BasicIO.transferFully(in, out)
  def transfer(in: File, out: OutputStream): Unit        = BasicIO.transferFully(new FileInputStream(in), out)

	def classLocation(cl: Class[_]): URL = {
		val codeSource = cl.getProtectionDomain.getCodeSource
		if(codeSource == null) sys.error("No class location for " + cl)
		else codeSource.getLocation
	}
	def classLocationFile(cl: Class[_]): File = toFile(classLocation(cl))
	def classLocation[T](implicit mf: Manifest[T]): URL = classLocation(mf.erasure)
	def classLocationFile[T](implicit mf: Manifest[T]): File = classLocationFile(mf.erasure)

	def toFile(url: URL) =
		try { new File(url.toURI) }
		catch { case _: URISyntaxException => new File(url.getPath) }
}

class ProcessSpecification extends Properties("Process I/O") {
	implicit val exitCodeArb: Arbitrary[Array[Byte]] = Arbitrary(Gen.choose(0, 10) flatMap { size =>
	  Gen.resize(size, Arbitrary.arbArray[Byte].arbitrary) 
	})

	/*property("Correct exit code") = forAll( (exitCode: Byte) => checkExit(exitCode))
	property("#&& correct") = forAll( (exitCodes: Array[Byte]) => checkBinary(exitCodes)(_ #&& _)(_ && _))
	property("#|| correct") = forAll( (exitCodes: Array[Byte]) => checkBinary(exitCodes)(_ #|| _)(_ || _))
	property("### correct") = forAll( (exitCodes: Array[Byte]) => checkBinary(exitCodes)(_ ### _)( (x,latest) => latest))*/
	property("Pipe to output file") = forAll( (data: Array[Byte]) => checkFileOut(data))
	property("Pipe to input file") = forAll( (data: Array[Byte]) => checkFileIn(data))
	property("Pipe to process") = forAll( (data: Array[Byte]) => checkPipe(data))

	private def checkBinary(codes: Array[Byte])(reduceProcesses: (ProcessBuilder, ProcessBuilder) => ProcessBuilder)(reduceExit: (Boolean, Boolean) => Boolean) =
	{
		(codes.length > 1) ==>
		{
			val unsignedCodes = codes.map(unsigned)
			val exitCode = unsignedCodes.map(code => Process(process("processtest.exit " + code))).reduceLeft(reduceProcesses) !
			val expectedExitCode = unsignedCodes.map(toBoolean).reduceLeft(reduceExit)
			toBoolean(exitCode) == expectedExitCode
		}
	}
	private def toBoolean(exitCode: Int) = exitCode == 0
	private def checkExit(code: Byte) =
	{
		val exitCode = unsigned(code)
		(process("processtest.exit " + exitCode) !) == exitCode
	}
	private def checkFileOut(data: Array[Byte]) =
	{
		withData(data) { (temporaryFile, temporaryFile2) =>
			val catCommand = process("processtest.cat " + temporaryFile.getAbsolutePath)
			catCommand #> temporaryFile2
		}
	}
	private def checkFileIn(data: Array[Byte]) =
	{
		withData(data) { (temporaryFile, temporaryFile2) =>
			val catCommand = process("processtest.cat")
			temporaryFile #> catCommand #> temporaryFile2
		}
	}
	private def checkPipe(data: Array[Byte]) =
	{
		withData(data) { (temporaryFile, temporaryFile2) =>
			val catCommand = process("processtest.cat")
			temporaryFile #> catCommand #| catCommand #> temporaryFile2
		}
	}
	private def temp() = SFile(File.createTempFile("processtest", ""))
	private def withData(data: Array[Byte])(f: (File, File) => ProcessBuilder) =
	{
		val temporaryFile1 = temp()
		val temporaryFile2 = temp()
		try {
		  temporaryFile1 writeBytes data
			val process = f(temporaryFile1.jfile, temporaryFile2.jfile)
			( process ! ) == 0 &&
			{
				val b1 = temporaryFile1.slurp()
				val b2 = temporaryFile2.slurp()
				b1 == b2
			}
		}
		finally
		{
			temporaryFile1.delete()
			temporaryFile2.delete()
		}
	}
	private def unsigned(b: Byte): Int = ((b: Int) +256) % 256
	private def process(command: String) = {
		val thisClasspath = List(getSource[ScalaObject], getSource[IO.type], getSource[SourceTag]).mkString(File.pathSeparator)
		"java -cp " + thisClasspath + " " + command
	}
	private def getSource[T : Manifest]: String =
		IO.classLocationFile[T].getAbsolutePath
}
private trait SourceTag


object Test extends ProcessSpecification { }