<commit_before>/*
 * Copyright 2011-2017 <NAME>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package eu.cdevreeze.yaidom.meta

import java.io.File

import org.junit.Test
import org.junit.runner.RunWith
import org.scalatest.FunSuite
import org.scalatest.junit.JUnitRunner

import scala.collection.immutable
import scala.meta._

/**
 * Test case checking for unidirectional package dependencies in yaidom, by inspecting import statements.
 *
 * @author <NAME>
 */
@RunWith(classOf[JUnitRunner])
class PackageDependencyTest extends FunSuite {

  private val mainScalaDir: File = {
    val euDir = new File(classOf[PackageDependencyTest].getResource("/eu").toURI)
    assert(euDir.isDirectory)
    val testClassDir = euDir.getParentFile
    assert(testClassDir.isDirectory)
    val projDir = getProjectDir(testClassDir)
    val resultDir = new File(projDir, "src/main/scala")
    resultDir.ensuring(_.isDirectory)
  }

  test("testParentPackage") {
    testPackageDependencies(None, Set(), Set())
  }

  test("testCorePackage") {
    testPackageDependencies(Some("core"), Set(), Set())
  }

  test("testQueryApiPackage") {
    testPackageDependencies(
      Some("queryapi"),
      Set("core"),
      Set("core"))
  }

  test("testResolvedPackage") {
    testPackageDependencies(
      Some("resolved"),
      Set("core", "queryapi"),
      Set("core", "queryapi"))
  }

  test("testSimplePackage") {
    testPackageDependencies(
      Some("simple"),
      Set("core", "queryapi", "resolved"),
      Set("core", "queryapi", "resolved"))
  }

  test("testIndexedPackage") {
    testPackageDependencies(
      Some("indexed"),
      Set("core", "queryapi", "resolved", "simple"),
      Set("core", "queryapi", "resolved", "simple"))
  }

  test("testConvertPackage") {
    testPackageDependencies(
      Some("convert"),
      Set("core", "simple"),
      Set("core", "queryapi", "resolved", "simple"))
  }

  test("testParsePackage") {
    testPackageDependencies(
      Some("parse"),
      Set("convert", "simple"),
      Set("core", "queryapi", "resolved", "simple", "convert"))
  }

  test("testPrintPackage") {
    testPackageDependencies(
      Some("print"),
      Set("convert", "simple"),
      Set("core", "queryapi", "resolved", "simple", "convert"))
  }

  test("testDomPackage") {
    testPackageDependencies(
      Some("dom"),
      Set("core", "queryapi", "resolved", "convert"),
      Set("core", "queryapi", "resolved", "convert"))
  }

  test("testScalaXmlPackage") {
    testPackageDependencies(
      Some("scalaxml"),
      Set("core", "queryapi", "resolved", "convert"),
      Set("core", "queryapi", "resolved", "convert"))
  }

  private def testPackageDependencies(
    yaidomSubPackageOption: Option[String],
    minimalSubPackages: Set[String],
    allowedSubPackages: Set[String]): Unit = {

    require(minimalSubPackages.subsetOf(allowedSubPackages))

    val dir =
      if (yaidomSubPackageOption.isEmpty) {
        new File(mainScalaDir, "eu/cdevreeze/yaidom")
      } else {
        new File(new File(mainScalaDir, "eu/cdevreeze/yaidom"), yaidomSubPackageOption.get)
      }

    val sources = findSourcesInDir(dir)
    val importers = sources.flatMap(source => findImporters(source))

    val usedYaidomSubpackages: Set[String] = importers.flatMap(i => usedYaidomSubPackages(i)).toSet

    assertResult(Set.empty) {
      usedYaidomSubpackages.diff(allowedSubPackages)
    }
    assertResult(Set.empty) {
      minimalSubPackages.diff(usedYaidomSubpackages)
    }
  }

  private def findSourcesInDir(dir: File): immutable.IndexedSeq[Source] = {
    require(dir.isDirectory)
    val sourceFiles = dir.listFiles.toVector.filter(f => f.isFile && f.getName.endsWith(".scala"))
    sourceFiles.map(f => f.parse[Source].get)
  }

  private def findImporters(source: Source): immutable.Seq[Importer] = {
    source collect { case i: Importer => i }
  }

  private def isYaidomImporter(importer: Importer): Boolean = {
    val termNames = importer collect { case tn: Term.Name => tn }

    termNames.take(3).map(_.structure) ==
      List(Term.Name("eu"), Term.Name("cdevreeze"), Term.Name("yaidom")).map(_.structure)
  }

  private def usedYaidomSubPackages(importer: Importer): Set[String] = {
    if (isYaidomImporter(importer)) {
      val termNames = importer collect { case tn: Term.Name => tn }

      val termNameOption = termNames.drop(3).headOption

      termNameOption match {
        case Some(name) if yaidomSubPackages.contains(name.value.trim) => Set(name.value.trim)
        case Some(name) => Set()
        case None =>
          importer.importees.flatMap(_.collect({ case n: Name if yaidomSubPackages.contains(n.value) => n.value })).toSet
      }
    } else {
      Set()
    }
  }

