All Downloads are FREE. Search and download functionalities are using the official Maven repository.

us.ihmc.commons.allocations.AllocationTestTest Maven / Gradle / Ivy

package us.ihmc.commons.allocations;

import org.apache.commons.lang3.mutable.MutableDouble;
import org.apache.commons.lang3.mutable.MutableInt;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.parallel.Execution;
import org.junit.jupiter.api.parallel.ExecutionMode;
import us.ihmc.commons.MutationTestFacilitator;
import us.ihmc.log.LogTools;
import us.ihmc.commons.thread.ThreadTools;

import java.util.List;

@Tag("allocation")
public class AllocationTestTest
{
   private enum MyEnum
   {
      A, B, C, D
   }

   ;

   @Execution(ExecutionMode.SAME_THREAD)
   @Test
   public void testSettingOfVector()
   {
      MutableDouble data = new MutableDouble();
      List allocations = new AllocationProfiler().recordAllocations(() -> data.setValue(1.0));
      Assertions.assertEquals(0, allocations.size());
   }

   @SuppressWarnings("unused")
   @Execution(ExecutionMode.SAME_THREAD)
   @Test
   public void testAllocationOfArray()
   {
      List allocations = new AllocationProfiler().recordAllocations(() -> {
         double[] someArray = new double[12];
      });

      Assertions.assertEquals(1, allocations.size());
      assertAllocationsContain(allocations, double[].class);
//      Assertions.assertTrue(allocations.get(0).getAllocatedObject().getClass().equals(double[].class));
      LogTools.info(allocations.get(0).toString());
   }

   @Execution(ExecutionMode.SAME_THREAD)
   @Test
   public void testSingleAllocation()
   {
      List allocations = new AllocationProfiler().recordAllocations(() -> new MutableDouble());
      printAllocations(allocations);
      Assertions.assertEquals(1, allocations.size());
      Assertions.assertTrue(allocations.get(0).getAllocatedObject().getClass().equals(MutableDouble.class));
      LogTools.info(allocations.get(0).toString());
   }

   @Execution(ExecutionMode.SAME_THREAD)
   @Test
   public void testSingleAllocationConstructorFilter()
   {
      List allocations;
      AllocationProfiler allocationProfiler = new AllocationProfiler();

      allocationProfiler.setRecordConstructorAllocations(true);
      allocations = allocationProfiler.recordAllocations(() -> new LilAllocator());
      printAllocations(allocations);
      Assertions.assertEquals(3, allocations.size());

      allocationProfiler.setRecordConstructorAllocations(false);
      allocations = allocationProfiler.recordAllocations(() -> new LilAllocator());
      printAllocations(allocations);
      Assertions.assertEquals(1, allocations.size());
   }

   @Execution(ExecutionMode.SAME_THREAD)
   @Test
   public void testWhitelist()
   {
      List allocations;
      AllocationProfiler allocationProfiler = new AllocationProfiler();

      LilAllocator lilAllocator;
      MutableInt mutableInt;

      // test control; no black or white lists
      allocationProfiler.setIncludeAllAllocations(false); // exclude everything
      allocationProfiler.startRecordingAllocations();
      lilAllocator = new LilAllocator(); // allocates 1 but ignore, stuff inside does not count
      mutableInt = new MutableInt(); // random new thing
      lilAllocator.doStuff(); // allocates 2 things inside
      allocationProfiler.stopRecordingAllocations();

      allocations = allocationProfiler.pollAllocations();
      printAllocations(allocations);
      Assertions.assertEquals(0, allocations.size()); // nothing was included so should be 0

      // add one class to whitelist
      allocationProfiler.includeAllocationsInsideClass(LilAllocator.class.getName());
      allocationProfiler.startRecordingAllocations();
      lilAllocator = new LilAllocator(); // does not count, constructor exclusion
      mutableInt = new MutableInt(); // random new thing, but not in whitelist
      lilAllocator.doStuff(); // allocates 2 things inside
      allocationProfiler.stopRecordingAllocations();

      allocations = allocationProfiler.pollAllocations();
      printAllocations(allocations);
      Assertions.assertEquals(2, allocations.size());
   }

   @Execution(ExecutionMode.SAME_THREAD)
   @Test
   public void testBlacklist()
   {
      List allocations;
      AllocationProfiler allocationProfiler = new AllocationProfiler();
      allocationProfiler.setRecordConstructorAllocations(false);

      LilAllocator lilAllocator;

      // add one class to whitelist
      allocationProfiler.excludeAllocationsInsideClass(LilAllocator.class.getName());
      allocationProfiler.startRecordingAllocations();

      lilAllocator = new LilAllocator(); // allocates 1, stuff inside does not count

      if (lilAllocator != null)
      {
         ThreadTools.sleep(10); // otherwise apparently MutableInt will get allocated early and fail the test
         new MutableInt(); // random new thing, but not in whitelist
      }

      lilAllocator.doStuff(); // allocates 2 things inside
      allocationProfiler.stopRecordingAllocations();

      allocations = allocationProfiler.pollAllocations();
      printAllocations(allocations);

      assertAllocationsContain(allocations, LilAllocator.class);
      assertAllocationsContain(allocations, MutableInt.class);
//      Assertions.assertTrue(allocations.get(0).getAllocatedObject().getClass().equals(LilAllocator.class));
//      Assertions.assertTrue(allocations.get(0).getDescription().equals("us/ihmc/commons/allocations/AllocationTestTest$LilAllocator"));
//      Assertions.assertTrue(allocations.get(0).getSize() == 24);
//      Assertions.assertTrue(allocations.get(1).getAllocatedObject().getClass().equals(MutableInt.class));
      Assertions.assertEquals(2, allocations.size());
   }

