Lab 2 - Simple Search Engine and Testing
Table of Contents
1. Simple Search Engine
In Week 2, we implemented an ultra-basic search engine to practice our use of ssh
and scp
. Using the structure of the given Server.java
file, I was able to implement the search engine using the following code:
import java.io.IOException;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
class Handler implements URLHandler {
List<String> list = new ArrayList<>();
public String handleRequest(URI url) {
if (url.getPath().equals("/")) {
return String.format("Basic Search Engine");
}
else {
System.out.println("Path: " + url.getPath());
if (url.getPath().contains("/add")) {
String[] parameters = url.getQuery().split("=");
if (parameters[0].equals("s")) {
list.add(parameters[1]);
return String.format("%s added to the list", parameters[1]);
}
}
if (url.getPath().contains("/search")) {
String[] parameters = url.getQuery().split("=");
List<String> ans = new ArrayList<>();
if (parameters[0].equals("s")) {
for (String i: list) {
if (i.contains(parameters[1])) {
ans.add(i);
}
}
}
return String.join(" ", ans);
}
return "404 Not Found!";
}
}
}
class SearchEngine {
public static void main(String[] args) throws IOException {
if(args.length == 0){
System.out.println("Missing port number! Try any number between 1024 to 49151");
return;
}
int port = Integer.parseInt(args[0]);
Server.start(port, new Handler());
}
}
You can run the above class using javac SearchEngine.java
and java SearchEngine <port-number>
. (Note that you must pass in the desired port number as an argument into the command line - this value can be anything between 1024 and 49151). Once you run the program, the main
function is called - establishing the web server at the selected port and allowing you to view the live version of your project at <host>:<port-number>
. Your screen should look somewhat like the one below:
After getting the live version of the program running, you can append various paths to the end of the URL to achieve different results. There are two basic functions that you can use: /add?s=<element>
and /search?s=<query>
. They’re both detailed below:
- /add
-
After appending
/add
to the end of your URL, you can append?s=
followed by any String value. Doing this will call thehandleRequest
function and will go into the the firstif
condition. This appendage will add your chosen value to the ArrayList,list
. The function will then print to the screen, confirming that your chosen value has been added to the list. An example for the String value “34” is shown below:
-
- /search
-
After adding
/search
to the end of your URL, you can append?s=
followed by any String value. This will invoke the secondif
condition inhandleRequest
and will search the ArrayList,list
, for any occurrences of the String value passed in through the query. The function then iterates throughlist
and returns a list of the elements fromlist
that contain the String value. In the example below, I have added the following values tolist
:{"34", "25", "24", "234", "as34d"}
. Searching for the value “34” returns the following:
-
2. Testing
- ArrayExamples Bugs
- Test - The test used to identify this bug is detailed below:
@Test public void testReverse() { int[] a = {3, 1, 5}; assertArrayEquals(new int[]{5, 1, 3}, ArrayExamples.reversed(a)); }
- Code - The code for the
ArrayExmples.reversed()
function is detailed below:
static int[] reversed(int[] arr) { int[] newArray = new int[arr.length]; for(int i = 0; i < arr.length; i += 1) { arr[i] = newArray[arr.length - i - 1]; } return arr; }
- Symptoms - When the above test is run, the
reversed
function runs on arraya
, but returns the array{0, 0, 0}
, which is the incorrect reversal. The correct reversed array should be{5, 1, 3}
. - Bugs - When the above test is run, the function above is invoked on the array
a
. Thereversed
function then iterates througharr
(reference toa
), reassigning each value inarr
(a
) to the diametrically opposite index value fromnewArray
, an initialized array from within thereversed
function. This causes each value ina
to be reassigned to the default values put intonewArray
whennewArray
was initialized, which in our case, is 0. - Fixes - This issue could be easily corrected by correcting line 4 of the
reversed
function to be the following:newArray[i] = arr[arr.length - i - 1];
. Additionally, you would need to change the return statement to bereturn newArray;
instead ofreturn arr;
- Sample Run - The JUNIT report for this test is shown below:
- ListExamples Bugs
- Test - The test used to identify this bug is detailed below:
@Test public void testMerge() { ArrayList<String> first = new ArrayList<String>(); ArrayList<String> second = new ArrayList<String>(); first.add("A"); second.add("B"); first.add("C"); second.add("D"); ArrayList<String> test = new ArrayList<String>(); test.add("A"); test.add("B"); test.add("C"); test.add("D"); assertEquals(test, ListExamples.merge(first, second)); }
- Code - The code for the
ListExamples.merge()
function is detailed below:
static List<String> merge(List<String> list1, List<String> list2) { List<String> result = new ArrayList<>(); int index1 = 0, index2 = 0; while(index1 < list1.size() && index2 < list2.size()) { if(list1.get(index1).compareTo(list2.get(index2)) < 0) { result.add(list1.get(index1)); index1 += 1; } else { result.add(list2.get(index2)); index2 += 1; } } while(index1 < list1.size()) { result.add(list1.get(index1)); index1 += 1; } while(index2 < list2.size()) { result.add(list2.get(index2)); index1 += 1; } return result; }
- Symptoms - The test
testMerge
invokes themerge
function from above on thefirst
andsecond
ArrayLists. When run on these two ArrayLists, themerge
function runs infinitely, and is stuck in an infinite loop. This causes the heap (the memory allocated by Java for your program) gets too full, causing the program to be terminated early. - Bugs - The function
merge
, when run on two ArrayLists, does not check if the element that it is considering adding has already been added. Thus, in line 28, the program continuously adds the last element fromlist1
(first
) when all elements inlist1
are lexicographically lesser in value, as compared with the elements fromlist2
(second
). - Fixes - The function
merge
should keep a track of which list the last element was added from, whether that be through a boolean value or keeping a current List and redefining that to the current active list. Once a list has been exhausted and all the elements of the list have been added to theresult
ArrayList, the function should only add elements from the other List. - Sample Run - The JUNIT report for this test is shown below: