aboutsummaryrefslogtreecommitdiffstats
path: root/tests/check_util.c
blob: b00d645bff8a1ee0c4ac27019346c994d1fc5da3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
#include <stdlib.h>
#include <glib.h>
#include <gmodule.h>
#include <check.h>
#include <string.h>
#include "irc.h"
#include "set.h"
#include "misc.h"
#include "url.h"

START_TEST(test_strip_linefeed)
{
	int i;
	const char *get[] = { "Test", "Test\r", "Test\rX\r", NULL };
	const char *expected[] = { "Test", "Test", "TestX", NULL };

	for (i = 0; get[i]; i++) {
		char copy[20];
		strcpy(copy, get[i]);
		strip_linefeed(copy);
		fail_unless (strcmp(copy, expected[i]) == 0, 
					 "(%d) strip_linefeed broken: %s -> %s (expected: %s)", 
					 i, get[i], copy, expected[i]);
	}
}
END_TEST

START_TEST(test_strip_newlines)
{
	int i;
	const char *get[] = { "Test", "Test\r\n", "Test\nX\n", NULL };
	const char *expected[] = { "Test", "Test  ", "Test X ", NULL };

	for (i = 0; get[i]; i++) {
		char copy[20], *ret;
		strcpy(copy, get[i]);
		ret = strip_newlines(copy);
		fail_unless (strcmp(copy, expected[i]) == 0, 
					 "(%d) strip_newlines broken: %s -> %s (expected: %s)", 
					 i, get[i], copy, expected[i]);
		fail_unless (copy == ret, "Original string not returned"); 
	}
}
END_TEST

START_TEST(test_set_url_http)
	url_t url;
	
	fail_if (0 == url_set(&url, "http://host/"));
	fail_unless (!strcmp(url.host, "host"));
	fail_unless (!strcmp(url.file, "/"));
	fail_unless (!strcmp(url.user, ""));
	fail_unless (!strcmp(url.pass, ""));
	fail_unless (url.proto == PROTO_HTTP);
	fail_unless (url.port == 80);
END_TEST

START_TEST(test_set_url_https)
	url_t url;
	
	fail_if (0 == url_set(&url, "https://ahost/AimeeMann"));
	fail_unless (!strcmp(url.host, "ahost"));
	fail_unless (!strcmp(url.file, "/AimeeMann"));
	fail_unless (!strcmp(url.user, ""));
	fail_unless (!strcmp(url.pass, ""));
	fail_unless (url.proto == PROTO_HTTPS);
	fail_unless (url.port == 443);
END_TEST

START_TEST(test_set_url_port)
	url_t url;
	
	fail_if (0 == url_set(&url, "https://ahost:200/Lost/In/Space"));
	fail_unless (!strcmp(url.host, "ahost"));
	fail_unless (!strcmp(url.file, "/Lost/In/Space"));
	fail_unless (!strcmp(url.user, ""));
	fail_unless (!strcmp(url.pass, ""));
	fail_unless (url.proto == PROTO_HTTPS);
	fail_unless (url.port == 200);
END_TEST

START_TEST(test_set_url_username)
	url_t url;
	
	fail_if (0 == url_set(&url, "socks4://user@ahost/Space"));
	fail_unless (!strcmp(url.host, "ahost"));
	fail_unless (!strcmp(url.file, "/Space"));
	fail_unless (!strcmp(url.user, "user"));
	fail_unless (!strcmp(url.pass, ""));
	fail_unless (url.proto == PROTO_SOCKS4);
	fail_unless (url.port == 1080);
END_TEST

START_TEST(test_set_url_username_pwd)
	url_t url;
	
	fail_if (0 == url_set(&url, "socks5://user:pass@ahost/"));
	fail_unless (!strcmp(url.host, "ahost"));
	fail_unless (!strcmp(url.file, "/"));
	fail_unless (!strcmp(url.user, "user"));
	fail_unless (!strcmp(url.pass, "pass"));
	fail_unless (url.proto == PROTO_SOCKS5);
	fail_unless (url.port == 1080);
END_TEST

