mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-06-21 01:01:43 +00:00
[wpiutil] Add reflection based cleanup helper (#4919)
Co-authored-by: Starlight220 <53231611+Starlight220@users.noreply.github.com>
This commit is contained in:
@@ -0,0 +1,154 @@
|
||||
// Copyright (c) FIRST and other WPILib contributors.
|
||||
// Open Source Software; you can modify and/or share it under the terms of
|
||||
// the WPILib BSD license file in the root directory of this project.
|
||||
|
||||
package edu.wpi.first.util.cleanup;
|
||||
|
||||
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.ArrayList;
|
||||
import java.util.List;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class CleanupPoolTest {
|
||||
static class AutoCloseableObject implements AutoCloseable {
|
||||
public boolean m_closed;
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
m_closed = true;
|
||||
}
|
||||
}
|
||||
|
||||
static class AutoCloseableObjectWithCallback implements AutoCloseable {
|
||||
private final Runnable m_cb;
|
||||
|
||||
AutoCloseableObjectWithCallback(Runnable cb) {
|
||||
m_cb = cb;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
m_cb.run();
|
||||
}
|
||||
}
|
||||
|
||||
static class FailingAutoCloseableObject implements AutoCloseable {
|
||||
public static final String message = "This is an expected failure";
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
throw new RuntimeException(message);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void cleanupStackWorks() {
|
||||
List<AutoCloseableObject> objects = new ArrayList<>();
|
||||
objects.add(new AutoCloseableObject());
|
||||
objects.add(new AutoCloseableObject());
|
||||
objects.add(new AutoCloseableObject());
|
||||
|
||||
try (CleanupPool pool = new CleanupPool()) {
|
||||
for (AutoCloseableObject autoCloseableObject : objects) {
|
||||
pool.register(autoCloseableObject);
|
||||
}
|
||||
}
|
||||
|
||||
for (AutoCloseableObject autoCloseableObject : objects) {
|
||||
assertTrue(autoCloseableObject.m_closed);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("PMD.AvoidCatchingGenericException")
|
||||
void cleanupStackWithExceptionNotInCloseWorks() {
|
||||
List<AutoCloseableObject> objects = new ArrayList<>();
|
||||
objects.add(new AutoCloseableObject());
|
||||
objects.add(new AutoCloseableObject());
|
||||
objects.add(new AutoCloseableObject());
|
||||
|
||||
String message = "This is a known failure";
|
||||
|
||||
try (CleanupPool pool = new CleanupPool()) {
|
||||
for (AutoCloseableObject autoCloseableObject : objects) {
|
||||
pool.register(autoCloseableObject);
|
||||
}
|
||||
throw new Exception(message);
|
||||
} catch (Exception e) {
|
||||
assertEquals(message, e.getMessage());
|
||||
}
|
||||
|
||||
for (AutoCloseableObject autoCloseableObject : objects) {
|
||||
assertTrue(autoCloseableObject.m_closed);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("PMD.AvoidCatchingGenericException")
|
||||
void cleanupStackWithExceptionInCloseWorks() {
|
||||
List<AutoCloseableObject> objects = new ArrayList<>();
|
||||
objects.add(new AutoCloseableObject());
|
||||
objects.add(new AutoCloseableObject());
|
||||
objects.add(new AutoCloseableObject());
|
||||
|
||||
try (CleanupPool pool = new CleanupPool()) {
|
||||
for (AutoCloseableObject autoCloseableObject : objects) {
|
||||
pool.register(new FailingAutoCloseableObject());
|
||||
pool.register(autoCloseableObject);
|
||||
}
|
||||
}
|
||||
|
||||
for (AutoCloseableObject autoCloseableObject : objects) {
|
||||
assertTrue(autoCloseableObject.m_closed);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void cleanupStackRemovalWorks() {
|
||||
List<AutoCloseableObject> objects = new ArrayList<>();
|
||||
objects.add(new AutoCloseableObject());
|
||||
objects.add(new AutoCloseableObject());
|
||||
objects.add(new AutoCloseableObject());
|
||||
|
||||
try (CleanupPool pool = new CleanupPool()) {
|
||||
for (AutoCloseableObject autoCloseableObject : objects) {
|
||||
pool.register(autoCloseableObject);
|
||||
}
|
||||
|
||||
pool.remove(objects.get(0));
|
||||
}
|
||||
|
||||
int idx = 0;
|
||||
for (AutoCloseableObject autoCloseableObject : objects) {
|
||||
if (idx == 0) {
|
||||
assertFalse(autoCloseableObject.m_closed);
|
||||
} else {
|
||||
assertTrue(autoCloseableObject.m_closed);
|
||||
}
|
||||
idx++;
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void cleanupStackIsLifo() {
|
||||
List<AutoCloseableObjectWithCallback> objects = new ArrayList<>();
|
||||
List<Integer> order = new ArrayList<>();
|
||||
objects.add(new AutoCloseableObjectWithCallback(() -> order.add(0)));
|
||||
objects.add(new AutoCloseableObjectWithCallback(() -> order.add(1)));
|
||||
objects.add(new AutoCloseableObjectWithCallback(() -> order.add(2)));
|
||||
|
||||
try (CleanupPool pool = new CleanupPool()) {
|
||||
for (AutoCloseable autoCloseableObject : objects) {
|
||||
pool.register(autoCloseableObject);
|
||||
}
|
||||
}
|
||||
|
||||
assertEquals(order.size(), 3);
|
||||
assertEquals(order.get(0), 2);
|
||||
assertEquals(order.get(1), 1);
|
||||
assertEquals(order.get(2), 0);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
// Copyright (c) FIRST and other WPILib contributors.
|
||||
// Open Source Software; you can modify and/or share it under the terms of
|
||||
// the WPILib BSD license file in the root directory of this project.
|
||||
|
||||
package edu.wpi.first.util.cleanup;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class ReflectionCleanupTest {
|
||||
static class CleanupClass implements AutoCloseable {
|
||||
public boolean m_closed;
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
m_closed = true;
|
||||
}
|
||||
}
|
||||
|
||||
static class CleanupTest implements ReflectionCleanup {
|
||||
public CleanupClass m_class1 = new CleanupClass();
|
||||
public CleanupClass m_class2 = new CleanupClass();
|
||||
public Object m_nonCleanupObject = new Object();
|
||||
public Object m_nullCleanupObject;
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
reflectionCleanup(CleanupTest.class);
|
||||
}
|
||||
}
|
||||
|
||||
static class CleanupTest2 extends CleanupTest {
|
||||
@SkipCleanup public CleanupClass m_class3 = new CleanupClass();
|
||||
public CleanupClass m_class4 = new CleanupClass();
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
reflectionCleanup(CleanupTest2.class);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void cleanupClosesAllFields() {
|
||||
CleanupTest test = new CleanupTest();
|
||||
test.close();
|
||||
assertTrue(test.m_class1.m_closed);
|
||||
assertTrue(test.m_class2.m_closed);
|
||||
}
|
||||
|
||||
@Test
|
||||
void cleanupOnlyClosesExplicitClassAndSkipWorks() {
|
||||
CleanupTest2 test = new CleanupTest2();
|
||||
test.close();
|
||||
assertFalse(test.m_class1.m_closed);
|
||||
assertFalse(test.m_class2.m_closed);
|
||||
assertFalse(test.m_class3.m_closed);
|
||||
assertTrue(test.m_class4.m_closed);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user