@Test
public void fieldSelectionAndNavigationTest() {

  final long TEST_CLASS_ID = 1, TEST_FIELD_ID = 2;
  final String TEST_CLASS_NAME = "com.Foo";
  final String TEST_FIELD_NAME = "com.Field";
  MemoryAspectObserver aspectObserver = new MemoryAspectObserver(myStage.getAspect());
  CodeLocation codeLocationFoo = new CodeLocation.Builder("Foo").setMethodName("fooMethod1").setLineNumber(5).build();
  CodeLocation codeLocationBar = new CodeLocation.Builder("Bar").setMethodName("barMethod1").setLineNumber(20).build();
  //noinspection ConstantConditions
  AllocationStack callstackFoo = AllocationStack.newBuilder()
    .setFullStack(
      AllocationStack.StackFrameWrapper.newBuilder()
        .addFrames(
          AllocationStack.StackFrame.newBuilder()
            .setClassName(codeLocationFoo.getClassName())
            .setMethodName(codeLocationFoo.getMethodName())
            .setLineNumber(codeLocationFoo.getLineNumber() + 1)))
    .build();
  //noinspection ConstantConditions
  AllocationStack callstackBar = AllocationStack.newBuilder()
    .setFullStack(
      AllocationStack.StackFrameWrapper.newBuilder()
        .addFrames(
          AllocationStack.StackFrame.newBuilder()
            .setClassName(codeLocationBar.getClassName())
            .setMethodName(codeLocationBar.getMethodName())
            .setLineNumber(codeLocationBar.getLineNumber() + 1)))
    .build();
  FakeCaptureObject captureObject = new FakeCaptureObject.Builder().build();
  FakeInstanceObject instanceFooField =
    new FakeInstanceObject.Builder(captureObject, TEST_FIELD_ID, TEST_FIELD_NAME).setName("instanceFooField").build();
  FakeInstanceObject instanceBarField =
    new FakeInstanceObject.Builder(captureObject, TEST_FIELD_ID, TEST_FIELD_NAME).setName("instanceBarField").build();
  FakeFieldObject fieldFoo = new FakeFieldObject("fieldFoo", OBJECT, instanceFooField);
  FakeFieldObject fieldBar = new FakeFieldObject("fieldBar", OBJECT, instanceBarField);
  FakeInstanceObject instanceFoo =
    new FakeInstanceObject.Builder(captureObject, TEST_CLASS_ID, TEST_CLASS_NAME).setName("instanceFoo").setAllocationStack(callstackFoo)
      .setFields(Collections.singletonList(fieldFoo.getFieldName())).build();
  instanceFoo.setFieldValue(fieldFoo.getFieldName(), fieldFoo.getValueType(), instanceFooField);
  FakeInstanceObject instanceBar =
    new FakeInstanceObject.Builder(captureObject, TEST_CLASS_ID, TEST_CLASS_NAME).setName("instanceBar").setAllocationStack(callstackBar)
      .setFields(Collections.singletonList(fieldBar.getFieldName())).build();
  instanceBar.setFieldValue(fieldBar.getFieldName(), fieldBar.getValueType(), instanceBarField);
  Set<InstanceObject> instanceObjects = new HashSet<>(Arrays.asList(instanceFoo, instanceBar, instanceFooField, instanceBarField));
  captureObject.addInstanceObjects(instanceObjects);
  myStage
    .selectCaptureDuration(new CaptureDurationData<>(1, false, false, new CaptureEntry<CaptureObject>(new Object(), () -> captureObject)),
                           null);
  assertThat(myStage.getConfiguration().getClassGrouping()).isEqualTo(ARRANGE_BY_CLASS);
  assertThat(myStage.getSelectedHeapSet()).isNotNull();
  assertThat(myStage.getSelectedHeapSet().getId()).isEqualTo(FakeCaptureObject.DEFAULT_HEAP_ID);
  myStage.selectClassSet(findChildClassSetWithName(myStage.getSelectedHeapSet(), TEST_CLASS_NAME));
  myStage.selectInstanceObject(instanceFoo);
  myStage.selectFieldObjectPath(Collections.singletonList(fieldFoo));
  aspectObserver.assertAndResetCounts(0, 1, 1, 0, 2, 2, 1, 1);
  myStage.getConfiguration().setClassGrouping(ARRANGE_BY_CALLSTACK);
  aspectObserver.assertAndResetCounts(0, 0, 0, 1, 0, 1, 2, 2);
  assertThat(myStage.getSelectedInstanceObject()).isEqualTo(instanceFoo);
  assertThat(myStage.getSelectedFieldObjectPath()).isEqualTo(Collections.singletonList(fieldFoo));
  myClassSetTree = myClassSetView.getTree();
  assertThat(myClassSetTree).isNotNull();
  Object classSetRoot = myClassSetTree.getModel().getRoot();
  assertThat(classSetRoot).isInstanceOf(MemoryObjectTreeNode.class);
  assertThat(((MemoryObjectTreeNode)classSetRoot).getAdapter()).isInstanceOf(ClassSet.class);
  //noinspection unchecked
  myClassSetRootNode = (MemoryObjectTreeNode<MemoryObject>)classSetRoot;
  findChildWithPredicate(findChildWithPredicate(myClassSetRootNode, instance -> instance == instanceFoo),
                         field -> Objects.equals(field, fieldFoo));
  myStage.getConfiguration().setClassGrouping(ARRANGE_BY_PACKAGE);
  aspectObserver.assertAndResetCounts(0, 0, 0, 1, 0, 1, 2, 2);
  assertThat(myStage.getSelectedInstanceObject()).isEqualTo(instanceFoo);
  assertThat(myStage.getSelectedFieldObjectPath()).isEqualTo(Collections.singletonList(fieldFoo));
  Supplier<CodeLocation> codeLocationSupplier = myFakeIdeProfilerComponents.getCodeLocationSupplier(myClassSetTree);
  assertThat(codeLocationSupplier).isNotNull();
  CodeLocation codeLocation = codeLocationSupplier.get();
  assertThat(codeLocation).isNotNull();
  String codeLocationClassName = codeLocation.getClassName();
  assertThat(codeLocationClassName).isEqualTo(TEST_FIELD_NAME);
  myStage.getStudioProfilers().getIdeServices().getCodeNavigator().addListener(myStage); // manually add, since we didn't enter stage
  myStage.getStudioProfilers().getIdeServices().getCodeNavigator().navigate(codeLocation);
  myStage.getStudioProfilers().getIdeServices().getCodeNavigator().removeListener(myStage);
  assertThat(myStage.getProfilerMode()).isEqualTo(ProfilerMode.NORMAL);
}