You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tapestry.apache.org by be...@apache.org on 2025/09/13 15:01:00 UTC
(tapestry-5) branch gradle-improvements-javax created (now 7682b7394)
This is an automated email from the ASF dual-hosted git repository.
benw pushed a change to branch gradle-improvements-javax
in repository https://gitbox.apache.org/repos/asf/tapestry-5.git
at 7682b7394 TAP5-2809: fix tests
This branch includes the following new commits:
new 12ae99184 TAP5-2809: basic gradle setup
new b474b2110 TAP5-2809: fix tapestry-ioc-junit compilation issues
new 4098b2df2 Improving handling of resource minimization exceptions
new c7e338116 TAP5-2809: fix plastic tests that rely on Groovy quirks
new 6ab32d670 TAP5-2809: fix webresources test
new 348d8bad9 TAP5-2809: Fix Javadoc errors
new 52ae5b493 TAP5-2809: Fix Javadoc warnings
new b6520b3b9 TAP5-2809: Fix groovy test
new 0e7061725 TAP5-2809: removed singluar test that relied on a Groovy bug
new 4be4227d5 TAP5-2809: disabled another test relying on Groovy weirdness
new ed3dd34e2 TAP5-2809: Groovy 4
new 7682b7394 TAP5-2809: fix tests
The 12 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails. The revisions
listed as "add" were already present in the repository and have only
been added to this reference.
(tapestry-5) 10/12: TAP5-2809: disabled another test relying on Groovy weirdness
Posted by be...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
benw pushed a commit to branch gradle-improvements-javax
in repository https://gitbox.apache.org/repos/asf/tapestry-5.git
commit 4be4227d5778b8ee5016b543f0c2e51bca753ae9
Author: Ben Weidig <be...@netzgut.net>
AuthorDate: Sun Aug 3 16:36:05 2025 +0200
TAP5-2809: disabled another test relying on Groovy weirdness
---
tapestry-ioc/src/test/groovy/ioc/specs/GeneralIntegrationSpec.groovy | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/tapestry-ioc/src/test/groovy/ioc/specs/GeneralIntegrationSpec.groovy b/tapestry-ioc/src/test/groovy/ioc/specs/GeneralIntegrationSpec.groovy
index ea3a16a23..376574bd4 100644
--- a/tapestry-ioc/src/test/groovy/ioc/specs/GeneralIntegrationSpec.groovy
+++ b/tapestry-ioc/src/test/groovy/ioc/specs/GeneralIntegrationSpec.groovy
@@ -16,6 +16,8 @@ import org.apache.tapestry5.plastic.MethodInvocation
import org.hibernate.Session
import org.hibernate.cfg.Configuration
+import spock.lang.Ignore
+
class GeneralIntegrationSpec extends AbstractSharedRegistrySpecification {
def "PropertyAccess service is available"() {
@@ -52,6 +54,9 @@ class GeneralIntegrationSpec extends AbstractSharedRegistrySpecification {
}
// TAP5-2667
+ // This test no longer works as calling static methods on instances was a Groovy bug
+ // See: https://issues.apache.org/jira/browse/GROOVY-10590
+ @Ignore
def "Default methods in a service should be skipped while introducing methods and advising methods"() {
when:
Registry registry = RegistryBuilder.buildAndStartupRegistry(TestModule.class);
(tapestry-5) 01/12: TAP5-2809: basic gradle setup
Posted by be...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
benw pushed a commit to branch gradle-improvements-javax
in repository https://gitbox.apache.org/repos/asf/tapestry-5.git
commit 12ae9918421cb480e9ff3d4b848e8bdebf42e8c8
Author: Ben Weidig <be...@netzgut.net>
AuthorDate: Sat Sep 13 13:07:01 2025 +0200
TAP5-2809: basic gradle setup
An attempt to replicate the basic gradle setup from (future) master.
The project doesn't build, but Gradle itself is running clean without
instantly failing.
---
beanmodel/build.gradle | 60 +-
build.gradle | 806 ++++++++-------------
buildSrc/build.gradle | 20 +
.../main/groovy/t5build/GenerateChecksums.groovy | 61 ++
buildSrc/src/main/groovy/t5build/SSshExec.groovy | 21 +
buildSrc/src/main/groovy/t5build/Scp.groovy | 36 +
buildSrc/src/main/groovy/t5build/SshTask.groovy | 94 +++
.../main/groovy/t5build/TapestryBuildLogic.groovy | 22 +
.../main/groovy/tapestry.java-convention.gradle | 66 ++
.../tapestry.junit4-legacy-convention.gradle | 12 +
.../main/groovy/tapestry.junit5-convention.gradle | 13 +
.../groovy/tapestry.junit5-spock-convention.gradle | 9 +
.../src/main/groovy/tapestry.ssh-convention.gradle | 15 +
.../groovy/tapestry.testing-base-convention.gradle | 64 ++
.../main/groovy/tapestry.testng-convention.gradle | 27 +
commons/build.gradle | 26 +-
genericsresolver-guava/build.gradle | 16 +-
gradle/libs.versions.toml | 168 +++++
gradle/wrapper/gradle-wrapper.jar | Bin 59821 -> 43462 bytes
gradle/wrapper/gradle-wrapper.properties | 4 +-
gradlew | 41 +-
gradlew.bat | 15 +-
plastic/build.gradle | 23 +-
quickstart/build.gradle | 24 +-
settings.gradle | 87 ++-
sha256.gradle | 25 -
ssh.gradle | 124 ----
tapestry-beanvalidator/build.gradle | 44 +-
tapestry-cdi/build.gradle | 91 ++-
tapestry-clojure/build.gradle | 29 +-
tapestry-core/build.gradle | 222 +++---
tapestry-func/build.gradle | 12 +-
tapestry-hibernate-core/build.gradle | 21 +-
tapestry-hibernate/build.gradle | 39 +-
tapestry-http/build.gradle | 34 +-
tapestry-internal-test/build.gradle | 6 +-
tapestry-ioc-jcache/build.gradle | 54 +-
tapestry-ioc-junit/build.gradle | 13 +-
tapestry-ioc/build.gradle | 35 +-
tapestry-javadoc/build.gradle | 51 +-
tapestry-jmx/build.gradle | 17 +-
tapestry-jpa/build.gradle | 53 +-
tapestry-json/build.gradle | 18 +-
tapestry-kaptcha/build.gradle | 18 +-
tapestry-latest-java-tests/build.gradle | 26 +-
tapestry-mongodb/build.gradle | 27 +-
tapestry-openapi-viewer/build.gradle | 7 +-
tapestry-rest-jackson/build.gradle | 16 +-
tapestry-runner/build.gradle | 27 +-
tapestry-spock/build.gradle | 22 +-
tapestry-spring/build.gradle | 44 +-
tapestry-test-data/build.gradle | 4 +-
tapestry-test/build.gradle | 33 +-
tapestry-upload/build.gradle | 25 +-
tapestry-version-migrator/build.gradle | 18 +-
tapestry-webresources/build.gradle | 78 +-
tapestry5-annotations/build.gradle | 2 +-
57 files changed, 1710 insertions(+), 1255 deletions(-)
diff --git a/beanmodel/build.gradle b/beanmodel/build.gradle
index 5adf920bd..68391ae01 100644
--- a/beanmodel/build.gradle
+++ b/beanmodel/build.gradle
@@ -1,39 +1,47 @@
-import org.gradle.plugins.ide.idea.model.*
-import t5build.*
-
-description = "Fast class property discovery, reading and writing library based on bytecode generation. Extracted from Apache Tapestry, but not dependent on the Web framework (tapestry-core) nor the IoC one (tapestry-ioc)."
-
-//apply plugin: JavaPlugin
-apply plugin: 'antlr'
+plugins {
+ id 'tapestry.junit5-convention'
+ id 'antlr'
+}
-buildDir = 'target/gradle-build'
+description = 'Fast class property discovery, reading and writing library based on bytecode generation. Extracted from Apache Tapestry, but not dependent on the Web framework (tapestry-core) nor the IoC one (tapestry-ioc).'
dependencies {
- api project(":plastic")
- api project(":tapestry5-annotations")
- api project(":commons")
- implementation "org.slf4j:slf4j-api:${versions.slf4j}"
+ implementation project(':plastic')
+ implementation project(':tapestry5-annotations')
+ implementation project(':commons')
- // ANTLR tool path used with the generateGrammarSource task
- antlr "org.antlr:antlr:3.5.2"
+ implementation libs.slf4j.api
+
+ antlr libs.antlr
// Transitive will bring in the unwanted string template library as well
- implementation "org.antlr:antlr-runtime:3.5.2", {
- exclude group: "org.antlr", module: "stringtemplate"
+ implementation(libs.antlr.runtime) {
+ exclude group: 'org.antlr', module: 'stringtemplate'
}
- testImplementation "org.testng:testng:${versions.testng}", { transitive = false }
- testImplementation "org.easymock:easymock:${versions.easymock}"
- testImplementation "org.junit.jupiter:junit-jupiter:${versions.junitJupiter}"
- testImplementation "org.spockframework:spock-core:${versions.spock}"
+ testImplementation platform(libs.spock.bom)
+ testImplementation libs.spock.core
}
-clean.delete generateGrammarSource.outputDirectory
+tasks.named('clean') {
+ delete generateGrammarSource.outputDirectory
+}
-compileJava {
- options.fork(memoryMaximumSize: '512m')
+tasks.named('compileJava', JavaCompile) {
+ dependsOn generateGrammarSource
+ options.fork = true
+ options.forkOptions.memoryMaximumSize = '512M'
}
-test {
- useJUnit()
-}
\ No newline at end of file
+tasks.named('sourcesJar') {
+ dependsOn 'generateGrammarSource'
+ duplicatesStrategy = DuplicatesStrategy.EXCLUDE
+}
+
+sourceSets {
+ main {
+ java {
+ srcDir generateGrammarSource.outputDirectory
+ }
+ }
+}
diff --git a/build.gradle b/build.gradle
index 184c8da88..300c62ef3 100755
--- a/build.gradle
+++ b/build.gradle
@@ -1,291 +1,125 @@
-description = "Apache Tapestry 5 Project"
-
+import t5build.GenerateChecksums
+import t5build.TapestryBuildLogic
import org.apache.tools.ant.filters.ReplaceTokens
-apply plugin: "base"
-apply plugin: "maven-publish"
-
-apply from: "ssh.gradle"
-apply from: "md5.gradle"
-apply from: "sha256.gradle"
-
-project.ext.versions = [
- jetty: "8.1.19.v20160209",
- tomcat: "7.0.70",
- testng: "7.5.1",
- easymock: "5.4.0",
- servletapi: "3.0.1",
- spock: "2.3-groovy-3.0",
- hibernate: "5.4.32.Final",
- slf4j: "1.7.25",
- geb: "2.0",
- selenium: "4.5.0",
- seleniumServer: "4.12.1",
- jackson: "2.13.1",
- jsonschemaGenerator: "4.20.0",
- junitJupiter: "5.10.2",
- commonsLang: "3.17.0",
- commonsIo: "2.17.0",
- webdriverManager: "5.3.1",
- antlrRuntime: "3.5.3",
- hsqldb: "2.7.3:jdk8",
- snakeyaml: "2.3"
-]
-
-def artifactSuffix = ""
-
-// Artifacts that have both an unsuffixed artifact from the javax branch
-// and a suffixed one from the master branch
-def suffixedArtifactNames = ["tapestry-core", "tapestry-http", "tapestry-test",
- "tapestry-runner", "tapestry-spring", "tapestry-kaptcha",
- "tapestry-openapi-viewer", "tapestry-upload", "tapestry-jmx",
- "tapestry-jpa", "tapestry-kaptcha", "tapestry-openapi-viewer",
- "tapestry-rest-jackson", "tapestry-webresources", "tapestry-cdi",
- "tapestry-ioc", "tapestry-ioc-jcache", "tapestry-jmx", "tapestry-spock",
- "tapestry-clojure", "tapestry-hibernate", "tapestry-hibernate-core",
- "tapestry-ioc-junit", "tapestry-latest-java-tests", "tapestry-mongodb",
- "tapestry-spock", "tapestry-beanvalidator"]
-
-ext.continuousIntegrationBuild = Boolean.getBoolean("ci")
-
-// Provided so that the CI server can override the normal version number for nightly builds.
-project.version = tapestryVersion()
-
-// Remember that when generating a release, this should be incremented. Also don"t forget to
-// tag the release in Git.
-// Version number is always "5.x(.y)?-SNAPSHOT" and only gets fixed, e.g. to 5.4-alpha-1
-// during a release
-
-def tapestryVersion() {
-
- def major = "5.10.0"
- def minor = ""
-
- // When building on the CI server, make sure -SNAPSHOT is appended, as it is a nightly build.
- // When building normally, or for a release, no suffix is desired.
- continuousIntegrationBuild ? major + "-SNAPSHOT" : major + minor
+plugins {
+ id 'base'
+ id 'maven-publish'
}
-// Let analysis.apache.org get in touch with our builds
-
-project.ext {
-
- stagingUrl = "https://repository.apache.org/service/local/staging/deploy/maven2/"
- snapshotUrl = "https://repository.apache.org/content/repositories/snapshots"
-
- doSign = !project.hasProperty("noSign") && project.hasProperty("signing.keyId")
+description = 'Apache Tapestry 5 Project'
+
+ext {
+ tapestryMajorVersion = '5.10.0'
+ tapestryMinorVersion = '' // Use for release suffixes like '-alpha-1'
+
+ artifactSuffix = '-jakarta'
+
+ // Artifacts that have both an unsuffixed artifact from the javax branch
+ // and a suffixed one from the master branch
+ suffixedArtifactNames = [
+ 'tapestry-beanvalidator',
+ 'tapestry-cdi',
+ 'tapestry-clojure',
+ 'tapestry-hibernate-core',
+ 'tapestry-hibernate',
+ 'tapestry-http',
+ 'tapestry-ioc-jcache',
+ 'tapestry-ioc-junit',
+ 'tapestry-ioc',
+ 'tapestry-jmx',
+ 'tapestry-jpa',
+ 'tapestry-kaptcha',
+ 'tapestry-latest-java-tests',
+ 'tapestry-mongodb',
+ 'tapestry-openapi-viewer',
+ 'tapestry-rest-jackson',
+ 'tapestry-runner',
+ 'tapestry-spock',
+ 'tapestry-spring',
+ 'tapestry-test',
+ 'tapestry-upload',
+ 'tapestry-webresources',
+ 'tapestry-core',
+ ]
+
+ continuousIntegrationBuild = Boolean.getBoolean('ci')
+ stagingUrl = 'https://repository.apache.org/service/local/staging/deploy/maven2/'
+ snapshotUrl = 'https://repository.apache.org/content/repositories/snapshots'
+ doSign = !project.hasProperty('noSign') && project.hasProperty('signing.keyId')
// apacheDeployUserName and apacheDeployPassword should be specified in ~/.gradle/gradle.properties
- deployUsernameProperty = isSnapshot() ? "snapshotDeployUserName" : "apacheDeployUserName"
- deployPasswordProperty = isSnapshot() ? "snapshotDeployPassword" : "apacheDeployPassword"
-
- canDeploy = [deployUsernameProperty, deployPasswordProperty, "apacheArchivesFolder"].every { project.hasProperty(it) }
-
- // These are all deferred inside closures, to allow people without the necessary values in their
- // gradle.properties to build locally, just not deploy. getProperty() throws an exception if the property
- // is not present.
- deployUsername = { getProperty(deployUsernameProperty) }
- deployPassword = { getProperty(deployPasswordProperty) }
-
- archiveDeployFolder = { getProperty("apacheArchivesFolder") }
-}
-
-println "JDK: " + System.getProperty("java.version")
-
-//println "Can deploy? $canDeploy"
-//println "Is snapshot? isSnapshot"
-//println "deployUsernameProperty $deployUsernameProperty"
-//println "deployPasswordProperty $deployPasswordProperty"
-//println "continuousIntegrationBuild? $continuousIntegrationBuild"
-
-allprojects {
-
- apply plugin: "eclipse"
- apply plugin: "idea"
+ def deployFlavor = TapestryBuildLogic.isSnapshot(project) ? 'snapshot' : 'apache'
- repositories {
- mavenLocal()
- mavenCentral()
-
- // All things JBoss/Hibernate
- maven {
- name "JBoss"
- url "https://repository.jboss.org/nexus/content/repositories/releases/"
- }
- }
-
- configurations {
- // Non-code artifacts, such as sources JARs and zipped JavaDocs
- meta
- }
+ deployUsername = providers.gradleProperty("${deployFlavor}DeployUserName")
+ deployPassword = providers.gradleProperty("${deployFlavor}DeployPassword")
+ archiveDeployFolder = providers.gradleProperty('apacheArchivesFolder')
+ canDeploy = [
+ deployUsername,
+ deployPassword,
+ archiveDeployFolder
+ ].every { it.present }
}
-idea {
- project {
- languageLevel = "1.8"
- }
-}
+// Provided so that the CI server can override the normal version number for nightly builds.
+version = TapestryBuildLogic.tapestryVersion(project)
// Specific to top-level build, not set for subprojects:
-
configurations {
javadoc
published.extendsFrom archives, meta
+
if (doSign) {
published.extendsFrom signatures
}
+
binaries // additional dependencies included in the binary archive
}
dependencies {
- if (JavaVersion.current() != JavaVersion.VERSION_1_8) {
- javadoc project(":tapestry-javadoc")
+ if (JavaVersion.current().isCompatibleWith(JavaVersion.VERSION_11)) {
+ javadoc project(':tapestry-javadoc')
+ meta providers.provider {
+ tasks.named('aggregateJavadoc').get().outputs.files
+ }
}
// From tapestry-ioc:
- binaries "javax.inject:javax.inject:1"
- binaries "org.slf4j:slf4j-api:${versions.slf4j}"
- binaries "commons-codec:commons-codec:1.17.1"
- binaries "org.antlr:antlr-runtime:${versions.antlrRuntime}", { transitive = false }
+ binaries libs.javax.inject
+ binaries libs.slf4j.api
+ binaries libs.commons.codec
+ binaries libs.antlr.runtime, {
+ transitive = false
+ }
}
-String jdkVersion = System.properties['java.version']
-def jdkMajorVersion = jdkVersion.substring(0, jdkVersion.indexOf(".")) // 1, 9, 10...
-
subprojects {
-
- def specifyMaxPermSize = jdkVersion ==~ /1\.[67].+/
-
- apply plugin: "maven-publish" // for deployment
+ plugins.apply 'tapestry.java-convention'
+ plugins.apply 'maven-publish'
+ plugins.apply 'project-report'
+ plugins.apply 'jacoco'
+ plugins.apply 'groovy'
- configurations {
- provided
- }
-
- apply plugin: "java"
- apply plugin: "java-library"
- apply plugin: "groovy" // mostly for testing
-
- apply plugin: "project-report"
- apply plugin: "jacoco"
- apply plugin: "base"
-
jacoco {
- toolVersion = "0.8.7"
- }
-
- sourceCompatibility = "1.8"
- targetCompatibility = "1.8"
-
- // See http://jira.codehaus.org/browse/GRADLE-784
-
- sourceSets {
- main {
- compileClasspath += configurations.provided
- }
- test {
- compileClasspath += configurations.provided
- runtimeClasspath += configurations.provided
- }
+ toolVersion = '0.8.7'
}
- idea.module {
- scopes.PROVIDED.plus += [configurations.provided]
- }
-
- eclipse.classpath.plusConfigurations += [configurations.provided]
-
dependencies {
-
- // https://docs.gradle.org/7.3.3/userguide/upgrading_version_6.html#potential_breaking_changes,
- // Table 1. Common configuration upgrades
- testImplementation "org.spockframework:spock-core:${versions.spock}"
-
- testRuntimeOnly "org.slf4j:slf4j-log4j12:${versions.slf4j}"
- }
-
- compileTestGroovy {
- configure(groovyOptions.forkOptions) {
- memoryMaximumSize = '1g'
- jvmArgs = ['-Xms512m', '-Xmx1g']
- if (specifyMaxPermSize){
- jvmArgs << '-XX:MaxPermSize=512m'
- }
- }
+ implementation libs.slf4j.api
}
- tasks.withType(Test) {
- useTestNG()
-
- options.suites("src/test/conf/testng.xml")
- if (specifyMaxPermSize){
- maxHeapSize "400M"
- jvmArgs("-XX:MaxPermSize=200m")
- }else{
- maxHeapSize "600M"
- }
-
- // Needed to have XMLTokenStreamTests.testStreamEncoding() passing on Java 9+
- if (JavaVersion.current().isCompatibleWith(JavaVersion.VERSION_1_9)) {
- jvmArgs("--add-opens=java.base/java.nio.charset=ALL-UNNAMED");
- }
-
- // Turn off live service reloading
-
- systemProperties["tapestry.service-reloading-enabled"] = "false"
- systemProperties["java.io.tmpdir"] = temporaryDir.absolutePath
-
- jvmArgs("-Dfile.encoding=UTF-8")
-
- environment.LANG = 'en_US.UTF-8'
-
- if (continuousIntegrationBuild) {
- // Travis runs our builds with TERM=dumb and kills it if we don't produce any
- // output for 10 minutes, so we log some task execution progress
-
- testLogging {
- exceptionFormat "full"
- }
-
- def numberOfTestsExecuted = 0
- afterTest { descriptor, result->
- numberOfTestsExecuted++
- if (numberOfTestsExecuted % 25 == 0){
- logger.lifecycle "$numberOfTestsExecuted tests executed"
- }
- }
+ tasks.withType(GroovyCompile).configureEach {
+ if (name == 'compileTestGroovy') {
+ options.fork = true
+ options.forkOptions.memoryMaximumSize = '1g'
+ options.forkOptions.jvmArgs = ['-Xms512m', '-Xmx1g']
}
}
- jar {
- // println "JAR projectDir: " + projectDir.getName().replaceAll("5", "").replaceAll("tapestry-", "").replaceAll("-", "");
- from(projectDir) {
- include "*.txt"
- into "META-INF"
- }
- manifest {
- attributes("Automatic-Module-Name": "org.apache.tapestry." + projectDir.getName()
- .replaceAll("tapestry5", "tapestry")
- .replaceAll("tapestry-", "")
- .replaceAll("-", ""))
- if (projectDir.getName().equals("tapestry-version-migrator")) {
- attributes("Main-Class": "org.apache.tapestry5.versionmigrator.Main")
- }
- }
- }
-
- assemble.dependsOn(processResources, compileJava, jar)
-
- task sourcesJar(type: Jar) {
- dependsOn classes
- archiveClassifier = "sources"
- from sourceSets.main.allSource
- from(projectDir) {
- include "*.txt"
- into "META-INF"
- }
+ tasks.named('assemble') {
+ dependsOn processResources, compileJava, jar
}
artifacts {
@@ -301,42 +135,41 @@ subprojects {
published.extendsFrom signatures
}
}
-
+
publishing {
publications {
mavenJava(MavenPublication) {
version = parent.version
- groupId = "org.apache.tapestry"
+ groupId = 'org.apache.tapestry'
if (suffixedArtifactNames.contains(project.name)) {
artifactId = project.name + artifactSuffix
}
from components.java
artifact sourcesJar
-
-
+
pom {
name = project.name
// TODO: find some way to get the subproject description here.
- // description =
- url = "https://tapestry.apache.org/"
+ // description =
+ url = 'https://tapestry.apache.org/'
licenses {
license {
name = 'The Apache License, Version 2.0'
- url = 'http://www.apache.org/licenses/LICENSE-2.0.txt'
+ url = 'http://www.apache.org/licenses/LICENSE-2.0.txt'
}
}
scm {
connection = 'scm:git:https://gitbox.apache.org/repos/asf/tapestry-5.git'
- developerConnection = 'scm:git://gitbox.apache.org/repos/asf/tapestry-5.git'
- url = 'https://git-wip-us.apache.org/repos/asf?p=tapestry-5.git;a=summary'
+ developerConnection = 'scm:git://gitbox.apache.org/repos/asf/tapestry-5.git'
+ url = 'https://git-wip-us.apache.org/repos/asf?p=tapestry-5.git;a=summary'
}
// Changes the generated pom.xml so its dependencies on suffixed artifacts
// get properly updated with suffixed artifact ids
withXml {
def artifactIdQName = new groovy.namespace.QName(
- "http://maven.apache.org/POM/4.0.0", "artifactId")
- def node = asNode();
- def dependencies = node.get("dependencies")[0]
+ 'http://maven.apache.org/POM/4.0.0', 'artifactId')
+ def node = asNode()
+ def dependencies = node.get('dependencies')[0]
if (dependencies != null) {
dependencies.'*'.forEach {
def artifactIdNode = it.getAt(artifactIdQName)[0]
@@ -347,103 +180,87 @@ subprojects {
}
}
}
- matching {
- it.name.endsWith(".jar") || it.name.endsWith(".pom")
- }
}
}
if (canDeploy) {
repositories {
mavenLocal()
- if (continuousIntegrationBuild) {
- maven {
- name = "apacheSnapshots"
- url = snapshotUrl
- credentials {
- username = deployUsername()
- password = deployPassword()
- }
- }
- }
- else {
- maven {
- name = "apacheStaging"
- url = stagingUrl
- credentials {
- username = deployUsername()
- password = deployPassword()
- }
+
+ def repoUrl = continuousIntegrationBuild ? snapshotUrl : stagingUrl
+ def repoName = continuousIntegrationBuild ? 'apacheSnapshots' : 'apacheStaging'
+
+ maven {
+ name = repoName
+ url = repoUrl
+ credentials {
+ username = deployUsername.get()
+ password = deployPassword.get()
}
}
-
}
}
}
if (doSign) {
- apply plugin: "signing"
+ apply plugin: 'signing'
signing {
sign publishing.publications.mavenJava
}
}
-
+
def actuallyPublish = !artifactSuffix.isEmpty() || suffixedArtifactNames.contains(project.name)
- // println "XXXXXX Actually publish? " + actuallyPublish + " project " + project.name + " " + "!artifactSuffix.isEmpty() " + !artifactSuffix.isEmpty()
+ // println 'XXXXXX Actually publish? ' + actuallyPublish + ' project ' + project.name + ' ' + '!artifactSuffix.isEmpty() ' + !artifactSuffix.isEmpty()
if (!actuallyPublish) {
- tasks.withType(PublishToMavenRepository).configureEach { it.enabled = false }
- tasks.withType(PublishToMavenLocal).configureEach { it.enabled = false }
+ tasks.withType(PublishToMavenRepository).configureEach {
+ it.enabled = false
+ }
+ tasks.withType(PublishToMavenLocal).configureEach {
+ it.enabled = false
+ }
}
- task uploadPublished {
-
+ tasks.register('uploadPublished') {
doFirst {
if (!canDeploy) {
- throw new InvalidUserDataException("Missing upload credentials. Set '$deployUsernameProperty' and '$deployPasswordProperty' root project properties.")
+ throw new InvalidUserDataException("Missing upload credentials. Set '${deployUsernameProperty}' and '${deployPasswordProperty}' root project properties.")
}
}
-
}
}
-subprojects.each { project.evaluationDependsOn(it.name) }
-
-subprojects {
-
- configurations.all {
-
- resolutionStrategy.force "antlr:antlr:2.7.7",
- "cglib:cglib-nodep:2.2",
- "commons-codec:commons-codec:1.10",
- "commons-io:commons-io:${versions.commonsIo}",
- "commons-logging:commons-logging:1.1.3",
- "org.hsqldb:hsqldb:${versions.hsqldb}",
- "org.antlr:antlr-runtime:${versions.antlrRuntime}",
- "org.apache.tomcat:dbcp:6.0.32",
- "org.hamcrest:hamcrest-core:1.3",
- "org.json:json:20140107",
- "org.yaml:snakeyaml:${versions.snakeyaml}",
- "xml-apis:xml-apis:1.4.01"
-
- }
-}
// Cribbed from https://github.com/hibernate/hibernate-core/blob/master/release/release.gradle#L19
-task aggregateJavadoc(type: Javadoc) {
+tasks.register('aggregateJavadoc', Javadoc) {
+ group = 'Documentation'
+ description = 'Build the aggregated JavaDocs for all modules'
+
dependsOn configurations.javadoc
- group "Documentation"
- description "Build the aggregated JavaDocs for all modules"
- maxMemory "512m"
- destinationDir file("$buildDir/documentation/javadocs")
+ maxMemory = '512m'
+ destinationDir = layout.buildDirectory.dir('documentation/javadocs').get().asFile
- def tapestryStylesheet = file("src/javadoc/stylesheet7.css")
+ def tapestryStylesheet = file('src/javadoc/stylesheet7.css')
int thisYear = java.time.Year.now().getValue()
def allMainSourceSets = subprojects*.sourceSets*.main.flatten()
def allMainJavaFiles = allMainSourceSets*.java
def allMainJavaSrcDirs = allMainJavaFiles*.srcDirs
+ if (JavaVersion.current().isCompatibleWith(JavaVersion.VERSION_17)) {
+ exclude 'org/apache/tapestry5/spring/**'
+ }
+
+ exclude 'org/apache/tapestry5/internal/plastic/asm/**'
+ exclude 'org/apache/tapestry5/internal/webresources/**'
+ exclude 'org/apache/tapestry5/webresources/modules/**'
+
+ source allMainJavaFiles
+
+ classpath += files(allMainSourceSets*.compileClasspath)
+
+ inputs.files allMainJavaSrcDirs
+
options {
splitIndex true
linkSource true
@@ -452,28 +269,24 @@ task aggregateJavadoc(type: Javadoc) {
header "Tapestry API - ${project.version}"
docTitle "Tapestry API - ($project.version)"
bottom "${project.version} - Copyright © 2003-${thisYear} <a href=\"http://tapestry.apache.org/\">The Apache Software Foundation</a>."
- use = true // 'use' seems to be a reserved word for the DSL
- links "https://docs.oracle.com/javase/8/docs/api/"
- links "https://docs.oracle.com/javaee/7/api/"
- if (JavaVersion.current() != JavaVersion.VERSION_1_8) {
+ setUse(use)
+ links 'https://docs.oracle.com/javase/8/docs/api/'
+
+ if (JavaVersion.current().isCompatibleWith(JavaVersion.VERSION_11)) {
tagletPath Collections.unmodifiableList(new ArrayList<>((Set) configurations.javadoc.files))
}
// Uncomment jFlags to debug `./gradlew aggregateJavadoc`
-// jFlags '-Xdebug', '-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=5005'
+ // jFlags '-Xdebug', '-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=5005'
addStringOption '-source-path', files(allMainJavaSrcDirs.flatten()).asPath
addStringOption 'source', '8'
- taglets "org.apache.tapestry5.javadoc.TapestryDocTaglet"
- }
-
- exclude "org/apache/tapestry5/internal/plastic/asm/**"
- exclude "org/apache/tapestry5/internal/webresources/**"
- exclude "org/apache/tapestry5/webresources/modules/**"
-
- source allMainJavaFiles
-
- classpath += files(allMainSourceSets*.compileClasspath)
+ taglets 'org.apache.tapestry5.javadoc.TapestryDocTaglet'
- inputs.files allMainJavaSrcDirs
+ // Javadoc became stricer, so lets do this to actually build for now
+ if (JavaVersion.current().isJava9Compatible()) {
+ addBooleanOption('html5', true)
+ addStringOption('Xdoclint:none', '-quiet')
+ }
+ }
// As part of generating the documentation, ALSO copy any related files:
// Any extra images (Tapestry logo)
@@ -483,138 +296,159 @@ task aggregateJavadoc(type: Javadoc) {
copy {
from allMainJavaSrcDirs
into aggregateJavadoc.destinationDir
- exclude "**/*.java"
- exclude "**/*.xdoc"
- exclude "**/package.html"
+ exclude '**/*.java'
+ exclude '**/*.xdoc'
+ exclude '**/package.html'
}
copy {
- from file("src/javadoc/images")
+ from file('src/javadoc/images')
into aggregateJavadoc.destinationDir
}
}
}
-task typeScriptDocs() {
- group "Documentation"
- description "Builds typedoc documentation for all TypeScript sources"
- dependsOn project(":tapestry-core").tasks.generateTypeScriptDocs
+tasks.register('typeScriptDocs') {
+ group = 'Documentation'
+ description = 'Builds typedoc documentation for all TypeScript sources'
+
+ dependsOn(project(':tapestry-core').tasks.named('generateTypeScriptDocs'))
}
-dependencies {
- if (JavaVersion.current() != JavaVersion.VERSION_1_8) {
- meta aggregateJavadoc.outputs.files
+tasks.register('combinedJacocoReport', JacocoReport) {
+ group = 'Verification'
+ description = 'Generates combined JaCoCo coverage report for all subprojects'
+
+ def excludedProjects = [
+ 'quickstart',
+ 'beanmodel',
+ 'commons',
+ 'genericsresolver-guava',
+ 'tapestry5-annotations',
+ 'tapestry-internal-test',
+ 'tapestry-runner',
+ 'tapestry-test-constants',
+ 'tapestry-test-data',
+ 'tapestry-ioc-jcache'
+ ]
+
+ def subprojectsToConsider = subprojects.findAll {
+ !excludedProjects.contains(it.name)
+ }
+
+ dependsOn = subprojectsToConsider.test
+
+ additionalSourceDirs.from(files(subprojectsToConsider.sourceSets.main.allSource.srcDirs))
+ sourceDirectories.from(files(subprojectsToConsider.sourceSets.main.allSource.srcDirs))
+ classDirectories.from(files(subprojectsToConsider.sourceSets.main.output))
+ executionData.from(files(subprojectsToConsider.jacocoTestReport.executionData).filter {
+ it.exists()
+ })
+ jacocoClasspath = files(subprojectsToConsider.jacocoTestReport.jacocoClasspath)
+
+ reports {
+ html {
+ required = true
+ outputLocation = layout.buildDirectory.dir('reports/jacoco')
+ }
+ xml.required = false
+ csv.required = false
}
}
-task combinedJacocoReport(type:JacocoReport){
- def subprojectsToConsider = subprojects.findAll {it.name != 'quickstart' && it.name != 'beanmodel' && it.name != 'commons' && it.name != 'genericsresolver-guava' && it.name != 'tapestry5-annotations' && it.name != 'tapestry-internal-test' && it.name != 'tapestry-runner' && it.name != 'tapestry-test-constants' && it.name != 'tapestry-test-data' && it.name != 'tapestry-ioc-jcache'}
- dependsOn = subprojectsToConsider.test
- additionalSourceDirs.from(files(subprojectsToConsider.sourceSets.main.allSource.srcDirs))
- sourceDirectories.from(files(subprojectsToConsider.sourceSets.main.allSource.srcDirs))
- classDirectories.from(files(subprojectsToConsider.sourceSets.main.output))
- executionData.from(files(subprojectsToConsider.jacocoTestReport.executionData).filter { it.exists() })
- jacocoClasspath = files(subprojectsToConsider.jacocoTestReport.jacocoClasspath)
- reports {
- html {
- required = true
- destination = file("$buildDir/reports/jacoco")
- }
- xml {
- required = false
- }
- csv {
- required = false
- }
- }
- onlyIf = {
- true
- }
-}
+tasks.register('continuousIntegration') {
+ group = 'Verification'
+ description = 'Runs a full CI build: assembles all artifacts, runs all checks, and generates aggregate reports.'
-task continuousIntegration {
def dependants = [
- 'tapestry-core:testWithPrototypeAndRequireJsDisabled',
- 'tapestry-core:testWithJqueryAndRequireJsDisabled',
- subprojects.build, // jQuery and Require.js enabled
- 'tapestry-core:testWithPrototypeAndRequireJsEnabled',
- combinedJacocoReport]
+ 'tapestry-core:testWithPrototypeAndRequireJsDisabled',
+ 'tapestry-core:testWithJqueryAndRequireJsDisabled',
+ 'tapestry-core:testWithPrototypeAndRequireJsEnabled',
+ subprojects.check, // jQuery and Require.js enabled
+ combinedJacocoReport
+ ]
+
// tapestry-javadoc doesn't work with Java 8 anymore. That's why it's only added if != 8.
if (JavaVersion.current() != JavaVersion.VERSION_1_8) {
dependants << aggregateJavadoc
}
- dependsOn dependants
- description "Task executed on Jenkins CI server after Git commits"
+
+ dependsOn(dependants)
}
-task zippedSources(type: Zip) {
- description "Creates a combined Zip file of all sub-project's sources"
- group "Release artifact"
+
+tasks.register('zippedSources', Zip) {
+ group = 'Release artifact'
+ description = "Creates a combined Zip file of all sub-project's sources"
- dependsOn("tapestry-core:compileTypeScript")
+ dependsOn 'tapestry-core:compileTypeScript'
- destinationDirectory = buildDir
- archiveBaseName = "apache-tapestry"
+ destinationDirectory = layout.buildDirectory
+ archiveBaseName = 'apache-tapestry'
version project.version
- archiveClassifier = "sources"
+ archiveClassifier = 'sources'
from project.projectDir
- exclude "out/**"
- exclude "**/*.iml"
- exclude "**/*.ipr"
- exclude "**/*.iws"
- exclude "**/.*/**"
- exclude "**/bin/**"
- exclude "**/target/**"
- exclude "**/build/**"
- exclude "**/test-output/**" // Left around by TestNG sometimes
- exclude "**/modules/***.js"
- exclude "**/es-modules/***.js"
+ exclude 'out/**'
+ exclude '**/*.iml'
+ exclude '**/*.ipr'
+ exclude '**/*.iws'
+ exclude '**/.*/**'
+ exclude '**/bin/**'
+ exclude '**/target/**'
+ exclude '**/build/**'
+ exclude '**/test-output/**' // Left around by TestNG sometime
+ exclude '**/modules/***.js'
+ exclude '**/es-modules/***.js'
}
-task zippedApidoc(type: Zip) {
+tasks.register('zippedApidoc', Zip) {
+ group = 'Release artifact'
+ description = "Zip archive of the project's aggregate JavaDoc and TypeScript documentation"
+
dependsOn typeScriptDocs
dependsOn aggregateJavadoc
- description "Zip archive of the project's aggregate JavaDoc and TypeScript documentation"
- group "Release artifact"
- destinationDirectory = buildDir
- archiveBaseName = "apache-tapestry"
+ destinationDirectory = layout.buildDirectory
+ archiveBaseName = 'apache-tapestry'
version project.version
- archiveClassifier = "apidocs"
+ archiveClassifier = 'apidocs'
- from file("src/docroot-template"), {
+ from(file('src/docroot-template')) {
filter ReplaceTokens, tokens: [version: project.version]
- include "*.html"
+ include '*.html'
}
- from file("src/docroot-template"), {
- exclude "*.html"
+ from(file('src/docroot-template')) {
+ exclude '*.html'
}
- into "apidocs", { from aggregateJavadoc.outputs.files }
-
-
- into "typescript", { from typeScriptDocs.outputs.files }
+ into('apidocs') {
+ from aggregateJavadoc.outputs.files
+ }
+ into('typescript') {
+ from typeScriptDocs.outputs.files
+ }
}
-task zippedBinaries(type: Zip) {
- description "Zip archive of binaries of each sub-project"
+tasks.register('zippedBinaries', Zip) {
+ group 'Release artifact'
+ description 'Zip archive of binaries of each sub-project'
+
// TODO: Plus dependencies?
- group "Release artifact"
// This may create a few unwanted dependencies, but does
// seem to ensure that the subprojects are created
inputs.files subprojects*.configurations*.archives.artifacts.files
- destinationDirectory = buildDir
- archiveBaseName = "apache-tapestry"
+ destinationDirectory = layout.buildDirectory
+ archiveBaseName = 'apache-tapestry'
version project.version
- archiveClassifier = "bin"
+ archiveClassifier = 'bin'
// This is via some experimentation
from subprojects*.configurations*.archives.artifacts*.file*.findAll {
- !(it.name.endsWith(".asc") || it.name.startsWith("quickstart"))
+ !(it.name.endsWith('.asc') || it.name.startsWith('quickstart'))
}
from configurations.binaries
@@ -622,12 +456,12 @@ task zippedBinaries(type: Zip) {
// Pick up various licenses and notices
from(projectDir) {
- include "*.txt"
+ include '*.txt'
}
subprojects.each { sub ->
from(sub.projectDir) {
- include "*.txt"
+ include '*.txt'
into sub.name
}
}
@@ -649,25 +483,19 @@ if (canDeploy) {
upload.extendsFrom archives, signatures
}
- task generateMD5Checksums(type: GenMD5) {
- group "Release artifact"
- description "Creates MD5 checksums for archives of source and JavaDoc"
- source tasks.withType(Zip)
- outputDir "$buildDir/md5"
- }
+ tasks.register('generateChecksums', GenerateChecksums) {
+ group 'Release artifact'
+ description 'Creates MD5/SHA256 checksums for archives of source and JavaDoc'
- task generateSHA256Checksums(type: GenSHA256) {
- group "Release artifact"
- description "Creates SHA-256 checksums for archives of source and JavaDoc"
source tasks.withType(Zip)
- outputDir "$buildDir/sha256"
+ outputDir = layout.buildDirectory.dir('checksums')
}
// This requires that you have the apacheArchivesFolder property configured in your
// ~/.gradle/gradle.properties. The folder should be a Subversion workspace for
// https://dist.apache.org/repos/dist/dev/tapestry
- // after the build, you must manually add the new files to the workspace (using "svn add")
- // then commit ("svn commit").
+ // after the build, you must manually add the new files to the workspace (using 'svn add')
+ // then commit ('svn commit').
// The files will be visible in https://dist.apache.org/repos/dist/dev/tapestry/, allowing
// committers to download and verify them.
@@ -677,75 +505,71 @@ if (canDeploy) {
// there will publish them to http://www.apache.org/dist/tapestry ... and from there
// to all Apache mirrors (after about a 24 hour delay).
- task copyArchives(type: Copy) {
- group "Release artifact"
- description "Copies build archives (source, bin, docs) to a configured deployment folder, along with MD5 and SHA-256 checksums and PGP signatures (if signing is enabled)"
+ tasks.register('copyArchives', Copy) {
+ group 'Release artifact'
+ description 'Copies build archives (source, bin, docs) to a configured deployment folder, along with MD5 and SHA-256 checksums and PGP signatures (if signing is enabled)'
- destinationDir file(archiveDeployFolder())
+ destinationDirectory = file(archiveDeployFolder.get())
- from generateMD5Checksums
- from generateSHA256Checksums
+ from tasks.generateChecksums
from configurations.uploads.allArtifacts.files
}
- task generateRelease {
+ tasks.register('generateRelease') {
+ group 'Release artifact'
+ description 'Generates and uploads a final release to Apache Nexus and copies archives for deployment'
+
dependsOn subprojects.assemble, subprojects.uploadPublished, subprojects.publish, copyArchives
- group "Release artifact"
- description "Generates and uploads a final release to Apache Nexus and copies archives for deployment"
}
}
-boolean isSnapshot() {
- project.version.contains("SNAPSHOT")
-}
+tasks.register('updateBootstrap') {
+ group = 'Maintenance'
+ description = 'Updates the included Bootstrap dependencies from GitHub'
-boolean isWindows() {
- System.properties['os.name'].toLowerCase().contains('windows')
-}
+ doLast {
+ def bootstrapVersion = '3.3.7'
+ def target = new File(temporaryDir, 'bootstrap.zip')
+ ant.get(src: "https://github.com/twbs/bootstrap/archive/v${bootstrapVersion}.zip", dest: target)
+
+ def adjustDirectory = {
+ def relativePath = it.relativePath
+ if (relativePath.pathString.contains('/dist/')){
+ relativePath = new RelativePath(!it.file.isDirectory(), relativePath.segments[2..-1] as String[])
+ } else {
+ relativePath = new RelativePath(!it.file.isDirectory(), relativePath.segments[1..-1] as String[])
+ }
+ println "copying ${it.relativePath} to ${relativePath}"
+ it.relativePath = relativePath
+ }
+
+ copy {
+ from(zipTree(target)){
+ include('*/js/*.js')
+ include('*/dist/fonts/*')
+ eachFile adjustDirectory
+ }
+ from(zipTree(target)){
+ include('*/dist/css/bootstrap.css')
+ include('*/dist/css/bootstrap-theme.css')
+ eachFile adjustDirectory
+ // TAP5-2351: remove source map reference from css files
+ filter({
+ (it ==~ /\/\*\s*# sourceMappingURL=[\S]+\s*\*\//) ? '' : it
+ })
+ }
+ into('tapestry-core/src/main/resources/META-INF/assets/tapestry5/bootstrap/')
+ }
-task updateBootstrap {
- doLast {
- def bootstrapVersion = '3.3.7'
- def target = new File(temporaryDir, 'bootstrap.zip')
- ant.get(src: "https://github.com/twbs/bootstrap/archive/v${bootstrapVersion}.zip", dest: target)
-
- def adjustDirectory = {
- def relativePath = it.relativePath
- if (relativePath.pathString.contains('/dist/')){
- relativePath = new RelativePath(!it.file.isDirectory(), relativePath.segments[2..-1] as String[])
- } else {
- relativePath = new RelativePath(!it.file.isDirectory(), relativePath.segments[1..-1] as String[])
- }
- println "copying $it.relativePath to $relativePath"
- it.relativePath = relativePath
-
- }
-
- copy {
- from(zipTree(target)){
- include('*/js/*.js')
- include('*/dist/fonts/*')
- eachFile adjustDirectory
- }
- from(zipTree(target)){
- include('*/dist/css/bootstrap.css')
- include('*/dist/css/bootstrap-theme.css')
- eachFile adjustDirectory
- // TAP5-2351: remove source map reference from css files
- filter({ (it ==~ /\/\*\s*# sourceMappingURL=[\S]+\s*\*\//) ? "" : it })
- }
- into('tapestry-core/src/main/resources/META-INF/assets/tapestry5/bootstrap/')
- }
-
- copy {
- from(zipTree(target)){
- include('*/js/*.js')
- include('*/dist/fonts/*')
- include('*/less/**/*.less')
-
- eachFile adjustDirectory
- }
- into('tapestry-webresources/src/test/webapp/bootstrap/')
- }
- }
+ copy {
+ from(zipTree(target)){
+ include('*/js/*.js')
+ include('*/dist/fonts/*')
+ include('*/less/**/*.less')
+
+ eachFile adjustDirectory
+ }
+ into('tapestry-webresources/src/test/webapp/bootstrap/')
+ }
+ }
}
diff --git a/buildSrc/build.gradle b/buildSrc/build.gradle
new file mode 100644
index 000000000..a4c2a3726
--- /dev/null
+++ b/buildSrc/build.gradle
@@ -0,0 +1,20 @@
+plugins {
+ id 'groovy-gradle-plugin'
+}
+
+repositories {
+ gradlePluginPortal()
+}
+
+dependencies {
+ implementation('ro.isdc.wro4j:wro4j-extensions:1.8.0') {
+ exclude group: 'org.jruby'
+ exclude module: 'spring-web'
+ exclude module: 'closure-compiler'
+ exclude module: 'gmaven-runtime-1.7'
+ exclude module: 'less4j'
+ }
+ implementation 'org.apache.ant:ant-jsch:1.8.2'
+
+ gradleApi()
+}
diff --git a/buildSrc/src/main/groovy/t5build/GenerateChecksums.groovy b/buildSrc/src/main/groovy/t5build/GenerateChecksums.groovy
new file mode 100644
index 000000000..dd9f9997f
--- /dev/null
+++ b/buildSrc/src/main/groovy/t5build/GenerateChecksums.groovy
@@ -0,0 +1,61 @@
+package t5build
+
+import org.gradle.api.DefaultTask
+import org.gradle.api.file.DirectoryProperty
+import org.gradle.api.tasks.InputFiles
+import org.gradle.api.tasks.OutputDirectory
+import org.gradle.api.tasks.TaskAction
+import org.gradle.api.tasks.SourceTask
+import org.gradle.api.file.ConfigurableFileCollection
+
+import java.security.MessageDigest
+
+class GenerateChecksums extends SourceTask {
+
+ enum Algorithm {
+ MD5('MD5', 32, 'md5'),
+ SHA256('SHA-256', 64, 'sha256')
+
+ final String name
+ final int padding
+ final String extension
+
+ Algorithm(String name, int padding, String extension) {
+ this.name = name
+ this.padding = padding
+ this.extension = extension
+ }
+ }
+
+ @OutputDirectory
+ File outputDir
+
+
+ @TaskAction
+ void generate() {
+ source.each { file ->
+ // Create a map of MessageDigest instances, one for each algorithm,
+ // so it's easier to update them and use later
+ def digests = Algorithm.values().collectEntries { alg ->
+ [(alg): MessageDigest.getInstance(alg.name)]
+ }
+
+ // use inputstream so to avoid loading whole file into memory
+ file.withInputStream { is ->
+ byte[] buffer = new byte[8192]
+ int bytesRead
+ while ((bytesRead = is.read(buffer)) != -1) {
+ digests.values().each { digest ->
+ digest.update(buffer, 0, bytesRead)
+ }
+ }
+ }
+
+ // Write checksum files
+ digests.each { algo, digest ->
+ def checksum = new BigInteger(1, digest.digest()).toString(16).padLeft(algo.padding, '0')
+ new File(outputDir, "${file.name}.${algo.extension}").text = checksum
+ }
+ }
+ }
+}
diff --git a/buildSrc/src/main/groovy/t5build/SSshExec.groovy b/buildSrc/src/main/groovy/t5build/SSshExec.groovy
new file mode 100644
index 000000000..e985b4591
--- /dev/null
+++ b/buildSrc/src/main/groovy/t5build/SSshExec.groovy
@@ -0,0 +1,21 @@
+package t5build
+
+import org.gradle.api.tasks.Input
+import org.gradle.api.tasks.TaskAction
+
+class SshExec extends SshTask {
+
+ @Input
+ List<String[]> commandLines = []
+
+ void commandLine(String... commandLine) {
+ commandLines << commandLine
+ }
+
+ @TaskAction
+ void doActions() {
+ commandLines.each { commandLine ->
+ ssh(*commandLine)
+ }
+ }
+}
\ No newline at end of file
diff --git a/buildSrc/src/main/groovy/t5build/Scp.groovy b/buildSrc/src/main/groovy/t5build/Scp.groovy
new file mode 100644
index 000000000..3280cfb9d
--- /dev/null
+++ b/buildSrc/src/main/groovy/t5build/Scp.groovy
@@ -0,0 +1,36 @@
+package t5build
+
+import org.gradle.api.tasks.Input
+import org.gradle.api.tasks.InputFiles
+import org.gradle.api.tasks.SkipWhenEmpty
+import org.gradle.api.tasks.TaskAction
+import java.io.File
+
+class Scp extends SshTask {
+
+ @InputFiles @SkipWhenEmpty
+ def source
+
+ @Input
+ String destination
+
+ @Input
+ boolean isDir = false
+
+ @TaskAction
+ void doActions() {
+ if (isDir) {
+ scpDir(source, destination)
+ return
+ }
+ project.files(source).each { doFile(it) }
+ }
+
+ private void doFile(File file) {
+ if (file.isDirectory()) {
+ file.eachFile { doFile(it) }
+ } else {
+ scpFile(file, destination)
+ }
+ }
+}
\ No newline at end of file
diff --git a/buildSrc/src/main/groovy/t5build/SshTask.groovy b/buildSrc/src/main/groovy/t5build/SshTask.groovy
new file mode 100644
index 000000000..769b32adf
--- /dev/null
+++ b/buildSrc/src/main/groovy/t5build/SshTask.groovy
@@ -0,0 +1,94 @@
+package t5build
+
+import org.gradle.api.DefaultTask
+import org.gradle.api.file.FileCollection
+import org.gradle.api.logging.LogLevel
+import org.gradle.api.tasks.Input
+import org.gradle.api.tasks.InputFiles
+import org.gradle.api.tasks.Internal
+
+abstract class SshTask extends DefaultTask {
+
+ @InputFiles
+ FileCollection sshAntClasspath
+
+ @Input
+ String host
+
+ @Input
+ String userName
+
+ // TODO: Passwords should not be plain @Input.
+ @Input
+ String password
+
+ @Input
+ boolean verbose = false
+
+ private boolean antInited = false
+
+ protected void initAnt() {
+ if (antInited) {
+ return
+ }
+ ant.taskdef(name: 'scp',
+ classname: 'org.apache.tools.ant.taskdefs.optional.ssh.Scp',
+ classpath: sshAntClasspath.asPath,
+ loaderref: 'ssh')
+
+ ant.taskdef(name: 'sshexec',
+ classname: 'org.apache.tools.ant.taskdefs.optional.ssh.SSHExec',
+ classpath: sshAntClasspath.asPath,
+ loaderref: 'ssh')
+ antInited = true
+ }
+
+ protected void withInfoLogging(Closure action) {
+ def oldLogLevel = getLogging().getLevel()
+ getLogging().setLevel([LogLevel.INFO, oldLogLevel].min())
+ try {
+ action()
+ } finally {
+ if (oldLogLevel != null) {
+ getLogging().setLevel(oldLogLevel)
+ }
+ }
+ }
+
+ protected void scpFile(Object source, String destination) {
+ initAnt()
+ withInfoLogging {
+ // TODO: This keyfile is hardcoded and uses an old algorithm (dsa)
+ ant.scp(localFile: project.files(source).singleFile,
+ remoteToFile: "${userName}@${host}:${destination}",
+ keyfile: "${System.properties['user.home']}/.ssh/id_dsa",
+ verbose: verbose)
+ }
+ }
+
+ protected void scpDir(Object source, String destination) {
+ initAnt()
+ withInfoLogging {
+ ant.sshexec(host: host,
+ username: userName,
+ password: password,
+ command: "mkdir -p ${destination}")
+
+ ant.scp(remoteTodir: "${userName}@${host}:${destination}",
+ keyfile: "${System.properties['user.home']}/.ssh/id_dsa",
+ verbose: verbose) {
+ project.files(source).addToAntBuilder(ant, 'fileSet', FileCollection.AntType.FileSet)
+ }
+ }
+ }
+
+ protected void ssh(Object... commandLine) {
+ initAnt()
+ withInfoLogging {
+ ant.sshexec(host: host,
+ username: userName,
+ password: password,
+ command: commandLine.join(' '))
+ }
+ }
+}
diff --git a/buildSrc/src/main/groovy/t5build/TapestryBuildLogic.groovy b/buildSrc/src/main/groovy/t5build/TapestryBuildLogic.groovy
new file mode 100644
index 000000000..13f9b935a
--- /dev/null
+++ b/buildSrc/src/main/groovy/t5build/TapestryBuildLogic.groovy
@@ -0,0 +1,22 @@
+package t5build
+
+import org.gradle.api.Project
+
+class TapestryBuildLogic {
+
+ static boolean isSnapshot(Project project) {
+ return tapestryVersion(project).endsWith('SNAPSHOT')
+ }
+
+ static boolean isWindows() {
+ return System.properties['os.name'].toLowerCase().contains('windows')
+ }
+
+ static String tapestryVersion(Project project) {
+ String major = project.rootProject.ext.tapestryMajorVersion
+ String minor = project.rootProject.ext.tapestryMinorVersion
+
+ boolean isCiBuild = project.rootProject.hasProperty('continuousIntegrationBuild') && project.rootProject.continuousIntegrationBuild
+ return isCiBuild ? major + '-SNAPSHOT' : major + minor
+ }
+}
\ No newline at end of file
diff --git a/buildSrc/src/main/groovy/tapestry.java-convention.gradle b/buildSrc/src/main/groovy/tapestry.java-convention.gradle
new file mode 100644
index 000000000..b94a82142
--- /dev/null
+++ b/buildSrc/src/main/groovy/tapestry.java-convention.gradle
@@ -0,0 +1,66 @@
+plugins {
+ id 'java-library'
+ id 'eclipse'
+ id 'idea'
+ id 'groovy'
+}
+
+java {
+ sourceCompatibility = JavaVersion.VERSION_1_8
+ targetCompatibility = JavaVersion.VERSION_1_8
+
+ withSourcesJar()
+}
+
+configurations {
+ provided
+ meta
+}
+
+// Ensure the 'provided' dependencies are available on the compile classpaths.
+sourceSets {
+ main.compileClasspath += configurations.provided
+ test.compileClasspath += configurations.provided
+ test.runtimeClasspath += configurations.provided
+}
+
+// Ensure IDEs understand the 'provided' configuration and more IDE setup
+idea {
+ module {
+ scopes.PROVIDED.plus += [configurations.provided]
+ }
+}
+eclipse.classpath.plusConfigurations += [configurations.provided]
+
+
+// Enforce consistent dependency versions across all modules using constraints.
+// This prevents multiple versions of the same library from appearing in the classpath.
+// The versions themselves are defined in `gradle/libs.versions.toml`.
+dependencies {
+ constraints {
+ implementation libs.cglib.nodep
+ implementation libs.commons.codec
+ implementation libs.commons.io
+ implementation libs.commons.logging
+ implementation("${libs.hsqldb.get().module.group}:${libs.hsqldb.get().module.name}:${libs.hsqldb.get().version}:jdk8")
+ implementation libs.hamcrest.core
+ implementation libs.json
+ implementation libs.snakeyaml
+ implementation libs.xml.apis
+ }
+}
+
+tasks.withType(Jar).configureEach {
+ // Include license/notice files in the final JAR.
+ from(project.projectDir) {
+ include '*.txt'
+ into 'META-INF'
+ }
+
+ // JPMS compatibility
+ manifest {
+ attributes("Automatic-Module-Name": "org.apache.tapestry.${project.name}"
+ .replace('tapestry-', '')
+ .replace('-', '.'))
+ }
+}
diff --git a/buildSrc/src/main/groovy/tapestry.junit4-legacy-convention.gradle b/buildSrc/src/main/groovy/tapestry.junit4-legacy-convention.gradle
new file mode 100644
index 000000000..436efdc53
--- /dev/null
+++ b/buildSrc/src/main/groovy/tapestry.junit4-legacy-convention.gradle
@@ -0,0 +1,12 @@
+plugins {
+ id 'tapestry.testing-base-convention'
+}
+
+dependencies {
+ testImplementation libs.junit4
+ testImplementation libs.hamcrest.core
+}
+
+tasks.withType(Test).configureEach {
+ useJUnit()
+}
diff --git a/buildSrc/src/main/groovy/tapestry.junit5-convention.gradle b/buildSrc/src/main/groovy/tapestry.junit5-convention.gradle
new file mode 100644
index 000000000..0d2bf88de
--- /dev/null
+++ b/buildSrc/src/main/groovy/tapestry.junit5-convention.gradle
@@ -0,0 +1,13 @@
+plugins {
+ id 'tapestry.testing-base-convention'
+}
+
+dependencies {
+ testImplementation platform(libs.junit.bom)
+ testImplementation libs.bundles.junit.jupiter.essentials
+ testRuntimeOnly libs.junit.jupiter.engine
+}
+
+tasks.withType(Test).configureEach {
+ useJUnitPlatform()
+}
diff --git a/buildSrc/src/main/groovy/tapestry.junit5-spock-convention.gradle b/buildSrc/src/main/groovy/tapestry.junit5-spock-convention.gradle
new file mode 100644
index 000000000..3f58f33c0
--- /dev/null
+++ b/buildSrc/src/main/groovy/tapestry.junit5-spock-convention.gradle
@@ -0,0 +1,9 @@
+plugins {
+ id 'tapestry.junit5-convention'
+ id 'groovy'
+}
+
+dependencies {
+ testImplementation platform(libs.spock.bom)
+ testImplementation libs.spock.core
+}
diff --git a/buildSrc/src/main/groovy/tapestry.ssh-convention.gradle b/buildSrc/src/main/groovy/tapestry.ssh-convention.gradle
new file mode 100644
index 000000000..2f6aa7c8a
--- /dev/null
+++ b/buildSrc/src/main/groovy/tapestry.ssh-convention.gradle
@@ -0,0 +1,15 @@
+import t5build.SshTask
+
+// This configuration will hold the ant-jsch.jar at runtime
+configurations {
+ sshAntTask
+}
+
+dependencies {
+ sshAntTask libs.ant.jsch
+}
+
+// Configure all SshTask instances to use the files from the configuration
+tasks.withType(SshTask).configureEach {
+ it.sshAntClasspath = configurations.sshAntTask
+}
diff --git a/buildSrc/src/main/groovy/tapestry.testing-base-convention.gradle b/buildSrc/src/main/groovy/tapestry.testing-base-convention.gradle
new file mode 100644
index 000000000..7a3efcd79
--- /dev/null
+++ b/buildSrc/src/main/groovy/tapestry.testing-base-convention.gradle
@@ -0,0 +1,64 @@
+plugins {
+ id 'java-library'
+}
+
+dependencies {
+ testRuntimeOnly libs.slf4j.simple
+}
+
+tasks.withType(Test).configureEach { testTask ->
+ maxHeapSize = '600M'
+
+ systemProperties['tapestry.service-reloading-enabled'] = 'false'
+ systemProperties['java.io.tmpdir'] = temporaryDir.absolutePath
+
+ jvmArgs '-Dfile.encoding=UTF-8'
+ environment.LANG = 'en_US.UTF-8'
+
+ // TAP5-2722
+ systemProperty 'user.language', 'en'
+
+ testLogging {
+ exceptionFormat 'full'
+ events 'passed', 'skipped', 'failed'
+ showStandardStreams = true
+ }
+
+ def total = 0, passed = 0, failed = 0, skipped = 0
+
+ afterTest { descriptor, result ->
+ switch (result.resultType) {
+ case org.gradle.api.tasks.testing.TestResult.ResultType.SUCCESS:
+ passed++
+ break
+ case org.gradle.api.tasks.testing.TestResult.ResultType.FAILURE:
+ failed++
+ break
+ case org.gradle.api.tasks.testing.TestResult.ResultType.SKIPPED:
+ skipped++
+ break
+ }
+ total++
+ if (total % 25 == 0) {
+ logger.lifecycle "Project ${project.name}: Tests run: ${total}, Passed: ${passed}, Failed: ${failed}, Skipped: ${skipped}"
+ }
+ }
+
+ afterSuite { descriptor, result ->
+ // The root suite has a null parent. We only want to log the final summary.
+ if (descriptor.parent == null) {
+ total = passed + failed + skipped
+ // Using project.path gives a clear identifier like ":tapestry-core"
+ def projectName = project.path
+
+ // Don't log if no tests were run
+ if (total > 0) {
+ logger.lifecycle "------------------------------------------------------------------------"
+ logger.lifecycle "Test Results for ${projectName}"
+ logger.lifecycle " Tests run: ${total}, Passed: ${passed}, Failed: ${failed}, Skipped: ${skipped}"
+ logger.lifecycle "------------------------------------------------------------------------"
+ }
+ }
+ }
+}
+
diff --git a/buildSrc/src/main/groovy/tapestry.testng-convention.gradle b/buildSrc/src/main/groovy/tapestry.testng-convention.gradle
new file mode 100644
index 000000000..90dac3640
--- /dev/null
+++ b/buildSrc/src/main/groovy/tapestry.testng-convention.gradle
@@ -0,0 +1,27 @@
+plugins {
+ id 'tapestry.testing-base-convention'
+}
+
+dependencies {
+ testImplementation libs.testng
+ testImplementation libs.easymock
+ testImplementation libs.hamcrest.core
+}
+
+tasks.withType(Test).configureEach { testTask ->
+
+ def suiteFile = [
+ 'src/test/resources/testng.xml',
+ 'src/test/conf/testng.xml'
+ ].find { path ->
+ project.file(path).exists()
+ }
+
+ if (suiteFile) {
+ testTask.useTestNG {
+ suites suiteFile
+ }
+ } else {
+ testTask.useTestNG()
+ }
+}
diff --git a/commons/build.gradle b/commons/build.gradle
index 99cb1d4d9..ecc9bf194 100644
--- a/commons/build.gradle
+++ b/commons/build.gradle
@@ -1,24 +1,12 @@
-import org.gradle.plugins.ide.idea.model.*
-import t5build.*
-
-description = "Project including common classes for tapestry-core, tapestry-ioc and beanmodel."
+plugins {
+ id 'tapestry.junit5-spock-convention'
+}
-//apply plugin: JavaPlugin
+description = 'Project including common classes for tapestry-core, tapestry-ioc and beanmodel.'
-buildDir = 'target/gradle-build'
-
dependencies {
- api project(":plastic")
- api project(":tapestry5-annotations")
- implementation project(":tapestry-func")
- testImplementation "org.junit.jupiter:junit-jupiter:${versions.junitJupiter}"
-}
+ api project(':plastic')
+ api project(':tapestry5-annotations')
-jar {
- manifest {
- }
+ implementation project(':tapestry-func')
}
-
-test {
- useJUnit()
-}
\ No newline at end of file
diff --git a/genericsresolver-guava/build.gradle b/genericsresolver-guava/build.gradle
index a20be0d48..90892270a 100644
--- a/genericsresolver-guava/build.gradle
+++ b/genericsresolver-guava/build.gradle
@@ -1,9 +1,13 @@
+plugins {
+ id 'tapestry.testng-convention'
+}
description = "Replaces the Tapestry Commons's own Java Generics resolution code with the one from Google Guava's one"
dependencies {
- implementation project(':commons')
- testImplementation project(':tapestry-core')
- testImplementation project(':tapestry-test')
- provided implementation ('com.google.guava:guava:27.0.1-jre')
- testImplementation "org.junit.jupiter:junit-jupiter:${versions.junitJupiter}"
-}
\ No newline at end of file
+ implementation project(':commons')
+
+ provided libs.guava
+
+ testImplementation project(':tapestry-core')
+ testImplementation project(':tapestry-test')
+}
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
new file mode 100644
index 000000000..b0055439f
--- /dev/null
+++ b/gradle/libs.versions.toml
@@ -0,0 +1,168 @@
+[versions]
+
+# LOGGING
+
+slf4j = "1.7.25"
+
+# JAVAX/JAKARTA
+
+javax-inject = "1"
+javax-servlet-api = "3.0.1"
+javax-validation-api = "1.0.0.GA"
+
+jakarta-annotation-api = "1.3.4"
+jakarta-persistence-api = "3.0.0"
+jakarta-xml-bind-api = "2.3.2"
+
+# APACHE COMMONS
+
+commons-cli = "1.2"
+commons-codec = "1.18.0"
+commons-httpclient = "4.1"
+commons-io = "2.19.0"
+commons-lang3 = "3.17.0"
+commons-logging = "1.3.5"
+commons-text = "1.13.1"
+
+# HIBERNATE
+
+hibernate = "5.4.32.Final"
+hibernate-validator = "4.3.2.Final"
+
+hsqldb = "2.7.3"
+
+# ANTLR
+
+antlr = "3.5.3"
+
+# MISC
+
+snakeyaml = "2.3"
+cglib = "2.2"
+hamcrest-core = "1.3"
+json = "20140107"
+xml-apis = "1.4.01"
+guice = "3.0"
+ant-jsch = "1.8.2"
+guava = "27.0.1-jre"
+jackson = "2.13.1"
+clojure = "1.6.0"
+httpcomponents-httpclient = "4.5.14"
+
+# TESTING
+
+slf4j-simple = "2.0.17"
+junit5 = "5.10.2"
+junit4 = "4.13.2"
+testng = "7.5.1"
+easymock = "5.4.0"
+spock = "2.3-groovy-3.0"
+geb = "2.0"
+webdrivermanager = "5.3.1"
+selenium = "4.5.0"
+selenium-java = "4.12.1"
+selenium-server = "4.12.1"
+
+# QUICKSTART
+
+quickstart-spring-boot = "2.5.4"
+quickstart-json = "1.1.4"
+quickstart-log4j = "2.17.2"
+quickstart-yasson = "2.0.4"
+quickstart-maven-compiler = "3.8.1"
+quickstart-maven-surefire = "3.1"
+quickstart-maven-war = "3.3.1"
+quickstart-maven-jetty = "10.0.6"
+quickstart-gretty = "3.0.6"
+
+[libraries]
+
+# LOGGING
+
+slf4j-api = { module = "org.slf4j:slf4j-api", version.ref = "slf4j" }
+slf4j-log4j12 = { module = "org.slf4j:slf4j-log4j12", version.ref = "slf4j" }
+
+# JAVAX/JAKARTA
+
+javax-inject = { module = "javax.inject:javax.inject", version.ref = "javax-inject" }
+javax-servlet-api = { module = "javax.servlet:javax.servlet-api", version.ref = "javax-servlet-api" }
+javax-validation-api = { module = "javax.validation:validation-api", version.ref = "javax-validation-api" }
+
+jakarta-annotation-api = { module = "jakarta.annotation:jakarta.annotation-api", version.ref = "jakarta-annotation-api" }
+jakarta-persistence-api = { module = "jakarta.persistence:jakarta.persistence-api", version.ref = "jakarta-persistence-api" }
+jakarta-xml-bind-api = { module = "jakarta.xml.bind:jakarta.xml.bind-api", version.ref = "jakarta-xml-bind-api" }
+
+# APACHE COMMONS
+
+commons-cli = { module = "commons-cli:commons-cli", version.ref = "commons-cli" }
+commons-codec = { module = "commons-codec:commons-codec", version.ref = "commons-codec" }
+commons-httpclient = { module = "commons-httpclient:commons-httpclient", version.ref = "commons-httpclient" }
+commons-io = { module = "commons-io:commons-io", version.ref = "commons-io" }
+commons-lang3 = { module = "org.apache.commons:commons-lang3", version.ref = "commons-lang3" }
+commons-logging = { module = "commons-logging:commons-logging", version.ref = "commons-logging" }
+commons-text = { module = "org.apache.commons:commons-text", version.ref = "commons-text" }
+
+# HIBERNATE
+
+hibernate-core = { module = "org.hibernate:hibernate-core", version.ref = "hibernate" }
+hibernate-validator = { module = "org.hibernate:hibernate-validator", version.ref = "hibernate-validator" }
+
+hsqldb = { module = "org.hsqldb:hsqldb", version.ref = "hsqldb" }
+
+# ANTLR
+
+antlr = { module = "org.antlr:antlr", version.ref = "antlr" }
+antlr-runtime = { module = "org.antlr:antlr-runtime", version.ref = "antlr" }
+
+# MISC
+
+snakeyaml = { module = "org.yaml:snakeyaml", version.ref = "snakeyaml" }
+cglib-nodep = { module = "cglib:cglib-nodep", version.ref = "cglib" }
+hamcrest-core = { module = "org.hamcrest:hamcrest-core", version.ref = "hamcrest-core" }
+json = { module = "org.json:json", version.ref = "json" }
+xml-apis = { module = "xml-apis:xml-apis", version.ref = "xml-apis" }
+guice = { module = "com.google.inject:guice", version.ref = "guice" }
+ant-jsch = { module = "org.apache.ant:ant-jsch", version.ref = "ant-jsch" }
+guava = { module = "com.google.guava:guava", version.ref = "guava" }
+clojure = { module = "org.clojure:clojure", version.ref = "clojure" }
+httpcomponents-httpclient = { module = "org.apache.httpcomponents:httpclient", version.ref = "httpcomponents-httpclient" }
+
+# JACKSON
+
+jackson-databind = { module = "com.fasterxml.jackson.core:jackson-databind", version.ref = "jackson" }
+
+# TESTING
+
+slf4j-simple = { module = "org.slf4j:slf4j-simple", version.ref = "slf4j-simple" }
+
+junit-bom = { module = "org.junit:junit-bom", version.ref = "junit5" }
+junit-jupiter = { module = "org.junit.jupiter:junit-jupiter"}
+junit-jupiter-api = { module = "org.junit.jupiter:junit-jupiter-api" }
+junit-jupiter-params = { module = "org.junit.jupiter:junit-jupiter-params" }
+junit-jupiter-engine = { module = "org.junit.jupiter:junit-jupiter-engine" }
+
+junit4 = { module = "junit:junit", version.ref = "junit4" }
+
+testng = { module = "org.testng:testng", version.ref = "testng" }
+
+easymock = { module = "org.easymock:easymock", version.ref = "easymock" }
+
+spock-bom = { module = "org.spockframework:spock-bom", version.ref = "spock" }
+spock-core = { module = "org.spockframework:spock-core" }
+
+geb-spock = { module = "org.gebish:geb-spock", version.ref = "geb" }
+
+selenium-legrc = { module = "org.seleniumhq.selenium:selenium-leg-rc", version.ref = "selenium" }
+selenium-api = { module = "org.seleniumhq.selenium:selenium-api", version.ref = "selenium" }
+selenium-java = { module = "org.seleniumhq.selenium:selenium-java", version.ref = "selenium-java" }
+selenium-server = { module = "org.seleniumhq.selenium:selenium-server", version.ref = "selenium-server" }
+
+webdrivermanager = { module = "io.github.bonigarcia:webdrivermanager", version.ref = "webdrivermanager" }
+
+
+[bundles]
+
+junit-jupiter-essentials = [
+ "junit-jupiter-api",
+ "junit-jupiter-params"
+]
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
index 41d9927a4..d64cd4917 100644
Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index a59520664..ff23a68d7 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,5 +1,7 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.2-bin.zip
+networkTimeout=10000
+validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/gradlew b/gradlew
index 1b6c78733..1aa94a426 100755
--- a/gradlew
+++ b/gradlew
@@ -55,7 +55,7 @@
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
-# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
@@ -80,13 +80,11 @@ do
esac
done
-APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
-
-APP_NAME="Gradle"
+# This is normally unused
+# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
-
-# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
+APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
@@ -133,22 +131,29 @@ location of your Java installation."
fi
else
JAVACMD=java
- which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+ if ! command -v java >/dev/null 2>&1
+ then
+ die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
+ fi
fi
# Increase the maximum file descriptors if we can.
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #(
max*)
+ # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
+ # shellcheck disable=SC2039,SC3045
MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit"
esac
case $MAX_FD in #(
'' | soft) :;; #(
*)
+ # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
+ # shellcheck disable=SC2039,SC3045
ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD"
esac
@@ -193,11 +198,15 @@ if "$cygwin" || "$msys" ; then
done
fi
-# Collect all arguments for the java command;
-# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
-# shell script including quotes and variable substitutions, so put them in
-# double quotes to make sure that they get re-expanded; and
-# * put everything else in single quotes, so that it's not re-expanded.
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+
+# Collect all arguments for the java command:
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
+# and any embedded shellness will be escaped.
+# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
+# treated as '${Hostname}' itself on the command line.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
@@ -205,6 +214,12 @@ set -- \
org.gradle.wrapper.GradleWrapperMain \
"$@"
+# Stop when "xargs" is not available.
+if ! command -v xargs >/dev/null 2>&1
+then
+ die "xargs is not available"
+fi
+
# Use "xargs" to parse quoted args.
#
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
diff --git a/gradlew.bat b/gradlew.bat
index ac1b06f93..6689b85be 100644
--- a/gradlew.bat
+++ b/gradlew.bat
@@ -14,7 +14,7 @@
@rem limitations under the License.
@rem
-@if "%DEBUG%" == "" @echo off
+@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@@ -25,7 +25,8 @@
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
-if "%DIRNAME%" == "" set DIRNAME=.
+if "%DIRNAME%"=="" set DIRNAME=.
+@rem This is normally unused
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@@ -40,7 +41,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
-if "%ERRORLEVEL%" == "0" goto execute
+if %ERRORLEVEL% equ 0 goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
@@ -75,13 +76,15 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
:end
@rem End local scope for the variables with windows NT shell
-if "%ERRORLEVEL%"=="0" goto mainEnd
+if %ERRORLEVEL% equ 0 goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
-if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
-exit /b 1
+set EXIT_CODE=%ERRORLEVEL%
+if %EXIT_CODE% equ 0 set EXIT_CODE=1
+if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
+exit /b %EXIT_CODE%
:mainEnd
if "%OS%"=="Windows_NT" endlocal
diff --git a/plastic/build.gradle b/plastic/build.gradle
index f5bdee139..35f5d8103 100644
--- a/plastic/build.gradle
+++ b/plastic/build.gradle
@@ -1,15 +1,18 @@
-description = "High-level runtime transformations of Java classes"
+plugins {
+ id 'tapestry.junit5-spock-convention'
+}
+
+description = 'High-level runtime transformations of Java classes'
dependencies {
- implementation "org.slf4j:slf4j-api:${versions.slf4j}"
- testImplementation "org.junit.jupiter:junit-jupiter:${versions.junitJupiter}"
+ implementation libs.slf4j.api
}
-test {
- useJUnit()
+// add vendored ASM
+sourceSets {
+ main {
+ java {
+ srcDir 'src/external/java'
+ }
+ }
}
-
-// Add the source directory for the imported/repackaged ASM 7.0.1 code
-
-sourceSets.main.java.srcDir "src/external/java"
-
diff --git a/quickstart/build.gradle b/quickstart/build.gradle
index 98225bf97..a88fe8054 100644
--- a/quickstart/build.gradle
+++ b/quickstart/build.gradle
@@ -50,18 +50,18 @@ task processFiltered(type: Copy) {
filter(ReplaceTokens, tokens: [
quickstartVersion: project.parent.version,
tapestryVersion: project.parent.version,
- springBootVersion: '2.5.4',
- junitVersion: '5.8.2',
- jacksonVersion: '2.13.1',
- jsonVersion: '1.1.4',
- log4jVersion: '2.17.2',
- yassonVersion: '2.0.4',
- servletVersion: '3.1.0',
- mavenCompilerVersion: '3.8.1',
- mavenSurefireVersion: '3.0.0-M5',
- mavenWarVersion: '3.3.1',
- mavenJettyVersion: '10.0.6',
- grettyVersion: '3.0.6'
+ springBootVersion: libs.versions.quickstart.spring.boot.get(),
+ junitVersion: libs.versions.junit5.get(),
+ jacksonVersion: libs.versions.jackson.get(),
+ jsonVersion: libs.versions.quickstart.json.get(),
+ log4jVersion: libs.versions.quickstart.log4j.get(),
+ yassonVersion: libs.versions.quickstart.yasson.get(),
+ servletVersion: libs.versions.javax.servlet.api.get(),
+ mavenCompilerVersion: libs.versions.quickstart.maven.compiler.get(),
+ mavenSurefireVersion: libs.versions.quickstart.maven.surefire.get(),
+ mavenWarVersion: libs.versions.quickstart.maven.war.get(),
+ mavenJettyVersion: libs.versions.quickstart.maven.jetty.get(),
+ grettyVersion: libs.versions.quickstart.gretty.get()
])
}
diff --git a/settings.gradle b/settings.gradle
index 58d041ac8..5f4f20356 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -3,20 +3,83 @@ plugins {
id 'com.gradle.common-custom-user-data-gradle-plugin' version '2.0.2'
}
+rootProject.name = 'tapestry-5'
+
+dependencyResolutionManagement {
+ repositories {
+ mavenLocal()
+ mavenCentral()
+ maven {
+ name = 'JBoss'
+ url = 'https://repository.jboss.org/nexus/content/repositories/releases/'
+ }
+ maven {
+ // tapestry-jpa
+ name = 'EclipseLink'
+ url = 'https://download.eclipse.org/rt/eclipselink/maven.repo/'
+ }
+ }
+}
+
+include('plastic',
+ 'tapestry5-annotations',
+ 'tapestry-test',
+ 'tapestry-func',
+ 'tapestry-ioc',
+ 'tapestry-json',
+ 'tapestry-http',
+ 'tapestry-core',
+ 'tapestry-hibernate-core',
+ 'tapestry-hibernate',
+ 'tapestry-jmx',
+ 'tapestry-upload',
+ 'tapestry-beanvalidator',
+ 'tapestry-jpa',
+ 'tapestry-kaptcha',
+ 'quickstart',
+ 'tapestry-clojure',
+ 'tapestry-mongodb',
+ 'tapestry-test-data',
+ 'tapestry-internal-test',
+ 'tapestry-ioc-junit',
+ 'tapestry-webresources',
+ 'tapestry-runner',
+ 'tapestry-test-constants',
+ 'tapestry-ioc-jcache',
+ 'beanmodel',
+ 'commons',
+ 'genericsresolver-guava',
+ 'tapestry-version-migrator',
+ 'tapestry-spock',
+ 'tapestry-openapi-viewer',
+ 'tapestry-rest-jackson')
+
+if (JavaVersion.current().isCompatibleWith(JavaVersion.VERSION_11)) {
+ include('tapestry-javadoc')
+}
+
+if (JavaVersion.current().isCompatibleWith(JavaVersion.VERSION_17)) {
+ include('tapestry-latest-java-tests', 'tapestry-spring')
+}
+
def isTravisCI = System.getenv('TRAVIS_JOB_ID') != null
def isJenkins = System.getenv('JENKINS_URL') != null
def isCI = isTravisCI || isJenkins
develocity {
- server = "https://develocity.apache.org"
- projectId = "tapestry"
+ server = 'https://develocity.apache.org'
+ projectId = 'tapestry'
buildScan {
uploadInBackground = !isCI
publishing.onlyIf { it.authenticated }
obfuscation {
// This obfuscates the IP addresses of the build machine in the build scan.
// Alternatively, the build scan will provide the hostname for troubleshooting host-specific issues.
- ipAddresses { addresses -> addresses.collect { address -> "0.0.0.0"} }
+ ipAddresses { addresses ->
+ addresses.collect { address ->
+ '0.0.0.0'
+ }
+ }
}
}
}
@@ -30,21 +93,3 @@ buildCache {
enabled = false
}
}
-
-rootProject.name = "tapestry-5"
-
-include "plastic", "tapestry5-annotations", "tapestry-test", "tapestry-func", "tapestry-ioc", "tapestry-json", "tapestry-http", "tapestry-core"
-include "tapestry-hibernate-core", "tapestry-hibernate", "tapestry-jmx", "tapestry-upload", "tapestry-spring"
-include "tapestry-beanvalidator", "tapestry-jpa", "tapestry-kaptcha"
-if (JavaVersion.current() != JavaVersion.VERSION_1_8) {
- include "tapestry-javadoc"
-}
-if (JavaVersion.current().isCompatibleWith(JavaVersion.VERSION_17)) {
- include "tapestry-latest-java-tests"
-}
-include "quickstart", "tapestry-clojure", "tapestry-mongodb"
-include "tapestry-test-data", 'tapestry-internal-test', "tapestry-ioc-junit"
-include "tapestry-webresources", "tapestry-runner", "tapestry-test-constants"
-include "tapestry-ioc-jcache", "beanmodel", "commons", "genericsresolver-guava", "tapestry-version-migrator"
-// include "tapestry-cdi"
-include "tapestry-spock", "tapestry-openapi-viewer", "tapestry-rest-jackson"
diff --git a/sha256.gradle b/sha256.gradle
deleted file mode 100644
index 8abaec5ff..000000000
--- a/sha256.gradle
+++ /dev/null
@@ -1,25 +0,0 @@
-import java.security.MessageDigest
-
-class GenSHA256 extends SourceTask {
-
- def outputDir
-
- @OutputDirectory
- File getOutputDir() { project.file(outputDir) }
-
- @TaskAction
- void writeSHA256s() {
-
- source.each { file ->
- MessageDigest digest = MessageDigest.getInstance("SHA-256")
-
- digest.update(file.bytes)
-
- def checksum = new BigInteger(1, digest.digest()).toString(16).padLeft(32, "0")
-
- new File(outputDir, file.name + ".sha256").text = checksum
- }
- }
-}
-
-project.ext.GenSHA256 = GenSHA256.class
\ No newline at end of file
diff --git a/ssh.gradle b/ssh.gradle
deleted file mode 100644
index e367719ce..000000000
--- a/ssh.gradle
+++ /dev/null
@@ -1,124 +0,0 @@
-project.ext.Scp = Scp.class
-project.ext.SshExec = SshExec.class
-project.ext.SshTask = SshTask.class
-
-configurations {
- sshAntTask
-}
-
-dependencies {
- sshAntTask "org.apache.ant:ant-jsch:1.8.2"
-}
-
-tasks.withType(SshTask) {
- sshAntClasspath = configurations.sshAntTask
-}
-
-class SshTask extends DefaultTask {
- @InputFiles
- FileCollection sshAntClasspath
-
- @Input
- String host
-
- @Input
- String userName
-
- @Input
- String password
-
- boolean verbose = false
-
- private boolean antInited = false
-
- protected initAnt() {
- if (!antInited) {
- ant.taskdef(name: 'scp',
- classname: 'org.apache.tools.ant.taskdefs.optional.ssh.Scp',
- classpath: sshAntClasspath.asPath,
- loaderref: 'ssh')
- ant.taskdef(name: 'sshexec',
- classname: 'org.apache.tools.ant.taskdefs.optional.ssh.SSHExec',
- classpath: sshAntClasspath.asPath,
- loaderref: 'ssh')
- antInited = true
- }
- }
-
- protected withInfoLogging(Closure action) {
- def oldLogLevel = logging.level
- logging.level = [LogLevel.INFO, oldLogLevel].min()
- try {
- action()
- } finally {
- if (oldLogLevel) {
- logging.level = oldLogLevel
- }
- }
- }
-
- def scpFile(source, destination) {
- initAnt()
- withInfoLogging {
- ant.scp(localFile: project.files(source).singleFile, remoteToFile: "${userName}@${host}:${destination}", keyfile : "${System.properties['user.home']}/.ssh/id_dsa", verbose: verbose)
- }
- }
-
- def scpDir(source, destination) {
- initAnt()
- withInfoLogging {
- ant.sshexec(host: host, username: userName, password: password, command: "mkdir -p ${destination}")
- ant.scp(remoteTodir: "${userName}@${host}:${destination}", keyfile : "${System.properties['user.home']}/.ssh/id_dsa", verbose: verbose) {
- project.files(source).addToAntBuilder(ant, "fileSet", FileCollection.AntType.FileSet)
- }
- }
- }
-
- def ssh(Object... commandLine) {
- initAnt()
- withInfoLogging {
- ant.sshexec(host: host, username: userName, password: password, command: commandLine.join(' '))
- }
- }
-}
-
-class Scp extends SshTask {
- @InputFiles @SkipWhenEmpty source
- @Input destination
- boolean isDir = false
-
- @TaskAction
- void doActions() {
- if (isDir) {
- scpDir(source, destination)
- return
- }
-
- project.files(source).each { doFile(it) }
- }
-
- void doFile(File file) {
-
- if (file.directory) {
- file.eachFile { doFile(it) }
- } else {
- scpFile(file, destination)
- }
- }
-}
-
-class SshExec extends SshTask {
- @Input
- List<String[]> commandLines = []
-
- void commandLine(String... commandLine) {
- commandLines << commandLine
- }
-
- @TaskAction
- void doActions() {
- commandLines.each { commandLine ->
- ssh(* commandLine)
- }
- }
-}
\ No newline at end of file
diff --git a/tapestry-beanvalidator/build.gradle b/tapestry-beanvalidator/build.gradle
index 82ba5f0b9..b11ffabcd 100644
--- a/tapestry-beanvalidator/build.gradle
+++ b/tapestry-beanvalidator/build.gradle
@@ -1,28 +1,34 @@
+plugins {
+ id 'tapestry.testng-convention'
+}
+
import t5build.*
-description = "Support for JSR-303 Bean Validation via the Hibernate validator implementation"
+description = 'Support for JSR-303 Bean Validation via the Hibernate validator implementation'
dependencies {
- implementation project(':tapestry-core')
-
- implementation "javax.validation:validation-api:1.0.0.GA"
- implementation "org.hibernate:hibernate-validator:4.3.2.Final"
-
- testImplementation project(':tapestry-test')
- implementation "org.seleniumhq.selenium:selenium-leg-rc:${versions.selenium}", {
- exclude group: "org.seleniumhq.selenium", module: "jetty-repacked"
- exclude group: "org.testng", module: "testng"
- exclude group: "javax.servlet", module: "javax.servlet-api"
- }
- testImplementation "org.junit.jupiter:junit-jupiter:${versions.junitJupiter}"
-
+ implementation project(':tapestry-core')
+
+ implementation libs.javax.validation.api
+ implementation libs.hibernate.validator
+
+ implementation(libs.selenium.legrc) {
+ exclude group: 'org.seleniumhq.selenium', module: 'jetty-repacked'
+ exclude group: 'org.testng', module: 'testng'
+ }
+
+ testImplementation project(':tapestry-test')
}
// Start up the test app, useful when debugging failing integration tests
-task runTestApp303(type:JavaExec) {
- main = 'org.apache.tapestry5.test.JettyRunner'
- args "-d", "src/test/webapp", "-p", "8080"
- classpath += project.sourceSets.test.runtimeClasspath
+tasks.register('runTestApp303', JavaExec) {
+ mainClass = 'org.apache.tapestry5.test.JettyRunner'
+ args '-d', 'src/test/webapp', '-p', '8080'
+ classpath += project.sourceSets.test.runtimeClasspath
}
-jar.manifest.attributes 'Tapestry-Module-Classes': 'org.apache.tapestry5.beanvalidator.modules.BeanValidatorModule'
+tasks.named('jar', Jar) {
+ manifest {
+ attributes 'Tapestry-Module-Classes': 'org.apache.tapestry5.beanvalidator.modules.BeanValidatorModule'
+ }
+}
diff --git a/tapestry-cdi/build.gradle b/tapestry-cdi/build.gradle
index 2e51bd96c..d40e22e16 100644
--- a/tapestry-cdi/build.gradle
+++ b/tapestry-cdi/build.gradle
@@ -8,22 +8,20 @@ apply plugin: JavaPlugin
buildDir = 'target/gradle-build'
project.ext.libraryVersions = [
- javaeeapi: '6.0-4',
- tomee: '1.6.0',
- ziplock: '1.5.1',
- junit: '4.8.1',
- commonsHttpclient: '3.1',
- arquillian: '1.1.1.Final',
- jbossJavaeeSpec: '1.0.0.Final',
- arquillianGlassfish: '1.0.0.CR4',
- glassfishDistrib: '3.1.1-b04',
- jbossDistrib: '7.1.1.Final',
- cdi: '1.0-SP4',
- jbossAS7: '7.1.1.Final',
- shrinkwrapDesc: '2.0.0-alpha-3'
+ tomee: 'org.apache.openejb:arquillian-tomee-embedded:1.6.0',
+ ziplock: 'org.apache.openejb:ziplock:1.5.1',
+ commonsHttpclient: 'commons-httpclient:commons-httpclient:3.1',
+ arquillianJunitContainer: 'org.jboss.arquillian.junit:arquillian-junit-container:1.1.1.Final',
+ arquillianGlassfish: 'org.jboss.arquillian.container:arquillian-glassfish-managed-3.1:1.0.0.CR4',
+ glassfishDistrib: 'org.glassfish.distributions:glassfish:3.1.1-b04@zip',
+ jbossAS7: 'org.jboss.as:jboss-as-arquillian-container-managed:7.1.1.Final',
+ jbossDistrib: 'org.jboss.as:jboss-as-dist:7.1.1.Final@zip',
+ jbossJavaeeSpec: 'org.jboss.spec:jboss-javaee-6.0:1.0.0.Final',
+ cdiApi: 'jakarta.enterprise:cdi-api:1.0-SP4',
+ shrinkwrapDescriptorsApi: 'org.jboss.shrinkwrap.descriptors:shrinkwrap-descriptors-api-javaee:2.0.0-alpha-3',
+ shrinkwrapDescriptorsImpl: 'org.jboss.shrinkwrap.descriptors:shrinkwrap-descriptors-impl-javaee:2.0.0-alpha-3',
]
-
configurations {
compileOnly
jboss
@@ -36,30 +34,28 @@ configurations {
dependencies {
compile project(':tapestry-core')
compile project(':tapestry-ioc')
- testCompile (project(':tapestry-test')){
- transitive = false
- }
-
- // replace javax.enterprise:cdi-api with group: 'org.jboss.spec', name: 'jboss-javaee-6.0', version: libraryVersions.jbossJavaeeSpec to compile against full Java EE API
- compileOnly group: 'javax.enterprise', name: 'cdi-api', version: libraryVersions.cdi
-
-
- testCompile group: 'org.apache.openejb', name: 'ziplock', version: libraryVersions.ziplock
- testCompile group: 'junit', name: 'junit', version: libraryVersions.junit
- testCompile group: 'commons-httpclient', name: 'commons-httpclient', version: libraryVersions.commonsHttpclient
+ testCompile (project(':tapestry-test')) {
+ transitive = false
+ }
+
+ // replace jakarta.enterprise:cdi-api with group: 'org.jboss.spec', name: 'jboss-javaee-6.0', version: libraryVersions.jbossJavaeeSpec to compile against full Java EE API
+ compileOnly moduleLibs.cdiApi
+
+ testCompile moduleLibs.ziplock
+ testCompile moduleLibs.commonsHttpclient
- testCompile group: 'org.jboss.arquillian.junit', name: 'arquillian-junit-container', version: libraryVersions.arquillian
- testCompile group: 'org.jboss.shrinkwrap.descriptors', name: 'shrinkwrap-descriptors-api-javaee', version: libraryVersions.shrinkwrapDesc
- testRuntime group: 'org.jboss.shrinkwrap.descriptors', name: 'shrinkwrap-descriptors-impl-javaee', version: libraryVersions.shrinkwrapDesc
+ testCompile moduleLibs.arquillianJunitContainer
+ testCompile moduleLibs.shrinkwrapDescriptorsApi
+ testRuntime moduleLibs.shrinkwrapDescriptorsImpl
- tomeeEmbeddedTestRuntime group: 'org.apache.openejb', name: 'arquillian-tomee-embedded', version: libraryVersions.tomee
+ tomeeEmbeddedTestRuntime mopduleLibs.tomee
- jbossAS7ManagedTestRuntime group: 'org.jboss.as', name: 'jboss-as-arquillian-container-managed', version: libraryVersions.jbossAS7
- jbossAS7ManagedTestRuntime group: 'org.jboss.spec', name: 'jboss-javaee-6.0', version: libraryVersions.jbossJavaeeSpec
- jboss "org.jboss.as:jboss-as-dist:$libraryVersions.jbossDistrib@zip"
+ jbossAS7ManagedTestRuntime moduleLibs.jbossAS7
+ jbossAS7ManagedTestRuntime moduleLibs.jbossJavaeeSpec
+ jboss moduleLibs.jbossDistrib
- glassfishManagedTestRuntime group: 'org.jboss.arquillian.container', name: 'arquillian-glassfish-managed-3.1', version: libraryVersions.arquillianGlassfish
- glassfish "org.glassfish.distributions:glassfish:$libraryVersions.glassfishDistrib@zip"
+ glassfishManagedTestRuntime moduleLibs.arquillianGlassfish
+ glassfish moduleLibs.glassfishDistrib
}
sourceSets {
@@ -72,10 +68,10 @@ sourceSets {
}
idea {
- module {
- scopes.PROVIDED.plus += configurations.compileOnly
- }
+ module {
+ scopes.PROVIDED.plus += configurations.compileOnly
}
+}
eclipse {
classpath {
@@ -83,8 +79,8 @@ eclipse {
}
}
-task resolveJBoss(type: Copy) {
- destinationDir = file('target')
+task resolveJBoss(type: Copy) {
+ destinationDir = file('target')
from { zipTree(configurations.jboss.singleFile) }
}
@@ -95,16 +91,16 @@ task resolveGlassfish(type: Copy) {
task tomeeEmbeddedTest(type: Test) {
- systemProperty 'arquillian.launch', "tomee_embedded"
+ systemProperty 'arquillian.launch', 'tomee_embedded'
}
task jbossAS7ManagedTest(type: Test) {
- systemProperty 'arquillian.launch', "jbossas_managed"
+ systemProperty 'arquillian.launch', 'jbossas_managed'
dependsOn { resolveJBoss }
}
task glassfishManagedTest(type: Test){
- systemProperty 'arquillian.launch', "glassfish_managed"
+ systemProperty 'arquillian.launch', 'glassfish_managed'
dependsOn { resolveGlassfish }
}
@@ -118,9 +114,8 @@ test {
setEnabled(false)
}
-jar {
-
- manifest {
- attributes 'Tapestry-Module-Classes': 'org.apache.tapestry5.cdi.CDIInjectModule'
- }
- }
+jar {
+ manifest {
+ attributes 'Tapestry-Module-Classes': 'org.apache.tapestry5.cdi.CDIInjectModule'
+ }
+}
diff --git a/tapestry-clojure/build.gradle b/tapestry-clojure/build.gradle
index d1f044446..0d7c7c95f 100644
--- a/tapestry-clojure/build.gradle
+++ b/tapestry-clojure/build.gradle
@@ -1,21 +1,22 @@
-description = "Allows Clojure functions to be injected into Tapestry services and components"
+plugins {
+ id 'tapestry.junit5-spock-convention'
+}
+
+description = 'Allows Clojure functions to be injected into Tapestry services and components'
dependencies {
- implementation project(':tapestry-ioc')
- implementation "org.clojure:clojure:1.6.0"
+ implementation project(':tapestry-ioc')
- // Added just to prove that it works (TAP5-1945)
- testImplementation project(':tapestry-core')
- testRuntimeOnly "javax.servlet:javax.servlet-api:${versions.servletapi}"
- testImplementation "org.junit.jupiter:junit-jupiter:${versions.junitJupiter}"
-}
+ implementation libs.clojure
-test {
- useJUnit()
+ // Added just to prove that it works (TAP5-1945)
+ testImplementation project(':tapestry-core')
+
+ testRuntimeOnly libs.javax.servlet.api
}
jar {
- manifest {
- attributes 'Tapestry-Module-Classes': 'org.apache.tapestry5.clojure.modules.ClojureModule'
- }
-}
\ No newline at end of file
+ manifest {
+ attributes 'Tapestry-Module-Classes': 'org.apache.tapestry5.clojure.modules.ClojureModule'
+ }
+}
diff --git a/tapestry-core/build.gradle b/tapestry-core/build.gradle
index e985abf06..c5ed7c95e 100644
--- a/tapestry-core/build.gradle
+++ b/tapestry-core/build.gradle
@@ -1,15 +1,15 @@
-import org.gradle.plugins.ide.idea.model.*
-import org.apache.tools.ant.filters.ReplaceTokens
-//import t5build.*
+plugins {
+ id 'tapestry.junit5-convention'
+ id 'tapestry.testng-convention'
+}
-description = "Central module for Tapestry, containing all core services and components"
+import t5build.TapestryBuildLogic
+import org.apache.tools.ant.filters.ReplaceTokens
-project.ext {
- mainGeneratedDir = "src/main/generated"
- testGeneratedDir = "src/test/generated"
-}
+description = 'Central module for Tapestry, containing all core services and components'
-clean.delete mainGeneratedDir, testGeneratedDir
+def npmWorkingDir = 'src/main/typescript/'
+def npmExec = TapestryBuildLogic.isWindows() ? 'npm.cmd' : 'npm'
dependencies {
api project(':tapestry-ioc')
@@ -17,148 +17,152 @@ dependencies {
api project(':beanmodel')
api project(':tapestry-http')
- api "org.apache.commons:commons-lang3:${versions.commonsLang}"
+ implementation libs.jakarta.annotation.api
+ implementation libs.jakarta.xml.bind.api
-
- implementation 'jakarta.annotation:jakarta.annotation-api:1.3.4'
- implementation 'jakarta.xml.bind:jakarta.xml.bind-api:2.3.2'
- implementation 'org.glassfish.jaxb:jaxb-runtime:2.3.2'
- implementation 'com.sun.xml.ws:jaxws-rt:2.3.2'
- implementation 'javax.xml.ws:jaxws-api:2.3.1'
+ implementation libs.commons.codec
+ implementation libs.commons.lang3
- provided project(":tapestry-test")
- provided project(":tapestry-test-constants")
+ provided project(':tapestry-test')
+ provided project(':tapestry-test-constants')
- provided "javax.servlet:javax.servlet-api:${versions.servletapi}"
+ provided libs.javax.servlet.api
- implementation "commons-codec:commons-codec:1.10"
-
- testImplementation "org.junit.jupiter:junit-jupiter:${versions.junitJupiter}"
- testImplementation "org.apache.httpcomponents:httpclient:4.5.14"
- testRuntimeOnly project(':tapestry-spock')
+ testImplementation libs.httpcomponents.httpclient
+ testImplementation project(":tapestry-spock")
- testRuntimeOnly "org.hsqldb:hsqldb:${versions.hsqldb}"
- testRuntimeOnly 'com.google.inject:guice:3.0'
+ testRuntimeOnly("${libs.hsqldb.get().module.group}:${libs.hsqldb.get().module.name}:${libs.hsqldb.get().version}:jdk8")
+ testRuntimeOnly libs.guice
}
-def npmWorkingDir = "src/main/typescript/"
-
-task npmInstall(type: Exec) {
- group "TypeScript"
- description "Runs npm install"
+tasks.register('npmInstall', Exec) {
+ group = 'TypeScript'
+ description = 'Runs npm install'
workingDir = npmWorkingDir
- commandLine isWindows() ? "npm.cmd" : "npm", 'install'
+ commandLine npmExec, 'install'
}
-task compileTypeScriptToAmd(type: Exec) {
+tasks.register('compileTypeScriptToAmd', Exec) {
+ group = 'TypeScript'
+ description = 'Compiles TypeScript to AMD modules'
+
dependsOn npmInstall
workingDir = npmWorkingDir
- commandLine isWindows() ? "npm.cmd" : "npm", 'run', 'build-amd'
+ commandLine npmExec, 'run', 'build-amd'
}
-task compileTypeScriptToEsModule(type: Exec) {
+tasks.register('compileTypeScriptToEsModule', Exec) {
+ group = 'TypeScript'
+ description = 'Compiles TypeScript to ES modules'
+
dependsOn npmInstall
workingDir = npmWorkingDir
- commandLine isWindows() ? "npm.cmd" : "npm", 'run', 'build-es-module'
+ commandLine npmExec, 'run', 'build-es-module'
}
-task compileTypeScript() {
- dependsOn compileTypeScriptToAmd
- dependsOn compileTypeScriptToEsModule
+tasks.register('compileTypeScript', Delete) {
+ group = 'TypeScript'
+ description = 'Compiles all TypeScript variants'
+
+ dependsOn compileTypeScriptToAmd, compileTypeScriptToEsModule
}
-task generateTypeScriptDocs(type: Exec) {
+tasks.named('sourcesJar') {
+ dependsOn compileTypeScript
+}
+
+tasks.register('generateTypeScriptDocs', Exec) {
+ group = 'TypeScript'
+ description = 'Generates TypeScript documentation'
+
dependsOn npmInstall
-
+
workingDir = npmWorkingDir
- commandLine isWindows() ? "npm.cmd" : "npm", 'run', 'docs'
+ commandLine npmExec, 'run', 'docs'
}
-task cleanTypeScriptFiles(type: Delete) {
- delete fileTree("src/main/resources/META-INF/assets/es-modules/t5/core") {
- include '**.js'
+tasks.register('cleanTypeScriptFiles', Delete) {
+ group = 'TypeScript'
+ description = 'Cleans generated TypeScript files'
+
+ delete fileTree('src/main/resources/META-INF/assets/es-modules/t5/core') {
+ include '**/*.js'
}
- delete fileTree("src/main/resources/META-INF/modules/t5/core") {
- include '**.js'
+ delete fileTree('src/main/resources/META-INF/modules/t5/core') {
+ include '**/*.js'
}
- delete "src/main/typescript/docs"
+ delete 'src/main/typescript/docs'
+}
+
+tasks.named('processResources') {
+ dependsOn compileTypeScript
+}
+
+tasks.named('clean') {
+ dependsOn cleanTypeScriptFiles
}
-processResources.dependsOn compileTypeScript
-clean.dependsOn cleanTypeScriptFiles
// Not sure why this is necessary:
-compileTestGroovy.dependsOn compileTestJava
+tasks.named('compileTestGroovy') {
+ dependsOn compileTestJava
+}
test {
- // Needed to have XMLTokenStreamTests.testStreamEncoding() passing on Java 9+
+ // Needed to have XMLTokenStreamTests.testStreamEncoding() passing on Java 9+
if (JavaVersion.current().isCompatibleWith(JavaVersion.VERSION_1_9)) {
- jvmArgs("--add-opens=java.base/java.nio.charset=ALL-UNNAMED");
+ jvmArgs('--add-opens=java.base/java.nio.charset=ALL-UNNAMED')
+ }
+
+ // TAP5-2722
+ systemProperty 'user.language', 'en'
+}
+
+[
+ 'app1',
+ 'app2',
+ 'app3',
+ 'app4',
+ 'app5',
+ 'app7',
+ 'appfolder'
+].each { appName ->
+ tasks.register("runTest${appName.capitalize()}", JavaExec) {
+ group = 'Application'
+ description = "Starts the ${appName} integration test app, useful when debugging."
+
+ mainClass = 'org.apache.tapestry5.test.JettyRunner'
+ args '-d', "src/test/${appName}", '-p', '8080'
+ classpath = sourceSets.test.runtimeClasspath
}
- // TAP5-2722
- systemProperty 'user.language', 'en'
-}
-
-task runTestApp1(type:JavaExec) {
- description 'Start app1 integration test app, useful when debugging failing integration tests'
- main = 'org.apache.tapestry5.test.JettyRunner'
- args "-d", "src/test/app1", "-p", "8080"
- classpath += project.sourceSets.test.runtimeClasspath
-}
-task runTestApp2(type:JavaExec) {
- description 'Start app2 integration test app, useful when debugging failing integration tests'
- main = 'org.apache.tapestry5.test.JettyRunner'
- args "-d", "src/test/app2", "-p", "8080"
- classpath += project.sourceSets.test.runtimeClasspath
-}
-task runTestApp3(type:JavaExec) {
- description 'Start app3 integration test app, useful when debugging failing integration tests'
- main = 'org.apache.tapestry5.test.JettyRunner'
- args "-d", "src/test/app3", "-p", "8080"
- classpath += project.sourceSets.test.runtimeClasspath
-}
-task runTestApp4(type:JavaExec) {
- description 'Start app4 integration test app, useful when debugging failing integration tests'
- main = 'org.apache.tapestry5.test.JettyRunner'
- args "-d", "src/test/app4", "-p", "8080"
- classpath += project.sourceSets.test.runtimeClasspath
-}
-task runTestApp5(type:JavaExec) {
- description 'Start app5 integration test app, useful when debugging failing integration tests'
- main = 'org.apache.tapestry5.test.JettyRunner'
- args "-d", "src/test/app5", "-p", "8080"
- classpath += project.sourceSets.test.runtimeClasspath
-}
-task runTestApp7(type:JavaExec) {
- description 'Start app7 integration test app, useful when debugging failing integration tests'
- main = 'org.apache.tapestry5.test.JettyRunner'
- args "-d", "src/test/app7", "-p", "8080"
- classpath += project.sourceSets.test.runtimeClasspath
-}
-task runTestAppfolder(type:JavaExec) {
- description 'Start appFolder integration test app, useful when debugging failing integration tests'
- main = 'org.apache.tapestry5.test.JettyRunner'
- args "-d", "src/test/appfolder", "-p", "8080"
- classpath += project.sourceSets.test.runtimeClasspath
}
// Default is jQuery and Require.js enabled, so here are the tests for the
// other combinations
-task testWithJqueryAndRequireJsDisabled(type:Test) {
- systemProperties."tapestry.javascript-infrastructure-provider" = "jquery"
- systemProperties."tapestry.require-js-enabled" = "false"
+tasks.register('testWithJqueryAndRequireJsDisabled', Test) {
+ group = 'Verification'
+ description = 'Runs tests with jQuery and Require.js disabled'
+
+ systemProperty 'tapestry.javascript-infrastructure-provider', 'jquery'
+ systemProperty 'tapestry.require-js-enabled', 'false'
}
-task testWithPrototypeAndRequireJsEnabled(type:Test) {
- systemProperties."tapestry.javascript-infrastructure-provider" = "prototype"
- systemProperties."tapestry.require-js-enabled" = "true"
-}
+tasks.register('testWithPrototypeAndRequireJsEnabled', Test) {
+ group = 'Verification'
+ description = 'Runs tests with Prototype and Require.js enabled'
-task testWithPrototypeAndRequireJsDisabled(type:Test) {
- systemProperties."tapestry.javascript-infrastructure-provider" = "prototype"
- systemProperties."tapestry.require-js-enabled" = "false"
-}
\ No newline at end of file
+ systemProperty 'tapestry.javascript-infrastructure-provider', 'prototype'
+ systemProperty 'tapestry.require-js-enabled', 'true'
+}
+
+tasks.register('testWithPrototypeAndRequireJsDisabled', Test) {
+ group = 'Verification'
+ description = 'Runs tests with Prototype and Require.js disabled'
+
+ systemProperty 'tapestry.javascript-infrastructure-provider', 'prototype'
+ systemProperty 'tapestry.require-js-enabled', 'false'
+}
diff --git a/tapestry-func/build.gradle b/tapestry-func/build.gradle
index fa7b059ea..d52fbe364 100644
--- a/tapestry-func/build.gradle
+++ b/tapestry-func/build.gradle
@@ -1,7 +1,9 @@
-description = "Light-weight functional programming for Flows of values"
+plugins {
+ id 'tapestry.junit5-convention'
+}
+
+description = 'Light-weight functional programming for Flows of values'
dependencies {
- testImplementation "org.testng:testng:${versions.testng}"
- testImplementation "commons-lang:commons-lang:2.6"
- testImplementation "org.junit.jupiter:junit-jupiter:${versions.junitJupiter}"
-}
\ No newline at end of file
+ testImplementation libs.commons.lang3
+}
diff --git a/tapestry-hibernate-core/build.gradle b/tapestry-hibernate-core/build.gradle
index 3e541327a..f89144f41 100644
--- a/tapestry-hibernate-core/build.gradle
+++ b/tapestry-hibernate-core/build.gradle
@@ -1,21 +1,26 @@
-description = "Basic Hibernate services for Tapestry, useable outside of a Tapestry web application"
+plugins {
+ id 'tapestry.testng-convention'
+}
+
+description = 'Basic Hibernate services for Tapestry, useable outside of a Tapestry web application'
+def moduleLibs = [
+ jaxbRuntime: 'org.glassfish.jaxb:jaxb-runtime:2.3.2',
+]
dependencies {
implementation project(':tapestry-ioc')
- api group: 'org.hibernate', name: 'hibernate-core', version: versions.hibernate
-
- implementation 'org.glassfish.jaxb:jaxb-runtime:2.3.2'
+ api libs.hibernate.core
+
+ implementation moduleLibs.jaxbRuntime
testImplementation project(':tapestry-test')
- testImplementation "org.easymock:easymock:${versions.easymock}"
- testImplementation "org.testng:testng:${versions.testng}", { transitive = false }
- testRuntimeOnly "org.hsqldb:hsqldb:${versions.hsqldb}"
+ testRuntimeOnly("${libs.hsqldb.get().module.group}:${libs.hsqldb.get().module.name}:${libs.hsqldb.get().version}:jdk8")
}
jar {
manifest {
attributes 'Tapestry-Module-Classes': 'org.apache.tapestry5.hibernate.modules.HibernateCoreModule'
}
-}
\ No newline at end of file
+}
diff --git a/tapestry-hibernate/build.gradle b/tapestry-hibernate/build.gradle
index f13cdcde9..de74ab1cd 100644
--- a/tapestry-hibernate/build.gradle
+++ b/tapestry-hibernate/build.gradle
@@ -1,24 +1,33 @@
-description = "Provides support for simple CRUD applications built on top of Tapestry and Hibernate"
+plugins {
+ id 'tapestry.testng-convention'
+}
+
+description = 'Provides support for simple CRUD applications built on top of Tapestry and Hibernate'
+
+def moduleLibs = [
+ jbossLogging: 'org.jboss.logging:jboss-logging:3.3.0.Final',
+]
dependencies {
- api project(':tapestry-core')
- api project(':tapestry-hibernate-core')
- implementation "org.jboss.logging:jboss-logging:3.3.0.Final"
+ api project(':tapestry-core')
+ api project(':tapestry-hibernate-core')
- testImplementation project(':tapestry-test')
-
- testRuntimeOnly "org.hsqldb:hsqldb:${versions.hsqldb}"
+ implementation moduleLibs.jbossLogging
+
+ testImplementation project(':tapestry-test')
+ testRuntimeOnly("${libs.hsqldb.get().module.group}:${libs.hsqldb.get().module.name}:${libs.hsqldb.get().version}:jdk8")
}
-jar {
+tasks.register('runTestApp0', JavaExec) {
+ description = 'Start tapestry-hibernate integration test app, useful when debugging failing integration tests'
+
+ mainClass = 'org.apache.tapestry5.test.JettyRunner'
+ args '-d', 'src/test/webapp', '-p', '8080'
+ classpath += project.sourceSets.test.runtimeClasspath
+}
+
+tasks.named('jar', Jar) {
manifest {
attributes 'Tapestry-Module-Classes': 'org.apache.tapestry5.hibernate.web.modules.HibernateModule'
}
}
-
-task runTestApp0(type:JavaExec) {
- description 'Start tapestry-hibernate integration test app, useful when debugging failing integration tests'
- main = 'org.apache.tapestry5.test.JettyRunner'
- args "-d", "src/test/webapp", "-p", "8080"
- classpath += project.sourceSets.test.runtimeClasspath
-}
diff --git a/tapestry-http/build.gradle b/tapestry-http/build.gradle
index be6b4cede..f6cbd76da 100644
--- a/tapestry-http/build.gradle
+++ b/tapestry-http/build.gradle
@@ -1,32 +1,36 @@
-import org.gradle.plugins.ide.idea.model.*
+plugins {
+ id 'tapestry.testng-convention'
+}
+
import org.apache.tools.ant.filters.ReplaceTokens
-import t5build.*
-description = "Tapestry classes that handle HTTP requests"
+description = 'Tapestry classes that handle HTTP requests'
dependencies {
implementation project(':tapestry-ioc')
implementation project(':tapestry-json')
implementation project(':beanmodel')
- provided project(":tapestry-test")
- provided project(":tapestry-test-constants")
-
- provided "javax.servlet:javax.servlet-api:${versions.servletapi}"
+ provided libs.javax.servlet.api
- implementation "commons-codec:commons-codec:1.10"
- implementation "commons-io:commons-io:${versions.commonsIo}"
+ implementation libs.commons.codec
+ implementation libs.commons.io
- testRuntimeOnly "org.hsqldb:hsqldb:${versions.hsqldb}"
+ testImplementation project(':tapestry-test')
+ testImplementation project(':tapestry-test-constants')
- testRuntimeOnly 'com.google.inject:guice:3.0'
+ testRuntimeOnly("${libs.hsqldb.get().module.group}:${libs.hsqldb.get().module.name}:${libs.hsqldb.get().version}:jdk8")
+ testRuntimeOnly libs.guice
+ testRuntimeOnly libs.slf4j.simple
}
// Not sure why this is necessary:
-compileTestGroovy.dependsOn compileTestJava
+tasks.named('compileTestGroovy') {
+ dependsOn compileTestJava
+}
-jar {
- from("src/main/filtered-resources") {
+tasks.named('jar', Jar) {
+ from('src/main/filtered-resources') {
filter(ReplaceTokens, tokens: [version: project.parent.version])
}
-}
\ No newline at end of file
+}
diff --git a/tapestry-internal-test/build.gradle b/tapestry-internal-test/build.gradle
index 9caa72c9b..4213b6d2d 100644
--- a/tapestry-internal-test/build.gradle
+++ b/tapestry-internal-test/build.gradle
@@ -1,5 +1,5 @@
-description = "Internal utilties used to assist with testing; not intended for outside use"
+description = 'Internal utilties used to assist with testing; not intended for outside use'
dependencies {
- implementation project(":tapestry-core")
-}
\ No newline at end of file
+ implementation project(':tapestry-core')
+}
diff --git a/tapestry-ioc-jcache/build.gradle b/tapestry-ioc-jcache/build.gradle
index 878cbab07..6d10137f7 100644
--- a/tapestry-ioc-jcache/build.gradle
+++ b/tapestry-ioc-jcache/build.gradle
@@ -1,35 +1,41 @@
-import org.gradle.plugins.ide.idea.model.*
-import t5build.*
-
-description = "JCache (JSR 107) integration for Tapestry-IoC"
+plugins {
+ id 'tapestry.junit4-legacy-convention'
+}
-//apply plugin: JavaPlugin
+description = 'JCache (JSR 107) integration for Tapestry-IoC'
-project.ext.libraryVersions = [
- jcache: '1.0.0',
+def moduleLibs = [
+ javaxCacheApi: 'javax.cache:cache-api:1.0.0',
+ javaxCacheTests: 'javax.cache:cache-tests:1.0.0',
+ javaxCacheDomain: 'javax.cache:test-domain:1.0.0',
+ cacheAnnotations: 'org.jsr107.ri:cache-annotations-ri-common:1.0.0',
+ infinispanJcache: 'org.infinispan:infinispan-jcache:7.0.0.Alpha4',
]
dependencies {
- /*compile "org.apache.tapestry:tapestry-ioc:${tapestryVersion()}"*/
- provided project(":tapestry-ioc")
- implementation "javax.cache:cache-api:${libraryVersions.jcache}"
- implementation "org.jsr107.ri:cache-annotations-ri-common:${libraryVersions.jcache}"
- testImplementation "javax.cache:cache-tests:${libraryVersions.jcache}"
- testImplementation "javax.cache:test-domain:${libraryVersions.jcache}"
- testRuntimeOnly "org.infinispan:infinispan-jcache:7.0.0.Alpha4" /* Just to be able to run the tests */
+ provided project(":tapestry-ioc")
+
+ implementation moduleLibs.javaxCacheApi
+ implementation moduleLibs.cacheAnnotations
+
+ testImplementation(moduleLibs.javaxCacheTests)
+ testImplementation moduleLibs.javaxCacheDomain
+ testRuntimeOnly moduleLibs.infinispanJcache /* Just to be able to run the tests */
}
-jar {
- manifest {
- attributes 'Tapestry-Module-Classes': 'org.apache.tapestry5.jcache.module.JCacheModule'
- }
+tasks.named('jar', Jar) {
+ manifest {
+ attributes 'Tapestry-Module-Classes': 'org.apache.tapestry5.jcache.module.JCacheModule'
+ }
}
test {
- useJUnit()
-
- // those tests do not work with JDK 6 (java.lang.UnsupportedClassVersionError)
- exclude '**/InterceptionUsingDefaultCacheNameTest.class',
- '**/InterceptionCacheNameOnEachMethodTest.class',
- '**/InterceptionUsingCacheConfigTest.class'
+ if (JavaVersion.current().isJava9Compatible()) {
+ jvmArgs '--add-opens', 'java.base/java.util=ALL-UNNAMED'
+ jvmArgs '--add-opens', 'java.base/java.util.concurrent=ALL-UNNAMED'
+ jvmArgs '--add-opens', 'java.base/java.io=ALL-UNNAMED'
+ jvmArgs '--add-opens', 'java.base/java.lang=ALL-UNNAMED'
+ jvmArgs '--add-opens', 'java.base/java.lang.invoke=ALL-UNNAMED'
+ jvmArgs '--add-opens', 'java.base/java.lang.reflect=ALL-UNNAMED'
+ }
}
diff --git a/tapestry-ioc-junit/build.gradle b/tapestry-ioc-junit/build.gradle
index 39a81a2ca..117e20ba3 100644
--- a/tapestry-ioc-junit/build.gradle
+++ b/tapestry-ioc-junit/build.gradle
@@ -1,10 +1,13 @@
-description = "Utilities for junit testing a tapestry-ioc application"
+plugins {
+ id 'tapestry.junit5-convention'
+}
+
+description = 'Utilities for junit testing a tapestry-ioc application'
dependencies {
implementation project(':tapestry-ioc')
- implementation 'junit:junit:4.11'
-}
-test {
- useJUnit()
+ // We also need these in implementation
+ implementation platform(libs.junit.bom)
+ implementation libs.junit.jupiter.api
}
diff --git a/tapestry-ioc/build.gradle b/tapestry-ioc/build.gradle
index df3f1d9ac..75879fb7b 100644
--- a/tapestry-ioc/build.gradle
+++ b/tapestry-ioc/build.gradle
@@ -1,35 +1,28 @@
-description = "A code-centric, high-performance, simple Inversion of Control container"
+plugins {
+ id 'tapestry.junit5-spock-convention'
+}
+description = 'A code-centric, high-performance, simple Inversion of Control container'
dependencies {
api project(':tapestry-func')
- api project(':tapestry5-annotations')
- api project(":plastic")
- api project(":beanmodel")
+ api project(':commons')
+ implementation project(":beanmodel")
provided project(':tapestry-test')
// For now, keep these compile dependencies synchronized with the binaries dependencies
// of the top-level build:
- api "javax.inject:javax.inject:1"
- api "javax.annotation:javax.annotation-api:1.3.2"
+ api libs.javax.inject
+ api libs.jakarta.annotation.api
- api "org.slf4j:slf4j-api:${versions.slf4j}"
+ testImplementation libs.commons.lang3
+ testImplementation libs.hibernate.core
+ testRuntimeOnly("${libs.hsqldb.get().module.group}:${libs.hsqldb.get().module.name}:${libs.hsqldb.get().version}:jdk8")
- testImplementation "commons-lang:commons-lang:2.6"
- testImplementation "org.apache.commons:commons-lang3:3.4"
-
- testImplementation "org.apache.commons:commons-lang3:3.4"
- testImplementation "org.hibernate:hibernate-core:5.2.10.Final"
- testRuntimeOnly "org.hsqldb:hsqldb:${versions.hsqldb}"
-
- testImplementation "org.junit.jupiter:junit-jupiter:${versions.junitJupiter}"
-
- provided "org.testng:testng:${versions.testng}", { transitive = false }
}
-test {
- useJUnitPlatform()
+tasks.named('test', Test) {
// Override the master build.gradle
- systemProperties.remove("tapestry.service-reloading-enabled")
-}
\ No newline at end of file
+ systemProperties.remove('tapestry.service-reloading-enabled')
+}
diff --git a/tapestry-javadoc/build.gradle b/tapestry-javadoc/build.gradle
index d72b91a73..59bd8a2b7 100644
--- a/tapestry-javadoc/build.gradle
+++ b/tapestry-javadoc/build.gradle
@@ -1,32 +1,35 @@
-description = "JavaDoc Plugin for Tapestry that generates component reference documentation for component classes"
+plugins {
+ id 'tapestry.junit5-convention'
+}
+
+description = 'JavaDoc Plugin for Tapestry that generates component reference documentation for component classes'
dependencies {
- implementation project(':tapestry-core')
- implementation "commons-lang:commons-lang:2.6"
-
- if (JavaVersion.current() <= JavaVersion.VERSION_1_8) {
- implementation files(getTools())
- }
-
-}
+ implementation project(':tapestry-core')
-/** Returns the tools.jar/classes.jar of the Java runtime. */
-File getTools() {
+ implementation libs.commons.lang3
+ implementation libs.commons.text
- def dir = isMacOSX_1_6() ? "classes" : "lib"
-
- def jar = isMacOSX_1_6() ? "classes" : "tools.jar"
-
- def jreRelpath = "../${dir}/${jar}"
- def jdkRelpath = "$dir/${jar}"
-
- def javaHome = System.properties['java.home']
+ testImplementation platform(libs.spock.bom)
+ testImplementation libs.spock.core
+}
- return new File(javaHome, jdkRelpath).exists() ? new File(javaHome, jdkRelpath) : new File(javaHome, jreRelpath)
+java {
+ toolchain {
+ languageVersion = JavaLanguageVersion.of(11)
+ }
}
-boolean isMacOSX_1_6() {
- System.properties['os.name'].toLowerCase().contains('mac os') &&
- System.properties['java.version'].startsWith("1.6.")
+tasks.withType(JavaCompile).configureEach {
+ // Override Java 8 compatibility inherited from root
+ sourceCompatibility = '11'
+ targetCompatibility = '11'
+
+ // Only apply --add-modules if target is not 1.8
+ if (JavaVersion.current().isCompatibleWith(JavaVersion.VERSION_11)) {
+ options.compilerArgs += [
+ '--add-modules',
+ 'jdk.compiler'
+ ]
+ }
}
-
\ No newline at end of file
diff --git a/tapestry-jmx/build.gradle b/tapestry-jmx/build.gradle
index ef371e800..00694090c 100644
--- a/tapestry-jmx/build.gradle
+++ b/tapestry-jmx/build.gradle
@@ -1,18 +1,17 @@
-description = "Allows easy exposure of Tapestry Services as JMX MBeans"
+plugins {
+ id 'tapestry.testng-convention'
+}
-dependencies {
- implementation project(':tapestry-core')
+description = 'Allows easy exposure of Tapestry Services as JMX MBeans'
- testImplementation project(':tapestry-test')
- }
+dependencies {
+ implementation project(':tapestry-core')
-test {
- systemProperties "tapestry.service-reloading-enabled": "false"
+ testImplementation project(':tapestry-test')
}
-
jar {
manifest {
attributes 'Tapestry-Module-Classes': 'org.apache.tapestry5.jmx.modules.JmxModule'
}
-}
\ No newline at end of file
+}
diff --git a/tapestry-jpa/build.gradle b/tapestry-jpa/build.gradle
index e72805b6a..58c723e7b 100644
--- a/tapestry-jpa/build.gradle
+++ b/tapestry-jpa/build.gradle
@@ -1,40 +1,41 @@
-description = "Provides support for simple CRUD applications built on top of Tapestry and JPA"
+plugins {
+ id 'tapestry.testng-convention'
+}
+
+description = 'Provides support for simple CRUD applications built on top of Tapestry and JPA'
+
+def moduleLibs = [
+ jpaSpecs: 'org.apache.geronimo.specs:geronimo-jpa_2.0_spec:1.1',
+ javaxCdiApi: 'javax.enterprise:cdi-api:1.2',
+ eclipselink: 'org.eclipse.persistence:eclipselink:2.7.7',
+ dbcp: 'org.apache.tomcat:dbcp:6.0.32',
+ h2: 'com.h2database:h2:1.3.175'
+]
dependencies {
- implementation project(':tapestry-core')
- implementation "org.apache.geronimo.specs:geronimo-jpa_2.0_spec:1.1"
- implementation 'javax.enterprise:cdi-api:1.2'
+ implementation project(':tapestry-core')
+ implementation moduleLibs.jpaSpecs
+ implementation moduleLibs.javaxCdiApi
- testImplementation project(':tapestry-test')
- testImplementation 'org.eclipse.persistence:eclipselink:2.7.7'
+ testImplementation project(':tapestry-test')
+ testImplementation moduleLibs.eclipselink
- testRuntimeOnly "com.h2database:h2:1.2.145"
- testRuntimeOnly "org.apache.tomcat:dbcp:6.0.32"
- testRuntimeOnly 'com.h2database:h2:1.3.175'
+ testRuntimeOnly moduleLibs.dbcp
+ testRuntimeOnly moduleLibs.h2
}
-repositories {
- maven {
- name "EclipseLink"
- url "https://download.eclipse.org/rt/eclipselink/maven.repo/"
+(1..6).each {
+ tasks.register("runTestApp${it}", JavaExec) {
+ description = "Start app${it} integration test app, useful when debugging failing integration tests"
+ mainClass = 'org.apache.tapestry5.test.JettyRunner'
+ args '-d', "src/test/app${it}", '-p', '8080'
+ classpath = project.sourceSets.test.runtimeClasspath
}
}
-test {
- systemProperties "tapestry.service-reloading-enabled": "false"
-}
-
-
-jar {
+tasks.named('jar', Jar) {
manifest {
attributes 'Tapestry-Module-Classes': 'org.apache.tapestry5.jpa.modules.JpaModule'
}
}
-
-task runTestApp6(type:JavaExec) {
- description 'Start app6 integration test app, useful when debugging failing integration tests'
- main = 'org.apache.tapestry5.test.JettyRunner'
- args "-d", "src/test/app6", "-p", "8080"
- classpath += project.sourceSets.test.runtimeClasspath
-}
diff --git a/tapestry-json/build.gradle b/tapestry-json/build.gradle
index 055ed9a73..9d71e30d7 100644
--- a/tapestry-json/build.gradle
+++ b/tapestry-json/build.gradle
@@ -1,16 +1,18 @@
-description = "Repackaged, improved (and tested) version of code originally from https://github.com/tdunning/open-json"
+plugins {
+ id 'tapestry.junit5-convention'
+}
+
+description = 'Repackaged, improved (and tested) version of code originally from https://github.com/tdunning/open-json'
dependencies {
- provided project(':tapestry-ioc')
- testImplementation "org.junit.jupiter:junit-jupiter:${versions.junitJupiter}"
-}
+ implementation project(':tapestry5-annotations')
+ implementation project(':commons')
-test {
- useJUnit()
+ testImplementation project(":tapestry-func")
}
-jar {
+tasks.named('jar', Jar) {
manifest {
attributes 'Tapestry-Module-Classes': 'org.apache.tapestry5.json.modules.JSONModule'
}
-}
\ No newline at end of file
+}
diff --git a/tapestry-kaptcha/build.gradle b/tapestry-kaptcha/build.gradle
index 4b79ed964..8ccbd8a4a 100644
--- a/tapestry-kaptcha/build.gradle
+++ b/tapestry-kaptcha/build.gradle
@@ -1,17 +1,25 @@
-description = "Kaptcha user verification support"
+plugins {
+ id 'tapestry.testng-convention'
+}
+
+description = 'Kaptcha user verification support'
+
+def moduleLibs= [
+ kaptcha: 'com.github.axet:kaptcha:0.0.8',
+]
dependencies {
implementation project(':tapestry-core')
- implementation "com.github.axet:kaptcha:0.0.8"
+ implementation moduleLibs.kaptcha
- provided "javax.servlet:javax.servlet-api:${versions.servletapi}"
+ provided libs.javax.servlet.api
testImplementation project(':tapestry-test')
}
-jar {
+tasks.named('jar', Jar) {
manifest {
attributes 'Tapestry-Module-Classes': 'org.apache.tapestry5.kaptcha.modules.KaptchaModule'
}
-}
\ No newline at end of file
+}
diff --git a/tapestry-latest-java-tests/build.gradle b/tapestry-latest-java-tests/build.gradle
index 4371b82ff..6954db351 100644
--- a/tapestry-latest-java-tests/build.gradle
+++ b/tapestry-latest-java-tests/build.gradle
@@ -1,26 +1,20 @@
-description = "Test suite for making sure Tapestry runs on latest Java"
+plugins {
+ id 'tapestry.junit5-spock-convention'
+}
-sourceCompatibility = "17"
-targetCompatibility = "17"
+description = 'Test suite for making sure Tapestry runs on latest Java'
-tasks.withType(JavaCompile).each {
- it.options.compilerArgs.add("--enable-preview")
-}
+sourceCompatibility = '17'
+targetCompatibility = '17'
-test {
- dependsOn 'testNG'
- useJUnitPlatform()
- jvmArgs(["--enable-preview"])
+tasks.withType(JavaCompile).configureEach {
+ options.compilerArgs += '--enable-preview'
}
-tasks.register('testNG', Test) {
- useTestNG()
- jvmArgs(["--enable-preview"])
+tasks.withType(Test).configureEach {
+ jvmArgs += '--enable-preview'
}
dependencies {
testImplementation project(':tapestry-ioc')
- testImplementation "org.slf4j:slf4j-api:${versions.slf4j}"
- testImplementation "org.testng:testng:${versions.testng}"
- testImplementation "org.junit.jupiter:junit-jupiter:${versions.junitJupiter}"
}
diff --git a/tapestry-mongodb/build.gradle b/tapestry-mongodb/build.gradle
index 6428ece0d..bd6e72126 100644
--- a/tapestry-mongodb/build.gradle
+++ b/tapestry-mongodb/build.gradle
@@ -1,18 +1,25 @@
-description = "Basic MongoDB services for Tapestry, useable outside of a Tapestry web application"
+plugins {
+ id 'tapestry.junit5-spock-convention'
+}
+
+import groovy.transform.AutoExternalize
+
+description = 'Basic MongoDB services for Tapestry, useable outside of a Tapestry web application'
+
+def moduleLibs = [
+ mongoJavaDriver: 'org.mongodb:mongo-java-driver:2.10.1',
+ jongo: 'org.jongo:jongo:0.3',
+ embedMongo: 'de.flapdoodle.embed:de.flapdoodle.embed.mongo:1.28',
+]
dependencies {
implementation project(':tapestry-ioc')
- testImplementation project(':tapestry-test')
-
- implementation group: 'org.mongodb', name: 'mongo-java-driver', version: '2.10.1'
- testImplementation group: 'org.jongo', name: 'jongo', version: '0.3'
- testImplementation "org.junit.jupiter:junit-jupiter:${versions.junitJupiter}"
- testImplementation "de.flapdoodle.embed:de.flapdoodle.embed.mongo:1.28"
-}
+ implementation moduleLibs.mongoJavaDriver
-test {
- useJUnit()
+ testImplementation project(':tapestry-test')
+ testImplementation moduleLibs.jongo
+ testImplementation moduleLibs.embedMongo
}
jar {
diff --git a/tapestry-openapi-viewer/build.gradle b/tapestry-openapi-viewer/build.gradle
index b6a62e6ff..5662fb5ba 100644
--- a/tapestry-openapi-viewer/build.gradle
+++ b/tapestry-openapi-viewer/build.gradle
@@ -1,11 +1,12 @@
-description = "Embedded OpenAPI (Swagger) viewer for Tapestry, based on Swagger UI"
+description = 'Embedded OpenAPI (Swagger) viewer for Tapestry, based on Swagger UI'
dependencies {
implementation project(':tapestry-core')
- testImplementation "javax.servlet:javax.servlet-api:${versions.servletapi}"
+
+ testImplementation libs.javax.servlet.api
}
-jar {
+tasks.named('jar', Jar) {
manifest {
attributes 'Tapestry-Module-Classes': 'org.apache.tapestry5.openapiviewer.modules.TapestryOpenApiViewerModule'
}
diff --git a/tapestry-rest-jackson/build.gradle b/tapestry-rest-jackson/build.gradle
index aa806f3a4..85e76208f 100644
--- a/tapestry-rest-jackson/build.gradle
+++ b/tapestry-rest-jackson/build.gradle
@@ -1,13 +1,19 @@
-description = "Support for using Jackson Databind with the Tapestry REST support"
+def moduleLibs = [
+ jsonschemaGenerator: 'com.github.victools:jsonschema-generator:4.20.0',
+]
+
+description = 'Support for using Jackson Databind with the Tapestry REST support'
dependencies {
implementation project(':tapestry-core')
- implementation "com.fasterxml.jackson.core:jackson-databind:${versions.jackson}"
- implementation "com.github.victools:jsonschema-generator:${versions.jsonschemaGenerator}"
- provided "javax.servlet:javax.servlet-api:${versions.servletapi}"
+
+ implementation libs.jackson.databind
+ implementation moduleLibs.jsonschemaGenerator
+
+ provided libs.javax.servlet.api
}
-jar {
+tasks.named('jar', Jar) {
manifest {
attributes 'Tapestry-Module-Classes': 'org.apache.tapestry5.rest.jackson.modules.RestJacksonModule'
}
diff --git a/tapestry-runner/build.gradle b/tapestry-runner/build.gradle
index 88acdb405..1391e5b0c 100644
--- a/tapestry-runner/build.gradle
+++ b/tapestry-runner/build.gradle
@@ -1,17 +1,22 @@
-description = "Utilities for running a Tapestry application in Jetty or Tomcat as part of test suite."
+description = 'Utilities for running a Tapestry application in Jetty or Tomcat as part of test suite.'
+
+def moduleVersions = [
+ jetty: '8.1.19.v20160209',
+ tomcat: '7.0.70',
+]
dependencies {
+ api project(':tapestry-test-constants')
- api project(":tapestry-test-constants")
- implementation "org.eclipse.jetty:jetty-server:${versions.jetty}"
- implementation "org.eclipse.jetty:jetty-jndi:${versions.jetty}"
- implementation "org.eclipse.jetty:jetty-plus:${versions.jetty}"
- implementation "org.eclipse.jetty:jetty-webapp:${versions.jetty}"
+ implementation "org.eclipse.jetty:jetty-server:${moduleVersions.jetty}"
+ implementation "org.eclipse.jetty:jetty-jndi:${moduleVersions.jetty}"
+ implementation "org.eclipse.jetty:jetty-plus:${moduleVersions.jetty}"
+ implementation "org.eclipse.jetty:jetty-webapp:${moduleVersions.jetty}"
- implementation "org.apache.tomcat:tomcat-catalina:${versions.tomcat}"
- implementation "org.apache.tomcat:tomcat-coyote:${versions.tomcat}"
- implementation "org.apache.tomcat:tomcat-jasper:${versions.tomcat}"
+ implementation "org.apache.tomcat:tomcat-catalina:${moduleVersions.tomcat}"
+ implementation "org.apache.tomcat:tomcat-coyote:${moduleVersions.tomcat}"
+ implementation "org.apache.tomcat:tomcat-jasper:${moduleVersions.tomcat}"
- implementation "org.apache.tomcat:tomcat-dbcp:${versions.tomcat}"
- implementation "commons-cli:commons-cli:1.2"
+ implementation "org.apache.tomcat:tomcat-dbcp:${moduleVersions.tomcat}"
+ implementation libs.commons.cli
}
diff --git a/tapestry-spock/build.gradle b/tapestry-spock/build.gradle
index 894614390..50a9a60c8 100644
--- a/tapestry-spock/build.gradle
+++ b/tapestry-spock/build.gradle
@@ -1,14 +1,16 @@
-description = "Provides support Tapestry injections in Spock specifications"
+plugins {
+ id 'tapestry.junit5-convention'
+ id 'groovy'
+}
+
+description = 'Provides support Tapestry injections in Spock specifications'
dependencies {
- implementation project(':commons')
- implementation project(':tapestry-ioc')
- implementation "org.spockframework:spock-core:${versions.spock}"
-
- testImplementation "javax.inject:javax.inject:1"
- testImplementation "org.junit.jupiter:junit-jupiter:${versions.junitJupiter}"
-}
+ provided project(':commons')
+ provided project(':tapestry-ioc')
+
+ api platform(libs.spock.bom)
+ api libs.spock.core
-test {
- useJUnitPlatform()
+ testImplementation libs.javax.inject
}
diff --git a/tapestry-spring/build.gradle b/tapestry-spring/build.gradle
index 1b4bb0c34..fd0346f6a 100644
--- a/tapestry-spring/build.gradle
+++ b/tapestry-spring/build.gradle
@@ -1,30 +1,34 @@
-description = "Integration of Tapestry with the Spring Inversion Of Control Container"
+plugins {
+ id 'tapestry.testng-convention'
+}
+
+description = 'Integration of Tapestry with the Spring Inversion Of Control Container'
+def moduleLibs = [
+ springWeb: 'org.springframework:spring-web:3.2.9.RELEASE',
+]
dependencies {
- implementation project(':tapestry-core')
- implementation "org.springframework:spring-web:3.2.9.RELEASE"
+ implementation project(':tapestry-core')
+
+ implementation moduleLibs.springWeb
- provided "javax.servlet:javax.servlet-api:${versions.servletapi}"
+ provided libs.javax.servlet.api
- testImplementation project(':tapestry-test')
+ testImplementation project(':tapestry-test')
}
-jar {
- manifest {
- attributes 'Tapestry-Module-Classes': 'org.apache.tapestry5.spring.modules.SpringModule'
+['', '1'].each { suffix ->
+ tasks.register("runTestApp${suffix}", JavaExec) {
+ group = 'Application'
+ description = "Start tapestry-spring integration test app${suffix}, useful when debugging failing integration tests"
+ mainClass = 'org.apache.tapestry5.test.JettyRunner'
+ args '-d', "src/test/webapp${suffix}", '-p', '8080'
+ classpath += project.sourceSets.test.runtimeClasspath
}
}
-task runTestApp(type:JavaExec) {
- description 'Start tapestry-spring integration test app, useful when debugging failing integration tests'
- main = 'org.apache.tapestry5.test.JettyRunner'
- args "-d", "src/test/webapp", "-p", "8080"
- classpath += project.sourceSets.test.runtimeClasspath
+tasks.named('jar', Jar) {
+ manifest {
+ attributes 'Tapestry-Module-Classes': 'org.apache.tapestry5.spring.modules.SpringModule'
+ }
}
-
-task runTestApp1(type:JavaExec) {
- description 'Start tapestry-spring integration test app 1, useful when debugging failing integration tests'
- main = 'org.apache.tapestry5.test.JettyRunner'
- args "-d", "src/test/webapp1", "-p", "8080"
- classpath += project.sourceSets.test.runtimeClasspath
-}
\ No newline at end of file
diff --git a/tapestry-test-data/build.gradle b/tapestry-test-data/build.gradle
index 63229bc4f..ea9530ee9 100644
--- a/tapestry-test-data/build.gradle
+++ b/tapestry-test-data/build.gradle
@@ -1,5 +1,5 @@
-description = "Utilities for generating random data used when populating entities"
+description = 'Utilities for generating random data used when populating entities'
dependencies {
- implementation "org.slf4j:slf4j-api:${versions.slf4j}"
+ implementation libs.slf4j.api
}
diff --git a/tapestry-test/build.gradle b/tapestry-test/build.gradle
index faf10b63e..70b34c377 100644
--- a/tapestry-test/build.gradle
+++ b/tapestry-test/build.gradle
@@ -1,20 +1,27 @@
-description = "[Deprecated] Utilities for integration testing of Tapestry applications using Selenium"
+plugins {
+ id 'tapestry.testng-convention'
+}
+
+description = '[Deprecated] Utilities for integration testing of Tapestry applications using Selenium'
dependencies {
- api project(":tapestry-test-data")
- api project(":tapestry-runner")
+ api project(':tapestry-test-data')
+ api project(':tapestry-runner')
+
+ implementation libs.webdrivermanager
- implementation ("io.github.bonigarcia:webdrivermanager:${versions.webdriverManager}")
+ api libs.selenium.java
- api "org.seleniumhq.selenium:selenium-leg-rc:${versions.selenium}", {
- exclude group: "org.seleniumhq.selenium", module: "jetty-repacked"
- exclude group: "org.testng", module: "testng"
- exclude group: "javax.servlet", module: "javax.servlet-api"
- exclude group: "org.seleniumhq.selenium", module: "selenium-firefox-driver"
- }
- api "org.seleniumhq.selenium:selenium-java:${versions.seleniumServer}"
+ api(libs.selenium.legrc) {
+ exclude group: 'org.seleniumhq.selenium', module: 'jetty-repacked'
+ exclude group: 'org.testng', module: 'testng'
+ exclude group: 'junit', module: 'junit'
+ exclude group: 'javax.servlet', module: 'javax.servlet-api'
+ exclude group: 'org.seleniumhq.selenium', module: 'selenium-firefox-driver'
+ }
- api "org.testng:testng:${versions.testng}"
- api "org.easymock:easymock:${versions.easymock}"
+ // we need to add them to api
+ api libs.testng
+ api libs.easymock
}
diff --git a/tapestry-upload/build.gradle b/tapestry-upload/build.gradle
index 99d15479c..048f8e0a2 100644
--- a/tapestry-upload/build.gradle
+++ b/tapestry-upload/build.gradle
@@ -1,15 +1,26 @@
-description = "File Upload component, with supporting services"
+plugins {
+ id 'tapestry.testng-convention'
+}
+
+description = 'File Upload component, with supporting services'
+
+def moduleLibs = [
+ commonsFileupload: 'commons-fileupload:commons-fileupload:1.5',
+]
dependencies {
- implementation project(':tapestry-core')
- api "commons-fileupload:commons-fileupload:1.5"
- implementation "commons-io:commons-io:${versions.commonsIo}"
- provided "javax.servlet:javax.servlet-api:${versions.servletapi}"
+ implementation project(':tapestry-core')
+
+ implementation libs.commons.io
+
+ api moduleLibs.commonsFileupload
+
+ provided libs.javax.servlet.api
- testImplementation project(':tapestry-test')
+ testImplementation project(':tapestry-test')
}
-jar {
+tasks.named('jar', Jar) {
manifest {
attributes 'Tapestry-Module-Classes': 'org.apache.tapestry5.upload.modules.UploadModule'
}
diff --git a/tapestry-version-migrator/build.gradle b/tapestry-version-migrator/build.gradle
index 04a897d10..4a19631fa 100644
--- a/tapestry-version-migrator/build.gradle
+++ b/tapestry-version-migrator/build.gradle
@@ -1,16 +1,18 @@
-description = "Tool to help migrate source code using Tapestry from one version to another. Initially built for 5.7.0"
-
-dependencies {
- testImplementation group: 'org.testng', name: 'testng', version: '7.3.0'
+plugins {
+ id 'tapestry.testng-convention'
}
-test {
- useTestNG() {
- useDefaultListeners = true // Tells TestNG to execute its default reporting structure
+description = 'Tool to help migrate source code using Tapestry from one version to another. Initially built for 5.7.0'
+
+tasks.withType(Test).configureEach {
+ if (options instanceof TestNGOptions) {
+ options {
+ useDefaultListeners = true
+ }
}
}
-jar {
+tasks.named('jar', Jar) {
manifest {
attributes 'Main-Class': 'org.apache.tapestry5.versionmigrator.Main'
}
diff --git a/tapestry-webresources/build.gradle b/tapestry-webresources/build.gradle
index 73a69bdf2..943d36fdb 100644
--- a/tapestry-webresources/build.gradle
+++ b/tapestry-webresources/build.gradle
@@ -1,48 +1,52 @@
-description = "Integration with WRO4J to perform runtime CoffeeScript compilation, JavaScript minimization, and more."
+plugins {
+ id 'tapestry.junit5-convention'
+ id 'tapestry.testng-convention'
+}
+
+description = 'Integration with WRO4J to perform runtime CoffeeScript compilation, JavaScript minimization, and more.'
-//configurations {
-// all {
-// exclude group: "org.codehaus.groovy", module: "groovy-all" // avoid multiple Groovy compilers on classpath
-// }
-//}
+def moduleLibs = [
+ closureCompiler: 'com.google.javascript:closure-compiler-unshaded:v20220502',
+ less4j: 'com.github.sommeri:less4j:1.12.0',
+ autoValueAnnotations: 'com.google.auto.value:auto-value-annotations:1.9',
+ rhino: 'org.mozilla:rhino:1.7.7.2',
+]
dependencies {
- api project(":tapestry-core")
- testImplementation project(":tapestry-test")
- api "com.google.javascript:closure-compiler-unshaded:v20220502"
- implementation "com.github.sommeri:less4j:1.12.0"
-
- compileOnly "com.google.auto.value:auto-value-annotations:1.9"
-
- implementation "org.mozilla:rhino:1.7.7.2"
-
- testImplementation project(":tapestry-runner")
- testImplementation "org.gebish:geb-spock:${versions.geb}", {
- exclude group: "org.codehaus.groovy", module: "groovy-all" // avoid multiple Groovy compilers on classpath
- }
- testImplementation "org.spockframework:spock-tapestry:${versions.spock}", {
- exclude group: "org.apache.tapestry"
- }
- testImplementation "org.junit.jupiter:junit-jupiter:${versions.junitJupiter}"
- testImplementation "org.seleniumhq.selenium:selenium-leg-rc:${versions.selenium}", {
- exclude group: "org.seleniumhq.selenium", module: "jetty-repacked"
- exclude group: "org.testng", module: "testng"
- exclude group: "javax.servlet", module: "javax.servlet-api"
- exclude group: "org.seleniumhq.selenium", module: "selenium-firefox-driver"
+ api project(':tapestry-core')
+
+ api moduleLibs.closureCompiler
+
+ implementation moduleLibs.less4j
+ implementation moduleLibs.rhino
+
+ compileOnly moduleLibs.autoValueAnnotations
+
+ testImplementation project(':tapestry-test')
+ testImplementation project(':tapestry-runner')
+
+ testImplementation(libs.geb.spock) {
+ exclude group: 'org.codehaus.groovy', module: 'groovy-all' // avoid multiple Groovy compilers on classpath
}
- testImplementation "org.seleniumhq.selenium:selenium-java:${versions.seleniumServer}"
- testImplementation ("io.github.bonigarcia:webdrivermanager:${versions.webdriverManager}")
-}
-jar.manifest {
- attributes 'Tapestry-Module-Classes': 'org.apache.tapestry5.webresources.modules.WebResourcesModule'
+ testImplementation project(":tapestry-spock")
+ testImplementation libs.selenium.java
+ testImplementation libs.webdrivermanager
}
test {
- useJUnitPlatform()
+ systemProperties(
+ 'geb.build.reportsDir': "$reporting.baseDir/geb",
+ 'tapestry.compiled-asset-cache-dir': "$buildDir/compiled-asset-cache",
+ 'tapestry.production-mode': 'false',
+ 'tapestry.compress-whitespace': 'false',
+ 'tapestry.combine-scripts': 'false'
+ )
+}
- systemProperties("geb.build.reportsDir": "$reporting.baseDir/geb",
- "tapestry.compiled-asset-cache-dir": "$buildDir/compiled-asset-cache",
- "tapestry.production-mode": "false")
+tasks.named('jar', Jar) {
+ manifest {
+ attributes 'Tapestry-Module-Classes': 'org.apache.tapestry5.webresources.modules.WebResourcesModule'
+ }
}
diff --git a/tapestry5-annotations/build.gradle b/tapestry5-annotations/build.gradle
index 4f411a174..bc3d98c9e 100644
--- a/tapestry5-annotations/build.gradle
+++ b/tapestry5-annotations/build.gradle
@@ -1 +1 @@
-description = "Annotations used with Tapestry, Tapestry-IoC and BeanModel applications"
\ No newline at end of file
+description = 'Annotations used with Tapestry, Tapestry-IoC and BeanModel applications'
(tapestry-5) 07/12: TAP5-2809: Fix Javadoc warnings
Posted by be...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
benw pushed a commit to branch gradle-improvements-javax
in repository https://gitbox.apache.org/repos/asf/tapestry-5.git
commit 52ae5b493deeff353aaad9af5e11aa03048778ae
Author: Ben Weidig <be...@netzgut.net>
AuthorDate: Tue Jun 10 08:41:07 2025 +0200
TAP5-2809: Fix Javadoc warnings
---
.../internal/services/DocumentLinker.java | 11 ++++++++--
.../services/ajax/AjaxFormUpdateController.java | 2 ++
.../services/ComponentEventRequestFilter.java | 1 +
.../services/ajax/AjaxResponseRenderer.java | 4 +++-
.../services/javascript/JavaScriptStack.java | 7 +++++++
.../services/javascript/JavaScriptSupport.java | 6 ++++++
.../http/internal/services/DefaultCorsHandler.java | 2 +-
.../ValidatingOrderedConfigurationWrapper.java | 2 --
.../ioc/internal/services/cron/CronExpression.java | 24 +++++++++++-----------
.../services/ObjectMapperSource.java | 5 +++--
10 files changed, 44 insertions(+), 20 deletions(-)
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/DocumentLinker.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/DocumentLinker.java
index 9326f12f0..aefcb3bae 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/DocumentLinker.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/DocumentLinker.java
@@ -34,6 +34,8 @@ public interface DocumentLinker
* the core libraries have loaded and initialized. Thus difference between core libraries and other libraries
* is new in 5.4, and represents a conflict between asynchronous loading of modules (introduced in 5.4) and
* sequential loading of libraries (in 5.3 and earlier).
+ *
+ * @param libraryURL non-core JavaScript library to add. It cannot be null.
*/
void addLibrary(String libraryURL);
@@ -42,17 +44,20 @@ public interface DocumentLinker
* and is used to bootstrap up to adding non-core libraries.
*
* @since 5.4
+ * @param libraryURL core JavaScript library to add. It cannot be null.
*/
void addCoreLibrary(String libraryURL);
/**
* Adds a link to load a CSS stylesheet.
+ *
+ * @param stylesheet {@link StylesheetLink} to add. It cannot be null.
*/
void addStylesheetLink(StylesheetLink stylesheet);
/**
* Adds a module configuration callback for this request.
- *
+ *
* @param callback a {@link ModuleConfigurationCallback}. It cannot be null.
* @since 5.4
*/
@@ -60,7 +65,7 @@ public interface DocumentLinker
/**
* Adds an ES module configuration callback for this request.
- *
+ *
* @param callback a {@link EsModuleConfigurationCallback}. It cannot be null.
* @since 5.10.0
*/
@@ -101,6 +106,8 @@ public interface DocumentLinker
/**
* Adds ES module initialization.
+ *
+ * @param initialization a {@link EsModuleInitialization} to configure details of the ES module import. It cannot be null.
* @since 5.10.0
*/
void addEsModuleInitialization(EsModuleInitialization initialization);
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ajax/AjaxFormUpdateController.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ajax/AjaxFormUpdateController.java
index 0e408c28a..deb599188 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ajax/AjaxFormUpdateController.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ajax/AjaxFormUpdateController.java
@@ -35,6 +35,8 @@ public interface AjaxFormUpdateController
* Called before starting to render a zone's content; initializes
* the {@link FormSupport} and {@link ValidationTracker} environmentals
* and starts a heartbeat.
+ *
+ * @param writer to write markup to
*/
void setupBeforePartialZoneRender(MarkupWriter writer);
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/services/ComponentEventRequestFilter.java b/tapestry-core/src/main/java/org/apache/tapestry5/services/ComponentEventRequestFilter.java
index dd3266ef9..e1bb41a1e 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/services/ComponentEventRequestFilter.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/services/ComponentEventRequestFilter.java
@@ -26,6 +26,7 @@ public interface ComponentEventRequestFilter
*
* @param parameters defining details of the request
* @param handler to delegate to
+ * @throws IOException
*/
void handle(ComponentEventRequestParameters parameters, ComponentEventRequestHandler handler) throws IOException;
}
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/services/ajax/AjaxResponseRenderer.java b/tapestry-core/src/main/java/org/apache/tapestry5/services/ajax/AjaxResponseRenderer.java
index af63592d0..557d22ea4 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/services/ajax/AjaxResponseRenderer.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/services/ajax/AjaxResponseRenderer.java
@@ -72,6 +72,8 @@ public interface AjaxResponseRenderer
* Adds a rendering filter. Dynamically added filters are only in place during the handling of the current request, and come after any filters
* contributed to the {@link org.apache.tapestry5.services.PartialMarkupRenderer} service.
*
+ * @param filter
+ * a partial markup filter
* @return this renderer, for a fluid interface
*/
AjaxResponseRenderer addFilter(PartialMarkupRendererFilter filter);
@@ -81,7 +83,7 @@ public interface AjaxResponseRenderer
* the callback is invoked before the rest of the rendering pipeline is invoked.
*
* @param callback
- * object o be invoked
+ * object to be invoked
* @return this renderer, for a fluid interface
*/
AjaxResponseRenderer addCallback(JSONCallback callback);
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/services/javascript/JavaScriptStack.java b/tapestry-core/src/main/java/org/apache/tapestry5/services/javascript/JavaScriptStack.java
index 25555e396..e9b15e493 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/services/javascript/JavaScriptStack.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/services/javascript/JavaScriptStack.java
@@ -49,11 +49,15 @@ public interface JavaScriptStack
* Returns a list of JavaScriptStack names that this stack depends on. Each stack will be processed before
* the current stack (thus a dependency stack's libraries, stylesheets and initialization is emitted before
* the dependent stack).
+ *
+ * @return list of JavaScriptStack dependency names
*/
List<String> getStacks();
/**
* Returns a list of <em>localized</em> assets for JavaScript libraries that form the stack.
+ *
+ * @return list of {@link Asset} this JavaScriptStack if formed of
*/
List<Asset> getJavaScriptLibraries();
@@ -69,6 +73,7 @@ public interface JavaScriptStack
*
* @see ModuleManager
* @see org.apache.tapestry5.SymbolConstants#COMBINE_SCRIPTS
+ * @return list of included modules
* @since 5.4
*/
List<String> getModules();
@@ -85,6 +90,7 @@ public interface JavaScriptStack
* Identifies how to aggregate JavaScript within the stack.
* The default is {@link org.apache.tapestry5.services.javascript.JavaScriptAggregationStrategy#COMBINE_AND_MINIMIZE}.
*
+ * @return how the stack is aggregated
* @since 5.4
*/
JavaScriptAggregationStrategy getJavaScriptAggregationStrategy();
@@ -97,6 +103,7 @@ public interface JavaScriptStack
*
* @deprecated Deprecated in Tapestry 5.4; may be removed in a future release. Implementations
* may return null.
+ * @return how the stack is aggregated
*/
String getInitialization();
}
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/services/javascript/JavaScriptSupport.java b/tapestry-core/src/main/java/org/apache/tapestry5/services/javascript/JavaScriptSupport.java
index 18fcedc4c..498a8274e 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/services/javascript/JavaScriptSupport.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/services/javascript/JavaScriptSupport.java
@@ -120,6 +120,8 @@ public interface JavaScriptSupport
* method are aggregated into a call to the Tapestry.init() function. Initialization occurs at
* {@link InitializationPriority#NORMAL} priority.
*
+ * @param priority
+ * priority to use when adding the script
* @param functionName
* name of client-side function (within Tapestry.Initializer namespace) to execute
* @param parameter
@@ -178,6 +180,7 @@ public interface JavaScriptSupport
* (whereas modules may be loaded in parallel), and all libraries are added before any modules are loaded.
* Because of this, it is preferrable to organize your JavaScript into modules, rather than libraries.
*
+ * @param asset JavaScript library to import
* @return this JavaScriptSupport, for further configuration
* @see org.apache.tapestry5.annotations.Import
*/
@@ -224,6 +227,8 @@ public interface JavaScriptSupport
* Import a Javascript library with an arbitrary URL.
*
* Please refer to the {@linkplain #importJavaScriptLibrary(Asset) notes about libraries vs. modules}.
+ * @param libraryURL JavaScript library to import
+ * @return this JavaScriptSupport, for further configuration
*/
JavaScriptSupport importJavaScriptLibrary(String libraryURL);
@@ -237,6 +242,7 @@ public interface JavaScriptSupport
* focus is set only if the provided priority is greater than the current priority
* @param fieldId
* id of client-side element to take focus
+ * @return this JavaScriptSupport, for further configuration
*/
JavaScriptSupport autofocus(FieldFocusPriority priority, String fieldId);
diff --git a/tapestry-http/src/main/java/org/apache/tapestry5/http/internal/services/DefaultCorsHandler.java b/tapestry-http/src/main/java/org/apache/tapestry5/http/internal/services/DefaultCorsHandler.java
index b14f9a284..74fd7920c 100644
--- a/tapestry-http/src/main/java/org/apache/tapestry5/http/internal/services/DefaultCorsHandler.java
+++ b/tapestry-http/src/main/java/org/apache/tapestry5/http/internal/services/DefaultCorsHandler.java
@@ -27,7 +27,7 @@ import org.apache.tapestry5.http.services.CorsHandlerHelper;
* regardless of path. It will also perform preflight requests if
* {@link CorsHandlerHelper#isPreflight(HttpServletRequest)}
* returns <code>true</code>. Most logic is delegated is {@link CorsHandlerHelper}.
- * <p>
+ * </p>
* <p>
* This implementation is inspired by the cors NPM module.
* </p>
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ValidatingOrderedConfigurationWrapper.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ValidatingOrderedConfigurationWrapper.java
index 046eb7a40..7a6cbc1b1 100644
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ValidatingOrderedConfigurationWrapper.java
+++ b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ValidatingOrderedConfigurationWrapper.java
@@ -25,8 +25,6 @@ import java.util.Map;
/**
* Wraps a {@link java.util.List} as a {@link org.apache.tapestry5.commons.OrderedConfiguration}, implementing validation of
* values provided to an {@link org.apache.tapestry5.commons.OrderedConfiguration}.
- *
- * @param <T>
*/
public class ValidatingOrderedConfigurationWrapper<T> extends AbstractConfigurationImpl<T> implements
OrderedConfiguration<T>
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/cron/CronExpression.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/cron/CronExpression.java
index 77630245c..ccf368127 100644
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/cron/CronExpression.java
+++ b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/cron/CronExpression.java
@@ -21,7 +21,7 @@ import java.util.*;
* expressions provide the ability to specify complex time combinations such as
* "At 8:00am every Monday through Friday" or "At 1:30am every
* last Friday of the month".
- * <P>
+ * <p>
* Cron expressions are comprised of 6 required fields and one optional field
* separated by white space. The fields respectively are described as follows:
*
@@ -84,21 +84,21 @@ import java.util.*;
* <td style="text-align: left;"><code>, - * /</code></td>
* </tr>
* </table>
- * <P>
+ * <p>
* The '*' character is used to specify all values. For example, "*"
* in the minute field means "every minute".
- * <P>
+ * <p>
* The '?' character is allowed for the day-of-month and day-of-week fields. It
* is used to specify 'no specific value'. This is useful when you need to
* specify something in one of the two fields, but not the other.
- * <P>
+ * <p>
* The '-' character is used to specify ranges For example "10-12" in
* the hour field means "the hours 10, 11 and 12".
- * <P>
+ * <p>
* The ',' character is used to specify additional values. For example
* "MON,WED,FRI" in the day-of-week field means "the days Monday,
* Wednesday, and Friday".
- * <P>
+ * <p>
* The '/' character is used to specify increments. For example "0/15"
* in the seconds field means "the seconds 0, 15, 30, and 45". And
* "5/15" in the seconds field means "the seconds 5, 20, 35, and
@@ -110,7 +110,7 @@ import java.util.*;
* on every "nth" value in the given set. Thus "7/6" in the
* month field only turns on month "7", it does NOT mean every 6th
* month, please note that subtlety.
- * <P>
+ * <p>
* The 'L' character is allowed for the day-of-month and day-of-week fields.
* This character is short-hand for "last", but it has different
* meaning in each of the two fields. For example, the value "L" in
@@ -123,7 +123,7 @@ import java.util.*;
* from the last day of the month, such as "L-3" which would mean the third-to-last
* day of the calendar month. <i>When using the 'L' option, it is important not to
* specify lists, or ranges of values, as you'll get confusing/unexpected results.</i>
- * <P>
+ * <p>
* The 'W' character is allowed for the day-of-month field. This character
* is used to specify the weekday (Monday-Friday) nearest the given day. As an
* example, if you were to specify "15W" as the value for the
@@ -135,11 +135,11 @@ import java.util.*;
* 1st is a Saturday, the trigger will fire on Monday the 3rd, as it will not
* 'jump' over the boundary of a month's days. The 'W' character can only be
* specified when the day-of-month is a single day, not a range or list of days.
- * <P>
+ * <p>
* The 'L' and 'W' characters can also be combined for the day-of-month
* expression to yield 'LW', which translates to "last weekday of the
* month".
- * <P>
+ * <p>
* The '#' character is allowed for the day-of-week field. This character is
* used to specify "the nth" XXX day of the month. For example, the
* value of "6#3" in the day-of-week field means the third Friday of
@@ -150,7 +150,7 @@ import java.util.*;
* no firing will occur that month. If the '#' character is used, there can
* only be one expression in the day-of-week field ("3#1,6#3" is
* not valid, since there are two expressions).
- * <P>
+ * <p>
* <!--The 'C' character is allowed for the day-of-month and day-of-week fields.
* This character is short-hand for "calendar". This means values are
* calculated against the associated calendar, if any. If no calendar is
@@ -158,7 +158,7 @@ import java.util.*;
* value of "5C" in the day-of-month field means "the first day included by the
* calendar on or after the 5th". A value of "1C" in the day-of-week field
* means "the first day included by the calendar on or after Sunday".-->
- * <P>
+ * <p>
* The legal characters and the names of months and days of the week are not
* case sensitive.
*
diff --git a/tapestry-rest-jackson/src/main/java/org/apache/tapestry5/jacksondatabind/services/ObjectMapperSource.java b/tapestry-rest-jackson/src/main/java/org/apache/tapestry5/jacksondatabind/services/ObjectMapperSource.java
index ea81ca35b..f1cb6caca 100644
--- a/tapestry-rest-jackson/src/main/java/org/apache/tapestry5/jacksondatabind/services/ObjectMapperSource.java
+++ b/tapestry-rest-jackson/src/main/java/org/apache/tapestry5/jacksondatabind/services/ObjectMapperSource.java
@@ -19,12 +19,13 @@ import com.fasterxml.jackson.databind.ObjectMapper;
/**
* <p>
* Service that provides {@link ObjectMapper} instances for specific mapped entity classes.
+ * </p>
* <p>
- * <p>
- * It's defined as an ordered configuration of {@link ObjectMapperSource} instances.
+ * It's defined as an ordered configuration of {@link ObjectMapperSource} instances.
* Calls to {@link #get(Class)} will call the same method in contributed instances until
* one returns a non-null {@link ObjectMapper} instance.
* </p>
+ *
* @see ObjectMapper
* @see MappedEntityManager
* @since 5.8.0
(tapestry-5) 04/12: TAP5-2809: fix plastic tests that rely on Groovy quirks
Posted by be...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
benw pushed a commit to branch gradle-improvements-javax
in repository https://gitbox.apache.org/repos/asf/tapestry-5.git
commit c7e338116edf4b0dd01e5dc241782a52e2b8241b
Author: Ben Weidig <be...@netzgut.net>
AuthorDate: Sun Aug 24 12:01:04 2025 +0200
TAP5-2809: fix plastic tests that rely on Groovy quirks
---
.../tapestry5/plastic/FieldPropertyMethodCreation.groovy | 14 +++++++++-----
.../apache/tapestry5/plastic/MethodAnnotationAccess.groovy | 4 ++--
2 files changed, 11 insertions(+), 7 deletions(-)
diff --git a/plastic/src/test/groovy/org/apache/tapestry5/plastic/FieldPropertyMethodCreation.groovy b/plastic/src/test/groovy/org/apache/tapestry5/plastic/FieldPropertyMethodCreation.groovy
index 62627d885..3a4fd3e3f 100644
--- a/plastic/src/test/groovy/org/apache/tapestry5/plastic/FieldPropertyMethodCreation.groovy
+++ b/plastic/src/test/groovy/org/apache/tapestry5/plastic/FieldPropertyMethodCreation.groovy
@@ -3,10 +3,12 @@ package org.apache.tapestry5.plastic
import spock.lang.Issue
import testannotations.Property
import testsubjects.AccessorsAlreadyExistSubject
-import testsubjects.AccessorsAlreadyExistSubject2;
+import testsubjects.AccessorsAlreadyExistSubject2
import testsubjects.CreateAccessorsSubject
import testsubjects.GenericCreateAccessorsSubject
+import java.lang.invoke.MethodType
+import java.lang.reflect.*
import java.util.concurrent.atomic.AtomicReference
class FieldPropertyMethodCreation extends AbstractPlasticSpecification
@@ -70,12 +72,10 @@ class FieldPropertyMethodCreation extends AbstractPlasticSpecification
assert o.refValue == "Plastic"
def get = o.class.getMethod("getRef")
- get.signature == "()Ljava/util/concurrent/atomic/AtomicReference<Ljava/lang/String;>;"
- get.genericInfo != null
+ getSignature(get) == "()Ljava/util/concurrent/atomic/AtomicReference;"
def set = o.class.getMethod("setRef", AtomicReference)
- set.signature == "(Ljava/util/concurrent/atomic/AtomicReference<Ljava/lang/String;>;)V"
- set.genericInfo != null
+ getSignature(set) == "(Ljava/util/concurrent/atomic/AtomicReference;)V"
}
def "create getter that already exists"() {
@@ -114,4 +114,8 @@ class FieldPropertyMethodCreation extends AbstractPlasticSpecification
assert e.message == "Unable to create new accessor method public void setValue(java.lang.String) on class testsubjects.AccessorsAlreadyExistSubject as the method is already implemented."
}
+
+ private def getSignature(Method m) {
+ MethodType.methodType(m.returnType, m.parameterTypes).toMethodDescriptorString()
+ }
}
diff --git a/plastic/src/test/groovy/org/apache/tapestry5/plastic/MethodAnnotationAccess.groovy b/plastic/src/test/groovy/org/apache/tapestry5/plastic/MethodAnnotationAccess.groovy
index baa11488a..33b2c5b61 100644
--- a/plastic/src/test/groovy/org/apache/tapestry5/plastic/MethodAnnotationAccess.groovy
+++ b/plastic/src/test/groovy/org/apache/tapestry5/plastic/MethodAnnotationAccess.groovy
@@ -20,7 +20,7 @@ class MethodAnnotationAccess extends AbstractPlasticSpecification {
then:
- methods.size == 2
+ methods.size() == 2
noMethod.description.methodName == "no"
yesMethod.description.methodName == "yes"
@@ -34,7 +34,7 @@ class MethodAnnotationAccess extends AbstractPlasticSpecification {
def methods = pc.getMethodsWithAnnotation(PrimitiveValues)
then:
- methods.size == 1
+ methods.size() == 1
when:
def pv = methods[0].getAnnotation(PrimitiveValues)
(tapestry-5) 06/12: TAP5-2809: Fix Javadoc errors
Posted by be...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
benw pushed a commit to branch gradle-improvements-javax
in repository https://gitbox.apache.org/repos/asf/tapestry-5.git
commit 348d8bad921aafd8867e7f9f09f5c9571dccd714
Author: Ben Weidig <be...@netzgut.net>
AuthorDate: Tue Jun 10 08:38:30 2025 +0200
TAP5-2809: Fix Javadoc errors
---
.../src/main/java/org/apache/tapestry5/ioc/junit/ModuleDef.java | 2 +-
.../src/main/java/org/apache/tapestry5/ioc/junit/Registry.java | 2 +-
.../main/java/org/apache/tapestry5/ioc/junit/RegistryShutdownType.java | 2 +-
3 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/tapestry-ioc-junit/src/main/java/org/apache/tapestry5/ioc/junit/ModuleDef.java b/tapestry-ioc-junit/src/main/java/org/apache/tapestry5/ioc/junit/ModuleDef.java
index aa8a20e0d..ae0834fbb 100644
--- a/tapestry-ioc-junit/src/main/java/org/apache/tapestry5/ioc/junit/ModuleDef.java
+++ b/tapestry-ioc-junit/src/main/java/org/apache/tapestry5/ioc/junit/ModuleDef.java
@@ -22,7 +22,7 @@ import java.lang.annotation.Target;
/**
* Marker annotation for a method which creates a {@link org.apache.tapestry5.ioc.def.ModuleDef}.
- * Used by the {@link TapestryIOCJUnit4ClassRunner}, methods with this annotation must be public, static, no-args methods
+ * Used by the {@link TapestryIOCJUnitExtension}, methods with this annotation must be public, static, no-args methods
* which return {@link org.apache.tapestry5.ioc.def.ModuleDef} (or a subclass)
*/
@Retention(RetentionPolicy.RUNTIME)
diff --git a/tapestry-ioc-junit/src/main/java/org/apache/tapestry5/ioc/junit/Registry.java b/tapestry-ioc-junit/src/main/java/org/apache/tapestry5/ioc/junit/Registry.java
index 55f3e1a79..a2dd6ce62 100644
--- a/tapestry-ioc-junit/src/main/java/org/apache/tapestry5/ioc/junit/Registry.java
+++ b/tapestry-ioc-junit/src/main/java/org/apache/tapestry5/ioc/junit/Registry.java
@@ -21,7 +21,7 @@ import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
- * Used by the {@link TapestryIOCJUnit4ClassRunner} to configure a test {@link org.apache.tapestry5.ioc.Registry}
+ * Used by the {@link TapestryIOCJUnitExtension} to configure a test {@link org.apache.tapestry5.ioc.Registry}
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
diff --git a/tapestry-ioc-junit/src/main/java/org/apache/tapestry5/ioc/junit/RegistryShutdownType.java b/tapestry-ioc-junit/src/main/java/org/apache/tapestry5/ioc/junit/RegistryShutdownType.java
index 468dd86fa..0d74bb1a5 100644
--- a/tapestry-ioc-junit/src/main/java/org/apache/tapestry5/ioc/junit/RegistryShutdownType.java
+++ b/tapestry-ioc-junit/src/main/java/org/apache/tapestry5/ioc/junit/RegistryShutdownType.java
@@ -15,7 +15,7 @@
package org.apache.tapestry5.ioc.junit;
/**
- * Used in conjunction with the {@link TapestryIOCJUnit4ClassRunner} to determine the registry lifecycle
+ * Used in conjunction with the {@link TapestryIOCJUnitExtension} to determine the registry lifecycle
*/
public enum RegistryShutdownType {
/**
(tapestry-5) 02/12: TAP5-2809: fix tapestry-ioc-junit compilation issues
Posted by be...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
benw pushed a commit to branch gradle-improvements-javax
in repository https://gitbox.apache.org/repos/asf/tapestry-5.git
commit b474b2110750f0bffdfbbad7615215c07efa4f28
Author: Ben Weidig <be...@netzgut.net>
AuthorDate: Sat Sep 13 13:23:58 2025 +0200
TAP5-2809: fix tapestry-ioc-junit compilation issues
---
.../ioc/junit/TapestryIOCJUnit4ClassRunner.java | 150 --------------
.../ioc/junit/TapestryIOCJUnitExtension.java | 108 ++++++++++
.../tapestry5/ioc/junit/TestRegistryManager.java | 226 +++++++++++----------
3 files changed, 231 insertions(+), 253 deletions(-)
diff --git a/tapestry-ioc-junit/src/main/java/org/apache/tapestry5/ioc/junit/TapestryIOCJUnit4ClassRunner.java b/tapestry-ioc-junit/src/main/java/org/apache/tapestry5/ioc/junit/TapestryIOCJUnit4ClassRunner.java
deleted file mode 100644
index d12741978..000000000
--- a/tapestry-ioc-junit/src/main/java/org/apache/tapestry5/ioc/junit/TapestryIOCJUnit4ClassRunner.java
+++ /dev/null
@@ -1,150 +0,0 @@
-// 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 org.apache.tapestry5.ioc.junit;
-
-import org.apache.tapestry5.ioc.annotations.Inject;
-import org.apache.tapestry5.ioc.def.ModuleDef;
-import org.junit.runner.Description;
-import org.junit.runner.Result;
-import org.junit.runner.notification.Failure;
-import org.junit.runner.notification.RunListener;
-import org.junit.runner.notification.RunNotifier;
-import org.junit.runner.notification.StoppedByUserException;
-import org.junit.runners.BlockJUnit4ClassRunner;
-import org.junit.runners.model.InitializationError;
-import org.junit.runners.model.Statement;
-
-/**
- *
- * A JUnit4ClassRunner to help with Tapestry IOC integration tests. The test
- * runner requires a registry configuration to be defined in a {@link Registry}
- * annotation. A {@link RegistryShutdownType} can be specified to configure the
- * lifecycle of the test registry and it's services
- *
- *
- *
- * {@link org.apache.tapestry5.ioc.junit.ModuleDef}s can be added to the
- * {@link org.apache.tapestry5.ioc.Registry} by annotating a factory method(s)
- * with {@link ModuleDef}. These {@link ModuleDef} factory methods must be
- * <ul>
- * <li>public</li>
- * <li>static</li>
- * <li>take zero arguments</li>
- * <li>return a subclass of {@link org.apache.tapestry5.ioc.junit.ModuleDef}</li>
- * </ul>
- *
- *
- *
- * Any services defined in the registry can be {@link Inject}ed into the test
- * class to be used during testing.
- *
- */
-public class TapestryIOCJUnit4ClassRunner extends BlockJUnit4ClassRunner {
- private final TestRegistryManager registryManager;
-
- public TapestryIOCJUnit4ClassRunner(Class<?> type) throws InitializationError {
- super(type);
- this.registryManager = new TestRegistryManager(type);
- }
-
- @Override
- public void run(RunNotifier notifier) {
- RunNotifier wrapper = new RegistryManagerRunNotifier(registryManager, notifier);
- super.run(wrapper);
- }
-
- @Override
- protected Statement withAfterClasses(Statement statement) {
- final Statement superStatement = super.withAfterClasses(statement);
- return new Statement() {
- @Override
- public void evaluate() throws Throwable {
- superStatement.evaluate();
- registryManager.afterTestClass();
- }
- };
- }
-
- @Override
- protected Object createTest() throws Exception {
- org.apache.tapestry5.ioc.Registry registry = registryManager.getOrCreateRegistry();
- return registry.autobuild(getTestClass().getJavaClass());
- }
-
- public static class RegistryManagerRunNotifier extends RunNotifier {
- private final RunNotifier delegate;
- private final TestRegistryManager registryManager;
-
- public RegistryManagerRunNotifier(TestRegistryManager registryManager, RunNotifier delegate) {
- super();
- this.delegate = delegate;
- this.registryManager = registryManager;
- }
-
- @Override
- public void addListener(RunListener listener) {
- delegate.addListener(listener);
- }
-
- @Override
- public void removeListener(RunListener listener) {
- delegate.removeListener(listener);
- }
-
- @Override
- public void fireTestRunStarted(Description description) {
- delegate.fireTestRunStarted(description);
- }
-
- @Override
- public void fireTestRunFinished(Result result) {
- delegate.fireTestRunFinished(result);
- }
-
- @Override
- public void fireTestStarted(Description description) throws StoppedByUserException {
- delegate.fireTestStarted(description);
- }
-
- @Override
- public void fireTestFailure(Failure failure) {
- delegate.fireTestFailure(failure);
- }
-
- @Override
- public void fireTestAssumptionFailed(Failure failure) {
- delegate.fireTestAssumptionFailed(failure);
- }
-
- @Override
- public void fireTestIgnored(Description description) {
- delegate.fireTestIgnored(description);
- }
-
- @Override
- public void fireTestFinished(Description description) {
- registryManager.afterTestMethod();
- delegate.fireTestFinished(description);
- }
-
- @Override
- public void pleaseStop() {
- delegate.pleaseStop();
- }
-
- @Override
- public void addFirstListener(RunListener listener) {
- delegate.addFirstListener(listener);
- }
- }
-}
\ No newline at end of file
diff --git a/tapestry-ioc-junit/src/main/java/org/apache/tapestry5/ioc/junit/TapestryIOCJUnitExtension.java b/tapestry-ioc-junit/src/main/java/org/apache/tapestry5/ioc/junit/TapestryIOCJUnitExtension.java
new file mode 100644
index 000000000..f6e75087d
--- /dev/null
+++ b/tapestry-ioc-junit/src/main/java/org/apache/tapestry5/ioc/junit/TapestryIOCJUnitExtension.java
@@ -0,0 +1,108 @@
+// Copyright 2025 The Apache Software Foundation
+//
+// 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 org.apache.tapestry5.ioc.junit;
+
+import java.lang.reflect.Field;
+
+import org.apache.tapestry5.ioc.Registry;
+import org.apache.tapestry5.ioc.annotations.Inject;
+import org.junit.jupiter.api.extension.AfterAllCallback;
+import org.junit.jupiter.api.extension.AfterEachCallback;
+import org.junit.jupiter.api.extension.BeforeAllCallback;
+import org.junit.jupiter.api.extension.BeforeEachCallback;
+import org.junit.jupiter.api.extension.ExtensionContext;
+import org.junit.jupiter.api.extension.TestInstanceFactory;
+import org.junit.jupiter.api.extension.TestInstanceFactoryContext;
+import org.junit.jupiter.api.extension.TestInstantiationException;
+
+public class TapestryIOCJUnitExtension implements BeforeAllCallback, AfterAllCallback,
+ BeforeEachCallback, AfterEachCallback, TestInstanceFactory
+{
+
+ private TestRegistryManager registryManager;
+
+ @Override
+ public void beforeAll(ExtensionContext context) throws Exception
+ {
+ Class<?> testClass = context.getRequiredTestClass();
+ registryManager = new TestRegistryManager(testClass);
+ }
+
+ @Override
+ public void afterAll(ExtensionContext context) throws Exception
+ {
+ if (registryManager != null)
+ {
+ registryManager.afterTestClass();
+ }
+ }
+
+ @Override
+ public void beforeEach(ExtensionContext context) throws Exception
+ {
+ // No-op: lifecycle handled by createTestInstance
+ }
+
+ @Override
+ public void afterEach(ExtensionContext context) throws Exception
+ {
+ if (registryManager != null)
+ {
+ registryManager.afterTestMethod();
+ }
+ }
+
+ @Override
+ public Object createTestInstance(TestInstanceFactoryContext factoryContext,
+ ExtensionContext extensionContext) throws TestInstantiationException
+ {
+ if (registryManager == null)
+ {
+ registryManager = new TestRegistryManager(factoryContext.getTestClass());
+ }
+ try
+ {
+ Registry registry = registryManager.getOrCreateRegistry();
+ Object testInstance = registry.autobuild(factoryContext.getTestClass());
+ injectFields(testInstance, registry);
+ return testInstance;
+ }
+ catch (Exception e)
+ {
+ throw new TestInstantiationException("", e);
+ }
+ }
+
+ private void injectFields(Object instance, Registry registry)
+ {
+ Class<?> clazz = instance.getClass();
+ for (Field field : clazz.getDeclaredFields())
+ {
+ if (field.isAnnotationPresent(Inject.class))
+ {
+ Object service = registry.getObject(field.getType(), null);
+ field.setAccessible(true);
+ try
+ {
+ field.set(instance, service);
+ }
+ catch (IllegalAccessException e)
+ {
+ throw new RuntimeException("Failed to inject field: " + field, e);
+ }
+ }
+ }
+ }
+}
diff --git a/tapestry-ioc-junit/src/main/java/org/apache/tapestry5/ioc/junit/TestRegistryManager.java b/tapestry-ioc-junit/src/main/java/org/apache/tapestry5/ioc/junit/TestRegistryManager.java
index fd8ac454f..d74b61519 100644
--- a/tapestry-ioc-junit/src/main/java/org/apache/tapestry5/ioc/junit/TestRegistryManager.java
+++ b/tapestry-ioc-junit/src/main/java/org/apache/tapestry5/ioc/junit/TestRegistryManager.java
@@ -22,110 +22,130 @@ import java.util.Collections;
import java.util.List;
import org.apache.tapestry5.ioc.RegistryBuilder;
-import org.junit.runners.model.InitializationError;
/**
- * Helper class used by the {@link TapestryIOCJUnit4ClassRunner} to manage the test registry
+ * Helper class used by the {@link TapestryIOCJUnitExtension} to manage the test registry
*/
-public class TestRegistryManager {
- private final Registry annotation;
- private final List<Method> moduleDefFactories;
-
- private org.apache.tapestry5.ioc.Registry registry;
-
- public TestRegistryManager(Class<?> type) throws InitializationError {
- super();
-
- Registry annotation = type.getAnnotation(Registry.class);
- if (annotation == null) {
- throw new InitializationError(type.getName() + " does not specify a @Registry");
- }
-
- this.annotation = annotation;
- this.moduleDefFactories = findModuleDefFactories(type);
- }
-
- protected List<Method> findModuleDefFactories(Class<?> type) throws InitializationError {
- List<Method> factoryMethods = new ArrayList<Method>();
- for (Method method : type.getMethods()) {
- if (method.getAnnotation(ModuleDef.class) != null) {
- validateModuleDefMethod(method);
- factoryMethods.add(method);
- }
- }
- return factoryMethods.isEmpty() ? Collections.<Method> emptyList() : factoryMethods;
- }
-
- protected void validateModuleDefMethod(Method method) throws InitializationError {
- int modifiers = method.getModifiers();
- if (method.getParameterTypes().length != 0
- || !Modifier.isStatic(modifiers)
- || !Modifier.isPublic(modifiers)) {
-
- throw new InitializationError(
- String.format("@ModuleDef method %s must be public static and accept no arguments",
- method.getName()));
- }
- if (!org.apache.tapestry5.ioc.def.ModuleDef.class.isAssignableFrom(method.getReturnType())) {
- throw new InitializationError(
- String.format("@ModuleDef method %s return type %s is not valid",
- method.getName(), method.getReturnType().getName()));
- }
- }
-
- /**
- * Get the existing registry or create one if required.
- * @return The test Registry
- * @throws Exception
- */
- public org.apache.tapestry5.ioc.Registry getOrCreateRegistry() throws Exception {
- if (registry == null) {
- RegistryBuilder builder = new RegistryBuilder();
- if (annotation.modules() != null) {
- builder.add(annotation.modules());
- }
- for (Method moduleDefFactory : moduleDefFactories) {
- try {
- org.apache.tapestry5.ioc.def.ModuleDef moduleDef =
- (org.apache.tapestry5.ioc.def.ModuleDef) moduleDefFactory.invoke(null);
-
- builder.add(moduleDef);
- } catch (InvocationTargetException e) {
- if (e.getTargetException() instanceof Exception) {
- throw (Exception) e.getTargetException();
- }
- throw e;
- }
- }
- registry = builder.build();
- registry.performRegistryStartup();
- }
- return registry;
- }
-
- /**
- * Notify that the current test method has completed
- */
- public void afterTestMethod() {
- if (annotation.shutdown() == RegistryShutdownType.AFTER_METHOD) {
- shutdownRegistry();
- }
- }
-
- /**
- * Notify that the current test class has completed
- */
- public void afterTestClass() {
- if (annotation.shutdown() == RegistryShutdownType.AFTER_CLASS) {
- shutdownRegistry();
- }
- }
-
- protected void shutdownRegistry() {
- try {
- registry.shutdown();
- } finally {
- registry = null;
- }
- }
+public class TestRegistryManager
+{
+ private final Registry annotation;
+ private final List<Method> moduleDefFactories;
+
+ private org.apache.tapestry5.ioc.Registry registry;
+
+ public TestRegistryManager(Class<?> type) throws RuntimeException
+ {
+ super();
+
+ Registry annotation = type.getAnnotation(Registry.class);
+ if (annotation == null)
+ { throw new RuntimeException(type.getName() + " does not specify a @Registry"); }
+
+ this.annotation = annotation;
+ this.moduleDefFactories = findModuleDefFactories(type);
+ }
+
+ protected List<Method> findModuleDefFactories(Class<?> type) throws RuntimeException
+ {
+ List<Method> factoryMethods = new ArrayList<Method>();
+ for (Method method : type.getMethods())
+ {
+ if (method.getAnnotation(ModuleDef.class) != null)
+ {
+ validateModuleDefMethod(method);
+ factoryMethods.add(method);
+ }
+ }
+ return factoryMethods.isEmpty() ? Collections.<Method> emptyList() : factoryMethods;
+ }
+
+ protected void validateModuleDefMethod(Method method) throws RuntimeException
+ {
+ int modifiers = method.getModifiers();
+ if (method.getParameterTypes().length != 0 || !Modifier.isStatic(modifiers)
+ || !Modifier.isPublic(modifiers))
+ {
+
+ throw new RuntimeException(String.format(
+ "@ModuleDef method %s must be public static and accept no arguments",
+ method.getName()));
+ }
+ if (!org.apache.tapestry5.ioc.def.ModuleDef.class.isAssignableFrom(method.getReturnType()))
+ {
+ throw new RuntimeException(
+ String.format("@ModuleDef method %s return type %s is not valid",
+ method.getName(), method.getReturnType().getName()));
+ }
+ }
+
+ /**
+ * Get the existing registry or create one if required.
+ *
+ * @return The test Registry
+ * @throws Exception
+ */
+ public org.apache.tapestry5.ioc.Registry getOrCreateRegistry() throws Exception
+ {
+ if (registry == null)
+ {
+ RegistryBuilder builder = new RegistryBuilder();
+ if (annotation.modules() != null)
+ {
+ builder.add(annotation.modules());
+ }
+ for (Method moduleDefFactory : moduleDefFactories)
+ {
+ try
+ {
+ org.apache.tapestry5.ioc.def.ModuleDef moduleDef = (org.apache.tapestry5.ioc.def.ModuleDef) moduleDefFactory
+ .invoke(null);
+
+ builder.add(moduleDef);
+ }
+ catch (InvocationTargetException e)
+ {
+ if (e.getTargetException() instanceof Exception)
+ { throw (Exception) e.getTargetException(); }
+ throw e;
+ }
+ }
+ registry = builder.build();
+ registry.performRegistryStartup();
+ }
+ return registry;
+ }
+
+ /**
+ * Notify that the current test method has completed
+ */
+ public void afterTestMethod()
+ {
+ if (annotation.shutdown() == RegistryShutdownType.AFTER_METHOD)
+ {
+ shutdownRegistry();
+ }
+ }
+
+ /**
+ * Notify that the current test class has completed
+ */
+ public void afterTestClass()
+ {
+ if (annotation.shutdown() == RegistryShutdownType.AFTER_CLASS)
+ {
+ shutdownRegistry();
+ }
+ }
+
+ protected void shutdownRegistry()
+ {
+ try
+ {
+ registry.shutdown();
+ }
+ finally
+ {
+ registry = null;
+ }
+ }
}
(tapestry-5) 09/12: TAP5-2809: removed singluar test that relied on a Groovy bug
Posted by be...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
benw pushed a commit to branch gradle-improvements-javax
in repository https://gitbox.apache.org/repos/asf/tapestry-5.git
commit 0e7061725490e3d9734767cfee3ee817db597e4a
Author: Ben Weidig <be...@netzgut.net>
AuthorDate: Sun Jun 15 16:05:24 2025 +0200
TAP5-2809: removed singluar test that relied on a Groovy bug
---
.../apache/tapestry5/plastic/MethodProxying.groovy | 55 ++++++++++------------
1 file changed, 25 insertions(+), 30 deletions(-)
diff --git a/plastic/src/test/groovy/org/apache/tapestry5/plastic/MethodProxying.groovy b/plastic/src/test/groovy/org/apache/tapestry5/plastic/MethodProxying.groovy
index 18856c63e..fc6e01534 100644
--- a/plastic/src/test/groovy/org/apache/tapestry5/plastic/MethodProxying.groovy
+++ b/plastic/src/test/groovy/org/apache/tapestry5/plastic/MethodProxying.groovy
@@ -33,38 +33,34 @@ class MethodProxying extends AbstractPlasticSpecification {
1 * mockRunnable.run()
}
- def "Proxying with static methods"() {
- setup:
-
- def mockRunnable = Mock(Runnable.class)
-
- def o = mgr.createClass(Object, { PlasticClass pc ->
-
- def field = pc.introduceField(Runnable, "delegate").inject(mockRunnable)
-
- pc.proxyInterface(WithStatic, field)
- } as PlasticClassTransformer).newInstance()
-
- expect:
-
- WithStatic.isInstance o
- o.version() == 1
-
- when:
-
- o.run()
-
- then:
-
- 1 * mockRunnable.run()
- }
+ /*
+ * The call o.version() was wroking due to a bug in Groovy and
+ * calliong static methods on instances no longer works since 3.0.18
+ * https://issues.apache.org/jira/browse/GROOVY-8164
+ * https://issues.apache.org/jira/browse/GROOVY-10764
+ def "Proxying with static methods"() {
+ setup:
+ def mockRunnable = Mock(Runnable.class)
+ def o = mgr.createClass(Object, { PlasticClass pc ->
+ def field = pc.introduceField(Runnable, "delegate").inject(mockRunnable)
+ pc.proxyInterface(WithStatic, field)
+ } as PlasticClassTransformer).newInstance()
+ expect:
+ WithStatic.isInstance o
+ o.version() == 1
+ when:
+ o.run()
+ then:
+ 1 * mockRunnable.run()
+ }
+ */
@Issue("TAP5-2582")
def "Proxying with multiple methods of the same signature"() {
setup:
def mockRunner = Mock(SameMethodsInterface.class) {
- run() >> new testinterfaces.samemethodinterface.pkg2.Result();
+ run() >> new testinterfaces.samemethodinterface.pkg2.Result()
}
def o = mgr.createClass(Object, { PlasticClass pc ->
@@ -76,13 +72,13 @@ class MethodProxying extends AbstractPlasticSpecification {
when:
- def result = o.run();
+ def result = o.run()
then:
- result instanceof testinterfaces.samemethodinterface.pkg1.Result;
+ result instanceof testinterfaces.samemethodinterface.pkg1.Result
- result instanceof testinterfaces.samemethodinterface.pkg2.Result;
+ result instanceof testinterfaces.samemethodinterface.pkg2.Result
}
def "proxy method with arguments and return value"() {
@@ -130,7 +126,6 @@ class MethodProxying extends AbstractPlasticSpecification {
mi.returnValue = memory
// And don't proceed()
-
} as MethodAdvice)
def m = Memory.getMethod("returnLast", long)
(tapestry-5) 08/12: TAP5-2809: Fix groovy test
Posted by be...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
benw pushed a commit to branch gradle-improvements-javax
in repository https://gitbox.apache.org/repos/asf/tapestry-5.git
commit b6520b3b9bebd538d725c8f769b5445ff3e231e3
Author: Ben Weidig <be...@netzgut.net>
AuthorDate: Sun Jun 15 13:47:59 2025 +0200
TAP5-2809: Fix groovy test
---
tapestry-ioc/src/test/groovy/ioc/specs/ChainBuilderImplSpec.groovy | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tapestry-ioc/src/test/groovy/ioc/specs/ChainBuilderImplSpec.groovy b/tapestry-ioc/src/test/groovy/ioc/specs/ChainBuilderImplSpec.groovy
index 12ff3a7dc..8ec96b1f5 100644
--- a/tapestry-ioc/src/test/groovy/ioc/specs/ChainBuilderImplSpec.groovy
+++ b/tapestry-ioc/src/test/groovy/ioc/specs/ChainBuilderImplSpec.groovy
@@ -118,7 +118,7 @@ class ChainBuilderImplSpec extends AbstractSharedRegistrySpecification {
chain.toString() == "<Command chain of ioc.specs.ChainCommand>"
}
- final private static class InterfaceWithStaticMethodImpl extends InterfaceWithStaticMethod
+ final private static class InterfaceWithStaticMethodImpl implements InterfaceWithStaticMethod
{
public int something() { return 2; }
}
(tapestry-5) 11/12: TAP5-2809: Groovy 4
Posted by be...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
benw pushed a commit to branch gradle-improvements-javax
in repository https://gitbox.apache.org/repos/asf/tapestry-5.git
commit ed3dd34e2050f1922671ec13cba0bee99d90b459
Author: Ben Weidig <be...@netzgut.net>
AuthorDate: Sat Sep 13 16:57:55 2025 +0200
TAP5-2809: Groovy 4
---
build.gradle | 2 ++
.../groovy/tapestry.junit5-spock-convention.gradle | 2 ++
gradle/libs.versions.toml | 35 +++++++++++++++-------
tapestry-spock/build.gradle | 2 ++
4 files changed, 30 insertions(+), 11 deletions(-)
diff --git a/build.gradle b/build.gradle
index 300c62ef3..fe00c0996 100755
--- a/build.gradle
+++ b/build.gradle
@@ -108,6 +108,8 @@ subprojects {
dependencies {
implementation libs.slf4j.api
+ implementation libs.bundles.groovy
+
}
tasks.withType(GroovyCompile).configureEach {
diff --git a/buildSrc/src/main/groovy/tapestry.junit5-spock-convention.gradle b/buildSrc/src/main/groovy/tapestry.junit5-spock-convention.gradle
index 3f58f33c0..1570598ef 100644
--- a/buildSrc/src/main/groovy/tapestry.junit5-spock-convention.gradle
+++ b/buildSrc/src/main/groovy/tapestry.junit5-spock-convention.gradle
@@ -4,6 +4,8 @@ plugins {
}
dependencies {
+ testImplementation libs.bundles.groovy
+
testImplementation platform(libs.spock.bom)
testImplementation libs.spock.core
}
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index b0055439f..c3246addf 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -6,13 +6,13 @@ slf4j = "1.7.25"
# JAVAX/JAKARTA
-javax-inject = "1"
-javax-servlet-api = "3.0.1"
-javax-validation-api = "1.0.0.GA"
+javax-inject = "1"
+javax-persistence-api = "2.2"
+javax-servlet-api = "3.0.1"
+javax-validation-api = "1.0.0.GA"
-jakarta-annotation-api = "1.3.4"
-jakarta-persistence-api = "3.0.0"
-jakarta-xml-bind-api = "2.3.2"
+jakarta-annotation-api = "1.3.4"
+jakarta-xml-bind-api = "2.3.2"
# APACHE COMMONS
@@ -43,6 +43,7 @@ hamcrest-core = "1.3"
json = "20140107"
xml-apis = "1.4.01"
guice = "3.0"
+groovy = "4.0.27"
ant-jsch = "1.8.2"
guava = "27.0.1-jre"
jackson = "2.13.1"
@@ -56,7 +57,7 @@ junit5 = "5.10.2"
junit4 = "4.13.2"
testng = "7.5.1"
easymock = "5.4.0"
-spock = "2.3-groovy-3.0"
+spock = "2.3-groovy-4.0"
geb = "2.0"
webdrivermanager = "5.3.1"
selenium = "4.5.0"
@@ -84,12 +85,12 @@ slf4j-log4j12 = { module = "org.slf4j:slf4j-log4j12", version.ref = "slf4j" }
# JAVAX/JAKARTA
-javax-inject = { module = "javax.inject:javax.inject", version.ref = "javax-inject" }
-javax-servlet-api = { module = "javax.servlet:javax.servlet-api", version.ref = "javax-servlet-api" }
-javax-validation-api = { module = "javax.validation:validation-api", version.ref = "javax-validation-api" }
+javax-inject = { module = "javax.inject:javax.inject", version.ref = "javax-inject" }
+javax-persistence-api = { module = "javax.persistence:javax.persistence-api", version.ref = "javax-persistence-api" }
+javax-servlet-api = { module = "javax.servlet:javax.servlet-api", version.ref = "javax-servlet-api" }
+javax-validation-api = { module = "javax.validation:validation-api", version.ref = "javax-validation-api" }
jakarta-annotation-api = { module = "jakarta.annotation:jakarta.annotation-api", version.ref = "jakarta-annotation-api" }
-jakarta-persistence-api = { module = "jakarta.persistence:jakarta.persistence-api", version.ref = "jakarta-persistence-api" }
jakarta-xml-bind-api = { module = "jakarta.xml.bind:jakarta.xml.bind-api", version.ref = "jakarta-xml-bind-api" }
# APACHE COMMONS
@@ -127,6 +128,12 @@ guava = { module = "com.google.guava:guava", version.ref = "guava" }
clojure = { module = "org.clojure:clojure", version.ref = "clojure" }
httpcomponents-httpclient = { module = "org.apache.httpcomponents:httpclient", version.ref = "httpcomponents-httpclient" }
+# GROOVY
+
+groovy-core = { module = "org.apache.groovy:groovy", version.ref = "groovy" }
+groovy-json = { module = "org.apache.groovy:groovy-json", version.ref = "groovy" }
+groovy-nio = { module = "org.apache.groovy:groovy-nio", version.ref = "groovy" }
+
# JACKSON
jackson-databind = { module = "com.fasterxml.jackson.core:jackson-databind", version.ref = "jackson" }
@@ -162,6 +169,12 @@ webdrivermanager = { module = "io.github.bonigarcia:webdrivermanager", version.r
[bundles]
+groovy = [
+ "groovy-core",
+ "groovy-json",
+ "groovy-nio"
+]
+
junit-jupiter-essentials = [
"junit-jupiter-api",
"junit-jupiter-params"
diff --git a/tapestry-spock/build.gradle b/tapestry-spock/build.gradle
index 50a9a60c8..d9c32a07d 100644
--- a/tapestry-spock/build.gradle
+++ b/tapestry-spock/build.gradle
@@ -9,6 +9,8 @@ dependencies {
provided project(':commons')
provided project(':tapestry-ioc')
+ api libs.bundles.groovy
+
api platform(libs.spock.bom)
api libs.spock.core
(tapestry-5) 05/12: TAP5-2809: fix webresources test
Posted by be...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
benw pushed a commit to branch gradle-improvements-javax
in repository https://gitbox.apache.org/repos/asf/tapestry-5.git
commit 6ab32d670e264a85e328f44b993f366bebfa2064
Author: Ben Weidig <be...@netzgut.net>
AuthorDate: Sun Aug 24 10:46:37 2025 +0200
TAP5-2809: fix webresources test
---
tapestry-webresources/src/test/resources/META-INF/modules/index.coffee | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tapestry-webresources/src/test/resources/META-INF/modules/index.coffee b/tapestry-webresources/src/test/resources/META-INF/modules/index.coffee
index 3b1d46a77..f1c1adf4b 100644
--- a/tapestry-webresources/src/test/resources/META-INF/modules/index.coffee
+++ b/tapestry-webresources/src/test/resources/META-INF/modules/index.coffee
@@ -1,3 +1,3 @@
require ["t5/core/dom"], (dom) ->
- (dom "banner").update "Index module loaded, bare!"
\ No newline at end of file
+ (dom.default("banner")).update "Index module loaded, bare!"
\ No newline at end of file
(tapestry-5) 12/12: TAP5-2809: fix tests
Posted by be...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
benw pushed a commit to branch gradle-improvements-javax
in repository https://gitbox.apache.org/repos/asf/tapestry-5.git
commit 7682b73949c3baaa3acfe7d62b30bc1a7edf9b53
Author: Ben Weidig <be...@netzgut.net>
AuthorDate: Sat Sep 13 17:00:31 2025 +0200
TAP5-2809: fix tests
---
plastic/src/test/conf/testng.xml | 6 -
.../src/test/{conf => resources}/testng.xml | 0
.../apache/tapestry5/clojure/tests/TestModule.java | 12 +
.../app1/PartialTemplateRendererTests.groovy | 1 -
.../ComponentDependencyRegistryImplTest.java | 332 +++----
.../test/{conf => resources}/testng-limited.xml | 0
.../src/test/{conf => resources}/testng.xml | 163 ++--
tapestry-func/src/test/conf/testng.xml | 8 -
.../org/apache/tapestry5/func/BaseFuncTest.java | 36 +-
.../org/apache/tapestry5/func/FlowToSetTests.java | 8 +-
.../java/org/apache/tapestry5/func/FuncTest.java | 251 ++----
.../org/apache/tapestry5/func/InterleaveTests.java | 13 +-
.../java/org/apache/tapestry5/func/MapperTest.java | 68 +-
.../java/org/apache/tapestry5/func/RangeTests.java | 15 +-
.../tapestry5/func/StringPredicateTests.java | 4 +-
.../org/apache/tapestry5/func/TakeDropTests.java | 18 +-
.../java/org/apache/tapestry5/func/TupleTests.java | 8 +-
.../org/apache/tapestry5/func/ZippedFlowTests.java | 68 +-
.../src/test/{conf => resources}/testng.xml | 0
.../src/test/{conf => resources}/testng.xml | 0
.../services/CorsHandlerHelperImplTest.java | 175 ++--
.../services/CorsHttpServletRequestFilterTest.java | 2 +-
.../tapestry5/http/test/services/AppModule.java | 7 +
...TapestryIOCJUnit4ClassRunnerAfterClassTest.java | 63 --
...apestryIOCJUnit4ClassRunnerAfterMethodTest.java | 65 --
.../TapestryIOCJUnit4ClassRunnerModuleDefTest.java | 69 --
.../ioc/junit/TapestryIOCJUnit5AfterClassTest.java | 74 ++
.../junit/TapestryIOCJUnit5AfterMethodTest.java | 69 ++
.../ioc/junit/TapestryIOCJUnit5ModuleDefTest.java | 74 ++
.../src/test/{conf => resources}/testng.xml | 0
tapestry-jpa/build.gradle | 1 +
.../jpa/integration/app5/DummyEntityManager.java | 71 ++
.../app5/DummyEntityManagerFactory.java | 33 +
.../integration/app5/DummyPersistenceProvider.java | 11 +
.../src/test/{conf => resources}/testng.xml | 0
tapestry-json/src/test/conf/testng.xml | 8 -
.../test/groovy/json/specs/CoercionsSpec.groovy | 29 -
.../test/groovy/json/specs/JSONArraySpec.groovy | 639 -------------
.../groovy/json/specs/JSONCollectorsSpec.groovy | 101 ---
.../test/groovy/json/specs/JSONObjectSpec.groovy | 989 ---------------------
.../src/test/groovy/json/specs/JSONSpec.groovy | 36 -
.../org/apache/tapestry5/json/CoercionsTest.java | 44 +
.../org/apache/tapestry5/json/JSONArrayTest.java | 488 ++++++++++
.../apache/tapestry5/json/JSONCollectorsTest.java | 97 ++
.../org/apache/tapestry5/json/JSONObjectTest.java | 891 +++++++++++++++++++
.../java/org/apache/tapestry5/json/JSONTest.java | 53 ++
.../src/test/{conf => resources}/testng.xml | 0
.../src/test/groovy/MongoDBSpec.groovy | 2 +
.../src/test/{conf => resources}/testng.xml | 0
.../src/test/{conf => resources}/testng.xml | 0
.../src/test/{conf => resources}/testng.xml | 0
.../src/test/{conf => resources}/testng.xml | 0
.../services/web/WebResourcesTest.java | 1 +
tapestry5-annotations/src/test/conf/testng.xml | 21 -
54 files changed, 2476 insertions(+), 2648 deletions(-)
diff --git a/plastic/src/test/conf/testng.xml b/plastic/src/test/conf/testng.xml
deleted file mode 100644
index f8e52b4e2..000000000
--- a/plastic/src/test/conf/testng.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
-<!-- This file is only needed for compatibility with the Maven build, it is not needed for the Gradle build -->
-<suite name="Plastic" annotations="1.5" verbose="2">
- <test name="Placeholder -- Maven Build / TestNG Can't Run The Spock Tests">
- </test>
-</suite>
diff --git a/tapestry-beanvalidator/src/test/conf/testng.xml b/tapestry-beanvalidator/src/test/resources/testng.xml
similarity index 100%
rename from tapestry-beanvalidator/src/test/conf/testng.xml
rename to tapestry-beanvalidator/src/test/resources/testng.xml
diff --git a/tapestry-clojure/src/test/java/org/apache/tapestry5/clojure/tests/TestModule.java b/tapestry-clojure/src/test/java/org/apache/tapestry5/clojure/tests/TestModule.java
index 2697ddc4b..0318e5add 100644
--- a/tapestry-clojure/src/test/java/org/apache/tapestry5/clojure/tests/TestModule.java
+++ b/tapestry-clojure/src/test/java/org/apache/tapestry5/clojure/tests/TestModule.java
@@ -1,9 +1,21 @@
package org.apache.tapestry5.clojure.tests;
import org.apache.tapestry5.clojure.ClojureBuilder;
+import org.apache.tapestry5.commons.MappedConfiguration;
+import org.apache.tapestry5.http.internal.TapestryHttpInternalConstants;
+import org.apache.tapestry5.ioc.annotations.Contribute;
+import org.apache.tapestry5.ioc.services.ApplicationDefaults;
+import org.apache.tapestry5.ioc.services.SymbolProvider;
public class TestModule
{
+ @ApplicationDefaults
+ @Contribute(SymbolProvider.class)
+ public static void contributeTestApplicationDefaults(MappedConfiguration<String, String> conf)
+ {
+ conf.add(TapestryHttpInternalConstants.TAPESTRY_APP_PACKAGE_PARAM, "test");
+ }
+
public static Fixture buildFixture(ClojureBuilder builder)
{
return builder.build(Fixture.class);
diff --git a/tapestry-core/src/test/groovy/org/apache/tapestry5/integration/app1/PartialTemplateRendererTests.groovy b/tapestry-core/src/test/groovy/org/apache/tapestry5/integration/app1/PartialTemplateRendererTests.groovy
index 5943a6928..a70c21e98 100644
--- a/tapestry-core/src/test/groovy/org/apache/tapestry5/integration/app1/PartialTemplateRendererTests.groovy
+++ b/tapestry-core/src/test/groovy/org/apache/tapestry5/integration/app1/PartialTemplateRendererTests.groovy
@@ -16,7 +16,6 @@ package org.apache.tapestry5.integration.app1
import org.apache.tapestry5.services.PartialTemplateRenderer;
import org.testng.annotations.Test
-import org.junit.Assert;
/**
* Tests the {@link PartialTemplateRenderer} service.
diff --git a/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/ComponentDependencyRegistryImplTest.java b/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/ComponentDependencyRegistryImplTest.java
index 8115652dc..6964d5444 100644
--- a/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/ComponentDependencyRegistryImplTest.java
+++ b/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/ComponentDependencyRegistryImplTest.java
@@ -14,9 +14,9 @@
package org.apache.tapestry5.internal.services;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
import java.io.File;
import java.net.MalformedURLException;
@@ -104,40 +104,41 @@ import org.testng.annotations.Test;
@SuppressWarnings("deprecation")
public class ComponentDependencyRegistryImplTest
{
-
+
private ComponentDependencyRegistryImpl componentDependencyRegistry;
-
+
private PageClassLoaderContextManager pageClassLoaderContextManager;
-
+
private ComponentClassResolver resolver;
-
+
private PlasticManager plasticManager;
-
+
private TemplateParser templateParser;
-
+
private ComponentTemplateLocator componentTemplateLocator;
-
+
@BeforeMethod
public void setup()
{
- assertFalse(
- String.format("During testing, %s shouldn't exist", ComponentDependencyRegistry.FILENAME),
- new File(ComponentDependencyRegistry.FILENAME).exists());
-
+ assertFalse(new File(ComponentDependencyRegistry.FILENAME).exists(), String.format(
+ "During testing, %s shouldn't exist", ComponentDependencyRegistry.FILENAME));
+
MockMappedConfiguration<String, URL> templateConfiguration = new MockMappedConfiguration<String, URL>();
TapestryModule.contributeTemplateParser(templateConfiguration);
- templateParser = new TemplateParserImpl(templateConfiguration.map, false, new QuietOperationTracker());
-
+ templateParser = new TemplateParserImpl(templateConfiguration.map, false,
+ new QuietOperationTracker());
+
final String rootFolder = "src/test/app1/";
final File folderFile = new File(rootFolder);
final Resource app1ContextFolderResource = new FileResource("/", folderFile);
-
- final PageTemplateLocator pageTemplateLocator = new PageTemplateLocator(app1ContextFolderResource, resolver, "");
+
+ final PageTemplateLocator pageTemplateLocator = new PageTemplateLocator(
+ app1ContextFolderResource, resolver, "");
final DefaultTemplateLocator defaultTemplateLocator = new DefaultTemplateLocator();
- componentTemplateLocator = new ComponentTemplateLocator()
+ componentTemplateLocator = new ComponentTemplateLocator()
{
@Override
- public Resource locateTemplate(ComponentModel model, Locale locale)
+ public Resource locateTemplate(ComponentModel model, Locale locale)
{
Resource resource = defaultTemplateLocator.locateTemplate(model, locale);
if (resource == null)
@@ -147,16 +148,16 @@ public class ComponentDependencyRegistryImplTest
return resource != null && resource.exists() ? resource : null;
}
};
-
+
resolver = EasyMock.createMock(ComponentClassResolver.class);
-
+
EasyMock.expect(resolver.resolvePageClassNameToPageName(EasyMock.anyString()))
.andAnswer(() -> {
String s = ((String) EasyMock.getCurrentArguments()[0]);
final String pageName = s.substring(s.lastIndexOf('.') + 1);
return pageName;
}).anyTimes();
-
+
expectResolveComponent(TextField.class);
expectResolveComponent(PasswordField.class);
expectResolveComponent(Border.class);
@@ -165,7 +166,7 @@ public class ComponentDependencyRegistryImplTest
expectResolveComponent(ActionLink.class);
expectResolveComponent(If.class);
expectResolveComponent(ErrorComponent.class);
- expectResolveComponent(EventLink.class);
+ expectResolveComponent(EventLink.class);
expectResolveComponent(Output.class);
expectResolveComponent(Delegate.class);
expectResolveComponent(TextOutput.class);
@@ -184,101 +185,105 @@ public class ComponentDependencyRegistryImplTest
expectResolveComponent(Glyphicon.class);
expectResolveComponent(SubclassWithImport.class);
expectResolveComponent(OutputRaw.class);
-
+
EasyMock.expect(resolver.resolveMixinTypeToClassName("textonlyondisabled"))
- .andReturn(TextOnlyOnDisabled.class.getName()).anyTimes();
+ .andReturn(TextOnlyOnDisabled.class.getName()).anyTimes();
EasyMock.expect(resolver.resolveMixinTypeToClassName("echovalue2"))
- .andReturn(EchoValue2.class.getName()).anyTimes();
+ .andReturn(EchoValue2.class.getName()).anyTimes();
EasyMock.expect(resolver.resolveMixinTypeToClassName("alttitledefault"))
- .andReturn(AltTitleDefault.class.getName()).anyTimes();
+ .andReturn(AltTitleDefault.class.getName()).anyTimes();
EasyMock.expect(resolver.resolveMixinTypeToClassName("formgroup"))
- .andReturn(FormGroup.class.getName()).anyTimes();
-
+ .andReturn(FormGroup.class.getName()).anyTimes();
+
EasyMock.expect(resolver.isPage(EasyMock.anyString())).andAnswer(() -> {
String string = (String) EasyMock.getCurrentArguments()[0];
return string.contains(".pages.");
}).anyTimes();
-
+
pageClassLoaderContextManager = EasyMock.createMock(PageClassLoaderContextManager.class);
plasticManager = EasyMock.createMock(PlasticManager.class);
EasyMock.expect(plasticManager.shouldInterceptClassLoading(EasyMock.anyString()))
- .andAnswer(() -> {
- String className = (String) EasyMock.getCurrentArguments()[0];
- return className.contains(".pages.") || className.contains(".mixins.") ||
- className.contains(".components.") || className.contains(".base.");
- }).anyTimes();
-
+ .andAnswer(() -> {
+ String className = (String) EasyMock.getCurrentArguments()[0];
+ return className.contains(".pages.") || className.contains(".mixins.")
+ || className.contains(".components.") || className.contains(".base.");
+ }).anyTimes();
+
componentDependencyRegistry = new ComponentDependencyRegistryImpl(
- pageClassLoaderContextManager, plasticManager, resolver, templateParser,
+ pageClassLoaderContextManager, plasticManager, resolver, templateParser,
componentTemplateLocator, ComponentDependencyRegistry.FILENAME, false);
EasyMock.replay(pageClassLoaderContextManager, plasticManager, resolver);
}
- private void expectResolveComponent(final Class<?> clasz) {
+ private void expectResolveComponent(final Class<?> clasz)
+ {
final String className = clasz.getName();
final java.lang.String simpleName = clasz.getSimpleName();
- EasyMock.expect(resolver.resolveComponentTypeToClassName(simpleName))
- .andReturn(className).anyTimes();
+ EasyMock.expect(resolver.resolveComponentTypeToClassName(simpleName)).andReturn(className)
+ .anyTimes();
EasyMock.expect(resolver.resolveComponentTypeToClassName(simpleName.toLowerCase()))
- .andReturn(className).anyTimes();
+ .andReturn(className).anyTimes();
EasyMock.expect(resolver.resolveComponentTypeToClassName(
simpleName.substring(0, 1).toLowerCase() + simpleName.substring(1)))
- .andReturn(className).anyTimes();
+ .andReturn(className).anyTimes();
}
-
+
private void configurePCCM(boolean merging)
{
EasyMock.reset(pageClassLoaderContextManager);
EasyMock.expect(pageClassLoaderContextManager.isMerging()).andReturn(merging).anyTimes();
EasyMock.replay(pageClassLoaderContextManager);
}
-
+
@Test(timeOut = 5000)
public void listen()
{
-
+
componentDependencyRegistry.setEnableEnsureClassIsAlreadyProcessed(false);
-
+
add("foo", "bar");
add("d", "a");
add("dd", "aa");
add("dd", "a");
add("dd", "a");
-
+
final List<String> resources = Arrays.asList("a", "aa", "none");
-
+
configurePCCM(true);
List<String> result = componentDependencyRegistry.listen(resources);
- assertEquals(0, result.size());
-
+ assertEquals(result.size(), 0);
+
configurePCCM(false);
result = componentDependencyRegistry.listen(resources);
Collections.sort(result);
assertEquals(result, Arrays.asList("d", "dd"));
assertEquals("bar", getDependencies("foo").iterator().next());
- assertEquals("foo", componentDependencyRegistry.getDependents("bar").iterator().next());
-
+ assertEquals("foo", componentDependencyRegistry.getDependents("bar").iterator().next());
+
configurePCCM(false);
result = componentDependencyRegistry.listen(Collections.emptyList());
assertEquals(result, Collections.emptyList());
assertEquals(componentDependencyRegistry.getDependents("bar").size(), 0);
assertEquals(getDependencies("foo").size(), 0);
-
+
}
-
+
private Set<String> getDependencies(String className)
{
Set<String> dependencies = new HashSet<>();
- dependencies.addAll(componentDependencyRegistry.getDependencies(className, DependencyType.USAGE));
- dependencies.addAll(componentDependencyRegistry.getDependencies(className, DependencyType.SUPERCLASS));
- dependencies.addAll(componentDependencyRegistry.getDependencies(className, DependencyType.INJECT_PAGE));
+ dependencies.addAll(
+ componentDependencyRegistry.getDependencies(className, DependencyType.USAGE));
+ dependencies.addAll(
+ componentDependencyRegistry.getDependencies(className, DependencyType.SUPERCLASS));
+ dependencies.addAll(
+ componentDependencyRegistry.getDependencies(className, DependencyType.INJECT_PAGE));
return Collections.unmodifiableSet(dependencies);
}
-
+
@Test
public void dependency_methods()
{
-
+
final String foo = "foo";
final String bar = "bar";
final String something = "something";
@@ -286,22 +291,18 @@ public class ComponentDependencyRegistryImplTest
final String fulano = "fulano";
final String beltrano = "beltrano";
final String sicrano = "sicrano";
-
+
componentDependencyRegistry.setEnableEnsureClassIsAlreadyProcessed(false);
-
- assertEquals(
- "getDependents() should never return null",
- Collections.emptySet(),
- getDependencies(foo));
-
- assertEquals(
- "getDependents() should never return null",
- Collections.emptySet(),
- componentDependencyRegistry.getDependents(foo));
+
+ assertEquals(getDependencies(foo), Collections.emptySet(),
+ "getDependents() should never return null");
+
+ assertEquals(componentDependencyRegistry.getDependents(foo), Collections.emptySet(),
+ "getDependents() should never return null");
// In Brazil, Fulano, Beltrano and Sicrano are the most used people
// placeholder names, in that order.
-
+
add(foo, bar);
add(something, fulano);
add(other, beltrano);
@@ -312,7 +313,7 @@ public class ComponentDependencyRegistryImplTest
add(beltrano, null);
add(beltrano, sicrano);
add(sicrano, null);
-
+
assertEquals(new HashSet<>(Arrays.asList(fulano, beltrano)), getDependencies(other));
assertEquals(new HashSet<>(Arrays.asList(fulano)), getDependencies(something));
assertEquals(new HashSet<>(Arrays.asList()), getDependencies(fulano));
@@ -320,15 +321,20 @@ public class ComponentDependencyRegistryImplTest
assertEquals(new HashSet<>(Arrays.asList()), getDependencies(bar));
assertEquals(new HashSet<>(Arrays.asList(sicrano)), getDependencies(beltrano));
- assertEquals(new HashSet<>(Arrays.asList(foo)), componentDependencyRegistry.getDependents(bar));
- assertEquals(new HashSet<>(Arrays.asList(other, something)), componentDependencyRegistry.getDependents(fulano));
- assertEquals(new HashSet<>(Arrays.asList()), componentDependencyRegistry.getDependents(foo));
- assertEquals(new HashSet<>(Arrays.asList(other)), componentDependencyRegistry.getDependents(beltrano));
- assertEquals(new HashSet<>(Arrays.asList(beltrano)), componentDependencyRegistry.getDependents(sicrano));
-
- assertEquals(new HashSet<>(Arrays.asList(bar, fulano, sicrano)),
+ assertEquals(new HashSet<>(Arrays.asList(foo)),
+ componentDependencyRegistry.getDependents(bar));
+ assertEquals(new HashSet<>(Arrays.asList(other, something)),
+ componentDependencyRegistry.getDependents(fulano));
+ assertEquals(new HashSet<>(Arrays.asList()),
+ componentDependencyRegistry.getDependents(foo));
+ assertEquals(new HashSet<>(Arrays.asList(other)),
+ componentDependencyRegistry.getDependents(beltrano));
+ assertEquals(new HashSet<>(Arrays.asList(beltrano)),
+ componentDependencyRegistry.getDependents(sicrano));
+
+ assertEquals(new HashSet<>(Arrays.asList(bar, fulano, sicrano)),
componentDependencyRegistry.getRootClasses());
-
+
assertTrue(componentDependencyRegistry.contains(foo));
assertTrue(componentDependencyRegistry.contains(bar));
assertTrue(componentDependencyRegistry.contains(other));
@@ -346,10 +352,10 @@ public class ComponentDependencyRegistryImplTest
assertTrue(componentDependencyRegistry.getClassNames().contains(beltrano));
assertTrue(componentDependencyRegistry.getClassNames().contains(sicrano));
assertFalse(componentDependencyRegistry.getClassNames().contains("blah"));
-
+
// Testing the clear method
componentDependencyRegistry.clear(beltrano);
-
+
assertEquals(new HashSet<>(Arrays.asList(fulano)), getDependencies(other));
assertEquals(new HashSet<>(Arrays.asList(fulano)), getDependencies(something));
assertEquals(new HashSet<>(Arrays.asList()), getDependencies(fulano));
@@ -357,14 +363,20 @@ public class ComponentDependencyRegistryImplTest
assertEquals(new HashSet<>(Arrays.asList()), getDependencies(bar));
assertEquals(new HashSet<>(Arrays.asList()), getDependencies(sicrano));
- assertEquals(new HashSet<>(Arrays.asList(foo)), componentDependencyRegistry.getDependents(bar));
- assertEquals(new HashSet<>(Arrays.asList(other, something)), componentDependencyRegistry.getDependents(fulano));
- assertEquals(new HashSet<>(Arrays.asList()), componentDependencyRegistry.getDependents(foo));
- assertEquals(new HashSet<>(Arrays.asList()), componentDependencyRegistry.getDependents(beltrano));
- assertEquals(new HashSet<>(Arrays.asList()), componentDependencyRegistry.getDependents(sicrano));
-
- assertEquals(new HashSet<>(Arrays.asList(bar, fulano, sicrano)), componentDependencyRegistry.getRootClasses());
-
+ assertEquals(new HashSet<>(Arrays.asList(foo)),
+ componentDependencyRegistry.getDependents(bar));
+ assertEquals(new HashSet<>(Arrays.asList(other, something)),
+ componentDependencyRegistry.getDependents(fulano));
+ assertEquals(new HashSet<>(Arrays.asList()),
+ componentDependencyRegistry.getDependents(foo));
+ assertEquals(new HashSet<>(Arrays.asList()),
+ componentDependencyRegistry.getDependents(beltrano));
+ assertEquals(new HashSet<>(Arrays.asList()),
+ componentDependencyRegistry.getDependents(sicrano));
+
+ assertEquals(new HashSet<>(Arrays.asList(bar, fulano, sicrano)),
+ componentDependencyRegistry.getRootClasses());
+
assertTrue(componentDependencyRegistry.contains(foo));
assertTrue(componentDependencyRegistry.contains(bar));
assertTrue(componentDependencyRegistry.contains(other));
@@ -382,13 +394,13 @@ public class ComponentDependencyRegistryImplTest
assertTrue(componentDependencyRegistry.getClassNames().contains(sicrano));
assertFalse(componentDependencyRegistry.getClassNames().contains(beltrano));
assertFalse(componentDependencyRegistry.getClassNames().contains("blah"));
-
+
}
-
+
@Test
public void get_all_non_page_dependencies()
{
-
+
final String page = "page";
final String className = "root";
final String superclass = "superclass";
@@ -397,14 +409,14 @@ public class ComponentDependencyRegistryImplTest
expectedAllNonPageDependencies.add(d);
add(c, d, DependencyType.USAGE);
};
-
+
componentDependencyRegistry.setEnableEnsureClassIsAlreadyProcessed(false);
-
+
add(className, page, DependencyType.INJECT_PAGE);
-
+
add(className, superclass, DependencyType.SUPERCLASS);
expectedAllNonPageDependencies.add(superclass);
-
+
add.accept(className, "child1");
add.accept(className, "child2");
add.accept("child1", "child1.1");
@@ -412,155 +424,152 @@ public class ComponentDependencyRegistryImplTest
add.accept("child2.1", className);
add.accept(superclass, "child2.1");
add.accept(superclass, "superclassDependency");
-
+
expectedAllNonPageDependencies.remove(className);
- final Set<String> allNonPageDependencies = componentDependencyRegistry.getAllNonPageDependencies(className);
+ final Set<String> allNonPageDependencies = componentDependencyRegistry
+ .getAllNonPageDependencies(className);
assertFalse(allNonPageDependencies.contains(className));
assertEquals(expectedAllNonPageDependencies, allNonPageDependencies);
-
+
}
-
+
@Test
public void register()
{
-
+
componentDependencyRegistry.setEnableEnsureClassIsAlreadyProcessed(true);
-
+
componentDependencyRegistry.clear();
-
+
// Dynamic dependency definitions
componentDependencyRegistry.register(PropertyDisplay.class);
assertDependencies(PropertyDisplay.class, AbstractPropertyOutput.class);
componentDependencyRegistry.register(PropertyEditor.class);
assertDependencies(PropertyEditor.class);
-
+
// Superclass
componentDependencyRegistry.register(EventLink.class);
// Superclass, recursively
assertDependencies(AbstractComponentEventLink.class, AbstractLink.class);
- assertDependencies(AbstractLink.class);
-
- // @InjectComponent
+ assertDependencies(AbstractLink.class);
+
+ // @InjectComponent
// Components declared in templates
componentDependencyRegistry.register(AlertsDemo.class);
assertDependencies(AlertsDemo.class, Zone.class, // @InjectComponent
// Components declared in template
- Border.class, BeanEditForm.class, Zone.class, If.class,
- ActionLink.class, ErrorComponent.class, EventLink.class);
-
+ Border.class, BeanEditForm.class, Zone.class, If.class, ActionLink.class,
+ ErrorComponent.class, EventLink.class);
+
// Mixins defined in in templates (t:mixins="...").
componentDependencyRegistry.register(MixinParameterDefault.class);
assertDependencies(MixinParameterDefault.class, AltTitleDefault.class, // Mixin
ActionLink.class, Border.class); // Components declared in template);
-
+
// @Component, type() not defined
componentDependencyRegistry.register(OuterAny.class);
assertDependencies(OuterAny.class, Any.class);
-
+
// @Component, type() defined
componentDependencyRegistry.register(AtComponentType.class);
assertDependencies(AtComponentType.class, TextField.class, Border.class);
// @Mixin, type() not defined
componentDependencyRegistry.register(AbstractTextField.class);
- assertDependencies(AbstractTextField.class,
- RenderDisabled.class, AbstractField.class);
+ assertDependencies(AbstractTextField.class, RenderDisabled.class, AbstractField.class);
// @Mixin, type() defined
componentDependencyRegistry.register(TextOnlyOnDisabledTextField.class);
- assertDependencies(TextOnlyOnDisabledTextField.class,
- TextOnlyOnDisabled.class, TextField.class);
-
+ assertDependencies(TextOnlyOnDisabledTextField.class, TextOnlyOnDisabled.class,
+ TextField.class);
+
// @MixinClasses and @Mixins
componentDependencyRegistry.register(InstanceMixinDependencies.class);
- assertDependencies(InstanceMixinDependencies.class,
- EchoValue.class, EchoValue2.class, TextField.class);
+ assertDependencies(InstanceMixinDependencies.class, EchoValue.class, EchoValue2.class,
+ TextField.class);
// Templates with <t:extension-point>
componentDependencyRegistry.register(BaseLayoutPage.class);
- assertDependencies(BaseLayoutPage.class,
- Delegate.class, SubclassWithImport.class, Border.class);
-
+ assertDependencies(BaseLayoutPage.class, Delegate.class, SubclassWithImport.class,
+ Border.class);
+
// Templates with <t:replace>
componentDependencyRegistry.register(SubclassWithImport.class);
- assertDependencies(SubclassWithImport.class,
- OutputRaw.class, SuperclassWithImport.class, Loop.class);
-
+ assertDependencies(SubclassWithImport.class, OutputRaw.class, SuperclassWithImport.class,
+ Loop.class);
+
// Circular dependency: BlockHolder <-> BlockCaller
componentDependencyRegistry.register(BlockHolder.class);
- assertDependencies(BlockHolder.class,
- BlockCaller.class, Loop.class, ActionLink.class);
- assertDependencies(BlockCaller.class,
- BlockHolder.class, Border.class, PageLink.class, Delegate.class);
-
+ assertDependencies(BlockHolder.class, BlockCaller.class, Loop.class, ActionLink.class);
+ assertDependencies(BlockCaller.class, BlockHolder.class, Border.class, PageLink.class,
+ Delegate.class);
+
}
-
- private void assertDependencies(Class<?> clasz, Class<?>... dependencies) {
- assertEquals(
- setOf(dependencies),
- getDependencies(clasz.getName()));
+
+ private void assertDependencies(Class<?> clasz, Class<?>... dependencies)
+ {
+ assertEquals(setOf(dependencies), getDependencies(clasz.getName()));
}
- private static Set<String> setOf(Class<?> ... classes)
+ private static Set<String> setOf(Class<?>... classes)
{
- return Arrays.asList(classes).stream()
- .map(Class::getName)
- .collect(Collectors.toSet());
+ return Arrays.asList(classes).stream().map(Class::getName).collect(Collectors.toSet());
}
private void add(String component, String dependency)
{
add(component, dependency, DependencyType.USAGE);
}
-
+
private void add(String component, String dependency, DependencyType type)
{
componentDependencyRegistry.add(component, dependency, type, true);
}
@SuppressWarnings("hiding")
- private static final class MockMappedConfiguration<String, URL> implements MappedConfiguration<String, URL>
+ private static final class MockMappedConfiguration<String, URL>
+ implements MappedConfiguration<String, URL>
{
-
+
private final Map<String, URL> map = new HashMap<>();
@Override
- public void add(String key, URL value)
+ public void add(String key, URL value)
{
map.put(key, value);
}
@Override
- public void override(String key, URL value)
+ public void override(String key, URL value)
{
throw new UnsupportedOperationException();
}
@Override
- public void addInstance(String key, Class<? extends URL> clazz)
+ public void addInstance(String key, Class<? extends URL> clazz)
{
throw new UnsupportedOperationException();
}
@Override
- public void overrideInstance(String key, Class<? extends URL> clazz)
+ public void overrideInstance(String key, Class<? extends URL> clazz)
{
- throw new UnsupportedOperationException();
+ throw new UnsupportedOperationException();
}
-
+
}
-
+
final private static class FileResource extends AbstractResource
{
-
+
final private File file;
-
+
final private String path;
- public FileResource(String path, File file)
+ public FileResource(String path, File file)
{
super(path);
this.file = file;
@@ -568,30 +577,31 @@ public class ComponentDependencyRegistryImplTest
}
@Override
- public java.net.URL toURL()
+ public java.net.URL toURL()
{
- try
+ try
{
final File actualFile = new File(file, path);
return actualFile.exists() ? actualFile.toURL() : null;
- } catch (MalformedURLException e)
+ }
+ catch (MalformedURLException e)
{
throw new RuntimeException(e);
}
}
@Override
- protected Resource newResource(String path)
+ protected Resource newResource(String path)
{
return new FileResource(path, file);
}
@Override
- public String toString()
+ public String toString()
{
return "FileResource [file=" + file + "/" + path + "]";
}
-
+
}
-
+
}
diff --git a/tapestry-core/src/test/conf/testng-limited.xml b/tapestry-core/src/test/resources/testng-limited.xml
similarity index 100%
rename from tapestry-core/src/test/conf/testng-limited.xml
rename to tapestry-core/src/test/resources/testng-limited.xml
diff --git a/tapestry-core/src/test/conf/testng.xml b/tapestry-core/src/test/resources/testng.xml
similarity index 55%
rename from tapestry-core/src/test/conf/testng.xml
rename to tapestry-core/src/test/resources/testng.xml
index e30025f49..e7ffac3f7 100644
--- a/tapestry-core/src/test/conf/testng.xml
+++ b/tapestry-core/src/test/resources/testng.xml
@@ -7,119 +7,160 @@
<!-- The suite may no longer be run in parallel, because of some tricky issues related to locking of class loaders. Running
in parallel causes thread deadlocks, when unmanaged tests run at the same time as Selenium-based integration tests. See TAPESTRY-2561. -->
-<suite name="Tapestry Core" annotations="1.5" verbose="2">
- <test name="Component Unit Tests" enabled="true">
+<suite
+ name="Tapestry Core"
+ annotations="1.5"
+ verbose="2">
+ <test
+ name="Component Unit Tests"
+ enabled="true">
<packages>
- <package name="org.apache.tapestry5.pagetester"/>
- <package name="org.apache.tapestry5.integration.pagelevel"/>
- <package name="org.apache.tapestry5.corelib.base"/>
- <package name="org.apache.tapestry5.corelib.components"/>
- <package name="org.apache.tapestry5.corelib.mixins"/>
- <package name="org.apache.tapestry5.corelib.internal"/>
+ <package name="org.apache.tapestry5.pagetester" />
+ <package name="org.apache.tapestry5.integration.pagelevel" />
+ <package name="org.apache.tapestry5.corelib.base" />
+ <package name="org.apache.tapestry5.corelib.components" />
+ <package name="org.apache.tapestry5.corelib.mixins" />
+ <package name="org.apache.tapestry5.corelib.internal" />
</packages>
</test>
- <test name="Service Unit Tests" enabled="true">
+ <test
+ name="Service Unit Tests"
+ enabled="true">
<packages>
- <package name="org.apache.tapestry5.root"/>
- <package name="org.apache.tapestry5.dom"/>
- <package name="org.apache.tapestry5.runtime"/>
- <package name="org.apache.tapestry5.services"/>
- <package name="org.apache.tapestry5.services.javascript"/>
- <package name="org.apache.tapestry5.util"/>
- <package name="org.apache.tapestry5.validator"/>
- <package name="org.apache.tapestry5.internal"/>
- <package name="org.apache.tapestry5.internal.beaneditor"/>
- <package name="org.apache.tapestry5.internal.bindings"/>
- <package name="org.apache.tapestry5.internal.grid"/>
- <package name="org.apache.tapestry5.internal.model"/>
- <package name="org.apache.tapestry5.internal.pageload"/>
- <package name="org.apache.tapestry5.internal.services"/>
- <package name="org.apache.tapestry5.internal.services.assets"/>
- <package name="org.apache.tapestry5.internal.services.messages"/>
- <package name="org.apache.tapestry5.internal.services.meta"/>
- <package name="org.apache.tapestry5.internal.services.templates"/>
- <package name="org.apache.tapestry5.internal.structure"/>
- <package name="org.apache.tapestry5.internal.test"/>
- <package name="org.apache.tapestry5.internal.transform"/>
- <package name="org.apache.tapestry5.internal.translator"/>
- <package name="org.apache.tapestry5.internal.util"/>
- <package name="org.apache.tapestry5.internal.services.ajax"/>
+ <package name="org.apache.tapestry5.root" />
+ <package name="org.apache.tapestry5.dom" />
+ <package name="org.apache.tapestry5.runtime" />
+ <package name="org.apache.tapestry5.services" />
+ <package name="org.apache.tapestry5.services.javascript" />
+ <package name="org.apache.tapestry5.util" />
+ <package name="org.apache.tapestry5.validator" />
+ <package name="org.apache.tapestry5.internal" />
+ <package name="org.apache.tapestry5.internal.beaneditor" />
+ <package name="org.apache.tapestry5.internal.bindings" />
+ <package name="org.apache.tapestry5.internal.grid" />
+ <package name="org.apache.tapestry5.internal.model" />
+ <package name="org.apache.tapestry5.internal.pageload" />
+ <package name="org.apache.tapestry5.internal.services" />
+ <package name="org.apache.tapestry5.internal.services.assets" />
+ <package name="org.apache.tapestry5.internal.services.messages" />
+ <package name="org.apache.tapestry5.internal.services.meta" />
+ <package name="org.apache.tapestry5.internal.services.templates" />
+ <package name="org.apache.tapestry5.internal.structure" />
+ <package name="org.apache.tapestry5.internal.test" />
+ <package name="org.apache.tapestry5.internal.transform" />
+ <package name="org.apache.tapestry5.internal.translator" />
+ <package name="org.apache.tapestry5.internal.util" />
+ <package name="org.apache.tapestry5.internal.services.ajax" />
</packages>
</test>
<!-- We break these out by which of the test applications they apply to. We have a bunch. -->
- <test name="Core Integration Tests" enabled="true">
- <parameter name="tapestry.web-app-folder" value="src/test/app1"/>
+ <test
+ name="Core Integration Tests"
+ enabled="true">
+ <parameter
+ name="tapestry.web-app-folder"
+ value="src/test/app1" />
<packages>
- <package name="org.apache.tapestry5.integration.app1"/>
+ <package name="org.apache.tapestry5.integration.app1" />
</packages>
</test>
- <test name="Additional Integration Tests" enabled="true">
- <parameter name="tapestry.web-app-folder" value="src/test/app3"/>
+ <test
+ name="Additional Integration Tests"
+ enabled="true">
+ <parameter
+ name="tapestry.web-app-folder"
+ value="src/test/app3" />
<packages>
- <package name="org.apache.tapestry5.integration.app3"/>
+ <package name="org.apache.tapestry5.integration.app3" />
</packages>
</test>
- <test name="Live Reload Tests" enabled="true">
+ <test
+ name="Live Reload Tests"
+ enabled="true">
<packages>
- <package name="org.apache.tapestry5.integration.reload"/>
+ <package name="org.apache.tapestry5.integration.reload" />
</packages>
</test>
- <test name="LinkTransformer Tests" enabled="true">
- <parameter name="tapestry.web-app-folder" value="src/test/linktrans"/>
+ <test
+ name="LinkTransformer Tests"
+ enabled="true">
+ <parameter
+ name="tapestry.web-app-folder"
+ value="src/test/linktrans" />
<packages>
- <package name="org.apache.tapestry5.integration.linktrans"/>
+ <package name="org.apache.tapestry5.integration.linktrans" />
</packages>
</test>
- <test name="App Skinning and Misc. Tests" enabled="true">
+ <test
+ name="App Skinning and Misc. Tests"
+ enabled="true">
<packages>
- <package name="org.apache.tapestry5.integration.app5"/>
+ <package name="org.apache.tapestry5.integration.app5" />
</packages>
</test>
- <test name="Bootstrap 4 related Tests" enabled="true">
+ <test
+ name="Bootstrap 4 related Tests"
+ enabled="true">
<packages>
- <package name="org.apache.tapestry5.integration.app7"/>
+ <package name="org.apache.tapestry5.integration.app7" />
</packages>
</test>
- <test name="Components Param Symbols Tests" enabled="true">
- <parameter name="tapestry.web-app-folder" value="src/test/symbolparam"/>
+ <test
+ name="Components Param Symbols Tests"
+ enabled="true">
+ <parameter
+ name="tapestry.web-app-folder"
+ value="src/test/symbolparam" />
<packages>
- <package name="org.apache.tapestry5.integration.symbolparam"/>
+ <package name="org.apache.tapestry5.integration.symbolparam" />
</packages>
</test>
- <test name="AppFolder Tests" enabled="true">
+ <test
+ name="AppFolder Tests"
+ enabled="true">
<packages>
- <package name="org.apache.tapestry5.integration.appfolder"/>
+ <package name="org.apache.tapestry5.integration.appfolder" />
</packages>
</test>
- <test name="PageTester Tests" enabled="true">
+ <test
+ name="PageTester Tests"
+ enabled="true">
<packages>
- <package name="org.apache.tapestry5.integration.pagetester"/>
+ <package name="org.apache.tapestry5.integration.pagetester" />
</packages>
</test>
- <test name="Activation Context Tests" enabled="true">
- <parameter name="tapestry.web-app-folder" value="src/test/activationctx"/>
+ <test
+ name="Activation Context Tests"
+ enabled="true">
+ <parameter
+ name="tapestry.web-app-folder"
+ value="src/test/activationctx" />
<packages>
- <package name="org.apache.tapestry5.integration.activationctx"/>
+ <package name="org.apache.tapestry5.integration.activationctx" />
</packages>
</test>
- <test name="Activation Context Tests 2 old behavior" enabled="true">
- <parameter name="tapestry.web-app-folder" value="src/test/activationctx2"/>
+ <test
+ name="Activation Context Tests 2 old behavior"
+ enabled="true">
+ <parameter
+ name="tapestry.web-app-folder"
+ value="src/test/activationctx2" />
<packages>
- <package name="org.apache.tapestry5.integration.activationctx2"/>
+ <package name="org.apache.tapestry5.integration.activationctx2" />
</packages>
</test>
diff --git a/tapestry-func/src/test/conf/testng.xml b/tapestry-func/src/test/conf/testng.xml
deleted file mode 100644
index 0a06c77d9..000000000
--- a/tapestry-func/src/test/conf/testng.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
-<suite name="Tapestry Func">
- <test name="Functional Programming Library">
- <packages>
- <package name="org.apache.tapestry5.func"/>
- </packages>
- </test>
-</suite>
diff --git a/tapestry-func/src/test/java/org/apache/tapestry5/func/BaseFuncTest.java b/tapestry-func/src/test/java/org/apache/tapestry5/func/BaseFuncTest.java
index bed7e2fd3..680f32820 100644
--- a/tapestry-func/src/test/java/org/apache/tapestry5/func/BaseFuncTest.java
+++ b/tapestry-func/src/test/java/org/apache/tapestry5/func/BaseFuncTest.java
@@ -1,4 +1,4 @@
-// Copyright 2010 The Apache Software Foundation
+// Copyright 2010, 2025 The Apache Software Foundation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -17,37 +17,16 @@ package org.apache.tapestry5.func;
import java.util.Arrays;
import java.util.List;
-import org.testng.Assert;
+import static org.junit.jupiter.api.Assertions.assertEquals;
-public class BaseFuncTest extends Assert
+public class BaseFuncTest
{
- protected Mapper<String, Integer> stringToLength = new Mapper<String, Integer>()
- {
- @Override
- public Integer map(String input)
- {
- return input.length();
- }
- };
+ protected Mapper<String, Integer> stringToLength = String::length;
- protected Mapper<Integer, Boolean> toEven = new Mapper<Integer, Boolean>()
- {
- @Override
- public Boolean map(Integer input)
- {
- return evenp.accept(input);
- }
- };
+ protected Mapper<Integer, Boolean> toEven = input -> this.evenp.accept(input);
- protected Predicate<Number> evenp = new Predicate<Number>()
- {
- @Override
- public boolean accept(Number object)
- {
- return object.longValue() % 2 == 0;
- };
- };
+ protected Predicate<Number> evenp = object -> object.longValue() % 2 == 0;
protected Flow<Integer> filteredEmpty = F.flow(1, 3, 5, 7).filter(evenp);
@@ -58,12 +37,11 @@ public class BaseFuncTest extends Assert
protected <T> void assertListsEquals(List<T> actual, T... expected)
{
- assertEquals(actual, Arrays.asList(expected));
+ assertEquals(Arrays.asList(expected), actual);
}
protected void unreachable()
{
throw new RuntimeException("Should not be reachable.");
}
-
}
diff --git a/tapestry-func/src/test/java/org/apache/tapestry5/func/FlowToSetTests.java b/tapestry-func/src/test/java/org/apache/tapestry5/func/FlowToSetTests.java
index 54b98541c..890e34198 100644
--- a/tapestry-func/src/test/java/org/apache/tapestry5/func/FlowToSetTests.java
+++ b/tapestry-func/src/test/java/org/apache/tapestry5/func/FlowToSetTests.java
@@ -1,4 +1,4 @@
-// Copyright 2010 The Apache Software Foundation
+// Copyright 2010, 2025 The Apache Software Foundation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -18,14 +18,16 @@ import java.util.Arrays;
import java.util.Collections;
import java.util.Set;
-import org.testng.annotations.Test;
+import org.junit.jupiter.api.Test;
+import static org.junit.jupiter.api.Assertions.assertSame;
+import static org.junit.jupiter.api.Assertions.assertTrue;
public class FlowToSetTests extends BaseFuncTest
{
@Test
public void empty_flow_to_set()
{
- assertSame(F.emptyFlow().toSet(), Collections.EMPTY_SET);
+ assertSame(Collections.emptySet(), F.emptyFlow().toSet());
}
@Test
diff --git a/tapestry-func/src/test/java/org/apache/tapestry5/func/FuncTest.java b/tapestry-func/src/test/java/org/apache/tapestry5/func/FuncTest.java
index 8e9ed9235..07c49c1c3 100644
--- a/tapestry-func/src/test/java/org/apache/tapestry5/func/FuncTest.java
+++ b/tapestry-func/src/test/java/org/apache/tapestry5/func/FuncTest.java
@@ -1,4 +1,4 @@
-// Copyright 2010, 2011 The Apache Software Foundation
+// Copyright 2010, 2011, 2025 The Apache Software Foundation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -21,7 +21,13 @@ import java.util.Iterator;
import java.util.List;
import java.util.Locale;
-import org.testng.annotations.Test;
+import org.junit.jupiter.api.Test;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertSame;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
public class FuncTest extends BaseFuncTest
{
@@ -44,11 +50,11 @@ public class FuncTest extends BaseFuncTest
@Test
public void map_empty_collection_is_the_empty_list()
{
- List<String> source = Arrays.asList();
+ List<String> source = Collections.emptyList();
List<Integer> lengths = F.flow(source).map(stringToLength).toList();
- assertSame(lengths, Collections.EMPTY_LIST);
+ assertSame(Collections.emptyList(), lengths);
}
@Test
@@ -58,21 +64,16 @@ public class FuncTest extends BaseFuncTest
final StringBuffer buffer = new StringBuffer();
- Worker<String> worker = new Worker<String>()
- {
- @Override
- public void work(String value)
- {
- if (buffer.length() > 0)
- buffer.append(' ');
-
- buffer.append(value);
- }
+ Worker<String> worker = value -> {
+ if (buffer.length() > 0)
+ buffer.append(' ');
+
+ buffer.append(value);
};
F.flow(source).each(worker);
- assertEquals(buffer.toString(), "Mary had a little lamb");
+ assertEquals("Mary had a little lamb", buffer.toString());
}
@Test
@@ -82,28 +83,16 @@ public class FuncTest extends BaseFuncTest
final StringBuffer buffer = new StringBuffer();
- Worker<String> worker = new Worker<String>()
- {
- @Override
- public void work(String value)
- {
- if (buffer.length() > 0)
- buffer.append(' ');
-
- buffer.append(value);
- }
+ Worker<String> worker = value -> {
+ if (buffer.length() > 0)
+ buffer.append(' ');
+
+ buffer.append(value);
};
- F.flow(source).filter(new Predicate<String>()
- {
- @Override
- public boolean accept(String object)
- {
- return object.contains("a");
- }
- }).each(worker);
+ F.flow(source).filter(object -> object.contains("a")).each(worker);
- assertEquals(buffer.toString(), "Mary had a lamb");
+ assertEquals("Mary had a lamb", buffer.toString());
}
@Test
@@ -113,21 +102,16 @@ public class FuncTest extends BaseFuncTest
final StringBuffer buffer = new StringBuffer();
- Worker<String> worker = new Worker<String>()
- {
- @Override
- public void work(String value)
- {
- if (buffer.length() > 0)
- buffer.append(' ');
-
- buffer.append(value);
- }
+ Worker<String> worker = value -> {
+ if (buffer.length() > 0)
+ buffer.append(' ');
+
+ buffer.append(value);
};
- assertSame(flow.each(worker), flow);
+ assertSame(flow, flow.each(worker));
- assertEquals(buffer.toString(), "Mary had a little lamb");
+ assertEquals("Mary had a little lamb", buffer.toString());
}
@Test
@@ -135,32 +119,22 @@ public class FuncTest extends BaseFuncTest
{
final StringBuffer buffer = new StringBuffer();
- Worker<String> appendWorker = new Worker<String>()
- {
- @Override
- public void work(String value)
- {
- if (buffer.length() > 0)
- buffer.append(' ');
-
- buffer.append(value);
- }
+ Worker<String> appendWorker = value -> {
+ if (buffer.length() > 0)
+ buffer.append(' ');
+
+ buffer.append(value);
};
- Worker<String> appendLength = new Worker<String>()
- {
- @Override
- public void work(String value)
- {
- buffer.append('(');
- buffer.append(value.length());
- buffer.append(')');
- }
+ Worker<String> appendLength = value -> {
+ buffer.append('(');
+ buffer.append(value.length());
+ buffer.append(')');
};
F.flow("Mary", "had", "a", "little", "lamb").each(F.combine(appendWorker, appendLength));
- assertEquals(buffer.toString(), "Mary(4) had(3) a(1) little(6) lamb(4)");
+ assertEquals("Mary(4) had(3) a(1) little(6) lamb(4)", buffer.toString());
}
@Test
@@ -204,7 +178,7 @@ public class FuncTest extends BaseFuncTest
List<Integer> output = F.flow(input).filter(evenp).toList();
- assertSame(output, Collections.EMPTY_LIST);
+ assertSame(Collections.emptyList(), output);
}
@Test
@@ -272,11 +246,11 @@ public class FuncTest extends BaseFuncTest
Predicate<String> isNull = F.isNull();
Predicate<String> isNotNull = F.notNull();
- assertEquals(isNull.accept(null), true);
- assertEquals(isNotNull.accept(null), false);
+ assertTrue(isNull.accept(null));
+ assertFalse(isNotNull.accept(null));
- assertEquals(isNull.accept("foo"), false);
- assertEquals(isNotNull.accept("bar"), true);
+ assertFalse(isNull.accept("foo"));
+ assertTrue(isNotNull.accept("bar"));
}
@Test
@@ -285,7 +259,7 @@ public class FuncTest extends BaseFuncTest
int total = F.flow(F.flow("Mary", "had", "a", "little", "lamb").map(stringToLength).toList()).reduce(
F.SUM_INTS, 0);
- assertEquals(total, 18);
+ assertEquals(18, total);
}
@Test
@@ -293,7 +267,7 @@ public class FuncTest extends BaseFuncTest
{
int total = F.flow("Mary", "had", "a", "little", "lamb").map(stringToLength).reduce(F.SUM_INTS, 0);
- assertEquals(total, 18);
+ assertEquals(18, total);
}
@Test
@@ -301,11 +275,11 @@ public class FuncTest extends BaseFuncTest
{
Flow<Integer> empty = F.flow();
- assertSame(empty.reverse(), empty);
+ assertSame(empty, empty.reverse());
Flow<Integer> one = F.flow(1);
- assertSame(one.reverse(), one);
+ assertSame(one, one.reverse());
}
@Test
@@ -324,7 +298,7 @@ public class FuncTest extends BaseFuncTest
Flow<Integer> empty = F.flow();
Flow<Integer> flow = F.flow(1, 2, 3);
- assertSame(empty.concat(flow), flow);
+ assertSame(flow, empty.concat(flow));
}
@Test
@@ -358,46 +332,32 @@ public class FuncTest extends BaseFuncTest
{
Flow<String> zero = F.flow();
- Comparator<String> comparator = new Comparator<String>()
- {
- @Override
- public int compare(String o1, String o2)
- {
- return o1.length() - o2.length();
- }
- };
+ Comparator<String> comparator = (o1, o2) -> o1.length() - o2.length();
- assertSame(zero.sort(), zero);
- assertSame(zero.sort(comparator), zero);
+ assertSame(zero, zero.sort());
+ assertSame(zero, zero.sort(comparator));
Flow<String> one = F.flow("Hello");
- assertSame(one.sort(), one);
- assertSame(one.sort(comparator), one);
+ assertSame(one, one.sort());
+ assertSame(one, one.sort(comparator));
}
@Test
public void sort_using_explicit_comparator()
{
Flow<String> flow = F.flow("a", "eeeee", "ccc", "bb", "dddd");
- Comparator<String> comparator = new Comparator<String>()
- {
- @Override
- public int compare(String o1, String o2)
- {
- return o1.length() - o2.length();
- }
- };
+ Comparator<String> comparator = (o1, o2) -> o1.length() - o2.length();
assertFlowValues(flow.sort(comparator), "a", "bb", "ccc", "dddd", "eeeee");
}
- @Test(expectedExceptions = ClassCastException.class)
+ @Test
public void unable_to_sort_a_flow_of_non_comparables()
{
Flow<Locale> flow = F.flow(Locale.ENGLISH, Locale.FRANCE);
- flow.sort();
+ assertThrows(ClassCastException.class, flow::sort);
}
@Test
@@ -412,19 +372,23 @@ public class FuncTest extends BaseFuncTest
total += i;
}
- assertEquals(total, 16);
+ assertEquals(16, total);
}
@Test
public void first_of_non_empty_flow()
{
- assertEquals(F.flow("Mary", "had", "a", "little", "lamb").first(), "Mary");
+ String first = F.flow("Mary", "had", "a", "little", "lamb").first();
+
+ assertEquals("Mary", first);
}
@Test
public void rest_of_non_empty_flow()
{
- assertFlowValues(F.flow("Mary", "had", "a", "little", "lamb").rest(), "had", "a", "little", "lamb");
+ Flow<String> rest = F.flow("Mary", "had", "a", "little", "lamb").rest();
+
+ assertFlowValues(rest, "had", "a", "little", "lamb");
}
@Test
@@ -451,7 +415,7 @@ public class FuncTest extends BaseFuncTest
public void list_of_empty_flow_is_empty()
{
assertTrue(filteredEmpty.isEmpty());
- assertSame(filteredEmpty.toList(), Collections.EMPTY_LIST);
+ assertSame(Collections.emptyList(), filteredEmpty.toList());
}
@Test
@@ -459,16 +423,11 @@ public class FuncTest extends BaseFuncTest
{
assertSame(filteredEmpty.reverse(), F.EMPTY_FLOW);
assertSame(filteredEmpty.sort(), F.EMPTY_FLOW);
- assertSame(filteredEmpty.sort(new Comparator<Integer>()
- {
- @Override
- public int compare(Integer o1, Integer o2)
- {
- unreachable();
+ assertSame(F.EMPTY_FLOW, filteredEmpty.sort((o1, o2) -> {
+ unreachable();
- return 0;
- }
- }), F.EMPTY_FLOW);
+ return 0;
+ }));
}
@Test
@@ -483,7 +442,7 @@ public class FuncTest extends BaseFuncTest
assertFlowValues(filteredEmpty.append(1, 2, 3).reverse(), 3, 2, 1);
}
- @Test(expectedExceptions = UnsupportedOperationException.class)
+ @Test
public void remove_on_flow_iterator_is_not_supported()
{
Flow<Integer> flow = F.flow(1, 2, 3).filter(evenp);
@@ -493,7 +452,7 @@ public class FuncTest extends BaseFuncTest
assertTrue(it.hasNext());
assertEquals(it.next(), Integer.valueOf(2));
- it.remove();
+ assertThrows(UnsupportedOperationException.class, it::remove);
}
@Test
@@ -501,22 +460,10 @@ public class FuncTest extends BaseFuncTest
{
Flow<String> flow = F.flow("Mary", "had", "a", "little", "lamb");
- List<String> result = flow.filter(new Predicate<String>()
- {
- @Override
- public boolean accept(String object)
- {
- return object.contains("a");
- }
- }).sort(new Comparator<String>()
- {
- @Override
- public int compare(String o1, String o2)
- {
- return o1.length() - o2.length();
-
- };
- }).toList();
+ List<String> result = flow
+ .filter(object -> object.contains("a"))
+ .sort((o1, o2) -> o1.length() - o2.length())
+ .toList();
assertListsEquals(result, "a", "had", "Mary", "lamb");
}
@@ -526,14 +473,7 @@ public class FuncTest extends BaseFuncTest
{
Flow<Integer> flow = F.emptyFlow();
- assertSame(flow.each(new Worker<Integer>()
- {
- @Override
- public void work(Integer value)
- {
- unreachable();
- }
- }), flow);
+ assertSame(flow, flow.each(value -> unreachable()));
}
@Test
@@ -541,7 +481,7 @@ public class FuncTest extends BaseFuncTest
{
Flow<Integer> flow = F.emptyFlow();
- assertSame(flow.remove(evenp), flow);
+ assertSame(flow, flow.remove(evenp));
}
@Test
@@ -550,28 +490,23 @@ public class FuncTest extends BaseFuncTest
Flow<Integer> flow = F.emptyFlow();
Integer initial = 99;
- assertSame(flow.reduce(new Reducer<Integer, Integer>()
- {
- @Override
- public Integer reduce(Integer accumulator, Integer value)
- {
- unreachable();
+ assertSame(initial, flow.reduce((accumulator, value) -> {
+ unreachable();
- return null;
- }
- }, initial), initial);
+ return null;
+ }, initial));
}
@Test
public void count_of_the_empty_flow_is_zero()
{
- assertEquals(F.flow().count(), 0);
+ assertEquals(0, F.flow().count());
}
@Test
public void count_of_array_flow()
{
- assertEquals(F.flow(1, 2, 3).count(), 3);
+ assertEquals(3, F.flow(1, 2, 3).count());
}
@Test
@@ -579,16 +514,16 @@ public class FuncTest extends BaseFuncTest
{
Flow<String> flow = F.flow("Mary", "had", "a", "little", "lamb");
- assertEquals(flow.filter(F.isNull()).count(), 0);
- assertEquals(flow.removeNulls().count(), 5);
+ assertEquals(0, flow.filter(F.isNull()).count());
+ assertEquals(5, flow.removeNulls().count());
}
@Test
public void count_of_a_large_flow()
{
- Flow<Integer> flow = F.series(1, 1).take(50000);
+ Flow<Integer> flow = F.series(1, 1).take(50_000);
- assertEquals(flow.count(), 50000);
+ assertEquals(50_000, flow.count());
}
@Test
@@ -611,15 +546,7 @@ public class FuncTest extends BaseFuncTest
@Test
public void lazy_flow_from_iterable()
{
- Iterable<Integer> iterable = new Iterable<Integer>()
- {
-
- @Override
- public Iterator<Integer> iterator()
- {
- return Arrays.asList(9, 7, 1).iterator();
- }
- };
+ Iterable<Integer> iterable = () -> Arrays.asList(9, 7, 1).iterator();
Flow<Integer> flow = F.flow(iterable);
diff --git a/tapestry-func/src/test/java/org/apache/tapestry5/func/InterleaveTests.java b/tapestry-func/src/test/java/org/apache/tapestry5/func/InterleaveTests.java
index 37fe18371..e2f4dda98 100644
--- a/tapestry-func/src/test/java/org/apache/tapestry5/func/InterleaveTests.java
+++ b/tapestry-func/src/test/java/org/apache/tapestry5/func/InterleaveTests.java
@@ -1,4 +1,4 @@
-// Copyright 2011 The Apache Software Foundation
+// Copyright 2011, 2025 The Apache Software Foundation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
package org.apache.tapestry5.func;
-import org.testng.annotations.Test;
+import org.junit.jupiter.api.Test;
public class InterleaveTests extends BaseFuncTest
{
@@ -23,9 +23,9 @@ public class InterleaveTests extends BaseFuncTest
{
Flow<Integer> first = F.flow(1, 2, 3);
Flow<Integer> second = F.flow(100, 200, 300);
- Flow<Integer> third = F.flow(1000, 2000, 3000);
+ Flow<Integer> third = F.flow(1_000, 2_000, 3_000);
- assertFlowValues(first.interleave(second, third), 1, 100, 1000, 2, 200, 2000, 3, 300, 3000);
+ assertFlowValues(first.interleave(second, third), 1, 100, 1_000, 2, 200, 2_000, 3, 300, 3_000);
}
@Test
@@ -33,9 +33,8 @@ public class InterleaveTests extends BaseFuncTest
{
Flow<Integer> first = F.flow(1, 2, 3);
Flow<Integer> second = F.flow(100);
- Flow<Integer> third = F.flow(1000, 2000, 3000);
-
- assertFlowValues(first.interleave(second, third), 1, 100, 1000);
+ Flow<Integer> third = F.flow(1_000, 2_000, 3_000);
+ assertFlowValues(first.interleave(second, third), 1, 100, 1_000);
}
}
diff --git a/tapestry-func/src/test/java/org/apache/tapestry5/func/MapperTest.java b/tapestry-func/src/test/java/org/apache/tapestry5/func/MapperTest.java
index 6144fa7ce..7a2a03156 100644
--- a/tapestry-func/src/test/java/org/apache/tapestry5/func/MapperTest.java
+++ b/tapestry-func/src/test/java/org/apache/tapestry5/func/MapperTest.java
@@ -1,4 +1,4 @@
-// Copyright 2010 The Apache Software Foundation
+// Copyright 2010, 2025 The Apache Software Foundation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -18,23 +18,20 @@ import java.util.Arrays;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
-import org.testng.annotations.Test;
+import org.junit.jupiter.api.Test;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertSame;
+import static org.junit.jupiter.api.Assertions.assertTrue;
public class MapperTest extends BaseFuncTest
{
- protected Mapper<Integer, Flow<Integer>> sequencer = new Mapper<Integer, Flow<Integer>>()
- {
-
- @Override
- public Flow<Integer> map(Integer value)
- {
- Flow<Integer> flow = F.flow();
+ protected Mapper<Integer, Flow<Integer>> sequencer = value -> {
+ Flow<Integer> flow = F.flow();
- for (int i = 0; i < value; i++)
- flow = flow.append(value);
+ for (int i = 0; i < value; i++)
+ flow = flow.append(value);
- return flow;
- }
+ return flow;
};
@Test
@@ -56,15 +53,10 @@ public class MapperTest extends BaseFuncTest
@Test
public void map_of_filtered_empty_is_empty()
{
- assertTrue(filteredEmpty.map(new Mapper<Integer, Integer>()
- {
- @Override
- public Integer map(Integer value)
- {
- unreachable();
-
- return value;
- }
+ assertTrue(filteredEmpty.map(value -> {
+ unreachable();
+
+ return value;
}).isEmpty());
}
@@ -73,7 +65,7 @@ public class MapperTest extends BaseFuncTest
{
Flow<Integer> flow = F.flow();
- assertSame(flow.mapcat(sequencer), flow);
+ assertSame(flow, flow.mapcat(sequencer));
assertTrue(filteredEmpty.mapcat(sequencer).isEmpty());
}
@@ -92,7 +84,7 @@ public class MapperTest extends BaseFuncTest
Flow<Integer> flow = F.flow("Mary", "had", "etc.").filter(F.isNull()).map(stringToLength);
assertTrue(flow.isEmpty());
- assertEquals(flow.count(), 0);
+ assertEquals(0, flow.count());
}
@Test
@@ -108,20 +100,14 @@ public class MapperTest extends BaseFuncTest
{
final AtomicInteger count = new AtomicInteger();
- Mapper<Integer, Integer> doubler = new Mapper<Integer, Integer>()
- {
- @Override
- public Integer map(Integer value)
- {
- count.incrementAndGet();
-
- return value * 2;
- }
+ Mapper<Integer, Integer> doubler = value -> {
+ count.incrementAndGet();
+ return value * 2;
};
assertFlowValues(F.range(1, 100).filter(F.gt(10)).map(doubler).take(3), 22, 24, 26);
- assertEquals(count.get(), 3);
+ assertEquals(3, count.get());
count.set(0);
@@ -129,17 +115,17 @@ public class MapperTest extends BaseFuncTest
// ever actually running the mapper to determine the final value.
assertEquals(F.range(1, 100).map(doubler).count(), 99);
- assertEquals(count.get(), 0);
+ assertEquals(0, count.get());
// Because values are now lazily evaluated as well as flows, we can count the size of a flow
// without ever actually calculating (via the mapper) an output value.
Flow<Integer> flow = F.range(1, 100).map(doubler).concat(F.range(1, 10).map(doubler));
- assertEquals(flow.count(), 108);
- assertEquals(count.get(), 0);
+ assertEquals(108, flow.count());
+ assertEquals(0, count.get());
assertFlowValues(flow.take(2), 2, 4);
- assertEquals(count.get(), 2);
+ assertEquals(2, count.get());
count.set(0);
@@ -147,7 +133,7 @@ public class MapperTest extends BaseFuncTest
// of the original flow, and previously computed values (2 and 4) are still accessible!
assertFlowValues(flow.take(3), 2, 4, 6);
- assertEquals(count.get(), 1);
+ assertEquals(1, count.get());
}
@Test
@@ -155,8 +141,8 @@ public class MapperTest extends BaseFuncTest
{
Flow<Integer> flow = F.flow(1, 2, 3);
- assertSame(flow.map(F.ADD_INTS, filteredEmpty), F.EMPTY_FLOW);
- assertSame(filteredEmpty.map(F.ADD_INTS, flow), F.EMPTY_FLOW);
+ assertSame(F.emptyFlow(), flow.map(F.ADD_INTS, filteredEmpty));
+ assertSame(F.emptyFlow(), filteredEmpty.map(F.ADD_INTS, flow));
}
@Test
diff --git a/tapestry-func/src/test/java/org/apache/tapestry5/func/RangeTests.java b/tapestry-func/src/test/java/org/apache/tapestry5/func/RangeTests.java
index 9a8c4b265..6ccdcfa73 100644
--- a/tapestry-func/src/test/java/org/apache/tapestry5/func/RangeTests.java
+++ b/tapestry-func/src/test/java/org/apache/tapestry5/func/RangeTests.java
@@ -1,4 +1,4 @@
-// Copyright 2010 The Apache Software Foundation
+// Copyright 2010, 2025 The Apache Software Foundation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -14,7 +14,8 @@
package org.apache.tapestry5.func;
-import org.testng.annotations.Test;
+import org.junit.jupiter.api.Test;
+import static org.junit.jupiter.api.Assertions.assertTrue;
public class RangeTests extends BaseFuncTest
{
@@ -27,7 +28,6 @@ public class RangeTests extends BaseFuncTest
@Test
public void ascending_range()
{
-
assertFlowValues(F.range(5, 8), 5, 6, 7);
}
@@ -56,14 +56,7 @@ public class RangeTests extends BaseFuncTest
@Test
public void iterate()
{
- Mapper<Integer, Integer> times2 = new Mapper<Integer, Integer>()
- {
- @Override
- public Integer map(Integer value)
- {
- return 2 * value;
- }
- };
+ Mapper<Integer, Integer> times2 = value -> 2 * value;
assertFlowValues(F.iterate(1, times2).take(5), 1, 2, 4, 8, 16);
}
diff --git a/tapestry-func/src/test/java/org/apache/tapestry5/func/StringPredicateTests.java b/tapestry-func/src/test/java/org/apache/tapestry5/func/StringPredicateTests.java
index 47d4cdf86..87ec5d93f 100644
--- a/tapestry-func/src/test/java/org/apache/tapestry5/func/StringPredicateTests.java
+++ b/tapestry-func/src/test/java/org/apache/tapestry5/func/StringPredicateTests.java
@@ -1,4 +1,4 @@
-// Copyright 2011, 2012 The Apache Software Foundation
+// Copyright 2011, 2012, 2025 The Apache Software Foundation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -13,7 +13,7 @@
// limitations under the License.
package org.apache.tapestry5.func;
-import org.testng.annotations.Test;
+import org.junit.jupiter.api.Test;
public class StringPredicateTests extends BaseFuncTest
{
diff --git a/tapestry-func/src/test/java/org/apache/tapestry5/func/TakeDropTests.java b/tapestry-func/src/test/java/org/apache/tapestry5/func/TakeDropTests.java
index 88e0e2e32..e73ba0a19 100644
--- a/tapestry-func/src/test/java/org/apache/tapestry5/func/TakeDropTests.java
+++ b/tapestry-func/src/test/java/org/apache/tapestry5/func/TakeDropTests.java
@@ -1,4 +1,4 @@
-// Copyright 2010 The Apache Software Foundation
+// Copyright 2010, 2025 The Apache Software Foundation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -14,14 +14,16 @@
package org.apache.tapestry5.func;
-import org.testng.annotations.Test;
+import org.junit.jupiter.api.Test;
+import static org.junit.jupiter.api.Assertions.assertSame;
+import static org.junit.jupiter.api.Assertions.assertTrue;
public class TakeDropTests extends BaseFuncTest
{
@Test
public void take_from_empty_list()
{
- assertSame(F.flow().take(34), F.EMPTY_FLOW);
+ assertSame(F.emptyFlow(), F.flow().take(34));
}
@Test
@@ -39,7 +41,7 @@ public class TakeDropTests extends BaseFuncTest
assertFlowValues(flow.take(99), 1, 2, 3, 4, 5);
- assertSame(flow.take(0), F.EMPTY_FLOW);
+ assertSame(F.emptyFlow(), flow.take(0));
}
@Test
@@ -48,7 +50,7 @@ public class TakeDropTests extends BaseFuncTest
// This can go much, much larger but starts taking a while. Don't hold a reference to the
// start
// of the series or it can run out of memory.
- int length = 100000;
+ int length = 100_000;
assertFlowValues(F.series(1, 1).filter(evenp).drop(length).take(3), 2 * length + 2, 2 * length + 4,
2 * length + 6);
@@ -57,7 +59,7 @@ public class TakeDropTests extends BaseFuncTest
@Test
public void drop_from_empty_is_empty()
{
- assertSame(F.flow().drop(99), F.EMPTY_FLOW);
+ assertSame(F.emptyFlow(), F.flow().drop(99));
}
@Test
@@ -75,7 +77,7 @@ public class TakeDropTests extends BaseFuncTest
@Test
public void drop_all_from_array_flow_is_empty_flow()
{
- assertSame(F.flow(1, 2, 3).drop(3), F.EMPTY_FLOW);
+ assertSame(F.emptyFlow(), F.flow(1, 2, 3).drop(3));
}
@Test
@@ -83,7 +85,7 @@ public class TakeDropTests extends BaseFuncTest
{
Flow<Integer> flow = F.flow(1, 2, 3);
- assertSame(flow.drop(0), flow);
+ assertSame(flow, flow.drop(0));
}
@Test
diff --git a/tapestry-func/src/test/java/org/apache/tapestry5/func/TupleTests.java b/tapestry-func/src/test/java/org/apache/tapestry5/func/TupleTests.java
index 3eadf3724..0ddfa6b6f 100644
--- a/tapestry-func/src/test/java/org/apache/tapestry5/func/TupleTests.java
+++ b/tapestry-func/src/test/java/org/apache/tapestry5/func/TupleTests.java
@@ -1,5 +1,5 @@
package org.apache.tapestry5.func;
-// Copyright 2010 The Apache Software Foundation
+// Copyright 2010, 2025 The Apache Software Foundation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -14,7 +14,11 @@ package org.apache.tapestry5.func;
// limitations under the License.
import org.apache.tapestry5.func.Tuple;
-import org.testng.annotations.Test;
+
+import org.junit.jupiter.api.Test;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
public class TupleTests extends BaseFuncTest
{
diff --git a/tapestry-func/src/test/java/org/apache/tapestry5/func/ZippedFlowTests.java b/tapestry-func/src/test/java/org/apache/tapestry5/func/ZippedFlowTests.java
index a4b8ee632..82bde9a8f 100644
--- a/tapestry-func/src/test/java/org/apache/tapestry5/func/ZippedFlowTests.java
+++ b/tapestry-func/src/test/java/org/apache/tapestry5/func/ZippedFlowTests.java
@@ -1,4 +1,4 @@
-// Copyright 2010, 2011 The Apache Software Foundation
+// Copyright 2010, 2011, 2025 The Apache Software Foundation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -14,8 +14,12 @@
package org.apache.tapestry5.func;
-import org.apache.commons.lang.StringUtils;
-import org.testng.annotations.Test;
+import org.apache.commons.lang3.StringUtils;
+
+import org.junit.jupiter.api.Test;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
import java.util.Arrays;
import java.util.HashMap;
@@ -36,14 +40,14 @@ public class ZippedFlowTests extends BaseFuncTest
{
Map<Integer, String> map = zipped.toMap();
- assertEquals(map.size(), 3);
- assertEquals(map.get(2), "barney");
+ assertEquals(3, map.size());
+ assertEquals("barney", map.get(2));
}
@Test
public void map_to_zipped_flow()
{
- Map<Integer, String> map = new HashMap<Integer, String>();
+ Map<Integer, String> map = new HashMap<>();
map.put(1, "fred");
map.put(2, "barney");
@@ -105,7 +109,7 @@ public class ZippedFlowTests extends BaseFuncTest
@Test
public void first_tuple_from_zipped_flow()
{
- assertEquals(zipped.drop(2).first(), Tuple.create(3, "wilma"));
+ assertEquals(Tuple.create(3, "wilma"), zipped.drop(2).first());
}
@Test
@@ -124,28 +128,28 @@ public class ZippedFlowTests extends BaseFuncTest
ZippedFlow<Integer, String> extendedFlow = zipped.concat(Arrays.asList(null, pebbles, null));
ZippedFlow<Integer, String> noNulls = extendedFlow.removeNulls();
- assertEquals(extendedFlow.count(), 6);
- assertEquals(noNulls.count(), 4);
+ assertEquals(6, extendedFlow.count());
+ assertEquals(4, noNulls.count());
- assertEquals(noNulls.reverse().seconds().first(), "pebbles");
+ assertEquals("pebbles", noNulls.reverse().seconds().first());
}
@Test
public void rest_of_zipped_flow()
{
- assertEquals(zipped.rest().first().second, "barney");
+ assertEquals("barney", zipped.rest().first().second);
}
@Test
public void count_of_zipped_flow()
{
- assertEquals(zipped.count(), 3);
+ assertEquals(3, zipped.count());
}
@Test
public void take_from_zipped_flow()
{
- assertEquals(zipped.take(2).reverse().first().second, "barney");
+ assertEquals("barney", zipped.take(2).reverse().first().second);
}
@Test
@@ -153,39 +157,23 @@ public class ZippedFlowTests extends BaseFuncTest
{
final AtomicInteger count = new AtomicInteger();
- zipped.each(new Worker<Tuple<Integer, String>>()
- {
- @Override
- public void work(Tuple<Integer, String> value)
- {
- count.addAndGet(value.second.length());
- }
-
- });
+ zipped.each(value -> count.addAndGet(value.second.length()));
- assertEquals(count.get(), 15);
+ assertEquals(15, count.get());
}
@Test
public void reduce_zipped_flow()
{
- int totalLength = zipped.reduce(new Reducer<Integer, Tuple<Integer, String>>()
- {
- @Override
- public Integer reduce(Integer accumulator, Tuple<Integer, String> value)
- {
- return accumulator + value.second.length();
- }
-
- }, 0);
+ int totalLength = zipped.reduce((acc, value) -> acc + value.second.length(), 0);
- assertEquals(totalLength, 15);
+ assertEquals(15, totalLength);
}
@Test
public void remove_from_zipped_flow()
{
- assertEquals(zipped.remove(F.notNull()).count(), 0);
+ assertEquals(0, zipped.remove(F.notNull()).count());
}
@SuppressWarnings("unchecked")
@@ -198,21 +186,21 @@ public class ZippedFlowTests extends BaseFuncTest
ZippedFlow<Integer, String> zipped2 = zipped.concat(asList);
- assertEquals(zipped2.count(), 4);
+ assertEquals(4, zipped2.count());
- assertEquals(zipped2.reverse().seconds().first(), "bam-bam");
+ assertEquals("bam-bam", zipped2.reverse().seconds().first());
}
@Test
public void firsts()
{
- assertEquals(zipped.reverse().firsts().first(), (Integer) 3);
+ assertEquals((Integer)3, zipped.reverse().firsts().first());
}
@Test
public void seconds()
{
- assertEquals(zipped.seconds().first(), "fred");
+ assertEquals("fred", zipped.seconds().first());
}
@Test
@@ -229,7 +217,7 @@ public class ZippedFlowTests extends BaseFuncTest
}).first();
- assertEquals(firstTuple.first, "derf");
- assertEquals(firstTuple.second, "1-4");
+ assertEquals("derf", firstTuple.first);
+ assertEquals("1-4", firstTuple.second);
}
}
diff --git a/tapestry-hibernate-core/src/test/conf/testng.xml b/tapestry-hibernate-core/src/test/resources/testng.xml
similarity index 100%
rename from tapestry-hibernate-core/src/test/conf/testng.xml
rename to tapestry-hibernate-core/src/test/resources/testng.xml
diff --git a/tapestry-hibernate/src/test/conf/testng.xml b/tapestry-hibernate/src/test/resources/testng.xml
similarity index 100%
rename from tapestry-hibernate/src/test/conf/testng.xml
rename to tapestry-hibernate/src/test/resources/testng.xml
diff --git a/tapestry-http/src/test/java/org/apache/tapestry5/http/internal/services/CorsHandlerHelperImplTest.java b/tapestry-http/src/test/java/org/apache/tapestry5/http/internal/services/CorsHandlerHelperImplTest.java
index 10632f99b..0c393c5f5 100644
--- a/tapestry-http/src/test/java/org/apache/tapestry5/http/internal/services/CorsHandlerHelperImplTest.java
+++ b/tapestry-http/src/test/java/org/apache/tapestry5/http/internal/services/CorsHandlerHelperImplTest.java
@@ -14,26 +14,27 @@ import javax.servlet.http.HttpServletResponse;
import org.apache.tapestry5.http.services.CorsHandlerHelper;
import org.easymock.EasyMock;
-import org.junit.Assert;
+import org.testng.Assert;
import org.testng.annotations.Test;
/**
- * Test suite for {@link CorsHandlerHelperImpl.
+ * Test suite for {@link CorsHandlerHelperImpl}.
*/
public class CorsHandlerHelperImplTest {
-
+
@Test
public void get_origin()
{
-
+
final String[] allowedOrigins = new String[] {"http://tapestry.apache.org", "https://apache.org"};
-
+
// Scenario 1: explicit origins
-
+
CorsHandlerHelper helper = create(String.join(" , ", allowedOrigins));
+
HttpServletRequest request = EasyMock.createMock(HttpServletRequest.class);
-
+
for (String origin : allowedOrigins)
{
@@ -41,20 +42,20 @@ public class CorsHandlerHelperImplTest {
EasyMock.reset(request);
EasyMock.expect(request.getHeader(CorsHandlerHelper.ORIGIN_HEADER)).andReturn(origin);
EasyMock.replay(request);
- Assert.assertEquals("Allowed origin", origin, helper.getAllowedOrigin(request).get());
+ Assert.assertEquals(origin, helper.getAllowedOrigin(request).get(), "Allowed origin");
EasyMock.verify(request);
-
+
// Non-allowed origins
EasyMock.reset(request);
EasyMock.expect(request.getHeader(CorsHandlerHelper.ORIGIN_HEADER)).andReturn(origin + "baaaa");
EasyMock.replay(request);
- Assert.assertFalse("Non-allowed origins", helper.getAllowedOrigin(request).isPresent());
+ Assert.assertFalse(helper.getAllowedOrigin(request).isPresent(), "Non-allowed origins");
EasyMock.verify(request);
-
+
}
-
+
// Scenario 2: allow all origins
-
+
helper = create(CorsHandlerHelper.ORIGIN_WILDCARD);
for (int i = 0; i < 10; i++)
{
@@ -62,23 +63,24 @@ public class CorsHandlerHelperImplTest {
EasyMock.reset(request);
EasyMock.expect(request.getHeader(CorsHandlerHelper.ORIGIN_HEADER)).andReturn(origin);
EasyMock.replay(request);
- Assert.assertEquals("All origins should be accepted", CorsHandlerHelper.ORIGIN_WILDCARD, helper.getAllowedOrigin(request).get());
+ Assert.assertEquals(CorsHandlerHelper.ORIGIN_WILDCARD,
+ helper.getAllowedOrigin(request).get(), "All origins should be accepted");
EasyMock.verify(request);
}
-
+
}
@Test
public void is_preflight()
{
-
+
// Scenario 1: not OPTIONS
final String origin = "https://tapestry.apache.org";
CorsHandlerHelper helper = create(origin);
HttpServletRequest request = EasyMock.createMock(HttpServletRequest.class);
EasyMock.expect(request.getMethod()).andReturn("PUT");
EasyMock.replay(request);
- Assert.assertFalse("Not OPTIONS", helper.isPreflight(request));
+ Assert.assertFalse(helper.isPreflight(request), "Not OPTIONS");
EasyMock.verify(request);
// Scenario 2: no Origin
@@ -86,7 +88,7 @@ public class CorsHandlerHelperImplTest {
EasyMock.expect(request.getMethod()).andReturn(CorsHandlerHelper.OPTIONS_METHOD);
EasyMock.expect(request.getHeader(CorsHandlerHelper.ORIGIN_HEADER)).andReturn(null);
EasyMock.replay(request);
- Assert.assertFalse("No Origin", helper.isPreflight(request));
+ Assert.assertFalse(helper.isPreflight(request), "No Origin");
EasyMock.verify(request);
// Scenario 3: accepted origin
@@ -94,7 +96,7 @@ public class CorsHandlerHelperImplTest {
EasyMock.expect(request.getMethod()).andReturn(CorsHandlerHelper.OPTIONS_METHOD);
EasyMock.expect(request.getHeader(CorsHandlerHelper.ORIGIN_HEADER)).andReturn(origin);
EasyMock.replay(request);
- Assert.assertTrue("Preflight indeed", helper.isPreflight(request));
+ Assert.assertTrue(helper.isPreflight(request), "Preflight indeed");
EasyMock.verify(request);
// Scenario 4: non-accepted origin
@@ -102,24 +104,24 @@ public class CorsHandlerHelperImplTest {
EasyMock.expect(request.getMethod()).andReturn(CorsHandlerHelper.OPTIONS_METHOD);
EasyMock.expect(request.getHeader(CorsHandlerHelper.ORIGIN_HEADER)).andReturn(origin + "baaah");
EasyMock.replay(request);
- Assert.assertFalse("Non-accepted origin", helper.isPreflight(request));
+ Assert.assertFalse(helper.isPreflight(request), "Non-accepted origin");
EasyMock.verify(request);
}
-
+
@Test
public void get_path()
{
CorsHandlerHelper helper = create("*");
HttpServletRequest request = EasyMock.createMock(HttpServletRequest.class);
-
+
final String pathInfo = "/blah/foo/";
EasyMock.expect(request.getPathInfo()).andReturn(pathInfo);
EasyMock.replay(request);
Assert.assertEquals(pathInfo, helper.getPath(request));
EasyMock.verify(request);
-
+
EasyMock.reset(request);
EasyMock.expect(request.getPathInfo()).andReturn("");
EasyMock.replay(request);
@@ -135,19 +137,19 @@ public class CorsHandlerHelperImplTest {
EasyMock.verify(request);
}
-
+
@Test
public void configure_origin()
{
CorsHandlerHelper helper = create("*");
HttpServletResponse response = new TestableHttpServletResponse();;
-
+
final String origin = "https://apache.org";
helper.configureOrigin(response, origin);
Assert.assertEquals(origin, response.getHeader(CorsHandlerHelper.ALLOW_ORIGIN_HEADER));
Assert.assertEquals(CorsHandlerHelper.ORIGIN_HEADER, response.getHeader(CorsHandlerHelper.VARY_HEADER));
}
-
+
@Test
public void add_value_to_vary_header()
{
@@ -159,30 +161,30 @@ public class CorsHandlerHelperImplTest {
}
Assert.assertEquals(String.join(", ", values), response.getHeader(CorsHandlerHelper.VARY_HEADER));
}
-
+
@Test
public void configure_credentials()
{
HttpServletResponse response = new TestableHttpServletResponse();
-
+
CorsHandlerHelper helper = create(CorsHandlerHelper.ORIGIN_WILDCARD, true);
helper.configureCredentials(response);
Assert.assertEquals("true", response.getHeader(CorsHandlerHelper.ALLOW_CREDENTIALS_HEADER));
-
+
response = new TestableHttpServletResponse();
helper = create(CorsHandlerHelper.ORIGIN_WILDCARD, false);
helper.configureCredentials(response);
- Assert.assertNull("Header shouldn't be set",
- response.getHeader(CorsHandlerHelper.ALLOW_CREDENTIALS_HEADER));
+ Assert.assertNull(response.getHeader(CorsHandlerHelper.ALLOW_CREDENTIALS_HEADER),
+ "Header shouldn't be set");
}
-
+
@Test
public void configure_methods()
{
HttpServletResponse response = new TestableHttpServletResponse();
-
+
final String allowedMethods = "GET,PUT";
CorsHandlerHelper helper = new CorsHandlerHelperImpl("", false, allowedMethods, "", "", "");
response = new TestableHttpServletResponse();
@@ -195,7 +197,7 @@ public class CorsHandlerHelperImplTest {
{
HttpServletResponse response = new TestableHttpServletResponse();
HttpServletRequest request = EasyMock.createMock(HttpServletRequest.class);
-
+
// Scenario 1: configuration isn't empty
final String configuredHeaders = "Blah,Foo";
CorsHandlerHelper helper = new CorsHandlerHelperImpl("", false, "", configuredHeaders, "", "");
@@ -214,8 +216,10 @@ public class CorsHandlerHelperImplTest {
EasyMock.replay(request);
helper.configureAllowedHeaders(response, request);
EasyMock.verify(request);
- Assert.assertEquals(requestHeaders, response.getHeader(CorsHandlerHelper.ALLOW_HEADERS_HEADER));
- Assert.assertEquals(CorsHandlerHelper.REQUEST_HEADERS_HEADER, response.getHeader(CorsHandlerHelper.VARY_HEADER));
+ Assert.assertEquals(response.getHeader(CorsHandlerHelper.ALLOW_HEADERS_HEADER),
+ requestHeaders);
+ Assert.assertEquals(response.getHeader(CorsHandlerHelper.VARY_HEADER),
+ CorsHandlerHelper.REQUEST_HEADERS_HEADER);
// Scenario 3: configuration empty, request's Access-Control-Request-Headers also empty
response = new TestableHttpServletResponse();
@@ -225,7 +229,8 @@ public class CorsHandlerHelperImplTest {
helper.configureAllowedHeaders(response, request);
EasyMock.verify(request);
Assert.assertNull(response.getHeader(CorsHandlerHelper.ALLOW_HEADERS_HEADER));
- Assert.assertEquals(CorsHandlerHelper.REQUEST_HEADERS_HEADER, response.getHeader(CorsHandlerHelper.VARY_HEADER));
+ Assert.assertEquals(response.getHeader(CorsHandlerHelper.VARY_HEADER),
+ CorsHandlerHelper.REQUEST_HEADERS_HEADER);
}
@@ -233,18 +238,18 @@ public class CorsHandlerHelperImplTest {
public void configure_expose_headers()
{
HttpServletResponse response = new TestableHttpServletResponse();
-
+
final String exposeHeaders = "Blah,Foo,Bar";
CorsHandlerHelper helper = new CorsHandlerHelperImpl("", false, "", "", exposeHeaders, "");
helper.configureExposeHeaders(response);
Assert.assertEquals(exposeHeaders, response.getHeader(CorsHandlerHelper.EXPOSE_HEADERS_HEADER));
-
+
response = new TestableHttpServletResponse();
helper = new CorsHandlerHelperImpl("", false, "", "", "", "");
helper.configureExposeHeaders(response);
- Assert.assertNull("Header shouldn't be set",
- response.getHeader(CorsHandlerHelper.EXPOSE_HEADERS_HEADER));
+ Assert.assertNull(response.getHeader(CorsHandlerHelper.EXPOSE_HEADERS_HEADER),
+ "Header shouldn't be set");
}
@@ -252,18 +257,18 @@ public class CorsHandlerHelperImplTest {
public void configure_max_age()
{
HttpServletResponse response = new TestableHttpServletResponse();
-
+
final String maxAge = "1234567";
CorsHandlerHelper helper = new CorsHandlerHelperImpl("", false, "", "", "", maxAge);
helper.configureMaxAge(response);
Assert.assertEquals(maxAge, response.getHeader(CorsHandlerHelper.MAX_AGE_HEADER));
-
+
response = new TestableHttpServletResponse();
helper = new CorsHandlerHelperImpl("", false, "", "", "", "");
helper.configureExposeHeaders(response);
- Assert.assertNull("Header shouldn't be set",
- response.getHeader(CorsHandlerHelper.MAX_AGE_HEADER));
+ Assert.assertNull(response.getHeader(CorsHandlerHelper.MAX_AGE_HEADER),
+ "Header shouldn't be set");
}
@@ -271,211 +276,211 @@ public class CorsHandlerHelperImplTest {
{
return create(allowedOrigins, false);
}
-
+
private CorsHandlerHelper create(String allowedOrigins, boolean allowCredentials)
{
return new CorsHandlerHelperImpl(allowedOrigins, allowCredentials, "", "", "", "");
}
-
+
private final class TestableHttpServletResponse implements HttpServletResponse
{
-
+
private final Map<String, String> headers = new HashMap<>();
@Override
- public String getCharacterEncoding()
+ public String getCharacterEncoding()
{
throw new UnsupportedOperationException();
}
@Override
- public String getContentType()
+ public String getContentType()
{
throw new UnsupportedOperationException();
}
@Override
- public ServletOutputStream getOutputStream() throws IOException
+ public ServletOutputStream getOutputStream() throws IOException
{
throw new UnsupportedOperationException();
}
@Override
- public PrintWriter getWriter() throws IOException
+ public PrintWriter getWriter() throws IOException
{
return null;
}
@Override
- public void setCharacterEncoding(String charset)
+ public void setCharacterEncoding(String charset)
{
throw new UnsupportedOperationException();
}
@Override
- public void setContentLength(int len)
+ public void setContentLength(int len)
{
throw new UnsupportedOperationException();
}
@Override
- public void setContentType(String type)
+ public void setContentType(String type)
{
throw new UnsupportedOperationException();
}
@Override
- public void setBufferSize(int size)
+ public void setBufferSize(int size)
{
throw new UnsupportedOperationException();
}
@Override
- public int getBufferSize()
+ public int getBufferSize()
{
throw new UnsupportedOperationException();
}
@Override
- public void flushBuffer() throws IOException
+ public void flushBuffer() throws IOException
{
throw new UnsupportedOperationException();
}
@Override
- public void resetBuffer()
+ public void resetBuffer()
{
throw new UnsupportedOperationException();
}
@Override
- public boolean isCommitted()
+ public boolean isCommitted()
{
return false;
}
@Override
- public void reset()
+ public void reset()
{
throw new UnsupportedOperationException();
}
@Override
- public void setLocale(Locale loc)
+ public void setLocale(Locale loc)
{
throw new UnsupportedOperationException();
}
@Override
- public Locale getLocale()
+ public Locale getLocale()
{
throw new UnsupportedOperationException();
}
@Override
- public void addCookie(Cookie cookie)
+ public void addCookie(Cookie cookie)
{
throw new UnsupportedOperationException();
}
@Override
- public boolean containsHeader(String name)
+ public boolean containsHeader(String name)
{
throw new UnsupportedOperationException();
}
@Override
- public String encodeURL(String url)
+ public String encodeURL(String url)
{
throw new UnsupportedOperationException();
}
@Override
- public String encodeRedirectURL(String url)
+ public String encodeRedirectURL(String url)
{
throw new UnsupportedOperationException();
}
@Override
- public String encodeUrl(String url)
+ public String encodeUrl(String url)
{
throw new UnsupportedOperationException();
}
@Override
- public String encodeRedirectUrl(String url)
+ public String encodeRedirectUrl(String url)
{
throw new UnsupportedOperationException();
}
@Override
- public void sendError(int sc, String msg) throws IOException
+ public void sendError(int sc, String msg) throws IOException
{
throw new UnsupportedOperationException();
}
@Override
- public void sendError(int sc) throws IOException
+ public void sendError(int sc) throws IOException
{
throw new UnsupportedOperationException();
}
@Override
- public void sendRedirect(String location) throws IOException
+ public void sendRedirect(String location) throws IOException
{
throw new UnsupportedOperationException();
}
@Override
- public void setDateHeader(String name, long date)
+ public void setDateHeader(String name, long date)
{
throw new UnsupportedOperationException();
}
@Override
- public void addDateHeader(String name, long date)
+ public void addDateHeader(String name, long date)
{
throw new UnsupportedOperationException();
}
@Override
- public void setHeader(String name, String value)
+ public void setHeader(String name, String value)
{
headers.put(name, value);
}
@Override
- public void addHeader(String name, String value)
+ public void addHeader(String name, String value)
{
throw new UnsupportedOperationException();
}
@Override
- public void setIntHeader(String name, int value)
+ public void setIntHeader(String name, int value)
{
throw new UnsupportedOperationException();
}
@Override
- public void addIntHeader(String name, int value)
+ public void addIntHeader(String name, int value)
{
throw new UnsupportedOperationException();
}
@Override
- public void setStatus(int sc)
+ public void setStatus(int sc)
{
throw new UnsupportedOperationException();
}
@Override
- public void setStatus(int sc, String sm)
+ public void setStatus(int sc, String sm)
{
throw new UnsupportedOperationException();
}
@Override
- public int getStatus()
+ public int getStatus()
{
throw new UnsupportedOperationException();
}
@@ -486,17 +491,17 @@ public class CorsHandlerHelperImplTest {
}
@Override
- public Collection<String> getHeaders(String name)
+ public Collection<String> getHeaders(String name)
{
throw new UnsupportedOperationException();
}
@Override
- public Collection<String> getHeaderNames()
+ public Collection<String> getHeaderNames()
{
throw new UnsupportedOperationException();
}
-
+
}
-
+
}
diff --git a/tapestry-http/src/test/java/org/apache/tapestry5/http/internal/services/CorsHttpServletRequestFilterTest.java b/tapestry-http/src/test/java/org/apache/tapestry5/http/internal/services/CorsHttpServletRequestFilterTest.java
index c39334425..826817375 100644
--- a/tapestry-http/src/test/java/org/apache/tapestry5/http/internal/services/CorsHttpServletRequestFilterTest.java
+++ b/tapestry-http/src/test/java/org/apache/tapestry5/http/internal/services/CorsHttpServletRequestFilterTest.java
@@ -11,7 +11,7 @@ import org.apache.tapestry5.http.services.CorsHandler;
import org.apache.tapestry5.http.services.CorsHttpServletRequestFilter;
import org.apache.tapestry5.http.services.HttpServletRequestHandler;
import org.easymock.EasyMock;
-import org.junit.Assert;
+import org.testng.Assert;
import org.testng.annotations.Test;
/**
diff --git a/tapestry-http/src/test/java/org/apache/tapestry5/http/test/services/AppModule.java b/tapestry-http/src/test/java/org/apache/tapestry5/http/test/services/AppModule.java
index f7eab0d06..ce01d3601 100644
--- a/tapestry-http/src/test/java/org/apache/tapestry5/http/test/services/AppModule.java
+++ b/tapestry-http/src/test/java/org/apache/tapestry5/http/test/services/AppModule.java
@@ -3,6 +3,7 @@ package org.apache.tapestry5.http.test.services;
import org.apache.tapestry5.commons.MappedConfiguration;
import org.apache.tapestry5.commons.OrderedConfiguration;
import org.apache.tapestry5.http.TapestryHttpSymbolConstants;
+import org.apache.tapestry5.http.services.CompressionAnalyzer;
import org.apache.tapestry5.http.services.Dispatcher;
import org.apache.tapestry5.http.services.HttpServletRequestFilter;
import org.apache.tapestry5.http.services.RequestFilter;
@@ -30,6 +31,12 @@ public class AppModule {
public static void contributeApplicationDefaults(MappedConfiguration<String, Object> configuration)
{
configuration.add(TapestryHttpSymbolConstants.GZIP_COMPRESSION_ENABLED, true);
+ configuration.add(TapestryHttpSymbolConstants.PRODUCTION_MODE, true);
+ }
+
+ public static CompressionAnalyzer buildCompressionAnalyzer()
+ {
+ return str -> true;
}
}
diff --git a/tapestry-ioc-junit/src/test/java/org/apache/tapestry5/ioc/junit/TapestryIOCJUnit4ClassRunnerAfterClassTest.java b/tapestry-ioc-junit/src/test/java/org/apache/tapestry5/ioc/junit/TapestryIOCJUnit4ClassRunnerAfterClassTest.java
deleted file mode 100644
index 67be2ef61..000000000
--- a/tapestry-ioc-junit/src/test/java/org/apache/tapestry5/ioc/junit/TapestryIOCJUnit4ClassRunnerAfterClassTest.java
+++ /dev/null
@@ -1,63 +0,0 @@
-// Copyright 2006, 2007, 2008, 2009, 2010, 2011, 2012 The Apache Software Foundation
-//
-// 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 org.apache.tapestry5.ioc.junit;
-
-import static org.apache.tapestry5.ioc.junit.RegistryShutdownType.AFTER_CLASS;
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.runners.MethodSorters.NAME_ASCENDING;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import org.apache.tapestry5.ioc.annotations.Inject;
-import org.apache.tapestry5.ioc.junit.Registry;
-import org.apache.tapestry5.ioc.junit.TapestryIOCJUnit4ClassRunner;
-import org.apache.tapestry5.ioc.junit.TapestryIOCJUnit4ClassRunnerAfterClassTest.AfterClassTestModule;
-import org.junit.FixMethodOrder;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-@RunWith(TapestryIOCJUnit4ClassRunner.class)
-@Registry(modules=AfterClassTestModule.class, shutdown=AFTER_CLASS)
-@FixMethodOrder(NAME_ASCENDING) // guarantees test ordering
-public class TapestryIOCJUnit4ClassRunnerAfterClassTest {
- public static class AfterClassTestModule {
- public List<String> buildList() {
- List<String> list = new ArrayList<String>();
- list.add("foo");
- return list;
- }
- }
-
- @Inject
- private List<String> list;
-
- @Test
- public void testInjectA() {
- assertArrayEquals(new Object[] { "foo" }, list.toArray());
- list.add("bar");
- }
-
- @Test
- public void testInjectB() {
- assertArrayEquals(new Object[] { "foo", "bar" }, list.toArray());
- list.add("baz");
- }
-
- @Test
- public void testInjectC() {
- assertArrayEquals(new Object[] { "foo", "bar", "baz" }, list.toArray());
- }
-}
diff --git a/tapestry-ioc-junit/src/test/java/org/apache/tapestry5/ioc/junit/TapestryIOCJUnit4ClassRunnerAfterMethodTest.java b/tapestry-ioc-junit/src/test/java/org/apache/tapestry5/ioc/junit/TapestryIOCJUnit4ClassRunnerAfterMethodTest.java
deleted file mode 100644
index acbaa8189..000000000
--- a/tapestry-ioc-junit/src/test/java/org/apache/tapestry5/ioc/junit/TapestryIOCJUnit4ClassRunnerAfterMethodTest.java
+++ /dev/null
@@ -1,65 +0,0 @@
-// Copyright 2006, 2007, 2008, 2009, 2010, 2011, 2012 The Apache Software Foundation
-//
-// 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 org.apache.tapestry5.ioc.junit;
-
-import static org.apache.tapestry5.ioc.junit.RegistryShutdownType.AFTER_METHOD;
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.runners.MethodSorters.NAME_ASCENDING;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import org.apache.tapestry5.ioc.annotations.Inject;
-import org.apache.tapestry5.ioc.junit.Registry;
-import org.apache.tapestry5.ioc.junit.TapestryIOCJUnit4ClassRunner;
-import org.apache.tapestry5.ioc.junit.TapestryIOCJUnit4ClassRunnerAfterMethodTest.AfterMethodTestModule;
-import org.junit.FixMethodOrder;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-@RunWith(TapestryIOCJUnit4ClassRunner.class)
-@Registry(modules=AfterMethodTestModule.class, shutdown=AFTER_METHOD)
-@FixMethodOrder(NAME_ASCENDING) // guarantees test ordering
-public class TapestryIOCJUnit4ClassRunnerAfterMethodTest {
- public static class AfterMethodTestModule {
- public List<String> buildList() {
- List<String> list = new ArrayList<String>();
- list.add("foo");
- return list;
- }
- }
-
- @Inject
- private List<String> list;
-
- @Test
- public void testInjectA() {
- assertArrayEquals(new Object[] { "foo" }, list.toArray());
-
- list.add("bar");
- }
-
- @Test
- public void testInjectB() {
- assertArrayEquals(new Object[] { "foo" }, list.toArray());
-
- list.add("baz");
- }
-
- @Test
- public void testInjectC() {
- assertArrayEquals(new Object[] { "foo" }, list.toArray());
- }
-}
diff --git a/tapestry-ioc-junit/src/test/java/org/apache/tapestry5/ioc/junit/TapestryIOCJUnit4ClassRunnerModuleDefTest.java b/tapestry-ioc-junit/src/test/java/org/apache/tapestry5/ioc/junit/TapestryIOCJUnit4ClassRunnerModuleDefTest.java
deleted file mode 100644
index 3915584c8..000000000
--- a/tapestry-ioc-junit/src/test/java/org/apache/tapestry5/ioc/junit/TapestryIOCJUnit4ClassRunnerModuleDefTest.java
+++ /dev/null
@@ -1,69 +0,0 @@
-// Copyright 2006, 2007, 2008, 2009, 2010, 2011, 2012 The Apache Software Foundation
-//
-// 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 org.apache.tapestry5.ioc.junit;
-
-import static org.junit.Assert.assertEquals;
-
-import java.util.Date;
-import java.util.HashMap;
-import java.util.Map;
-
-import org.apache.tapestry5.ioc.annotations.Inject;
-import org.apache.tapestry5.ioc.junit.ModuleDef;
-import org.apache.tapestry5.ioc.junit.Registry;
-import org.apache.tapestry5.ioc.junit.TapestryIOCJUnit4ClassRunner;
-import org.apache.tapestry5.ioc.junit.TapestryIOCJUnit4ClassRunnerModuleDefTest.ModuleDefTestModule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-@RunWith(TapestryIOCJUnit4ClassRunner.class)
-@Registry(modules=ModuleDefTestModule.class)
-public class TapestryIOCJUnit4ClassRunnerModuleDefTest {
- @ModuleDef
- public static MapModuleDef createModuleDef1() {
- Map<String,Object> map = new HashMap<String, Object>();
- map.put("a", new Date(111));
- map.put("b", 222L);
-
- return new MapModuleDef(map);
- }
-
- @ModuleDef
- public static org.apache.tapestry5.ioc.def.ModuleDef createModuleDef2() {
- Map<String,Object> map = new HashMap<String, Object>();
- map.put("c", 333);
-
- return new MapModuleDef(map);
- }
-
- public static class ModuleDefTestModule {
- public String buildD() {
- return "444";
- }
- }
-
- @Inject private Date a;
- @Inject private Long b;
- @Inject private Integer c;
- @Inject private String d;
-
- @Test
- public void testModuleDefInject() {
- assertEquals(new Date(111), a);
- assertEquals(new Long(222L), b);
- assertEquals(new Integer(333), c);
- assertEquals("444", d);
- }
-}
\ No newline at end of file
diff --git a/tapestry-ioc-junit/src/test/java/org/apache/tapestry5/ioc/junit/TapestryIOCJUnit5AfterClassTest.java b/tapestry-ioc-junit/src/test/java/org/apache/tapestry5/ioc/junit/TapestryIOCJUnit5AfterClassTest.java
new file mode 100644
index 000000000..40a894e11
--- /dev/null
+++ b/tapestry-ioc-junit/src/test/java/org/apache/tapestry5/ioc/junit/TapestryIOCJUnit5AfterClassTest.java
@@ -0,0 +1,74 @@
+// Copyright 2006–2025 The Apache Software Foundation
+//
+// 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 org.apache.tapestry5.ioc.junit;
+
+import static org.junit.jupiter.api.Assertions.assertArrayEquals;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.tapestry5.ioc.annotations.Inject;
+import org.apache.tapestry5.ioc.junit.TapestryIOCJUnit5AfterClassTest.AfterClassTestModule;
+import org.junit.jupiter.api.MethodOrderer.OrderAnnotation;
+import org.junit.jupiter.api.Order;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.TestMethodOrder;
+import org.junit.jupiter.api.extension.ExtendWith;
+
+@ExtendWith(TapestryIOCJUnitExtension.class)
+@Registry(modules = AfterClassTestModule.class, shutdown = RegistryShutdownType.AFTER_CLASS)
+@TestMethodOrder(OrderAnnotation.class)
+public class TapestryIOCJUnit5AfterClassTest
+{
+
+ public static class AfterClassTestModule
+ {
+ public List<String> buildList()
+ {
+ List<String> list = new ArrayList<>();
+ list.add("foo");
+ return list;
+ }
+ }
+
+ @Inject
+ private List<String> list;
+
+ @Test
+ @Order(1)
+ public void testInjectA()
+ {
+ assertArrayEquals(new Object[]
+ { "foo" }, list.toArray());
+ list.add("bar");
+ }
+
+ @Test
+ @Order(2)
+ public void testInjectB()
+ {
+ assertArrayEquals(new Object[]
+ { "foo", "bar" }, list.toArray());
+ list.add("baz");
+ }
+
+ @Test
+ @Order(3)
+ public void testInjectC()
+ {
+ assertArrayEquals(new Object[]
+ { "foo", "bar", "baz" }, list.toArray());
+ }
+}
\ No newline at end of file
diff --git a/tapestry-ioc-junit/src/test/java/org/apache/tapestry5/ioc/junit/TapestryIOCJUnit5AfterMethodTest.java b/tapestry-ioc-junit/src/test/java/org/apache/tapestry5/ioc/junit/TapestryIOCJUnit5AfterMethodTest.java
new file mode 100644
index 000000000..c41dab760
--- /dev/null
+++ b/tapestry-ioc-junit/src/test/java/org/apache/tapestry5/ioc/junit/TapestryIOCJUnit5AfterMethodTest.java
@@ -0,0 +1,69 @@
+// Copyright 2006–2025 The Apache Software Foundation
+//
+// 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 org.apache.tapestry5.ioc.junit;
+
+import static org.junit.jupiter.api.Assertions.assertArrayEquals;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.tapestry5.ioc.annotations.Inject;
+import org.junit.jupiter.api.MethodOrderer;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.TestMethodOrder;
+import org.junit.jupiter.api.extension.ExtendWith;
+
+@ExtendWith(TapestryIOCJUnitExtension.class)
+@Registry(modules = TapestryIOCJUnit5AfterMethodTest.AfterMethodTestModule.class, shutdown = RegistryShutdownType.AFTER_METHOD)
+@TestMethodOrder(MethodOrderer.MethodName.class)
+public class TapestryIOCJUnit5AfterMethodTest
+{
+
+ public static class AfterMethodTestModule
+ {
+ public List<String> buildList()
+ {
+ List<String> list = new ArrayList<>();
+ list.add("foo");
+ return list;
+ }
+ }
+
+ @Inject
+ private List<String> list;
+
+ @Test
+ void testInjectA()
+ {
+ assertArrayEquals(new Object[]
+ { "foo" }, list.toArray());
+ list.add("bar");
+ }
+
+ @Test
+ void testInjectB()
+ {
+ assertArrayEquals(new Object[]
+ { "foo" }, list.toArray());
+ list.add("baz");
+ }
+
+ @Test
+ void testInjectC()
+ {
+ assertArrayEquals(new Object[]
+ { "foo" }, list.toArray());
+ }
+}
diff --git a/tapestry-ioc-junit/src/test/java/org/apache/tapestry5/ioc/junit/TapestryIOCJUnit5ModuleDefTest.java b/tapestry-ioc-junit/src/test/java/org/apache/tapestry5/ioc/junit/TapestryIOCJUnit5ModuleDefTest.java
new file mode 100644
index 000000000..dabbb69bf
--- /dev/null
+++ b/tapestry-ioc-junit/src/test/java/org/apache/tapestry5/ioc/junit/TapestryIOCJUnit5ModuleDefTest.java
@@ -0,0 +1,74 @@
+// Copyright 2006–2025 The Apache Software Foundation
+//
+// 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 org.apache.tapestry5.ioc.junit;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.tapestry5.ioc.annotations.Inject;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+
+@ExtendWith(TapestryIOCJUnitExtension.class)
+@Registry(modules = TapestryIOCJUnit5ModuleDefTest.ModuleDefTestModule.class)
+public class TapestryIOCJUnit5ModuleDefTest
+{
+
+ @ModuleDef
+ public static org.apache.tapestry5.ioc.def.ModuleDef createModuleDef1()
+ {
+ Map<String, Object> map = new HashMap<>();
+ map.put("a", new Date(111));
+ map.put("b", 222L);
+ return new MapModuleDef(map);
+ }
+
+ @ModuleDef
+ public static org.apache.tapestry5.ioc.def.ModuleDef createModuleDef2()
+ {
+ Map<String, Object> map = new HashMap<>();
+ map.put("c", 333);
+ return new MapModuleDef(map);
+ }
+
+ public static class ModuleDefTestModule
+ {
+ public String buildD()
+ {
+ return "444";
+ }
+ }
+
+ @Inject
+ private Date a;
+ @Inject
+ private Long b;
+ @Inject
+ private Integer c;
+ @Inject
+ private String d;
+
+ @Test
+ void testModuleDefInject()
+ {
+ assertEquals(new Date(111), a);
+ assertEquals(Long.valueOf(222L), b);
+ assertEquals(Integer.valueOf(333), c);
+ assertEquals("444", d);
+ }
+}
diff --git a/tapestry-jmx/src/test/conf/testng.xml b/tapestry-jmx/src/test/resources/testng.xml
similarity index 100%
rename from tapestry-jmx/src/test/conf/testng.xml
rename to tapestry-jmx/src/test/resources/testng.xml
diff --git a/tapestry-jpa/build.gradle b/tapestry-jpa/build.gradle
index 58c723e7b..5e402d261 100644
--- a/tapestry-jpa/build.gradle
+++ b/tapestry-jpa/build.gradle
@@ -15,6 +15,7 @@ def moduleLibs = [
dependencies {
implementation project(':tapestry-core')
+ api libs.javax.persistence.api
implementation moduleLibs.jpaSpecs
implementation moduleLibs.javaxCdiApi
diff --git a/tapestry-jpa/src/test/java/org/apache/tapestry5/jpa/integration/app5/DummyEntityManager.java b/tapestry-jpa/src/test/java/org/apache/tapestry5/jpa/integration/app5/DummyEntityManager.java
index 75697ab4e..e4d3df4e8 100644
--- a/tapestry-jpa/src/test/java/org/apache/tapestry5/jpa/integration/app5/DummyEntityManager.java
+++ b/tapestry-jpa/src/test/java/org/apache/tapestry5/jpa/integration/app5/DummyEntityManager.java
@@ -14,17 +14,22 @@
package org.apache.tapestry5.jpa.integration.app5;
+import java.util.List;
import java.util.Map;
+import javax.persistence.EntityGraph;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.FlushModeType;
import javax.persistence.LockModeType;
import javax.persistence.Query;
+import javax.persistence.StoredProcedureQuery;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
+import javax.persistence.criteria.CriteriaDelete;
import javax.persistence.criteria.CriteriaQuery;
+import javax.persistence.criteria.CriteriaUpdate;
import javax.persistence.metamodel.Metamodel;
public class DummyEntityManager implements EntityManager
@@ -276,5 +281,71 @@ public class DummyEntityManager implements EntityManager
{
return null;
}
+
+ @Override
+ public Query createQuery(CriteriaUpdate updateQuery)
+ {
+ return null;
+ }
+
+ @Override
+ public Query createQuery(CriteriaDelete deleteQuery)
+ {
+ return null;
+ }
+
+ @Override
+ public StoredProcedureQuery createNamedStoredProcedureQuery(String name)
+ {
+ return null;
+ }
+
+ @Override
+ public StoredProcedureQuery createStoredProcedureQuery(String procedureName)
+ {
+ return null;
+ }
+
+ @Override
+ public StoredProcedureQuery createStoredProcedureQuery(String procedureName, Class... resultClasses)
+ {
+ return null;
+ }
+
+ @Override
+ public StoredProcedureQuery createStoredProcedureQuery(String procedureName, String... resultSetMappings)
+ {
+ return null;
+ }
+
+ @Override
+ public boolean isJoinedToTransaction()
+ {
+ return false;
+ }
+
+ @Override
+ public <T> EntityGraph<T> createEntityGraph(Class<T> rootType)
+ {
+ return null;
+ }
+
+ @Override
+ public EntityGraph<?> createEntityGraph(String graphName)
+ {
+ return null;
+ }
+
+ @Override
+ public EntityGraph<?> getEntityGraph(String graphName)
+ {
+ return null;
+ }
+
+ @Override
+ public <T> List<EntityGraph<? super T>> getEntityGraphs(Class<T> entityClass)
+ {
+ return null;
+ }
}
diff --git a/tapestry-jpa/src/test/java/org/apache/tapestry5/jpa/integration/app5/DummyEntityManagerFactory.java b/tapestry-jpa/src/test/java/org/apache/tapestry5/jpa/integration/app5/DummyEntityManagerFactory.java
index f4ab8da50..c1206326e 100644
--- a/tapestry-jpa/src/test/java/org/apache/tapestry5/jpa/integration/app5/DummyEntityManagerFactory.java
+++ b/tapestry-jpa/src/test/java/org/apache/tapestry5/jpa/integration/app5/DummyEntityManagerFactory.java
@@ -15,9 +15,12 @@
package org.apache.tapestry5.jpa.integration.app5;
import javax.persistence.Cache;
+import javax.persistence.EntityGraph;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.PersistenceUnitUtil;
+import javax.persistence.Query;
+import javax.persistence.SynchronizationType;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.metamodel.Metamodel;
import java.util.Map;
@@ -78,4 +81,34 @@ final class DummyEntityManagerFactory implements EntityManagerFactory
{
}
+
+ @Override
+ public EntityManager createEntityManager(SynchronizationType synchronizationType)
+ {
+ return null;
+ }
+
+ @Override
+ public EntityManager createEntityManager(SynchronizationType synchronizationType, Map map)
+ {
+ return null;
+ }
+
+ @Override
+ public void addNamedQuery(String name, Query query)
+ {
+
+ }
+
+ @Override
+ public <T> T unwrap(Class<T> cls)
+ {
+ return null;
+ }
+
+ @Override
+ public <T> void addNamedEntityGraph(String graphName, EntityGraph<T> entityGraph)
+ {
+
+ }
}
diff --git a/tapestry-jpa/src/test/java/org/apache/tapestry5/jpa/integration/app5/DummyPersistenceProvider.java b/tapestry-jpa/src/test/java/org/apache/tapestry5/jpa/integration/app5/DummyPersistenceProvider.java
index 723b67768..240cbae6c 100644
--- a/tapestry-jpa/src/test/java/org/apache/tapestry5/jpa/integration/app5/DummyPersistenceProvider.java
+++ b/tapestry-jpa/src/test/java/org/apache/tapestry5/jpa/integration/app5/DummyPersistenceProvider.java
@@ -41,4 +41,15 @@ public class DummyPersistenceProvider implements PersistenceProvider
return null;
}
+ @Override
+ public void generateSchema(PersistenceUnitInfo info, Map map)
+ {
+
+ }
+
+ @Override
+ public boolean generateSchema(String persistenceUnitName, Map map)
+ {
+ return false;
+ }
}
diff --git a/tapestry-jpa/src/test/conf/testng.xml b/tapestry-jpa/src/test/resources/testng.xml
similarity index 100%
rename from tapestry-jpa/src/test/conf/testng.xml
rename to tapestry-jpa/src/test/resources/testng.xml
diff --git a/tapestry-json/src/test/conf/testng.xml b/tapestry-json/src/test/conf/testng.xml
deleted file mode 100644
index ab3857602..000000000
--- a/tapestry-json/src/test/conf/testng.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
-<suite name="Tapestry JSON" annotations="1.5" verbose="2">
- <test name="Unit Tests" enabled="true">
- <packages>
- <package name="org.apache.tapestry5.json"/>
- </packages>
- </test>
-</suite>
diff --git a/tapestry-json/src/test/groovy/json/specs/CoercionsSpec.groovy b/tapestry-json/src/test/groovy/json/specs/CoercionsSpec.groovy
deleted file mode 100644
index d7c1d1494..000000000
--- a/tapestry-json/src/test/groovy/json/specs/CoercionsSpec.groovy
+++ /dev/null
@@ -1,29 +0,0 @@
-package json.specs
-
-import org.apache.tapestry5.internal.json.StringToJSONArray
-import org.apache.tapestry5.internal.json.StringToJSONObject
-import org.apache.tapestry5.json.JSONArray
-import org.apache.tapestry5.json.JSONObject
-import spock.lang.Specification
-
-class CoercionsSpec extends Specification {
-
- def "string to JSONObject"() {
- def json = /{foo:"bar"}/
- def expected = new JSONObject(json)
-
- expect:
-
- new StringToJSONObject().coerce(json) == expected
- }
-
- void "string to JSONArray"() {
-
- def json = /[1, 2, 'three']/
- def expected = new JSONArray(json)
-
- expect:
-
- new StringToJSONArray().coerce(json) == expected
- }
-}
diff --git a/tapestry-json/src/test/groovy/json/specs/JSONArraySpec.groovy b/tapestry-json/src/test/groovy/json/specs/JSONArraySpec.groovy
deleted file mode 100644
index 52419cc7e..000000000
--- a/tapestry-json/src/test/groovy/json/specs/JSONArraySpec.groovy
+++ /dev/null
@@ -1,639 +0,0 @@
-package json.specs
-
-import org.apache.tapestry5.json.JSONArray
-import org.apache.tapestry5.json.JSONLiteral
-import org.apache.tapestry5.json.JSONObject
-import org.apache.tapestry5.json.exceptions.JSONArrayIndexOutOfBoundsException
-import org.apache.tapestry5.json.exceptions.JSONInvalidTypeException
-import org.apache.tapestry5.json.exceptions.JSONSyntaxException
-import org.apache.tapestry5.json.exceptions.JSONTypeMismatchException
-
-import spock.lang.Specification
-
-class JSONArraySpec extends Specification {
-
- def "can create a JSONArray by parsing a JSON string"() {
- when:
-
- def array = new JSONArray(/[ 'foo', 'bar', "baz" ]/)
-
- then:
-
- array.size() == 3
- array.get(0) == "foo"
- array.get(1) == "bar"
- array.get(2) == "baz"
- }
-
- def "create a JSONArray from varags"() {
- when:
-
- def array = new JSONArray("fred", "barney", "wilma")
-
- then:
-
- array.size() == 3
-
- array.toCompactString() == /["fred","barney","wilma"]/
- }
-
- def "array must start with a bracket"() {
- when:
-
- new JSONArray("1, 2, 3]")
-
- then:
-
- JSONSyntaxException e = thrown()
-
- e.message == "A JSONArray text must start with '[' (actual: '1') at character 1 of 1, 2, 3]"
- }
-
- def "parse an empty array"() {
- when:
-
- def array = new JSONArray("[]")
-
- then:
-
- array.isEmpty()
- }
-
- def "isEmpty() is false if array is non-empty"() {
- when:
-
- def array = new JSONArray("[1]")
-
- then:
-
- array.isEmpty() == false
- }
-
- def "isEmpty() == zero length == zero size"() {
- when:
-
- def array = new JSONArray("[]")
-
- then:
-
- array.isEmpty()
- array.length() == 0
- array.size() == 0
- }
-
- def "an empty element in the parse is a null"() {
- when:
-
- def array = new JSONArray("[1,,3]")
-
- then:
-
- array.size() == 3
- array.getInt(0) == 1
- array.isNull(1)
- array.getInt(2) == 3
- }
-
- def "a comma at the end of the list is ignored"() {
- when:
-
- def array = new JSONArray("[1,2,]")
-
- then:
-
- array.size() == 2
- array.get(0) == 1
- array.get(1) == 2
- }
-
- def "getBoolean() when not a boolean at index is an exception"() {
- def array = new JSONArray("[123]")
-
- when:
-
- array.getBoolean(0)
-
- then:
-
- JSONTypeMismatchException e = thrown()
-
- e.message == "JSONArray[0] is not a BOOLEAN. Actual: java.lang.Integer"
- }
-
- def "handling of boolean values passed into constructor"() {
- when:
-
- def array = new JSONArray(true, false, "True", "False")
-
- then:
-
- array.getBoolean(0) == true
- array.getBoolean(1) == false
-
- array.getBoolean(2) == true
- array.getBoolean(3) == false
- }
-
- def "getDouble() when not a double at index is an exception"() {
- def array = new JSONArray(true)
-
- when:
-
- array.getDouble(0)
-
- then:
-
- JSONTypeMismatchException e = thrown()
-
- e.message == "JSONArray[0] is not a NUMBER. Actual: java.lang.Boolean"
- }
-
- def "getDouble() works with numbers and parseable strings"() {
- def array = new JSONArray(400l, "95.5")
-
- expect:
-
- array.getDouble(0) == 400d
- array.getDouble(1) == 95.5d
- }
-
- def "getLong() works with numbers and parseable strings"() {
- def array = new JSONArray(400l, "95.5")
-
- expect:
-
- array.getLong(0) == 400l
- array.getLong(1) == 95l
- }
-
- def "getJSONArray() when not an array at index is exception"() {
- def array = new JSONArray("fred", "barney")
-
- when:
-
- array.getJSONArray(1)
-
- then:
-
- JSONTypeMismatchException e = thrown()
-
- e.message == "JSONArray[1] is not a ARRAY. Actual: java.lang.String"
- }
-
- def "get a nested array"() {
- def nested = new JSONArray()
- def outer = new JSONArray(nested)
-
- expect:
-
- outer.getJSONArray(0).is(nested)
- }
-
- def "getJSONObject() when not a JSONObject at index is an exception"() {
- def array = new JSONArray("fred", "barney", "wilma")
-
- when:
-
- array.getJSONObject(1)
-
- then:
-
- JSONTypeMismatchException e = thrown()
-
- e.message == "JSONArray[1] is not a OBJECT. Actual: java.lang.String"
- }
-
- def "may not put at a negative index"() {
- def array = new JSONArray()
-
- when:
-
- array.put(-2, "fred")
-
- then:
-
- JSONArrayIndexOutOfBoundsException e = thrown()
-
- e.index == -2
- }
-
- def "put() overrides existing value in array"() {
- def array = new JSONArray("fred", "barney", "wilma")
-
- when:
-
- array.put 2, "betty"
-
- then:
-
- array.get(2) == "betty"
- }
-
- def "put() with index past end pads array with nulls"() {
- def array = new JSONArray("fred", "barney", "wilma")
-
- when:
-
- array.put 4, "bambam"
-
- then:
-
- array.isNull(3)
-
- array.toCompactString() == /["fred","barney","wilma",null,"bambam"]/
- }
-
- def "array equality"() {
- when:
-
- def array1 = new JSONArray(1, 2, 3)
- def array2 = new JSONArray(1, 2, 3)
-
- then:
-
- array1 == array1
- !array1.equals(null)
- array1 != this
- array1 == array2
-
- when:
-
- array2.put 9, "stuff"
-
- then:
-
- array1 != array2
- }
-
- def "array hashCode"() {
- when:
-
- def array1 = new JSONArray(1, 2, 3)
- def array2 = new JSONArray(1, 2, 3)
-
- then:
-
- array1.hashCode() == array2.hashCode()
-
- when:
-
- array2.put 9, "stuff"
-
- then:
-
- array1.hashCode() != array2.hashCode()
- }
-
- def "pretty print"() {
- def array = new JSONArray("fred", "barney")
-
- expect:
-
- array.toString() == '''[
- "fred",
- "barney"
-]'''
- }
-
- def "JSONArray is Iterable"() {
- def array = new JSONArray(1, 2, false)
-
- when:
-
- def i = array.iterator()
-
- then:
-
- i.next() == 1
- i.next() == 2
- i.next() == false
-
- !i.hasNext()
- }
-
- def "remove an element by index"() {
- def array = new JSONArray("one", "two", "three")
-
- when:
-
- array.remove(1)
-
- then:
-
- array.size() == 2
- array.toCompactString() == /["one","three"]/
- }
-
- def "remove an element by value"() {
- def array = new JSONArray("one", "two", "three")
-
- when:
-
- def result = array.remove("one")
-
- then:
-
- result == true
- array.size() == 2
- array.toCompactString() == /["two","three"]/
- }
-
- def "remove an element by value - not found"() {
- def array = new JSONArray("one", "two", "three")
-
- when:
-
- def result = array.remove("four")
-
- then:
-
- result == false
- array.size() == 3
- array.toCompactString() == /["one","two","three"]/
- }
-
- def "remove all elements by collection"() {
- def array = new JSONArray("one", "two", "three")
-
- when:
-
- def result = array.removeAll(["one", "three"])
-
- then:
-
- result == true
- array.size() == 1
- array.toCompactString() == /["two"]/
- }
-
- def "remove all elements by collection - partial"() {
- def array = new JSONArray("one", "two", "three")
-
- when:
-
- def result = array.removeAll(["one", "four"])
-
- then:
-
- result == true
- array.size() == 2
- array.toCompactString() == /["two","three"]/
- }
-
- def "remove all elements by collection - none found"() {
- def array = new JSONArray("one", "two", "three")
-
- when:
-
- def result = array.removeAll(["four", "five"])
-
- then:
-
- result == false
- array.size() == 3
- array.toCompactString() == /["one","two","three"]/
- }
-
- def "retain all elements by collection - all"() {
- def array = new JSONArray("one", "two", "three")
-
- when:
-
- def result = array.retainAll(["one", "two", "three"])
-
- then:
-
- result == false
- array.size() == 3
- array.toCompactString() == /["one","two","three"]/
- }
-
- def "retain all elements by collection - partial"() {
- def array = new JSONArray("one", "two", "three")
-
- when:
-
- def result = array.retainAll(["one", "three"])
-
- then:
-
- result == true
- array.size() == 2
- array.toCompactString() == /["one","three"]/
- }
-
- def "retain all elements by collection - none"() {
- def array = new JSONArray("one", "two", "three")
-
- when:
-
- def result = array.retainAll(["four", "five"])
-
- then:
-
- result == true
- array.isEmpty()
- array.toCompactString() == /[]/
- }
-
- def "putAll() adds new objects to existing array"() {
- def array = new JSONArray(100, 200)
-
- when:
-
- array.putAll([300, 400, 500])
-
- then:
-
- array.toCompactString() == /[100,200,300,400,500]/
- }
-
- def "putAll() with null does not modify the array"() {
- def array = new JSONArray(100, 200)
-
- when:
-
- array.putAll(null)
-
- then:
-
- array.toCompactString() == /[100,200]/
- }
-
-
- def "addAll() adds new objects to existing array"() {
- def array = new JSONArray(100, 200)
-
- when:
-
- array.addAll([300, 400, 500])
-
- then:
-
- array.toCompactString() == /[100,200,300,400,500]/
- }
-
-
- def "addAll() returns true if changed"() {
- def array = new JSONArray(100, 200)
-
- when:
-
- def result = array.addAll([300, 400, 500])
-
- then:
-
- result == true
- }
-
- def "addAll() returns false if not changed"() {
- def array = new JSONArray(100, 200)
-
- when:
-
- def result = array.addAll((Collection)null)
-
- then:
-
- result == false
- }
-
- def "list returned by toList() is unmodifiable"() {
- def array = new JSONArray(100, 200)
- def list = array.toList()
-
- when:
-
- list.clear()
-
- then:
-
- thrown(UnsupportedOperationException)
- }
-
- def "list from toList() is live"() {
- def array = new JSONArray(100, 200)
- when:
-
- def list = array.toList()
-
- then:
-
- list == [100, 200]
-
- when:
-
- array.remove(0)
-
- then:
-
- list == [200]
- }
-
- def "can initialize JSONObject from an Iterable"() {
- when:
-
- def list = JSONArray.from([1, 2, 3])
-
- then:
-
- list.toString(true) == "[1,2,3]"
- }
-
- def "put() should throw an IllegalArgumentException when receiving null"() {
-
- def array = new JSONArray()
-
- when:
-
- array.put(null)
-
- then:
-
- thrown IllegalArgumentException
- }
-
- def "new JSONArray() should throw an IllegalArgumentException when receiving null"() {
-
- when:
-
- new JSONArray(1, null, 3)
-
- then:
-
- thrown IllegalArgumentException
- }
-
- def "only specific object types may be added - no exception"() {
- def array = new JSONArray()
-
- when:
-
- array.put(value)
-
- then:
-
- noExceptionThrown()
-
- where:
- value << [
- true,
- 3,
- 3.5,
- "*VALUE*",
- new JSONLiteral("*LITERAL*"),
- new JSONObject(),
- new JSONArray()
- ]
- }
-
- def "only specific object types may be added - exception"() {
- def array = new JSONArray()
-
- when:
-
- array.put(value)
-
- then:
-
- JSONInvalidTypeException e = thrown()
-
- where:
- value << [
- new java.util.Date(),
- [],
- [:]
- ]
- }
-
- def "array index out of bounds must throw informative exception"() {
- def array = new JSONArray(1, 2, 3)
-
- when:
-
- array.get(array.size())
-
- then:
-
- JSONArrayIndexOutOfBoundsException e = thrown()
- e.index == 3
- }
-
- def "non-finite / NaN Double not allowed in constructor"() {
-
- when:
-
- new JSONArray(value)
-
- then:
-
- RuntimeException e = thrown()
-
- where:
- value << [
- Double.POSITIVE_INFINITY,
- Double.NEGATIVE_INFINITY,
- Double.NaN
- ]
- }
-}
diff --git a/tapestry-json/src/test/groovy/json/specs/JSONCollectorsSpec.groovy b/tapestry-json/src/test/groovy/json/specs/JSONCollectorsSpec.groovy
deleted file mode 100644
index a8c452312..000000000
--- a/tapestry-json/src/test/groovy/json/specs/JSONCollectorsSpec.groovy
+++ /dev/null
@@ -1,101 +0,0 @@
-package json.specs
-
-import org.apache.tapestry5.json.JSONCollectors
-import org.apache.tapestry5.json.exceptions.JSONInvalidTypeException
-
-import java.util.stream.Stream
-
-import spock.lang.Specification
-
-class JSONCollectorsSpec extends Specification {
-
- def "collect stream to array"() {
-
- given:
-
- def stringValue = "a string value"
- def longValue = 3L
-
- def stream = Stream.of(stringValue, longValue)
-
- when:
-
- def collected = stream.collect(JSONCollectors.toArray());
-
- then:
-
- collected.size() == 2
- collected.get(0) == stringValue
- collected.get(1) == longValue
- }
-
- def "collect stream to array invalid type"() {
-
- given:
-
- def stringValue = "a string value"
- def longValue = 3L
- def invalidValue = new java.util.Date()
-
- def stream = Stream.of(stringValue, longValue, invalidValue)
-
- when:
-
- def collected = stream.collect(JSONCollectors.toArray());
-
- then:
-
- JSONInvalidTypeException e = thrown()
- }
-
- def "collect stream to map"() {
-
- given:
-
- def first = new Tuple("first key", "a string value")
- def second = new Tuple("second key", 3L)
-
- def stream = Stream.of(first, second)
-
- when:
-
- def collected = stream.collect(JSONCollectors.toMap({ t -> t.get(0) }, { t -> t.get(1) }));
-
- then:
-
- collected.size() == 2
- collected.get(first.get(0)) == first.get(1)
- collected.get(second.get(0)) == second.get(1)
- }
-
- def "collect stream to map invalid type"() {
-
- given:
-
- def first = new Tuple("first key", "a string value")
- def second = new Tuple("second key", 3L)
- def third = new Tuple("invalid type", new java.util.Date())
-
- def stream = Stream.of(first, second, third)
-
- when:
-
- def collected = stream.collect(JSONCollectors.toMap({ t -> t.get(0) }, { t -> t.get(1) }));
-
- then:
-
- JSONInvalidTypeException e = thrown()
- }
-
- def "collect stream to map duplicate key"() {
-
- when:
-
- def collected = Stream.of("first", "second", "first").collect(JSONCollectors.toMap({ v -> v }, { v -> v }))
-
- then:
-
- IllegalStateException e = thrown()
- }
-
-}
diff --git a/tapestry-json/src/test/groovy/json/specs/JSONObjectSpec.groovy b/tapestry-json/src/test/groovy/json/specs/JSONObjectSpec.groovy
deleted file mode 100644
index 4d07bc605..000000000
--- a/tapestry-json/src/test/groovy/json/specs/JSONObjectSpec.groovy
+++ /dev/null
@@ -1,989 +0,0 @@
-package json.specs
-
-import org.apache.tapestry5.json.JSONArray
-import org.apache.tapestry5.json.JSONLiteral
-import org.apache.tapestry5.json.JSONObject
-import org.apache.tapestry5.json.JSONString
-import org.apache.tapestry5.json.exceptions.JSONInvalidTypeException
-import org.apache.tapestry5.json.exceptions.JSONSyntaxException
-import org.apache.tapestry5.json.exceptions.JSONTypeMismatchException
-import org.apache.tapestry5.json.exceptions.JSONValueNotFoundException
-
-import spock.lang.Issue
-import spock.lang.Specification
-import spock.lang.Unroll
-
-class JSONObjectSpec extends Specification {
-
- def "copy an existing JSONObject"() {
- def master = new JSONObject("fred", "flintstone", "barney", "rubble")
-
- when:
-
- def emptyCopy = new JSONObject(master)
-
- then:
-
- emptyCopy.keys().empty
-
- when:
-
- def limitedCopy = new JSONObject(master, "fred")
-
- then:
-
- limitedCopy.keys().size() == 1
- limitedCopy.get("fred") == "flintstone"
-
- when:
-
- def fullCopy = new JSONObject(master, "fred", "barney")
-
- then:
-
- fullCopy.toCompactString() == /{"fred":"flintstone","barney":"rubble"}/
- }
-
- def "copy all properties of JSONObject"() {
- def master = new JSONObject("fred", "flintstone", "barney", "rubble")
-
- when:
-
- def fullCopy = master.copy()
-
- then:
-
- master == fullCopy
-
- // And they are independent:
-
- when:
-
- master.put("wilma", "flintstone")
-
- then:
-
- master != fullCopy
- }
-
- def "unknown keys when copying a JSONObject are ignored"() {
- def master = new JSONObject("fred", "flintstone", "barney", "rubble")
-
- when:
-
- def copy = new JSONObject(master, "fred", "wilma")
-
- then:
-
- copy.keys().size() == 1
- copy.get("fred") == "flintstone"
- }
-
- def "get with unknown key is an exception"() {
- def master = new JSONObject("fred", "flintstone")
-
- when:
-
- master.get "barney"
-
- then:
-
- JSONValueNotFoundException e = thrown()
-
- e.message == /JSONObject["barney"] is not found. Required: ANY/
- }
-
- def "getOrDefault returns defaultValue if not found"() {
- def master = new JSONObject("fred", "flintstone")
-
- when:
-
- def result = master.getOrDefault "barney", "gumble"
-
- then:
-
- result == "gumble"
- }
-
- def "getOrDefault returns value if found"() {
- def master = new JSONObject("fred", "flintstone")
-
- when:
-
- def result = master.getOrDefault "fred", "other"
-
- then:
-
- result == "flintstone"
- }
-
- @Unroll
- def "ensure that stored value #typeName #value is #expectedTypeName #expected"() {
-
- when:
-
- def object = new JSONObject().put("key", value)
-
- then:
-
- object."get${expectedTypeName.capitalize()}"("key") == expected
-
- where:
-
- value | expected | expectedType
- "true" | true | boolean
- "TRUE" | true | boolean
- "false" | false | boolean
- "FALSE" | false | boolean
- Boolean.TRUE | true | boolean
- Boolean.FALSE | false | boolean
- 3.5d | 3.5d | double
- 1000l | 1000d | double
- "-101.7" | -101.7d | double
- "3" | 3 | int
- 97l | 97 | int
- "-8.76" | -8 | int
- 92d | 92l | long
- "-200" | -200l | long
- 123 | "123" | String
-
- typeName = value.class.simpleName
- expectedTypeName = expectedType.simpleName
- }
-
- @Unroll
- def "conversion of double #input to string should be '#expected'"() {
- expect:
-
- JSONObject.doubleToString(input) == expected
-
- where:
-
- input | expected
- 3d | "3"
- -22.5d | "-22.5"
- 0d | "0"
- Double.NaN | "null"
- Double.NEGATIVE_INFINITY | "null"
- Double.POSITIVE_INFINITY | "null"
- }
-
- def "exception when getBoolean() on a value that is not a boolean"() {
-
- def object = new JSONObject().put("akey", 37)
-
- when:
-
- object.getBoolean "akey"
-
- then:
-
- JSONTypeMismatchException e = thrown()
-
- e.message == /JSONObject["akey"] is not a BOOLEAN. Actual: java.lang.Integer/
- }
-
- def "accumulate simple values"() {
- def object = new JSONObject()
-
- def key = "acckey"
-
- when:
-
- object.accumulate key, "alpha"
-
- then: "first value added is just stored"
-
- object.toCompactString() == /{"acckey":"alpha"}/
-
- when: "subsequent values added are accumulated in a JSONArray"
-
- object.accumulate key, "beta"
- object.accumulate key, "gamma"
-
- then:
-
- object.toCompactString() == /{"acckey":["alpha","beta","gamma"]}/
-
- object.getJSONArray(key).length() == 3
- }
-
- def "accumulate when the stored value is already an array just appends the value"() {
- def object = new JSONObject()
-
- when:
-
- object.accumulate "key", new JSONArray("fred", "barney")
-
- then:
-
- object.toCompactString() == /{"key":["fred","barney"]}/
-
- when:
-
- object.accumulate "key", "wilma"
-
- then:
-
- object.toCompactString() == /{"key":["fred","barney","wilma"]}/
- }
-
- def "can create a JSONObject from a JSON string"() {
- when:
-
- def object = new JSONObject(/ { fred: "flintstone", caveman: true, friends: ["barney"] }/)
-
- then:
-
- object.get("fred") == "flintstone"
- object.getBoolean("caveman") == true
-
- def friends = object.getJSONArray "friends"
-
- friends.length() == 1
- friends.get(0) == "barney"
- }
-
- def "append to an unknown key creates a JSONArray for the value"() {
- def object = new JSONObject()
-
- when:
-
- object.append "friends", "barney"
-
- then:
-
- object.toCompactString() == /{"friends":["barney"]}/
- }
-
- def "append to an existing key containing a JSONArray appends to the array"() {
- def object = new JSONObject(/{friends: ["barney"] }/)
-
- when:
-
- object.append "friends", "zaphod"
-
- then:
-
- object.toCompactString() == /{"friends":["barney","zaphod"]}/
- }
-
- def "appending to a key whose value is not aArray is an exception"() {
- def object = new JSONObject(/{friends: 0 }/)
-
- when:
-
- object.append "friends", "zaphod"
-
- then:
-
- JSONTypeMismatchException e = thrown()
-
- e.message == /JSONObject["friends"] is not a ARRAY. Actual: java.lang.Integer/
- }
-
- def "getDouble() with a non-numeric value is an exception"() {
- def object = new JSONObject(/{notdouble: true}/)
-
- when:
-
- object.getDouble "notdouble"
-
- then:
-
- JSONTypeMismatchException e = thrown()
-
- e.message == /JSONObject["notdouble"] is not a NUMBER. Actual: java.lang.Boolean/
- }
-
- def "getDouble() with a string that can not be parsed as a number is an exception"() {
- def object = new JSONObject(/{notdouble: "this is a fact"}/)
-
- when:
-
- object.getDouble "notdouble"
-
- then:
-
- JSONTypeMismatchException e = thrown()
-
- e.message == /JSONObject["notdouble"] is not a NUMBER. Actual: java.lang.String/
- }
-
- def "has() will identify which keys have values and which do not"() {
- def object = new JSONObject(/{fred: 'flintstone'}/)
-
- expect:
-
- object.has("fred")
- !object.has("barney")
- }
-
- def "getJSONArray() for a value that is not aArray is an exception"() {
- def object = new JSONObject(/{notarray: 22.7}/)
-
- when:
-
- object.getJSONArray "notarray"
-
- then:
-
- RuntimeException e = thrown()
-
- e.message == /JSONObject["notarray"] is not a ARRAY. Actual: java.lang.Double/
- }
-
- def "length() of a JSONObject is the number of keys"() {
- when:
-
- def object = new JSONObject()
-
- then:
-
- object.length() == 0
-
- when:
-
- object.put "fred", "flintstone"
-
- then:
-
- object.length() == 1
-
- when:
-
- object.accumulate "fred", "murray"
-
- then:
-
- object.length() == 1
-
- when:
-
- object.put "barney", "rubble"
-
- then:
-
- object.length() == 2
- }
-
- def "names() returns the keys as a JSONArray"() {
- def object = new JSONObject(/ {fred: 'flintstone', barney: 'rubble' }/)
-
- when:
-
- def names = object.names()
-
- then:
-
- names instanceof JSONArray
- names.length() == 2
-
- new ArrayList(names.toList()).sort() == ["barney", "fred"]
- }
-
- def "names() with no properties returns null"() {
-
- when:
-
- def object = new JSONObject()
-
- then:
-
- object.names() == null
- }
-
- def "the null literal is the NULL object"() {
- when:
-
- def object = new JSONObject(/{nullkey: null}/)
-
- then:
-
- object.get("nullkey") is JSONObject.NULL
- object.isNull("nullkey")
- }
-
- def "the NULL object is output as null literal"() {
- when:
-
- def object = new JSONObject().put("nullkey", JSONObject.NULL)
-
- then:
-
- object.isNull("nullkey")
- object.toCompactString() == /{"nullkey":null}/
- }
-
- def "the NULL object matches Java's null"() {
- expect:
-
- JSONObject.NULL.equals(null)
- }
-
- @Unroll
- def "#desc invalid input is an exception"() {
- when:
-
- new JSONObject(input)
-
- then:
-
- JSONSyntaxException e = thrown()
-
- e.message.trim().startsWith expected
-
- where:
-
- input | expected | desc
- "{ " | "A JSONObject text must end with '}' at character 3" | "unmatched open brace"
- "fred" | /A JSONObject text must start with '{' (actual: 'f') at character 1 of/ | "missing open brace"
- /{ "akey" }/ | /Expected a ':' after a key at character 10 of/ | "missing value after key"
- /{ "fred" : 1 "barney" }/ | /Expected a ',' or '}' at character 14 of/ | "missing property separator"
- /{ "list" : [1, 2/ | /Expected a ',' or ']' at character 16 of/ | "missing seperator or closing bracket"
- '''/* unclosed''' | /Unclosed comment at character 11 of/ | "unclosed C-style comment"
- /{ "fred \n}/ | /Unterminated string at character 11 of/ | "unterminated string at line end"
- /{ fred: ,}/ | /Missing value at character 8 of / | "missing value after key"
- }
-
- def "can use ':' or '=>' as key seperator, and ';' as property separator"() {
- def object = new JSONObject(/{ "fred" = 1; "barney" => 2}/)
-
- expect:
-
- object.getInt("fred") == 1
- object.getInt("barney") == 2
- }
-
- @Unroll
- def "conversion of #typeName #value to string is #expected"() {
- expect:
-
- JSONObject.numberToString(value) == expected
-
- where:
-
- value | expected
- new BigDecimal("100.0000000") | "100"
-
- typeName = value.class.simpleName
- }
-
- @Unroll
- def "quote(): #desc"() {
- expect:
-
- JSONObject.quote(value) == expected
-
- where:
-
- value | expected | desc
- null | /""/ | "null is empty string"
- "" | /""/ | "empty string is empty string"
- '''"/\b\t\n\f\r\u2001/a</''' | '''"\\"/\\b\\t\\n\\f\\r\\u2001/a<\\/"''' | "special characters"
- }
-
- def "non-finite numbers are not allowed"() {
- def object = new JSONObject()
-
- when:
-
- object.put "nonfinite", value
-
- then:
-
- RuntimeException e = thrown()
-
- e.message == /JSON does not allow non-finite numbers./
-
- where:
-
- value << [
- Double.NaN,
- Double.NEGATIVE_INFINITY,
- Double.POSITIVE_INFINITY,
- Float.NaN,
- Float.NEGATIVE_INFINITY,
- Float.POSITIVE_INFINITY
- ]
- }
-
- def "parse an empty object is empty"() {
- when:
-
- def object = new JSONObject(/{}/)
-
- then:
-
- object.length() == 0
- }
-
- def "put a Java null is a remove"() {
- def object = new JSONObject(/{fred:'flintstone', barney:'rubble'}/)
-
- when:
-
- object.put("fred", null)
-
- then:
-
- object.toCompactString() == /{"barney":"rubble"}/
- }
-
- def "only specific object types may be added - no exception"() {
- def object = new JSONObject(/{}/)
-
- when:
-
- object.put("key", value)
-
- then:
-
- noExceptionThrown()
-
- where:
- value << [
- null,
- true,
- 3,
- 3.5,
- "*VALUE*",
- new JSONLiteral("*LITERAL*"),
- new JSONObject(),
- new JSONArray()
- ]
- }
-
- def "only specific object types may be added - exception"() {
- def object = new JSONObject(/{}/)
-
- when:
-
- object.put("key", value)
-
- then:
-
- JSONInvalidTypeException e = thrown()
-
- where:
- value << [
- new java.util.Date(),
- [],
- [:]
- ]
- }
-
- def "JSONString can output anything it wants"() {
- def string = { "*VALUE*" } as JSONString
-
- def object = new JSONObject()
-
- when:
-
- object.put("key", string)
-
- then:
-
- object.toCompactString() == /{"key":*VALUE*}/
- }
-
- def "equals() implementation"() {
- def json = /{ "key" : 99 }/
-
- when:
-
- def obj1 = new JSONObject(json)
- def obj2 = new JSONObject(json)
-
- then:
-
- obj1 == obj2
- obj2 == obj1
-
- obj1.equals(null) == false
- obj1 != json
-
- when:
-
- obj2.put("screw", "the pooch")
-
- then:
-
- obj1 != obj2
- }
-
- def "hashCode() implementation"() {
- def json = /{ "key" : 99 }/
-
- when:
-
- def obj1 = new JSONObject(json)
- def obj2 = new JSONObject(json)
-
- then:
-
- obj1.hashCode() == obj2.hashCode()
-
- when:
-
- obj2.put("screw", "the pooch")
-
- then:
-
- obj1.hashCode() != obj2.hashCode()
- }
-
- def "escaped characters in the JSON are parsed correctly"() {
- when:
-
- def object = new JSONObject("{ \"key\" : \"\\\"/\\b\\t\\n\\f\\r\\u2001/a<\\/\\x20\" }")
-
- then:
-
- object.get("key") == '''"/\b\t\n\f\r\u2001/a</ '''
- }
-
- def "parse a nested object"() {
- def object = new JSONObject(/ { key: { name: "inner" }}/)
-
- expect:
-
- object.getJSONObject("key").getString("name") == "inner"
- }
-
- def "parse boolean literals"() {
- def object = new JSONObject(/{ t: true, f: false }/)
-
- expect:
-
- object.getBoolean("t") == true
- object.getBoolean("f") == false
- }
-
- def "parse numeric forms"() {
- def object = new JSONObject(/{ hex: 0x50, oct: 030, posInt: +50, negInt: -50,
- long: 4294968530, float: -32.7 }/)
-
- expect:
-
- object.getInt("hex") == 80
- object.getInt("oct") == 24
- object.getInt("posInt") == 50
- object.getInt("negInt") == -50
- object.getLong("long") == 4294968530l
- object.getDouble("float") == -32.7d
- }
-
- def "NULL toString() is null keyword"() {
- expect:
-
- JSONObject.NULL.toString() == "null"
- }
-
- def "JSONLiteral can output any content"() {
-
- def text = '''function(x) { $('bar').show(); }'''
-
- def literal = new JSONLiteral(text)
-
- when:
-
- def object = new JSONObject().put("callback", literal)
-
- then:
-
- object.toCompactString() == /{"callback":${text}}/
- literal.toString() == text
- }
-
- def "pretty print"() {
- def object = new JSONObject("fred", "flintstone", "barney", "rubble")
-
- expect:
-
- object.toString() == '''{
- "fred" : "flintstone",
- "barney" : "rubble"
-}'''
- }
-
- def "C style comments are ignored"() {
- when:
-
- def object = new JSONObject('''/* C comment */ { "foo" : "bar" /* *ignored* */ }''')
-
- then:
-
- object.get("foo") == "bar"
- }
-
- def "double slash comments extend to end of line"() {
- when:
-
- def object = new JSONObject('''{ foo: // This is a double-slash comment
-"bar" }''')
-
- then:
-
- object.get("foo") == "bar"
- }
-
- def "hash comments extend to end of line"() {
- when:
-
- def object = new JSONObject('''{ foo: # This is a hash comment
-"bar" }''')
-
- then:
-
- object.get("foo") == "bar"
- }
-
- def "pretty-print an empty JSONObject"() {
- def object = new JSONObject()
-
- expect:
-
- object.toString() == /{}/
- }
-
- def "complex pretty-print"() {
- when:
-
- def object = new JSONObject('''
-{ outer: { inner: "here" },
- number: 22.7,
- array: [1, 2, 3],
- boolean: true,
- otherwise: 'a quoted string'
-}
-''')
-
- then:
-
- object.toString() == '''{
- "outer" : {
- "inner" : "here"
- },
- "number" : 22.7,
- "array" : [
- 1,
- 2,
- 3
- ],
- "boolean" : true,
- "otherwise" : "a quoted string"
-}'''
- }
-
- def "toCompactString()"() {
- def object = new JSONObject("kermit", "frog")
-
- expect:
-
- object.toString(true) == /{"kermit":"frog"}/
- object.toString(false) == /{
- "kermit" : "frog"
-}/
- }
-
- def "print to PrintWriter)"() {
- def object = new JSONObject("kermit", "frog")
-
- expect:
-
- print(object, true) == /{"kermit":"frog"}/
- print(object, false) == /{
- "kermit" : "frog"
-}/
- }
-
- def withPrintWriter(closure) {
- def caw = new CharArrayWriter()
- def pw = new PrintWriter(caw)
-
- closure(pw)
-
- pw.close()
-
- return caw.toString()
- }
-
- def print(object, compact) {
-
- withPrintWriter { pw -> object.print(pw, compact) }
- }
-
- def "prettyPrint() to PrintWriter"() {
- def object = new JSONObject("kermit", "frog")
-
- when:
-
- def json = withPrintWriter { pw -> object.prettyPrint(pw) }
-
- then:
-
- json == /{
- "kermit" : "frog"
-}/
- }
-
- def "getString() at index"() {
- def array = new JSONArray("one", 2, false)
-
- expect:
-
- array.getString(0) == "one"
- array.getString(1) == "2"
- array.getString(2) == "false"
- }
-
- def "toMap() is not modifiable"() {
- def object = new JSONObject()
-
- def map = object.toMap()
-
- when:
-
- map.clear()
-
- then:
-
- thrown(UnsupportedOperationException)
- }
-
- def "can access contents of object as a map"() {
- def object = new JSONObject("foo", "bar")
- .put("null", JSONObject.NULL)
- .put("number", 6)
-
- when:
-
- def map = object.toMap()
-
- then:
-
- map.foo == "bar"
- map.number == 6
- map["null"].is(JSONObject.NULL)
- }
-
- def "the map returned by toMap() is live"() {
- def object = new JSONObject("foo", "bar")
-
- def map = object.toMap()
-
- when:
-
- object.put "foo", null
-
- then:
-
- object.length() == 0
- map.isEmpty()
- }
-
- def "can add new properties via putAll()"() {
- def object = new JSONObject("fred", "flintstone")
-
- when:
-
- def result = object.putAll([barney: "rubble", wilma: "flintstone"])
-
- then:
-
- object.toCompactString() == /{"fred":"flintstone","barney":"rubble","wilma":"flintstone"}/
- }
-
- def "in() where the value is not JSONObject is an exception"() {
- def object = new JSONObject("time", "to rock")
-
- when:
-
- object.in("time")
-
- then:
-
- IllegalStateException e = thrown()
-
- e.message == /JSONObject["time"] is not a JSONObject./
- }
-
- def "in() creates a JSONObject if necessary"() {
- def object = new JSONObject()
-
- when:
-
- object.in("nested").put("created", true)
-
- then:
-
- object.toCompactString() == /{"nested":{"created":true}}/
- }
-
- def "in() returns the JSONObject"() {
- def object = new JSONObject(/{nested: {}}/)
-
- when:
-
- object.in("nested").put("time", "to rock")
-
- then:
-
- object.toCompactString() == /{"nested":{"time":"to rock"}}/
- }
-
- def "constructor supports non-string keys and values"() {
- when:
-
- def object = new JSONObject(true, "truthy", false, false)
-
- then:
-
- object.has "true"
- object.getString("true") == "truthy"
- object.has "false"
- object.get("false").is false
- }
-
- private static copyViaSerialization(source) {
-
- def bos = new ByteArrayOutputStream()
-
- bos.withObjectOutputStream { it << source }
-
- def bis = new ByteArrayInputStream(bos.toByteArray())
-
- bis.withObjectInputStream { it.readObject() }
- }
-
- def "serialize and de-serialize"() {
- when:
-
- def source = new JSONObject("string", "a string", "null", JSONObject.NULL)
-
- def copy = copyViaSerialization source
-
- then:
-
- source == copy
- }
-
- @Issue("TAP5-2759")
- def "getLongOrDefault correct type for default value"() {
- // This test seems obvious, but it fails if the getLongOrDefault method
- // isn't using long as the type for the default value in its method declaration
- given:
-
- def object = new JSONObject()
- def defaultValue = 2_147_483_648L
-
- when:
-
- def value = object.getLongOrDefault("key", defaultValue)
-
- then:
-
- value == defaultValue
- }
-}
diff --git a/tapestry-json/src/test/groovy/json/specs/JSONSpec.groovy b/tapestry-json/src/test/groovy/json/specs/JSONSpec.groovy
deleted file mode 100644
index 5b8ae3f31..000000000
--- a/tapestry-json/src/test/groovy/json/specs/JSONSpec.groovy
+++ /dev/null
@@ -1,36 +0,0 @@
-package json.specs
-
-import org.apache.tapestry5.json.JSONArray
-import org.apache.tapestry5.json.JSONLiteral
-import org.apache.tapestry5.json.JSONObject
-import org.apache.tapestry5.json.JSONString
-import org.apache.tapestry5.json.exceptions.JSONInvalidTypeException
-import org.apache.tapestry5.json.JSON
-import spock.lang.Specification
-import spock.lang.Unroll
-
-class JSONSpec extends Specification {
-
- def "invalid types throw JSONInvalidTypeException"() {
- when:
-
- JSON.testValidity([:])
-
- then:
-
- JSONInvalidTypeException e = thrown()
-
- e.message == '''JSONArray values / JSONObject properties may be one of Boolean, Number, String, org.apache.tapestry5.json.JSONArray, org.apache.tapestry5.json.JSONLiteral, org.apache.tapestry5.json.JSONObject, org.apache.tapestry5.json.JSONObject$Null, org.apache.tapestry5.json.JSONString. Type java.util.LinkedHashMap is not allowed.'''
- }
-
- def "null is invalid"() {
- when:
-
- JSON.testValidity(null)
-
- then:
-
- IllegalArgumentException e = thrown()
- }
-
-}
diff --git a/tapestry-json/src/test/java/org/apache/tapestry5/json/CoercionsTest.java b/tapestry-json/src/test/java/org/apache/tapestry5/json/CoercionsTest.java
new file mode 100644
index 000000000..1f516f83a
--- /dev/null
+++ b/tapestry-json/src/test/java/org/apache/tapestry5/json/CoercionsTest.java
@@ -0,0 +1,44 @@
+// Copyright 2025 The Apache Software Foundation
+//
+// 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 org.apache.tapestry5.json;
+
+import org.apache.tapestry5.internal.json.StringToJSONArray;
+import org.apache.tapestry5.internal.json.StringToJSONObject;
+import org.apache.tapestry5.json.JSONArray;
+import org.apache.tapestry5.json.JSONObject;
+
+import org.junit.jupiter.api.Test;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+public class CoercionsTest {
+
+ @Test
+ void stringToJSONObject() {
+ String jsonString = "{\"foo\":\"bar\"}";
+
+ JSONObject expected = new JSONObject(jsonString);
+
+ assertEquals(expected, new StringToJSONObject().coerce(jsonString));
+ }
+
+ @Test
+ void stringToJSONArray() {
+ String jsonString = "[1, 2, \"three\"]";
+
+ JSONArray expected = new JSONArray(jsonString);
+
+ assertEquals(expected, new StringToJSONArray().coerce(jsonString));
+ }
+}
\ No newline at end of file
diff --git a/tapestry-json/src/test/java/org/apache/tapestry5/json/JSONArrayTest.java b/tapestry-json/src/test/java/org/apache/tapestry5/json/JSONArrayTest.java
new file mode 100644
index 000000000..a05522ebe
--- /dev/null
+++ b/tapestry-json/src/test/java/org/apache/tapestry5/json/JSONArrayTest.java
@@ -0,0 +1,488 @@
+// Copyright 2010-2023, 2025 The Apache Software Foundation
+//
+// 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 org.apache.tapestry5.json;
+
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotEquals;
+import static org.junit.jupiter.api.Assertions.assertSame;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.stream.Stream;
+
+import org.apache.tapestry5.json.exceptions.JSONArrayIndexOutOfBoundsException;
+import org.apache.tapestry5.json.exceptions.JSONInvalidTypeException;
+import org.apache.tapestry5.json.exceptions.JSONSyntaxException;
+import org.apache.tapestry5.json.exceptions.JSONTypeMismatchException;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+
+public class JSONArrayTest {
+
+ @Test
+ void canCreateAJSONArrayByParsingAJSONString() {
+ String jsonString = "[ 'foo', 'bar', \"baz\" ]";
+
+ JSONArray array = new JSONArray(jsonString);
+
+ assertEquals(3, array.size());
+ assertEquals("foo", array.get(0));
+ assertEquals("bar", array.get(1));
+ assertEquals("baz", array.get(2));
+ }
+
+ @Test
+ void createAJSONArrayFromVarags() {
+ JSONArray array = new JSONArray("fred", "barney", "wilma");
+
+ assertEquals(3, array.size());
+ assertEquals("[\"fred\",\"barney\",\"wilma\"]", array.toCompactString());
+ }
+
+ @Test
+ void arrayMustStartWithABracket() {
+ JSONSyntaxException e = assertThrows(JSONSyntaxException.class, () -> {
+ new JSONArray("1, 2, 3]");
+ });
+
+ assertEquals("A JSONArray text must start with '[' (actual: '1') at character 1 of 1, 2, 3]", e.getMessage());
+ }
+
+ @Test
+ void parseAnEmptyArray() {
+ JSONArray array = new JSONArray("[]");
+ assertTrue(array.isEmpty());
+ }
+
+ @Test
+ void isEmptyIsFalseIfArrayIsNonEmpty() {
+ JSONArray array = new JSONArray("[1]");
+ assertFalse(array.isEmpty());
+ }
+
+ @Test
+ void isEmptyEqualsZeroLengthEqualsZeroSize() {
+ JSONArray array = new JSONArray("[]");
+
+ assertTrue(array.isEmpty());
+ assertEquals(0, array.length());
+ assertEquals(0, array.size());
+ }
+
+ @Test
+ void anEmptyElementInTheParseIsANull() {
+ JSONArray array = new JSONArray("[1,,3]");
+
+ assertEquals(3, array.size());
+ assertEquals(1, array.getInt(0));
+ assertTrue(array.isNull(1));
+ assertEquals(3, array.getInt(2));
+ }
+
+ @Test
+ void aCommaAtTheEndOfTheListIsIgnored() {
+ JSONArray array = new JSONArray("[1,2,]");
+
+ assertEquals(2, array.size());
+ assertEquals(1, array.get(0));
+ assertEquals(2, array.get(1));
+ }
+
+ @Test
+ void getBooleanWhenNotABooleanAtIndexIsAnException() {
+ JSONArray array = new JSONArray("[123]");
+
+ JSONTypeMismatchException e = assertThrows(JSONTypeMismatchException.class, () -> {
+ array.getBoolean(0);
+ });
+
+ assertEquals("JSONArray[0] is not a BOOLEAN. Actual: java.lang.Integer", e.getMessage());
+ }
+
+ @Test
+ void handlingOfBooleanValuesPassedIntoConstructor() {
+ JSONArray array = new JSONArray(true, false, "True", "False");
+
+ assertTrue(array.getBoolean(0));
+ assertFalse(array.getBoolean(1));
+ assertTrue(array.getBoolean(2));
+ assertFalse(array.getBoolean(3));
+ }
+
+ @Test
+ void getDoubleWhenNotADoubleAtIndexIsAnException() {
+ JSONArray array = new JSONArray(true);
+
+ JSONTypeMismatchException e = assertThrows(JSONTypeMismatchException.class, () -> {
+ array.getDouble(0);
+ });
+
+ assertEquals("JSONArray[0] is not a NUMBER. Actual: java.lang.Boolean", e.getMessage());
+ }
+
+ @Test
+ void getDoubleWorksWithNumbersAndParseableStrings() {
+ JSONArray array = new JSONArray(400L, "95.5");
+
+ assertEquals(400d, array.getDouble(0));
+ assertEquals(95.5d, array.getDouble(1));
+ }
+
+ @Test
+ void getLongWorksWithNumbersAndParseableStrings() {
+ JSONArray array = new JSONArray(400L, "95.5");
+
+ assertEquals(400L, array.getLong(0));
+ assertEquals(95L, array.getLong(1));
+ }
+
+ @Test
+ void getJSONArrayWhenNotAnArrayAtIndexIsException() {
+ JSONArray array = new JSONArray("fred", "barney");
+
+ JSONTypeMismatchException e = assertThrows(JSONTypeMismatchException.class, () -> {
+ array.getJSONArray(1);
+ });
+
+ assertEquals("JSONArray[1] is not a ARRAY. Actual: java.lang.String", e.getMessage());
+ }
+
+ @Test
+ void getANestedArray() {
+ JSONArray nested = new JSONArray();
+ JSONArray outer = new JSONArray(nested);
+
+ assertSame(nested, outer.getJSONArray(0));
+ }
+
+ @Test
+ void getJSONObjectWhenNotAJSONObjectAtIndexIsAnException() {
+ JSONArray array = new JSONArray("fred", "barney", "wilma");
+
+ JSONTypeMismatchException e = assertThrows(JSONTypeMismatchException.class, () -> {
+ array.getJSONObject(1);
+ });
+
+ assertEquals("JSONArray[1] is not a OBJECT. Actual: java.lang.String", e.getMessage());
+ }
+
+ @Test
+ void mayNotPutAtANegativeIndex() {
+ JSONArray array = new JSONArray();
+
+ JSONArrayIndexOutOfBoundsException e = assertThrows(JSONArrayIndexOutOfBoundsException.class, () -> {
+ array.put(-2, "fred");
+ });
+
+ assertEquals(-2, e.getIndex());
+ }
+
+ @Test
+ void putOverridesExistingValueInArray() {
+ JSONArray array = new JSONArray("fred", "barney", "wilma");
+ array.put(2, "betty");
+ assertEquals("betty", array.get(2));
+ }
+
+ @Test
+ void putWithIndexPastEndPadsArrayWithNulls() {
+ JSONArray array = new JSONArray("fred", "barney", "wilma");
+ array.put(4, "bambam");
+
+ assertTrue(array.isNull(3));
+ assertEquals("[\"fred\",\"barney\",\"wilma\",null,\"bambam\"]", array.toCompactString());
+ }
+
+ @Test
+ void arrayEquality() {
+ JSONArray array1 = new JSONArray(1, 2, 3);
+ JSONArray array2 = new JSONArray(1, 2, 3);
+
+ assertEquals(array1, array1);
+ assertNotEquals(null, array1);
+ assertNotEquals(this, array1);
+ assertEquals(array1, array2);
+
+ array2.put(9, "stuff");
+ assertNotEquals(array1, array2);
+ }
+
+ @Test
+ void arrayHashCode() {
+ JSONArray array1 = new JSONArray(1, 2, 3);
+ JSONArray array2 = new JSONArray(1, 2, 3);
+
+ assertEquals(array1.hashCode(), array2.hashCode());
+
+ array2.put(9, "stuff");
+ assertNotEquals(array1.hashCode(), array2.hashCode());
+ }
+
+ @Test
+ void prettyPrint() {
+ JSONArray array = new JSONArray("fred", "barney");
+ String expected = "[\n \"fred\",\n \"barney\"\n]";
+
+ assertEquals(expected, array.toString());
+ }
+
+ @Test
+ void JSONArrayIsIterable() {
+ JSONArray array = new JSONArray(1, 2, false);
+ Iterator<?> i = array.iterator();
+
+ assertEquals(1, i.next());
+ assertEquals(2, i.next());
+ assertEquals(false, i.next());
+ assertFalse(i.hasNext());
+ }
+
+ @Test
+ void removeAnElementByIndex() {
+ JSONArray array = new JSONArray("one", "two", "three");
+ array.remove(1);
+
+ assertEquals(2, array.size());
+ assertEquals("[\"one\",\"three\"]", array.toCompactString());
+ }
+
+ @Test
+ void removeAnElementByValue() {
+ JSONArray array = new JSONArray("one", "two", "three");
+ boolean result = array.remove("one");
+
+ assertTrue(result);
+ assertEquals(2, array.size());
+ assertEquals("[\"two\",\"three\"]", array.toCompactString());
+ }
+
+ @Test
+ void removeAnElementByValueNotFound() {
+ JSONArray array = new JSONArray("one", "two", "three");
+ boolean result = array.remove("four");
+
+ assertFalse(result);
+ assertEquals(3, array.size());
+ assertEquals("[\"one\",\"two\",\"three\"]", array.toCompactString());
+ }
+
+ @Test
+ void removeAllElementsByCollection() {
+ JSONArray array = new JSONArray("one", "two", "three");
+ boolean result = array.removeAll(Arrays.asList("one", "three"));
+
+ assertTrue(result);
+ assertEquals(1, array.size());
+ assertEquals("[\"two\"]", array.toCompactString());
+ }
+
+ @Test
+ void removeAllElementsByCollectionPartial() {
+ JSONArray array = new JSONArray("one", "two", "three");
+ boolean result = array.removeAll(Arrays.asList("one", "four"));
+
+ assertTrue(result);
+ assertEquals(2, array.size());
+ assertEquals("[\"two\",\"three\"]", array.toCompactString());
+ }
+
+ @Test
+ void removeAllElementsByCollectionNoneFound() {
+ JSONArray array = new JSONArray("one", "two", "three");
+ boolean result = array.removeAll(Arrays.asList("four", "five"));
+
+ assertFalse(result);
+ assertEquals(3, array.size());
+ assertEquals("[\"one\",\"two\",\"three\"]", array.toCompactString());
+ }
+
+ @Test
+ void retainAllElementsByCollectionAll() {
+ JSONArray array = new JSONArray("one", "two", "three");
+ boolean result = array.retainAll(Arrays.asList("one", "two", "three"));
+
+ assertFalse(result);
+ assertEquals(3, array.size());
+ assertEquals("[\"one\",\"two\",\"three\"]", array.toCompactString());
+ }
+
+ @Test
+ void retainAllElementsByCollectionPartial() {
+ JSONArray array = new JSONArray("one", "two", "three");
+ boolean result = array.retainAll(Arrays.asList("one", "three"));
+
+ assertTrue(result);
+ assertEquals(2, array.size());
+ assertEquals("[\"one\",\"three\"]", array.toCompactString());
+ }
+
+ @Test
+ void retainAllElementsByCollectionNone() {
+ JSONArray array = new JSONArray("one", "two", "three");
+ boolean result = array.retainAll(Arrays.asList("four", "five"));
+
+ assertTrue(result);
+ assertTrue(array.isEmpty());
+ assertEquals("[]", array.toCompactString());
+ }
+
+ @Test
+ void putAllAddsNewObjectsToExistingArray() {
+ JSONArray array = new JSONArray(100, 200);
+ array.putAll(Arrays.asList(300, 400, 500));
+
+ assertEquals("[100,200,300,400,500]", array.toCompactString());
+ }
+
+ @Test
+ void putAllWithNullDoesNotModifyTheArray() {
+ JSONArray array = new JSONArray(100, 200);
+ array.putAll(null);
+
+ assertEquals("[100,200]", array.toCompactString());
+ }
+
+ @Test
+ void addAllAddsNewObjectsToExistingArray() {
+ JSONArray array = new JSONArray(100, 200);
+ array.addAll(Arrays.asList(300, 400, 500));
+
+ assertEquals("[100,200,300,400,500]", array.toCompactString());
+ }
+
+ @Test
+ void addAllReturnsTrueIfChanged() {
+ JSONArray array = new JSONArray(100, 200);
+ boolean result = array.addAll(Arrays.asList(300, 400, 500));
+
+ assertTrue(result);
+ }
+
+ @Test
+ void addAllReturnsFalseIfNotChanged() {
+ JSONArray array = new JSONArray(100, 200);
+ boolean result = array.addAll((Collection<?>) null);
+
+ assertFalse(result);
+ }
+
+ @Test
+ void listReturnedByToListIsUnmodifiable() {
+ JSONArray array = new JSONArray(100, 200);
+ List<?> list = array.toList();
+
+ assertThrows(UnsupportedOperationException.class, list::clear);
+ }
+
+ @Test
+ void listFromToListIsLive() {
+ JSONArray array = new JSONArray(100, 200);
+ List<?> list = array.toList();
+
+ assertEquals(Arrays.asList(100, 200), list);
+
+ array.remove(0);
+
+ assertEquals(Arrays.asList(200), list);
+ }
+
+ @Test
+ void canInitializeJSONArrayFromAnIterable() {
+ JSONArray list = JSONArray.from(Arrays.asList(1, 2, 3));
+
+ assertEquals("[1,2,3]", list.toString(true));
+ }
+
+ @Test
+ void putShouldThrowAnIllegalArgumentExceptionWhenReceivingNull() {
+ JSONArray array = new JSONArray();
+
+ assertThrows(IllegalArgumentException.class, () -> array.put(null));
+ }
+
+ @Test
+ void newJSONArrayShouldThrowAnIllegalArgumentExceptionWhenReceivingNull() {
+ assertThrows(IllegalArgumentException.class, () -> new JSONArray(1, null, 3));
+ }
+
+ static Stream<Object> validTypesProvider() {
+ return Stream.of(
+ Arguments.of(true),
+ Arguments.of(3),
+ Arguments.of(3.5),
+ Arguments.of("*VALUE*"),
+ Arguments.of(new JSONLiteral("*LITERAL*")),
+ Arguments.of(new JSONObject()),
+ Arguments.of(new JSONArray())
+ );
+ }
+
+ @ParameterizedTest
+ @MethodSource("validTypesProvider")
+ void onlySpecificObjectTypesMayBeAddedNoException(Object value) {
+ JSONArray array = new JSONArray();
+
+ assertDoesNotThrow(() -> array.put(value));
+ }
+
+ static Stream<Arguments> invalidTypesProvider() {
+ return Stream.of(
+ Arguments.of(new java.util.Date()),
+ Arguments.of((Object) new Object[] {}),
+ Arguments.of(Collections.emptyMap())
+ );
+ }
+
+ @ParameterizedTest
+ @MethodSource("invalidTypesProvider")
+ void onlySpecificObjectTypesMayBeAddedException(Object value) {
+ JSONArray array = new JSONArray();
+
+ assertThrows(JSONInvalidTypeException.class, () -> array.put(value));
+ }
+
+ @Test
+ void arrayIndexOutOfBoundsMustThrowInformativeException() {
+ JSONArray array = new JSONArray(1, 2, 3);
+ JSONArrayIndexOutOfBoundsException e = assertThrows(JSONArrayIndexOutOfBoundsException.class, () -> {
+ array.get(array.size());
+ });
+
+ assertEquals(3, e.getIndex());
+ }
+
+ static Stream<Arguments> nonFiniteDoubleProvider() {
+ return Stream.of(
+ Arguments.of(Double.POSITIVE_INFINITY),
+ Arguments.of(Double.NEGATIVE_INFINITY),
+ Arguments.of(Double.NaN)
+ );
+ }
+
+ @ParameterizedTest
+ @MethodSource("nonFiniteDoubleProvider")
+ void nonFiniteOrNaNDoubleNotAllowedInConstructor(Double value) {
+ assertThrows(IllegalArgumentException.class, () -> new JSONArray(value));
+ }
+}
\ No newline at end of file
diff --git a/tapestry-json/src/test/java/org/apache/tapestry5/json/JSONCollectorsTest.java b/tapestry-json/src/test/java/org/apache/tapestry5/json/JSONCollectorsTest.java
new file mode 100644
index 000000000..419611d8a
--- /dev/null
+++ b/tapestry-json/src/test/java/org/apache/tapestry5/json/JSONCollectorsTest.java
@@ -0,0 +1,97 @@
+// Copyright 2025 The Apache Software Foundation
+//
+// 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 org.apache.tapestry5.json;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import java.util.stream.Stream;
+
+import org.apache.tapestry5.func.Tuple;
+import org.apache.tapestry5.json.exceptions.JSONInvalidTypeException;
+import org.junit.jupiter.api.Test;
+
+public class JSONCollectorsTest {
+
+ @Test
+ void collectStreamToArray() {
+
+ String stringValue = "a string value";
+ long longValue = 3L;
+ Stream<Object> stream = Stream.of(stringValue, longValue);
+
+ JSONArray collected = stream.collect(JSONCollectors.toArray());
+
+ assertNotNull(collected);
+ assertEquals(2, collected.size());
+ assertEquals(stringValue, collected.get(0));
+ assertEquals(longValue, collected.get(1));
+ }
+
+ @Test
+ void collectStreamToArrayInvalidType() {
+
+ String stringValue = "a string value";
+ long longValue = 3L;
+ Object invalidValue = new java.util.Date();
+
+ Stream<Object> stream = Stream.of(stringValue, longValue, invalidValue);
+
+ assertThrows(JSONInvalidTypeException.class, () -> {
+ stream.collect(JSONCollectors.toArray());
+ });
+ }
+
+ @Test
+ void collectStreamToMap() {
+
+ Tuple<String, Object> first = new Tuple<>("first key", "a string value");
+ Tuple<String, Object> second = new Tuple<>("second key", 3L);
+
+ Stream<Tuple<String, Object>> stream = Stream.of(first, second);
+
+ JSONObject collected = stream
+ .collect(JSONCollectors.toMap(t -> t.first, t -> t.second));
+
+ assertNotNull(collected);
+ assertEquals(2, collected.size());
+ assertEquals(first.second, collected.get(first.first));
+ assertEquals(second.second, collected.get(second.first));
+ }
+
+ @Test
+ @SuppressWarnings({ "unchecked", "rawtypes" }) // Suppress warnings for Tuple generic types
+ void collectStreamToMapInvalidType() {
+
+ Tuple<String, Object> first = new Tuple<>("first key", "a string value");
+ Tuple<String, Object> second = new Tuple<>("second key", 3L);
+ Tuple<String, Object> third = new Tuple<>("invalid type", new java.util.Date());
+
+ Stream<Tuple<String, Object>> stream = Stream.of(first, second, third);
+
+ assertThrows(JSONInvalidTypeException.class, () -> {
+ stream.collect(JSONCollectors.toMap(t -> t.first, t -> t.second));
+ });
+ }
+
+ @Test
+ void collectStreamToMapDuplicateKey() {
+
+ assertThrows(IllegalStateException.class, () -> {
+ Stream.of("first", "second", "first").collect(JSONCollectors.toMap(v -> v, v -> v));
+ });
+ }
+}
\ No newline at end of file
diff --git a/tapestry-json/src/test/java/org/apache/tapestry5/json/JSONObjectTest.java b/tapestry-json/src/test/java/org/apache/tapestry5/json/JSONObjectTest.java
new file mode 100644
index 000000000..0b4167a80
--- /dev/null
+++ b/tapestry-json/src/test/java/org/apache/tapestry5/json/JSONObjectTest.java
@@ -0,0 +1,891 @@
+// Copyright 2025 The Apache Software Foundation
+//
+// 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 org.apache.tapestry5.json;
+
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertSame;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.CharArrayWriter;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.PrintWriter;
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Consumer;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import org.apache.tapestry5.json.exceptions.JSONInvalidTypeException;
+import org.apache.tapestry5.json.exceptions.JSONSyntaxException;
+import org.apache.tapestry5.json.exceptions.JSONTypeMismatchException;
+import org.apache.tapestry5.json.exceptions.JSONValueNotFoundException;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+
+public class JSONObjectTest {
+
+ @Test
+ void copyAnExistingJSONObject() {
+
+ JSONObject master = new JSONObject("fred", "flintstone", "barney", "rubble");
+
+ JSONObject emptyCopy = new JSONObject(master);
+
+ assertTrue(emptyCopy.keys().isEmpty());
+
+ JSONObject limitedCopy = new JSONObject(master, "fred");
+
+ assertEquals(1, limitedCopy.keys().size());
+ assertEquals("flintstone", limitedCopy.get("fred"));
+
+ JSONObject fullCopy = new JSONObject(master, "fred", "barney");
+
+ assertEquals("{\"fred\":\"flintstone\",\"barney\":\"rubble\"}", fullCopy.toCompactString());
+ }
+
+ @Test
+ void copyAllPropertiesOfJSONObject() {
+
+ JSONObject master = new JSONObject("fred", "flintstone", "barney", "rubble");
+
+ JSONObject fullCopy = master.copy();
+
+ assertEquals(master, fullCopy);
+
+ master.put("wilma", "flintstone");
+
+ assertNotEquals(master, fullCopy);
+ }
+
+ @Test
+ void unknownKeysWhenCopyingAJSONObjectAreIgnored() {
+
+ JSONObject master = new JSONObject("fred", "flintstone", "barney", "rubble");
+
+ JSONObject copy = new JSONObject(master, "fred", "wilma");
+
+ assertEquals(1, copy.keys().size());
+ assertEquals("flintstone", copy.get("fred"));
+ }
+
+ @Test
+ void getWithUnknownKeyIsAnException() {
+
+ JSONObject master = new JSONObject("fred", "flintstone");
+
+ JSONValueNotFoundException e = assertThrows(JSONValueNotFoundException.class, () -> {
+ master.get("barney");
+ });
+
+ assertTrue(e.getMessage().startsWith("JSONObject[\"barney\"] is not found."));
+ assertTrue(e.getMessage().contains("Required: ANY"));
+ }
+
+ @Test
+ void getOrDefaultReturnsDefaultValueIfNotFound() {
+
+ JSONObject master = new JSONObject("fred", "flintstone");
+
+ Object result = master.getOrDefault("barney", "gumble");
+
+ assertEquals("gumble", result);
+ }
+
+ @Test
+ void getOrDefaultReturnsValueIfFound() {
+
+ JSONObject master = new JSONObject("fred", "flintstone");
+
+ Object result = master.getOrDefault("fred", "other");
+
+ assertEquals("flintstone", result);
+ }
+
+ // Data provider for ensureThatStoredValueIsExpected
+ static Stream<Arguments> storedValueProvider() {
+ return Stream.of(
+ Arguments.of("true", true, "Boolean"),
+ Arguments.of("TRUE", true, "Boolean"),
+ Arguments.of("false", false, "Boolean"),
+ Arguments.of("FALSE", false, "Boolean"),
+ Arguments.of(Boolean.TRUE, true, "Boolean"),
+ Arguments.of(Boolean.FALSE, false, "Boolean"),
+ Arguments.of(3.5d, 3.5d, "Double"),
+ Arguments.of(1_000L, 1_000d, "Double"),
+ Arguments.of("-101.7", -101.7d, "Double"),
+ Arguments.of("3", 3, "Int"),
+ Arguments.of(97L, 97, "Int"),
+ Arguments.of("-8.76", -8, "Int"),
+ Arguments.of(92d, 92L, "Long"),
+ Arguments.of("-200", -200L, "Long"),
+ Arguments.of(123, "123", "String")
+ );
+ }
+
+ @ParameterizedTest(name = "ensure that stored value {0} ({argumentsWithNames}) is {2} {1}")
+ @MethodSource("storedValueProvider")
+ void ensureThatStoredValueIsExpected(Object value, Object expected, String expectedType) {
+
+ JSONObject object = new JSONObject().put("key", value);
+ Function<String, Object> fn;
+ switch (expectedType) {
+ case "Boolean":
+ fn = object::getBoolean;
+ break;
+ case "Double":
+ fn = object::getDouble;
+ break;
+ case "Int":
+ fn = object::getInt;
+ break;
+ case "Long":
+ fn = object::getLong;
+ break;
+ case "String":
+ fn = object::getString;
+ break;
+ default:
+ throw new IllegalArgumentException("Unknown expected type: " + expectedType);
+ }
+
+ Object result = fn.apply("key");
+
+ assertEquals(expected, result);
+ }
+
+
+ static Stream<Arguments> doubleToStringProvider() {
+ return Stream.of(
+ Arguments.of(3d, "3"),
+ Arguments.of(-22.5d, "-22.5"),
+ Arguments.of(0d, "0"),
+ Arguments.of(Double.NaN, "null"),
+ Arguments.of(Double.NEGATIVE_INFINITY, "null"),
+ Arguments.of(Double.POSITIVE_INFINITY, "null")
+ );
+ }
+
+ @ParameterizedTest(name = "conversion of double {0} to string should be ''{1}''")
+ @MethodSource("doubleToStringProvider")
+ void doubleToStringConversion(double input, String expected) {
+
+ assertEquals(expected, JSONObject.doubleToString(input));
+ }
+
+ @Test
+ void exceptionWhenGetBooleanOnAValueThatIsNotABoolean() {
+
+ JSONObject object = new JSONObject().put("key", 37);
+
+ JSONTypeMismatchException e = assertThrows(JSONTypeMismatchException.class, () -> {
+ object.getBoolean("key");
+ });
+
+ assertTrue(e.getMessage().startsWith("JSONObject[\"key\"] is not a BOOLEAN."));
+ }
+
+ @Test
+ void accumulateSimpleValues() {
+
+ JSONObject object = new JSONObject();
+ String key = "acckey";
+
+ object.accumulate(key, "alpha");
+
+ assertEquals("{\"acckey\":\"alpha\"}", object.toCompactString());
+
+ object.accumulate(key, "beta");
+ object.accumulate(key, "gamma");
+
+ assertEquals("{\"acckey\":[\"alpha\",\"beta\",\"gamma\"]}", object.toCompactString());
+ assertEquals(3, object.getJSONArray(key).size());
+ }
+
+ @Test
+ void accumulateWhenTheStoredValueIsAlreadyAnArrayJustAppendsTheValue() {
+
+ JSONObject object = new JSONObject();
+
+ object.accumulate("key", new JSONArray("fred", "barney"));
+
+ assertEquals("{\"key\":[\"fred\",\"barney\"]}", object.toCompactString());
+
+ object.accumulate("key", "wilma");
+
+ assertEquals("{\"key\":[\"fred\",\"barney\",\"wilma\"]}", object.toCompactString());
+ }
+
+ @Test
+ void canCreateAJSONObjectFromAJSONString() {
+
+ JSONObject object = new JSONObject("{ fred: \"flintstone\", caveman: true, friends: [\"barney\"] }");
+
+ assertEquals("flintstone", object.get("fred"));
+ assertTrue(object.getBoolean("caveman"));
+
+ JSONArray friends = object.getJSONArray("friends");
+
+ assertEquals(1, friends.size());
+ assertEquals("barney", friends.get(0));
+ }
+
+ @Test
+ void appendToAnUnknownKeyCreatesAJSONArrayForTheValue() {
+
+ JSONObject object = new JSONObject();
+
+ object.append("friends", "barney");
+
+ assertEquals("{\"friends\":[\"barney\"]}", object.toCompactString());
+ }
+
+ @Test
+ void appendToAnExistingKeyContainingAJSONArrayAppendsToTheArray() {
+
+ JSONObject object = new JSONObject("{friends: [\"barney\"] }");
+
+ object.append("friends", "zaphod");
+
+ assertEquals("{\"friends\":[\"barney\",\"zaphod\"]}", object.toCompactString());
+ }
+
+ @Test
+ void appendingToAKeyWhoseValueIsNotAArrayIsAnException() {
+
+ JSONObject object = new JSONObject("{friends: 0 }");
+
+ JSONTypeMismatchException e = assertThrows(JSONTypeMismatchException.class, () -> {
+ object.append("friends", "zaphod");
+ });
+
+ assertTrue(e.getMessage().startsWith("JSONObject[\"friends\"] is not a ARRAY."));
+ }
+
+ @Test
+ void getDoubleWithANonNumericValueIsAnException() {
+
+ JSONObject object = new JSONObject("{notdouble: true}");
+
+ JSONTypeMismatchException e = assertThrows(JSONTypeMismatchException.class, () -> {
+ object.getDouble("notdouble");
+ });
+
+ assertTrue(e.getMessage().startsWith("JSONObject[\"notdouble\"] is not a NUMBER."));
+ }
+
+ @Test
+ void getDoubleWithAStringThatCanNotBeParsedAsANumberIsAnException() {
+
+ JSONObject object = new JSONObject("{notdouble: \"this is a fact\"}");
+
+ JSONTypeMismatchException e = assertThrows(JSONTypeMismatchException.class, () -> {
+ object.getDouble("notdouble");
+ });
+
+ assertTrue(e.getMessage().startsWith("JSONObject[\"notdouble\"] is not a NUMBER."));
+ }
+
+ @Test
+ void hasWillIdentifyWhichKeysHaveValuesAndWhichDoNot() {
+
+ JSONObject object = new JSONObject("{fred: 'flintstone'}");
+
+ assertTrue(object.has("fred"));
+ assertFalse(object.has("barney"));
+ }
+
+ @Test
+ void getJSONArrayForAValueThatIsNotAArrayIsAnException() {
+
+ JSONObject object = new JSONObject("{notarray: 22.7}");
+
+ JSONTypeMismatchException e = assertThrows(JSONTypeMismatchException.class, () -> {
+ object.getJSONArray("notarray");
+ });
+
+ assertTrue(e.getMessage().startsWith("JSONObject[\"notarray\"] is not a ARRAY."));
+ }
+
+ @Test
+ void lengthOfAJSONObjectIsTheNumberOfKeys() {
+
+ JSONObject object = new JSONObject();
+
+ assertEquals(0, object.size());
+
+ object.put("fred", "flintstone");
+
+ assertEquals(1, object.size());
+
+ object.accumulate("fred", "murray");
+
+ assertEquals(1, object.size());
+
+ object.put("barney", "rubble");
+
+ assertEquals(2, object.size());
+ }
+
+ @Test
+ void namesReturnsTheKeysAsAJSONArray() {
+
+ JSONObject object = new JSONObject("{fred: 'flintstone', barney: 'rubble' }");
+
+ JSONArray names = object.names();
+
+ assertNotNull(names);
+ assertTrue(names instanceof JSONArray);
+ assertEquals(2, names.size());
+
+ List<Object> nameList = new ArrayList<>(names.toList());
+ Collections.sort(nameList, (o1, o2) -> ((String) o1).compareTo((String) o2));
+
+ assertEquals(Arrays.asList("barney", "fred"), nameList);
+ }
+
+ @Test
+ void namesWithNoPropertiesReturnsNull() {
+
+ JSONObject object = new JSONObject();
+
+ assertNull(object.names());
+ }
+
+ @Test
+ void theNullLiteralIsTheNULLObject() {
+
+ JSONObject object = new JSONObject("{nullkey: null}");
+
+ assertSame(JSONObject.NULL, object.get("nullkey"));
+ assertTrue(object.isNull("nullkey"));
+ }
+
+ @Test
+ void theNULLObjectIsOutputAsNullLiteral() {
+
+ JSONObject object = new JSONObject().put("nullkey", JSONObject.NULL);
+
+ assertTrue(object.isNull("nullkey"));
+ assertEquals("{\"nullkey\":null}", object.toCompactString());
+ }
+
+ @Test
+ void theNULLObjectMatchesJavasNull() {
+
+ assertTrue(JSONObject.NULL.equals(null));
+ }
+
+ static Stream<Arguments> invalidInputProvider() {
+ return Stream.of(
+ Arguments.of("{ ", "A JSONObject text must end with '}' at character 3", "unmatched open brace"),
+ Arguments.of("fred", "A JSONObject text must start with '{' (actual: 'f') at character 1 of", "missing open brace"),
+ Arguments.of("{ \"akey\" }", "Expected a ':' after a key at character 10 of", "missing value after key"),
+ Arguments.of("{ \"fred\" : 1 \"barney\" }", "Expected a ',' or '}' at character 14 of", "missing property separator"),
+ Arguments.of("{ \"list\" : [1, 2", "Expected a ',' or ']' at character 16 of", "missing seperator or closing bracket"),
+ Arguments.of("/* unclosed", "Unclosed comment at character 11 of", "unclosed C-style comment"),
+ Arguments.of("{ \"fred \\n}", "Unterminated string at character 11 of", "unterminated string at line end"),
+ Arguments.of("{ fred: ,}", "Missing value at character 8 of ", "missing value after key")
+ );
+ }
+
+ @ParameterizedTest(name = "invalid input ({2}) throws exception")
+ @MethodSource("invalidInputProvider")
+ void invalidInputThrowsException(String input, String expected, String desc) {
+ // When/Then
+ JSONSyntaxException e = assertThrows(JSONSyntaxException.class, () -> {
+ new JSONObject(input);
+ });
+
+ assertTrue(e.getMessage().trim().startsWith(expected),
+ "Expected message to start with: " + expected + ", but was: " + e.getMessage().trim());
+ }
+
+
+ @Test
+ void canUseColonOrArrowAsKeySeperatorAndSemicolonAsPropertySeparator() {
+ JSONObject object = new JSONObject("{ \"fred\" = 1; \"barney\" => 2}");
+
+ assertEquals(1, object.getInt("fred"));
+ assertEquals(2, object.getInt("barney"));
+ }
+
+ static Stream<Arguments> numberToStringConversionProvider() {
+ return Stream.of(
+ Arguments.of(new BigDecimal("100.0000000"), "100")
+ );
+ }
+
+ @ParameterizedTest(name = "conversion of {0} ({argumentsWithNames}) to string is {1}")
+ @MethodSource("numberToStringConversionProvider")
+ void numberToStringConversion(Number value, String expected) {
+
+ assertEquals(expected, JSONObject.numberToString(value));
+ }
+
+ static Stream<Arguments> quoteProvider() {
+ return Stream.of(
+ Arguments.of(null, "\"\"", "null is empty string"),
+ Arguments.of("", "\"\"", "empty string is empty string"),
+ Arguments.of("\"/\b\t\n\f\r\u2001/a</", "\"\\\"/\\b\\t\\n\\f\\r\\u2001/a<\\/\"", "special characters")
+ );
+ }
+
+ @ParameterizedTest(name = "quote(): {2}")
+ @MethodSource("quoteProvider")
+ void quoteTest(String value, String expected, String desc) {
+
+ assertEquals(expected, JSONObject.quote(value));
+ }
+
+ static Stream<Arguments> nonFiniteNumbersProvider() {
+ return Stream.of(
+ Arguments.of(Double.NaN),
+ Arguments.of(Double.NEGATIVE_INFINITY),
+ Arguments.of(Double.POSITIVE_INFINITY),
+ Arguments.of(Float.NaN),
+ Arguments.of(Float.NEGATIVE_INFINITY),
+ Arguments.of(Float.POSITIVE_INFINITY)
+ );
+ }
+
+ @ParameterizedTest
+ @MethodSource("nonFiniteNumbersProvider")
+ void nonFiniteNumbersAreNotAllowed(Number value) {
+
+ JSONObject object = new JSONObject();
+
+ RuntimeException e = assertThrows(IllegalArgumentException.class, () -> {
+ object.put("nonfinite", value);
+ });
+
+ assertEquals("JSON does not allow non-finite numbers.", e.getMessage());
+ }
+
+ @Test
+ void parseAnEmptyObjectIsEmpty() {
+ JSONObject object = new JSONObject("{}");
+ assertEquals(0, object.size());
+ }
+
+ @Test
+ void putAJavaNullIsARemove() {
+
+ JSONObject object = new JSONObject("{fred:'flintstone', barney:'rubble'}");
+
+ object.put("fred", null);
+
+ assertEquals("{\"barney\":\"rubble\"}", object.toCompactString());
+ }
+
+ static Stream<Arguments> validTypesForPutProvider() {
+ return Stream.of(
+ Arguments.of((Object) null),
+ Arguments.of(true),
+ Arguments.of(3),
+ Arguments.of(3.5),
+ Arguments.of("*VALUE*"),
+ Arguments.of(new JSONLiteral("*LITERAL*")),
+ Arguments.of(new JSONObject()),
+ Arguments.of(new JSONArray())
+ );
+ }
+
+ @ParameterizedTest
+ @MethodSource("validTypesForPutProvider")
+ void onlySpecificObjectTypesMayBeAddedNoException(Object value) {
+
+ JSONObject object = new JSONObject("{}");
+
+ assertDoesNotThrow(() -> object.put("key", value));
+ }
+
+
+ static Stream<Arguments> invalidTypesForPutProvider() {
+ return Stream.of(
+ Arguments.of(new java.util.Date()),
+ Arguments.of((Object) new Object[] {}),
+ Arguments.of(Collections.emptyMap())
+ );
+ }
+ @ParameterizedTest
+ @MethodSource("invalidTypesForPutProvider")
+ void onlySpecificObjectTypesMayBeAddedException(Object value) {
+
+ JSONObject object = new JSONObject("{}");
+
+ assertThrows(JSONInvalidTypeException.class, () -> object.put("key", value));
+ }
+
+ @Test
+ void JSONStringCanOutputAnythingItWants() {
+ JSONString string = () -> "*VALUE*";
+ JSONObject object = new JSONObject();
+
+ object.put("key", string);
+
+ assertEquals("{\"key\":*VALUE*}", object.toCompactString());
+ }
+
+ @Test
+ void equalsImplementation() {
+ String jsonStr = "{ \"key\" : 99 }";
+ JSONObject obj1 = new JSONObject(jsonStr);
+ JSONObject obj2 = new JSONObject(jsonStr);
+
+ assertEquals(obj1, obj2);
+ assertEquals(obj2, obj1);
+ assertNotEquals(null, obj1);
+ assertNotEquals(jsonStr, obj1);
+
+ obj2.put("screw", "the pooch");
+
+ assertNotEquals(obj1, obj2);
+ }
+
+ @Test
+ void hashCodeImplementation() {
+
+ String jsonStr = "{ \"key\" : 99 }";
+ JSONObject obj1 = new JSONObject(jsonStr);
+ JSONObject obj2 = new JSONObject(jsonStr);
+
+ assertEquals(obj1.hashCode(), obj2.hashCode());
+
+ obj2.put("screw", "the pooch");
+
+ assertNotEquals(obj1.hashCode(), obj2.hashCode());
+ }
+
+ @Test
+ void escapedCharactersInTheJSONAreParsedCorrectly() {
+
+ JSONObject object = new JSONObject("{ \"key\" : \"\\\"/\\b\\t\\n\\f\\r\\u2001/a<\\/\\x20\" }");
+
+ assertEquals("\"/\b\t\n\f\r\u2001/a</ ", object.get("key"));
+ }
+
+ @Test
+ void parseANestedObject() {
+
+ JSONObject object = new JSONObject("{ key: { name: \"inner\" }}");
+
+ assertEquals("inner", object.getJSONObject("key").getString("name"));
+ }
+
+ @Test
+ void parseBooleanLiterals() {
+
+ JSONObject object = new JSONObject("{ t: true, f: false }");
+
+ assertTrue(object.getBoolean("t"));
+ assertFalse(object.getBoolean("f"));
+ }
+
+ @Test
+ void parseNumericForms() {
+
+ JSONObject object = new JSONObject("{ hex: 0x50, oct: 030, posInt: +50, negInt: -50, long: 4294968530, float: -32.7 }");
+
+ assertEquals(80, object.getInt("hex"));
+ assertEquals(24, object.getInt("oct"));
+ assertEquals(50, object.getInt("posInt"));
+ assertEquals(-50, object.getInt("negInt"));
+ assertEquals(4294968530L, object.getLong("long"));
+ assertEquals(-32.7d, object.getDouble("float"));
+ }
+
+ @Test
+ void NULLToStringIsNullKeyword() {
+
+ assertEquals("null", JSONObject.NULL.toString());
+ }
+
+ @Test
+ void JSONLiteralCanOutputAnyContent() {
+
+ String text = "function(x) { $('bar').show(); }";
+ JSONLiteral literal = new JSONLiteral(text);
+ JSONObject object = new JSONObject().put("callback", literal);
+
+ assertEquals("{\"callback\":" + text + "}", object.toCompactString());
+ assertEquals(text, literal.toString());
+ }
+
+ @Test
+ void prettyPrintTest() {
+
+ JSONObject object = new JSONObject("fred", "flintstone", "barney", "rubble");
+ String expected = "{\n \"fred\" : \"flintstone\",\n \"barney\" : \"rubble\"\n}";
+
+ assertEquals(expected.trim(), object.toString().trim());
+ }
+
+ @Test
+ void cStyleCommentsAreIgnored() {
+
+ JSONObject object = new JSONObject("/* C comment */ { \"foo\" : \"bar\" /* *ignored* */ }");
+
+ assertEquals("bar", object.get("foo"));
+ }
+
+ @Test
+ void doubleSlashCommentsExtendToEndOfLine() {
+
+ JSONObject object = new JSONObject("{ foo: // This is a double-slash comment\n\"bar\" }");
+
+ assertEquals("bar", object.get("foo"));
+ }
+
+ @Test
+ void hashCommentsExtendToEndOfLine() {
+
+ JSONObject object = new JSONObject("{ foo: # This is a hash comment\n\"bar\" }");
+
+ assertEquals("bar", object.get("foo"));
+ }
+
+ @Test
+ void prettyPrintAnEmptyJSONObject() {
+
+ JSONObject object = new JSONObject();
+
+ assertEquals("{}", object.toString());
+ }
+
+ @Test
+ void complexPrettyPrint() {
+ JSONObject object = new JSONObject(
+ "{ outer: { inner: \"here\" },\n" +
+ " number: 22.7,\n" +
+ " array: [1, 2, 3],\n" +
+ " boolean: true,\n" +
+ " otherwise: 'a quoted string'\n" +
+ "}"
+ );
+ String expected = "{\n" +
+ " \"outer\" : {\n" +
+ " \"inner\" : \"here\"\n" +
+ " },\n" +
+ " \"number\" : 22.7,\n" +
+ " \"array\" : [\n" +
+ " 1,\n" +
+ " 2,\n" +
+ " 3\n" +
+ " ],\n" +
+ " \"boolean\" : true,\n" +
+ " \"otherwise\" : \"a quoted string\"\n" +
+ "}";
+ assertEquals(expected.trim(), object.toString().trim());
+ }
+
+
+ @Test
+ void toCompactStringTest() {
+
+ JSONObject object = new JSONObject("kermit", "frog");
+
+ assertEquals("{\"kermit\":\"frog\"}", object.toString(true));
+ assertEquals("{\n \"kermit\" : \"frog\"\n}", object.toString(false).replace("\r\n", "\n"));
+ }
+
+ private static String withPrintWriter(Consumer<PrintWriter> closure) {
+
+ CharArrayWriter caw = new CharArrayWriter();
+ try (PrintWriter pw = new PrintWriter(caw)) {
+ closure.accept(pw);
+ }
+
+ return caw.toString();
+ }
+
+ private static String print(JSONObject object, boolean compact) {
+ return withPrintWriter(pw -> object.print(pw, compact));
+ }
+
+ @Test
+ void printToPrintWriterTest() {
+
+ JSONObject object = new JSONObject("kermit", "frog");
+
+ assertEquals("{\"kermit\":\"frog\"}", print(object, true));
+ assertEquals("{\n \"kermit\" : \"frog\"\n}", print(object, false).replace("\r\n", "\n"));
+ }
+
+
+ @Test
+ void prettyPrintToPrintWriter() {
+
+ JSONObject object = new JSONObject("kermit", "frog");
+
+ String json = withPrintWriter(pw -> object.prettyPrint(pw));
+ assertEquals("{\n \"kermit\" : \"frog\"\n}", json.replace("\r\n", "\n"));
+ }
+
+ @Test
+ void getStringAtIndex() {
+
+ JSONArray array = new JSONArray("one", 2, false);
+
+ assertEquals("one", array.getString(0));
+ assertEquals("2", array.getString(1));
+ assertEquals("false", array.getString(2));
+ }
+
+ @Test
+ void toMapIsNotModifiable() {
+
+ JSONObject object = new JSONObject();
+ Map<String, Object> map = object.toMap();
+
+ assertThrows(UnsupportedOperationException.class, map::clear);
+ }
+
+ @Test
+ void canAccessContentsOfObjectAsAMap() {
+
+ JSONObject object = new JSONObject("foo", "bar")
+ .put("null", JSONObject.NULL)
+ .put("number", 6);
+ Map<String, Object> map = object.toMap();
+
+ assertEquals("bar", map.get("foo"));
+ assertEquals(6, map.get("number"));
+ assertSame(JSONObject.NULL, map.get("null"));
+ }
+
+ @Test
+ void theMapReturnedByToMapIsLive() {
+
+ JSONObject object = new JSONObject("foo", "bar");
+ Map<String, Object> map = object.toMap();
+
+ object.put("foo", null);
+
+ assertEquals(0, object.size());
+ assertTrue(map.isEmpty());
+ }
+
+ @Test
+ void canAddNewPropertiesViaPutAll() {
+
+ JSONObject object = new JSONObject("fred", "flintstone");
+ Map<String, Object> newProps = new HashMap<>();
+ newProps.put("barney", "rubble");
+ newProps.put("wilma", "flintstone");
+
+ object.putAll(newProps);
+
+ assertTrue(object.keySet().containsAll(Arrays.asList("fred", "barney", "wilma")));
+ assertEquals(
+ Stream.of("flintstone", "rubble", "flintstone").sorted().collect(Collectors.toList()),
+ object.values().stream().sorted().collect(Collectors.toList())
+ );
+ }
+
+ @Test
+ void inWhereTheValueIsNotJSONObjectIsAnException() {
+
+ JSONObject object = new JSONObject("time", "to rock");
+
+ IllegalStateException e = assertThrows(IllegalStateException.class, () -> {
+ object.in("time");
+ });
+
+ assertEquals("JSONObject[\"time\"] is not a JSONObject.", e.getMessage());
+ }
+
+ @Test
+ void inCreatesAJSONObjectIfNecessary() {
+
+ JSONObject object = new JSONObject();
+
+ object.in("nested").put("created", true);
+
+ assertEquals("{\"nested\":{\"created\":true}}", object.toCompactString());
+ }
+
+ @Test
+ void inReturnsTheJSONObject() {
+
+ JSONObject object = new JSONObject("{nested: {}}");
+
+ object.in("nested").put("time", "to rock");
+
+ assertEquals("{\"nested\":{\"time\":\"to rock\"}}", object.toCompactString());
+ }
+
+ @Test
+ void constructorSupportsNonStringKeysAndValues() {
+
+ JSONObject object = new JSONObject(true, "truthy", false, false);
+
+ assertTrue(object.containsKey("true")); // Keys are stringified
+ assertEquals("truthy", object.getString("true"));
+ assertTrue(object.containsKey("false"));
+ assertEquals(false, object.get("false"));
+ }
+
+
+ private static Object copyViaSerialization(Object source) throws IOException, ClassNotFoundException {
+
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ try (ObjectOutputStream oos = new ObjectOutputStream(bos)) {
+ oos.writeObject(source);
+ }
+
+ ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
+ try (ObjectInputStream ois = new ObjectInputStream(bis)) {
+ return ois.readObject();
+ }
+ }
+
+ @Test
+ void serializeAndDeSerialize() throws IOException, ClassNotFoundException {
+
+ JSONObject source = new JSONObject("string", "a string", "null", JSONObject.NULL);
+
+ JSONObject copy = (JSONObject) copyViaSerialization(source);
+
+ assertEquals(source, copy);
+ }
+
+ // TAP5-2759
+ @Test
+ void getLongOrDefaultCorrectTypeForDefaultValue() {
+ JSONObject object = new JSONObject();
+ long defaultValue = 2_147_483_648L; // This is Integer.MAX_VALUE + 1, so it's a long
+ long value = object.getLongOrDefault("key", defaultValue);
+
+ assertEquals(defaultValue, value);
+ }
+}
\ No newline at end of file
diff --git a/tapestry-json/src/test/java/org/apache/tapestry5/json/JSONTest.java b/tapestry-json/src/test/java/org/apache/tapestry5/json/JSONTest.java
new file mode 100644
index 000000000..0446b942a
--- /dev/null
+++ b/tapestry-json/src/test/java/org/apache/tapestry5/json/JSONTest.java
@@ -0,0 +1,53 @@
+// Copyright 2025 The Apache Software Foundation
+//
+// 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 org.apache.tapestry5.json;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import java.util.Collections;
+import java.util.Map;
+
+import org.apache.tapestry5.json.exceptions.JSONInvalidTypeException;
+import org.junit.jupiter.api.Test;
+
+public class JSONTest {
+
+ @Test
+ void invalidTypesThrowJSONInvalidTypeException() {
+ Map<String, String> invalidValue = Collections.emptyMap();
+
+ JSONInvalidTypeException e = assertThrows(JSONInvalidTypeException.class, () -> {
+ JSON.testValidity(invalidValue);
+ });
+
+ String expectedMessage = String.format(
+ "JSONArray values / JSONObject properties may be one of Boolean, Number, String, %s, %s, %s, %s, %s. Type %s is not allowed.",
+ "org.apache.tapestry5.json.JSONArray",
+ "org.apache.tapestry5.json.JSONLiteral",
+ "org.apache.tapestry5.json.JSONObject",
+ "org.apache.tapestry5.json.JSONObject$Null",
+ "org.apache.tapestry5.json.JSONString",
+ invalidValue.getClass().getName());
+ assertEquals(expectedMessage, e.getMessage());
+ }
+
+ @Test
+ void nullIsInvalid() {
+ assertThrows(IllegalArgumentException.class, () -> {
+ JSON.testValidity(null);
+ });
+ }
+}
\ No newline at end of file
diff --git a/tapestry-kaptcha/src/test/conf/testng.xml b/tapestry-kaptcha/src/test/resources/testng.xml
similarity index 100%
rename from tapestry-kaptcha/src/test/conf/testng.xml
rename to tapestry-kaptcha/src/test/resources/testng.xml
diff --git a/tapestry-mongodb/src/test/groovy/MongoDBSpec.groovy b/tapestry-mongodb/src/test/groovy/MongoDBSpec.groovy
index 510a2e41e..cbce0dd32 100644
--- a/tapestry-mongodb/src/test/groovy/MongoDBSpec.groovy
+++ b/tapestry-mongodb/src/test/groovy/MongoDBSpec.groovy
@@ -16,9 +16,11 @@ import de.flapdoodle.embed.mongo.config.MongodConfig
import de.flapdoodle.embed.mongo.distribution.Version
import de.flapdoodle.embed.process.runtime.Network
import spock.lang.AutoCleanup
+import spock.lang.Ignore
import spock.lang.Shared
import spock.lang.Specification
+@Ignore
class MongoDBSpec extends Specification
{
final int total = 1000
diff --git a/tapestry-mongodb/src/test/conf/testng.xml b/tapestry-mongodb/src/test/resources/testng.xml
similarity index 100%
rename from tapestry-mongodb/src/test/conf/testng.xml
rename to tapestry-mongodb/src/test/resources/testng.xml
diff --git a/tapestry-spring/src/test/conf/testng.xml b/tapestry-spring/src/test/resources/testng.xml
similarity index 100%
rename from tapestry-spring/src/test/conf/testng.xml
rename to tapestry-spring/src/test/resources/testng.xml
diff --git a/tapestry-test/src/test/conf/testng.xml b/tapestry-test/src/test/resources/testng.xml
similarity index 100%
rename from tapestry-test/src/test/conf/testng.xml
rename to tapestry-test/src/test/resources/testng.xml
diff --git a/tapestry-upload/src/test/conf/testng.xml b/tapestry-upload/src/test/resources/testng.xml
similarity index 100%
rename from tapestry-upload/src/test/conf/testng.xml
rename to tapestry-upload/src/test/resources/testng.xml
diff --git a/tapestry-webresources/src/test/java/t5/webresources/services/web/WebResourcesTest.java b/tapestry-webresources/src/test/java/t5/webresources/services/web/WebResourcesTest.java
index e39cb9c58..f96f77120 100644
--- a/tapestry-webresources/src/test/java/t5/webresources/services/web/WebResourcesTest.java
+++ b/tapestry-webresources/src/test/java/t5/webresources/services/web/WebResourcesTest.java
@@ -35,6 +35,7 @@ public class WebResourcesTest extends SeleniumTestCase {
public void test_Less_compilation()
{
open("/");
+ waitForInitializedPage();
click("css=.navbar .dropdown-toggle");
click("link=MultiLess");
waitForInitializedPage();
diff --git a/tapestry5-annotations/src/test/conf/testng.xml b/tapestry5-annotations/src/test/conf/testng.xml
deleted file mode 100644
index e7dc420fd..000000000
--- a/tapestry5-annotations/src/test/conf/testng.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
-<!--
- Copyright 2008 The Apache Software Foundation
-
- 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.
--->
-
-<suite name="Tapestry Annotations" annotations="1.5" verbose="2">
- <!-- This avoids a build error when performing a non-clean build. Just another Maven fuckup to be worked around. -->
- <test name="Placeholder (no tests)"/>
-</suite>
(tapestry-5) 03/12: Improving handling of resource minimization exceptions
Posted by be...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
benw pushed a commit to branch gradle-improvements-javax
in repository https://gitbox.apache.org/repos/asf/tapestry-5.git
commit 4098b2df2352f0dae994985cf40603316f36f314
Author: Thiago H. de Paula Figueiredo <th...@arsmachina.com.br>
AuthorDate: Sun Aug 24 11:14:57 2025 -0300
Improving handling of resource minimization exceptions
---
.../assets/JavaScriptStackMinimizeDisabler.java | 32 ++++++++++++++++++++--
.../webresources/GoogleClosureMinimizer.java | 2 +-
.../ResourceMinimizationException.java | 32 ++++++++++++++++++++++
3 files changed, 62 insertions(+), 4 deletions(-)
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/assets/JavaScriptStackMinimizeDisabler.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/assets/JavaScriptStackMinimizeDisabler.java
index 9bca3fa0f..fe475efb2 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/assets/JavaScriptStackMinimizeDisabler.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/assets/JavaScriptStackMinimizeDisabler.java
@@ -12,6 +12,8 @@
package org.apache.tapestry5.internal.services.assets;
+import java.io.IOException;
+
import org.apache.tapestry5.TapestryConstants;
import org.apache.tapestry5.commons.Resource;
import org.apache.tapestry5.http.services.Request;
@@ -21,8 +23,8 @@ import org.apache.tapestry5.services.assets.StreamableResourceProcessing;
import org.apache.tapestry5.services.assets.StreamableResourceSource;
import org.apache.tapestry5.services.javascript.JavaScriptStack;
import org.apache.tapestry5.services.javascript.JavaScriptStackSource;
-
-import java.io.IOException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
/**
* Attempts to match resources against a {@link org.apache.tapestry5.services.javascript.JavaScriptStack}, and
@@ -33,6 +35,8 @@ import java.io.IOException;
public class JavaScriptStackMinimizeDisabler extends DelegatingSRS
{
+ private static final Logger LOGGER = LoggerFactory.getLogger(JavaScriptStackMinimizeDisabler.class);
+
private final JavaScriptStackSource javaScriptStackSource;
private final Request request;
@@ -59,7 +63,29 @@ public class JavaScriptStackMinimizeDisabler extends DelegatingSRS
try
{
return delegate.getStreamableResource(baseResource, processing, dependencies);
- } finally
+ }
+ catch (RuntimeException e)
+ {
+ if (processing != StreamableResourceProcessing.FOR_AGGREGATION)
+ {
+ // We know our current minimizer, Google Closure Compiler,
+ // doesn't support ES modules
+ if (LOGGER.isWarnEnabled() &&
+ !baseResource.toString().contains("/es-modules/") &&
+ !baseResource.toString().toLowerCase().contains("es module wrapper"))
+ {
+ LOGGER.warn("Exception happened while processing " + baseResource +
+ "Trying again without compression nor minification.", e);
+ }
+ request.setAttribute(TapestryConstants.DISABLE_JAVASCRIPT_MINIMIZATION, true);
+ return delegate.getStreamableResource(baseResource, StreamableResourceProcessing.FOR_AGGREGATION, dependencies);
+ }
+ else
+ {
+ throw e;
+ }
+ }
+ finally
{
request.setAttribute(TapestryConstants.DISABLE_JAVASCRIPT_MINIMIZATION, null);
}
diff --git a/tapestry-webresources/src/main/java/org/apache/tapestry5/internal/webresources/GoogleClosureMinimizer.java b/tapestry-webresources/src/main/java/org/apache/tapestry5/internal/webresources/GoogleClosureMinimizer.java
index b134b2bad..f2385dccd 100644
--- a/tapestry-webresources/src/main/java/org/apache/tapestry5/internal/webresources/GoogleClosureMinimizer.java
+++ b/tapestry-webresources/src/main/java/org/apache/tapestry5/internal/webresources/GoogleClosureMinimizer.java
@@ -106,7 +106,7 @@ public class GoogleClosureMinimizer extends AbstractMinimizer
return IOUtils.toInputStream(compiler.toSource(), StandardCharsets.UTF_8);
}
- throw new RuntimeException(String.format("Compilation failed for %s. Errors: %s.",
+ throw new ResourceMinimizationException(String.format("Compilation failed for %s. Errors: %s.",
resource,
InternalUtils.join(CollectionFactory.newList(result.errors), ";")));
}
diff --git a/tapestry-webresources/src/main/java/org/apache/tapestry5/internal/webresources/ResourceMinimizationException.java b/tapestry-webresources/src/main/java/org/apache/tapestry5/internal/webresources/ResourceMinimizationException.java
new file mode 100644
index 000000000..e4df96ba7
--- /dev/null
+++ b/tapestry-webresources/src/main/java/org/apache/tapestry5/internal/webresources/ResourceMinimizationException.java
@@ -0,0 +1,32 @@
+// Copyright 2015 The Apache Software Foundation
+//
+// 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 org.apache.tapestry5.internal.webresources;
+
+/**
+ * Manages a collection of Resources and can check to see if any resource's actual content has changed.
+ *
+ * @since 5.10.0
+ */
+public class ResourceMinimizationException extends RuntimeException
+{
+
+ private static final long serialVersionUID = 1L;
+
+ public ResourceMinimizationException(String message)
+ {
+ super(message);
+ }
+
+}