get rid of intellij.build.toolbox.litegen parameter and use BuildOptions.TOOLBOX_LITE...
[idea/community.git] / jps / jps-builders / testSrc / org / jetbrains / jps / incremental / artifacts / ArtifactBuilderTest.kt
1 /*
2  * Copyright 2000-2012 JetBrains s.r.o.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package org.jetbrains.jps.incremental.artifacts
17
18 import com.intellij.openapi.application.ex.PathManagerEx
19 import com.intellij.openapi.util.io.FileUtil
20 import com.intellij.util.PathUtil
21 import com.intellij.util.io.directoryContent
22 import com.intellij.util.io.zipFile
23 import org.jetbrains.jps.builders.CompileScopeTestBuilder
24 import org.jetbrains.jps.incremental.artifacts.LayoutElementTestUtil.archive
25 import org.jetbrains.jps.incremental.artifacts.LayoutElementTestUtil.root
26 import org.jetbrains.jps.incremental.messages.BuildMessage
27 import org.jetbrains.jps.model.java.JavaSourceRootType
28 import org.jetbrains.jps.model.java.JpsJavaExtensionService
29 import org.jetbrains.jps.util.JpsPathUtil
30 import java.io.BufferedOutputStream
31 import java.io.File
32 import java.io.FileOutputStream
33 import java.io.IOException
34 import java.util.jar.JarFile
35 import java.util.zip.CRC32
36 import java.util.zip.ZipEntry
37 import java.util.zip.ZipFile
38 import java.util.zip.ZipOutputStream
39
40 /**
41  * @author nik
42  */
43 class ArtifactBuilderTest : ArtifactBuilderTestCase() {
44   fun testFileCopy() {
45     val a = addArtifact(root().fileCopy(createFile("file.txt", "foo")))
46     buildAll()
47     assertOutput(a, directoryContent { file("file.txt", "foo") })
48   }
49
50   fun testDir() {
51     val a = addArtifact(
52       root()
53         .fileCopy(createFile("abc.txt"))
54           .dir("dir")
55           .fileCopy(createFile("xxx.txt", "bar"))
56     )
57     buildAll()
58     assertOutput(a, directoryContent {
59       file("abc.txt")
60       dir("dir") {
61         file("xxx.txt", "bar")
62       }
63     })
64   }
65
66   fun testArchive() {
67     val a = addArtifact(
68       root()
69         .archive("xxx.zip")
70           .fileCopy(createFile("X.class", "data"))
71           .dir("dir")
72             .fileCopy(createFile("Y.class"))
73     )
74     buildAll()
75     assertOutput(a, directoryContent {
76       zip("xxx.zip") {
77         file("X.class", "data")
78         dir("dir") {
79           file("Y.class")
80         }
81       }
82     })
83   }
84
85   fun testTwoDirsInArchive() {
86     val dir1 = PathUtil.getParentPath(PathUtil.getParentPath(createFile("dir1/a/x.txt")))
87     val dir2 = PathUtil.getParentPath(PathUtil.getParentPath(createFile("dir2/a/y.txt")))
88     val a = addArtifact(
89       root()
90         .archive("a.jar")
91           .dirCopy(dir1)
92           .dirCopy(dir2)
93           .dir("a").fileCopy(createFile("z.txt"))
94     )
95     buildAll()
96     assertOutput(a, directoryContent {
97       zip("a.jar") {
98         dir("a") {
99           file("x.txt")
100           file("y.txt")
101           file("z.txt")
102         }
103       }
104     })
105   }
106
107   fun testArchiveInArchive() {
108     val a = addArtifact(
109       root()
110         .archive("a.jar")
111         .archive("b.jar")
112         .fileCopy(createFile("xxx.txt", "foo"))
113     )
114     buildAll()
115     assertOutput(a, directoryContent {
116       zip("a.jar") {
117         zip("b.jar") {
118           file("xxx.txt", "foo")
119         }
120       }
121     })
122   }
123
124   fun testIncludedArtifact() {
125     val included = addArtifact("included",
126                                root()
127                                  .fileCopy(createFile("aaa.txt")))
128     val a = addArtifact(
129       root()
130         .dir("dir")
131         .artifact(included)
132         .end()
133         .fileCopy(createFile("bbb.txt"))
134     )
135     buildAll()
136
137     assertOutput(included, directoryContent { file("aaa.txt") })
138     assertOutput(a, directoryContent {
139       dir("dir") {
140         file("aaa.txt")
141       }
142       file("bbb.txt")
143   })
144   }
145
146   fun testMergeDirectories() {
147     val included = addArtifact("included",
148                                root().dir("dir").fileCopy(createFile("aaa.class")))
149     val a = addArtifact(
150       root()
151         .artifact(included)
152         .dir("dir")
153         .fileCopy(createFile("bbb.class")))
154     buildAll()
155     assertOutput(a, directoryContent {
156       dir("dir") {
157         file("aaa.class")
158         file("bbb.class")
159       }
160     })
161   }
162
163   fun testCopyLibrary() {
164     val library = addProjectLibrary("lib", createFile("lib/a.jar"))
165     val a = addArtifact(root().lib(library))
166     buildAll()
167     assertOutput(a, directoryContent { file("a.jar") })
168   }
169
170   fun testModuleOutput() {
171     val file = createFile("src/A.java", "public class A {}")
172     val module = addModule("a", PathUtil.getParentPath(file))
173     val artifact = addArtifact(root().module(module))
174
175     buildArtifacts(artifact)
176     assertOutput(artifact, directoryContent { file("A.class") })
177   }
178
179   fun testModuleSources() {
180     val file = createFile("src/A.java", "class A{}")
181     val testFile = createFile("tests/ATest.java", "class ATest{}")
182     val m = addModule("m", PathUtil.getParentPath(file))
183     m.addSourceRoot(JpsPathUtil.pathToUrl(PathUtil.getParentPath(testFile)), JavaSourceRootType.TEST_SOURCE)
184     val a = addArtifact(root().moduleSource(m))
185     buildAll()
186     assertOutput(a, directoryContent {
187       file("A.java")
188     })
189
190     val b = createFile("src/B.java", "class B{}")
191
192     buildAll()
193     assertOutput(a, directoryContent {
194       file("A.java")
195       file("B.java")
196     })
197
198     delete(b)
199     buildAll()
200     assertOutput(a, directoryContent {
201       file("A.java")
202     })
203   }
204
205   fun testModuleSourcesWithPackagePrefix() {
206     val file = createFile("src/A.java", "class A{}")
207     val m = addModule("m", PathUtil.getParentPath(file))
208     val sourceRoot = assertOneElement(m.sourceRoots)
209     val typed = sourceRoot.asTyped(JavaSourceRootType.SOURCE)
210     assertNotNull(typed)
211     typed!!.properties.packagePrefix = "org.foo"
212
213     val a = addArtifact(root().moduleSource(m))
214     buildAll()
215     assertOutput(a, directoryContent {
216       dir("org") {
217         dir("foo") {
218           file("A.java")
219         }
220       }
221     })
222   }
223
224   fun testCopyResourcesFromModuleOutput() {
225     val file = createFile("src/a.xml", "")
226     JpsJavaExtensionService.getInstance().getOrCreateCompilerConfiguration(myProject).addResourcePattern("*.xml")
227     val module = addModule("a", PathUtil.getParentPath(file))
228     val artifact = addArtifact(root().module(module))
229     buildArtifacts(artifact)
230     assertOutput(artifact, directoryContent { file("a.xml") })
231   }
232
233   fun testIgnoredFile() {
234     val file = createFile("a/.svn/a.txt")
235     createFile("a/svn/b.txt")
236     val a = addArtifact(root().parentDirCopy(PathUtil.getParentPath(file)))
237     buildAll()
238     assertOutput(a, directoryContent { dir("svn") { file("b.txt") }})
239   }
240
241   fun testIgnoredFileInArchive() {
242     val file = createFile("a/.svn/a.txt")
243     createFile("a/svn/b.txt")
244     val a = addArtifact(archive("a.jar").parentDirCopy(PathUtil.getParentPath(file)))
245     buildAll()
246     assertOutput(a, directoryContent { zip("a.jar") { dir("svn") { file("b.txt")}}})
247   }
248
249   fun testCopyExcludedFolder() {
250     //explicitly added excluded files should be copied (e.g. compile output)
251     val file = createFile("xxx/excluded/a.txt")
252     createFile("xxx/excluded/CVS")
253     val excluded = PathUtil.getParentPath(file)
254     val dir = PathUtil.getParentPath(excluded)
255
256     val module = addModule("myModule")
257     module.contentRootsList.addUrl(JpsPathUtil.pathToUrl(dir))
258     module.excludeRootsList.addUrl(JpsPathUtil.pathToUrl(excluded))
259
260     val a = addArtifact(root().dirCopy(excluded))
261     buildAll()
262     assertOutput(a, directoryContent { file("a.txt") })
263   }
264
265   fun testCopyExcludedFile() {
266     //excluded files under non-excluded directory should not be copied
267     val file = createFile("xxx/excluded/a.txt")
268     createFile("xxx/b.txt")
269     createFile("xxx/CVS")
270     val dir = PathUtil.getParentPath(PathUtil.getParentPath(file))
271
272     val module = addModule("myModule")
273     module.contentRootsList.addUrl(JpsPathUtil.pathToUrl(dir))
274     module.excludeRootsList.addUrl(JpsPathUtil.pathToUrl(PathUtil.getParentPath(file)))
275
276     val a = addArtifact(root().dirCopy(dir))
277     buildAll()
278     assertOutput(a, directoryContent { file("b.txt") })
279   }
280
281   fun testExtractDirectory() {
282     val jarFile = createXJarFile()
283     val a = addArtifact("a", root().dir("dir").extractedDir(jarFile, "/dir"))
284     buildAll()
285     assertOutput(a, directoryContent {
286       dir("dir") {
287         file("file.txt", "text")
288       }
289     })
290   }
291
292   @Throws(IOException::class)
293   fun testExtractDirectoryFromExcludedJar() {
294     val jarPath = createFile("dir/lib/j.jar")
295     val libDir = File(getOrCreateProjectDir(), "dir/lib")
296     directoryContent {
297       zip("j.jar") {
298         file("a.txt", "a")
299       }
300     }.generate(libDir)
301     val module = addModule("m")
302     val libDirPath = FileUtil.toSystemIndependentName(libDir.absolutePath)
303     module.contentRootsList.addUrl(JpsPathUtil.pathToUrl(PathUtil.getParentPath(libDirPath)))
304     module.excludeRootsList.addUrl(JpsPathUtil.pathToUrl(libDirPath))
305     val a = addArtifact("a", root().extractedDir(jarPath, ""))
306     buildAll()
307     assertOutput(a, directoryContent {
308       file("a.txt", "a")
309     })
310   }
311
312   fun testPackExtractedDirectory() {
313     val zipPath = createXJarFile()
314     val a = addArtifact("a", root().archive("a.jar").extractedDir(zipPath, "/dir"))
315     buildAll()
316     assertOutput(a, directoryContent { zip("a.jar") {
317       file("file.txt", "text")
318     }})
319   }
320
321   fun `test no duplicated directory entries for extracted directory packed into JAR file`() {
322     val zipPath = createXJarFile()
323     val a = addArtifact("a", root().archive("a.jar").extractedDir(zipPath, ""))
324     buildAll()
325     ZipFile(File(a.outputPath, "a.jar")).use {
326       assertNotNull(it.getEntry("dir/"))
327       assertNull(it.getEntry("dir//"))
328     }
329   }
330
331   private fun createXJarFile(): String {
332     val zipFile = zipFile {
333       dir("dir") {
334         file("file.txt", "text")
335       }
336     }.generateInTempDir()
337     return FileUtil.toSystemIndependentName(zipFile.absolutePath)
338   }
339
340   fun testSelfIncludingArtifact() {
341     val a = addArtifact("a", root().fileCopy(createFile("a.txt")))
342     LayoutElementTestUtil.addArtifactToLayout(a, a)
343     assertBuildFailed(a)
344   }
345
346   fun testCircularInclusion() {
347     val a = addArtifact("a", root().fileCopy(createFile("a.txt")))
348     val b = addArtifact("b", root().fileCopy(createFile("b.txt")))
349     LayoutElementTestUtil.addArtifactToLayout(a, b)
350     LayoutElementTestUtil.addArtifactToLayout(b, a)
351     assertBuildFailed(a)
352     assertBuildFailed(b)
353   }
354
355   fun testArtifactContainingSelfIncludingArtifact() {
356     val c = addArtifact("c", root().fileCopy(createFile("c.txt")))
357     val a = addArtifact("a", root().artifact(c).fileCopy(createFile("a.txt")))
358     LayoutElementTestUtil.addArtifactToLayout(a, a)
359     val b = addArtifact("b", root().artifact(a).fileCopy(createFile("b.txt")))
360
361     buildArtifacts(c)
362     assertBuildFailed(b)
363     assertBuildFailed(a)
364   }
365
366   fun testArtifactContainingSelfIncludingArtifactWithoutOutput() {
367     val a = addArtifact("a", root().fileCopy(createFile("a.txt")))
368     LayoutElementTestUtil.addArtifactToLayout(a, a)
369     val b = addArtifact("b", root().artifact(a))
370     a.outputPath = null
371
372     assertBuildFailed(b)
373   }
374
375   //IDEA-73893
376   @Throws(IOException::class)
377   fun testManifestFileIsFirstEntry() {
378     val firstFile = createFile("src/A.txt")
379     val manifestFile = createFile("src/MANIFEST.MF")
380     val lastFile = createFile("src/Z.txt")
381     val a = addArtifact(archive("a.jar").dir("META-INF")
382                           .fileCopy(firstFile).fileCopy(manifestFile).fileCopy(lastFile))
383     buildArtifacts(a)
384     val jarPath = a.outputPath!! + "/a.jar"
385     val jarFile = JarFile(File(jarPath))
386     jarFile.use {
387       val entries = it.entries()
388       assertTrue(entries.hasMoreElements())
389       val firstEntry = entries.nextElement()
390       assertEquals(JarFile.MANIFEST_NAME, firstEntry.name)
391     }
392   }
393
394   @Throws(IOException::class)
395   fun testPreserveCompressionMethodForEntryExtractedFromOneArchiveAndPackedIntoAnother() {
396     val path = createFile("data/a.jar")
397     val output = ZipOutputStream(BufferedOutputStream(FileOutputStream(File(path))))
398     try {
399       val entry = ZipEntry("a.txt")
400       val text = "text".toByteArray()
401       entry.method = ZipEntry.STORED
402       entry.size = text.size.toLong()
403       val crc32 = CRC32()
404       crc32.update(text)
405       entry.crc = crc32.value
406       output.putNextEntry(entry)
407       output.write(text)
408       output.closeEntry()
409     }
410     catch (e: Exception) {
411       e.printStackTrace()
412     }
413     finally {
414       output.close()
415     }
416     val a = addArtifact(archive("b.jar").extractedDir(path, ""))
417     buildAll()
418     assertOutput(a, directoryContent { zip("b.jar") { file("a.txt", "text") }})
419
420     val jarPath = a.outputPath!! + "/b.jar"
421     val zipFile = ZipFile(File(jarPath))
422     zipFile.use {
423       val entry = it.getEntry("a.txt")
424       assertNotNull(entry)
425       assertEquals(ZipEntry.STORED, entry.method)
426     }
427   }
428
429   fun testProperlyReportValueWithInvalidCrcInRepackedFile() {
430     val corruptedJar = PathManagerEx.findFileUnderCommunityHome(
431       "jps/jps-builders/testData/output/corruptedJar/incorrect-crc.jar")!!.absolutePath
432     val a = addArtifact(archive("a.jar").extractedDir(corruptedJar, ""))
433     val result = doBuild(CompileScopeTestBuilder.rebuild().artifacts(a))
434     result.assertFailed()
435     val message = result.getMessages(BuildMessage.Kind.ERROR).first()
436     assertTrue(message.messageText, message.messageText.contains("incorrect-crc.jar"));
437   }
438
439   fun testBuildModuleBeforeArtifactIfSomeDirectoryInsideModuleOutputIsCopiedToArtifact() {
440     val src = PathUtil.getParentPath(PathUtil.getParentPath(createFile("src/x/A.java", "package x; class A{}")))
441     val module = addModule("m", src)
442     val output = JpsJavaExtensionService.getInstance().getOutputDirectory(module, false)
443     val artifact = addArtifact(root().dirCopy(File(output, "x").absolutePath))
444     rebuildAllModulesAndArtifacts()
445     assertOutput(module, directoryContent { dir("x") { file("A.class") }})
446     assertOutput(artifact, directoryContent { file("A.class") })
447   }
448
449   fun testClearOutputOnRebuild() {
450     val file = createFile("d/a.txt")
451     val a = addArtifact(root().parentDirCopy(file))
452     buildAll()
453     createFileInArtifactOutput(a, "b.txt")
454     buildAllAndAssertUpToDate()
455     assertOutput(a, directoryContent {
456       file("a.txt")
457       file("b.txt")
458     })
459
460     rebuildAllModulesAndArtifacts()
461     assertOutput(a, directoryContent {
462       file("a.txt")
463       file("b.txt")
464     })
465   }
466
467   fun testDeleteOnlyOutputFileOnRebuildForArchiveArtifact() {
468     val file = createFile("a.txt")
469     val a = addArtifact(archive("a.jar").fileCopy(file))
470     buildAll()
471     createFileInArtifactOutput(a, "b.txt")
472     buildAllAndAssertUpToDate()
473     assertOutput(a, directoryContent {
474       zip("a.jar") { file("a.txt") }
475       file("b.txt")
476     })
477
478     rebuildAllModulesAndArtifacts()
479     assertOutput(a, directoryContent {
480       zip("a.jar") { file("a.txt") }
481       file("b.txt")
482     })
483   }
484
485   fun testDoNotCreateEmptyArchive() {
486     val file = createFile("dir/a.txt")
487     val a = addArtifact(archive("a.jar").parentDirCopy(file))
488     delete(file)
489     buildAll()
490     assertEmptyOutput(a)
491   }
492
493   fun testDoNotCreateEmptyArchiveInsideArchive() {
494     val file = createFile("dir/a.txt")
495     val a = addArtifact(archive("a.jar").archive("inner.jar").parentDirCopy(file))
496     delete(file)
497     buildAll()
498     assertEmptyOutput(a)
499   }
500
501   fun testDoNotCreateEmptyArchiveFromExtractedDirectory() {
502     val jarFile = createXJarFile()
503     val a = addArtifact("a", archive("a.jar").dir("dir").extractedDir(jarFile, "/xxx/"))
504     buildAll()
505     assertEmptyOutput(a)
506   }
507
508   fun testExtractNonExistentJarFile() {
509     val a = addArtifact(root().extractedDir("this-file-does-not-exist.jar", "/"))
510     buildAll()
511     assertEmptyOutput(a)
512   }
513
514   fun testRepackNonExistentJarFile() {
515     val a = addArtifact(archive("a.jar").extractedDir("this-file-does-not-exist.jar", "/").fileCopy(createFile("a.txt")))
516     buildAll()
517     assertOutput(a, directoryContent { zip("a.jar") {file("a.txt")}})
518   }
519 }