Expand and tidy tests

* Update expectation style to match new Mocha requirements
* Clean up broken Startupper tests
* Flesh out various test stubs
* Clean up formatting and other odds and ends
This commit is contained in:
Eric B. Budd 2021-10-26 09:44:29 -05:00 committed by Eric Budd
parent 1c124349eb
commit 93b64d33a9
3 changed files with 149 additions and 94 deletions

View File

@ -19,7 +19,7 @@ Iris is strictly text-based, requiring no GUI or web servers.
## Installation
At its core, Iris is simply a single, executable Ruby script. It has been tested and is known to work with Ruby 2.3.5. No extra gems or libraries are required.
At its core, Iris is simply a single, executable Ruby script. It has been tested and is known to work with Ruby 2.3.5 and above. No extra gems or libraries are required.
Copy or symlink `iris.rb` somewhere the whole server can use it; `/usr/local/bin` is a good candidate:
@ -616,6 +616,12 @@ gem install --user-install minitest
gem install --user-install mocha
```
To run the tests:
```bash
ruby tests/iris_test.rb
```
## Technical Bits
* [Dependencies](#dependencies)

View File

@ -1037,7 +1037,7 @@ class Startupper
NONFILE_OPTIONS = %w[-h --help -v --version]
def initialize(args)
perform_file_checks unless NONFILE_OPTIONS.include?(args)
Startupper.perform_file_checks unless NONFILE_OPTIONS.include?(args)
load_corpus(args)
@ -1052,8 +1052,7 @@ class Startupper
end
end
def perform_file_checks
raise 'Should not try to perform file checks in test mode!' if $test_corpus_file
def self.perform_file_checks
unless File.exists?(Config::MESSAGE_FILE)
Display.say "You don't have a message file at #{Config::MESSAGE_FILE}."
response = Readline.readline 'Would you like me to create it for you? (y/n) ', true
@ -1082,8 +1081,6 @@ class Startupper
end
def load_corpus(args)
$test_corpus_file = nil
if (args & %w{-f --test-file}).any?
filename_idx = (args.index('-f') || args.index('--test-file')) + 1
filename = args[filename_idx]

View File

@ -1,37 +1,37 @@
require 'minitest/autorun'
require 'mocha/mini_test'
require 'mocha/minitest'
# This allows the test to pretend that user "jerryberry" is logged in.
ENV['USER'] = 'jerryberry'
# Set this before loading the code so that the Config constants load correctly.
$test_corpus_file = "./tests/iris.messages.json"
# Setting this before loading the main code file so that the Config contants
# load correctly. This will allows the test to pretend that user "jerryberry"
# is logged in.
ENV.stubs(:[]).returns('jerryberry')
require './iris.rb'
describe Config do
it 'has the Iris semantic version number' do
Config::VERSION.must_match /^\d\.\d\.\d+$/
_(Config::VERSION).must_match /^\d\.\d\.\d+$/
end
it 'has the message file location' do
Config::MESSAGE_FILE.must_match /\/\.iris\.messages$/
_(Config::MESSAGE_FILE).must_match /\/\.iris\.messages$/
end
it 'has the readline history file location' do
Config::HISTORY_FILE.must_match /\/\.iris\.history$/
_(Config::HISTORY_FILE).must_match /\/\.iris\.history$/
end
it 'has the username' do
Config::USER.must_equal 'jerryberry'
_(Config::USER).must_equal 'jerryberry'
end
it 'has a hostname' do
Config::HOSTNAME.wont_be_nil
_(Config::HOSTNAME).wont_be_nil
end
it 'has the author' do
Config::AUTHOR.must_equal "#{Config::USER}@#{Config::HOSTNAME}"
_(Config::AUTHOR).must_equal "#{Config::USER}@#{Config::HOSTNAME}"
end
describe '.find_files' do
@ -43,17 +43,21 @@ describe Config do
it 'returns a list of Iris message files' do
Config.stubs(:`).returns("foo\nbar\n")
Config.find_files.must_equal ['foo', 'bar']
_(Config.find_files).must_equal ['foo', 'bar']
end
it 'returns an empty array if no Iris message files are found' do
Config.stubs(:`).returns('')
Config.find_files.must_equal []
_(Config.find_files).must_equal []
end
end
end
describe Corpus do
before do
Corpus.load
end
describe '.load' do
it 'loads all the message files'
it 'sets the corpus class variable'
@ -62,10 +66,6 @@ describe Corpus do
it 'creates parent-hash-to-child-indexes index'
end
describe '.all' do
it 'returns the entire corpus of messages'
end
describe '.topics' do
it 'returns all the messages which are topics'
it 'does not return reply messages'
@ -78,28 +78,26 @@ describe Corpus do
describe '.find_message_by_hash' do
it 'returns nil if a nil is passed in' do
Corpus.find_message_by_hash(nil).must_equal nil
assert_nil Corpus.find_message_by_hash(nil)
end
it 'returns nil if the hash is not found in the corpus' do
# Corpus.load
Corpus.find_message_by_hash('NoofMcGoof').must_equal nil
assert_nil Corpus.find_message_by_hash('NoofMcGoof')
end
it 'returns the message associated with the hash if it is found' do
Corpus.load
Corpus.find_message_by_hash("gpY2WW/jGcH+BODgySCwDANJlIM=").must_equal "Test"
message = Corpus.find_message_by_hash("gpY2WW/jGcH+BODgySCwDANJlIM=\n")
_(message.message).must_equal "Test"
end
end
describe '.find_all_by_parent_hash' do
it 'returns an empty array if a nil is passed in' do
Corpus.find_all_by_parent_hash(nil).must_equal []
_(Corpus.find_all_by_parent_hash(nil)).must_equal []
end
it 'returns an empty array if the hash is not a parent of any other messages' do
skip
Corpus.find_all_by_parent_hash('GoofMcDoof').must_equal []
_(Corpus.find_all_by_parent_hash('GoofMcDoof')).must_equal []
end
it 'returns an empty array if the hash is not found in the corpus'
@ -108,7 +106,7 @@ describe Corpus do
describe '.find_topic_by_id' do
it 'returns nil if a nil is passed in' do
Corpus.find_topic_by_id(nil).must_equal nil
assert_nil Corpus.find_topic_by_id(nil)
end
describe 'when an index string is passed in' do
@ -119,7 +117,7 @@ describe Corpus do
describe '.find_topic_by_hash' do
it 'returns nil if a nil is passed in' do
Corpus.find_topic_by_hash(nil).must_equal nil
assert_nil Corpus.find_topic_by_hash(nil)
end
describe 'when a hash string is passed in' do
@ -135,10 +133,6 @@ describe IrisFile do
end
describe Message do
it 'has a file version' do
Message::FILE_FORMAT.must_match /v\d/
end
it 'exposes all its data attributes for reading'
it 'is #valid? if it has no errors'
@ -163,33 +157,44 @@ end
describe Display do
it 'has a setting for a minimum width of 80' do
Display::MIN_WIDTH.must_equal 80
_(Display::MIN_WIDTH).must_equal 80
end
it 'has a setting for the calculated screen width'
it 'has a setting for a minimum height of 8' do
_(Display::MIN_HEIGHT).must_equal 8
end
it 'has settings for the calculated screen geometry' do
_(Display::WIDTH).wont_equal nil
_(Display::HEIGHT).wont_equal nil
end
describe '#topic_index_width' do
it 'returns the a minimun length of 2' do
Corpus.stubs(:topics).returns(%w{a})
Display.topic_index_width.must_equal 2
_(Display.topic_index_width).must_equal 2
end
it 'returns the length in characters of the longest topic index' do
Corpus.stubs(:topics).returns((0..1000).to_a)
Display.topic_index_width.must_equal 4
_(Display.topic_index_width).must_equal 4
end
it 'returns 2 if there are no topics' do
Corpus.stubs(:topics).returns([])
Display.topic_index_width.must_equal 2
_(Display.topic_index_width).must_equal 2
end
end
describe '#topic_author_width' do
it 'returns the length in characters of the longest author\'s name'
it 'returns the length in characters of the longest author\'s name' do
Corpus.stubs(:authors).returns(['jerryberry@ctrl-c.club'])
_(Display.topic_author_width).must_equal 22
end
it 'returns 1 if there are no topics' do
Corpus.stubs(:topics).returns([])
Display.topic_author_width.must_equal 1
Corpus.stubs(:authors).returns([])
_(Display.topic_author_width).must_equal 1
end
end
@ -254,46 +259,6 @@ describe Startupper do
File.stubs(:stat).with(read_file_path).returns(data_file_stat)
Interface.stubs(:start)
Display.stubs(:say)
end
it 'offers to create a message file if the user doesn\'t have one' do
File.stubs(:exists?).with(message_file_path).returns(false)
Readline.expects(:readline).with('Would you like me to create it for you? (y/n) ', true).returns('y')
IrisFile.expects(:create_message_file)
Startupper.new([])
end
it 'creates a read file if the user doesn\'t have one' do
File.stubs(:exists?).with(read_file_path).returns(false)
IrisFile.expects(:create_read_file)
Startupper.new([])
end
it 'warns the user if the message file permissions are wrong' do
skip
File.expects(:stat).with(message_file_path).returns(bad_file_stat)
Display.expects(:say).with('Your message file has incorrect permissions! Should be "-rw-r--r--".')
Startupper.new([])
end
it 'warns the user if the read file permissions are wrong' do
skip
File.stubs(:stat).with(read_file_path).returns(bad_file_stat)
Display.expects(:say).with('Your read file has incorrect permissions! Should be "-rw-r--r--".')
Startupper.new([])
end
it 'warns the user if the script file permissions are wrong' do
skip
File.expects(:stat).with(Config::IRIS_SCRIPT).returns(bad_file_stat)
Display.expects(:say).with('The Iris file has incorrect permissions! Should be "-rwxr-xr-x".')
Startupper.new([])
end
it 'starts the Interface if no command-line arguments are provided' do
@ -315,11 +280,67 @@ describe Startupper do
CLI.expects(:start).with(['-h'])
Startupper.new(['-h'])
end
it 'offers to create a message file if the user doesn\'t have one' do
File.stubs(:exists?).with(message_file_path).returns(false)
Display.stubs(:say)
Readline.expects(:readline).with('Would you like me to create it for you? (y/n) ', true).returns('y')
IrisFile.expects(:create_message_file)
Startupper.new([])
end
it 'creates a read file if the user doesn\'t have one' do
File.stubs(:exists?).with(read_file_path).returns(false)
IrisFile.expects(:create_read_file)
Startupper.new([])
end
it 'warns the user if the message file permissions are wrong' do
File.expects(:stat).with(message_file_path).returns(bad_file_stat)
Display.stubs(:say)
message_lines = [
"Your message file has incorrect permissions! Should be \"-rw-r--r--\".",
"You can change this from the command line with:",
" chmod 644 jerryberry/.iris.messages",
"Leaving your file with incorrect permissions could allow unauthorized edits!"
]
Display.expects(:say).with(message_lines)
Startupper.new([])
end
it 'warns the user if the read file permissions are wrong' do
File.stubs(:stat).with(read_file_path).returns(bad_file_stat)
Display.stubs(:say)
message_lines = [
"Your read file has incorrect permissions! Should be \"-rw-r--r--\".",
"You can change this from the command line with:",
" chmod 644 jerryberry/.iris.read"
]
Display.expects(:say).with(message_lines)
Startupper.new([])
end
it 'warns the user if the script file permissions are wrong' do
File.expects(:stat).with(Config::IRIS_SCRIPT).returns(bad_file_stat)
Display.stubs(:say)
message_lines = [
"Your Iris file has incorrect permissions! Should be \"-rwxr-xr-x\".",
"You can change this from the command line with:",
" chmod 755 doots", "If this file has the wrong permissions the program may be tampered with!"
]
Display.expects(:say).with(message_lines)
Startupper.new([])
end
end
end
describe 'String#colorize' do
let(:color_string) {
let(:color_strings) {
"
RED {r normal}\t{ri intense}\t{ru underline}\t{riu intense underline}
{rv reverse}\t{riv intense}\t{ruv underline}\t{riuv intense underline}
@ -335,28 +356,59 @@ describe 'String#colorize' do
{cv reverse}\t{civ intense}\t{cuv underline}\t{ciuv intense underline}
WHITE {w normal}\t{wi intense}\t{wu underline}\t{wiu intense underline}
{wv reverse}\t{wiv intense}\t{wuv underline}\t{wiuv intense underline}
"
".split("\n")[1..-2]
}
it 'produces the expected output' do
skip
# color_string.split("\n")[1].colorize.must_equal "\n RED \e[31mnormal\e[0m\t\e[1;31mintense\e[0m\t\e[31;4munderline\e[0m\t\e[1;31;4mintense underline\e[0m\n \e[31;7mreverse\e[0m\t\e[1;31;7mintense\e[0m\t\e[31;4;7munderline\e[0m\t\e[1;31;4;7mintense underline\e[0m\n GREEN \e[32mnormal\e[0m\t\e[1;32mintense\e[0m\t\e[32;4munderline\e[0m\t\e[1;32;4mintense underline\e[0m\n \e[32;7mreverse\e[0m\t\e[1;32;7mintense\e[0m\t\e[32;4;7munderline\e[0m\t\e[1;32;4;7mintense underline\e[0m\n YELLOW \e[33mnormal\e[0m\t\e[1;33mintense\e[0m\t\e[33;4munderline\e[0m\t\e[1;33;4mintense underline\e[0m\n \e[33;7mreverse\e[0m\t\e[1;33;7mintense\e[0m\t\e[33;4;7munderline\e[0m\t\e[1;33;4;7mintense underline\e[0m\n BLUE \e[34mnormal\e[0m\t\e[1;34mintense\e[0m\t\e[34;4munderline\e[0m\t\e[1;34;4mintense underline\e[0m\n \e[34;7mreverse\e[0m\t\e[1;34;7mintense\e[0m\t\e[34;4;7munderline\e[0m\t\e[1;34;4;7mintense underline\e[0m\n MAGENTA \e[35mnormal\e[0m\t\e[1;35mintense\e[0m\t\e[35;4munderline\e[0m\t\e[1;35;4mintense underline\e[0m\n \e[35;7mreverse\e[0m\t\e[1;35;7mintense\e[0m\t\e[35;4;7munderline\e[0m\t\e[1;35;4;7mintense underline\e[0m\n CYAN \e[36mnormal\e[0m\t\e[1;36mintense\e[0m\t\e[36;4munderline\e[0m\t\e[1;36;4mintense underline\e[0m\n \e[36;7mreverse\e[0m\t\e[1;36;7mintense\e[0m\t\e[36;4;7munderline\e[0m\t\e[1;36;4;7mintense underline\e[0m\n WHITE \e[37mnormal\e[0m\t\e[1;37mintense\e[0m\t\e[37;4munderline\e[0m\t\e[1;37;4mintense underline\e[0m\n \e[37;7mreverse\e[0m\t\e[1;37;7mintense\e[0m\t\e[37;4;7munderline\e[0m\t\e[1;37;4;7mintense underline\e[0m\n \e[0m"
color_string.split("\n")[1].colorize.must_equal " RED \e[31mnormal\e[0m\t\e[1;31mintense\e[0m\t\e[31;4munderline\e[0m\t\e[1;31;4mintense underline\e[0m\e[0m"
lead = "\e[0m\e[0m\e[0m\e[0m\e[0m\e[0m\e[0m\e[0m "
lines = [
"RED \e[31mnormal\e[0m\t\e[1;31mintense\e[0m\t\e[31;4munderline\e[0m\t\e[1;31;4mintense underline\e[0m\e[0m\e[0m\e[0m\e[0m\e[0m\e[0m\e[0m\e[0m\e[0m",
" \e[31;7mreverse\e[0m\t\e[1;31;7mintense\e[0m\t\e[31;4;7munderline\e[0m\t\e[1;31;4;7mintense underline\e[0m\e[0m\e[0m\e[0m\e[0m\e[0m\e[0m\e[0m\e[0m\e[0m",
"GREEN \e[32mnormal\e[0m\t\e[1;32mintense\e[0m\t\e[32;4munderline\e[0m\t\e[1;32;4mintense underline\e[0m\e[0m\e[0m\e[0m\e[0m\e[0m\e[0m\e[0m\e[0m\e[0m",
" \e[32;7mreverse\e[0m\t\e[1;32;7mintense\e[0m\t\e[32;4;7munderline\e[0m\t\e[1;32;4;7mintense underline\e[0m\e[0m\e[0m\e[0m\e[0m\e[0m\e[0m\e[0m\e[0m\e[0m",
"YELLOW \e[33mnormal\e[0m\t\e[1;33mintense\e[0m\t\e[33;4munderline\e[0m\t\e[1;33;4mintense underline\e[0m\e[0m\e[0m\e[0m\e[0m\e[0m\e[0m\e[0m\e[0m\e[0m",
" \e[33;7mreverse\e[0m\t\e[1;33;7mintense\e[0m\t\e[33;4;7munderline\e[0m\t\e[1;33;4;7mintense underline\e[0m\e[0m\e[0m\e[0m\e[0m\e[0m\e[0m\e[0m\e[0m\e[0m",
"BLUE \e[34mnormal\e[0m\t\e[1;34mintense\e[0m\t\e[34;4munderline\e[0m\t\e[1;34;4mintense underline\e[0m\e[0m\e[0m\e[0m\e[0m\e[0m\e[0m\e[0m\e[0m\e[0m",
" \e[34;7mreverse\e[0m\t\e[1;34;7mintense\e[0m\t\e[34;4;7munderline\e[0m\t\e[1;34;4;7mintense underline\e[0m\e[0m\e[0m\e[0m\e[0m\e[0m\e[0m\e[0m\e[0m\e[0m",
"MAGENTA \e[35mnormal\e[0m\t\e[1;35mintense\e[0m\t\e[35;4munderline\e[0m\t\e[1;35;4mintense underline\e[0m\e[0m\e[0m\e[0m\e[0m\e[0m\e[0m\e[0m\e[0m\e[0m",
" \e[35;7mreverse\e[0m\t\e[1;35;7mintense\e[0m\t\e[35;4;7munderline\e[0m\t\e[1;35;4;7mintense underline\e[0m\e[0m\e[0m\e[0m\e[0m\e[0m\e[0m\e[0m\e[0m\e[0m",
"CYAN \e[36mnormal\e[0m\t\e[1;36mintense\e[0m\t\e[36;4munderline\e[0m\t\e[1;36;4mintense underline\e[0m\e[0m\e[0m\e[0m\e[0m\e[0m\e[0m\e[0m\e[0m\e[0m",
" \e[36;7mreverse\e[0m\t\e[1;36;7mintense\e[0m\t\e[36;4;7munderline\e[0m\t\e[1;36;4;7mintense underline\e[0m\e[0m\e[0m\e[0m\e[0m\e[0m\e[0m\e[0m\e[0m\e[0m",
"WHITE \e[37mnormal\e[0m\t\e[1;37mintense\e[0m\t\e[37;4munderline\e[0m\t\e[1;37;4mintense underline\e[0m\e[0m\e[0m\e[0m\e[0m\e[0m\e[0m\e[0m\e[0m\e[0m",
" \e[37;7mreverse\e[0m\t\e[1;37;7mintense\e[0m\t\e[37;4;7munderline\e[0m\t\e[1;37;4;7mintense underline\e[0m\e[0m\e[0m\e[0m\e[0m\e[0m\e[0m\e[0m\e[0m\e[0m",
]
_(color_strings[0].colorize).must_equal lead + lines[0]
_(color_strings[1].colorize).must_equal lead + lines[1]
_(color_strings[2].colorize).must_equal lead + lines[2]
_(color_strings[3].colorize).must_equal lead + lines[3]
_(color_strings[4].colorize).must_equal lead + lines[4]
_(color_strings[5].colorize).must_equal lead + lines[5]
_(color_strings[6].colorize).must_equal lead + lines[6]
_(color_strings[7].colorize).must_equal lead + lines[7]
_(color_strings[8].colorize).must_equal lead + lines[8]
_(color_strings[9].colorize).must_equal lead + lines[9]
_(color_strings[10].colorize).must_equal lead + lines[10]
_(color_strings[11].colorize).must_equal lead + lines[11]
_(color_strings[12].colorize).must_equal lead + lines[12]
_(color_strings[13].colorize).must_equal lead + lines[13]
end
it 'returns an empty string wrapped with resets when provided an empty string' do
''.colorize.must_equal "\e[0m\e[0m"
_(''.colorize).must_equal "\e[0m\e[0m"
end
it 'allows curly brackets to be escaped' do
'I want \{no color\}'.colorize.must_equal "\e[0m\e[0mI want {no color}\e[0m\e[0m\e[0m"
_('I want \{no color\}'.colorize).must_equal "\e[0m\e[0mI want {no color}\e[0m\e[0m\e[0m"
end
end
describe 'String#decolorize' do
it 'returns the string with the coloring tags stripped'
it 'returns the string with the coloring tags stripped' do
_("{b colorful}".decolorize).must_equal "colorful"
end
it 'allows curly brackets to be escaped' do
'I want \{no color\}'.decolorize.must_equal "I want {no color}"
_('I want \{no color\}'.decolorize).must_equal "I want {no color}"
end
end