Begin building out test suite

- Minor code shuffling
- Privatization of some methods
- Readline script doesn't kick off if running from a test
This commit is contained in:
Eric Budd 2018-02-02 00:59:57 -05:00
parent 22372906cd
commit 3b6ad0d3d3
3 changed files with 299 additions and 72 deletions

146
iris.rb
View File

@ -63,7 +63,60 @@ class Config
AUTHOR = "#{USER}@#{HOSTNAME}"
def self.find_files
@@message_corpus ||= (`ls /home/**/.iris.messages`).split("\n")
(`ls /home/**/.iris.messages`).split("\n")
end
end
class Corpus
def self.load
@@corpus = Config.find_files.map { |filepath| IrisFile.load_messages(filepath) }.flatten.sort_by(&:timestamp)
@@topics = @@corpus.select{ |m| m.parent == nil }
@@my_corpus = IrisFile.load_messages.sort_by(&:timestamp)
@@all_hash_to_index = @@corpus.reduce({}) { |agg, msg| agg[msg.hash] = @@corpus.index(msg); agg }
@@all_parent_hash_to_index = @@corpus.reduce({}) do |agg, msg|
agg[msg.parent] ||= []
agg[msg.parent] << @@corpus.index(msg)
agg
end
end
def self.all
@@corpus
end
def self.topics
@@topics
end
def self.mine
@@my_corpus
end
def self.find_message_by_hash(hash)
return nil unless hash
index = @@all_hash_to_index[hash]
return nil unless index
all[index]
end
def self.find_all_by_parent_hash(hash)
return [] unless hash
indexes = @@all_parent_hash_to_index[hash]
return [] unless indexes
indexes.map{ |idx| all[idx] }
end
def self.find_topic(topic_lookup)
return nil unless topic_lookup
if topic_id.to_i == 0
# This must be a hash, handle appropriately
msg = find_message_by_hash(topic_id)
msg
else
# This must be an index, handle appropriately
index = topic_id.to_i - 1
return topics[index] if index >= 0 && index < topics.length
end
end
end
@ -125,59 +178,6 @@ class IrisFile
end
end
class Corpus
def self.load
@@corpus = Config.find_files.map { |filepath| IrisFile.load_messages(filepath) }.flatten.sort_by(&:timestamp)
@@topics = @@corpus.select{ |m| m.parent == nil }
@@my_corpus = IrisFile.load_messages.sort_by(&:timestamp)
@@all_hash_to_index = @@corpus.reduce({}) { |agg, msg| agg[msg.hash] = @@corpus.index(msg); agg }
@@all_parent_hash_to_index = @@corpus.reduce({}) do |agg, msg|
agg[msg.parent] ||= []
agg[msg.parent] << @@corpus.index(msg)
agg
end
end
def self.all
@@corpus
end
def self.topics
@@topics
end
def self.mine
@@my_corpus
end
def self.find_message_by_hash(hash)
return nil unless hash
index = @@all_hash_to_index[hash]
return nil unless index
all[index]
end
def self.find_all_by_parent_hash(hash)
return [] unless hash
indexes = @@all_parent_hash_to_index[hash]
return [] unless indexes
indexes.map{ |idx| all[idx] }
end
def self.find_topic(topic_id)
if topic_id.to_i == 0
# This must be a hash, handle appropriately
msg = find_message_by_hash(topic_id)
puts 'WARNING: Expected a topic but got a reply!' unless msg.is_topic?
msg
else
# This must be an index, handle appropriately
index = topic_id.to_i - 1
return topics[index] if index >= 0 && index < topics.length
end
end
end
class Message
FILE_FORMAT = 'v2'
@ -223,6 +223,10 @@ class Message
@errors.empty?
end
def topic?
parent.nil?
end
def save!
new_corpus = Corpus.mine << self
IrisFile.write_corpus(new_corpus.to_json)
@ -250,14 +254,6 @@ class Message
[head, message_stub].join(' | ')
end
def leader_text
is_topic? ? '***' : ' === REPLY==='
end
def verb_text
is_topic? ? 'posted' : 'replied'
end
def to_display
error_marker = valid? ? nil : '### THIS MESSAGE HAS THE FOLLOWING ERRORS ###'
error_follower = valid? ? nil : '### THIS MESSAGE MAY BE CORRUPT OR TAMPERED WITH ###'
@ -277,14 +273,6 @@ class Message
[to_display] + replies.map(&:to_display)
end
def replies
Corpus.find_all_by_parent_hash(hash)
end
def is_topic?
parent.nil?
end
def to_json(*args)
{
hash: hash,
@ -293,6 +281,20 @@ class Message
}.to_json
end
private
def leader_text
topic? ? '***' : ' === REPLY==='
end
def verb_text
topic? ? 'posted' : 'replied'
end
def replies
Corpus.find_all_by_parent_hash(hash)
end
def unconfirmed_payload
{
author: author,
@ -312,7 +314,7 @@ class Display
end
def self.topic_author_width
Corpus.topics.map(&:author).map(&:length).max
Corpus.topics.map(&:author).map(&:length).max || 1
end
def self.print_index(index)
@ -604,4 +606,4 @@ class Startupper
end
end
Startupper.new(ARGV)
Startupper.new(ARGV) if __FILE__==$0

219
iris_test.rb Normal file
View File

@ -0,0 +1,219 @@
require 'minitest/autorun'
require 'mocha/mini_test'
# 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$/
end
it 'has the message file location' do
Config::MESSAGE_FILE.must_match /\/\.iris\.messages$/
end
it 'has the readline history file location' do
Config::HISTORY_FILE.must_match /\/\.iris\.history$/
end
it 'has the username' do
Config::USER.must_equal 'jerryberry'
end
it 'has a hostname' do
Config::HOSTNAME.wont_be_nil
end
it 'has the author' do
Config::AUTHOR.must_equal "#{Config::USER}@#{Config::HOSTNAME}"
end
describe '.find_files' do
it 'looks up all the Iris message files on the system' do
# I am so sorry
Config.expects(:`).with('ls /home/**/.iris.messages').returns('')
Config.find_files
end
it 'returns a list of Iris message files' do
Config.stubs(:`).returns("foo\nbar\n")
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 []
end
end
end
describe Corpus do
describe '.load' do
it 'loads all the message files'
it 'sets the corpus class variable'
it 'sets the topics class variable'
it 'creates a hash index'
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'
end
describe '.mine' do
it 'returns all messages composed by the current user'
it 'does not return any messages not composed by the current user'
end
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
end
it 'returns nil if the hash is not found in the corpus' do
skip
Corpus.find_message_by_hash('NoofMcGoof').must_equal nil
end
it 'returns the message associated with the hash if it is found'
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 []
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 []
end
it 'returns an empty array if the hash is not found in the corpus'
it 'returns the messages associated with the parent hash'
end
describe '.find_topic' do
it 'returns nil if a nil is passed in' do
Corpus.find_topic(nil).must_equal nil
end
describe 'when a hash string is passed in' do
it 'returns nil if the topic is not found'
it 'returns the associated topic'
end
describe 'when an index string is passed in' do
it 'returns nil if the topic is not found'
it 'returns the associated topic'
end
end
end
describe IrisFile do
describe '.load_messages' do; end
describe '.create_message_file' do; end
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'
it 'is #topic? if it has no parent'
describe 'creation' do; end
describe 'validation' do; end
describe '#save!' do
it 'adds itself to the user\'s corpus'
it 'writes out the user\'s message file'
it 'reloads all message files'
end
describe '#hash' do; end
describe '#truncated_message' do; end
describe '#to_topic_line' do; end
describe '#to_display' do; end
describe '#to_topic_display' do; end
describe '#to_json' do; end
end
describe Display do
it 'has a setting for a minimum width of 80' do
Display::MIN_WIDTH.must_equal 80
end
it 'has a setting for the calculated screen width'
describe '#topic_index_width' do
it 'returns the length in characters of the longest topic index' do
Corpus.stubs(:topics).returns(%w{a bc def})
Display.topic_index_width.must_equal 1
Corpus.stubs(:topics).returns(%w{a b c d e f g h i j k})
Display.topic_index_width.must_equal 2
end
it 'returns 1 if there are no topics' do
Corpus.stubs(:topics).returns([])
Display.topic_index_width.must_equal 1
end
end
describe '#topic_author_width' do
it 'returns the length in characters of the longest author\'s name'
it 'returns 1 if there are no topics' do
Corpus.stubs(:topics).returns([])
Display.topic_author_width.must_equal 1
end
end
describe '.print_index' do; end
describe '.print_author' do; end
end
describe Interface do
it 'has a map of all single-word commands'
it 'has a map of all shortcuts and commands'
describe '#start' do; end
describe 'creation' do; end
describe '#reset_display' do; end
describe '#reply' do; end
describe '#show_topic' do; end
describe '#quit' do; end
describe '.start' do; end
describe '#compose' do; end
describe '#topics' do; end
describe '#help' do; end
describe '#freshen' do; end
describe '#readline (maybe?)' do; end
end
describe CLI do
describe '#start' do; end
describe 'creation' do; end
describe '--version or -v' do; end
describe '--stats or -s' do; end
describe '--help or -h' do; end
describe 'junk parameters' do; end
end
describe Startupper do
describe 'creation' do; end
describe 'perform_startup_checks' do; end
end

6
test_watch Executable file
View File

@ -0,0 +1,6 @@
echo "Watching..."
find . -name "*.rb" | entr sh -c 'clear; ruby iris_test.rb'
# while inotifywait -r -e modify ./spec; do
# SKIP_PRECOMPILE=TRUE SKIP_LINT=TRUE ./test.sh $1
# done