   private void assertAllocationsContain(List allocations, Class clazz)
   {
      boolean found = false;
      for (AllocationRecord record : allocations)
      {
         if (record.getAllocatedObject().getClass().equals(clazz))
            found = true;
      }

      Assertions.assertTrue(found);
   }

   @Execution(ExecutionMode.SAME_THREAD)
   @Test
   public void testMethodIncludeExclude()
   {
      List allocations;
      AllocationProfiler allocationProfiler = new AllocationProfiler();

      LilAllocator lilAllocator;
      MutableInt mutableInt;

      // add one class to whitelist
      String qualifiedMethodName = "us.ihmc.commons.allocations.AllocationTestTest$BrokenClass.imNotSupposedToAllocate";
      allocationProfiler.includeAllocationsInsideMethod(qualifiedMethodName);
      allocationProfiler.startRecordingAllocations();
      lilAllocator = new LilAllocator(); // allocates 1, stuff inside does not count
      mutableInt = new MutableInt(); // random new thing, but not in whitelist
      lilAllocator.doStuff(); // allocates 2 things inside
      allocationProfiler.stopRecordingAllocations();

      allocations = allocationProfiler.pollAllocations();
      LogTools.info("testMethodIncludeExclude1");
      printAllocations(allocations);
      Assertions.assertTrue(allocations.get(0).toString().contains(qualifiedMethodName));
      Assertions.assertEquals(1, allocations.size());

      // add one class to whitelist
      allocationProfiler.setIncludeAllAllocations(true);
      allocationProfiler.excludeAllocationsInsideMethod(qualifiedMethodName);
      allocationProfiler.startRecordingAllocations();
      lilAllocator = new LilAllocator(); // allocates 1, stuff inside does not count
      mutableInt = new MutableInt(); // random new thing, but not in whitelist
      lilAllocator.doStuff(); // allocates 2 things inside, but one excluded
      allocationProfiler.stopRecordingAllocations();

      allocations = allocationProfiler.pollAllocations();
      LogTools.info("testMethodIncludeExclude2");
      printAllocations(allocations);
      Assertions.assertEquals(3, allocations.size());
   }

   @Execution(ExecutionMode.SAME_THREAD)
   @Test
   public void testReset()
   {
      List allocations;
      AllocationProfiler allocationProfiler = new AllocationProfiler();
      LilAllocator lilAllocator;
      MutableInt mutableInt;

      String qualifiedMethodName = "us.ihmc.commons.allocations.AllocationTestTest$BrokenClass.imNotSupposedToAllocate";
      allocationProfiler.includeAllocationsInsideMethod(qualifiedMethodName);
      allocationProfiler.startRecordingAllocations();
      lilAllocator = new LilAllocator(); // allocates 1, stuff inside does not count
      mutableInt = new MutableInt(); // random new thing, but not in whitelist
      lilAllocator.doStuff(); // allocates 2 things inside
      allocationProfiler.stopRecordingAllocations();
      allocations = allocationProfiler.pollAllocations();
      printAllocations(allocations);
      Assertions.assertTrue(allocations.get(0).toString().contains(qualifiedMethodName));
      Assertions.assertEquals(1, allocations.size());

      allocationProfiler.reset();
      allocationProfiler.startRecordingAllocations();
      lilAllocator = new LilAllocator(); // allocates 1, stuff inside does not count
      mutableInt = new MutableInt(); // random new thing, but not in whitelist
      lilAllocator.doStuff(); // allocates 2 things inside, but one excluded
      allocationProfiler.stopRecordingAllocations();
      allocations = allocationProfiler.pollAllocations();
      printAllocations(allocations);
      Assertions.assertEquals(4, allocations.size());
   }

   private void printAllocations(List allocations)
   {
      for (AllocationRecord allocation : allocations)
      {
         LogTools.info(allocation.toString());
      }
   }

   // this switch doesn't allocate when run with Gradle. It therefore no longer reliably tests the application logic so disable it. - @dcalvert
   @Disabled
   @Execution(ExecutionMode.SAME_THREAD)
   @Test
   public void testSwitchTable()
   {
      // First time the switch statement is called for an enum a switch table is generated:
      List allocations = new AllocationProfiler().recordAllocations(() -> {
         switch (MyEnum.A)
         {
         default:
            break;
         }
      });
      printAllocations(allocations);
      Assertions.assertEquals(2, allocations.size(), "allocated");

      // The second time there are no allocations:
      allocations = new AllocationProfiler().recordAllocations(() -> {
         switch (MyEnum.B)
         {
         default:
            break;
         }
      });
      printAllocations(allocations);
      Assertions.assertEquals(0, allocations.size(), "allocated");
   }

   private class LilAllocator
   {
      private BrokenClass brokenClass; // "class of interest"
      private KnownAllocator knownAllocator = new KnownAllocator(); // outside constructor

      public LilAllocator()
      {
         brokenClass = new BrokenClass(); // inside constructor, these both count
      }

      public void doStuff()
      {
         brokenClass.imNotSupposedToAllocate();
         knownAllocator.whoCaresIfIAllocate();
      }
   }

   private class BrokenClass
   {
      public MutableInt mutableInt;

      public void imNotSupposedToAllocate()
      {
         mutableInt = new MutableInt();
      }
   }

   private class KnownAllocator
   {
      public MutableInt mutableInt;

      public void whoCaresIfIAllocate()
      {
         mutableInt = new MutableInt();
      }
   }

   public static void main(String[] args)
   {
      MutationTestFacilitator.facilitateMutationTestForClass(AllocationProfiler.class, AllocationTestTest.class);
   }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy