urban 0.1.3 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,57 @@
1
+ class MiniTest::StopLight
2
+ ESC = "\e["
3
+ NND = "#{ESC}0m"
4
+
5
+ attr_reader :io
6
+
7
+ def initialize io
8
+ @io = io
9
+ end
10
+
11
+ def red str
12
+ normal_color(31, str)
13
+ end
14
+
15
+ def yellow str
16
+ normal_color(33, str)
17
+ end
18
+
19
+ def green str
20
+ normal_color(32, str)
21
+ end
22
+
23
+ def normal_color(color_code, str)
24
+ "#{ESC}#{color_code}m#{str}#{NND}"
25
+ end
26
+
27
+ def print(o)
28
+ case o
29
+ when '.'; io.print green(o)
30
+ when 'E', 'F'; io.print red(o)
31
+ when 'S'; io.print yellow(o)
32
+ else; io.print o
33
+ end
34
+ end
35
+
36
+ def puts(*o)
37
+ o.map! do |str|
38
+ case str
39
+ when /Failure:/, /Error:/, /[1-9]+ failures/, /[1-9]+ errors/;
40
+ red(str)
41
+ when /Skipped:/
42
+ yellow(str)
43
+ when /0 failures, 0 errors/;
44
+ green(str).gsub(/([1-9]+ skips)/, yellow('\1'))
45
+ else;
46
+ str.gsub(/([1-9]+ skips)/, yellow('\1'))
47
+ end
48
+ end
49
+ super
50
+ end
51
+
52
+ def method_missing(msg, *args)
53
+ io.send(msg, *args)
54
+ end
55
+ end
56
+
57
+ MiniTest::Unit.output = MiniTest::StopLight.new(MiniTest::Unit.output)
@@ -1,34 +1,28 @@
1
1
  $LOAD_PATH.unshift(File.expand_path('../../lib', __FILE__))
2
2
 
3
3
  require 'rubygems'
4
+ gem 'minitest' if RUBY_VERSION > '1.9'
4
5
  require 'minitest/autorun'
5
6
  require 'urban'
6
7
  require 'urban/cli'
8
+ require 'minitest/stop_light'
9
+ require 'ostruct'
7
10
 
8
- TEST_PHRASE = OpenStruct.new({
9
- :word => 'impromptu',
10
- :definitions => [
11
- 'Something that is made up on the spot and given little time to gather and present. Usually referring to speeches that are given only a few minutes to prepare for.',
11
+ TEST_ENTRY = Urban::Dictionary::Entry.new('impromptu',
12
+ [ 'Something that is made up on the spot and given little time to gather and present. Usually referring to speeches that are given only a few minutes to prepare for.',
12
13
  'On the spot',
13
- 'Something that is made up on the spot. Can also mean a speech that was made with little or no preparation.'
14
- ]})
14
+ 'Something that is made up on the spot. Can also mean a speech that was made with little or no preparation.' ],
15
+ 'http://www.urbandictionary.com/define.php?term=impromptu')
16
+
17
+ EMPTY_ENTRY = Urban::Dictionary::Entry.new('gubble', nil, nil)
15
18
 
16
19
  def load_file(filename)
17
20
  IO.read(File.expand_path("../data/#{filename}", __FILE__))
18
21
  end
19
22
 
