/*
*
*
* Copyright 1990-2007 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version
* 2 only, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License version 2 for more details (a copy is
* included at /legal/license.txt).
*
* You should have received a copy of the GNU General Public License
* version 2 along with this work; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
* Clara, CA 95054 or visit www.sun.com if you need additional
* information or have any questions.
*/
package javax.microedition.sip;
import com.sun.midp.i3test.TestCase;
import com.sun.midp.io.j2me.storage.RandomAccessStream;
import com.sun.midp.io.j2me.storage.File;
import javax.microedition.io.Connector;
import java.io.IOException;
import java.io.OutputStream;
/**
* Tests for the SipHeader class.
*
* We assume that for a header like
* <pre>
* Accept-Language: da, en-gb;q=0.8, en;q=0.7
* </pre>
* 3 name-headerValue pairs will be generated by the implementation.
*/
class THeader {
/*
* structured internal representation
* Contact: "Mr. Watson" <sip:watson@worcester.bell-telephone.com>;
* q=0.7;expires=3600
* {{"Contact"},
* {": "},
* {"\"Mr. Watson\" <sip:watson@worcester.bell-telephone.com>"},
* {";"},
* {"q","=","0.7"},
* {";"},
* {"expires=3600",{"\r\n"}
* };
* name
* delim
* value
* delim
* param
* delim param
*
* hline = name delim value *( delim param )
* param = pname pdelim pvalue
*/
String[][]guts;
THeader(String[][] guts0) {
guts = acopy(guts0);
}
THeader(THeader p) {
guts = acopy(p.guts);
}
// auxiliary tools, generic stuff
public static String concata(String[] a) {
String res = "";
for (int i = 0; i < a.length; i++) {
res = res + a[i];
}
return res;
}
public static String concata(String[][]a, int i0, int im) {
String res = "";
if (a.length < im) {
im = a.length;
}
for (int i = i0; i < im; i++) {
res = res + concata(a[i]);
}
return res;
}
public static String[] acopy(String[] g) {
String[] res = new String[g.length];
for (int i = 0; i < g.length; i++) {
res[i] = new String(g[i]);
}
return res;
}
public static String[][] acopy(String[][] g) {
String[][] res = new String[g.length][];
for (int i = 0; i < g.length; i++) {
res[i] = acopy(g[i]);
}
return res;
}
public static String[][] acopyWithoutDelimAndPrm(String[][] g, int no) {
String[][] res = new String[g.length-2][];
if (0 <= no && no < g.length) {
for (int i = 0, j = 0; i < g.length; i++) {
if (i != no && i != no - 1) {
res[j++] = acopy(g[i]);
}
}
return res;
} else {
return acopy(g);
}
}
public static String[][] acopyWithDelimAndPrm(String[][] g,
String[]delim,
String[]prm) {
String[][] res = new String[g.length+2][];
int i, j;
for (i = 0, j = 0; i < g.length-1; i++) {
res[j++] = acopy(g[i]);
}
res[j++] = acopy(delim);
res[j++] = acopy(prm);
res[j++] = acopy(g[i++]);
return res;
}
// read access functions
// note: even positions for data, odd for delimiters
public String getName() {
return guts[0][0];
}
public String getValue() {
return guts[2][0];
}
public String getHeaderValue() {
return concata(guts, 2, guts.length-1);
}
public String toString() {
return concata(guts, 0, guts.length);
}
public String getPrmNam(int i) {
/*
* myout.println("index: " + i +" => " + ((i + 2) * 2
* +" guts.length: "+guts.length));
*/
if ((i + 2) * 2 >= guts.length)
return null;
return guts[(i + 2) * 2][0];
}
public String getPrmVal(int i) {
return guts[(i + 2) * 2][2];
}
public String[] getPrmWhole(int i) {
return guts[(i + 2) *2];
}
public String[] getParameterNames() {
String[] res = new String [guts.length / 2 - 2];
for (int i = 0; i < res.length; i++) {
res[i] = getPrmNam(i);
}
return res;
}
public int findPrmNam(String name) {
for (int i = 0, imax = guts.length / 2 - 2; i < imax; i++) {
if (name.equals(getPrmNam(i))) {
return i;
}
}
return -1;
}
// write access functions
// note: even positions for data, odd for delimiters
public void setName(String n) {
guts[0][0] = n;
}
public void setValue(String v) {
guts[2][0] = v;
}
public void setPrmNam(int i, String n) {
guts[(i + 2) * 2][0] = n;
}
public void setPrmVal(int i, String v) {
guts[(i + 2) *2][2] = v;
}
public void setPrmWhole(int i, String[] p) {
guts[(i + 2) *2] = p;
}
public void rmvPrm(int i) {
guts = acopyWithoutDelimAndPrm(guts, (i + 2) * 2);
}
public void appendPrmWhole(String[] prm) {
guts = acopyWithDelimAndPrm(guts,
new String[]
{ TestSipHeader2.makeDelimiterFor(this) },
prm);
}
public void setOrAddPrmWhole(String[] prm) {
int prmN = findPrmNam(prm[0]);
if (-1 != prmN) {
// myout.println("setOrAddPrmWhole: set");
setPrmWhole(prmN, prm);
} else {
// myout.println("setOrAddPrmWhole: append");
appendPrmWhole(prm);
}
}
}
class BlockedTestException extends Exception {
public BlockedTestException() { };
}
class NothingToDoInTestException extends Exception {
public NothingToDoInTestException() { };
}
abstract class TestSipHeader2_constants extends TestCase {
/** this one should never appear in the report */
public static final char NOTRUN = '-';
/** failure happened before the test was run */
public static final char BLOCKED = 'b';
/** test failed: wrong data */
public static final char FAILED = 'f';
/** test failed because it caused an exception */
public static final char EXCEPTION = 'X';
/** there has been nothing to do: not bad */
public static final char NOTHINGTODO = 'o';
/** success */
public static final char SUCCESS = 's';
final int nTests = 6;
final int nSubTests = 31; // not more that # of bits
final int exceptionAndNoSubTests = nSubTests - 1;
}
public class TestSipHeader2 extends TestSipHeader2_constants {
/** used as: testResult[firstHeaderN][secondHeaderN][testN] */
int testN;
/** used as: testResult[firstHeaderN][secondHeaderN][testN] */
int firstHeaderN;
/** used as: testResult[firstHeaderN][secondHeaderN][testN] */
int secondHeaderN;
/** used as: testResult[firstHeaderN][secondHeaderN][testN] */
char[][][] testResult;
/**
* a bit vertor. used as:
* failureReason[firstHeaderN][secondHeaderN][testN]
*/
int [][][] failureReason;
/** array of test names */
String[] testName = new String[nTests];
/** array of subtest names (that is, read access test names) */
private String[] subTestName = new String[nSubTests];
/**
* contains data on which we perform tests.
*/
String[][][] headerSample = new String[][][]
{
{{"Accept"}, {": "}, {"application/sdp"}, {"\r\n"}},
{{"Accept"}, {": "}, {"application/sdp"}, {";"}, {"level", "=", "1"},
{"\r\n"}},
{{"Accept"}, {": "}, {"text/html"}, {"\r\n"}},
{{"Accept-Encoding"}, {": "}, {"gzip"}, {"\r\n"}},
{{"Accept-Encoding"}, {": "}, {"identity"}, {"\r\n"}},
{{"Accept-Language"}, {": "}, {"da"}, {"\r\n"}},
{{"Accept-Language"}, {": "}, {"en-gb;q=0.8"}, {"\r\n"}},
{{"Accept-Language"}, {": "}, {"en;q=0.7"}, {"\r\n"}},
{{"Alert-Info"}, {": "}, {"<http://www.example.com/sounds/moo.wav>"},
{"\r\n"}},
{{"Alert-Info"}, {": "},
{"<http://www.freetones.org/vasya-pupkin/imperial.mp3>"}, {"\r\n"}},
{{"Allow"}, {": "}, {"INVITE"}, {"\r\n"}},
{{"Allow"}, {": "}, {"ACK"}, {"\r\n"}},
{{"Authentication-Info"}, {": "},
{"nextnonce", "=", "\"47364c23432d2e131a5fb210812c\""}, {"\r\n"}},
{{"Authentication-Info"}, {": "}, {"rspauth", "=", "\"1234567890\""},
{"\r\n"}},
{{"Authorization"}, {": "},
{"Digest"}, {" "},
{"username=\"Alice\""}, {", "},
{"realm", "=", "\"atlanta.com\""}, {", \n "},
{"nonce", "=", "\"84a4cc6f3082121f32b42a2187831a9e\""},
{", \n "},
{"response", "=", "\"7587245234b3434cc3412213e5f113a5432\""},
{"\r\n"}},
{{"Call-ID"}, {": "}, {"a84b4c76e66710@pc33.atlanta.com"}, {"\r\n"}},
{{"Call-ID"}, {": "},
{"f81d4fae-7dec-11d0-a765-00a0c91e6bf6@foo.bar.com"}, {"\r\n"}},
{{"Call-Info"}, {": "}, {"<http://wwww.example.com/alice/photo.jpg>"},
{" ;"}, {"purpose", "=", "icon"}, {"\r\n"}},
{{"Call-Info"}, {": "}, {"<http://www1.example.com/alice/>"}, {" ;"},
{"purpose", "=", "info"}, {"\r\n"}},
{{"Contact"}, {": "},
{"\"Mr. Watson\" <sip:watson@worcester.bell-telephone.com>"},
{";"},
{"q", "=", "0.7"}, {";"},
{"expires", "=", "3600"}, {"\r\n"}},
{{"Contact"}, {": "},
{"<sip:watson@worcester.bell-telephone.com>"}, {";"},
{"q", "=", "0.7"}, {";"},
{"expires", "=", "3600"}, {"\r\n"}},
{{"Contact"}, {": "}, {"<sip:alice@pc33.atlanta.com>"}, {"\r\n"}},
{{"CONTACT"}, {": "},
{"sip:user@host?Subject=foo&Call-Info=<http://www.foo.com>"},
{"\r\n"}},
{{"CONTACT"}, {": "}, {"<sip:alice@atlanta.com>"}, {";"},
{"ExPiReS", "=", "3600"}, {"\r\n"}},
{{"Content-Disposition"}, {": "}, {"session"}, {"\r\n"}},
{{"Content-Disposition"}, {": "}, {"icon"}, {"\r\n"}},
{{"Content-Disposition"}, {": "}, {"session"}, {";"},
{"handling=optional"}, {"\r\n"}},
{{"Content-Encoding"}, {": "}, {"gzip"}, {"\r\n"}},
{{"Content-Encoding"}, {": "}, {"compress"}, {"\r\n"}},
{{"Content-Encoding"}, {": "}, {"identity"}, {"\r\n"}},
{{"Content-Encoding"}, {": "}, {"deflate"}, {"\r\n"}},
{{"Content-Language"}, {": "}, {"fr"}, {"\r\n"}},
{{"Content-Language"}, {": "}, {"ru"}, {"\r\n"}},
{{"Content-Length"}, {": "}, {"142"}, {"\r\n"}},
{{"Content-Length"}, {": "}, {"0"}, {"\r\n"}},
{{"Content-Type"}, {": "}, {"application/sdp"}, {"\r\n"}},
{{"Content-Type"}, {": "}, {"image/gif"}, {"\r\n"}},
// ?? TODO: is space a delimiter?
{{"CSeq"}, {": "}, {"314159 INVITE"}, {"\r\n"}},
{{"CSeq"}, {": "}, {"63104 OPTIONS"}, {"\r\n"}},
{{"Date"}, {": "}, {"Sat, 13 Nov 2010 23:29:00 GMT"}, {"\r\n"}},
{{"Date"}, {": "}, {"Thu, 9 Jun 2005 17:32:21 GMT"}, {"\r\n"}},
{{"Error-Info"}, {": "}, {"<sip:not-in-service-recording@atlanta.com>"},
{"\r\n"}},
{{"Error-Info"}, {": "}, {"<sip:abc@def.gh>"}, {"\r\n"}},
{{"Expires"}, {": "}, {"5"}, {"\r\n"}},
{{"Expires"}, {": "}, {"7200"}, {"\r\n"}},
{{"From"}, {": "}, {"Bob <sip:bob@biloxi.com>"}, {";"},
{"tag", "=", "a6c85cf"}, {"\r\n"}},
{{"From"}, {": "}, {"Alice <sip:alice@atlanta.com>"}, {";"},
{"tag", "=", "1928301774"}, {"\r\n"}},
{{"From"}, {": "}, {"sip:+12125551212@phone2net.com"}, {";"},
{"tag=887s"}, {"\r\n"}},
{{"From"}, {": "}, {"Anonymous <sip:c8oqz84zk7z@privacy.org>"},
{";"}, {"tag", "=", "hyh8"}, {"\r\n"}},
{{"In-Reply-To"}, {": "}, {"17320@shanghai.chinatel.cn"}, {"\r\n"}},
{{"In-Reply-To"}, {": "}, {"70710@saturn.bell-tel.com"}, {"\r\n"}},
{{"Max-Forwards"}, {": "}, {"70"}, {"\r\n"}},
{{"Max-Forwards"}, {": "}, {"65"}, {"\r\n"}},
{{"Min-Expires"}, {": "}, {"60"}, {"\r\n"}},
{{"Min-Expires"}, {": "}, {"82"}, {"\r\n"}},
{{"Organization"}, {": "}, {" Boxes by Bob"}, {"\r\n"}},
{{"Organization"}, {": "}, {" gov.nist, whatever it could mean..."},
{"\r\n"}},
{{"Priority"}, {": "}, {"emergency"}, {"\r\n"}},
{{"Priority"}, {": "}, {"non-urgent"}, {"\r\n"}},
{{"Proxy-Authenticate"}, {": "}, {"Digest"}, {" "},
{"realm=\"atlanta.com\""}, {", "},
{"domain=\"sip:ss1.carrier.com\""}, {", "},
{"qop=\"auth\""}, {", "},
{"nonce=\"e84f1cce41e6cbe5aea9c8e88d35a\""}, {", "},
{"opaque=\"\""}, {", "},
{"stale=FALSE"}, {", "},
{"algorithm=MD5"}, {"\r\n"}},
//
{{"Proxy-Authorization"}, {": "}, {"Digest"}, {" "},
{"username=\"Alice\""}, {", "},
{"realm=\"otlonto.com\""}, {", "},
{"nonce=\"c60f3082ee1212b402a21831ae\""}, {", "},
{"response=\"245f23415f11432b3434341c022\""}, {"\r\n"}},
{{"Proxy-Require"}, {": "}, {"foo"}, {"\r\n"}},
{{"Proxy-Require"}, {": "}, {"bar"}
// , {"; "}, {"par", "=", "val"}
},
{{"Record-Route"}, {": "}, {"<sip:p4.domain.com;lr>"}, {"\r\n"}},
{{"Record-Route"}, {": "}, {"<sip:p3.middle.com>"}, {"\r\n"}},
{{"Reply-To"}, {": "}, {"Boob <sip:boob@beloxi.com>"}, {"\r\n"}},
{{"Reply-To"}, {": "}, {"Todd <sip:todd@biloxi.com>"}, {"\r\n"}},
{{"Require"}, {": "}, {"100rel"}, {"\r\n"}},
{{"Require"}, {": "}, {"glitchware-purse"}, {"\r\n"}},
{{"Retry-After"}, {": "}, {"18000"}, {";"},
{"duration", "=", "3600"}, {"\r\n"}},
{{"Retry-After"}, {": "}, {"120"}, {" (I'm in a meeting)"}, {"\r\n"}},
{{"Route"}, {": "}, {"<sip:alice@atlanta.com>"}, {"\r\n"}},
{{"Route"}, {": "}, {"<sip:UserB@there.com;maddr=ss2.wcom.com>"},
{"\r\n"}},
{{"Server"}, {": "}, {"HomeServer v2"}, {"\r\n"}},
{{"Server"}, {": "}, {"GlitchWare Ink Server v.1.0"}, {"\r\n"}},
// {{"Route"}, {": "},
// {"<sip:alice@atlanta.com>"}, {", "},
// {"<sip:bob@biloxi.com>"}, {", \n "},
// {"<sip:carol@chicago.com>"}, {"\r\n"}},
{{"Subject"}, {": "},
{"I know you're there, pick up the phone and talk to me!"}, {"\r\n"}},
{{"Subject"}, {": "}, {"Weekend plans"}, {"\r\n"}},
{{"Supported"}, {": "}, {"100rel"}, {"\r\n"}},
{{"Supported"}, {": "}, {"ggg"}, {"\r\n"}},
{{"Timestamp"}, {": "}, {"54"}, {"\r\n"}},
{{"Timestamp"}, {": "}, {"102"}, {"\r\n"}},
{{"To"}, {": "}, {"Bob <sip:bob@biloxi.com>"}, {"\r\n"}},
{{"To"}, {": "}, {"Todd <sip:todd@biloxi.com>"}, {";"},
{"tag", "=", "a6c85cf"}, {"\r\n"}},
{{"Unsupported"}, {": "}, {"100rel"}, {"\r\n"}},
{{"Unsupported"}, {": "}, {"mumble-dumble"}, {"\r\n"}},
{{"User-Agent"}, {": "}, {"Softphone Beta1.5"}, {"\r\n"}},
{{"User-Agent"}, {": "}, {"yes-kia car talk"}, {"\r\n"}},
{{"Via"}, {": "},
{"SIP/2.0/UDP pc33.atlanta.com"}, {";"},
{"branch", "=", "z9hG4bKhjhs8ass877"}, {"\r\n"}},
{{"Via"}, {": "},
{"SIP/2.0/UDP bigbox3.site3.atlanta.com"}, {"\n ;"},
{"branch", "=", "z9hG4bK77ef4c2312983.1"}, {";"},
{"received", "=", "192.0.2.2"}, {"\r\n"}},
{{"Warning"}, {": "}, {"370 devnull \"Choose a bigger pipe\""},
{"\r\n"}},
{{"Warning"}, {": "},
{"300 isi.edu \"Incompatible network protocol\""},
{"\r\n"}},
{{"WWW-Authenticate"}, {": "}, {"Digest"}, {" "},
{"realm=\"atlanta.com\""}, {", "},
{"domain=\"sip:boxesbybob.com\""}, {", "},
{"qop=\"auth\""}, {", "},
{"nonce=\"f84f1cec41e6cbe5aea9c8e88d359\""}, {", "},
{"opaque=\"\""}, {", "},
{"stale=FALSE"}, {", "},
{"algorithm=MD5"}, {"\r\n"}},
// Extension headers
{{"Asd"}, {": "}, {"fghjkl"}, {"; "}, {"qwe", "=", "rty"}, {"; "},
{"zxc", "=", "vbn"}, {"\r\n"}},
{{"Zxcv"}, {": "}, {"bnm"}, {"\r\n"}},
{{"Qwe"}, {": "}, {"rty"}, {"; "}, {"ui", "=", "op89"}, {"; "},
{"zx", "=", "cvb"}, {"; "}, {"nm", "=", "jhg-kl-09"}, {"\r\n"}},
// */
};
// auxiliary tools, specific stuff
public static String makeDelimiterFor(THeader h) {
String headerName = h.getName();
String res = "; ";
if (headerName == "WWW-Authenticate"
|| headerName == "Proxy-Authenticate"
|| headerName == "Proxy-Authorization"
|| headerName == "Authorization") {
res = ", ";
// TODO: IIRC the 1st delimiter is space while the 2nd one is comma
}
return res;
}
/**
* modify the string so that it looks good in the log (replace
* CR/LF by 'R' and 'N')
* @param s the string to be print-encoded
* @return the modified string
*/
static String prtEncode(String s) {
return s.replace('\r', 'R').replace('\n','N');
}
/**
* extract the test name from the class name. The class name has
* the form ...blah..blah...Tester_XYZ, where XYZ is the test name.
* @param s class name
* @return test name
*/
static String className2testName(String s) {
return s.substring(s.lastIndexOf('_') + 1);
// substring index = 0 if -1 is returned
}
public void linebreak() {
// if (verbose)
myout.println("=== 1st, 2nd:"+firstHeaderN+", "+secondHeaderN
+" ====================================================");
}
/**
* Print the test subtitle
*
* @param s descriptive text
* @param t the first THeader that contains data that get used and,
* probably, modified
* @param n the second THeader that serves as a source of data that
* replace data taken from the first THeader
*/
/*
* public void testing(String s, THeader t, THeader n)q {
* myout.println("### testing " + s +" '" + prtEncode(t.toString())
* + "' '" + prtEncode(n.toString()) + "'");
* }
*/
/**
* If got and expected do not match, set
* testResult[firstHeaderN][secondHeaderN][testN] to FAILED
*
* @param subTestN subtest number
* @param got the obtained string (gets compared to <code>expected</code>)
* @param expected the expected string
* @param shortDescr
* @param moreDescr some text for human readability
*/
public void expect(int subTestN,
String got,
String expected,
String shortDescr,
String moreDescr) {
if (null == subTestName[subTestN]) {
subTestName[subTestN] = shortDescr;
}
assertEquals("[" + shortDescr + "]" + "{" + moreDescr+ "}", expected, got);
if (got == null ? expected == null : got.equals(expected)) {
// myout.println("passed: "+subTestN+" "+description);
} else {
// myout.println( "*** error at subtest "
// + subTestN + " " + description +
// " \nexpected: '" + expected +
// "'\nobtained: '" + got + "'");
testResult[firstHeaderN][secondHeaderN][testN] = FAILED;
recordFailureReason(subTestN);
}
}
/**
* remembers which sub test has failed
* @param subTestNum
*/
void recordFailureReason(int subTestNum) {
failureReason[firstHeaderN][secondHeaderN][testN] |= 1 << subTestNum;
/*
* if (null == failureReason[firstHeaderN][secondHeaderN][testN]) {
* failureReason[firstHeaderN][secondHeaderN][testN] +=
* testName[testN];
* } else {
* failureReason[firstHeaderN][secondHeaderN][testN] +=
* " " + testName[testN];
* }
*/
}
/**
* convert a failure reason represented as a bit vector to a
* human-readable string with names of failed tests.
* @param fr failure reason
* @return
*/
String failureReasonToString(int fr) {
String res = "";
for (int i = 0; i < nSubTests; i++) {
if (0 != (fr & (1 << i))) {
if (res.equals("")) {
res = subTestName[i];
} else {
res += " " + subTestName[i];
}
}
}
if ("".equals(res))
res = "OK";
// if (fr != 0) res += " " + Integer.toHexString(fr);
return res;
}
/**
* an auxiliary function.
* if ctl is -1 (specifies the whole range), return ifrange, else
* return ifexact.
* @param ctl
* @param ifrange
* @param ifexact
* @return
*/
private int choose(int ctl, int ifrange, int ifexact) {
return ctl == -1 ? ifrange : ifexact;
}
/**
* return failure reasons encountered while running the specified test(s).
* @param fhn first header number, -1 for the whole range
* @param shn second header number, -1 for the whole range
* @param tn test number, -1 for the whole range
* @return
*/
int getFailureReasons(int fhn, int shn, int tn) {
// System.out.println("getFailureReasons(" + fhn + ", "
// + shn + ", " + tn + ")");
int cumulativeFailureReason = 0;
int nHeaderSamples = headerSample.length;
for (int firstHeaderN = choose(fhn, 0, fhn),
firstHeaderNBound = choose(fhn, nHeaderSamples, fhn + 1);
firstHeaderN < firstHeaderNBound;
firstHeaderN++) {
for (int secondHeaderN = choose(shn, 0, shn),
secondHeaderNBound = choose(shn, nHeaderSamples, shn + 1);
secondHeaderN < secondHeaderNBound;
secondHeaderN++) {
for (int testN = choose(tn, 0, tn),
testNBound = choose(tn, nTests, tn + 1);
testN < testNBound;
testN++) {
/*
* System.out.print("indices: " + firstHeaderN + " "
* + secondHeaderN + " " + testN);
* System.out.print(" bounds : " + firstHeaderNBound + " "
* + secondHeaderNBound + " " + testNBound);
* System.out.print(" reason:"
* + failureReason[firstHeaderN][secondHeaderN][testN]
* + "\n");
*/
cumulativeFailureReason |=
failureReason[firstHeaderN][secondHeaderN][testN];
}
}
}
return cumulativeFailureReason;
}
/**
* Throw a BlockedTestException if the test has failed at the
* pre-requisite stage. Why: we may discover a failure before
* we actually start the test, and we want such cases to be
* marked separately.
* Reads testResult[firstHeaderN][secondHeaderN][testN].
* @throws BlockedTestException
*/
public void failureMeansBlocked() throws BlockedTestException {
// myout.println("failureMeansBlocked():");
if (testResult[firstHeaderN][secondHeaderN][testN] != NOTRUN) {
// myout.println("failureMeansBlocked() yes!!!");
// testResult[firstHeaderN][secondHeaderN][testN] = BLOCKED;
throw new BlockedTestException();
}
}
/**
* same as expect, but for String arrays
* @param subTestN
* @param got
* @param expected
* @param shortDescr
* @param moreDescr
*/
public void expecta(int subTestN, String[] got, String[] expected,
String shortDescr, String moreDescr) {
// myout.println("areEqual(got, expected) = "
// + areEqual(got, expected));
if (null == subTestName[subTestN]) {
subTestName[subTestN] = shortDescr;
}
if (!areEqual(got, expected)) {
/*
* DEBUG:
* String msg = "*** error at subtest " + subTestN
* + " " + shortDescr + moreDescr
* + " \nexpected arr: ";
* msg += stringizeStrArr(expected);
* msg += "\nobtained arr: ";
* msg += stringizeStrArr(got);
* fail(msg);
*/
fail(shortDescr);
} else {
assertTrue(shortDescr + moreDescr, true);
// myout.println("passed: "+subTestN+" "+description);
}
}
/**
* compare two string arrays
* @param a
* @param b
* @return true if they are equal
*/
static boolean areEqual(String[] a, String[] b) {
if (a == b) {
return true;
}
if (a == null || b == null) {
return false;
}
if (a.length != b.length) {
return false;
}
for (int i = 0, len = a.length; i < len; i++) {
if (!a[i].equals(b[i])) {
return false;
}
}
return true;
}
/**
* print a string array to Syatem.out
* @param a
*/
void printStrArr(String[] a) {
myout.print("[" + a.length + "]" + "{");
for (int i = 0, len = a.length; i < len; i++) {
myout.print("'" + a[i] + "' ");
}
myout.print("}");
}
/**
* convert a string array to string
* @param a
*/
static String stringizeStrArr(String[] a) {
String res = "";
res = "[" + a.length + "]" + "{";
for (int i = 0, len = a.length; i < len; i++) {
res += "'" + a[i] + "' ";
}
res += "}";
return res;
}
/**
* print a string array to Syatem.out, and perform a carriage return
* @param a
*/
void printlnStrArr(String[] a) {
printStrArr(a);
myout.print("\n");
}
/**
* Compare data in the SipHeader h to the data in the THeader t,
* and modify testResult[firstHeaderN][secondHeaderN][testN] accordingly.
* Calls expect().
*
* This function is used first to verify the read access functions,
* and then to verify the results of write access functions.
* @param h
* @param t
* @param descr
*/
public void verifyOutputs(SipHeader h, THeader t, String descr) {
/*
* String args = " SipH='" + prtEncode(h.toString())
* + "' TH='" + prtEncode(t.toString()) + "'";
*/
String args = " '" + prtEncode(t.toString()) + "'";
try {
expect(1, h.getName(), t.getName(), "getName", args);
} catch (Throwable th) {
expect(1, "**EXCEPTION**", t.getName(), "getName", args);
}
try {
expect(2, h.getHeaderValue(), t.getHeaderValue(), "getHeaderValue",
args);
} catch (Throwable th) {
expect(2, "**EXCEPTION**", t.getHeaderValue(), "getHeaderValue",
args);
}
try {
expect(3, h.getValue(), t.getValue(), "getValue", args);
} catch (Throwable th) {
expect(3, "**EXCEPTION**", t.getValue(), "getValue", args);
}
try {
expect(4, h.toString(), t.toString(), "toString", args);
} catch (Throwable th) {
expect(4, "**EXCEPTION**", t.toString(), "toString", args);
}
try {
expecta(5, h.getParameterNames(), t.getParameterNames(),
"getParameterNames", args);
} catch (Throwable th) {
expecta(5, new String[] {"**EXCEPTION**"}, t.getParameterNames(),
"getParameterNames", args);
}
for (int i = 0; i < 9; i++) {
// myout.println("getParameterNames i:" + i);
if (t.getPrmNam(i) != null) {
try {
expect(10 + i, h.getParameter(t.getPrmNam(i)),
t.getPrmVal(i), "getParameter#" + i, args);
} catch (Throwable th) {
expect(10 + i, "**EXCEPTION**",
t.getPrmVal(i), "getParameter#" + i, args);
}
}
}
// expect(1,h., t.);
// expect(1,h., t.);
// expect(1,h., t.);
}
/**
* Common functionality for write function tester classes.
*/
abstract class Tester {
/**
* a constructor that does nothing
* (esp. in view of that there isn't any data)
*/
public Tester() { }
/**
* diagnostic actions to be performed when an exception happens
* @param t
* @param name
*/
void onExc(Throwable t, String name) {
myout.println("\n***{{ exception while testing "
+ name + "\n"
+ t + "\n}}***");
t.printStackTrace();
recordFailureReason(exceptionAndNoSubTests);
if (null == subTestName[exceptionAndNoSubTests]) {
subTestName[exceptionAndNoSubTests] = "EXCEPTION";
}
}
/**
* The framework function. Calls run() that gets overridden
* in the derived classes.
* @param t the first THeader that contains data that get used
* and, probably, modified
* @param n the second THeader that serves as a source of data
* that replace data taken from the first THeader
* @param descr0 test description: which arguments
*/
void test(THeader t, THeader n, String descr0) {
testResult[firstHeaderN][secondHeaderN][testN] = NOTRUN;
if (testName[testN] == null) {
testName[testN] = className2testName(this.getClass().getName());
}
String name = testName[testN];
String descr = name + " " + descr0;
declare(descr);
// testing(name, t, n);
try {
doTest(t, n, name + " " + descr);
/*
* myout.println("%%% successful run: "
* + testResult[firstHeaderN][secondHeaderN][testN]);
*/
if (testResult[firstHeaderN][secondHeaderN][testN] == NOTRUN) {
// still '-'; not 'f', and in fact no exception
// has been there
testResult[firstHeaderN][secondHeaderN][testN] = SUCCESS;
}
} catch (BlockedTestException bte) {
testResult[firstHeaderN][secondHeaderN][testN] = BLOCKED;
/*
* myout.println("%%% blocked test: "
* + testResult[firstHeaderN][secondHeaderN][testN]);
*/
fail(descr + "blocked");
} catch (NothingToDoInTestException ntdite) {
testResult[firstHeaderN][secondHeaderN][testN] = NOTHINGTODO;
/*
* myout.println("%%% nothing to do: "
* + testResult[firstHeaderN][secondHeaderN][testN]);
*/
assertTrue(descr + "nothing to do", true);
} catch (Throwable tt) {
testResult[firstHeaderN][secondHeaderN][testN] = EXCEPTION;
/*
* myout.println("%%% unsuccessful run: "
* + testResult[firstHeaderN][secondHeaderN][testN]);
*/
fail(descr + "exception");
onExc(tt, name);
}
}
/**
* run the test within the test() framework function.
* @param t the first THeader that contains data that get used and,
* probably, modified
* @param n the second THeader that serves as a source of data that
* replace data taken from the first THeader
* @param descr
* @throws BlockedTestException
*/
abstract void doTest(THeader t, THeader n, String descr)
throws BlockedTestException, NothingToDoInTestException;
}
class Tester_construct extends Tester {
public Tester_construct() { }
void doTest(THeader t, THeader n, String descr)
throws BlockedTestException {
/*
* myout.println("Creating # " + t.getName() + " # "
* + t.getHeaderValue() + " #");
*/
SipHeader s = new SipHeader(t.getName(), t.getHeaderValue());
verifyOutputs(s, t, descr);
}
}
class Tester_constructWithPrm extends Tester_construct {
String[] param1 = {"xprm1", "=", "Value1"};
String[] param2 = {"xprm2-pi", "=", "3.141592653589793238"};
String[] param3 = {"xprm3-text", "=",
"\"And his sister's weird, she drives a lorry\""};
public Tester_constructWithPrm() { }
void test(THeader t, THeader n, String descr) {
THeader tt = new THeader(t);
tt.appendPrmWhole(param1);
tt.appendPrmWhole(param2);
tt.appendPrmWhole(param3);
super.test(tt, n, descr);
}
}
class Tester_setName extends Tester {
public Tester_setName() { }
void doTest(THeader t, THeader n, String descr)
throws BlockedTestException {
/*
* myout.println("Test " + testN + " Creating # " + t.getName()
* + " # " + t.getHeaderValue() + " #");
*/
SipHeader s = new SipHeader(t.getName(), t.getHeaderValue());
verifyOutputs(s, t, descr);
failureMeansBlocked();
THeader m = new THeader(t);
m.setName(n.getName());
s.setName(n.getName());
verifyOutputs(s, m, descr);
}
}
class Tester_setValue extends Tester {
public Tester_setValue() { }
void doTest(THeader t, THeader n, String descr)
throws BlockedTestException {
SipHeader s = new SipHeader(t.getName(), t.getHeaderValue());
verifyOutputs(s, t, descr);
failureMeansBlocked();
THeader m = new THeader(t);
/*
* myout.println("s,m before: $" + prtEncode(s.toString()) + "$"
* + prtEncode(m.toString()) + "$");
* myout.println("setValue: $"
* + n.getValue() + "$");
*/
m.setValue(n.getValue());
s.setValue(n.getValue());
/*
* myout.println("s,m after : $" + prtEncode(s.toString())
* + "$" + prtEncode(m.toString()) + "$");
*/
verifyOutputs(s, m, descr);
}
}
class Tester_removeParameter extends Tester {
public Tester_removeParameter() { }
void doTest(THeader t, THeader n, String descr)
throws BlockedTestException, NothingToDoInTestException {
String[] prm = n.getParameterNames();
// printStrArr(prm);
if (0 == prm.length) {
// myout.println("nothing to do");
throw new NothingToDoInTestException();
}
for (int i = 0; i < prm.length; i++) {
SipHeader s = new SipHeader(t.getName(), t.getHeaderValue());
THeader m = new THeader(t);
verifyOutputs(s, m, descr);
failureMeansBlocked();
// myout.println("s,m before: $" + s + "$" + m + "$");
m.rmvPrm(i);
s.removeParameter(t.getPrmNam(i));
// myout.println("s,m after : $" + s + "$" + m + "$");
verifyOutputs(s, m, descr);
if (testResult[firstHeaderN][secondHeaderN][testN] != NOTRUN) {
// myout.println("s,m already wrong, exiting test");
break;
}
}
}
}
class Tester_setParameter extends Tester {
public Tester_setParameter() { }
void doTest(THeader t, THeader n, String descr)
throws BlockedTestException, NothingToDoInTestException {
String[] prm = n.getParameterNames();
// printStrArr(prm);
if (0 == prm.length) {
// myout.println("nothing to do");
throw new NothingToDoInTestException();
}
for (int i = 0; i < prm.length; i++) {
SipHeader s = new SipHeader(t.getName(), t.getHeaderValue());
THeader m = new THeader(t);
verifyOutputs(s, m, descr);
failureMeansBlocked();
// myout.println("s,m before: !" + s + "!" + m + "!");
m.setOrAddPrmWhole(n.getPrmWhole(i));
s.setParameter(n.getPrmNam(i), n.getPrmVal(i));
// myout.println("s,m after : !"+s+"!"+m+"!");
verifyOutputs(s, m, descr);
if (testResult[firstHeaderN][secondHeaderN][testN] != NOTRUN) {
// myout.println("s,m already wrong, exiting test");
break;
}
}
}
}
/**
* Run all tests with the arguments t and n
* @param t specifies the header that gets constructed and modified
* @param n a header that serves as a data source for modifications
* @param descr text description of arguments t and n
*/
public void verifyAll(THeader t, THeader n, String descr) {
testN = 0;
new Tester_construct().test(t, n, descr); testN++;
new Tester_constructWithPrm().test(t, n, descr); testN++;
new Tester_setName().test(t, n, descr); testN++;
new Tester_setValue().test(t, n, descr); testN++;
new Tester_removeParameter().test(t, n, descr); testN++;
new Tester_setParameter().test(t, n, descr); testN++;
if (testN != nTests) {
throw new RuntimeException("mismatch in # of tests");
}
}
/**
* Body of the test 1.
*
* Test constructors of SipAddress class.
*/
void Test1() {
for (int i = 0; i < headerSample.length; i++) {
for (int j = 0; j < headerSample.length; j++) {
firstHeaderN = i;
secondHeaderN = j;
linebreak();
THeader t = new THeader(headerSample[i]);
THeader n = new THeader(headerSample[j]);
/*
* DEBUG:
* String argsDescr = "\nwithHdr: '"
* + prtEncode(n.toString())
* + "' (" + i + ")\ndataSrc: '"
* + prtEncode(t.toString())
* + "' (" + j +")\n";
*/
String argsDescr = "test1";
verifyAll(t, n, argsDescr);
}
}
}
/*
* void Test2() {
* RandomAccessStream ras = new RandomAccessStream();
* try {
* ras.connect("test.log",Connector.WRITE);
* OutputStream os=ras.openOutputStream();
* os.write("testing log".getBytes());
* os.close();
* ras.disconnect();
* } catch (IOException e) {
* e.printStackTrace();
* }
* }
*/
MyOut myout = new MyOut();
class MyOut {
RandomAccessStream ras;
OutputStream os;
public static final String fileName = "funcmap.txt";
void init() {
ras = new RandomAccessStream();
try {
File fs = new File();
if (fs.exists(fileName)) {
fs.delete(fileName);
}
} catch (IOException e) {
System.err.print("problems when trying to delete old log file: "
+ fileName);
}
try {
ras.connect(fileName, Connector.WRITE);
os = ras.openOutputStream();
} catch (IOException e) {
System.err.print("could not open log");
}
}
void windup() {
try {
os.close();
ras.disconnect();
} catch (IOException e) {
System.err.print("could not close log");
}
}
void print(String s) {
try {
os.write(s.getBytes());
} catch (IOException e) {
System.err.print("could not write to log");
}
}
void print(char c) {
try {
os.write(c);
} catch (IOException e) {
System.err.print("could not write to log");
}
}
void println(String s) {
print(s+"\n");
}
void println() {
print("\n");
}
}
/**
* print the "functionality coverage map" indicating what tests
* fail on what data.
*/
void printResults() {
myout.print("\n");
for (int k = 0; k < nTests; k++) {
myout.print("---- test " + k + " -- " + testName[k] + " ---- \n");
for (int i = 0; i < headerSample.length; i++) {
myout.print("" + (i / 10 % 10));
}
myout.println();
for (int i = 0; i < headerSample.length; i++) {
myout.print("" + (i % 10));
}
myout.println();
for (int i = 0; i < headerSample.length; i++) {
for (int j = 0; j < headerSample.length; j++) {
myout.print(testResult[i][j][k]);
}
myout.print(" (" + i + ")"
+ prtEncode(new THeader(headerSample[i]).toString())
+ "\n");
}
myout.print("\n");
}
myout.print("---- used headers ---- \n");
for (int i = 0; i < headerSample.length; i++) {
for (int j = 0; j < i; j++) {
myout.print(" ");
}
myout.print("" + i +": ");
myout.print(prtEncode(new THeader(headerSample[i]).toString()));
myout.print("\n");
}
myout.print("\n");
}
void printAnalysis() {
try {
myout.print("---- per-sample analysis ---- \n");
for (int sn = 0; sn < headerSample.length; sn++) {
myout.println("\n" + sn + ") " + headerSample[sn][0][0]);
myout.println(new THeader(headerSample[sn]).toString());
for (int tn = 0; tn < nTests; tn++) {
myout.print(testName[tn] + ": ");
myout.println(failureReasonToString(getFailureReasons(sn,
-1,
tn)));
}
}
} catch (Throwable e) {
System.out.println("in printAnalysis():");
e.printStackTrace();
}
/*
* myout.print("---- per-class analysis ---- \n");
* for (int sampleNFrom=0, sampleNUpto=0; s
* ampleNFrom < headerSample.length;
* sampleNFrom = sampleNUpto) {
* myout.println(headerSample[sampleNFrom][0][0]);
* for (sampleNUpto = sampleNFrom;
* sampleNUpto<headerSample.length
* && headerSample[sampleNFrom][0][0]
* .equals(headerSample[sampleNUpto][0][0]);
* sampleNUpto++) {
* }
* for (int tn = 0; tn < nTests; tn++) {
* myout.print(testName[tn]+": ");
* }
* for (int k = sampleNFrom; k < sampleNUpto; k++) {
* }
* }
*/
}
/**
* Tests execute
*/
public void runTests() {
// declare("Constructor SipAddress test");
testResult = new char[headerSample.length][headerSample.length][nTests];
failureReason =
new int[headerSample.length][headerSample.length][nTests];
myout.init();
Test1();
printResults();
printAnalysis();
myout.windup();
}
}
|