diff --git a/src/kwio.sh b/src/kwio.sh index 42e6bb996..fb782b240 100644 --- a/src/kwio.sh +++ b/src/kwio.sh @@ -172,3 +172,88 @@ function ask_with_default() printf '%s\n' "$response" } + +# Load text from a file into a dictionary. The file that will be read must have +# a key before a text body to name that particular text as part of the key, for +# example: +# +# [KEY]: +# text +# +# [KEY] must be non-empty, alphanumeric and between square brackets followed by +# a colon. The global array string_file can then be queried by key as in +# ${string_file[]} to obtain the string. should be named according +# to its respective module for compatibility. That is, if we have modules A and +# B, name A's keys as [KEY_A] and B's keys as [KEY_B]. This makes it so the +# module's keys are compatible with each other +# +# @text_file_to_be_loaded_path The full path of the text file to be loaded as +# the first argument. +# +# Return: +# SUCCESS : In case of success. +# EKEYREJECTED : If an invalid key is found, prints the line with a bad key. +# ENOKEY : If a key is not found. +# ENOENT : If @text_file_to_be_loaded_path is invalid, or is not a text file. +# ENODATA : If the file given in @text_file_to_be_loaded_path is empty. +function load_module_text() +{ + local text_file_to_be_loaded_path="$1" + local key='' + local line_counter=0 + local error=0 # SUCCESS + local key_set=0 + local first_line=0 + + # Associative array to read strings from files + unset module_text_dictionary + declare -gA module_text_dictionary + + if [[ ! -f "$text_file_to_be_loaded_path" ]]; then + complain "[ERROR]:$text_file_to_be_loaded_path: Does not exist or is not a text file." + return 2 # ENOENT + fi + + if [[ ! -s "$text_file_to_be_loaded_path" ]]; then + complain "[ERROR]:$text_file_to_be_loaded_path: File is empty." + return 61 # ENODATA + fi + + while read -r line; do + ((line_counter++)) + # Match [VALUE]: + if [[ "$line" =~ ^\[(.*)\]:$ ]]; then + key='' + # Match to check if VALUE is composed of alphanumeric and underscores only + [[ "${BASH_REMATCH[1]}" =~ (^[A-Za-z0-9_][A-Za-z0-9_]*$) ]] && key="${BASH_REMATCH[1]}" + if [[ -z "$key" ]]; then + error=129 # EKEYREJECTED + complain "[ERROR]:$text_file_to_be_loaded_path:$line_counter: Keys should be alphanum chars." + continue + fi + + if [[ -n "${module_text_dictionary[$key]}" ]]; then + warning "[WARNING]:$text_file_to_be_loaded_path:$line_counter: Overwriting '$key' key." + fi + + key_set=1 + first_line=1 + module_text_dictionary["$key"]='' + # If we are inside a text block, collect the current line + elif [[ -n "$key" ]]; then + if [[ "$first_line" -eq 1 ]]; then + first_line=0 + else + module_text_dictionary["$key"]+=$'\n' + fi + module_text_dictionary["$key"]+="$line" + fi + done < "$text_file_to_be_loaded_path" + + if [[ "$key_set" -eq 0 ]]; then + error=126 # ENOKEY + complain "[ERROR]:$text_file_to_be_loaded_path: No key found." + fi + + return "$error" +} diff --git a/tests/kwio_test.sh b/tests/kwio_test.sh index 42e6c73d6..75674bbb0 100755 --- a/tests/kwio_test.sh +++ b/tests/kwio_test.sh @@ -10,6 +10,8 @@ include './src/kwlib.sh' # the function will return before the background commands finish. declare -A configurations +declare -g load_module_text_path="$PWD/tests/samples/load_module_text_test_samples/" + sound_file="$PWD/tests/.kwio_test_aux/sound.file" visual_file="$PWD/tests/.kwio_test_aux/visual.file" @@ -237,4 +239,84 @@ function test_ask_yN() assert_equals_helper "$assert_equals_message" "$LINENO" '0' "$output" } +function test_load_module_text_good_files() +{ + local multiple_line_str + + load_module_text "$load_module_text_path/file_correct" + assertEquals 'Should work without any errors.' 0 "$?" + + assertEquals 'Key1' 'Hello, there! How are you? I hope you are enjoying reading this test suit!' "${module_text_dictionary[key1]}" + assertEquals 'Key2' 'Hey, you still there? []' "${module_text_dictionary[key2]}" + + multiple_line_str=$'This should work with multiple lines.\nLine 1\nLine 2\nLine 3\nLine 4\nLine 5' + assertEquals 'Key3' "$multiple_line_str" "${module_text_dictionary[key3]}" + + assertEquals 'Key4' 'done.' "${module_text_dictionary[key4]}" + assertEquals 'Key5' '' "${module_text_dictionary[key5]}" + + multiple_line_str=$'\n\n\n\n\nThe one above should have an empty value.\n' + assertEquals 'Key6' "$multiple_line_str" "${module_text_dictionary[key6]}" + + multiple_line_str=$'\nThis value should be ok\n' + assertEquals 'Key7' "$multiple_line_str" "${module_text_dictionary[key7]}" +} + +function test_load_module_text_bad_keys() +{ + local expected + local output + + declare -a expected_sequence=( + "[ERROR]:$load_module_text_path/file_wrong_key:7: Keys should be alphanum chars." + "[ERROR]:$load_module_text_path/file_wrong_key:10: Keys should be alphanum chars." + "[ERROR]:$load_module_text_path/file_wrong_key:13: Keys should be alphanum chars." + "[ERROR]:$load_module_text_path/file_wrong_key:16: Keys should be alphanum chars." + "[ERROR]:$load_module_text_path/file_wrong_key:19: Keys should be alphanum chars." + ) + + output=$(load_module_text "$load_module_text_path/file_wrong_key") + assertEquals 'This file has invalid keys, this should return multiple errors.' 129 "$?" + + compare_command_sequence 'expected_sequence' "$output" "$LINENO" +} + +function test_load_module_text_invalid_files() +{ + local expected + local output + + expected="[ERROR]:$load_module_text_path/file_without_key: No key found." + output=$(load_module_text "$load_module_text_path/file_without_key") + assertEquals "[$LINENO]: This file has no keys, this should return an error." 126 "$?" + assertEquals "[$LINENO]: The ERROR message is not consistent with the error code or is incomplete." "$expected" "$output" + + expected="[ERROR]:$load_module_text_path/file_empty: File is empty." + output=$(load_module_text "$load_module_text_path/file_empty") + assertEquals "[$LINENO]: This file is empty, this should return an error." 61 "$?" + assertEquals "[$LINENO]: The ERROR message is not consistent with the error code or is incomplete." "$expected" "$output" +} + +function test_load_module_text_no_files() +{ + local expected + local output + + expected="[ERROR]:$load_module_text_path/file_does_not_exist_(do not create): Does not exist or is not a text file." + output=$(load_module_text "$load_module_text_path/file_does_not_exist_(do not create)") + assertEquals "[$LINENO]: This file does not exist, this should return an error." 2 "$?" + assertEquals "[$LINENO]: The ERROR message is not consistent with the error code or is incomplete." "$expected" "$output" +} + +function test_load_module_text_repeated_keys() +{ + local expected + local output + + expected="[WARNING]:$load_module_text_path/file_repeated_keys:9: Overwriting 'Sagan' key." + output=$(load_module_text "$load_module_text_path/file_repeated_keys") + assertEquals "[$LINENO]: Although we received warnings, the function should exit with SUCCESS" 0 "$?" + assertEquals "[$LINENO]: The ERROR message is not consistent with the error code or is incomplete." "$expected" "$output" +} + invoke_shunit diff --git a/tests/samples/load_module_text_test_samples/file_correct b/tests/samples/load_module_text_test_samples/file_correct new file mode 100644 index 000000000..a14874d2d --- /dev/null +++ b/tests/samples/load_module_text_test_samples/file_correct @@ -0,0 +1,26 @@ +[key1]: +Hello, there! How are you? I hope you are enjoying reading this test suit! +[key2]: +Hey, you still there? [] +[key3]: +This should work with multiple lines. +Line 1 +Line 2 +Line 3 +Line 4 +Line 5 +[key4]: +done. +[key5]: +[key6]: + + + + + +The one above should have an empty value. + +[key7]: + +This value should be ok + diff --git a/tests/samples/load_module_text_test_samples/file_empty b/tests/samples/load_module_text_test_samples/file_empty new file mode 100644 index 000000000..e69de29bb diff --git a/tests/samples/load_module_text_test_samples/file_repeated_keys b/tests/samples/load_module_text_test_samples/file_repeated_keys new file mode 100644 index 000000000..429fa6982 --- /dev/null +++ b/tests/samples/load_module_text_test_samples/file_repeated_keys @@ -0,0 +1,11 @@ +[Sagan]: +If you wish +to +make an +apple pie +from scratch +you must first invent the Universe. + +[Sagan]: +Extraordinary claims require +extraordinary evidence. diff --git a/tests/samples/load_module_text_test_samples/file_without_key b/tests/samples/load_module_text_test_samples/file_without_key new file mode 100644 index 000000000..74d09a174 --- /dev/null +++ b/tests/samples/load_module_text_test_samples/file_without_key @@ -0,0 +1 @@ +[this]: This file has text, but does not have a key. diff --git a/tests/samples/load_module_text_test_samples/file_wrong_key b/tests/samples/load_module_text_test_samples/file_wrong_key new file mode 100644 index 000000000..e160150b7 --- /dev/null +++ b/tests/samples/load_module_text_test_samples/file_wrong_key @@ -0,0 +1,20 @@ +[key]: +This key is fine. + +[k1y3]: +This is also fine. + +[~???????????????\\\\\\]: +This should give an error. + +[So, how are you]: +This should not work. + +[]]: +This also should not work. + +[[]: +Neither this. + +[[]]: +Neither this. \ No newline at end of file