struct
{
	char *orig;
	int line_len;
	char *wrapped;
} word_wrap_tests[] = {
	{
		"Line-wrapping is not as easy as it seems?",
		16,
		"Line-wrapping is\nnot as easy as\nit seems?"
	},
	{
		"Line-wrapping is not as easy as it seems?",
		8,
		"Line-\nwrapping\nis not\nas easy\nas it\nseems?"
	},
	{
		"Line-wrapping is\nnot as easy as it seems?",
		8,
		"Line-\nwrapping\nis\nnot as\neasy as\nit\nseems?"
	},
	{
		"a aa aaa aaaa aaaaa aaaaaa aaaaaaa aaaaaaaa",
		5,
		"a aa\naaa\naaaa\naaaaa\naaaaa\na\naaaaa\naa\naaaaa\naaa",
	},
	{
		"aaaaaaaa aaaaaaa aaaaaa aaaaa aaaa aaa aa a",
		5,
		"aaaaa\naaa\naaaaa\naa\naaaaa\na\naaaaa\naaaa\naaa\naa a",
	},
	{
		"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
		5,
		"aaaaa\naaaaa\naaaaa\naaaaa\naaaaa\naaaaa\naaaaa\na",
	},
	{
		NULL
	}
};

START_TEST(test_word_wrap)
	int i;
	
	for( i = 0; word_wrap_tests[i].orig && *word_wrap_tests[i].orig; i ++ )
	{
		char *wrapped = word_wrap( word_wrap_tests[i].orig, word_wrap_tests[i].line_len );
		
		fail_unless( strcmp( word_wrap_tests[i].wrapped, wrapped ) == 0,
		             "%s (line_len = %d) should wrap to `%s', not to `%s'",
		             word_wrap_tests[i].orig, word_wrap_tests[i].line_len,
		             word_wrap_tests[i].wrapped, wrapped );
		
		g_free( wrapped );
	}
END_TEST

