mirror of
https://github.com/GTNewHorizons/Angelica.git
synced 2026-10-25 20:22:22 +00:00
Speed up tests and run SDL-GPU device tests on CI (#2253)
* Speed up tests and run SDL-GPU device tests on CI * Arch rules share one ASM scan instead of ArchUnit * Tests needing an SDL GPU device fail without one instead of skipping * Replace checkstyle's wildcard-import check with a test * Use the runner's preinstalled Temurin JDKs * Cache build/rfg so the Minecraft decompile chain can be skipped * Unpack LWJGL natives before tests * Pin the shared workflow commit
This commit is contained in:
1 parent
46f8157087
commit
85d0641a73
33 files changed
+544
-202
No files matched your search
@@ -9,7 +9,42 @@ on:
|
||||
|
||||
jobs:
|
||||
build-and-test:
|
||||
uses: GTNewHorizons/GTNH-Actions-Workflows/.github/workflows/build-and-test.yml@30d03306cd2dbfade5083f5c6552afad5321d2bb
|
||||
uses: GTNewHorizons/GTNH-Actions-Workflows/.github/workflows/build-and-test.yml@05e7cd7ce0ea015acda8c10c1c39fb3a20a49e60
|
||||
with:
|
||||
disable-spotless-pr: true
|
||||
java-distribution: temurin
|
||||
cache-rfg: true
|
||||
secrets: inherit
|
||||
|
||||
sdl-gpu-tests:
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 20
|
||||
concurrency:
|
||||
group: sdl-gpu-tests-${{ github.event.pull_request.number || github.ref }}
|
||||
cancel-in-progress: true
|
||||
steps:
|
||||
- name: Install a software Vulkan driver
|
||||
run: |
|
||||
sudo apt-get update -y
|
||||
sudo apt-get install -y xvfb mesa-vulkan-drivers
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actions/setup-java@v5
|
||||
with:
|
||||
distribution: temurin
|
||||
java-version: |
|
||||
21
|
||||
25
|
||||
- uses: gradle/actions/setup-gradle@v5
|
||||
- name: Run SDL-GPU tests
|
||||
run: xvfb-run -a --server-args="-screen 0 1366x768x24" ./gradlew --build-cache --stacktrace --continue :sdl-gpu:glsmSdlTest :sdl-gpu:sdlGpuDeviceTest
|
||||
- name: Check LWJGL did not extract natives to the shared temp dir
|
||||
run: test ! -e "/tmp/lwjgl_$USER"
|
||||
- name: Attach SDL-GPU test results
|
||||
if: ${{ !cancelled() }}
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: sdl-gpu-test-results
|
||||
path: |
|
||||
sdl-gpu/build/test-results/
|
||||
sdl-gpu/build/reports/tests/
|
||||
sdl-gpu/hs_err_pid*.log
|
||||
+43
-2
@@ -89,8 +89,11 @@ tasks.register<Copy>("copyDependencies") {
|
||||
val embedOnly: Configuration by configurations
|
||||
val shadowImplementation: Configuration by configurations
|
||||
|
||||
val dependencyClasspath: FileCollection = sourceSets.main.get().runtimeClasspath - sourceSets.main.get().output
|
||||
|
||||
val downgradeEmbedOnlyForTest by tasks.registering(DowngradeFiles::class) {
|
||||
inputCollection = embedOnly
|
||||
classpath = dependencyClasspath
|
||||
outputs.dir(temporaryDir)
|
||||
}
|
||||
|
||||
@@ -104,6 +107,7 @@ val stripModuleInfoFromShadow by tasks.registering(Jar::class) {
|
||||
|
||||
val downgradeShadowImplForTest by tasks.registering(DowngradeFiles::class) {
|
||||
inputCollection = files(stripModuleInfoFromShadow.map { it.archiveFile })
|
||||
classpath = dependencyClasspath
|
||||
outputs.dir(temporaryDir)
|
||||
}
|
||||
|
||||
@@ -118,6 +122,7 @@ val glsmTestFixtures: Configuration by configurations.creating {
|
||||
|
||||
val downgradeGlsmTestFixturesForTest by tasks.registering(DowngradeFiles::class) {
|
||||
inputCollection = glsmTestFixtures
|
||||
classpath = dependencyClasspath
|
||||
outputs.dir(temporaryDir)
|
||||
}
|
||||
|
||||
@@ -159,9 +164,25 @@ if (isMacOs && providers.gradleProperty("clientJvmVendor").isPresent) {
|
||||
}
|
||||
}
|
||||
|
||||
// Forge's asm-debug-all 5.0.3 cannot read the Java 25 class files ArchScan walks; this ASM has to resolve first.
|
||||
val archScanAsm: Configuration by configurations.creating {
|
||||
isCanBeConsumed = false
|
||||
isCanBeResolved = true
|
||||
}
|
||||
|
||||
dependencies {
|
||||
archScanAsm(libs.asm.tree.test)
|
||||
archScanAsm(libs.asm.commons.test)
|
||||
}
|
||||
|
||||
sourceSets.test {
|
||||
compileClasspath = archScanAsm + compileClasspath
|
||||
}
|
||||
|
||||
tasks.test {
|
||||
useJUnitPlatform { excludeTags = setOf("gl-core") }
|
||||
configureAngelicaJava8()
|
||||
classpath = archScanAsm + classpath
|
||||
jvmArgs("-Dceleritas.lwjglService=org.taumc.celeritas.lwjgl.HeadlessTestLWJGLService")
|
||||
dependsOn(":glsm:classes", ":lwjgl3-backend:classes", ":sdl-gpu:classes")
|
||||
}
|
||||
@@ -169,6 +190,13 @@ tasks.test {
|
||||
val downgradeRootMainClasses = tasks.named<DowngradeFiles>("downgradeMainClasses")
|
||||
val downgradeRootTestClasses = tasks.named<DowngradeFiles>("downgradeTestClasses")
|
||||
|
||||
// JVMDowngrader only declares outputs for inputs that exist at configuration, so a clean tree has none.
|
||||
for (name in listOf("main", "mixin", "test")) {
|
||||
tasks.named<DowngradeFiles>("downgrade${name.replaceFirstChar { it.uppercase() }}Classes") {
|
||||
sourceSets[name].output.classesDirs.files.forEach { outputs.dir(temporaryDir.resolve(it.name)) }
|
||||
}
|
||||
}
|
||||
|
||||
val glCoreTest by tasks.registering(Test::class) {
|
||||
description = "Runs the gl-core tests in their own JVM with a real GL context."
|
||||
group = "verification"
|
||||
@@ -185,10 +213,23 @@ val glCoreTest by tasks.registering(Test::class) {
|
||||
.plus(sourceSets["test"].runtimeClasspath.minus(rawMain).minus(rawTest))
|
||||
|
||||
configureAngelicaJava8()
|
||||
mustRunAfter(tasks.test)
|
||||
}
|
||||
|
||||
tasks.test { finalizedBy(glCoreTest) }
|
||||
val verifyTestsRan by tasks.registering
|
||||
listOf(tasks.test, glCoreTest).forEach { testTask ->
|
||||
val name = testTask.name
|
||||
val verify = tasks.register("verify${name.replaceFirstChar { it.uppercase() }}Ran") {
|
||||
val resultsDir = layout.buildDirectory.dir("test-results/$name")
|
||||
dependsOn(testTask)
|
||||
doLast {
|
||||
val dir = resultsDir.get().asFile
|
||||
val xmls = dir.listFiles { f -> f.name.startsWith("TEST-") && f.name.endsWith(".xml") } ?: emptyArray()
|
||||
check(xmls.isNotEmpty()) { ":$name produced no TEST-*.xml in $dir - test task likely went NO-SOURCE" }
|
||||
}
|
||||
}
|
||||
verifyTestsRan.configure { dependsOn(verify) }
|
||||
}
|
||||
tasks.check { dependsOn(verifyTestsRan) }
|
||||
|
||||
apply(from = "gradle/angelica-shadow-common.gradle.kts")
|
||||
apply(from = "experimental-surround/surround.root.gradle.kts")
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.file.ArchiveOperations
|
||||
import org.gradle.api.tasks.SourceSetContainer
|
||||
import org.gradle.api.tasks.Sync
|
||||
import org.gradle.api.tasks.TaskProvider
|
||||
import org.gradle.api.tasks.testing.Test
|
||||
import org.gradle.kotlin.dsl.get
|
||||
import org.gradle.kotlin.dsl.register
|
||||
import org.gradle.kotlin.dsl.the
|
||||
import javax.inject.Inject
|
||||
|
||||
abstract class UnpackLwjgl3Natives : Sync() {
|
||||
@get:Inject
|
||||
abstract val archives: ArchiveOperations
|
||||
}
|
||||
|
||||
// LWJGL extracts jar-packed natives to a shared temp dir with no cross-process safety; plain files it loads in place.
|
||||
fun Project.registerLwjgl3NativesUnpack(): TaskProvider<UnpackLwjgl3Natives> {
|
||||
val jars = the<SourceSetContainer>()["test"].runtimeClasspath.filter {
|
||||
it.name.startsWith("lwjgl") && it.name.contains("-natives-") && !it.name.startsWith("lwjgl-platform-")
|
||||
}
|
||||
return tasks.register<UnpackLwjgl3Natives>("unpackLwjgl3Natives") {
|
||||
val archives = archives
|
||||
from(jars.elements.map { files -> files.map { archives.zipTree(it) } })
|
||||
exclude("META-INF/**")
|
||||
into(layout.buildDirectory.dir("lwjgl3-natives"))
|
||||
}
|
||||
}
|
||||
|
||||
fun Test.loadLwjgl3NativesFrom(unpack: TaskProvider<UnpackLwjgl3Natives>) {
|
||||
classpath = project.files(unpack) + classpath
|
||||
}
|
||||
@@ -204,7 +204,6 @@ afterEvaluate {
|
||||
testImplementation(libs.junit.platform.reporting)
|
||||
testImplementation(libs.junit.platform.launcher)
|
||||
|
||||
testImplementation(libs.archunit.junit5)
|
||||
testImplementation(libs.retrofuturabootstrap) { isTransitive = false }
|
||||
|
||||
glsmTestFixtures(testFixtures(project(":glsm")) as ModuleDependency) { isTransitive = false }
|
||||
|
||||
@@ -48,6 +48,7 @@ repositories {
|
||||
}
|
||||
|
||||
tasks.withType<DowngradeFiles>().configureEach {
|
||||
outputs.cacheIf { true }
|
||||
downgradeTo.set(JavaVersion.VERSION_1_8)
|
||||
multiReleaseOriginal.set(false)
|
||||
multiReleaseVersions.set(emptySet())
|
||||
|
||||
@@ -183,6 +183,7 @@ dependencies {
|
||||
}
|
||||
|
||||
tasks.withType<DowngradeFiles>().configureEach {
|
||||
outputs.cacheIf { true }
|
||||
downgradeTo.set(JavaVersion.VERSION_1_8)
|
||||
multiReleaseOriginal.set(false)
|
||||
multiReleaseVersions.set(emptySet())
|
||||
@@ -302,6 +303,8 @@ val verifyTestsRan by tasks.registering {
|
||||
}
|
||||
tasks.check { dependsOn(verifyTestsRan) }
|
||||
|
||||
val unpackLwjgl3Natives = registerLwjgl3NativesUnpack()
|
||||
|
||||
val spirvTest by tasks.registering(Test::class) {
|
||||
description = "Runs SpirvShaderTranslator* tests against native shaderc + spvc on Java 21."
|
||||
group = "verification"
|
||||
@@ -330,6 +333,7 @@ val spirvTest by tasks.registering(Test::class) {
|
||||
"-Djava.library.path=${extractNatives3.get().property("destinationFolder").let { (it as DirectoryProperty).asFile.get().path }}",
|
||||
"--enable-native-access=ALL-UNNAMED"
|
||||
)
|
||||
loadLwjgl3NativesFrom(unpackLwjgl3Natives)
|
||||
|
||||
testLogging {
|
||||
showStandardStreams = true
|
||||
|
||||
+1
-1
@@ -213,7 +213,7 @@ curseForgeRelations = requiredDependency\:gtnhlib
|
||||
disableSpotless = true
|
||||
|
||||
# Uncomment this to disable Checkstyle checks (currently wildcard import check).
|
||||
# disableCheckstyle = true
|
||||
disableCheckstyle = true
|
||||
|
||||
# Override the IDEA build type. Valid values are: "" (leave blank, do not override), "idea" (force use native IDEA build), "gradle"
|
||||
# (force use delegated build).
|
||||
|
||||
@@ -6,7 +6,10 @@ import xyz.wagyourtail.jvmdg.gradle.task.files.DowngradeFiles
|
||||
val libs = the<LibrariesForLibs>()
|
||||
|
||||
tasks.withType<DowngradeJar>().configureEach { logLevel.set("FATAL") }
|
||||
tasks.withType<DowngradeFiles>().configureEach { logLevel.set("FATAL") }
|
||||
tasks.withType<DowngradeFiles>().configureEach {
|
||||
logLevel.set("FATAL")
|
||||
outputs.cacheIf { true }
|
||||
}
|
||||
|
||||
configurations.all {
|
||||
resolutionStrategy.dependencySubstitution {
|
||||
|
||||
@@ -30,10 +30,9 @@ joml = "1.10.8"
|
||||
commonsLang3 = "3.17.0"
|
||||
jvmDowngrader = "1.3.5"
|
||||
junit = "5.14.1"
|
||||
asmTest = "9.7"
|
||||
asmTest = "9.9.1"
|
||||
asmBuild = "9.7"
|
||||
mockito = "3.12.4"
|
||||
archunit = "1.4.1"
|
||||
ant = "1.8.2"
|
||||
distantHorizonsApi = "5.1.0"
|
||||
|
||||
@@ -64,11 +63,11 @@ junit-platform-engine = { module = "org.junit.platform:junit-platform-engine" }
|
||||
junit-platform-reporting = { module = "org.junit.platform:junit-platform-reporting" }
|
||||
|
||||
mockito-core = { module = "org.mockito:mockito-core", version.ref = "mockito" }
|
||||
archunit-junit5 = { module = "com.tngtech.archunit:archunit-junit5", version.ref = "archunit" }
|
||||
ant = { module = "org.apache.ant:ant", version.ref = "ant" }
|
||||
distant-horizons-api = { module = "maven.modrinth:DistantHorizonsApi", version.ref = "distantHorizonsApi" }
|
||||
asm-tree-compile = { module = "org.ow2.asm:asm-tree", version.ref = "asmCompile" }
|
||||
asm-tree-test = { module = "org.ow2.asm:asm-tree", version.ref = "asmTest" }
|
||||
asm-commons-test = { module = "org.ow2.asm:asm-commons", version.ref = "asmTest" }
|
||||
asm-build = { module = "org.ow2.asm:asm", version.ref = "asmBuild" }
|
||||
lwjgl2 = { module = "org.lwjgl.lwjgl:lwjgl", version.ref = "lwjgl2" }
|
||||
lwjgl2-util = { module = "org.lwjgl.lwjgl:lwjgl_util", version.ref = "lwjgl2" }
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import java.time.Duration
|
||||
|
||||
plugins {
|
||||
`java-library`
|
||||
`maven-publish`
|
||||
@@ -94,6 +96,7 @@ dependencies {
|
||||
}
|
||||
|
||||
val glsmSdlTag = "glsm-sdl"
|
||||
val sdlGpuDeviceTag = "sdl-gpu-device"
|
||||
|
||||
val glsmSdlStubs = sourceSets.create("glsmSdlStubs") {
|
||||
java.srcDir("src/glsmSdlStubs/java")
|
||||
@@ -109,15 +112,29 @@ dependencies {
|
||||
testImplementation(glsmSdlAgent.output)
|
||||
}
|
||||
|
||||
tasks.test {
|
||||
useJUnitPlatform {
|
||||
excludeTags(glsmSdlTag)
|
||||
}
|
||||
tasks.withType<Test>().configureEach {
|
||||
if (System.getProperty("os.name").startsWith("Mac")) {
|
||||
jvmArgs("-XstartOnFirstThread")
|
||||
}
|
||||
}
|
||||
|
||||
tasks.test {
|
||||
useJUnitPlatform {
|
||||
excludeTags(glsmSdlTag, sdlGpuDeviceTag)
|
||||
}
|
||||
}
|
||||
|
||||
val sdlGpuDeviceTest by tasks.registering(Test::class) {
|
||||
description = "Runs the tests that need a real SDL GPU device."
|
||||
group = "verification"
|
||||
testClassesDirs = sourceSets["test"].output.classesDirs
|
||||
classpath = sourceSets["test"].runtimeClasspath
|
||||
useJUnitPlatform {
|
||||
includeTags(sdlGpuDeviceTag)
|
||||
}
|
||||
mustRunAfter(tasks.test)
|
||||
}
|
||||
|
||||
val glsmSdlRedirectAgentJar by tasks.registering(Jar::class) {
|
||||
archiveClassifier = "glsm-sdl-redirect-agent"
|
||||
from(glsmSdlAgent.output)
|
||||
@@ -146,9 +163,6 @@ val glsmSdlTest by tasks.registering(Test::class) {
|
||||
"-Dangelica.sdlgpu.disablePresenterThread=true",
|
||||
"-Dceleritas.lwjglService=com.gtnewhorizons.angelica.sdlgpu.SDLGPULWJGLService",
|
||||
)
|
||||
if (System.getProperty("os.name").startsWith("Mac")) {
|
||||
jvmArgs("-XstartOnFirstThread")
|
||||
}
|
||||
testLogging {
|
||||
events("passed", "skipped", "failed")
|
||||
exceptionFormat = org.gradle.api.tasks.testing.logging.TestExceptionFormat.FULL
|
||||
@@ -156,7 +170,23 @@ val glsmSdlTest by tasks.registering(Test::class) {
|
||||
mustRunAfter(tasks.test)
|
||||
}
|
||||
|
||||
tasks.check { dependsOn(glsmSdlTest) }
|
||||
val deviceTests = listOf(glsmSdlTest, sdlGpuDeviceTest)
|
||||
|
||||
deviceTests.forEach {
|
||||
it.configure {
|
||||
outputs.cacheIf { false }
|
||||
timeout = Duration.ofMinutes(5)
|
||||
systemProperty("junit.jupiter.execution.timeout.default", "60s")
|
||||
systemProperty("junit.jupiter.execution.timeout.threaddump.enabled", "true")
|
||||
}
|
||||
}
|
||||
|
||||
val unpackLwjgl3Natives = registerLwjgl3NativesUnpack()
|
||||
(deviceTests + tasks.test).forEach { it.configure { loadLwjgl3NativesFrom(unpackLwjgl3Natives) } }
|
||||
|
||||
if (!providers.environmentVariable("CI").isPresent) {
|
||||
tasks.check { dependsOn(deviceTests) }
|
||||
}
|
||||
|
||||
tasks.named<JavaCompile>("compileJava") {
|
||||
val classesDir = destinationDirectory
|
||||
|
||||
@@ -10,7 +10,7 @@ import org.lwjgl.sdl.SDLError;
|
||||
import org.lwjgl.sdl.SDLHints;
|
||||
import org.lwjgl.sdl.SDLInit;
|
||||
|
||||
import static org.junit.jupiter.api.Assumptions.assumeTrue;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.lwjgl.sdl.SDLGPU.SDL_CreateGPUDevice;
|
||||
import static org.lwjgl.sdl.SDLGPU.SDL_DestroyGPUDevice;
|
||||
import static org.lwjgl.sdl.SDLGPU.SDL_GetGPUDeviceDriver;
|
||||
@@ -90,13 +90,13 @@ public final class SdlTestRig {
|
||||
|
||||
public static void initSdlVideo() {
|
||||
SDLHints.SDL_SetHint(SDLHints.SDL_HINT_MAC_BACKGROUND_APP, "1");
|
||||
assumeTrue(SDLInit.SDL_Init(SDL_INIT_VIDEO), () -> "SDL_Init failed: " + SDLError.SDL_GetError());
|
||||
assertTrue(SDLInit.SDL_Init(SDL_INIT_VIDEO), () -> "SDL_Init failed: " + SDLError.SDL_GetError());
|
||||
}
|
||||
|
||||
public static SdlTestRig acquireRealDevice() {
|
||||
initSdlVideo();
|
||||
realSdlDevice = SDL_CreateGPUDevice(SHADER_FORMATS, true, (CharSequence) null);
|
||||
assumeTrue(realSdlDevice != 0, "No SDL GPU device: " + SDLError.SDL_GetError());
|
||||
assertTrue(realSdlDevice != 0, "No SDL GPU device: " + SDLError.SDL_GetError());
|
||||
|
||||
final SdlTestRig rig = new SdlTestRig(realSdlDevice);
|
||||
rig.frameManager.setResourceManager(rig.resourceManager);
|
||||
|
||||
+3
-1
@@ -5,6 +5,7 @@ import com.gtnewhorizons.angelica.sdlgpu.SdlTestRig;
|
||||
import it.unimi.dsi.fastutil.longs.Long2BooleanOpenHashMap;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Tag;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
@@ -13,6 +14,7 @@ import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.junit.jupiter.api.Assumptions.assumeTrue;
|
||||
|
||||
@Tag("sdl-gpu-device")
|
||||
class DeviceImageAtomicsGpuTest {
|
||||
|
||||
private Device device;
|
||||
@@ -34,7 +36,7 @@ class DeviceImageAtomicsGpuTest {
|
||||
@Test
|
||||
void verdictsAreCachedPerSizeAndDroppedWithTheDevice() {
|
||||
device = new Device();
|
||||
assumeTrue(device.createDevice(), "no SDL GPU device on this machine");
|
||||
assertTrue(device.createDevice(), "no SDL GPU device on this machine");
|
||||
assumeTrue(device.metalTextureAtomics(), "needs native Metal compiling at MSL 3.1 or newer");
|
||||
|
||||
assertFalse(device.supportsImageAtomics(40, 10, 2));
|
||||
|
||||
+4
-3
@@ -3,13 +3,14 @@ package com.gtnewhorizons.angelica.sdlgpu.device;
|
||||
import com.gtnewhorizons.angelica.sdlgpu.SdlTestRig;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Tag;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.junit.jupiter.api.Assumptions.assumeTrue;
|
||||
|
||||
@Tag("sdl-gpu-device")
|
||||
class DeviceLifecycleGpuTest {
|
||||
|
||||
private Device device;
|
||||
@@ -27,7 +28,7 @@ class DeviceLifecycleGpuTest {
|
||||
@Test
|
||||
void createsWithoutAWindowAndIsMemoized() {
|
||||
device = new Device();
|
||||
assumeTrue(device.createDevice(), "no SDL GPU device on this machine");
|
||||
assertTrue(device.createDevice(), "no SDL GPU device on this machine");
|
||||
|
||||
final long handle = device.getDevice();
|
||||
assertNotEquals(0L, handle);
|
||||
@@ -38,7 +39,7 @@ class DeviceLifecycleGpuTest {
|
||||
@Test
|
||||
void destroyIsIdempotentOnAnUnclaimedDevice() {
|
||||
device = new Device();
|
||||
assumeTrue(device.createDevice(), "no SDL GPU device on this machine");
|
||||
assertTrue(device.createDevice(), "no SDL GPU device on this machine");
|
||||
|
||||
device.destroyDevice();
|
||||
assertEquals(0L, device.getDevice());
|
||||
|
||||
+2
@@ -2,6 +2,7 @@ package com.gtnewhorizons.angelica.sdlgpu.device;
|
||||
|
||||
import com.gtnewhorizons.angelica.sdlgpu.RealDeviceExtension;
|
||||
import com.gtnewhorizons.angelica.sdlgpu.SdlTestRig;
|
||||
import org.junit.jupiter.api.Tag;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.lwjgl.system.MemoryStack;
|
||||
@@ -18,6 +19,7 @@ import static org.lwjgl.sdl.SDLVersion.SDL_GetVersion;
|
||||
import static org.lwjgl.sdl.SDLVersion.SDL_VERSIONNUM;
|
||||
|
||||
@ExtendWith(RealDeviceExtension.class)
|
||||
@Tag("sdl-gpu-device")
|
||||
class FenceProbeRealDeviceTest {
|
||||
|
||||
@Test
|
||||
|
||||
+1
-2
@@ -24,7 +24,6 @@ import java.nio.ByteBuffer;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.junit.jupiter.api.Assumptions.assumeTrue;
|
||||
|
||||
public final class GlsmSdlHeadlessRig {
|
||||
|
||||
@@ -48,7 +47,7 @@ public final class GlsmSdlHeadlessRig {
|
||||
public static void boot() {
|
||||
if (booted) return;
|
||||
SdlTestRig.initSdlVideo();
|
||||
assumeTrue(SDLGPUGate.device().createDevice(), () -> "no SDL GPU device: " + SDLError.SDL_GetError());
|
||||
assertTrue(SDLGPUGate.device().createDevice(), () -> "no SDL GPU device: " + SDLError.SDL_GetError());
|
||||
Reflect.setStatic(SDLGPUGate.class, "engaged", true);
|
||||
|
||||
final RenderBackend backend = BackendManager.RENDER_BACKEND;
|
||||
|
||||
+2
@@ -5,6 +5,7 @@ import com.gtnewhorizons.angelica.sdlgpu.SdlTestRig;
|
||||
import com.gtnewhorizons.angelica.sdlgpu.resource.FboState;
|
||||
import com.gtnewhorizons.angelica.sdlgpu.shader.ShaderManager;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Tag;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
|
||||
@@ -13,6 +14,7 @@ import static org.junit.jupiter.api.Assertions.assertNotEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
@ExtendWith(RealDeviceExtension.class)
|
||||
@Tag("sdl-gpu-device")
|
||||
class AttachmentClearTest {
|
||||
|
||||
private static SdlTestRig rig;
|
||||
|
||||
+2
@@ -5,6 +5,7 @@ import com.gtnewhorizons.angelica.sdlgpu.frame.ContextState;
|
||||
import com.gtnewhorizons.angelica.sdlgpu.shader.ShaderManager;
|
||||
import com.gtnewhorizons.angelica.sdlgpu.shader.ShaderManager.ProgramObject;
|
||||
import com.gtnewhorizons.angelica.sdlgpu.shader.ShaderManager.UniformMemberInfo;
|
||||
import org.junit.jupiter.api.Tag;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.lwjgl.util.spvc.Spvc;
|
||||
|
||||
@@ -97,6 +98,7 @@ class PerFrameBlockDedupTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
@Tag("sdl-gpu-device")
|
||||
void flushUniformBlocksEndsTheCopyPassOnceForTwoDirtyBlocks() throws Exception {
|
||||
final SdlTestRig rig = SdlTestRig.acquireRealDevice();
|
||||
try {
|
||||
|
||||
+2
@@ -5,6 +5,7 @@ import com.gtnewhorizons.angelica.sdlgpu.SdlTestRig;
|
||||
import com.gtnewhorizons.angelica.sdlgpu.frame.ContextState;
|
||||
import com.gtnewhorizons.angelica.sdlgpu.shader.ShaderManager;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Tag;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.lwjgl.opengl.GL20;
|
||||
@@ -21,6 +22,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.lwjgl.sdl.SDLGPU.*;
|
||||
|
||||
@ExtendWith(RealDeviceExtension.class)
|
||||
@Tag("sdl-gpu-device")
|
||||
class StencilMaskGpuTest {
|
||||
|
||||
private static SdlTestRig rig;
|
||||
|
||||
+2
@@ -5,6 +5,7 @@ import com.gtnewhorizons.angelica.sdlgpu.SdlTestRig;
|
||||
import com.gtnewhorizons.angelica.sdlgpu.device.Device;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Tag;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.lwjgl.opengl.GL15;
|
||||
@@ -14,6 +15,7 @@ import static org.junit.jupiter.api.Assertions.assertNotEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
@ExtendWith(RealDeviceExtension.class)
|
||||
@Tag("sdl-gpu-device")
|
||||
class BufferSizeGpuExactnessTest {
|
||||
|
||||
private static Device device;
|
||||
|
||||
+2
@@ -7,6 +7,7 @@ import com.gtnewhorizons.angelica.sdlgpu.frame.ContextState;
|
||||
import com.gtnewhorizons.angelica.sdlgpu.frame.FrameManager;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Tag;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.Timeout;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
@@ -21,6 +22,7 @@ import static org.lwjgl.sdl.SDLGPU.SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM;
|
||||
|
||||
@ExtendWith(RealDeviceExtension.class)
|
||||
@Timeout(120)
|
||||
@Tag("sdl-gpu-device")
|
||||
class CopyTexSubImageFromFbo0GpuTest {
|
||||
|
||||
private static final int SIZE = 64;
|
||||
|
||||
+2
@@ -8,6 +8,7 @@ import com.gtnewhorizons.angelica.sdlgpu.frame.FrameManager;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.MethodOrderer;
|
||||
import org.junit.jupiter.api.Order;
|
||||
import org.junit.jupiter.api.Tag;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.TestMethodOrder;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
@@ -28,6 +29,7 @@ import static org.lwjgl.system.MemoryStack.stackPush;
|
||||
|
||||
@ExtendWith(RealDeviceExtension.class)
|
||||
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
|
||||
@Tag("sdl-gpu-device")
|
||||
class UploadArenaGpuRoundTripTest {
|
||||
|
||||
private static Device device;
|
||||
|
||||
+2
@@ -3,6 +3,7 @@ package com.gtnewhorizons.angelica.sdlgpu.shader;
|
||||
import com.gtnewhorizons.angelica.sdlgpu.RealDeviceExtension;
|
||||
import com.gtnewhorizons.angelica.sdlgpu.SdlTestRig;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Tag;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.ValueSource;
|
||||
@@ -31,6 +32,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.lwjgl.sdl.SDLGPU.*;
|
||||
|
||||
@ExtendWith(RealDeviceExtension.class)
|
||||
@Tag("sdl-gpu-device")
|
||||
class FragmentStorageTextureReadGpuTest {
|
||||
|
||||
private static SdlTestRig rig;
|
||||
|
||||
@@ -0,0 +1,181 @@
|
||||
package com.gtnewhorizons.angelica.arch;
|
||||
|
||||
import org.objectweb.asm.ClassReader;
|
||||
import org.objectweb.asm.Handle;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.objectweb.asm.Type;
|
||||
import org.objectweb.asm.commons.ClassRemapper;
|
||||
import org.objectweb.asm.commons.Remapper;
|
||||
import org.objectweb.asm.tree.AbstractInsnNode;
|
||||
import org.objectweb.asm.tree.AnnotationNode;
|
||||
import org.objectweb.asm.tree.ClassNode;
|
||||
import org.objectweb.asm.tree.FieldInsnNode;
|
||||
import org.objectweb.asm.tree.InvokeDynamicInsnNode;
|
||||
import org.objectweb.asm.tree.LdcInsnNode;
|
||||
import org.objectweb.asm.tree.MethodInsnNode;
|
||||
import org.objectweb.asm.tree.MethodNode;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
final class ArchScan {
|
||||
|
||||
enum Dir {
|
||||
MAIN("build/classes/java/main"),
|
||||
MIXIN("build/classes/java/mixin"),
|
||||
GLSM("glsm/build/classes/java/main"),
|
||||
LWJGL3_BACKEND("lwjgl3-backend/build/classes/java/main"),
|
||||
SDL_GPU("sdl-gpu/build/classes/java/main");
|
||||
|
||||
final String path;
|
||||
|
||||
Dir(String path) {
|
||||
this.path = path;
|
||||
}
|
||||
}
|
||||
|
||||
enum Kind { FIELD, CALL }
|
||||
|
||||
record Access(String method, Kind kind, String owner, String name, String desc) {
|
||||
|
||||
String target() {
|
||||
return owner + "." + name + (kind == Kind.FIELD ? " " : "") + desc;
|
||||
}
|
||||
|
||||
List<String> descriptorTypes() {
|
||||
return kind == Kind.FIELD ? Collections.singletonList(Type.getType(desc).getClassName()) : signatureTypes(desc);
|
||||
}
|
||||
}
|
||||
|
||||
record ClassConstant(String method, String type) {
|
||||
}
|
||||
|
||||
record Member(String name, String desc) {
|
||||
}
|
||||
|
||||
record ScannedClass(Dir dir, String name, Set<String> annotations, Set<String> references, List<Member> methods, List<Access> accesses, List<ClassConstant> classConstants) {
|
||||
}
|
||||
|
||||
private static final List<ScannedClass> CLASSES = scan();
|
||||
private static final Map<String, ScannedClass> BY_NAME = index(CLASSES);
|
||||
|
||||
private ArchScan() {
|
||||
}
|
||||
|
||||
static List<ScannedClass> in(Dir... dirs) {
|
||||
final List<Dir> wanted = Arrays.asList(dirs);
|
||||
final List<ScannedClass> selected = new ArrayList<>();
|
||||
for (ScannedClass c : CLASSES) {
|
||||
if (wanted.contains(c.dir())) selected.add(c);
|
||||
}
|
||||
return selected;
|
||||
}
|
||||
|
||||
static List<String> signatureTypes(String desc) {
|
||||
final List<String> types = new ArrayList<>();
|
||||
for (Type argument : Type.getArgumentTypes(desc)) {
|
||||
types.add(argument.getClassName());
|
||||
}
|
||||
types.add(Type.getReturnType(desc).getClassName());
|
||||
return types;
|
||||
}
|
||||
|
||||
static ScannedClass find(String name) {
|
||||
return BY_NAME.get(name);
|
||||
}
|
||||
|
||||
static ScannedClass get(String name) {
|
||||
final ScannedClass c = BY_NAME.get(name);
|
||||
if (c == null) throw new IllegalStateException(name + " was not scanned; the scan paths are likely wrong");
|
||||
return c;
|
||||
}
|
||||
|
||||
private static Map<String, ScannedClass> index(List<ScannedClass> classes) {
|
||||
final Map<String, ScannedClass> byName = new HashMap<>();
|
||||
for (ScannedClass c : classes) {
|
||||
byName.put(c.name(), c);
|
||||
}
|
||||
return byName;
|
||||
}
|
||||
|
||||
private static List<ScannedClass> scan() {
|
||||
final List<ScannedClass> classes = new ArrayList<>();
|
||||
for (Dir dir : Dir.values()) {
|
||||
final Path root = Paths.get(dir.path);
|
||||
if (!Files.isDirectory(root)) throw new IllegalStateException(dir.path + " is not a directory");
|
||||
final int before = classes.size();
|
||||
try (Stream<Path> files = Files.walk(root)) {
|
||||
for (final Iterator<Path> it = files.iterator(); it.hasNext(); ) {
|
||||
final Path file = it.next();
|
||||
if (file.toString().endsWith(".class")) classes.add(read(dir, Files.readAllBytes(file)));
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException(e);
|
||||
}
|
||||
if (classes.size() == before) throw new IllegalStateException(dir.path + " yielded no classes");
|
||||
}
|
||||
return classes;
|
||||
}
|
||||
|
||||
private static ScannedClass read(Dir dir, byte[] bytes) {
|
||||
final Set<String> references = new HashSet<>();
|
||||
final ClassNode node = new ClassNode();
|
||||
final Remapper recorder = new Remapper() {
|
||||
@Override
|
||||
public String map(String internalName) {
|
||||
references.add(className(internalName));
|
||||
return internalName;
|
||||
}
|
||||
};
|
||||
new ClassReader(bytes).accept(new ClassRemapper(node, recorder), ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES);
|
||||
|
||||
final String name = className(node.name);
|
||||
references.remove(name);
|
||||
|
||||
final Set<String> annotations = new HashSet<>();
|
||||
if (node.visibleAnnotations != null) {
|
||||
for (AnnotationNode annotation : node.visibleAnnotations) {
|
||||
annotations.add(Type.getType(annotation.desc).getClassName());
|
||||
}
|
||||
}
|
||||
|
||||
final List<Member> methods = new ArrayList<>();
|
||||
final List<Access> accesses = new ArrayList<>();
|
||||
final List<ClassConstant> classConstants = new ArrayList<>();
|
||||
for (MethodNode method : node.methods) {
|
||||
methods.add(new Member(method.name, method.desc));
|
||||
final String origin = method.name + method.desc;
|
||||
for (AbstractInsnNode insn : method.instructions) {
|
||||
if (insn instanceof FieldInsnNode field) {
|
||||
accesses.add(new Access(origin, Kind.FIELD, className(field.owner), field.name, field.desc));
|
||||
} else if (insn instanceof MethodInsnNode call) {
|
||||
accesses.add(new Access(origin, Kind.CALL, className(call.owner), call.name, call.desc));
|
||||
} else if (insn instanceof InvokeDynamicInsnNode dynamic) {
|
||||
for (Object argument : dynamic.bsmArgs) {
|
||||
if (argument instanceof Handle handle) accesses.add(new Access(origin, handle.getTag() <= Opcodes.H_PUTSTATIC ? Kind.FIELD : Kind.CALL, className(handle.getOwner()), handle.getName(), handle.getDesc()));
|
||||
}
|
||||
} else if (insn instanceof LdcInsnNode ldc && ldc.cst instanceof Type type && (type.getSort() == Type.OBJECT || type.getSort() == Type.ARRAY)) {
|
||||
classConstants.add(new ClassConstant(origin, type.getClassName()));
|
||||
}
|
||||
}
|
||||
}
|
||||
return new ScannedClass(dir, name, annotations, references, methods, accesses, classConstants);
|
||||
}
|
||||
|
||||
private static String className(String internalName) {
|
||||
return Type.getObjectType(internalName).getClassName();
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,8 @@
|
||||
package com.gtnewhorizons.angelica.arch;
|
||||
|
||||
import com.tngtech.archunit.core.domain.JavaAccess;
|
||||
import com.tngtech.archunit.core.domain.JavaClass;
|
||||
import com.tngtech.archunit.core.domain.JavaClasses;
|
||||
import com.tngtech.archunit.core.importer.ClassFileImporter;
|
||||
import com.gtnewhorizons.angelica.arch.ArchScan.Access;
|
||||
import com.gtnewhorizons.angelica.arch.ArchScan.Dir;
|
||||
import com.gtnewhorizons.angelica.arch.ArchScan.ScannedClass;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -18,23 +17,20 @@ class EarlyLoadingBoundaryTest {
|
||||
private static final String TRACY = "com.gtnewhorizons.angelica.glsm.profiling.Tracy";
|
||||
|
||||
private static final Pattern GUARDED = Pattern.compile(
|
||||
".*/com/gtnewhorizons/angelica/(loading/[^/]+|mixins/Mixins(\\$[^/]*)?|AngelicaMod(\\$[^/]*)?|config/AngelicaConfig(\\$[^/]*)?)\\.class$");
|
||||
|
||||
private static final JavaClasses classes = new ClassFileImporter()
|
||||
.withImportOption(location -> location.matches(GUARDED))
|
||||
.importPaths("build/classes/java/main");
|
||||
"com\\.gtnewhorizons\\.angelica\\.(loading\\.[^.]+|mixins\\.Mixins(\\$[^.]*)?|AngelicaMod(\\$[^.]*)?|config\\.AngelicaConfig(\\$[^.]*)?)");
|
||||
|
||||
@Test
|
||||
void earlyLoadingClassesDoNotAccessTracy() {
|
||||
assertFalse(classes.isEmpty(), "no guarded classes imported");
|
||||
int guarded = 0;
|
||||
final List<String> violations = new ArrayList<>();
|
||||
for (JavaClass origin : classes) {
|
||||
for (JavaAccess<?> access : origin.getAccessesFromSelf()) {
|
||||
if (access.getTargetOwner().getName().equals(TRACY)) {
|
||||
violations.add(origin.getFullName() + " -> " + access.getTarget().getFullName());
|
||||
}
|
||||
for (ScannedClass origin : ArchScan.in(Dir.MAIN)) {
|
||||
if (!GUARDED.matcher(origin.name()).matches()) continue;
|
||||
guarded++;
|
||||
for (Access access : origin.accesses()) {
|
||||
if (access.owner().equals(TRACY)) violations.add(origin.name() + "." + access.method() + " -> " + access.target());
|
||||
}
|
||||
}
|
||||
assertFalse(guarded == 0, "no guarded classes scanned");
|
||||
assertTrue(violations.isEmpty(), "Coremod-phase code must not touch glsm.profiling.Tracy:\n" + String.join("\n", violations));
|
||||
}
|
||||
}
|
||||
@@ -1,17 +1,15 @@
|
||||
package com.gtnewhorizons.angelica.arch;
|
||||
|
||||
import com.tngtech.archunit.core.domain.AccessTarget;
|
||||
import com.tngtech.archunit.core.domain.JavaAccess;
|
||||
import com.tngtech.archunit.core.domain.JavaClass;
|
||||
import com.tngtech.archunit.core.domain.JavaClasses;
|
||||
import com.tngtech.archunit.core.domain.JavaMethod;
|
||||
import com.tngtech.archunit.core.importer.ClassFileImporter;
|
||||
import com.tngtech.archunit.core.importer.ImportOption;
|
||||
import com.gtnewhorizons.angelica.arch.ArchScan.Access;
|
||||
import com.gtnewhorizons.angelica.arch.ArchScan.Dir;
|
||||
import com.gtnewhorizons.angelica.arch.ArchScan.Member;
|
||||
import com.gtnewhorizons.angelica.arch.ArchScan.ScannedClass;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
/**
|
||||
@@ -29,24 +27,16 @@ class Lwjgl3AwareBoundaryTest {
|
||||
"com.gtnewhorizons.angelica.sdlgpu.",
|
||||
"com.gtnewhorizons.angelica.lwjgl3.");
|
||||
|
||||
private static final JavaClasses classes = new ClassFileImporter()
|
||||
.withImportOption(ImportOption.Predefined.DO_NOT_INCLUDE_TESTS)
|
||||
.importPaths(
|
||||
"build/classes/java/main",
|
||||
"build/classes/java/mixin",
|
||||
"glsm/build/classes/java/main",
|
||||
"lwjgl3-backend/build/classes/java/main",
|
||||
"sdl-gpu/build/classes/java/main");
|
||||
private static final List<ScannedClass> classes = ArchScan.in(Dir.values());
|
||||
|
||||
@Test
|
||||
void awareClassesDoNotReadRemappedMembers() {
|
||||
final List<String> violations = new ArrayList<>();
|
||||
for (JavaClass origin : classes) {
|
||||
if (!isAware(origin)) continue;
|
||||
for (JavaAccess<?> access : origin.getAccessesFromSelf()) {
|
||||
final JavaClass owner = access.getTargetOwner();
|
||||
if (isUntransformed(owner) || isAware(owner)) continue;
|
||||
if (mentionsLwjgl3Type(access.getTarget())) violations.add(describe(access));
|
||||
for (ScannedClass origin : classes) {
|
||||
if (!isAware(origin.name())) continue;
|
||||
for (Access access : origin.accesses()) {
|
||||
if (isUntransformed(access.owner()) || isAware(access.owner())) continue;
|
||||
if (mentionsLwjgl3Type(access)) violations.add(describe(origin, access));
|
||||
}
|
||||
}
|
||||
assertTrue(violations.isEmpty(), "@Lwjgl3Aware code referencing a remapped member with an org.lwjgl type in its descriptor:\n" + String.join("\n", violations));
|
||||
@@ -55,11 +45,11 @@ class Lwjgl3AwareBoundaryTest {
|
||||
@Test
|
||||
void remappedClassesDoNotReadAwareMembers() {
|
||||
final List<String> violations = new ArrayList<>();
|
||||
for (JavaClass origin : classes) {
|
||||
if (isAware(origin) || isUntransformed(origin)) continue;
|
||||
for (JavaAccess<?> access : origin.getAccessesFromSelf()) {
|
||||
if (!isAware(access.getTargetOwner())) continue;
|
||||
if (mentionsLwjgl3Type(access.getTarget())) violations.add(describe(access));
|
||||
for (ScannedClass origin : classes) {
|
||||
if (isAware(origin.name()) || isUntransformed(origin.name())) continue;
|
||||
for (Access access : origin.accesses()) {
|
||||
if (!isAware(access.owner())) continue;
|
||||
if (mentionsLwjgl3Type(access)) violations.add(describe(origin, access));
|
||||
}
|
||||
}
|
||||
assertTrue(violations.isEmpty(), "Remapped code referencing an @Lwjgl3Aware member with an org.lwjgl type in its descriptor:\n" + String.join("\n", violations));
|
||||
@@ -69,64 +59,51 @@ class Lwjgl3AwareBoundaryTest {
|
||||
@Test
|
||||
void nativeLwjgl3ModulesAreFullyAware() {
|
||||
final List<String> missing = new ArrayList<>();
|
||||
for (JavaClass c : classes) {
|
||||
if (AWARE_MODULES.stream().anyMatch(p -> c.getName().startsWith(p)) && !isAware(c)) {
|
||||
missing.add(c.getName());
|
||||
}
|
||||
int inAwareModules = 0;
|
||||
for (ScannedClass c : classes) {
|
||||
if (AWARE_MODULES.stream().noneMatch(p -> c.name().startsWith(p))) continue;
|
||||
inAwareModules++;
|
||||
if (!isAware(c.name())) missing.add(c.name());
|
||||
}
|
||||
assertFalse(inAwareModules == 0, "no classes scanned under " + AWARE_MODULES);
|
||||
assertTrue(missing.isEmpty(), "Classes missing @Lwjgl3Aware:\n" + String.join("\n", missing));
|
||||
}
|
||||
|
||||
@Test
|
||||
void renderBackendSignaturesAreRemapSafe() {
|
||||
final JavaClass renderBackend = classes.get("com.gtnewhorizons.angelica.glsm.backend.RenderBackend");
|
||||
final ScannedClass renderBackend = ArchScan.get("com.gtnewhorizons.angelica.glsm.backend.RenderBackend");
|
||||
final List<String> violations = new ArrayList<>();
|
||||
for (JavaMethod method : renderBackend.getMethods()) {
|
||||
final List<JavaClass> types = new ArrayList<>(method.getRawParameterTypes());
|
||||
types.add(method.getRawReturnType());
|
||||
if (types.stream().anyMatch(Lwjgl3AwareBoundaryTest::isRemapUnsafeType)) {
|
||||
violations.add(method.getFullName());
|
||||
for (Member method : renderBackend.methods()) {
|
||||
if (method.name().startsWith("<")) continue;
|
||||
if (ArchScan.signatureTypes(method.desc()).stream().anyMatch(Lwjgl3AwareBoundaryTest::isRemapUnsafeType)) {
|
||||
violations.add(renderBackend.name() + "." + method.name() + method.desc());
|
||||
}
|
||||
}
|
||||
assertTrue(violations.isEmpty(), "RenderBackend methods with an org.lwjgl/org.lwjglx/lwjgl3ify type in their signature:\n" + String.join("\n", violations));
|
||||
}
|
||||
|
||||
private static boolean isAware(JavaClass c) {
|
||||
return c.isAnnotatedWith(AWARE);
|
||||
private static boolean isAware(String name) {
|
||||
final ScannedClass c = ArchScan.find(name);
|
||||
return c != null && c.annotations().contains(AWARE);
|
||||
}
|
||||
|
||||
private static boolean isUntransformed(JavaClass c) {
|
||||
return UNTRANSFORMED_PACKAGES.stream().anyMatch(p -> c.getName().startsWith(p));
|
||||
private static boolean isUntransformed(String name) {
|
||||
return UNTRANSFORMED_PACKAGES.stream().anyMatch(name::startsWith);
|
||||
}
|
||||
|
||||
private static boolean isLwjgl3Type(JavaClass type) {
|
||||
return type.getName().startsWith("org.lwjgl.");
|
||||
private static boolean isLwjgl3Type(String name) {
|
||||
return name.startsWith("org.lwjgl.");
|
||||
}
|
||||
|
||||
private static boolean isRemapUnsafeType(JavaClass type) {
|
||||
final String name = type.getName();
|
||||
return isLwjgl3Type(type) || name.startsWith("org.lwjglx.") || name.startsWith("me.eigenraven.lwjgl3ify.");
|
||||
private static boolean isRemapUnsafeType(String name) {
|
||||
return isLwjgl3Type(name) || name.startsWith("org.lwjglx.") || name.startsWith("me.eigenraven.lwjgl3ify.");
|
||||
}
|
||||
|
||||
private static boolean mentionsLwjgl3Type(AccessTarget target) {
|
||||
return descriptorTypes(target).stream().anyMatch(Lwjgl3AwareBoundaryTest::isLwjgl3Type);
|
||||
private static boolean mentionsLwjgl3Type(Access access) {
|
||||
return access.descriptorTypes().stream().anyMatch(Lwjgl3AwareBoundaryTest::isLwjgl3Type);
|
||||
}
|
||||
|
||||
private static List<JavaClass> descriptorTypes(AccessTarget target) {
|
||||
if (target instanceof AccessTarget.FieldAccessTarget field) {
|
||||
return List.of(field.getRawType());
|
||||
}
|
||||
if (target instanceof AccessTarget.CodeUnitCallTarget call) {
|
||||
final List<JavaClass> types = new ArrayList<>(call.getRawParameterTypes());
|
||||
if (target instanceof AccessTarget.MethodCallTarget method) {
|
||||
types.add(method.getRawReturnType());
|
||||
}
|
||||
return types;
|
||||
}
|
||||
return List.of();
|
||||
}
|
||||
|
||||
private static String describe(JavaAccess<?> access) {
|
||||
return " " + access.getOwner().getFullName() + " -> " + access.getTarget().getFullName();
|
||||
private static String describe(ScannedClass origin, Access access) {
|
||||
return " " + origin.name() + "." + access.method() + " -> " + access.target();
|
||||
}
|
||||
}
|
||||
@@ -1,15 +1,16 @@
|
||||
package com.gtnewhorizons.angelica.arch;
|
||||
|
||||
import com.tngtech.archunit.core.domain.JavaClasses;
|
||||
import com.tngtech.archunit.core.importer.ClassFileImporter;
|
||||
import com.tngtech.archunit.core.importer.ImportOption;
|
||||
import com.tngtech.archunit.lang.ArchRule;
|
||||
import com.gtnewhorizons.angelica.arch.ArchScan.Access;
|
||||
import com.gtnewhorizons.angelica.arch.ArchScan.Dir;
|
||||
import com.gtnewhorizons.angelica.arch.ArchScan.Kind;
|
||||
import com.gtnewhorizons.angelica.arch.ArchScan.ScannedClass;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static com.tngtech.archunit.core.domain.JavaCall.Predicates.target;
|
||||
import static com.tngtech.archunit.core.domain.properties.HasName.Predicates.nameMatching;
|
||||
import static com.tngtech.archunit.core.domain.properties.HasOwner.Predicates.With.owner;
|
||||
import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.noClasses;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
/**
|
||||
* Enforces that all GL calls go through GLStateManager / RENDER_BACKEND. Direct method calls on org.lwjgl.opengl GL command classes are banned outside
|
||||
@@ -23,27 +24,22 @@ class NoDirectGLCallsTest {
|
||||
|
||||
// Matches GL command classes but not LWJGL infrastructure (Display, etc.)
|
||||
// Covers: GL11-GL44, ARB*, EXT*, NV*, AMD*, ATI*, KHR*, INTEL*, GLContext, plus OpenGlHelper
|
||||
private static final String GL_COMMAND_CLASSES = "org\\.lwjgl\\.opengl\\.(?!Display|ContextAttribs|PixelFormat|Drawable|SharedDrawable).*";
|
||||
private static final Pattern GL_COMMAND_CLASSES = Pattern.compile("org\\.lwjgl\\.opengl\\.(?!Display|ContextAttribs|PixelFormat|Drawable|SharedDrawable).*");
|
||||
|
||||
private static final JavaClasses classes = new ClassFileImporter()
|
||||
.withImportOption(ImportOption.Predefined.DO_NOT_INCLUDE_TESTS)
|
||||
.importPaths(
|
||||
"build/classes/java/main",
|
||||
"build/classes/java/mixin"
|
||||
);
|
||||
|
||||
private static final ArchRule NO_DIRECT_GL_CALLS = noClasses()
|
||||
.that().resideOutsideOfPackages(
|
||||
"com.gtnewhorizons.angelica.glsm.backend..",
|
||||
"com.gtnewhorizons.angelica.loading.."
|
||||
)
|
||||
.should().callMethodWhere(
|
||||
target(owner(nameMatching(GL_COMMAND_CLASSES)))
|
||||
)
|
||||
.because("GL calls must go through GLStateManager, not directly to LWJGL or the RENDER_BACKEND");
|
||||
private static final List<String> EXEMPT_PACKAGES = List.of(
|
||||
"com.gtnewhorizons.angelica.glsm.backend.",
|
||||
"com.gtnewhorizons.angelica.loading.");
|
||||
|
||||
@Test
|
||||
void noDirectGLCalls() {
|
||||
NO_DIRECT_GL_CALLS.check(classes);
|
||||
final List<String> violations = new ArrayList<>();
|
||||
for (ScannedClass origin : ArchScan.in(Dir.MAIN, Dir.MIXIN)) {
|
||||
if (EXEMPT_PACKAGES.stream().anyMatch(origin.name()::startsWith)) continue;
|
||||
for (Access access : origin.accesses()) {
|
||||
if (access.kind() != Kind.CALL || access.name().equals("<init>")) continue;
|
||||
if (GL_COMMAND_CLASSES.matcher(access.owner()).matches()) violations.add(" " + origin.name() + "." + access.method() + " -> " + access.target());
|
||||
}
|
||||
}
|
||||
assertTrue(violations.isEmpty(), "GL calls must go through GLStateManager, not directly to LWJGL or the RENDER_BACKEND:\n" + String.join("\n", violations));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package com.gtnewhorizons.angelica.arch;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
class NoWildcardImportsTest {
|
||||
|
||||
private static final List<String> SOURCE_DIRS = List.of("src/main/java", "src/mixin/java", "src/test/java");
|
||||
|
||||
private static final Pattern WILDCARD_IMPORT = Pattern.compile("\\s*import\\s+(?!static\\s)[\\w.]+\\.\\*\\s*;.*");
|
||||
|
||||
@Test
|
||||
void noWildcardImports() throws IOException {
|
||||
final List<String> violations = new ArrayList<>();
|
||||
for (String dir : SOURCE_DIRS) {
|
||||
final List<Path> sources;
|
||||
try (Stream<Path> files = Files.walk(Paths.get(dir))) {
|
||||
sources = files.filter(file -> file.toString().endsWith(".java")).collect(Collectors.toList());
|
||||
}
|
||||
assertFalse(sources.isEmpty(), dir + " has no Java sources");
|
||||
for (Path source : sources) {
|
||||
final String[] lines = new String(Files.readAllBytes(source), StandardCharsets.ISO_8859_1).split("\r?\n");
|
||||
for (int i = 0; i < lines.length; i++) {
|
||||
if (WILDCARD_IMPORT.matcher(lines[i]).matches()) violations.add(" " + source + ":" + (i + 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
assertTrue(violations.isEmpty(), "Wildcard imports (static ones are allowed):\n" + String.join("\n", violations));
|
||||
}
|
||||
}
|
||||
@@ -1,21 +1,16 @@
|
||||
package com.gtnewhorizons.angelica.arch;
|
||||
|
||||
import com.tngtech.archunit.base.DescribedPredicate;
|
||||
import com.tngtech.archunit.core.domain.JavaAccess;
|
||||
import com.tngtech.archunit.core.domain.JavaClass;
|
||||
import com.tngtech.archunit.core.domain.JavaClasses;
|
||||
import com.tngtech.archunit.core.domain.ReferencedClassObject;
|
||||
import com.tngtech.archunit.core.domain.JavaStaticInitializer;
|
||||
import com.tngtech.archunit.core.importer.ClassFileImporter;
|
||||
import com.tngtech.archunit.core.importer.ImportOption;
|
||||
import com.tngtech.archunit.lang.ArchRule;
|
||||
import com.gtnewhorizons.angelica.arch.ArchScan.Access;
|
||||
import com.gtnewhorizons.angelica.arch.ArchScan.ClassConstant;
|
||||
import com.gtnewhorizons.angelica.arch.ArchScan.Dir;
|
||||
import com.gtnewhorizons.angelica.arch.ArchScan.ScannedClass;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.noClasses;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
/**
|
||||
@@ -29,69 +24,59 @@ class SDLGPUEncapsulationTest {
|
||||
|
||||
private static final String LWJGL3_AWARE = "me.eigenraven.lwjgl3ify.api.Lwjgl3Aware";
|
||||
|
||||
private static final DescribedPredicate<JavaClass> SDLGPU_BEHIND_THE_GATE =
|
||||
new DescribedPredicate<>("anything under " + SDLGPU_ROOT + " other than SDLGPUGate") {
|
||||
@Override
|
||||
public boolean test(JavaClass c) {
|
||||
final String name = c.getName();
|
||||
return name.startsWith(SDLGPU_ROOT + ".") && !GATE.equals(name);
|
||||
}
|
||||
};
|
||||
|
||||
private static final DescribedPredicate<JavaClass> LWJGL3_ONLY_TYPE =
|
||||
new DescribedPredicate<>("types that only exist under lwjgl3ify/LWJGL3") {
|
||||
@Override
|
||||
public boolean test(JavaClass c) {
|
||||
final String name = c.getName();
|
||||
if (LWJGL3_AWARE.equals(name)) return false;
|
||||
return name.startsWith("org.lwjglx.") || name.startsWith("me.eigenraven.lwjgl3ify.") || name.startsWith("org.lwjgl.sdl.");
|
||||
}
|
||||
};
|
||||
|
||||
private static final JavaClasses CLASSES = new ClassFileImporter()
|
||||
.withImportOption(ImportOption.Predefined.DO_NOT_INCLUDE_TESTS)
|
||||
.importPaths("build/classes/java/main", "build/classes/java/mixin", "glsm/build/classes/java/main");
|
||||
|
||||
private static final JavaClasses SDLGPU_CLASSES = new ClassFileImporter()
|
||||
.withImportOption(ImportOption.Predefined.DO_NOT_INCLUDE_TESTS)
|
||||
.importPaths("sdl-gpu/build/classes/java/main");
|
||||
|
||||
private static final ArchRule SDLGPU_REACHED_ONLY_THROUGH_THE_GATE = noClasses()
|
||||
.that().resideOutsideOfPackage(SDLGPU_ROOT + "..")
|
||||
.should().dependOnClassesThat(SDLGPU_BEHIND_THE_GATE)
|
||||
.because("SDLGPUGate is the only :sdl-gpu class safe to load without LWJGL3");
|
||||
|
||||
private static final ArchRule NO_LWJGL3_ONLY_TYPES = noClasses()
|
||||
.that().resideOutsideOfPackage(SDLGPU_ROOT + "..")
|
||||
.should().dependOnClassesThat(LWJGL3_ONLY_TYPE)
|
||||
.because("main, mixin and glsm all load on an LWJGL2 launch, where these types are absent");
|
||||
|
||||
@Test
|
||||
void sdlGpuIsReachedOnlyThroughTheGate() {
|
||||
SDLGPU_REACHED_ONLY_THROUGH_THE_GATE.check(CLASSES);
|
||||
final List<String> violations = referencesOutsideSdlGpu(SDLGPUEncapsulationTest::isBehindTheGate);
|
||||
assertTrue(violations.isEmpty(), "SDLGPUGate is the only :sdl-gpu class safe to load without LWJGL3:\n" + String.join("\n", violations));
|
||||
}
|
||||
|
||||
@Test
|
||||
void noLwjgl3OnlyTypesOutsideSdlGpu() {
|
||||
NO_LWJGL3_ONLY_TYPES.check(CLASSES);
|
||||
final List<String> violations = referencesOutsideSdlGpu(SDLGPUEncapsulationTest::isLwjgl3OnlyType);
|
||||
assertTrue(violations.isEmpty(), "main, mixin and glsm all load on an LWJGL2 launch, where these types are absent:\n" + String.join("\n", violations));
|
||||
}
|
||||
|
||||
@Test
|
||||
void gateStaticInitIsLwjgl3Free() {
|
||||
final Optional<JavaStaticInitializer> clinit = SDLGPU_CLASSES.get(GATE).getStaticInitializer();
|
||||
assertTrue(clinit.isPresent(), GATE + " has no static initializer to check; the importer path is likely wrong");
|
||||
final ScannedClass gate = ArchScan.get(GATE);
|
||||
assertTrue(gate.methods().stream().anyMatch(m -> m.name().equals("<clinit>")), GATE + " has no static initializer to check; the scan path is likely wrong");
|
||||
|
||||
final List<String> violations = new ArrayList<>();
|
||||
for (JavaAccess<?> access : clinit.get().getAccessesFromSelf()) {
|
||||
if (isLwjgl3(access.getTargetOwner())) violations.add(" " + access.getTarget().getFullName());
|
||||
for (Access access : gate.accesses()) {
|
||||
if (isStaticInit(access.method()) && isLwjgl3(access.owner())) violations.add(" " + access.target());
|
||||
}
|
||||
for (ReferencedClassObject ref : clinit.get().getReferencedClassObjects()) {
|
||||
if (isLwjgl3(ref.getValue())) violations.add(" " + ref.getValue().getName() + ".class");
|
||||
for (ClassConstant constant : gate.classConstants()) {
|
||||
if (isStaticInit(constant.method()) && isLwjgl3(constant.type())) violations.add(" " + constant.type() + ".class");
|
||||
}
|
||||
assertTrue(violations.isEmpty(), GATE + " static init resolves LWJGL3 types:\n" + String.join("\n", violations));
|
||||
}
|
||||
|
||||
private static boolean isLwjgl3(JavaClass c) {
|
||||
return LWJGL3_ONLY_TYPE.test(c) || c.getName().startsWith("org.lwjgl.");
|
||||
private static List<String> referencesOutsideSdlGpu(Predicate<String> forbidden) {
|
||||
final List<String> violations = new ArrayList<>();
|
||||
for (ScannedClass origin : ArchScan.in(Dir.MAIN, Dir.MIXIN, Dir.GLSM)) {
|
||||
if (origin.name().startsWith(SDLGPU_ROOT + ".")) continue;
|
||||
for (String reference : origin.references()) {
|
||||
if (forbidden.test(reference)) violations.add(" " + origin.name() + " -> " + reference);
|
||||
}
|
||||
}
|
||||
Collections.sort(violations);
|
||||
return violations;
|
||||
}
|
||||
|
||||
private static boolean isBehindTheGate(String name) {
|
||||
return name.startsWith(SDLGPU_ROOT + ".") && !GATE.equals(name);
|
||||
}
|
||||
|
||||
private static boolean isLwjgl3OnlyType(String name) {
|
||||
if (LWJGL3_AWARE.equals(name)) return false;
|
||||
return name.startsWith("org.lwjglx.") || name.startsWith("me.eigenraven.lwjgl3ify.") || name.startsWith("org.lwjgl.sdl.");
|
||||
}
|
||||
|
||||
private static boolean isLwjgl3(String name) {
|
||||
return isLwjgl3OnlyType(name) || name.startsWith("org.lwjgl.");
|
||||
}
|
||||
|
||||
private static boolean isStaticInit(String method) {
|
||||
return method.startsWith("<clinit>") || method.startsWith("lambda$static$");
|
||||
}
|
||||
}
|
||||
@@ -81,15 +81,19 @@ final class BopFogTestSupport {
|
||||
}
|
||||
}
|
||||
|
||||
static <T> T stub(Class<T> type) {
|
||||
return Mockito.mock(type, Mockito.withSettings().stubOnly());
|
||||
}
|
||||
|
||||
static World mockWorld(Grid grid) {
|
||||
final World world = Mockito.mock(World.class);
|
||||
final IChunkProvider provider = Mockito.mock(IChunkProvider.class);
|
||||
final World world = stub(World.class);
|
||||
final IChunkProvider provider = stub(IChunkProvider.class);
|
||||
when(world.getChunkProvider()).thenReturn(provider);
|
||||
when(provider.chunkExists(anyInt(), anyInt())).thenReturn(true);
|
||||
|
||||
final BiomeGenBase fogBiome = BopFog.mockBiome();
|
||||
final BiomeGenBase fogBiome = Mockito.mock(BiomeGenBase.class, Mockito.withSettings().extraInterfaces(BopFog.TYPE).stubOnly());
|
||||
when(BopFog.stubCall(fogBiome)).thenAnswer(inv -> grid.colorAt(inv.getArgument(0), inv.getArgument(1), inv.getArgument(2)));
|
||||
final BiomeGenBase plainBiome = Mockito.mock(BiomeGenBase.class);
|
||||
final BiomeGenBase plainBiome = stub(BiomeGenBase.class);
|
||||
|
||||
when(world.getBiomeGenForCoords(anyInt(), anyInt())).thenAnswer(inv -> grid.isFog(inv.getArgument(0), inv.getArgument(1)) ? fogBiome : plainBiome);
|
||||
return world;
|
||||
|
||||
@@ -12,9 +12,9 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import static com.gtnewhorizons.angelica.compat.bop.BopFogTestSupport.mockWorld;
|
||||
import static com.gtnewhorizons.angelica.compat.bop.BopFogTestSupport.stub;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@@ -26,8 +26,8 @@ class FogAggregateTest {
|
||||
}
|
||||
|
||||
private static World world(AtomicBoolean loaded, AtomicInteger color) {
|
||||
final World world = mock(World.class);
|
||||
final IChunkProvider provider = mock(IChunkProvider.class);
|
||||
final World world = stub(World.class);
|
||||
final IChunkProvider provider = stub(IChunkProvider.class);
|
||||
when(world.getChunkProvider()).thenReturn(provider);
|
||||
when(provider.chunkExists(anyInt(), anyInt())).thenAnswer(inv -> loaded.get());
|
||||
final BiomeGenBase biome = BopFog.mockBiome();
|
||||
@@ -146,7 +146,7 @@ class FogAggregateTest {
|
||||
final AtomicBoolean loaded = new AtomicBoolean(false);
|
||||
final World world = world(loaded, new AtomicInteger(0x010203));
|
||||
final BiomeGenBase fog = world.getBiomeGenForCoords(0, 0);
|
||||
when(world.getBiomeGenForCoords(anyInt(), anyInt())).thenReturn(mock(BiomeGenBase.class));
|
||||
when(world.getBiomeGenForCoords(anyInt(), anyInt())).thenReturn(stub(BiomeGenBase.class));
|
||||
final float[] actual = new float[4];
|
||||
FogColourGrid.accumulateInterior(world, 0, 64, 0, 1, actual);
|
||||
assertBits(new float[4], actual);
|
||||
|
||||
@@ -5,12 +5,12 @@ import net.minecraft.world.biome.BiomeGenBase;
|
||||
import net.minecraft.world.chunk.IChunkProvider;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
import java.util.function.IntBinaryOperator;
|
||||
|
||||
import com.gtnewhorizons.angelica.compat.bop.BopFogTestSupport.BopFog;
|
||||
|
||||
import static com.gtnewhorizons.angelica.compat.bop.BopFogTestSupport.stub;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.Mockito.times;
|
||||
@@ -25,8 +25,8 @@ class FogColourGridTest {
|
||||
}
|
||||
|
||||
private static World mockWorld(boolean chunksLoaded) {
|
||||
final World world = Mockito.mock(World.class);
|
||||
final IChunkProvider provider = Mockito.mock(IChunkProvider.class);
|
||||
final World world = stub(World.class);
|
||||
final IChunkProvider provider = stub(IChunkProvider.class);
|
||||
when(world.getChunkProvider()).thenReturn(provider);
|
||||
when(provider.chunkExists(anyInt(), anyInt())).thenReturn(chunksLoaded);
|
||||
return world;
|
||||
|
||||
+1
-1
@@ -262,7 +262,7 @@ class SectionMetaBufferTest {
|
||||
});
|
||||
|
||||
try {
|
||||
Thread.sleep(2000);
|
||||
Thread.sleep(200);
|
||||
stop.set(true);
|
||||
writer.join();
|
||||
reader.join();
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
# The arch tests only need names and descriptors off the imported bytecode.
|
||||
resolveMissingDependenciesFromClassPath=false
|
||||
Reference in new issue
Block a user