diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml index bf1bc10f3..cfd23f546 100644 --- a/.github/workflows/gradle.yml +++ b/.github/workflows/gradle.yml @@ -33,6 +33,20 @@ jobs: - name: Test and Build with Gradle Wrapper run: ./gradlew build + update-pages: + needs: test + # Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages + permissions: + contents: write + pages: write + id-token: write + # Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued. + # However, do NOT cancel in-progress runs as we want to allow these production deployments to complete. + concurrency: + group: "pages" + cancel-in-progress: false + uses: ./.github/workflows/pages.yml + jacoco: needs: test runs-on: ubuntu-latest diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml new file mode 100644 index 000000000..5142a863a --- /dev/null +++ b/.github/workflows/pages.yml @@ -0,0 +1,49 @@ +# Simple workflow for deploying static content to GitHub Pages +name: Deploy static content to Pages + +on: + workflow_call: + + # Allows you to run this workflow manually from the Actions tab + workflow_dispatch: + +jobs: + # Single deploy job since we're just deploying + deploy: + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Pages + uses: actions/configure-pages@v5 + + - name: Set up JDK + uses: actions/setup-java@v4 + with: + java-version: '8' + distribution: 'temurin' + + - name: Setup Gradle + uses: gradle/actions/setup-gradle@417ae3ccd767c252f5661f1ace9f835f9654f2b5 + + - name: Generate Javadoc + run: ./gradlew aggregateJavaDoc + + - name: Generate Coverage + run: |- + ./gradlew testCodeCoverageReport + mv build/reports/jacoco/testCodeCoverageReport/html html/coverage + + - name: Upload artifact + uses: actions/upload-pages-artifact@v3 + with: + # Upload from html + path: './html/' + + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v4 diff --git a/build.gradle b/build.gradle index 82ca2f5fe..eb335ef90 100644 --- a/build.gradle +++ b/build.gradle @@ -143,7 +143,7 @@ allprojects { legacy_version = minecraftVersion obsolete_version = minecraftVersion - subprojects.findAll { it.path.contains("bukkit") }.each {dependsOn "${it.path}:test" } + subprojects.findAll { it.path.contains("bukkit") }.each { dependsOn "${it.path}:test" } } tasks.register('sourcesJar', Jar) { @@ -184,6 +184,13 @@ allprojects { } } +tasks.register("aggregateJavaDoc") { + allprojects.forEach { dependsOn "${it.path}:javadoc" } + doLast { + JavaDocUtils.aggregateJavaDoc("html/docs", rootProject.name, rootProject.version, TEST_MODULE) + } +} + testCodeCoverageReport { dependsOn test reports { diff --git a/buildSrc/build.gradle b/buildSrc/build.gradle new file mode 100644 index 000000000..c93826763 --- /dev/null +++ b/buildSrc/build.gradle @@ -0,0 +1,23 @@ +plugins { + id 'java' +} + +repositories { + mavenCentral() + maven { + name = "Fulminazzo repository" + url = "https://repo.fulminazzo.it/releases" + } +} + +dependencies { + testImplementation platform(libs.junit.platform) + testImplementation 'org.junit.jupiter:junit-jupiter' + testImplementation 'org.junit.jupiter:junit-jupiter-params' + + testImplementation libs.yamlparser +} + +test { + useJUnitPlatform() +} \ No newline at end of file diff --git a/buildSrc/settings.gradle b/buildSrc/settings.gradle new file mode 100644 index 000000000..7018d7b43 --- /dev/null +++ b/buildSrc/settings.gradle @@ -0,0 +1,7 @@ +dependencyResolutionManagement { + versionCatalogs { + libs { + from(files("../gradle/libs.versions.toml")) + } + } +} \ No newline at end of file diff --git a/buildSrc/src/main/groovy/JavaDocUtils.groovy b/buildSrc/src/main/groovy/JavaDocUtils.groovy new file mode 100644 index 000000000..331cbdaf9 --- /dev/null +++ b/buildSrc/src/main/groovy/JavaDocUtils.groovy @@ -0,0 +1,158 @@ +import groovy.transform.CompileDynamic + +import java.nio.file.Files +import java.nio.file.StandardCopyOption + +/** + * A collection of utilities to aggregate Javadocs + */ +@CompileDynamic +class JavaDocUtils { + private static final String DOCS_DIR = 'javadoc' + private static final String[] IGNORE_DIRS = [ 'main', 'java', 'groovy', 'html', 'src', 'buildSrc', 'resources' ] + private static final String[] RESOURCES = [ 'index.html', 'javadoc-stylesheet.css' ] + private static final String MODULE_PLACEHOLDER = '%modules%' + private static final String MODULE_FORMAT_FILE = 'module-format.html' + + /** + * Aggregates the javadoc of all the root and subprojects into a single directory + * + * @param output the output directory + * @param ignoreDirs the directories (modules) to be ignore + */ + static aggregateJavaDoc(String output, String name, String version, String... ignoreDirs) { + def current = new File(System.getProperty('user.dir')) + if (current.name == 'buildSrc') current = current.parentFile + def outputDir = new File(current, output) + + if (outputDir.exists() && !outputDir.deleteDir()) + throw new IllegalStateException("Could not delete previous directory ${output}") + if (!outputDir.mkdirs()) throw new IllegalStateException("Could not create directory ${output}") + + aggregateJavaDocRec(current, outputDir, ignoreDirs) + createModulesPage(name, version, outputDir) + } + + /** + * Copies the given file. + * + * @param src the source (copied) file + * @param dst the destination (copy) file + */ + static copyDirectory(File src, File dst) { + if (src.directory) { + def files = src.listFiles() + dst.mkdirs() + if (files != null) + files*.name.each { copyDirectory(new File(src, it), new File(dst, it)) } + } else Files.copy(src.toPath(), dst.toPath(), StandardCopyOption.REPLACE_EXISTING) + } + + /** + * Finds the most common path between the two given files + * + * @param file1 the first file + * @param file2 the second file + * @return the common path + */ + static commonPath(File file1, File file2) { + def path1 = file1.absolutePath + def path2 = file2.absolutePath + def result = '' + + for (i in 0..Math.min(path1.length(), path2.length())) { + def c1 = path1[i] + def c2 = path2[i] + if (c1 != c2) break + else result += c1 + } + + return result + } + + /** + * Gets the given resource. + * + * @param name the name + * @return the resource + */ + static getResource(String name) { + while (name.startsWith('/')) name = name.substring(1) + def resource = JavaDocUtils.getResourceAsStream(name) + if (resource == null) resource = JavaDocUtils.getResourceAsStream("/${name}") + if (resource == null) throw new IllegalArgumentException("Could not find resource '${name}'") + return resource + } + + private static aggregateJavaDocRec(File current, File output, String... ignoreDirs) { + if (!current.directory) return + + def files = current.listFiles() + if (files == null) + throw new IllegalArgumentException("Could not list files of ${current.path}") + + files.findAll { f -> f.directory } + .findAll { f -> !IGNORE_DIRS.any { d -> d == f.name } } + .findAll { f -> !ignoreDirs.any { d -> d == f.name } } + .each { f -> + if (f.name == DOCS_DIR) { + def dest = getDestinationFromModule(output, f) + def out = new File(output, dest) + copyDirectory(f, out) + } else aggregateJavaDocRec(f, output) + } + } + + private static createModulesPage(String name, String version, File file) { + if (!file.directory) return + def files = file.listFiles() + if (files == null) return + if (files.any { it.name.contains('.html') }) return + + RESOURCES.each { parseResource(file, it, name, version, files) } + + files.each { createModulesPage(it.name, version, it) } + } + + private static parseResource(File parentFile, String resource, String name, String version, File[] files) { + getResource("${resource}").withReader { reader -> + new File(parentFile, resource).withWriter { writer -> + String line + while ((line = reader.readLine()) != null) { + line = line.replace('%module_name%', name) + .replace('%module_version%', version) + if (line.contains(MODULE_PLACEHOLDER)) + line = parseModulesPlaceholder(line, files) + writer.write(line) + writer.write('\n') + } + } + } + } + + private static parseModulesPlaceholder(String line, File[] files) { + String output = '' + files*.name.each { n -> + getResource("/${MODULE_FORMAT_FILE}").withReader { r -> + String l + while ((l = r.readLine()) != null) + output += l.replace('%submodule_name%', n) + .replace('%submodule_path%', "${n}${File.separator}index.html") + } + } + line.replace(MODULE_PLACEHOLDER, output) + } + + private static getDestinationFromModule(File output, File file) { + def parent = new File(commonPath(output, file)) + def module = new File(file, '') + while (module.parentFile.parentFile != parent) + module = module.parentFile + def moduleName = module.name + + def dst = "${module.parentFile.name}" + if (moduleName != 'build') dst += "${File.separator}${module.name}" + return dst + } + +} diff --git a/buildSrc/src/main/resources/index.html b/buildSrc/src/main/resources/index.html new file mode 100644 index 000000000..7a55e1a92 --- /dev/null +++ b/buildSrc/src/main/resources/index.html @@ -0,0 +1,79 @@ + + + + Overview (%module_name% %module_version% API) + + + + +
+ +
+ + + +
+

