private boolean runtest(CramMD5Client client, CramMD5Server server, CharSequence usrnam, ByteChars secret, ByteChars nonce,
			String expected_challenge, String expected_response)
	{
		client.init();
		server.init();
		if (nonce != null) {
			ByteChars srvnonce = (ByteChars)DynLoader.getField(server, "srvnonce");
			srvnonce.set(nonce);
		}
		saslauth.username_good = new ByteChars(usrnam);
		if (usrnam.toString().equals("baduser")) {
			saslauth.passwd = new ByteChars("wrongpassword");
		} else if (usrnam.toString().equals("badpass")) {
			saslauth.passwd = null;
		} else {
			saslauth.passwd = new ByteChars(secret);
		}
		ByteChars sbuf = new ByteChars();
		ByteChars msg = server.setChallenge(sbuf);
		org.junit.Assert.assertTrue(msg == sbuf);
		if (expected_challenge != null) org.junit.Assert.assertEquals(expected_challenge, msg.toString());
		ByteChars cbuf = (usrnam.equals("tim") ? new ByteChars() : null);
		msg = client.setResponse(usrnam, secret, msg, cbuf);
		if (cbuf != null) org.junit.Assert.assertTrue(msg == cbuf);
		if (msg.ar_off == 0) {
			// shuffle buffer up to test offset handling
			byte[] buf = new byte[msg.ar_len + 15];
			System.arraycopy(msg.ar_buf, msg.ar_off, buf, 10, msg.ar_len);
			msg.pointAt(buf, 10, msg.ar_len);
		}
		if (expected_response != null) org.junit.Assert.assertEquals(expected_response, msg.toString());
		return server.verifyResponse(msg);
	}