0707.321 Principles of Software Engineering

Homework 4: Black Box Testing


Due Date

Both Sections: Monday, December 10
(Assignments submitted by Dec 7 will be graded for Dec 10)

Form of Submission

Homework can submitted via email or printout by deadline.

Preparation

This assignment will provide you with some experience in testing software. You are encouraged to do this assignment in pairs (let me know who you are working with), but independent work is permitted.

Assignment

  1. The software you will be testing is a C++ program library. Study the supplied interface specification and documentation, and develop a test plan. Your plan should consist of:

    1. Analysis of the specification
    2. A set of test cases
    3. Test data for the test cases

  2. On Wednesday, December 5, an implementation (mostly) satisfying the interface will be released. At that time, you will be able to apply your tests against the implementation and report on your findings. Your submission should consist of the three items above plus:

    1. The results of your tests (traces)
    2. A summary of your conclusions
    3. The source code you used to conduct the tests.

    Do not attempt to hypothesize on the cause of any "bugs" you find; just describe (in as much detail as possible) any problems your tests uncover.

    Feel free to expand your test suite as necessary after December 5. The purpose of the delayed deployment is to encourage you to think about your testing strategy in the abstract first. Since black box testing is performed without consulting the implementation, not having it available right away should not be a problem.


The Message Compressor


class Compressor {
public:
    static Compressor* MakeCompressor(bool removeWhitespace,
                                      bool removeVowels,
                                      const Dictionary* abbreviations);
    virtual ~Compressor() { }

    // Caller assumes ownership of output (for memory management)
    virtual bool CompressMessage(const char* input, char*& output) = 0;
};

The Message Compressor takes a string as input and performs a series of operations on it, with the intent of shortening its length without rendering it illegible. The newer generation of mobile telephones have the ability to display text messages, but the protocol requires that these messages must be quite short (usually less than 160 characters). The Message Compressor could be used to shorten messages (e.g. email) before they are forwarded to the phone.

Four compression strategies are available. One is always applied, the other three can applied optionally. They are:

  1. Whitespace Compression

    Replace all newline characters with a single space. Replace all occurrences of consecutive whitespace (i.e., space, tab, newline) characters with a single space. This strategy is always applied.

  2. Whitespace Removal

    When this compression strategy is applied, all whitespace between words is removed. To keep the word boundaries identifiable, the first letter of each word is capitalized.

  3. Vowel Removal

    When this compression strategy is applied, all vowels, except those appearing at the beginning of a word, are removed.

  4. Word Abbreviation Substitution

    Given a list of phrases and abbreviations, convert any occurrences of the phrases in the message into their abbreviations. Do not remove any vowels from the abbreviations, even if the Vowel Removal option is selected. Phrases can be removed entirely by leaving the second field blank.




Here are some sample messages, compressed under four different configurations. The sample Abbreviation Dictionary used appears in the Appendix.

"Mr. Watson. Come here. I need you."
"Mr.Watson.ComeHere.INeedYou." [1+2]
"Mr. Wtsn. Cm hr. I nd y." [1+3]
"Mr.Wtsn.CmHr.INdY." [1+2+3]
"MrWtsn.CmHr.INdU." [1+2+3+4*]

"Four score and seven years ago"
"FourScoreAndSevenYearsAgo" [1+2]
"Fr Scr And Svn Yrs Ag" [1+3]
"FrScrAndSvnYrsAg" [1+2+3]
"4Scr&7YrsAg" [1+2+3+4*]
See you monday at 4
SeeYouMondayAt4 [1+2]
S y mndy at 4 [1+3]
SYMndyAt4 [1+2+3]
CUMon@4 [1+2+3+4*]



Programming Interface

Message Compressors are constructed via the factory method: MakeCompressor(). The caller takes ownership of the compressor object, and is expected to delete it when they are done with it.

To compress a message, call the method CompressMessage(). The method takes two arguments, both character pointers (C strings), but their are roles are drastically different. The first string must be the message to be compressed. The second is uninitialized at entry, but upon successful return (when the return value is true), will contain a string representing the compressed message. The caller assumes responsibility for that second string, and is expected to delete it.





The Abbreviation Dictionary


class Dictionary {
public:
    static Dictionary* MakeDictionary();
    static Dictionary* MakeDictionary(const char* filename);
    virtual ~Dictionary() { }

    virtual bool AddToDictionary(const char* from, const char* to) = 0;
    virtual bool RemoveFromDictionary(const char* from) = 0;
};

The Abbreviation Dictionary is a table mapping words and phrases (the source) to other words or phrases (the abbreviation). The dictionary can be constructed from within a program (using the AddToDictionary() method) or it can be built up out of a file, where each source/abbreviation pair on its own line, with at least one tab character separating the source phrase from the abbreviation. The abbreviation can be empty, signifying that the source phrase should removed during compression.




Programming Interface

AddToDictionary() takes two string arguments (from, the source, and to the abbreviation) and returns a boolean, signifying whether the abbreviation was successfully entered into the dictionary. It is illegal to have multiple abbreviations for the same source. To redefine an source's abbreviation, remove it first.

RemoveFromDictionary() takes one string argument (the source) and returns a boolean, signifying whether the removal was successful. If the source provided does not appear in the dictionary, a false value is returned.

Dictionaries are constructed via the factory methods: MakeDictionary() and MakeDictionary(char *), the former returning an empty dictionary, and the latter returning a dictionary initialized with the entries found in the supplied file(name). The caller takes ownership of any dictionary objects constructed, and is expected to delete them when they are done with them.






Appendix A: Sample Test Program

Here is a very simple program illustrating how to use the Message Compression facility:
#include <iostream.h>
#include "compress.h"

main() {
    Compressor* comp =
        Compressor::MakeCompressor(true, false, Dictionary::MakeDictionary());

    char* out = 0;
    char* in = "Four score and seven years ago";

    bool b = comp->CompressMessage(in, out);

    int lin = strlen(in);
    cout << "IN:\t" << in << " (" << lin << ")" << endl;
    
    if (b) {
        int lout = strlen(out);
        cout << "OUT:\t" << out << " (" << lout << ")" << endl;
        cout << endl << "Compression rate: "
             << (100 * (lin - lout) / lin) << '%' << endl;
    }

    delete out;
    delete comp;
}




Appendix B: Sample Abbreviation Dictionary

one                             1
two                             2
three                           3
four                            4
five                            5
six                             6
seven                           7
eight                           8
nine                            9
ten                             10
eleven                          11
twelve                          12
and                             &
at                              @
plus                            +
see                             C
you                             U
for                             4
the             
love                            Luv
monday                          Mon
tuesday                         Tue
wednesday                       Wed
thursday                        Thurs
friday                          Fri
saturday                        Sat
sunday                          Sun
towards                         to
regarding                       Re
as far as I know                AFAIK
in my humble opinion            IMHO