diff --git a/lib/src/test/java/com/team2813/lib2813/preferences/IsolatedPreferences.java b/lib/src/test/java/com/team2813/lib2813/preferences/IsolatedPreferences.java index 0dc32574..b9be8530 100644 --- a/lib/src/test/java/com/team2813/lib2813/preferences/IsolatedPreferences.java +++ b/lib/src/test/java/com/team2813/lib2813/preferences/IsolatedPreferences.java @@ -42,12 +42,12 @@ protected void before() { @Override protected void after() { - if (!tempInstance.waitForListenerQueue(.4)) { + Preferences.setNetworkTableInstance(NetworkTableInstance.getDefault()); + if (!tempInstance.waitForListenerQueue(.2)) { System.err.println( "Timed out waiting for the NetworkTableInstance listener queue to empty (waited 200ms);" + " JVM may crash"); } - Preferences.setNetworkTableInstance(NetworkTableInstance.getDefault()); tempInstance.close(); } } diff --git a/testing/src/main/java/com/team2813/lib2813/testing/junit/jupiter/IsolatedNetworkTablesExtension.java b/testing/src/main/java/com/team2813/lib2813/testing/junit/jupiter/IsolatedNetworkTablesExtension.java index eb82b005..4b90a8a3 100644 --- a/testing/src/main/java/com/team2813/lib2813/testing/junit/jupiter/IsolatedNetworkTablesExtension.java +++ b/testing/src/main/java/com/team2813/lib2813/testing/junit/jupiter/IsolatedNetworkTablesExtension.java @@ -18,6 +18,7 @@ import edu.wpi.first.networktables.NetworkTableInstance; import edu.wpi.first.wpilibj.Preferences; import org.junit.jupiter.api.extension.AfterEachCallback; +import org.junit.jupiter.api.extension.BeforeEachCallback; import org.junit.jupiter.api.extension.Extension; import org.junit.jupiter.api.extension.ExtensionContext; import org.junit.jupiter.api.extension.ExtensionContext.Namespace; @@ -45,28 +46,37 @@ * @since 2.0.0 */ public final class IsolatedNetworkTablesExtension - implements Extension, AfterEachCallback, ParameterResolver { - private static final StoreKey NETWORK_TABLE_INSTANCE_KEY = - StoreKey.of(NetworkTableInstance.class); + implements Extension, BeforeEachCallback, AfterEachCallback, ParameterResolver { + private static final Namespace NAMESPACE = Namespace.create(IsolatedNetworkTablesExtension.class); + private static final StoreKey DATA_KEY = StoreKey.of(Data.class); + + @Override + public void beforeEach(ExtensionContext context) { + Store store = context.getStore(NAMESPACE); + NetworkTableInstance ntInstance = + DATA_KEY.getOrComputeIfAbsent(store, Data::create).testInstance; + Preferences.setNetworkTableInstance(ntInstance); + } @Override public void afterEach(ExtensionContext context) { // If this extension created a temporary NetworkTableInstance, close it. - var ntInstance = NETWORK_TABLE_INSTANCE_KEY.remove(getStore(context)); - if (ntInstance != null) { + Store store = context.getStore(NAMESPACE); + Data data = DATA_KEY.remove(store); + if (data != null) { + Preferences.setNetworkTableInstance(data.prevInstance); + // Clear out the listener queue before destroying our temporary NetworkTableInstance. // // This works around a race condition in WPILib where a listener registered by Preferences can // be called after the NetworkTableInstance was closed (see // https://github.com/wpilibsuite/allwpilib/issues/8215). - if (!ntInstance.waitForListenerQueue(.4)) { + if (!data.testInstance.waitForListenerQueue(.2)) { System.err.println( "Timed out waiting for the NetworkTableInstance listener queue to empty (waited 200ms);" + " JVM may crash"); } - - Preferences.setNetworkTableInstance(NetworkTableInstance.getDefault()); - ntInstance.close(); + data.testInstance.close(); } } @@ -74,6 +84,9 @@ public void afterEach(ExtensionContext context) { public boolean supportsParameter( ParameterContext parameterContext, ExtensionContext extensionContext) throws ParameterResolutionException { + if (parameterContext.getTarget().isEmpty()) { + return false; // The extension only supports test method parameter injection. + } return NetworkTableInstance.class.equals(parameterContext.getParameter().getType()); } @@ -81,17 +94,16 @@ public boolean supportsParameter( public NetworkTableInstance resolveParameter( ParameterContext parameterContext, ExtensionContext extensionContext) throws ParameterResolutionException { - Store store = getStore(extensionContext); - NetworkTableInstance ntInstance = - NETWORK_TABLE_INSTANCE_KEY.getOrComputeIfAbsent(store, NetworkTableInstance::create); - - ntInstance.startLocal(); - Preferences.setNetworkTableInstance(ntInstance); - return ntInstance; + Store store = extensionContext.getStore(NAMESPACE); + return DATA_KEY.get(store).testInstance; } - /** Gets the {@link Store} for this extension. */ - private Store getStore(ExtensionContext context) { - return context.getStore(Namespace.create(getClass(), context.getRequiredTestMethod())); + private record Data(NetworkTableInstance testInstance, NetworkTableInstance prevInstance) { + static Data create() { + NetworkTableInstance testInstance = NetworkTableInstance.create(); + testInstance.startLocal(); + NetworkTableInstance prevInstance = Preferences.getNetworkTable().getInstance(); + return new Data(testInstance, prevInstance); + } } } diff --git a/testing/src/test/java/com/team2813/lib2813/testing/junit/jupiter/IsolatedNetworkTablesExtensionTest.java b/testing/src/test/java/com/team2813/lib2813/testing/junit/jupiter/IsolatedNetworkTablesExtensionTest.java index ef6c25d5..cc0e0665 100644 --- a/testing/src/test/java/com/team2813/lib2813/testing/junit/jupiter/IsolatedNetworkTablesExtensionTest.java +++ b/testing/src/test/java/com/team2813/lib2813/testing/junit/jupiter/IsolatedNetworkTablesExtensionTest.java @@ -1,5 +1,5 @@ /* -Copyright 2025 Prospect Robotics SWENext Club +Copyright 2025-2026 Prospect Robotics SWENext Club Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -20,6 +20,7 @@ import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClass; import edu.wpi.first.networktables.NetworkTableInstance; +import edu.wpi.first.wpilibj.Preferences; import org.junit.jupiter.api.MethodOrderer; import org.junit.jupiter.api.Tag; import org.junit.jupiter.api.Test; @@ -42,6 +43,12 @@ public void verifyProvidesNetworkTableParameter(NetworkTableInstance ntInstance) assertThat(ntInstance.getHandle()) .isNotEqualTo(NetworkTableInstance.getDefault().getHandle()); } + + @Test + public void verifyReplacesPreferencesNetworkTableInstance() { + assertThat(Preferences.getNetworkTable().getInstance().getHandle()) + .isNotEqualTo(NetworkTableInstance.getDefault().getHandle()); + } } // end SampleTest @Test