@Test
 public void testBlockEntityPrefabCorrectlyRemovedOnChangeToBlockWithNoPrefab() {
   worldProvider.setBlock(Vector3i.zero(), blockWithString);
   EntityRef entity = worldProvider.getBlockEntityAt(Vector3i.zero());
   worldProvider.setBlock(Vector3i.zero(), plainBlock);
   assertEquals(null, entity.getParentPrefab());
 }
 @Test
 public void testBlockEntityPrefabCorrectlyAddedOnChangeToBlockWithPrefab() {
   worldProvider.setBlock(Vector3i.zero(), plainBlock);
   EntityRef entity = worldProvider.getBlockEntityAt(Vector3i.zero());
   worldProvider.setBlock(Vector3i.zero(), blockWithString);
   assertEquals(blockWithString.getPrefab(), entity.getParentPrefab().getURI().toSimpleString());
 }
 @Test
 public void componentUntouchedIfRetainRequested() {
   worldProvider.setBlock(Vector3i.zero(), blockInFamilyOne);
   EntityRef entity = worldProvider.getBlockEntityAt(Vector3i.zero());
   entity.addComponent(new IntegerComponent());
   worldProvider.setBlockRetainComponent(Vector3i.zero(), blockWithString, IntegerComponent.class);
   assertNotNull(entity.getComponent(IntegerComponent.class));
 }
 @Test
 public void testEntityBecomesTemporaryWhenChangedFromAKeepActiveBlock() {
   worldProvider.setBlock(Vector3i.zero(), keepActiveBlock);
   EntityRef blockEntity = worldProvider.getBlockEntityAt(new Vector3i(0, 0, 0));
   worldProvider.setBlock(Vector3i.zero(), BlockManager.getAir());
   worldProvider.update(1.0f);
   assertFalse(blockEntity.isActive());
 }
 @Test
 public void testEntityNotRemovedIfForceBlockActiveComponentAdded() {
   EntityRef blockEntity = worldProvider.getBlockEntityAt(new Vector3i(0, 0, 0));
   blockEntity.addComponent(new ForceBlockActiveComponent());
   worldProvider.update(1.0f);
   assertTrue(blockEntity.exists());
   assertTrue(blockEntity.isActive());
 }
 @Test
 public void componentsAlteredIfBlockInSameFamilyWhenForced() {
   worldProvider.setBlock(Vector3i.zero(), blockInFamilyOne);
   EntityRef entity = worldProvider.getBlockEntityAt(Vector3i.zero());
   entity.addComponent(new IntegerComponent());
   worldProvider.setBlockForceUpdateEntity(Vector3i.zero(), blockInFamilyTwo);
   assertNull(entity.getComponent(IntegerComponent.class));
 }
  @Test
  public void retainedComponentsNotAltered() {
    EntityRef entity = worldProvider.getBlockEntityAt(new Vector3i(0, 0, 0));
    entity.addComponent(new RetainedOnBlockChangeComponent(2));

    worldProvider.setBlock(Vector3i.zero(), blockWithRetainedComponent);

    assertEquals(2, entity.getComponent(RetainedOnBlockChangeComponent.class).value);
  }
 @Test
 public void testEntityCeasesToBeTemporaryIfBlockChangedToKeepActive() {
   worldProvider.setBlock(Vector3i.zero(), keepActiveBlock);
   worldProvider.update(1.0f);
   LifecycleEventChecker checker =
       new LifecycleEventChecker(entityManager.getEventSystem(), StringComponent.class);
   worldProvider.getBlockEntityAt(new Vector3i(0, 0, 0));
   assertTrue(checker.receivedEvents.isEmpty());
 }
 @Test
 public void testEntityBecomesTemporaryIfForceBlockActiveComponentRemoved() {
   EntityRef blockEntity = worldProvider.getBlockEntityAt(new Vector3i(0, 0, 0));
   blockEntity.addComponent(new ForceBlockActiveComponent());
   worldProvider.update(1.0f);
   blockEntity.removeComponent(ForceBlockActiveComponent.class);
   worldProvider.update(1.0f);
   assertFalse(blockEntity.exists());
   assertFalse(blockEntity.isActive());
 }
 @Test
 public void testPrefabUpdatedWhenBlockChanged() {
   worldProvider.setBlock(Vector3i.zero(), blockWithString);
   assertEquals(
       blockWithString.getPrefab(),
       worldProvider.getBlockEntityAt(new Vector3i(0, 0, 0)).getParentPrefab().getName());
   worldProvider.setBlock(Vector3i.zero(), blockWithDifferentString);
   assertEquals(
       blockWithDifferentString.getPrefab(),
       worldProvider.getBlockEntityAt(new Vector3i(0, 0, 0)).getParentPrefab().getName());
 }
  @Test
  public void allComponentsNotMarkedAsRetainedRemovedOnBlockChange() {
    worldStub.setBlock(Vector3i.zero(), blockWithString);
    EntityRef entity = worldProvider.getBlockEntityAt(new Vector3i(0, 0, 0));
    entity.addComponent(new ForceBlockActiveComponent());
    entity.addComponent(new RetainedOnBlockChangeComponent(2));

    worldProvider.setBlock(Vector3i.zero(), BlockManager.getAir());

    assertTrue(entity.hasComponent(RetainedOnBlockChangeComponent.class));
    assertFalse(entity.hasComponent(ForceBlockActiveComponent.class));
  }
 @Test
 public void testTemporaryCleanedUpWithNoEvent() {
   BlockEventChecker checker = new BlockEventChecker();
   entityManager.getEventSystem().registerEventHandler(checker);
   EntityRef blockEntity = worldProvider.getBlockEntityAt(new Vector3i(0, 0, 0));
   worldProvider.update(1.0f);
   assertFalse(blockEntity.exists());
   assertFalse(checker.addedReceived);
   assertFalse(checker.activateReceived);
   assertFalse(checker.deactivateReceived);
   assertFalse(checker.removedReceived);
 }
  @Test
  public void testEntityExtraComponentsRemovedBeforeCleanUp() {
    EntityRef entity = worldProvider.getBlockEntityAt(new Vector3i(0, 0, 0));
    entity.addComponent(new StringComponent("test"));

    LifecycleEventChecker checker =
        new LifecycleEventChecker(entityManager.getEventSystem(), StringComponent.class);

    worldProvider.update(1.0f);
    assertEquals(
        Lists.newArrayList(
            new EventInfo(BeforeDeactivateComponent.newInstance(), entity),
            new EventInfo(BeforeRemoveComponent.newInstance(), entity)),
        checker.receivedEvents);
  }
  @Test
  public void testComponentsUpdatedWhenBlockChanged() {
    worldProvider.setBlock(Vector3i.zero(), blockWithString);

    LifecycleEventChecker checker =
        new LifecycleEventChecker(entityManager.getEventSystem(), StringComponent.class);

    worldProvider.setBlock(Vector3i.zero(), blockWithDifferentString);
    EntityRef blockEntity = worldProvider.getBlockEntityAt(new Vector3i(0, 0, 0));
    assertTrue(blockEntity.exists());

    assertEquals(
        Lists.newArrayList(new EventInfo(OnChangedComponent.newInstance(), blockEntity)),
        checker.receivedEvents);
  }
  @Test
  public void testChangedComponentsRevertedBeforeCleanUp() {
    worldStub.setBlock(Vector3i.zero(), blockWithString);
    EntityRef entity = worldProvider.getBlockEntityAt(new Vector3i(0, 0, 0));
    StringComponent comp = entity.getComponent(StringComponent.class);
    comp.value = "Moo";
    entity.saveComponent(comp);

    LifecycleEventChecker checker =
        new LifecycleEventChecker(entityManager.getEventSystem(), StringComponent.class);

    worldProvider.update(1.0f);
    assertEquals(
        Lists.newArrayList(new EventInfo(OnChangedComponent.newInstance(), entity)),
        checker.receivedEvents);
  }
  @Test
  public void testEntityMissingComponentsAddedBeforeCleanUp() {
    worldStub.setBlock(Vector3i.zero(), blockWithString);
    EntityRef entity = worldProvider.getBlockEntityAt(new Vector3i(0, 0, 0));
    entity.removeComponent(StringComponent.class);

    LifecycleEventChecker checker =
        new LifecycleEventChecker(entityManager.getEventSystem(), StringComponent.class);

    worldProvider.update(1.0f);
    assertEquals(
        Lists.newArrayList(
            new EventInfo(OnAddedComponent.newInstance(), entity),
            new EventInfo(OnActivatedComponent.newInstance(), entity)),
        checker.receivedEvents);
  }
  @Test
  public void testEntityExtraComponentsRemovedBeforeCleanUpForBlocksWithPrefabs() {
    worldStub.setBlock(Vector3i.zero(), blockWithString);
    EntityRef entity = worldProvider.getBlockEntityAt(new Vector3i(0, 0, 0));
    entity.addComponent(new IntegerComponent(1));

    LifecycleEventChecker checker =
        new LifecycleEventChecker(entityManager.getEventSystem(), IntegerComponent.class);

    worldProvider.update(1.0f);
    assertEquals(
        Lists.newArrayList(
            new EventInfo(BeforeDeactivateComponent.newInstance(), entity),
            new EventInfo(BeforeRemoveComponent.newInstance(), entity)),
        checker.receivedEvents);
  }
  @Test
  public void networkComponentRemovedWhenTemporaryCleanedUp() {
    EntityRef entity = worldProvider.getBlockEntityAt(new Vector3i(0, 0, 0));
    entity.addComponent(new RetainedOnBlockChangeComponent(2));

    LifecycleEventChecker checker =
        new LifecycleEventChecker(entityManager.getEventSystem(), NetworkComponent.class);
    entity.removeComponent(RetainedOnBlockChangeComponent.class);

    worldProvider.update(1.0f);

    assertEquals(
        Lists.newArrayList(
            new EventInfo(BeforeDeactivateComponent.newInstance(), entity),
            new EventInfo(BeforeRemoveComponent.newInstance(), entity)),
        checker.receivedEvents);
  }
  @Test
  public void testActiveBlockNotCleanedUp() {
    Block testBlock = new Block();
    testBlock.setKeepActive(true);
    BlockFamily blockFamily = new SymmetricFamily(new BlockUri("test:keepActive"), testBlock);
    blockManager.addBlockFamily(blockFamily, true);
    worldStub.setBlock(Vector3i.zero(), testBlock);

    BlockEventChecker checker = new BlockEventChecker();
    entityManager.getEventSystem().registerEventHandler(checker);

    EntityRef blockEntity = worldProvider.getBlockEntityAt(new Vector3i(0, 0, 0));
    worldProvider.update(1.0f);
    assertTrue(blockEntity.exists());
    assertTrue(blockEntity.isActive());
    assertTrue(checker.addedReceived);
    assertTrue(checker.activateReceived);
  }
  @Test
  public void networkComponentAddedWhenChangedToNonTemporary() {
    LifecycleEventChecker checker =
        new LifecycleEventChecker(entityManager.getEventSystem(), NetworkComponent.class);
    EntityRef entity = worldProvider.getBlockEntityAt(new Vector3i(0, 0, 0));
    entity.addComponent(new RetainedOnBlockChangeComponent(2));

    assertEquals(
        Lists.newArrayList(
            new EventInfo(OnAddedComponent.newInstance(), entity),
            new EventInfo(OnActivatedComponent.newInstance(), entity)),
        checker.receivedEvents);
    assertTrue(entity.hasComponent(NetworkComponent.class));
  }
  @Before
  public void setup() {
    GameThread.setGameThread();
    AssetManager assetManager =
        CoreRegistry.put(
            AssetManager.class,
            new AssetManager(new ModuleManagerImpl(new ModuleSecurityManager())));
    assetManager.setAssetFactory(
        AssetType.PREFAB,
        new AssetFactory<PrefabData, Prefab>() {

          @Override
          public Prefab buildAsset(AssetUri uri, PrefabData data) {
            return new PojoPrefab(uri, data);
          }
        });
    EntitySystemBuilder builder = new EntitySystemBuilder();

    CoreRegistry.put(ComponentSystemManager.class, mock(ComponentSystemManager.class));

    blockManager =
        CoreRegistry.put(
            BlockManager.class,
            new BlockManagerImpl(mock(WorldAtlas.class), new DefaultBlockFamilyFactoryRegistry()));
    NetworkSystem networkSystem = mock(NetworkSystem.class);
    when(networkSystem.getMode()).thenReturn(NetworkMode.NONE);
    entityManager = builder.build(moduleManager, networkSystem, new ReflectionReflectFactory());
    worldStub = new WorldProviderCoreStub(BlockManager.getAir());
    worldProvider = new EntityAwareWorldProvider(worldStub, entityManager);

    plainBlock = new Block();
    blockManager.addBlockFamily(
        new SymmetricFamily(new BlockUri("test:plainBlock"), plainBlock), true);

    blockWithString = new Block();
    PrefabData prefabData = new PrefabData();
    prefabData.addComponent(new StringComponent("Test"));
    Assets.generateAsset(
        new AssetUri(AssetType.PREFAB, "test:prefabWithString"), prefabData, Prefab.class);
    blockWithString.setPrefab("test:prefabWithString");
    blockManager.addBlockFamily(
        new SymmetricFamily(new BlockUri("test:blockWithString"), blockWithString), true);

    blockWithDifferentString = new Block();
    prefabData = new PrefabData();
    prefabData.addComponent(new StringComponent("Test2"));
    Assets.generateAsset(
        new AssetUri(AssetType.PREFAB, "test:prefabWithDifferentString"), prefabData, Prefab.class);
    blockWithDifferentString.setPrefab("test:prefabWithDifferentString");
    blockManager.addBlockFamily(
        new SymmetricFamily(
            new BlockUri("test:blockWithDifferentString"), blockWithDifferentString),
        true);

    blockWithRetainedComponent = new Block();
    prefabData = new PrefabData();
    prefabData.addComponent(new RetainedOnBlockChangeComponent(3));
    Assets.generateAsset(
        new AssetUri(AssetType.PREFAB, "test:prefabWithRetainedComponent"),
        prefabData,
        Prefab.class);
    blockWithRetainedComponent.setPrefab("test:prefabWithRetainedComponent");
    blockManager.addBlockFamily(
        new SymmetricFamily(
            new BlockUri("test:blockWithRetainedComponent"), blockWithRetainedComponent),
        true);

    blockInFamilyOne = new Block();
    blockInFamilyOne.setKeepActive(true);
    blockInFamilyOne.setPrefab("test:prefabWithString");
    blockInFamilyTwo = new Block();
    blockInFamilyTwo.setPrefab("test:prefabWithString");
    blockInFamilyTwo.setKeepActive(true);
    blockManager.addBlockFamily(
        new HorizontalBlockFamily(
            new BlockUri("test:blockFamily"),
            ImmutableMap.<Side, Block>of(
                Side.FRONT,
                blockInFamilyOne,
                Side.LEFT,
                blockInFamilyTwo,
                Side.RIGHT,
                blockInFamilyTwo,
                Side.BACK,
                blockInFamilyOne),
            Collections.<String>emptyList()),
        true);

    keepActiveBlock = new Block();
    keepActiveBlock.setKeepActive(true);
    keepActiveBlock.setPrefab("test:prefabWithString");
    blockManager.addBlockFamily(
        new SymmetricFamily(new BlockUri("test:keepActiveBlock"), keepActiveBlock), true);

    worldProvider.initialise();
  }