summaryrefslogtreecommitdiff
path: root/test/files/run/various-flat-classpath-types.scala
blob: bc54ffb6cce2c1466ff594872e51628856986468 (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
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
/*
 * Copyright (c) 2014 Contributor. All rights reserved.
 */

import java.io.{File => JFile, FileInputStream, FileOutputStream}
import java.util.zip.{ZipEntry, ZipOutputStream}
import scala.reflect.io.{Directory, File}
import scala.tools.nsc.util.ClassPath.RootPackage
import scala.tools.nsc.classpath.PackageNameUtils
import scala.tools.nsc.io.Jar

/**
 * Generates directories, jars and zip files containing sources and classes
 * (the result of a compilation which is executed here)
 * and use them as a class- and sourcepath during compilation and running
 * created application. At the end everything is cleaned up.
 *
 * It can test also current, recursive classpath. Just right now we force
 * flat classpath to test it also when the recursive one would be set as a default.
 */
object Test {

  private implicit class JFileOps(file: JFile) {

    def createDir(newDirName: String) = {
      val newDir = new JFile(file, newDirName)
      newDir.mkdir()
      newDir
    }

    def createSrcFile(newFileName: String) = createFile(newFileName + ".scala")

    def createFile(fullFileName: String) = {
      val newFile = new JFile(file, fullFileName)
      newFile.createNewFile()
      newFile
    }

    def writeAll(text: String): Unit = File(file) writeAll text

    def moveContentToZip(zipName: String): Unit = {
      val newZip = zipsDir createFile s"$zipName.zip"
      val outputStream = new ZipOutputStream(new FileOutputStream(newZip))

      def addFileToZip(dirPrefix: String = "")(fileToAdd: JFile): Unit =
        if (fileToAdd.isDirectory) {
          val dirEntryName = fileToAdd.getName + "/"
          outputStream.putNextEntry(new ZipEntry(dirEntryName))
          fileToAdd.listFiles() foreach addFileToZip(dirEntryName)
        } else {
          val inputStream = new FileInputStream(fileToAdd)
          outputStream.putNextEntry(new ZipEntry(dirPrefix + fileToAdd.getName))

          val buffer = new Array[Byte](1024)
          var count = inputStream.read(buffer)
          while (count > 0) {
            outputStream.write(buffer, 0, count)
            count = inputStream.read(buffer)
          }

          inputStream.close()
        }

      file.listFiles() foreach addFileToZip()
      outputStream.close()

      cleanDir(file)
    }

    def moveContentToJar(jarName: String): Unit = {
      val newJar = jarsDir createFile s"$jarName.jar"
      Jar.create(file = File(newJar), sourceDir = Directory(file), mainClass = "won't be used")
      cleanDir(file)
    }

    def path: String = file.getAbsolutePath
  }

  private case class DirRep(name: String, nestedDirs: Seq[DirRep] = Nil, sourceFiles: Seq[String] = Nil)

  private val compiler = new scala.tools.nsc.MainClass
  private val appRunner = new scala.tools.nsc.MainGenericRunner
  private val javaClassPath = sys.props("java.class.path")

  // creates a test dir in a temporary dir containing compiled files of this test
  // root dir will be automatically deleted after the end of test
  private val rootDir = new JFile(sys.props("partest.output"))
  private val testDir = rootDir createDir s"cp-tests-${System.currentTimeMillis()}"

  private val jarsDir = testDir createDir "jars"
  private val zipsDir = testDir createDir "zips"
  private val srcDir = testDir createDir "src"
  private val binDir = testDir createDir "bin"
  private val outDir = testDir createDir "out"

  def main(args: Array[String]): Unit = {
    createClassesZipInZipsDir()
    createClassesJarInJarsDir()
    createClassesInBinDir()
    createSourcesZipInZipsDir()
    createSourcesJarInJarsDir()
    createSourcesInSrcDir()
    compileFinalApp()
    runApp()
    // at the end all created files will be deleted automatically
  }

  private def createClassesZipInZipsDir(): Unit = {
    val baseFileName = "ZipBin"
    createStandardSrcHierarchy(baseFileName)
    compileSrc(baseFileName)
    outDir moveContentToZip "Bin"
    cleanDir(srcDir)
  }

  private def createClassesJarInJarsDir(): Unit = {
    val baseFileName = "JarBin"
    createStandardSrcHierarchy(baseFileName)
    compileSrc(baseFileName)
    outDir moveContentToJar "Bin"
    cleanDir(srcDir)
  }

  private def createClassesInBinDir(): Unit = {
    val baseFileName = "DirBin"
    createStandardSrcHierarchy(baseFileName)
    compileSrc(baseFileName, destination = binDir)
    cleanDir(srcDir)
  }

  private def createSourcesZipInZipsDir(): Unit = {
    createStandardSrcHierarchy(baseFileName = "ZipSrc")
    srcDir moveContentToZip "Src"
  }

  private def createSourcesJarInJarsDir(): Unit = {
    createStandardSrcHierarchy(baseFileName = "JarSrc")
    srcDir moveContentToJar "Src"
  }

  private def createSourcesInSrcDir(): Unit = {
    createStandardSrcHierarchy(baseFileName = "DirSrc")

    val appFile = srcDir createSrcFile "Main"
    appFile writeAll s"""import nested._
         | object Main extends App {
         |   println(new ZipBin)
         |   println(new JarBin)
         |   println(new DirBin)
         |   println(new ZipSrc)
         |   println(new JarSrc)
         |   println(new DirSrc)
         |
         |   println(new NestedZipBin)
         |   println(new NestedJarBin)
         |   println(new NestedDirBin)
         |   println(new NestedZipSrc)
         |   println(new NestedJarSrc)
         |   println(new NestedDirSrc)
         | }
       """.stripMargin
  }

  private def compileFinalApp(): Unit = {
    val classPath = mkPath(javaClassPath, binDir.path, zipsDir.path + "/Bin.zip", jarsDir.path + "/Bin.jar")
    val sourcePath = mkPath(srcDir.path, zipsDir.path + "/Src.zip", jarsDir.path + "/Src.jar")

    compiler.process(Array("-cp", classPath, "-sourcepath", sourcePath,
      "-d", outDir.path, s"${srcDir.path}/Main.scala"))
  }

  private def runApp(): Unit = {
    val classPath = mkPath(javaClassPath, outDir.path, binDir.path, zipsDir.path + "/Bin.zip", jarsDir.path + "/Bin.jar")
    appRunner.process(Array("-cp", classPath, "Main"))
  }

  private def createStandardSrcHierarchy(baseFileName: String): Unit =
    createSources(RootPackage, srcDir,
      DirRep("",
        nestedDirs = Seq(DirRep("nested", sourceFiles = Seq("Nested" + baseFileName))),
        sourceFiles = Seq(baseFileName)
      )
    )

  private def createSources(pkg: String, dirFile: JFile, dirRep: DirRep): Unit = {
    dirRep.nestedDirs foreach { rep =>
      val nestedDir = dirFile createDir rep.name
      val nestedPkg = PackageNameUtils.packagePrefix(pkg) + rep.name
      createSources(nestedPkg, nestedDir, rep)
    }

    val pkgHeader = if (pkg == RootPackage) "" else s"package $pkg\n\n"
    dirRep.sourceFiles foreach { srcName =>
      val text = s"""${pkgHeader}case class $srcName(x: String = "")"""
      val srcFile = dirFile createSrcFile srcName
      srcFile writeAll text
    }
  }

  private def compileSrc(baseFileName: String, destination: JFile = outDir): Unit = {
    val srcDirPath = srcDir.path
    compiler.process(Array("-cp", javaClassPath, "-d", destination.path,
      s"$srcDirPath/$baseFileName.scala", s"$srcDirPath/nested/Nested$baseFileName.scala"))
  }

  private def cleanDir(dir: JFile): Unit =
    dir.listFiles().foreach { file =>
      if (file.isDirectory) cleanDir(file)
      file.delete()
    }

  private def mkPath(pathEntries: String*) = pathEntries.mkString(File.pathSeparator)
}