  private val yaidomSubPackages: Set[String] = {
    Set("convert", "core", "dom", "indexed", "java8", "parse", "print", "queryapi", "resolved", "scalaxml", "simple", "utils")
  }

  private def getProjectDir(dir: File): File = {
    require((dir ne null) && dir.isDirectory, s"Expected directory '${dir}' but this is not a directory")

    if (dir.getName == "yaidom") {
      dir
    } else {<commit_msg>Enhanced and improved PackageDependencyTest<commit_after>/*
 * Copyright 2011-2017 <NAME>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package eu.cdevreeze.yaidom.meta

import java.io.File

import org.junit.Test
import org.junit.runner.RunWith
import org.scalatest.FunSuite
import org.scalatest.junit.JUnitRunner

import scala.collection.immutable
import scala.meta._

/**
 * Test case checking for unidirectional package dependencies in yaidom, by inspecting import statements.
 *
 * @author <NAME>
 */
@RunWith(classOf[JUnitRunner])
class PackageDependencyTest extends FunSuite {

  /**
   * Sub-package of yaidom, for example List("core") or List("java8", "indexed").
   */
  type SubPackage = List[String]

  private val mainScalaDir: File = {
    val euDir = new File(classOf[PackageDependencyTest].getResource("/eu").toURI)
    assert(euDir.isDirectory)
    val testClassDir = euDir.getParentFile
    assert(testClassDir.isDirectory)
    val projDir = getProjectDir(testClassDir)
    val resultDir = new File(projDir, "src/main/scala")
    resultDir.ensuring(_.isDirectory)
  }

  test("testParentPackage") {
    testPackageDependencies(None, Set(), Set())
  }

  test("testCorePackage") {
    testPackageDependencies(Some(List("core")), Set(), Set())
  }

  test("testQueryApiPackage") {
    testPackageDependencies(
      Some(List("queryapi")),
      Set(List("core")),
      Set(List("core")))
  }

  test("testResolvedPackage") {
    testPackageDependencies(
      Some(List("resolved")),
      Set(List("core"), List("queryapi")),
      Set(List("core"), List("queryapi")))
  }

  test("testSimplePackage") {
    testPackageDependencies(
      Some(List("simple")),
      Set(List("core"), List("queryapi"), List("resolved")),
      Set(List("core"), List("queryapi"), List("resolved")))
  }

  test("testIndexedPackage") {
    testPackageDependencies(
      Some(List("indexed")),
      Set(List("core"), List("queryapi"), List("resolved"), List("simple")),
      Set(List("core"), List("queryapi"), List("resolved"), List("simple")))
  }

  test("testConvertPackage") {
    testPackageDependencies(
      Some(List("convert")),
      Set(List("core"), List("simple")),
      Set(List("core"), List("queryapi"), List("resolved"), List("simple")))
  }

  test("testParsePackage") {
    testPackageDependencies(
      Some(List("parse")),
      Set(List("convert"), List("simple")),
      Set(List("core"), List("queryapi"), List("resolved"), List("simple"), List("convert")))
  }

  test("testPrintPackage") {
    testPackageDependencies(
      Some(List("print")),
      Set(List("convert"), List("simple")),
      Set(List("core"), List("queryapi"), List("resolved"), List("simple"), List("convert")))
  }

  test("testDomPackage") {
    testPackageDependencies(
      Some(List("dom")),
      Set(List("core"), List("queryapi"), List("resolved"), List("convert")),
      Set(List("core"), List("queryapi"), List("resolved"), List("convert")))
  }

  test("testScalaXmlPackage") {
    testPackageDependencies(
      Some(List("scalaxml")),
      Set(List("core"), List("queryapi"), List("resolved"), List("convert")),
      Set(List("core"), List("queryapi"), List("resolved"), List("convert")))
  }

  test("testJava8Package") {
    testPackageDependencies(
      Some(List("java8")),
      Set(List("core")),
      Set(List("core"), List("queryapi"), List("resolved"), List("convert")))
  }

  test("testJava8QueryApiPackage") {
    testPackageDependencies(
      Some(List("java8", "queryapi")),
      Set(List("core"), List("java8")),
      Set(List("core"), List("java8"), List("queryapi"), List("resolved"), List("convert")))
  }

  test("testJava8SimpleElemPackage") {
    testPackageDependencies(
      Some(List("java8", "simpleelem")),
      Set(List("core"), List("java8"), List("java8", "queryapi"), List("simple")),
      Set(List("core"), List("java8"), List("java8", "queryapi"), List("simple"), List("queryapi"), List("resolved"), List("convert")))
  }

  test("testJava8IndexedElemPackage") {
    testPackageDependencies(
      Some(List("java8", "indexedelem")),
      Set(List("core"), List("java8"), List("java8", "queryapi"), List("indexed")),
      Set(List("core"), List("java8"), List("java8", "queryapi"), List("indexed"), List("queryapi"), List("resolved"), List("convert")))
  }

  test("testJava8ScalaXmlElemPackage") {
    testPackageDependencies(
      Some(List("java8", "scalaxmlelem")),
      Set(List("core"), List("java8"), List("java8", "queryapi"), List("scalaxml")),
      Set(List("core"), List("java8"), List("java8", "queryapi"), List("scalaxml"), List("queryapi"), List("resolved"), List("convert")))
  }

  test("testJava8DomElemPackage") {
    testPackageDependencies(
      Some(List("java8", "domelem")),
      Set(List("core"), List("java8"), List("java8", "queryapi"), List("dom")),
      Set(List("core"), List("java8"), List("java8", "queryapi"), List("dom"), List("queryapi"), List("resolved"), List("convert")))
  }

  test("testJava8ResolvedElemPackage") {
    testPackageDependencies(
      Some(List("java8", "resolvedelem")),
      Set(List("core"), List("java8"), List("java8", "queryapi"), List("resolved")),
      Set(List("core"), List("java8"), List("java8", "queryapi"), List("resolved"), List("queryapi"), List("convert")))
  }

  private def testPackageDependencies(
    yaidomSubPackageOption: Option[SubPackage],
    minimalSubPackages: Set[SubPackage],
    allowedSubPackages: Set[SubPackage]): Unit = {

    require(minimalSubPackages.subsetOf(allowedSubPackages))

    val dir =
      if (yaidomSubPackageOption.isEmpty) {
        new File(mainScalaDir, "eu/cdevreeze/yaidom")
      } else {
        new File(new File(mainScalaDir, "eu/cdevreeze/yaidom"), yaidomSubPackageOption.get.mkString("/"))
      }

    val sources = findSourcesInDir(dir)
    val importers = sources.flatMap(source => findImporters(source))

    val usedYaidomSubpackages: Set[SubPackage] = importers.flatMap(i => usedYaidomSubPackages(i)).toSet

    assertResult(Set.empty) {
      usedYaidomSubpackages.diff(allowedSubPackages)
    }
    assertResult(Set.empty) {
      minimalSubPackages.diff(usedYaidomSubpackages)
    }
  }

  private def findSourcesInDir(dir: File): immutable.IndexedSeq[Source] = {
    require(dir.isDirectory)
    val sourceFiles = dir.listFiles.toVector.filter(f => f.isFile && f.getName.endsWith(".scala"))
    sourceFiles.map(f => f.parse[Source].get)
  }

  private def findImporters(source: Source): immutable.Seq[Importer] = {
    source collect { case i: Importer => i }
  }

  private def isYaidomImporter(importer: Importer): Boolean = {
    val termNames = importer.ref collect { case tn: Term.Name => tn }

    termNames.take(3).map(_.structure) ==
      List(Term.Name("eu"), Term.Name("cdevreeze"), Term.Name("yaidom")).map(_.structure)
  }

  private def usedYaidomSubPackages(importer: Importer): Set[SubPackage] = {
    if (isYaidomImporter(importer)) {
      val termNames = importer.ref collect { case tn: Term.Name => tn }

      val termNamesAfterYaidom: List[Name] = termNames.drop(3)

      val importeeNames: Seq[Name] =
        importer.importees.flatMap(_.collect({ case n: Name => n }))

      val nameListsAfterYaidom: Seq[List[Name]] =
        importeeNames.map(name => termNamesAfterYaidom ::: List(name))

      val nameValueListsAfterYaidom: Seq[List[String]] =
        nameListsAfterYaidom.map(names => names.map(_.value))

      yaidomSubPackages.filter(subPkg => nameValueListsAfterYaidom.exists(names => names.startsWith(subPkg)))
    } else {
      Set()
    }
  }

  private val yaidomSubPackages: Set[SubPackage] = {
    Set(
      List("convert"),
      List("core"),
      List("dom"),
      List("indexed"),
      List("java8"),
      List("java8", "domelem"),
      List("java8", "indexedelem"),
      List("java8", "queryapi"),
      List("java8", "resolvedelem"),
      List("java8", "scalaxmlelem"),
      List("java8", "simpleelem"),
      List("parse"),
      List("print"),
      List("queryapi"),
      List("resolved"),
      List("scalaxml"),
      List("simple"),
      List("utils"))
  }

  private def getProjectDir(dir: File): File = {
    require((dir ne null) && dir.isDirectory, s"Expected directory '${dir}' but this is not a directory")

    if (dir.getName == "yaidom") {
      dir
    } else {
{'fraction_non_alphanumeric': 0.16304572729153735, 'fraction_numerical': 0.005034829988275053, 'mean_word_length': 4.094869992972593, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 30, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 8}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6891078', 'n_tokens_mistral': 4590, 'n_tokens_neox': 4458, 'n_words': 916}