-64
COVERSHEET.md
-64
COVERSHEET.md
···
1
-
---
2
-
Project: "#6"
3
-
Professor: "Professor Knoerr"
4
-
Class: "CS 1210 – Fall 2025"
5
-
Author: "Kieran Klukas"
6
-
---
7
-
8
-
# Requirements
9
-
10
-
<!--Restate the problem specifications in your own words-->
11
-
12
-
Search a provided old testament text file for arbitrary reference. It prompts the user for book, chapter, and verse and then searches for that verse. If book is not found then output `Book does not exist in the Old Testament`. If chapter isn't found then `Chapter # does not exist in Book`. Finally if the verse isn't found then output `Verse # does not exist in Book #`. Once the verse is found then append the verse to `verses.txt`.
13
-
14
-
# Design
15
-
16
-
<!--How did you attack the problem? What choices did you make in your design, and why?-->
17
-
18
-
I started with outlining the basic input system [`532c6cf`](https://github.com/cu-cs1210/lab-6-kieranklukas/commit/5b2ced23798fc7cbce79eb445c9592cccf16d6a6). Then worked on setting up a while loop to read the file line by line. I spent a while puzzling over exactly how I wanted to implement this and I am not entirely satisfied with my current solution. It would be interesting to try this problem in a functional language like gleam or erlang and see how much more cleanly I can parse the file. I implemented each reference part sequentially and then went back and made it check for barrier strings to stay within the proper book and chapter. I ended up realizing that the book of Psalms is referenced differently and so made some logic to permit its idiosyncracies [`7c18fff`](https://github.com/cu-cs1210/lab-6-kieranklukas/commit/7c18fffa30ab3e43bcb05ad4dff44f275987cbb8).
19
-
20
-
# Implementation
21
-
22
-
<!--Outline any interesting implementation details.-->
23
-
24
-
I used a single input variable to parse the file word by word until we get to the correct verse. I also check if the input book is listed as `Psalm` or `Psalms` and add or remove an `s` when doing checks or output as appropriate. The output file is also never opened until we find the verse and is immediately closed afterward. Also a minor note of intrest is that you can change the default paths that the program loads from and saves to by adding the paths as arguments (eg. `lab66 test/OT.txt build/verses.txt`).
25
-
26
-
# Testing
27
-
28
-
<!--
29
-
Explain how you tested your program, enumerating the tests if possible.
30
-
Explain why your test set was sufficient to believe that the software is working properly,
31
-
i.e., what were the range of possibilities of errors that you were testing for.
32
-
-->
33
-
34
-
I updated the `makefile` to add `make run` so I could compile and run it more easily and updated the test file to have the Zylabs test states as well as more granularly check a happy path and some adversarial paths.
35
-
36
-
# Outside Help
37
-
38
-
<!--Did you get help from anyone else on this project? Document their contribution to your learning.-->
39
-
40
-
No outside help was used beyond minor googling for how to capitalize an entire string and the proper syntax for appending (not covered in zybooks as far as I can tell but I'm sure you will cover it in lectures next week).
41
-
42
-
# Summary/Conclusion
43
-
44
-
<!--Present your results. Did it work properly? Are there any limitations?-->
45
-
46
-
The program works well and should cover most edgecases! As far as I can tell there isn't anything that should be able to break it beyond changing the `OT.txt` to be several GB in size.
47
-
48
-
# AI Use
49
-
50
-
<!--How did you use Generative AI in this project?-->
51
-
52
-
I used claude to generate a more complex test file and then modified it to add the rest of the zybooks tests as I got closer to finishing the project.
53
-
54
-
# Lessons Learned
55
-
56
-
<!--List any lessons learned. What might you have done differently if you were going to attack this again.-->
57
-
58
-
I would definetly want to try a different language for sure if I was doing this independantly but overal I think this implementation is fairly solid and I wouldn't change much. I did find out in this lab that it is always a good idea to check the whole input or you might run into weird bugs like how `PSALMS` is formatted.
59
-
60
-
# Time Spent
61
-
62
-
<!--Approximately how many hours did you spend on this project?-->
63
-
64
-

+15
-63
README.md
+15
-63
README.md
···
1
-
# Lab 6
2
-
3
-

4
-
5
-
For this lab the program must parse `OT.txt` (format below) to find specific references and produce scoped errors if the reference isn't found.
6
-
7
-
```text
8
-
THE BOOK OF GENESIS
9
-
10
-
CHAPTER 1
11
-
1 In the beginning God created the heaven and the earth.
12
-
2 And the earth was without form, and void; and darkness [was] upon the face of the deep. And the Spirit of God moved upon the face of the waters.
13
-
3 And God said, Let there be light: and there was light.
14
-
4 And God saw the light, that [it was] good: and God divided the light from the darkness.
1
+
# bible_search_gleam
15
2
16
-
THE BOOK OF PSALMS
3
+
[](https://hex.pm/packages/bible_search_gleam)
4
+
[](https://hexdocs.pm/bible_search_gleam/)
17
5
18
-
PSALM 1
19
-
1 Blessed [is] the man that walketh not in the counsel of the ungodly, nor standeth in the way of sinners, nor sitteth in the seat of the scornful.
20
-
2 But his delight [is] in the law of the LORD; and in his law doth he meditate day and night.
21
-
3 And he shall be like a tree planted by the rivers of water, that bringeth forth his fruit in his season; his leaf also shall not wither; and whatsoever he doeth shall prosper.
6
+
```sh
7
+
gleam add bible_search_gleam@1
22
8
```
23
-
24
-
The project is layed out as follows:
25
-
26
-
```bash
27
-
.
28
-
├── build # this directory isn't committed and is ephemeral
29
-
│ └── lab66
30
-
├── COVERSHEET.md
31
-
├── LICENSE.md
32
-
├── makefile
33
-
├── README.md
34
-
├── src
35
-
│ └── lab66.cpp
36
-
└── test
37
-
├── OT.txt
38
-
└── test.sh
9
+
```gleam
10
+
import bible_search_gleam
39
11
40
-
4 directories, 8 files
12
+
pub fn main() -> Nil {
13
+
// TODO: An example of the project in use
14
+
}
41
15
```
42
16
43
-
### Build scripts
17
+
Further documentation can be found at <https://hexdocs.pm/bible_search_gleam>.
44
18
45
-
The preferred way to run the program is through make:
19
+
## Development
46
20
47
-
```bash
48
-
make # compiles and runs tests
49
-
make run # compiles and runs the program
50
-
make clean # clean up the build dir
21
+
```sh
22
+
gleam run # Run the project
23
+
gleam test # Run the tests
51
24
```
52
-
53
-
it is however possible to still do things manually:
54
-
55
-
```bash
56
-
mkdir build
57
-
cd build
58
-
g++ ../src/lab66.cpp -o lab66
59
-
./lab66 ../test/OT.txt verses.txt
60
-
```
61
-
62
-
<p align="center">
63
-
<img src="https://raw.githubusercontent.com/taciturnaxolotl/carriage/main/.github/images/line-break.svg" />
64
-
</p>
65
-
66
-
<p align="center">
67
-
<i><code>© 2025-present <a href="https://github.com/taciturnaxololt">Kieran Klukas</a></code></i>
68
-
</p>
69
-
70
-
<p align="center">
71
-
<a href="https://github.com/cu-cs1210/lab-6-kieranklukas/blob/main/LICENSE.md"><img src="https://img.shields.io/static/v1.svg?style=for-the-badge&label=License&message=MIT&logoColor=d9e0ee&colorA=363a4f&colorB=b7bdf8"/></a>
72
-
</p>
docs/freeze.jpeg
docs/freeze.jpeg
This is a binary file and will not be displayed.
+21
gleam.toml
+21
gleam.toml
···
1
+
name = "bible_search"
2
+
version = "1.0.0"
3
+
4
+
# Fill out these fields if you intend to generate HTML documentation or publish
5
+
# your project to the Hex package manager.
6
+
#
7
+
# description = ""
8
+
# licences = ["Apache-2.0"]
9
+
# repository = { type = "github", user = "", repo = "" }
10
+
# links = [{ title = "Website", href = "" }]
11
+
#
12
+
# For a full reference of all the available options, you can have a look at
13
+
# https://gleam.run/writing-gleam/gleam-toml/.
14
+
15
+
[dependencies]
16
+
gleam_stdlib = ">= 0.44.0 and < 2.0.0"
17
+
simplifile = ">= 2.3.0 and < 3.0.0"
18
+
input = ">= 1.0.1 and < 2.0.0"
19
+
20
+
[dev-dependencies]
21
+
gleeunit = ">= 1.0.0 and < 2.0.0"
-16
makefile
-16
makefile
+16
manifest.toml
+16
manifest.toml
···
1
+
# This file was generated by Gleam
2
+
# You typically do not need to edit this file
3
+
4
+
packages = [
5
+
{ name = "filepath", version = "1.1.2", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "filepath", source = "hex", outer_checksum = "B06A9AF0BF10E51401D64B98E4B627F1D2E48C154967DA7AF4D0914780A6D40A" },
6
+
{ name = "gleam_stdlib", version = "0.65.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "7C69C71D8C493AE11A5184828A77110EB05A7786EBF8B25B36A72F879C3EE107" },
7
+
{ name = "gleeunit", version = "1.6.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleeunit", source = "hex", outer_checksum = "FDC68A8C492B1E9B429249062CD9BAC9B5538C6FBF584817205D0998C42E1DAC" },
8
+
{ name = "input", version = "1.0.1", build_tools = ["gleam"], requirements = [], otp_app = "input", source = "hex", outer_checksum = "FE84CDADC78A1367E4AFD561A529825A8FEC88D165CBDF511FD3226CABCDEE6F" },
9
+
{ name = "simplifile", version = "2.3.0", build_tools = ["gleam"], requirements = ["filepath", "gleam_stdlib"], otp_app = "simplifile", source = "hex", outer_checksum = "0A868DAC6063D9E983477981839810DC2E553285AB4588B87E3E9C96A7FB4CB4" },
10
+
]
11
+
12
+
[requirements]
13
+
gleam_stdlib = { version = ">= 0.44.0 and < 2.0.0" }
14
+
gleeunit = { version = ">= 1.0.0 and < 2.0.0" }
15
+
input = { version = ">= 1.0.1 and < 2.0.0" }
16
+
simplifile = { version = ">= 2.3.0 and < 3.0.0" }
+47
src/bible_search.gleam
+47
src/bible_search.gleam
···
1
+
import gleam/int
2
+
import gleam/io
3
+
import gleam/list
4
+
import gleam/string
5
+
import input.{input}
6
+
import simplifile
7
+
8
+
const filepath = "./OT.txt"
9
+
10
+
pub type Reference {
11
+
Reference(book: String, chapter: Int, verse: Int)
12
+
}
13
+
14
+
pub fn parse_reference(input: String) -> Result(Reference, String) {
15
+
let parts = string.split(input, on: " ")
16
+
17
+
case parts {
18
+
[book, chapter_s, verse_s] ->
19
+
case int.parse(chapter_s) {
20
+
Ok(chapter) ->
21
+
case int.parse(verse_s) {
22
+
Ok(verse) ->
23
+
Ok(Reference(book: string.uppercase(book), chapter:, verse:))
24
+
Error(_) -> Error("Invalid verse" <> verse_s)
25
+
}
26
+
Error(_) -> Error("Invalid chapter" <> chapter_s)
27
+
}
28
+
_ -> Error("invalid parse")
29
+
}
30
+
}
31
+
32
+
pub fn main() -> Nil {
33
+
let assert Ok(bible) = simplifile.read(from: filepath)
34
+
35
+
let biblelines = string.split(bible, on: "\n")
36
+
37
+
let assert Ok(search) = input(prompt: "> ")
38
+
39
+
let assert Ok(reference) = parse_reference(search)
40
+
41
+
list.each(biblelines, fn(line) {
42
+
case line {
43
+
"THE BOOK OF " <> book if book == reference.book -> io.println(book)
44
+
_ -> io.print("")
45
+
}
46
+
})
47
+
}
-143
src/lab66.cpp
-143
src/lab66.cpp
···
1
-
/*********************************************************
2
-
* Summary: find verses from the old testament
3
-
* appending them to file as found
4
-
*
5
-
* Author: Kieran Klukas
6
-
* Created: October 2025
7
-
*
8
-
********************************************************/
9
-
10
-
#include <iostream>
11
-
#include <cstdlib>
12
-
#include <fstream>
13
-
14
-
using namespace std;
15
-
16
-
int main(int argc, char **argv) {
17
-
18
-
ifstream OT;
19
-
ofstream OF;
20
-
string inputFilename = "OT.txt";
21
-
string outputFilename = "verses.txt";
22
-
23
-
string book;
24
-
string normalizedBook;
25
-
int chapter;
26
-
int verse;
27
-
28
-
// get path to OT.txt if provided otherwise use default path
29
-
// and then do the same for the verses.txt
30
-
if (argc >= 2) inputFilename = argv[1];
31
-
if (argc >= 3) outputFilename = argv[2];
32
-
33
-
OT.open(inputFilename);
34
-
35
-
if (!OT.is_open()) {
36
-
cout << inputFilename << ": failed to open file";
37
-
return 1;
38
-
}
39
-
40
-
cout << "Please enter the reference of the verse you would like" << endl;
41
-
42
-
cout << "the book: ";
43
-
getline(cin, book);
44
-
for (int i = 0; i < book.length(); i++)
45
-
normalizedBook += toupper(book[i]);
46
-
if (normalizedBook == "PSALMS")
47
-
normalizedBook = "PSALM";
48
-
49
-
cout << "the chapter: ";
50
-
cin >> chapter;
51
-
52
-
cout << "the verse: ";
53
-
cin >> verse;
54
-
55
-
cout << endl;
56
-
57
-
bool foundBook = false;
58
-
bool foundChapter = false;
59
-
bool foundVerse = false;
60
-
string verseString;
61
-
while (!OT.eof()) {
62
-
string input;
63
-
64
-
if (!foundBook) {
65
-
OT >> input; // THE
66
-
if (input != "THE") continue;
67
-
OT >> input; // BOOK
68
-
if (input != "BOOK") continue;
69
-
OT >> input; // OF
70
-
if (input != "OF") continue;
71
-
72
-
OT.ignore(); // skip the single space
73
-
74
-
getline(OT, input); // handle multi word books
75
-
76
-
// second check is for the book of psalms
77
-
if (input == normalizedBook || input == (normalizedBook + "S")) {
78
-
foundBook = true;
79
-
80
-
getline(OT, input); // discard empty line
81
-
continue;
82
-
}
83
-
} else {
84
-
if (!foundChapter) {
85
-
OT >> input;
86
-
if (input != "CHAPTER" && input != "PSALM") {
87
-
if (input == "THE") break;
88
-
89
-
continue;
90
-
}
91
-
92
-
OT >> input;
93
-
if (input == to_string(chapter)) {
94
-
foundChapter = true;
95
-
continue;
96
-
}
97
-
} else {
98
-
OT >> input;
99
-
100
-
if (input == "CHAPTER" || input == "PSALM") break;
101
-
102
-
if (input == to_string(verse)) {
103
-
foundVerse = true;
104
-
OT.ignore(); // ignore space
105
-
getline(OT, verseString);
106
-
break;
107
-
}
108
-
}
109
-
}
110
-
}
111
-
112
-
if (foundVerse) {
113
-
cout << verse << " " << verseString << endl;
114
-
115
-
OF.open(outputFilename, ios_base::app);
116
-
117
-
if (!OF.is_open()) {
118
-
cout << outputFilename << ": error saving file" << endl;
119
-
return 1;
120
-
}
121
-
122
-
OF << verse << " " << verseString << endl;
123
-
124
-
OF.close();
125
-
} else {
126
-
if (!foundBook) {
127
-
cout << (normalizedBook == "PSALM" ? book += "s" : book) << " does not exist in the Old Testament";
128
-
} else {
129
-
if (!foundChapter) {
130
-
cout << (normalizedBook == "PSALM" ? "Psalm " : "Chapter ") << chapter;
131
-
cout << " does not exist in " << (normalizedBook == "PSALM" ? book += "s" : book);
132
-
} else if (!foundVerse) {
133
-
cout << "Verse " << verse << " does not exist in " << book << " " << chapter;
134
-
}
135
-
}
136
-
137
-
cout << endl;
138
-
}
139
-
140
-
OT.close();
141
-
142
-
return 0;
143
-
}
test/OT.txt
OT.txt
test/OT.txt
OT.txt
+13
test/bible_search_gleam_test.gleam
+13
test/bible_search_gleam_test.gleam
-362
test/test.sh
-362
test/test.sh
···
1
-
#!/bin/bash
2
-
3
-
# Test script with configurable timeout support
4
-
# Usage: ./test.sh [timeout_seconds]
5
-
# Example: ./test.sh 5 (uses 5 second timeout)
6
-
# Default: 1 second timeout
7
-
8
-
# Colors for output
9
-
RED='\033[0;31m'
10
-
GREEN='\033[0;32m'
11
-
YELLOW='\033[1;33m'
12
-
BLUE='\033[0;34m'
13
-
NC='\033[0m' # No Color
14
-
15
-
# Test configuration
16
-
temp_file="lab66.output"
17
-
program="../build/lab66"
18
-
output_file="../build/verses.txt"
19
-
test_timeout=${1:-1}
20
-
21
-
# Test counters
22
-
total_tests=0
23
-
passed_tests=0
24
-
25
-
# Cleanup function
26
-
cleanup() {
27
-
rm -f "$temp_file" "$output_file"
28
-
}
29
-
30
-
# Error trap
31
-
trap cleanup EXIT ERR
32
-
33
-
# Function to print test results
34
-
print_result() {
35
-
local test_name="$1"
36
-
local result="$2"
37
-
local message="$3"
38
-
39
-
total_tests=$((total_tests + 1))
40
-
41
-
if [ "$result" = "PASS" ]; then
42
-
echo -e "${GREEN}[PASS]${NC} $test_name: $message"
43
-
passed_tests=$((passed_tests + 1))
44
-
elif [ "$result" = "TIMEOUT" ]; then
45
-
echo -e "${YELLOW}[TIMEOUT]${NC} $test_name: $message"
46
-
else
47
-
echo -e "${RED}[FAIL]${NC} $test_name: $message"
48
-
fi
49
-
}
50
-
51
-
# Function to print test section header
52
-
print_section() {
53
-
echo -e "\n${BLUE}=== $1 ===${NC}"
54
-
}
55
-
56
-
# Build program if needed
57
-
if [ ! -f "$program" ]; then
58
-
print_section "Building Program"
59
-
cd .. && make lab66 > /dev/null 2>&1
60
-
build_result=$?
61
-
cd test
62
-
if [ $build_result -ne 0 ]; then
63
-
print_result "Program Build" "FAIL" "Could not build $program"
64
-
exit 1
65
-
fi
66
-
print_result "Program Build" "PASS" "Program built successfully"
67
-
fi
68
-
69
-
# Test 1: Program compilation/existence
70
-
if [ ! -f "$program" ]; then
71
-
print_section "Test 1: Program Availability"
72
-
print_result "Program Existence" "FAIL" "Program $program not found"
73
-
exit 1
74
-
fi
75
-
76
-
# Test 2: Basic Bible Verse Lookup Test (Genesis 1:1)
77
-
print_section "Basic Bible Verse Lookup Test"
78
-
79
-
# Test with known valid verse
80
-
basic_input="Genesis\n1\n1"
81
-
resp=$(timeout "$test_timeout" bash -c "echo -e '$basic_input' | '$program' OT.txt '$output_file'" 2>&1)
82
-
exit_code=$?
83
-
84
-
# Print the output
85
-
if [ -n "$resp" ]; then
86
-
echo "$resp"
87
-
else
88
-
echo "(No output produced)"
89
-
fi
90
-
echo
91
-
92
-
if [ $exit_code -eq 124 ]; then
93
-
print_result "Basic Execution" "TIMEOUT" "Program timed out after ${test_timeout}s"
94
-
exit 1
95
-
elif [ $exit_code -ne 0 ]; then
96
-
print_result "Basic Execution" "FAIL" "Program exited with code $exit_code"
97
-
exit 1
98
-
else
99
-
print_result "Basic Execution" "PASS" "Program executed successfully"
100
-
fi
101
-
102
-
# Check if output contains required prompts
103
-
if [[ "$resp" == *"Please enter the reference of the verse you would like"* ]]; then
104
-
print_result "Initial Prompt" "PASS" "Program shows initial prompt"
105
-
else
106
-
print_result "Initial Prompt" "FAIL" "Program missing initial prompt"
107
-
fi
108
-
109
-
if [[ "$resp" == *"the book:"* ]]; then
110
-
print_result "Book Prompt" "PASS" "Program prompts for book"
111
-
else
112
-
print_result "Book Prompt" "FAIL" "Program missing book prompt"
113
-
fi
114
-
115
-
if [[ "$resp" == *"the chapter:"* ]]; then
116
-
print_result "Chapter Prompt" "PASS" "Program prompts for chapter"
117
-
else
118
-
print_result "Chapter Prompt" "FAIL" "Program missing chapter prompt"
119
-
fi
120
-
121
-
if [[ "$resp" == *"the verse:"* ]]; then
122
-
print_result "Verse Prompt" "PASS" "Program prompts for verse"
123
-
else
124
-
print_result "Verse Prompt" "FAIL" "Program missing verse prompt"
125
-
fi
126
-
127
-
# Check for verse output format
128
-
if [[ "$resp" == *"1 In the beginning God created the heaven and the earth"* ]]; then
129
-
print_result "Verse Format" "PASS" "Program outputs verse in correct format"
130
-
else
131
-
print_result "Verse Format" "FAIL" "Program missing or incorrect verse format"
132
-
fi
133
-
134
-
# Check if test/verses.txt file was created
135
-
if [ -f "$output_file" ]; then
136
-
verses_content=$(cat "$output_file")
137
-
if [[ "$verses_content" == *"In the beginning God created the heaven and the earth"* ]]; then
138
-
print_result "File Output" "PASS" "verses.txt created with correct content in build directory"
139
-
else
140
-
print_result "File Output" "FAIL" "verses.txt has incorrect content"
141
-
fi
142
-
else
143
-
print_result "File Output" "FAIL" "verses.txt file not created in build directory"
144
-
fi
145
-
146
-
# Function to run verse lookup test
147
-
run_verse_test() {
148
-
local test_name="$1"
149
-
local book="$2"
150
-
local chapter="$3"
151
-
local verse="$4"
152
-
local expected_pattern="$5"
153
-
local should_create_file="$6"
154
-
155
-
# Clean up previous test
156
-
rm -f "$output_file"
157
-
158
-
input="$book\n$chapter\n$verse"
159
-
output=$(timeout "$test_timeout" bash -c "echo -e '$input' | '$program' OT.txt '$output_file'" 2>&1)
160
-
exit_code=$?
161
-
162
-
if [ $exit_code -eq 124 ]; then
163
-
print_result "$test_name" "TIMEOUT" "Program timed out after ${test_timeout}s"
164
-
return
165
-
elif [ $exit_code -ne 0 ]; then
166
-
print_result "$test_name" "FAIL" "Program crashed (exit code $exit_code)"
167
-
return
168
-
fi
169
-
170
-
# Check if expected pattern is found in output
171
-
pattern_found=false
172
-
if [[ "$output" == *"$expected_pattern"* ]]; then
173
-
pattern_found=true
174
-
fi
175
-
176
-
# For tests expecting specific output, pattern must be found
177
-
if [ -n "$expected_pattern" ] && [ "$pattern_found" = "false" ]; then
178
-
print_result "$test_name" "FAIL" "Expected '$expected_pattern' not found in output"
179
-
return
180
-
fi
181
-
182
-
# Check file creation expectations
183
-
if [ "$should_create_file" = "true" ]; then
184
-
if [ -f "$output_file" ] && [ "$pattern_found" = "true" ]; then
185
-
print_result "$test_name" "PASS" "Expected output found and file created"
186
-
elif [ ! -f "$output_file" ]; then
187
-
print_result "$test_name" "FAIL" "Expected file verses.txt not created in build directory"
188
-
else
189
-
print_result "$test_name" "FAIL" "File created but expected output not found"
190
-
fi
191
-
else
192
-
if [ ! -f "$output_file" ] && [ "$pattern_found" = "true" ]; then
193
-
print_result "$test_name" "PASS" "Expected error output and no file created"
194
-
elif [ -f "$output_file" ]; then
195
-
print_result "$test_name" "FAIL" "verses.txt file should not be created for error cases"
196
-
else
197
-
print_result "$test_name" "FAIL" "Expected error message not found"
198
-
fi
199
-
fi
200
-
}
201
-
202
-
# Valid Verse Tests
203
-
print_section "Valid Verse Tests"
204
-
205
-
run_verse_test "Exodus 20:3" "Exodus" "20" "3" "3 Thou shalt have no other gods before me" true
206
-
run_verse_test "Psalm 23:1" "Psalm" "23" "1" "1 The LORD [is] my shepherd; I shall not want." true
207
-
208
-
# Error Case Tests
209
-
print_section "Error Case Tests"
210
-
211
-
run_verse_test "Invalid Book" "Matthew" "1" "1" "Matthew does not exist in the Old Testament" false
212
-
run_verse_test "Invalid Chapter" "Esther" "18" "3" "Chapter 18 does not exist in Esther" false
213
-
run_verse_test "Invalid Verse" "Psalm" "117" "5" "Verse 5 does not exist in Psalm 117" false
214
-
215
-
# Adversarial Testing Section
216
-
print_section "Adversarial Tests"
217
-
218
-
# Test edge cases
219
-
run_verse_test "Empty Book Name" "" "1" "1" "Please enter the reference" false
220
-
run_verse_test "Non-numeric Chapter" "Genesis" "abc" "1" "Please enter the reference" false
221
-
run_verse_test "Non-numeric Verse" "Genesis" "1" "xyz" "Please enter the reference" false
222
-
run_verse_test "Zero Chapter" "Genesis" "0" "1" "Please enter the reference" false
223
-
run_verse_test "Zero Verse" "Genesis" "1" "0" "Please enter the reference" false
224
-
run_verse_test "Negative Chapter" "Genesis" "-1" "1" "Please enter the reference" false
225
-
run_verse_test "Negative Verse" "Genesis" "1" "-1" "Please enter the reference" false
226
-
run_verse_test "Very Large Chapter" "Genesis" "999999" "1" "Please enter the reference" false
227
-
run_verse_test "Very Large Verse" "Genesis" "1" "999999" "Please enter the reference" false
228
-
229
-
# Test case sensitivity
230
-
run_verse_test "Lowercase Book" "genesis" "1" "1" "1 In the beginning God created the heaven and the earth." true
231
-
run_verse_test "Mixed Case Book" "GEnesis" "1" "1" "1 In the beginning God created the heaven and the earth." true
232
-
233
-
# Test two-word books
234
-
run_verse_test "First Samuel" "First Samuel" "1" "1" "1 Now there was a certain man of Ramathaim-zophim, of mount Ephraim, and his name [was] Elkanah, the son of Jeroham, the son of Elihu, the son of Tohu, the son of Zuph, an Ephrathite:" true
235
-
run_verse_test "Second Kings" "Second Kings" "1" "1" "1 Then Moab rebelled against Israel after the death of Ahab" true
236
-
237
-
# Appending Tests
238
-
print_section "Appending & File Path Tests"
239
-
240
-
# Function to run appending test
241
-
run_appending_test() {
242
-
local test_name="$1"
243
-
244
-
# Clean up previous test
245
-
rm -f "$output_file"
246
-
247
-
# First verse lookup
248
-
input1="Genesis\n1\n1"
249
-
output1=$(timeout "$test_timeout" bash -c "echo -e '$input1' | '$program' OT.txt '$output_file'" 2>&1)
250
-
exit_code1=$?
251
-
252
-
if [ $exit_code1 -ne 0 ]; then
253
-
print_result "$test_name - First Lookup" "FAIL" "First verse lookup failed"
254
-
return
255
-
fi
256
-
257
-
# Check first verse was written
258
-
if [ ! -f "$output_file" ]; then
259
-
print_result "$test_name - First File" "FAIL" "First verse file not created"
260
-
return
261
-
fi
262
-
263
-
first_content=$(cat "$output_file")
264
-
265
-
# Second verse lookup
266
-
input2="Genesis\n1\n2"
267
-
output2=$(timeout "$test_timeout" bash -c "echo -e '$input2' | '$program' OT.txt '$output_file'" 2>&1)
268
-
exit_code2=$?
269
-
270
-
if [ $exit_code2 -ne 0 ]; then
271
-
print_result "$test_name - Second Lookup" "FAIL" "Second verse lookup failed"
272
-
return
273
-
fi
274
-
275
-
# Check if file still exists and has content
276
-
if [ ! -f "$output_file" ]; then
277
-
print_result "$test_name - Second File" "FAIL" "File disappeared after second lookup"
278
-
return
279
-
fi
280
-
281
-
second_content=$(cat "$output_file")
282
-
283
-
# Check if both verses are in the file (appending behavior)
284
-
if [[ "$second_content" == *"1 In the beginning God created the heaven and the earth"* ]] && [[ "$second_content" == *"2 And the earth was without form, and void"* ]]; then
285
-
print_result "$test_name" "PASS" "Both verses found in file (appending works)"
286
-
elif [[ "$second_content" == *"2 And the earth was without form, and void"* ]] && [[ "$second_content" != *"1 In the beginning God created the heaven and the earth"* ]]; then
287
-
print_result "$test_name" "FAIL" "Only second verse found (overwriting instead of appending)"
288
-
else
289
-
print_result "$test_name" "FAIL" "Unexpected file content after second lookup"
290
-
fi
291
-
}
292
-
293
-
run_appending_test "Multiple Verse Appending"
294
-
295
-
# Function to run file path test
296
-
run_file_path_test() {
297
-
local test_name="$1"
298
-
local file_path="$2"
299
-
local expected_pattern="$3"
300
-
local should_succeed="$4"
301
-
302
-
# Clean up previous test
303
-
rm -f "$output_file"
304
-
305
-
# Provide verse lookup input for file path tests
306
-
input="Genesis\n1\n1"
307
-
308
-
if [ -n "$file_path" ]; then
309
-
output=$(timeout "$test_timeout" bash -c "echo -e '$input' | '$program' '$file_path' '$output_file'" 2>&1)
310
-
else
311
-
output=$(timeout "$test_timeout" bash -c "echo -e '$input' | '$program' OT.txt '$output_file'" 2>&1)
312
-
fi
313
-
exit_code=$?
314
-
315
-
if [ $exit_code -eq 124 ]; then
316
-
print_result "$test_name" "TIMEOUT" "Program timed out after ${test_timeout}s"
317
-
return
318
-
fi
319
-
320
-
if [ "$should_succeed" = "true" ]; then
321
-
if [ $exit_code -eq 0 ]; then
322
-
print_result "$test_name" "PASS" "Program accepted file path successfully"
323
-
else
324
-
print_result "$test_name" "FAIL" "Program failed with exit code $exit_code: $output"
325
-
fi
326
-
else
327
-
if [ $exit_code -ne 0 ] && [[ "$output" == *"$expected_pattern"* ]]; then
328
-
print_result "$test_name" "PASS" "Program correctly rejected invalid file path"
329
-
elif [ $exit_code -eq 0 ]; then
330
-
print_result "$test_name" "FAIL" "Program should have failed with invalid file path"
331
-
else
332
-
print_result "$test_name" "FAIL" "Expected error message '$expected_pattern' not found: $output"
333
-
fi
334
-
fi
335
-
}
336
-
337
-
# Test with existing file (absolute path)
338
-
run_file_path_test "Existing File (Absolute)" "/Users/kierank/code/school/lab-6/test/OT.txt" "" true
339
-
340
-
# Test with existing file (relative path)
341
-
run_file_path_test "Existing File (Relative)" "OT.txt" "" true
342
-
343
-
# Test with non-existing file
344
-
run_file_path_test "Non-existing File" "nonexistent.txt" "failed to open file" false
345
-
346
-
# Test with invalid path
347
-
run_file_path_test "Invalid Path" "/invalid/path/file.txt" "failed to open file" false
348
-
349
-
# Test with empty path
350
-
run_file_path_test "Empty Path" "" "" true
351
-
352
-
# Test summary
353
-
print_section "Test Summary"
354
-
echo -e "${BLUE}Tests passed: $passed_tests/$total_tests${NC}"
355
-
356
-
if [ $passed_tests -eq $total_tests ]; then
357
-
echo -e "${GREEN}All tests passed!${NC}"
358
-
exit 0
359
-
else
360
-
echo -e "${RED}Some tests failed!${NC}"
361
-
exit 1
362
-
fi