20
- ['refute', 'assert'].each do |action|
21
- eval <<-EOM
22
- def #{action}_cli_prints(matches, &block)
23
- out, err = capture_io(&block)
24
- [*matches].each { |match| #{action}_match(match, out) }
25
- end
26
- EOM
27
- end
28
-
29
23
  module Stub
30
24
  def stub(name, &block)
31
- self.class.send(:remove_method, name) if respond_to?(name)
32
- self.class.send(:define_method, name, &block)
25
+ singleton_class = class << self; self; end
26
+ singleton_class.send(:define_method, name, &block)
33
27
  end
34
28
  end
@@ -1,101 +1,212 @@
1
1
  require 'test_helper'
2
+ require 'open-uri'
3
+ require 'socket'
4
+ require 'shellwords'
2
5
 
3
6
  class CLITest < MiniTest::Unit::TestCase
4
7
 
8
+ HELP_SCREEN = <<-EOS
9
+ Usage: urban [OPTION]... [PHRASE]
10
+ Search http://urbandictionary.com for definitions of phrases
11
+
12
+ Options:
13
+ -a, --all List all definitions
14
+ -r, --random Return a random phrase and definition
15
+ -u, --url Print the definition's url after the definition
16
+ -h, --help Show this message
17
+ -v, --version Show version information
18
+ -l, --list DEPRECATED please use --all or -a instead
19
+
20
+ Examples:
21
+ urban cookie monster Search for "cookie monster" and print its
22
+ first definition
23
+ urban -a cookie monster Search for "cookie monster" and print all of
24
+ its available definitions
25
+ urban -r Print a random phrase and its first definition
26
+ urban -ra Print a random phrase and all of its available
27
+ definitions
28
+
29
+ EOS
30
+
5
31
  def setup
6
32
  @program = Urban::CLI.new
7
33
  end
8
34
 
9
- def test_parse_prints_help
10
- expectations = [
11
- /Usage: urban \[OPTION\]\.\.\. \[PHRASE\]/,
12
- /Search http:\/\/urbandictionary\.com for definitions/,
13
- /-l, --list\s*List all definitions/,
14
- /-r, --random\s*Find random word on urban dictionary/,
15
- /-h, --help\s*Show this message/,
16
- /-version\s*Show version/
17
- ]
18
- assert_cli_prints(expectations) { @program.run(["-h"]) }
35
+ # Helpers
36
+ def assert_program_output(argument_variations, stdout=nil, stderr=nil)
37
+ argument_variations.each do |args|
38
+ assert_output(stdout, stderr) { @program.run(Shellwords.shellwords(args)) }
39
+ end
19
40
  end
20
41
 
21
- def test_parse_prints_version_info
22
- args = ['-v']
23
- assert_cli_prints(/^Urban \d+\.\d+\.\d+ \(c\) Thomas Miller$/) { @program.run(args) }
24
- end
42
+ class CLIArgumentParsingTest < CLITest
25
43
 
26
- def test_no_args_prints_help
27
- args = []
28
- assert_cli_prints(/Usage: urban \[OPTION\]\.\.\. \[PHRASE\]/) { @program.run(args) }
29
- end
44
+ # Helpers
45
+ def assert_flag_is_set(name)
46
+ ["-#{name.chars.first}", "--#{name}"].each do |args|
47
+ options = @program.send(:parse, [args])
48
+ assert_equal(true, options.send(name))
49
+ end
50
+ end
30
51
 
31
- def test_no_args_with_list_option_prints_help
32
- args = ['-l']
33
- assert_cli_prints(/Usage: urban \[OPTION\]\.\.\. \[PHRASE\]/) { @program.run(args) }
34
- end
52
+ # Tests
53
+ def test_defaults
54
+ assert_silent do
55
+ options = @program.send(:parse, [])
56
+ assert_equal(false, options.help)
57
+ assert_equal(false, options.version)
58
+ assert_equal(false, options.random)
59
+ assert_equal(false, options.all)
60
+ assert_equal('', options.phrase)
61
+ end
62
+ end
35
63
 
36
- def test_parse_returns_random
37
- capture_io do
38
- actual = @program.send(:parse, ['-r'])
39
- assert(actual.random, 'Args -r; Expected true, returned false')
40
- actual = @program.send(:parse, ['--random'])
41
- assert(actual.random, 'Args --random Expected true, returned false')
64
+ def test_phrase
65
+ assert_silent do
66
+ options = @program.send(:parse, ['foo bar'])
67
+ assert_equal('foo bar', options.phrase)
68
+ end
42
69
  end
43
- end
44
70
 
45
- def test_parse_returns_list
46
- capture_io do
47
- actual = @program.send(:parse, ['-l'])
48
- assert(actual.list, 'Args: -l; Expected true, returned false')
49
- actual = @program.send(:parse, ['--list'])
50
- assert(actual.list, 'Args: --list; Expected true, returned false')
71
+ def test_help_flag
72
+ assert_silent do
73
+ assert_flag_is_set('help')
74
+ end
51
75
  end
52
- end
53
76
 
54
- def test_parse_returns_phrase
55
- capture_io do
56
- actual = @program.send(:parse, ['Cookie', 'monster'])
57
- assert_equal('Cookie monster', actual.phrase)
58
- actual = @program.send(:parse, ['Cookie monster'])
59
- assert_equal('Cookie monster', actual.phrase)
77
+ def test_version_flag
78
+ assert_silent do
79
+ assert_flag_is_set('version')
80
+ end
81
+ end
82
+
83
+ def test_random_flag
84
+ assert_silent do
85
+ assert_flag_is_set('random')
86
+ end
87
+ end
88
+
89
+ def test_all_flag
90
+ assert_silent do
91
+ assert_flag_is_set('all')
92
+ end
93
+ end
94
+
95
+ def test_all_flag
96
+ assert_silent do
97
+ assert_flag_is_set('url')
98
+ end
60
99
  end
61
100
  end
62
101
 
63
- class CLIDefinintionOutputTest < CLITest
102
+ class CLIRunnerStandardOutputTest < CLITest
103
+
104
+ SINGLE_DEFINITION = "\n#{TEST_ENTRY.phrase.upcase}\n\n#{TEST_ENTRY.definitions.first}\n\n"
105
+ MULTIPLE_DEFINITIONS = "\n#{TEST_ENTRY.phrase.upcase}\n\n#{TEST_ENTRY.definitions.join("\n\n")}\n\n"
106
+ DEFINITION_WITH_URL = "\n#{TEST_ENTRY.phrase.upcase}\n\n#{TEST_ENTRY.definitions.first}\n\nURL: #{TEST_ENTRY.url}\n\n"
107
+
64
108
  def setup
65
- @dictionary = MiniTest::Mock.new
66
109
  super
110
+ @dictionary = MiniTest::Mock.new
111
+ end
112
+
113
+ # Tests
114
+ def test_help_flag_prints_help
115
+ assert_output(HELP_SCREEN) { @program.run([]) }
67
116
  end
68
117
 
69
- def test_cli_prints_random_definition
70
- args = ['-r']
71
- expected = [ "#{TEST_PHRASE.word.upcase}", TEST_PHRASE.definitions.first ]
72
- @program.dictionary = @dictionary.expect(:random, TEST_PHRASE)
73
- assert_cli_prints(expected) { @program.run(args) }
118
+ def test_version_flag_prints_version
119
+ ['-v', '--v'].each do |args|
120
+ assert_output("Urban #{Urban::VERSION} (c) Thomas Miller\n") { @program.run([args]) }
121
+ end
122
+ end
123
+
124
+ def test_random_flag_prints_single_definition
125
+ @program.dictionary = @dictionary.expect(:random, TEST_ENTRY)
126
+ argument_variations = ['-r', '--random']
127
+ assert_program_output(argument_variations, SINGLE_DEFINITION)
128
+ @dictionary.verify
129
+ end
130
+
131
+ def test_phrase_prints_single_definition
132
+ @program.dictionary = @dictionary.expect(:search, TEST_ENTRY, ['impromptu'])
133
+ argument_variations = ['impromptu']
134
+ assert_program_output(argument_variations, SINGLE_DEFINITION)
135
+ @dictionary.verify
136
+ end
137
+
138
+ def test_random_and_all_flag_prints_multiple_definitions
139
+ @program.dictionary = @dictionary.expect(:random, TEST_ENTRY)
140
+ argument_variations = ['-ra', '-r -a', '--random -a', '-r --all', '--all --random']
141
+ assert_program_output(argument_variations, MULTIPLE_DEFINITIONS)
74
142
  @dictionary.verify
75
143
  end
76
144
 
77
- def test_cli_prints_random_definition_list
78
- args = ['-rl']
79
- expected = [ "#{TEST_PHRASE.word.upcase}", *TEST_PHRASE.definitions ]
80
- @program.dictionary = @dictionary.expect(:random, TEST_PHRASE)
81
- assert_cli_prints(expected) { @program.run(args) }
145
+ def test_phrase_and_all_flag_prints_multiple_definitions
146
+ @program.dictionary = @dictionary.expect(:search, TEST_ENTRY, ['impromptu'])
147
+ argument_variations = ['impromptu -a', '--all impromptu']
148
+ assert_program_output(argument_variations, MULTIPLE_DEFINITIONS)
82
149
  @dictionary.verify
83
150
  end
84
151
 
85
- def test_cli_prints_definition
86
- args = ['impromptu']
87
- expected = [ "#{TEST_PHRASE.word.upcase}", TEST_PHRASE.definitions.first ]
88
- @program.dictionary = @dictionary.expect(:search, TEST_PHRASE, ['impromptu'])
89
- assert_cli_prints(expected) { @program.run(['impromptu']) }
152
+ def test_random_and_url_flag_prints_definition_with_url
153
+ @program.dictionary = @dictionary.expect(:random, TEST_ENTRY)
154
+ argument_variations = ['-ru', '-r -u', '--random -u', '-r --url', '--url --random']
155
+ assert_program_output(argument_variations, DEFINITION_WITH_URL)
90
156
  @dictionary.verify
91
157
  end
92
158
 
93
- def test_cli_prints_definition_list
94
- args = ['-l', 'impromptu']
95
- expected = [ "#{TEST_PHRASE.word.upcase}", *TEST_PHRASE.definitions ]
96
- @program.dictionary = @dictionary.expect(:search, TEST_PHRASE, ['impromptu'])
97
- assert_cli_prints(expected) { @program.run(args) }
159
+ def test_phrase_and_url_flag_prints_definition_with_url
160
+ @program.dictionary = @dictionary.expect(:search, TEST_ENTRY, ['impromptu'])
161
+ argument_variations = ['impromptu -u', '--url impromptu']
162
+ assert_program_output(argument_variations, DEFINITION_WITH_URL)
98
163
  @dictionary.verify
99
164
  end
165
+
166
+ def test_list_flag_prints_deprecation_warning
167
+ expected = /WARNING: --list and -l are deprecated please use --all or -a instead/
168
+ @program.dictionary = @dictionary.expect(:search, TEST_ENTRY, ['impromptu'])
169
+ @program.dictionary = @dictionary.expect(:random, TEST_ENTRY)
170
+ stdout, stederr = capture_io { @program.run(Shellwords.shellwords('--list impromptu')) }
171
+ assert_match expected, stdout
172
+ stdou, stederr = capture_io { @program.run(Shellwords.shellwords('-rl')) }
173
+ assert_match expected, stdout
174
+ end
175
+ end
176
+
177
+ class CLIRunnerErrorOutputTest < CLITest
178
+
179
+ ERROR_MISSING_PHRASE = "urban: no definitions found for #{EMPTY_ENTRY.phrase.upcase}.\n"
180
+ ERROR_NO_INTERNET = "urban: no internet connection available.\n"
181
+ ERROR_INVALID_OPTION = <<-EOE
182
+ urban: invalid option: -b
183
+ Try `urban --help' for more information.
184
+ EOE
185
+
186
+ def setup
187
+ super
188
+ end
189
+
190
+ # Tests
191
+ def test_search_missing_phrase_prints_error
192
+ dictionary = MiniTest::Mock.new
193
+ @program.dictionary = dictionary.expect(:search, EMPTY_ENTRY, ['gubble'])
194
+ assert_program_output(['gubble'], nil, ERROR_MISSING_PHRASE)
195
+ dictionary.verify
196
+ end
197
+
198
+ def test_search_missing_phrase_prints_error
199
+ dictionary = (Object.new).extend Stub
200
+ dictionary.stub(:search) { |phrase| raise SocketError }
201
+ @program.dictionary = dictionary
202
+ assert_program_output(['gubble'], nil, ERROR_NO_INTERNET)
203
+ end
204
+
205
+ def test_invalid_option_prints_help
206
+ dictionary = (Object.new).extend Stub
207
+ dictionary.stub(:search) { |phrase| raise OptionParser::InvalidOption }
208
+ @program.dictionary = dictionary
209
+ assert_program_output(['-b'], nil, ERROR_INVALID_OPTION)
210
+ end
100
211
  end
101
212
  end
@@ -4,18 +4,34 @@ class DictionaryTest < MiniTest::Unit::TestCase
4
4
 
5
5
  def setup
6
6
  @web_service = MiniTest::Mock.new
7
- @dictionary = Urban::Dictionary.new
7
+ @dictionary = Urban::Dictionary
8
+
9
+ @response = OpenStruct.new
10
+ @response.url = 'http://www.urbandictionary.com/define.php?term=impromptu'
11
+ @response.stream = load_file('impromptu.html')
12
+ end
13
+
14
+ def test_process_extracts_elements_from_html
15
+ entry = @dictionary.send(:process, @response )
16
+ assert_equal(TEST_ENTRY, entry)
8
17
  end
9
18
 
10
19
  def test_dictionary_calls_random
11
- @dictionary.web_service = @web_service.expect(:query, load_file('impromptu.html') ,[:random])
12
- assert_equal(TEST_PHRASE, @dictionary.random)
20
+ @dictionary.web_service = @web_service.expect(:random, @response)
21
+ assert_equal(TEST_ENTRY, @dictionary.random)
13
22
  @web_service.verify
14
23
  end
15
24
 
16
- def test_dictionary_calls_define
17
- @dictionary.web_service = @web_service.expect(:query, load_file('impromptu.html'), [:define, 'impromptu'])
18
- assert_equal(TEST_PHRASE, @dictionary.search('impromptu'))
25
+ def test_dictionary_calls_search
26
+ @dictionary.web_service = @web_service.expect(:search, @response, ['impromptu'])
27
+ assert_equal(TEST_ENTRY, @dictionary.search('impromptu'))
28
+ @web_service.verify
29
+ end
30
+
31
+ def test_dictionary_returns_empty_for_missing_phrases
32
+ @response.stream = load_file('missing.html')
33
+ @dictionary.web_service = @web_service.expect(:search, @response, ['gubble'])
34
+ assert_equal(EMPTY_ENTRY, @dictionary.search('gubble'))
19
35
  @web_service.verify
20
36
  end
21
37
  end
@@ -3,19 +3,54 @@ require 'test_helper'
3
3
  class WebTest < MiniTest::Unit::TestCase
4
4
 
5
5
  def setup
6
- @web_service = (Urban::Web.new).extend Stub
7
- @web_service.stub(:open) { |arg| return arg; }
6
+ @web_module = (Object.new).extend(Urban::Web).extend(Stub)
8
7
  end
9
8
 
10
- def test_web_sends_request_to_random
11
- expected = 'http://www.urbandictionary.com/random.php'
12
- actual = @web_service.query(:random)
13
- assert_equal(expected, actual)
9
+ class WebFetchTest < WebTest
10
+ def setup
11
+ super
12
+ @web_module.stub(:open) { |arg| arg }
13
+ end
14
+
15
+ def test_fetch_with_no_params
16
+ expected = 'http://www.urbandictionary.com/test.php'
17
+ actual = @web_module.fetch('test.php')
18
+ assert_equal(expected, actual)
19
+ end
20
+
21
+ def test_fetch_with_params
22
+ expected = /http:\/\/www\.urbandictionary\.com\/test\.php\?\w+=\w+&\w+=\w+/
23
+ actual = @web_module.fetch('test.php', :name => 'foo', :term => 'bar')
24
+ assert_match(expected, actual)
25
+ end
14
26
  end
15
27
 
16
- def test_web_sends_request_to_define_with_phrase
17
- expected = 'http://www.urbandictionary.com/define.php?term=Cookie%20monster'
18
- actual = @web_service.query(:define, 'Cookie monster')
19
- assert_equal(expected, actual)
28
+ class WebInterfaceTest < WebTest
29
+
30
+ def setup
31
+ super
32
+ @expected = OpenStruct.new
33
+ @expected.base_uri = 'http://www.urbandictionary.com/define.php?term=impromptu'
34
+
35
+ @web_module.stub(:open) do |arg|
36
+ result = OpenStruct.new
37
+ result.base_uri = 'http://www.urbandictionary.com/define.php?term=impromptu'
38
+ result
39
+ end
40
+ end
41
+
42
+ def test_returns_response_for_random_word
43
+ actual = @web_module.random
44
+
45
+ assert_equal(@expected.base_uri, actual.url)
46
+ assert_equal(@expected, actual.stream)
47
+ end
48
+
49
+ def test_returns_response_for_define_with_phrase
50
+ actual = @web_module.search('cookie monster')
51
+
52
+ assert_equal(@expected.base_uri, actual.url)
53
+ assert_equal(@expected, actual.stream)
54
+ end
20
55
  end
21
56
  end