%module_name% %module_version% API

+
+ +
+ + + + + + + + %modules% + +
Submodules 
SubmoduleDescription
+
+ + +
+ +
+ + + + diff --git a/buildSrc/src/main/resources/javadoc-stylesheet.css b/buildSrc/src/main/resources/javadoc-stylesheet.css new file mode 100644 index 000000000..854f2694f --- /dev/null +++ b/buildSrc/src/main/resources/javadoc-stylesheet.css @@ -0,0 +1,668 @@ +/* Javadoc style sheet */ +@import url('resources/fonts/dejavu.css'); + +body { + background-color: #ffffff; + color: #353833; + font-family: 'DejaVu Sans', Arial, Helvetica, sans-serif; + font-size: 14px; + margin: 0; +} + +a:link, a:visited { + text-decoration: none; + color: #4A6782; +} + +a:hover, a:focus { + text-decoration: none; + color: #bb7a2a; +} + +a:active { + text-decoration: none; + color: #4A6782; +} + +a[name] { + color: #353833; +} + +a[name]:hover { + text-decoration: none; + color: #353833; +} + +pre { + font-family: 'DejaVu Sans Mono', monospace; + font-size: 14px; +} + +h1 { + font-size: 20px; +} + +h2 { + font-size: 18px; +} + +h3 { + font-size: 16px; + font-style: italic; +} + +h4 { + font-size: 13px; +} + +h5 { + font-size: 12px; +} + +h6 { + font-size: 11px; +} + +ul { + list-style-type: disc; +} + +code, tt { + font-family: 'DejaVu Sans Mono', monospace; + font-size: 14px; + padding-top: 4px; + margin-top: 8px; + line-height: 1.4em; +} + +dt code { + font-family: 'DejaVu Sans Mono', monospace; + font-size: 14px; + padding-top: 4px; +} + +table tr td dt code { + font-family: 'DejaVu Sans Mono', monospace; + font-size: 14px; + vertical-align: top; + padding-top: 4px; +} + +sup { + font-size: 8px; +} + +/* +Document title and Copyright styles +*/ +.clear { + clear: both; + height: 0; + overflow: hidden; +} + +.about-language { + float: right; + padding: 0 21px; + font-size: 11px; + z-index: 200; + margin-top: -9px; +} + +.legal-copy { + margin-left: .5em; +} + +.bar a, .bar a:link, .bar a:visited, .bar a:active { + color: #FFFFFF; + text-decoration: none; +} + +.bar a:hover, .bar a:focus { + color: #bb7a2a; +} + +.tab { + background-color: #0066FF; + color: #ffffff; + padding: 8px; + width: 5em; + font-weight: bold; +} + +/* +Navigation bar styles +*/ +.bar { + background-color: #4D7A97; + color: #FFFFFF; + padding: .8em .5em .4em .8em; + height: auto; + font-size: 11px; + margin: 0; +} + +.top-nav { + background-color: #4D7A97; + color: #FFFFFF; + float: left; + padding: 0; + width: 100%; + clear: right; + height: 2.8em; + padding-top: 10px; + overflow: hidden; + font-size: 12px; +} + +.bottom-nav { + margin-top: 10px; + background-color: #4D7A97; + color: #FFFFFF; + float: left; + padding: 0; + width: 100%; + clear: right; + height: 2.8em; + padding-top: 10px; + overflow: hidden; + font-size: 12px; +} + +.sub-nav { + background-color: #dee3e9; + float: left; + width: 100%; + overflow: hidden; + font-size: 12px; +} + +.sub-nav div { + clear: left; + float: left; + padding: 0 0 5px 6px; + text-transform: uppercase; +} + +ul.nav-list, ul.sub-nav-list { + float: left; + margin: 0 25px 0 0; + padding: 0; +} + +ul.nav-list li{ + list-style: none; + float: left; + padding: 5px 6px; + text-transform: uppercase; +} + +ul.sub-nav-list li{ + list-style: none; + float: left; +} + +.top-nav a:link, .top-nav a:active, .top-nav a:visited, .bottom-nav a:link, .bottom-nav a:active, .bottom-nav a:visited { + color: #FFFFFF; + text-decoration: none; + text-transform: uppercase; +} + +.top-nav a:hover, .bottom-nav a:hover { + text-decoration: none; + color: #bb7a2a; + text-transform: uppercase; +} + +.nav-bar-cell-1-rev { + background-color: #F8981D; + color: #253441; + margin: auto 5px; +} + +.skip-nav { + position: absolute; + top: auto; + left: -9999px; + overflow: hidden; +} + +/* +Page header and footer styles +*/ +.header, .footer { + clear: both; + margin: 0 20px; + padding: 5px 0 0; +} + +.index-header { + margin: 10px; + position: relative; +} + +.index-header span{ + margin-right: 15px; +} + +.index-header h1 { + font-size: 13px; +} + +.title { + color: #2c4557; + margin: 10px 0; +} + +.sub-title { + margin: 5px 0 0 0; +} + +.header ul { + margin: 0 0 15px 0; + padding: 0; +} + +.footer ul { + margin: 20px 0 5px 0; +} + +.header ul li, .footer ul li { + list-style: none; + font-size: 13px; +} + +/* +Heading styles +*/ +div.details ul.block-list ul.block-list ul.block-list li.block-list h4, div.details ul.block-list ul.block-list ul.block-list-last li.block-list h4 { + background-color: #dee3e9; + border: 1px solid #d0d9e0; + margin: 0 0 6px -8px; + padding: 7px 5px; +} + +ul.block-list ul.block-list ul.block-list li.block-list h3 { + background-color: #dee3e9; + border: 1px solid #d0d9e0; + margin: 0 0 6px -8px; + padding: 7px 5px; +} + +ul.block-list ul.block-list li.block-list h3 { + padding: 0; + margin: 15px 0; +} + +ul.block-list li.block-list h2 { + padding: 0 0 20px 0; +} + +/* +Page layout container styles +*/ +.content-container, .source-container, .class-use-container, .serialized-form-container, .constant-values-container { + clear: both; + padding: 10px 20px; + position: relative; +} + +.index-container { + margin: 10px; + position: relative; + font-size: 12px; +} + +.index-container h2 { + font-size: 13px; + padding: 0 0 3px 0; +} + +.index-container ul { + margin: 0; + padding: 0; +} + +.index-container ul li { + list-style: none; + padding-top: 2px; +} + +.content-container .description dl dt, .content-container .details dl dt, .serialized-form-container dl dt { + font-size: 12px; + font-weight: bold; + margin: 10px 0 0 0; + color: #4E4E4E; +} + +.content-container .description dl dd, .content-container .details dl dd, .serialized-form-container dl dd { + margin: 5px 0 10px 0; + font-size: 14px; + font-family: 'DejaVu Sans Mono',monospace; +} + +.serialized-form-container dl.name-value dt { + margin-left: 1px; + font-size: 1.1em; + display: inline; + font-weight: bold; +} + +.serialized-form-container dl.name-value dd { + margin: 0 0 0 1px; + font-size: 1.1em; + display: inline; +} + +/* +List styles +*/ +ul.horizontal li { + display: inline; + font-size: 0.9em; +} + +ul.inheritance { + margin: 0; + padding: 0; +} + +ul.inheritance li { + display: inline; + list-style: none; +} + +ul.inheritance li ul.inheritance { + margin-left: 15px; + padding-left: 15px; + padding-top: 1px; +} + +ul.block-list, ul.block-list-last { + margin: 10px 0 10px 0; + padding: 0; +} + +ul.block-list li.block-list, ul.block-list-last li.block-list { + list-style: none; + margin-bottom: 15px; + line-height: 1.4; +} + +ul.block-list ul.block-list li.block-list, ul.block-list ul.block-list-last li.block-list { + padding: 0 20px 5px 10px; + border: 1px solid #ededed; + background-color: #f8f8f8; +} + +ul.block-list ul.block-list ul.block-list li.block-list, ul.block-list ul.block-list ul.block-list-last li.block-list { + padding: 0 0 5px 8px; + background-color: #ffffff; + border: none; +} + +ul.block-list ul.block-list ul.block-list ul.block-list li.block-list { + margin-left: 0; + padding-left: 0; + padding-bottom: 15px; + border: none; +} + +ul.block-list ul.block-list ul.block-list ul.block-list li.block-list-last { + list-style: none; + border-bottom: none; + padding-bottom: 0; +} + +table tr td dl, table tr td dl dt, table tr td dl dd { + margin-top: 0; + margin-bottom: 1px; +} + +/* +Table styles +*/ +.overview-summary, .member-summary, .type-summary, .use-summary, .constants-summary, .deprecated-summary { + width: 100%; + border-left: 1px solid #EEE; + border-right: 1px solid #EEE; + border-bottom: 1px solid #EEE; +} + +.overview-summary, .member-summary { + padding: 0; +} + +.overview-summary caption, .member-summary caption, .type-summary caption, +.use-summary caption, .constants-summary caption, .deprecated-summary caption { + position: relative; + text-align: left; + background-repeat: no-repeat; + color: #253441; + font-weight: bold; + clear: none; + overflow: hidden; + padding: 0; + padding-top: 10px; + padding-left: 1px; + margin: 0; + white-space: pre; +} + +.overview-summary caption a:link, .member-summary caption a:link, .type-summary caption a:link, +.use-summary caption a:link, .constants-summary caption a:link, .deprecated-summary caption a:link, +.overview-summary caption a:hover, .member-summary caption a:hover, .type-summary caption a:hover, +.use-summary caption a:hover, .constants-summary caption a:hover, .deprecated-summary caption a:hover, +.overview-summary caption a:active, .member-summary caption a:active, .type-summary caption a:active, +.use-summary caption a:active, .constants-summary caption a:active, .deprecated-summary caption a:active, +.overview-summary caption a:visited, .member-summary caption a:visited, .type-summary caption a:visited, +.use-summary caption a:visited, .constants-summary caption a:visited, .deprecated-summary caption a:visited { + color: #FFFFFF; +} + +.overview-summary caption span, .member-summary caption span, .type-summary caption span, +.use-summary caption span, .constants-summary caption span, .deprecated-summary caption span { + white-space: nowrap; + padding-top: 5px; + padding-left: 12px; + padding-right: 12px; + padding-bottom: 7px; + display: inline-block; + float: left; + background-color: #F8981D; + border: none; + height: 16px; +} + +.member-summary caption span.active-table-tab span { + white-space: nowrap; + padding-top: 5px; + padding-left: 12px; + padding-right: 12px; + margin-right: 3px; + display: inline-block; + float: left; + background-color: #F8981D; + height: 16px; +} + +.member-summary caption span.table-tab span { + white-space: nowrap; + padding-top: 5px; + padding-left: 12px; + padding-right: 12px; + margin-right: 3px; + display: inline-block; + float: left; + background-color: #4D7A97; + height: 16px; +} + +.member-summary caption span.table-tab, .member-summary caption span.active-table-tab { + padding-top: 0; + padding-left: 0; + padding-right: 0; + background-image: none; + float: none; + display: inline; +} + +.overview-summary .tab-end, .member-summary .tab-end, .type-summary .tab-end, +.use-summary .tab-end, .constants-summary .tab-end, .deprecated-summary .tab-end { + display: none; + width: 5px; + position: relative; + float: left; + background-color: #F8981D; +} + +.member-summary .active-table-tab .tab-end { + display: none; + width: 5px; + margin-right: 3px; + position: relative; + float: left; + background-color: #F8981D; +} + +.member-summary .table-tab .tab-end { + display: none; + width: 5px; + margin-right: 3px; + position: relative; + background-color: #4D7A97; + float: left; + +} + +.overview-summary td, .member-summary td, .type-summary td, +.use-summary td, .constants-summary td, .deprecated-summary td { + text-align: left; + padding: 0 0 12px 10px; +} + +th.col-one, th.col-first, th.col-last, .use-summary th, .constants-summary th, +td.col-one, td.col-first, td.col-last, .use-summary td, .constants-summary td{ + vertical-align: top; + padding-right: 0; + padding-top: 8px; + padding-bottom: 3px; +} + +th.col-first, th.col-last, th.col-one, .constants-summary th { + background: #dee3e9; + text-align: left; + padding: 8px 3px 3px 7px; +} + +td.col-first, th.col-first { + white-space: nowrap; + font-size: 13px; +} + +td.col-last, th.col-last { + font-size: 13px; +} + +td.col-one, th.col-one { + font-size: 13px; +} + +.overview-summary td.col-first, .overview-summary th.col-first, +.use-summary td.col-first, .use-summary th.col-first, +.overview-summary td.col-one, .overview-summary th.col-one, +.member-summary td.col-first, .member-summary th.col-first, +.member-summary td.col-one, .member-summary th.col-one, +.type-summary td.col-first{ + width: 25%; + vertical-align: top; +} + +td.col-one a:link, td.col-one a:active, td.col-one a:visited, td.col-one a:hover, td.col-first a:link, td.col-first a:active, td.col-first a:visited, td.col-first a:hover, td.col-last a:link, td.col-last a:active, td.col-last a:visited, td.col-last a:hover, .constant-values-container td a:link, .constant-values-container td a:active, .constant-values-container td a:visited, .constant-values-container td a:hover { + font-weight: bold; +} + +.table-sub-heading-color { + background-color: #EEEEFF; +} + +.alt-color { + background-color: #FFFFFF; +} + +.row-color { + background-color: #EEEEEF; +} + +/* +Content styles +*/ +.description pre { + margin-top: 0; +} + +.deprecated-content { + margin: 0; + padding: 10px 0; +} + +.doc-summary { + padding: 0; +} + +ul.block-list ul.block-list ul.block-list li.block-list h3 { + font-style: normal; +} + +div.block { + font-size: 14px; + font-family: 'DejaVu Serif', Georgia, "Times New Roman", Times, serif; +} + +td.col-last div { + padding-top: 0; +} + + +td.col-last a { + padding-bottom: 3px; +} + +/* +Formatting effect styles +*/ +.source-line-no { + color: green; + padding: 0 30px 0 0; +} + +h1.hidden { + visibility: hidden; + overflow: hidden; + font-size: 10px; +} + +.block { + display: block; + margin: 3px 10px 2px 0; + color: #474747; +} + +.deprecated-label, .descframe-type-label, .member-name-label, .member-name-link, +.override-specify-label, .package-hierarchy-label, .param-label, .return-label, +.see-label, .simple-tag-label, .throws-label, .type-name-label, .type-name-link { + font-weight: bold; +} + +.deprecation-comment, .emphasized-phrase, .interface-name { + font-style: italic; +} + +div.block div.block span.deprecation-comment, div.block div.block span.emphasized-phrase, +div.block div.block span.interface-name { + font-style: normal; +} + +div.content-container ul.block-list li.block-list h2{ + padding-bottom: 0; +} diff --git a/buildSrc/src/main/resources/module-format.html b/buildSrc/src/main/resources/module-format.html new file mode 100644 index 000000000..ad433420c --- /dev/null +++ b/buildSrc/src/main/resources/module-format.html @@ -0,0 +1,4 @@ + + %submodule_name% +   + \ No newline at end of file diff --git a/buildSrc/src/test/java/JavaDocUtilsTest.java b/buildSrc/src/test/java/JavaDocUtilsTest.java new file mode 100644 index 000000000..bdedd090c --- /dev/null +++ b/buildSrc/src/test/java/JavaDocUtilsTest.java @@ -0,0 +1,67 @@ +import it.fulminazzo.yamlparser.utils.FileUtils; +import org.junit.jupiter.api.Test; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; + +import static org.junit.jupiter.api.Assertions.*; + +class JavaDocUtilsTest { + + @Test + void testCopy() throws IOException { + File parent = new File("build/resources/test"); + if (parent.exists()) FileUtils.deleteFolder(parent); + FileUtils.createFolder(parent); + // Setup + File dir1 = new File(parent, "dir1"); + dir1.mkdir(); + File file1 = new File(dir1, "file1"); + file1.createNewFile(); + FileUtils.writeToFile(file1, "Hello"); + File file2 = new File(dir1, "file2"); + file2.createNewFile(); + FileUtils.writeToFile(file2, "World"); + + // Copy + File dir2 = new File(parent, "dir2"); + JavaDocUtils.copyDirectory(dir1, dir2); + + // Verify + assertTrue(dir2.isDirectory(), String.format("No directory %s", dir2.getAbsolutePath())); + + file1 = new File(dir2, "file1"); + assertTrue(file1.exists(), String.format("No file %s", file1.getAbsolutePath())); + assertEquals("Hello", FileUtils.readFileToString(file1)); + + file2 = new File(dir2, "file2"); + assertTrue(file2.exists(), String.format("No file %s", file2.getAbsolutePath())); + assertEquals("World", FileUtils.readFileToString(file2)); + } + + @Test + void testCommonPaths() { + String expected = System.getProperty("user.dir") + "/this/path/is/expected/"; + File path1 = new File(expected, "this/is/not"); + File path2 = new File(expected, "me/neither"); + + Object actual = JavaDocUtils.commonPath(path1, path2); + assertEquals(expected, actual); + } + + @Test + void testGetResource() throws IOException { + InputStream stream = (InputStream) JavaDocUtils.getResource("mock.txt"); + assertNotNull(stream); + StringBuilder builder = new StringBuilder(); + while (stream.available() > 0) builder.append((char) stream.read()); + assertEquals("Hello world", builder.toString()); + } + + @Test + void testInvalidResource() { + assertThrowsExactly(IllegalArgumentException.class, () -> JavaDocUtils.getResource("invalid")); + } + +} \ No newline at end of file diff --git a/buildSrc/src/test/resources/mock.txt b/buildSrc/src/test/resources/mock.txt new file mode 100644 index 000000000..70c379b63 --- /dev/null +++ b/buildSrc/src/test/resources/mock.txt @@ -0,0 +1 @@ +Hello world \ No newline at end of file