//---------------
// The @RunWith(PowerMockRunner.class) annotation tells jUnit 
// that we are using an extension to handle testing of this class. 
// This tells jUnit to use this test runner instead of its own test runner. 
@RunWith(PowerMockRunner.class)

// The @PrepareForTest({IdentityUtilities.class, Person.class}) serves multiple purposes here. 
// The first is to tell PowerMock that we need to do some preparation 
// of the classes to instrument them for our testing. Classes defined using this annotation 
// are typically those that needs to be byte-code manipulated. This includes final classes,
// classes with final, private, static or native methods that should be mocked and also classes 
// that should be return a mock object upon instantiation. IdentityUtilities.class is our class 
// with a static method, and Person.class contains our private method. 
@PrepareForTest({
	RequiredInfo.class,
	Work.class,
	ContextWorkType.class,
	InstallationContext.class,
	RequiredInfo.class,
})

//---------------
	
ArgumentCaptor<String> captor = ArgumentCaptor.forClass(String.class);
doNothing().when(errors).setError(captor.capture());

String errorMessage = captor.getValue();
Assert.assertEquals("Name should be not null.", errorMessage);


ArgumentCaptor<Person> peopleCaptor = ArgumentCaptor.forClass(Person.class);
verify(mock, times(2)).doSomething(peopleCaptor.capture());

List<Person> capturedPeople = peopleCaptor.getAllValues();
assertEquals("John", capturedPeople.get(0).getName());
assertEquals("Jane", capturedPeople.get(1).getName());
	
//---------------

histogramEditor = spy(new HistogramEditor(projectEditor));
doNothing().when(histogramEditor).updateExternalData(any(), any(), any());

//---------------

mockStatic(InstallationContext.class);
when(InstallationContext.class, "get", anyString()).thenReturn(context);

//---------------

Whitebox.setInternalState(context, "cache", psCache);

//---------------

CopyUtil.copyRoleAssignments(work, null, null);
Mockito.verify(work, Mockito.never()).getRelationships();	

//---------------

verifyStatic(times(3)); // source + 2 children
CopyUtil.copyReferences(any(), any(), any());

//---------------

genericEntityBean = Whitebox.newInstance(GenericEntityBean.class);

//---------------

user = mock(User.class);
userBean = mock(UserBean.class, CALLS_REAL_METHODS);
doReturn(user).when(userBean).getUser();

//---------------

context = spy(new InstallationContext());
doNothing().when(context).save();
when(context.getName()).thenReturn("default");

//---------------

DualHashBidiMap dualHashBidiMap = new DualHashBidiMap(new HashMap<PersistentKey, PSObject>());
whenNew(DualHashBidiMap.class).withNoArguments().thenReturn(dualHashBidiMap);

//---------------

//given
Template template = new Template(file);
setInternalState(template, "_lastModified", 0l);
byte[] bytes;

//when
bytes = template.getBytes();

//then
assertEquals(1000l, getInternalState(template, "_lastChecked"));
assertEquals(2000, bytes.length);

//---------------

ContextTypes contextTypes = Whitebox.invokeConstructor(ContextTypes.class, new Class<?>[]{InstallationContext.class}, new Object[]{installationContext});

//---------------

Whitebox.invokeMethod(contextTypes, "registerType", Work.TYPE);
Whitebox.invokeMethod(contextTypes, "registerType", Template.TYPE);

//---------------

// Answer with the correct context type for PSType calls
when(installationContext.getContextPSType(any(PSType.class))).thenAnswer((InvocationOnMock i) -> contextTypes.getContextPSType((PSType)i.getArguments()[0]));


//---------------

// init context types
// unfortunately we should extend visibility of the object member to have access
ContextTypes types = null;
Constructor[] cons = ContextTypes.class.getDeclaredConstructors();
cons[0].setAccessible(true);
try {
	types = (ContextTypes) cons[0].newInstance(context);
	doReturn(types).when(context).getContextTypes();
} catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException | SecurityException e) {
	fail(e.getMessage());
}


//---------------

final List<ContextWorkStatus> states = new ArrayList<>();
for (WorkStatus status : WorkStatus.values()) {
	states.add(new ContextWorkStatus(context.getName(), status));
}
doAnswer(new Answer<List<ContextWorkStatus>>() {
	@Override
	public List<ContextWorkStatus> answer(InvocationOnMock invocation) throws Throwable {
		return states;
	}
}).when(context).listWorkStates(isA(WorkType.class));
final ContextWorkStates states2 = new ContextWorkStates(context.getName()); 
doAnswer(new Answer<ContextWorkStatus>() {
	@Override
	public ContextWorkStatus answer(InvocationOnMock invocation) throws Throwable {
		WorkStatus status = (WorkStatus) invocation.getArguments()[ 0 ];
		return states2.getStatus(status);
	}
	
}).when(context).getWorkStatus(any(WorkStatus.class));


//---------------

    @Rule
    public ExpectedException thrown = ExpectedException.none();
	
    @Test
    public void getValueFor_invalidField() throws Exception {
        thrown.expect(IllegalStateException.class);
        WorkflowFieldValues.getValueFor(work, "WA:xxx");
    }
	
//---------------

	suppress(method(MetricCopy.class, "init"));
	suppress(method(MetricCopy.class, "doCopy"));

//---------------

	suppress(methodsDeclaredIn(Parent.class));

//---------------

	when(instance.methodCall()).thenCallRealMethod();

//---------------


@RunWith(PowerMockRunner.class)
@PrepareForTest({User.class, Misc.class})
public abstract class QuestionHandlerTestBase {

    @Before
    public void setUpBase() throws Exception {
        mockStatic(Misc.class);
        when(Misc.class, "getInsufficientPermissionMessage", any(User.class)).thenReturn(INSUFFICIENT_PERMISSION_MESSAGE);
    }

	
	
public class BaseDelegationHandlerTest extends QuestionHandlerTestBase {
	// name should not match the setup method of the base class, because base beforw won't be called
    @Before
    public void setUp() throws Exception {
		
		
		
//----------------
BDDMockito.given(SigupAgentSql.getInstance(any())).willReturn(agentSql)

//----------------

doCallRealMethod().when(mail, "setText", any(), any(), any());
doNothing().when(mail).enqueue();

//----------------

doReturn(worksToReturn).when(Work.class, "findSameNameWorks", eq(context), anyString());

//----------------

        wbsMasterSection.renderExtResponse(PASTE_AFTER_COMMAND, new JSONObject());
        try {
            verifyPrivate(wbsMasterSection, times(1)).invoke("pasteAfter", any(JSONObject.class));
        } catch (Exception e) {
            throw new MockitoException("Cannot verify calls of pasteAfter", e);
        }