Suite *util_suite (void)
{
	Suite *s = suite_create("Util");
	TCase *tc_core = tcase_create("Core");
	suite_add_tcase (s, tc_core);
	tcase_add_test (tc_core, test_strip_linefeed);
	tcase_add_test (tc_core, test_strip_newlines);
	tcase_add_test (tc_core, test_set_url_http);
	tcase_add_test (tc_core, test_set_url_https);
	tcase_add_test (tc_core, test_set_url_port);
	tcase_add_test (tc_core, test_set_url_username);
	tcase_add_test (tc_core, test_set_url_username_pwd);
	tcase_add_test (tc_core, test_word_wrap);
	return s;
}
ass="c1"># Section comment attr_reader :comment ## # Context this Section lives in attr_reader :parent ## # Section sequence number (for linking) attr_reader :sequence ## # Section title attr_reader :title @@sequence = "SEC00000" @@sequence_lock = Mutex.new ## # Creates a new section with +title+ and +comment+ def initialize(parent, title, comment) @parent = parent @title = title @@sequence_lock.synchronize do @@sequence.succ! @sequence = @@sequence.dup end set_comment comment end ## # Sections are equal when they have the same #sequence def ==(other) self.class === other and @sequence == other.sequence end def inspect # :nodoc: "#<%s:0x%x %s %p>" % [ self.class, object_id, @sequence, title ] end ## # Set the comment for this section from the original comment block If # the first line contains :section:, strip it and use the rest. # Otherwise remove lines up to the line containing :section:, and look # for those lines again at the end and remove them. This lets us write # # # blah blah blah # # # # :SECTION: The title # # The body def set_comment(comment) return unless comment if comment =~ /^#[ \t]*:section:.*\n/ then start = $` rest = $' if start.empty? @comment = rest else @comment = rest.sub(/#{start.chomp}\Z/, '') end else @comment = comment end @comment = nil if @comment.empty? end end ## # Creates an unnamed empty context with public visibility def initialize super @in_files = [] @name ||= "unknown" @comment ||= "" @parent = nil @visibility = :public @current_section = Section.new self, nil, nil @sections = [@current_section] initialize_methods_etc initialize_classes_and_modules end ## # Sets the defaults for classes and modules def initialize_classes_and_modules @classes = {} @modules = {} end ## # Sets the defaults for methods and so-forth def initialize_methods_etc @method_list = [] @attributes = [] @aliases = [] @requires = [] @includes = [] @constants = [] # This Hash maps a method name to a list of unmatched aliases (aliases of # a method not yet encountered). @unmatched_alias_lists = {} end ## # Contexts are sorted by full_name def <=>(other) full_name <=> other.full_name end ## # Adds +an_alias+ that is automatically resolved def add_alias(an_alias) meth = find_instance_method_named(an_alias.old_name) if meth then add_alias_impl an_alias, meth else add_to @aliases, an_alias unmatched_alias_list = @unmatched_alias_lists[an_alias.old_name] ||= [] unmatched_alias_list.push an_alias end an_alias end ## # Adds +an_alias+ pointing to +meth+ def add_alias_impl(an_alias, meth) new_meth = RDoc::AnyMethod.new an_alias.text, an_alias.new_name new_meth.is_alias_for = meth new_meth.singleton = meth.singleton new_meth.params = meth.params new_meth.comment = "Alias for \##{meth.name}" meth.add_alias new_meth add_method new_meth end ## # Adds +attribute+ def add_attribute(attribute) add_to @attributes, attribute end ## # Adds a class named +name+ with +superclass+. # # Given <tt>class Container::Item</tt> RDoc assumes +Container+ is a module # unless it later sees <tt>class Container</tt>. add_class automatically # upgrades +name+ to a class in this case. def add_class(class_type, name, superclass = 'Object') klass = add_class_or_module @classes, class_type, name, superclass # If the parser encounters Container::Item before encountering # Container, then it assumes that Container is a module. This may not # be the case, so remove Container from the module list if present and # transfer any contained classes and modules to the new class. RDoc::TopLevel.lock.synchronize do mod = RDoc::TopLevel.modules_hash.delete klass.full_name if mod then klass.classes_hash.update mod.classes_hash klass.modules_hash.update mod.modules_hash klass.method_list.concat mod.method_list @modules.delete klass.name end RDoc::TopLevel.classes_hash[klass.full_name] = klass end klass end ## # Instantiates a +class_type+ named +name+ and adds it the modules or # classes Hash +collection+. def add_class_or_module(collection, class_type, name, superclass = nil) full_name = if RDoc::TopLevel === self then # HACK name else "#{self.full_name}::#{name}" end mod = collection[name] if mod then mod.superclass = superclass unless mod.module? else all = nil RDoc::TopLevel.lock.synchronize do all = if class_type == RDoc::NormalModule then RDoc::TopLevel.modules_hash else RDoc::TopLevel.classes_hash end mod = all[full_name] end unless mod then mod = class_type.new name, superclass else # If the class has been encountered already, check that its # superclass has been set (it may not have been, depending on the # context in which it was encountered). if class_type == RDoc::NormalClass then mod.superclass = superclass unless mod.superclass end end unless @done_documenting then RDoc::TopLevel.lock.synchronize do all[full_name] = mod end collection[name] = mod end mod.section = @current_section mod.parent = self end mod end ## # Adds +constant+ def add_constant(constant) add_to @constants, constant end ## # Adds included module +include+ def add_include(include) add_to @includes, include end ## # Adds +method+ def add_method(method) method.visibility = @visibility add_to @method_list, method unmatched_alias_list = @unmatched_alias_lists[method.name] if unmatched_alias_list then unmatched_alias_list.each do |unmatched_alias| add_alias_impl unmatched_alias, method @aliases.delete unmatched_alias end @unmatched_alias_lists.delete method.name end end ## # Adds a module named +name+. If RDoc already knows +name+ is a class then # that class is returned instead. See also #add_class def add_module(class_type, name) return @classes[name] if @classes.key? name add_class_or_module @modules, class_type, name, nil end ## # Adds +require+ to this context's top level def add_require(require) if RDoc::TopLevel === self then add_to @requires, require else parent.add_require require end end ## # Adds +thing+ to the collection +array+ def add_to(array, thing) array << thing if @document_self and not @done_documenting thing.parent = self thing.section = @current_section end ## # Array of classes in this context def classes @classes.values end ## # All classes and modules in this namespace def classes_and_modules classes + modules end ## # Hash of classes keyed by class name def classes_hash @classes end ## # Is part of this thing was defined in +file+? def defined_in?(file) @in_files.include?(file) end ## # Iterator for attributes def each_attribute # :yields: attribute @attributes.each {|a| yield a} end ## # Iterator for classes and modules def each_classmodule(&block) # :yields: module classes_and_modules.sort.each(&block) end ## # Iterator for constants def each_constant # :yields: constant @constants.each {|c| yield c} end ## # Iterator for included modules def each_include # :yields: include @includes.each do |i| yield i end end ## # Iterator for methods def each_method # :yields: method @method_list.sort.each {|m| yield m} end ## # Finds an attribute with +name+ in this context def find_attribute_named(name) @attributes.find { |m| m.name == name } end ## # Finds a constant with +name+ in this context def find_constant_named(name) @constants.find {|m| m.name == name} end ## # Find a module at a higher scope def find_enclosing_module_named(name) parent && parent.find_module_named(name) end ## # Finds a file with +name+ in this context def find_file_named(name) top_level.class.find_file_named(name) end ## # Finds an instance method with +name+ in this context def find_instance_method_named(name) @method_list.find { |meth| meth.name == name && !meth.singleton } end ## # Finds a method, constant, attribute, module or files named +symbol+ in # this context def find_local_symbol(symbol) find_method_named(symbol) or find_constant_named(symbol) or find_attribute_named(symbol) or find_module_named(symbol) or find_file_named(symbol) end ## # Finds a instance or module method with +name+ in this context def find_method_named(name) @method_list.find { |meth| meth.name == name } end ## # Find a module with +name+ using ruby's scoping rules def find_module_named(name) res = @modules[name] || @classes[name] return res if res return self if self.name == name find_enclosing_module_named name end ## # Look up +symbol+. If +method+ is non-nil, then we assume the symbol # references a module that contains that method. def find_symbol(symbol, method = nil) result = nil case symbol when /^::(.*)/ then result = top_level.find_symbol($1) when /::/ then modules = symbol.split(/::/) unless modules.empty? then module_name = modules.shift result = find_module_named(module_name) if result then modules.each do |name| result = result.find_module_named name break unless result end end end else # if a method is specified, then we're definitely looking for # a module, otherwise it could be any symbol if method then result = find_module_named symbol else result = find_local_symbol symbol if result.nil? then if symbol =~ /^[A-Z]/ then result = parent while result && result.name != symbol do result = result.parent end end end end end if result and method then fail unless result.respond_to? :find_local_symbol result = result.find_local_symbol(method) end result end ## # URL for this with a +prefix+ def http_url(prefix) path = full_name path = path.gsub(/<<\s*(\w*)/, 'from-\1') if path =~ /<</ path = [prefix] + path.split('::') File.join(*path.compact) + '.html' end ## # Breaks method_list into a nested hash by type (class or instance) and # visibility (public, protected private) def methods_by_type methods = {} TYPES.each do |type| visibilities = {} VISIBILITIES.each do |vis| visibilities[vis] = [] end methods[type] = visibilities end each_method do |method| methods[method.type][method.visibility] << method end methods end ## # Yields Method and Attr entries matching the list of names in +methods+. # Attributes are only returned when +singleton+ is false. def methods_matching(methods, singleton = false) count = 0 @method_list.each do |m| if methods.include? m.name and m.singleton == singleton then yield m count += 1 end end return if count == methods.size || singleton @attributes.each do |a| yield a if methods.include? a.name end end ## # Array of modules in this context def modules @modules.values end ## # Hash of modules keyed by module name def modules_hash @modules end ## # Changes the visibility for new methods to +visibility+ def ongoing_visibility=(visibility) @visibility = visibility end ## # Record which file +top_level+ is in def record_location(top_level) @in_files << top_level unless @in_files.include?(top_level) end ## # If a class's documentation is turned off after we've started collecting # methods etc., we need to remove the ones we have def remove_methods_etc initialize_methods_etc end ## # Given an array +methods+ of method names, set the visibility of each to # +visibility+ def set_visibility_for(methods, visibility, singleton = false) methods_matching methods, singleton do |m| m.visibility = visibility end end ## # Removes classes and modules when we see a :nodoc: all def remove_classes_and_modules initialize_classes_and_modules end ## # Creates a new section with +title+ and +comment+ def set_current_section(title, comment) @current_section = Section.new self, title, comment @sections << @current_section end ## # Return the TopLevel that owns us def top_level return @top_level if defined? @top_level @top_level = self @top_level = @top_level.parent until RDoc::TopLevel === @top_level @top_level end end