powerhome-activeldap 3.2.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (145) hide show
  1. checksums.yaml +7 -0
  2. data/.yardopts +6 -0
  3. data/COPYING +340 -0
  4. data/Gemfile +12 -0
  5. data/LICENSE +59 -0
  6. data/README.textile +140 -0
  7. data/TODO +32 -0
  8. data/benchmark/README.md +64 -0
  9. data/benchmark/bench-backend.rb +247 -0
  10. data/benchmark/bench-instantiate.rb +98 -0
  11. data/benchmark/config.yaml.sample +5 -0
  12. data/doc/text/development.textile +54 -0
  13. data/doc/text/news.textile +811 -0
  14. data/doc/text/rails.textile +144 -0
  15. data/doc/text/tutorial.textile +1010 -0
  16. data/examples/config.yaml.example +5 -0
  17. data/examples/example.der +0 -0
  18. data/examples/example.jpg +0 -0
  19. data/examples/groupadd +41 -0
  20. data/examples/groupdel +35 -0
  21. data/examples/groupls +49 -0
  22. data/examples/groupmod +42 -0
  23. data/examples/lpasswd +55 -0
  24. data/examples/objects/group.rb +13 -0
  25. data/examples/objects/ou.rb +4 -0
  26. data/examples/objects/user.rb +20 -0
  27. data/examples/ouadd +38 -0
  28. data/examples/useradd +45 -0
  29. data/examples/useradd-binary +53 -0
  30. data/examples/userdel +34 -0
  31. data/examples/userls +50 -0
  32. data/examples/usermod +42 -0
  33. data/examples/usermod-binary-add +50 -0
  34. data/examples/usermod-binary-add-time +54 -0
  35. data/examples/usermod-binary-del +48 -0
  36. data/examples/usermod-lang-add +43 -0
  37. data/lib/active_ldap.rb +85 -0
  38. data/lib/active_ldap/action_controller/ldap_benchmarking.rb +55 -0
  39. data/lib/active_ldap/acts/tree.rb +78 -0
  40. data/lib/active_ldap/adapter/base.rb +707 -0
  41. data/lib/active_ldap/adapter/jndi.rb +184 -0
  42. data/lib/active_ldap/adapter/jndi_connection.rb +185 -0
  43. data/lib/active_ldap/adapter/ldap.rb +290 -0
  44. data/lib/active_ldap/adapter/ldap_ext.rb +105 -0
  45. data/lib/active_ldap/adapter/net_ldap.rb +309 -0
  46. data/lib/active_ldap/adapter/net_ldap_ext.rb +23 -0
  47. data/lib/active_ldap/association/belongs_to.rb +47 -0
  48. data/lib/active_ldap/association/belongs_to_many.rb +58 -0
  49. data/lib/active_ldap/association/children.rb +21 -0
  50. data/lib/active_ldap/association/collection.rb +105 -0
  51. data/lib/active_ldap/association/has_many.rb +31 -0
  52. data/lib/active_ldap/association/has_many_utils.rb +44 -0
  53. data/lib/active_ldap/association/has_many_wrap.rb +75 -0
  54. data/lib/active_ldap/association/proxy.rb +107 -0
  55. data/lib/active_ldap/associations.rb +205 -0
  56. data/lib/active_ldap/attribute_methods.rb +23 -0
  57. data/lib/active_ldap/attribute_methods/before_type_cast.rb +24 -0
  58. data/lib/active_ldap/attribute_methods/dirty.rb +43 -0
  59. data/lib/active_ldap/attribute_methods/query.rb +31 -0
  60. data/lib/active_ldap/attribute_methods/read.rb +44 -0
  61. data/lib/active_ldap/attribute_methods/write.rb +38 -0
  62. data/lib/active_ldap/attributes.rb +176 -0
  63. data/lib/active_ldap/base.rb +1410 -0
  64. data/lib/active_ldap/callbacks.rb +71 -0
  65. data/lib/active_ldap/command.rb +49 -0
  66. data/lib/active_ldap/compatible.rb +44 -0
  67. data/lib/active_ldap/configuration.rb +147 -0
  68. data/lib/active_ldap/connection.rb +299 -0
  69. data/lib/active_ldap/distinguished_name.rb +291 -0
  70. data/lib/active_ldap/entry_attribute.rb +78 -0
  71. data/lib/active_ldap/escape.rb +12 -0
  72. data/lib/active_ldap/get_text.rb +20 -0
  73. data/lib/active_ldap/get_text/parser.rb +161 -0
  74. data/lib/active_ldap/helper.rb +92 -0
  75. data/lib/active_ldap/human_readable.rb +133 -0
  76. data/lib/active_ldap/ldap_error.rb +74 -0
  77. data/lib/active_ldap/ldif.rb +930 -0
  78. data/lib/active_ldap/log_subscriber.rb +50 -0
  79. data/lib/active_ldap/object_class.rb +95 -0
  80. data/lib/active_ldap/operations.rb +624 -0
  81. data/lib/active_ldap/persistence.rb +100 -0
  82. data/lib/active_ldap/populate.rb +53 -0
  83. data/lib/active_ldap/railtie.rb +43 -0
  84. data/lib/active_ldap/railties/controller_runtime.rb +48 -0
  85. data/lib/active_ldap/schema.rb +701 -0
  86. data/lib/active_ldap/schema/syntaxes.rb +422 -0
  87. data/lib/active_ldap/timeout.rb +75 -0
  88. data/lib/active_ldap/timeout_stub.rb +17 -0
  89. data/lib/active_ldap/user_password.rb +99 -0
  90. data/lib/active_ldap/validations.rb +200 -0
  91. data/lib/active_ldap/version.rb +3 -0
  92. data/lib/active_ldap/xml.rb +139 -0
  93. data/lib/rails/generators/active_ldap/model/USAGE +18 -0
  94. data/lib/rails/generators/active_ldap/model/model_generator.rb +47 -0
  95. data/lib/rails/generators/active_ldap/model/templates/model_active_ldap.rb +3 -0
  96. data/lib/rails/generators/active_ldap/scaffold/scaffold_generator.rb +14 -0
  97. data/lib/rails/generators/active_ldap/scaffold/templates/ldap.yml +19 -0
  98. data/po/en/active-ldap.po +4029 -0
  99. data/po/ja/active-ldap.po +4060 -0
  100. data/test/add-phonetic-attribute-options-to-slapd.ldif +10 -0
  101. data/test/al-test-utils.rb +428 -0
  102. data/test/command.rb +111 -0
  103. data/test/config.yaml.sample +6 -0
  104. data/test/fixtures/lower_case_object_class_schema.rb +802 -0
  105. data/test/run-test.rb +34 -0
  106. data/test/test_acts_as_tree.rb +60 -0
  107. data/test/test_adapter.rb +121 -0
  108. data/test/test_associations.rb +701 -0
  109. data/test/test_attributes.rb +117 -0
  110. data/test/test_base.rb +1214 -0
  111. data/test/test_base_per_instance.rb +61 -0
  112. data/test/test_bind.rb +62 -0
  113. data/test/test_callback.rb +31 -0
  114. data/test/test_configuration.rb +40 -0
  115. data/test/test_connection.rb +82 -0
  116. data/test/test_connection_per_class.rb +112 -0
  117. data/test/test_connection_per_dn.rb +112 -0
  118. data/test/test_dirty.rb +98 -0
  119. data/test/test_dn.rb +172 -0
  120. data/test/test_find.rb +176 -0
  121. data/test/test_groupadd.rb +50 -0
  122. data/test/test_groupdel.rb +46 -0
  123. data/test/test_groupls.rb +107 -0
  124. data/test/test_groupmod.rb +51 -0
  125. data/test/test_ldif.rb +1890 -0
  126. data/test/test_load.rb +133 -0
  127. data/test/test_lpasswd.rb +75 -0
  128. data/test/test_object_class.rb +74 -0
  129. data/test/test_persistence.rb +131 -0
  130. data/test/test_reflection.rb +175 -0
  131. data/test/test_schema.rb +559 -0
  132. data/test/test_syntax.rb +444 -0
  133. data/test/test_user.rb +217 -0
  134. data/test/test_user_password.rb +108 -0
  135. data/test/test_useradd-binary.rb +62 -0
  136. data/test/test_useradd.rb +57 -0
  137. data/test/test_userdel.rb +48 -0
  138. data/test/test_userls.rb +91 -0
  139. data/test/test_usermod-binary-add-time.rb +65 -0
  140. data/test/test_usermod-binary-add.rb +64 -0
  141. data/test/test_usermod-binary-del.rb +66 -0
  142. data/test/test_usermod-lang-add.rb +59 -0
  143. data/test/test_usermod.rb +58 -0
  144. data/test/test_validation.rb +274 -0
  145. metadata +379 -0
@@ -0,0 +1,46 @@
1
+ require 'al-test-utils'
2
+
3
+ class TestGroupdel < Test::Unit::TestCase
4
+ include AlTestUtils
5
+
6
+ def setup
7
+ super
8
+ @command = File.join(@examples_dir, "groupdel")
9
+ end
10
+
11
+ priority :must
12
+
13
+ priority :normal
14
+ def test_non_exist_group
15
+ ensure_delete_group("test-group") do |name|
16
+ assert(!@group_class.exists?(name))
17
+ assert_equal([false, "Group #{name} doesn't exist.\n"], run_command(name))
18
+ assert(!@group_class.exists?(name))
19
+ end
20
+ end
21
+
22
+ def test_delete_group
23
+ make_temporary_group do |group|
24
+ assert_groupdel_successfully(group.id)
25
+ end
26
+ end
27
+
28
+ private
29
+ def assert_groupdel_successfully(name, *args, &block)
30
+ _wrap_assertion do
31
+ assert(@group_class.exists?(name))
32
+ args.concat([name])
33
+ assert_equal([true, ""], run_command(*args, &block))
34
+ assert(!@group_class.exists?(name))
35
+ end
36
+ end
37
+
38
+ def assert_groupdel_failed(name, message, *args, &block)
39
+ _wrap_assertion do
40
+ assert(@group_class.exists?(name))
41
+ args.concat([name])
42
+ assert_equal([false, message], run_command(*args, &block))
43
+ assert(@group_class.exists?(name))
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,107 @@
1
+ require 'al-test-utils'
2
+
3
+ class TestGroupls < Test::Unit::TestCase
4
+ include AlTestUtils
5
+
6
+ def setup
7
+ super
8
+ @command = File.join(@examples_dir, "groupls")
9
+ make_ou("People")
10
+ @user_class.prefix = "ou=People"
11
+ end
12
+
13
+ priority :must
14
+
15
+ priority :normal
16
+ def test_non_exist_group
17
+ ensure_delete_group("test-group") do |name|
18
+ assert(!@group_class.exists?(name))
19
+ assert_equal([false, "Group #{name} doesn't exist.\n"], run_command(name))
20
+ assert(!@group_class.exists?(name))
21
+ end
22
+ end
23
+
24
+ def test_list_group_no_group
25
+ make_temporary_group do |group|
26
+ assert_groupls_successfully(group.id, [])
27
+ end
28
+ end
29
+
30
+ def test_list_group_have_primary_members
31
+ make_temporary_group do |group|
32
+ make_temporary_user(:gid_number => group.gid_number) do |user1,|
33
+ make_temporary_user(:gid_number => group.gid_number) do |user2,|
34
+ assert_groupls_successfully(group.id, [user1, user2])
35
+ end
36
+ end
37
+ end
38
+ end
39
+
40
+ def test_list_group_have_members
41
+ make_temporary_user do |user1,|
42
+ make_temporary_user do |user2,|
43
+ make_temporary_group do |group|
44
+ group.members << user1
45
+ group.members << user2
46
+ assert_groupls_successfully(group.id, [user1, user2])
47
+ end
48
+ end
49
+ end
50
+ end
51
+
52
+ def test_list_group_have_members_and_primary_members
53
+ make_temporary_group do |group|
54
+ options = {:gid_number => group.gid_number}
55
+ make_temporary_user(options) do |primary_user1,|
56
+ make_temporary_user(options) do |primary_user2,|
57
+ options1 = {:gid_number => group.gid_number.succ}
58
+ options2 = {:gid_number => group.gid_number.succ.succ}
59
+ make_temporary_user(options1) do |user1,|
60
+ make_temporary_user(options2) do |user2,|
61
+ group.members << user1
62
+ group.members << user2
63
+ assert_groupls_successfully(group.id,
64
+ [primary_user1, primary_user2,
65
+ user1, user2])
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
72
+
73
+ def test_list_group_have_non_exist_member
74
+ make_temporary_group do |group|
75
+ options = {:gid_number => group.gid_number.succ}
76
+ make_temporary_user(options) do |user,|
77
+ group.member_uid = [user.id]
78
+ assert(group.save)
79
+ assert_groupls_successfully(group.id, [user])
80
+ end
81
+ end
82
+ end
83
+
84
+ private
85
+ def assert_groupls_successfully(name, members, *args, &block)
86
+ _wrap_assertion do
87
+ assert(@group_class.exists?(name))
88
+ args.concat([name])
89
+ group = @group_class.find(name)
90
+ members = members.collect do |m|
91
+ "#{m.uid}[#{m.new_entry? ? '????' : m.uid_number}]"
92
+ end
93
+ result = "#{group.cn}(#{group.gid_number}): #{members.join(', ')}\n"
94
+ assert_equal([true, result], run_command(*args, &block))
95
+ assert(@group_class.exists?(name))
96
+ end
97
+ end
98
+
99
+ def assert_groupls_failed(name, message, *args, &block)
100
+ _wrap_assertion do
101
+ assert(@group_class.exists?(name))
102
+ args.concat([name])
103
+ assert_equal([false, message], run_command(*args, &block))
104
+ assert(@group_class.exists?(name))
105
+ end
106
+ end
107
+ end
@@ -0,0 +1,51 @@
1
+ require 'al-test-utils'
2
+
3
+ class TestGroupmod < Test::Unit::TestCase
4
+ include AlTestUtils
5
+
6
+ def setup
7
+ super
8
+ @command = File.join(@examples_dir, "groupmod")
9
+ end
10
+
11
+ priority :must
12
+
13
+ priority :normal
14
+ def test_non_exist_group
15
+ ensure_delete_group("test-group") do |name|
16
+ assert(!@group_class.exists?(name))
17
+ assert_equal([false, "Group #{name} doesn't exist.\n"],
18
+ run_command(name, 111111))
19
+ assert(!@group_class.exists?(name))
20
+ end
21
+ end
22
+
23
+ def test_modify_group
24
+ make_temporary_group do |group|
25
+ assert_groupmod_successfully(group.cn, group.gid_number.succ)
26
+ end
27
+ end
28
+
29
+ private
30
+ def assert_groupmod_successfully(name, gid, *args, &block)
31
+ _wrap_assertion do
32
+ assert(@group_class.exists?(name))
33
+ args.concat([name, gid])
34
+ assert_equal([true, ""], run_command(*args, &block))
35
+ assert(@group_class.exists?(name))
36
+
37
+ group = @group_class.find(name)
38
+ assert_equal(name, group.cn)
39
+ assert_equal(gid, group.gid_number)
40
+ end
41
+ end
42
+
43
+ def assert_groupmod_failed(name, gid, message, *args, &block)
44
+ _wrap_assertion do
45
+ assert(@group_class.exists?(name))
46
+ args.concat([name, gid])
47
+ assert_equal([false, message], run_command(*args, &block))
48
+ assert(@group_class.exists?(name))
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,1890 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ require 'al-test-utils'
4
+
5
+ class TestLDIF < Test::Unit::TestCase
6
+ include ActiveLdap::GetTextSupport
7
+ include AlTestUtils::Config
8
+ include AlTestUtils::ExampleFile
9
+
10
+ priority :must
11
+ def test_integer_attribute_value_to_s
12
+ dn = ActiveLdap::DN.parse("uid=user,ou=People,dc=example,dc=com")
13
+ record = ActiveLdap::Ldif::Record.new(dn, {"uidNumber" => [100]})
14
+ assert_equal(<<-EOL, record.to_s)
15
+ dn: uid=user,ou=People,dc=example,dc=com
16
+ uidNumber: 100
17
+ EOL
18
+ end
19
+
20
+ priority :normal
21
+ def test_accept_empty_lines_after_content
22
+ ldif_source = <<-EOL
23
+ version: 1
24
+ dn: dc=devel,dc=example,dc=com
25
+ dc: devel
26
+ objectClass: top
27
+ objectClass: dcObject
28
+ objectClass: organization
29
+ o: devel
30
+ EOL
31
+
32
+ expected_ldif_to_s = <<-EOL
33
+ version: 1
34
+ dn: dc=devel,dc=example,dc=com
35
+ dc: devel
36
+ o: devel
37
+ objectClass: dcObject
38
+ objectClass: organization
39
+ objectClass: top
40
+ EOL
41
+
42
+
43
+ assert_ldif_to_s(expected_ldif_to_s, ldif_source)
44
+ assert_ldif_to_s(expected_ldif_to_s, ldif_source + "\n")
45
+ assert_ldif_to_s(expected_ldif_to_s, ldif_source + "\n\n")
46
+ assert_ldif_to_s(expected_ldif_to_s, ldif_source + ("\n" * 10))
47
+ end
48
+
49
+ def test_accept_comments_after_content
50
+ ldif_source = <<-EOL
51
+ version: 1
52
+ dn: dc=devel,dc=example,dc=com
53
+ dc: devel
54
+ objectClass: top
55
+ objectClass: dcObject
56
+ objectClass: organization
57
+ o: devel
58
+
59
+ # search result
60
+
61
+ # numResponse: 1
62
+ # numEntries: 1
63
+
64
+ EOL
65
+
66
+ assert_ldif_to_s(<<-EOL, ldif_source)
67
+ version: 1
68
+ dn: dc=devel,dc=example,dc=com
69
+ dc: devel
70
+ o: devel
71
+ objectClass: dcObject
72
+ objectClass: organization
73
+ objectClass: top
74
+ EOL
75
+ end
76
+
77
+ def test_comments_and_empty_lines_before_content
78
+ ldif_source = <<-EOL
79
+ version: 1
80
+
81
+ #
82
+ # LDAPv3
83
+ # base <dc=devel,dc=clear-code,dc=com> with scope subtree
84
+ # filter: (objectclass=*)
85
+ # requesting: ALL
86
+ #
87
+
88
+ # devel.example.com
89
+ dn: dc=devel,dc=example,dc=com
90
+ dc: devel
91
+ objectClass: top
92
+ objectClass: dcObject
93
+ objectClass: organization
94
+ o: devel
95
+ EOL
96
+
97
+ assert_ldif_to_s(<<-EOL, ldif_source)
98
+ version: 1
99
+ dn: dc=devel,dc=example,dc=com
100
+ dc: devel
101
+ o: devel
102
+ objectClass: dcObject
103
+ objectClass: organization
104
+ objectClass: top
105
+ EOL
106
+ end
107
+
108
+ def test_unknown_change_type
109
+ ldif_source = <<-EOL
110
+ version: 1
111
+ dn: ou=Product Development, dc=airius, dc=com
112
+ changetype: XXX
113
+ EOL
114
+
115
+ ldif_source_with_error_mark = <<-EOL
116
+ changetype: |@|XXX
117
+ EOL
118
+
119
+ assert_invalid_ldif(["unknown change type: %s", "XXX"],
120
+ ldif_source, 3, 13, ldif_source_with_error_mark)
121
+ end
122
+
123
+ def test_unknown_modify_type
124
+ ldif_source = <<-EOL
125
+ version: 1
126
+ dn: ou=Product Development, dc=airius, dc=com
127
+ changetype: modify
128
+ XXX: postaladdress
129
+ -
130
+ EOL
131
+
132
+ ldif_source_with_error_mark = <<-EOL
133
+ |@|XXX: postaladdress
134
+ EOL
135
+
136
+ assert_invalid_ldif(["unknown modify type: %s", "XXX"],
137
+ ldif_source, 4, 1, ldif_source_with_error_mark)
138
+ end
139
+
140
+ def test_modify_spec_block_separator_is_missing
141
+ ldif_source = <<-EOL
142
+ version: 1
143
+ dn: ou=Product Development, dc=airius, dc=com
144
+ changetype: modify
145
+ add: postaladdress
146
+ EOL
147
+
148
+ ldif_source_with_error_mark = <<-EOL.chomp
149
+ add: postaladdress
150
+ |@|
151
+ EOL
152
+
153
+ assert_invalid_ldif("'-' is missing",
154
+ ldif_source, 5, 1, ldif_source_with_error_mark)
155
+ end
156
+
157
+ def test_modify_spec_first_line_separator_is_missing
158
+ ldif_source = <<-EOL.chomp
159
+ version: 1
160
+ dn: ou=Product Development, dc=airius, dc=com
161
+ changetype: modify
162
+ add: postaladdress
163
+ EOL
164
+
165
+ ldif_source_with_error_mark = <<-EOL.chomp
166
+ add: postaladdress|@|
167
+ EOL
168
+
169
+ assert_invalid_ldif("separator is missing",
170
+ ldif_source, 4, 19, ldif_source_with_error_mark)
171
+ end
172
+
173
+ def test_modify_target_attribute_name_is_missing
174
+ ldif_source = <<-EOL
175
+ version: 1
176
+ dn: ou=Product Development, dc=airius, dc=com
177
+ changetype: modify
178
+ add:
179
+ -
180
+ EOL
181
+
182
+ ldif_source_with_error_mark = <<-EOL
183
+ add:|@|
184
+ EOL
185
+
186
+ assert_invalid_ldif("attribute type is missing",
187
+ ldif_source, 4, 5, ldif_source_with_error_mark)
188
+ end
189
+
190
+ def test_newsuperior_separator_is_missing
191
+ ldif_source = <<-EOL.chomp
192
+ version: 1
193
+ dn: ou=Product Development, dc=airius, dc=com
194
+ changetype: moddn
195
+ newrdn: cn=Paula Jensen
196
+ deleteoldrdn: 1
197
+ newsuperior: ou=Accounting, dc=airius, dc=com
198
+ EOL
199
+
200
+ ldif_source_with_error_mark = <<-EOL.chomp
201
+ newsuperior: ou=Accounting, dc=airius, dc=com|@|
202
+ EOL
203
+
204
+ assert_invalid_ldif("separator is missing",
205
+ ldif_source, 6, 46, ldif_source_with_error_mark)
206
+ end
207
+
208
+ def test_newsuperior_value_is_missing
209
+ ldif_source = <<-EOL
210
+ version: 1
211
+ dn: ou=Product Development, dc=airius, dc=com
212
+ changetype: moddn
213
+ newrdn: cn=Paula Jensen
214
+ deleteoldrdn: 1
215
+ newsuperior:
216
+ EOL
217
+
218
+ ldif_source_with_error_mark = <<-EOL
219
+ newsuperior:|@|
220
+ EOL
221
+
222
+ assert_invalid_ldif("new superior value is missing",
223
+ ldif_source, 6, 13, ldif_source_with_error_mark)
224
+ end
225
+
226
+ def test_deleteoldrdn_separator_is_missing
227
+ ldif_source = <<-EOL.chomp
228
+ version: 1
229
+ dn: ou=Product Development, dc=airius, dc=com
230
+ changetype: moddn
231
+ newrdn: cn=Paula Jensen
232
+ deleteoldrdn: 1
233
+ EOL
234
+
235
+ ldif_source_with_error_mark = <<-EOL.chomp
236
+ deleteoldrdn: 1|@|
237
+ EOL
238
+
239
+ assert_invalid_ldif("separator is missing",
240
+ ldif_source, 5, 16, ldif_source_with_error_mark)
241
+ end
242
+
243
+ def test_invalid_deleteoldrdn_value
244
+ ldif_source = <<-EOL
245
+ version: 1
246
+ dn: ou=Product Development, dc=airius, dc=com
247
+ changetype: moddn
248
+ newrdn: cn=Paula Jensen
249
+ deleteoldrdn: x
250
+ EOL
251
+
252
+ ldif_source_with_error_mark = <<-EOL
253
+ deleteoldrdn: |@|x
254
+ EOL
255
+
256
+ assert_invalid_ldif("delete old RDN value is missing",
257
+ ldif_source, 5, 15, ldif_source_with_error_mark)
258
+ end
259
+
260
+ def test_deleteoldrdn_value_is_missing
261
+ ldif_source = <<-EOL
262
+ version: 1
263
+ dn: ou=Product Development, dc=airius, dc=com
264
+ changetype: moddn
265
+ newrdn: cn=Paula Jensen
266
+ deleteoldrdn:
267
+ EOL
268
+
269
+ ldif_source_with_error_mark = <<-EOL
270
+ deleteoldrdn:|@|
271
+ EOL
272
+
273
+ assert_invalid_ldif("delete old RDN value is missing",
274
+ ldif_source, 5, 14, ldif_source_with_error_mark)
275
+ end
276
+
277
+ def test_deleteoldrdn_mark_is_missing
278
+ ldif_source = <<-EOL
279
+ version: 1
280
+ dn: ou=Product Development, dc=airius, dc=com
281
+ changetype: moddn
282
+ newrdn: cn=Paula Jensen
283
+ EOL
284
+
285
+ ldif_source_with_error_mark = <<-EOL.chomp
286
+ newrdn: cn=Paula Jensen
287
+ |@|
288
+ EOL
289
+
290
+ assert_invalid_ldif("'deleteoldrdn:' is missing",
291
+ ldif_source, 5, 1, ldif_source_with_error_mark)
292
+ end
293
+
294
+ def test_newrdn_separator_is_missing
295
+ ldif_source = <<-EOL.chomp
296
+ version: 1
297
+ dn: ou=Product Development, dc=airius, dc=com
298
+ changetype: moddn
299
+ newrdn: cn=Paula Jensen
300
+ EOL
301
+
302
+ ldif_source_with_error_mark = <<-EOL.chomp
303
+ newrdn: cn=Paula Jensen|@|
304
+ EOL
305
+
306
+ assert_invalid_ldif("separator is missing",
307
+ ldif_source, 4, 24, ldif_source_with_error_mark)
308
+ end
309
+
310
+ def test_newrdn_value_is_missing
311
+ ldif_source = <<-EOL
312
+ version: 1
313
+ dn: ou=Product Development, dc=airius, dc=com
314
+ changetype: moddn
315
+ newrdn:
316
+ EOL
317
+
318
+ ldif_source_with_error_mark = <<-EOL
319
+ newrdn:|@|
320
+ EOL
321
+
322
+ assert_invalid_ldif("new RDN value is missing",
323
+ ldif_source, 4, 8, ldif_source_with_error_mark)
324
+ end
325
+
326
+ def test_newrdn_mark_is_missing
327
+ ldif_source = <<-EOL
328
+ version: 1
329
+ dn: ou=Product Development, dc=airius, dc=com
330
+ changetype: moddn
331
+ EOL
332
+
333
+ ldif_source_with_error_mark = <<-EOL.chomp
334
+ changetype: moddn
335
+ |@|
336
+ EOL
337
+
338
+ assert_invalid_ldif("'newrdn:' is missing",
339
+ ldif_source, 4, 1, ldif_source_with_error_mark)
340
+ end
341
+
342
+ def test_add_change_type_without_attribute
343
+ ldif_source = <<-EOL
344
+ version: 1
345
+ dn: ou=Product Development, dc=airius, dc=com
346
+ changetype: add
347
+ EOL
348
+
349
+ ldif_source_with_error_mark = <<-EOL.chomp
350
+ changetype: add
351
+ |@|
352
+ EOL
353
+
354
+ assert_invalid_ldif("attribute spec is missing",
355
+ ldif_source, 4, 1, ldif_source_with_error_mark)
356
+ end
357
+
358
+ def test_change_type_with_an_extra_space
359
+ ldif_source = <<-EOL
360
+ version: 1
361
+ dn: ou=Product Development, dc=airius, dc=com
362
+ changetype: delete
363
+ EOL
364
+
365
+ ldif_source_with_error_mark = <<-EOL
366
+ changetype: delete|@|
367
+ EOL
368
+
369
+ assert_invalid_ldif("separator is missing",
370
+ ldif_source, 3, 19, ldif_source_with_error_mark)
371
+ end
372
+
373
+ def test_change_type_separator_is_missing
374
+ ldif_source = <<-EOL.chomp
375
+ version: 1
376
+ dn: ou=Product Development, dc=airius, dc=com
377
+ changetype: delete
378
+ EOL
379
+
380
+ ldif_source_with_error_mark = <<-EOL.chomp
381
+ changetype: delete|@|
382
+ EOL
383
+
384
+ assert_invalid_ldif("separator is missing",
385
+ ldif_source, 3, 19, ldif_source_with_error_mark)
386
+ end
387
+
388
+ def test_change_type_value_is_missing
389
+ ldif_source = <<-EOL
390
+ version: 1
391
+ dn: ou=Product Development, dc=airius, dc=com
392
+ changetype:
393
+ EOL
394
+
395
+ ldif_source_with_error_mark = <<-EOL
396
+ changetype:|@|
397
+ EOL
398
+
399
+ assert_invalid_ldif("change type value is missing",
400
+ ldif_source, 3, 12, ldif_source_with_error_mark)
401
+ end
402
+
403
+ def test_control_separator_is_missing
404
+ ldif_source = <<-EOL.chomp
405
+ version: 1
406
+ dn: ou=Product Development, dc=airius, dc=com
407
+ control: 1.2.840.113556.1.4.805 true
408
+ EOL
409
+
410
+ ldif_source_with_error_mark = <<-EOL.chomp
411
+ control: 1.2.840.113556.1.4.805 true|@|
412
+ EOL
413
+
414
+ assert_invalid_ldif("separator is missing",
415
+ ldif_source, 3, 37, ldif_source_with_error_mark)
416
+ end
417
+
418
+ def test_criticality_is_missing
419
+ ldif_source = <<-EOL
420
+ version: 1
421
+ dn: ou=Product Development, dc=airius, dc=com
422
+ control: 1.2.840.113556.1.4.805
423
+ EOL
424
+
425
+ ldif_source_with_error_mark = <<-EOL
426
+ control: 1.2.840.113556.1.4.805 |@|
427
+ EOL
428
+
429
+ assert_invalid_ldif("criticality is missing",
430
+ ldif_source, 3, 33, ldif_source_with_error_mark)
431
+ end
432
+
433
+ def test_control_type_is_missing
434
+ ldif_source = <<-EOL
435
+ version: 1
436
+ dn: ou=Product Development, dc=airius, dc=com
437
+ control:
438
+ EOL
439
+
440
+ ldif_source_with_error_mark = <<-EOL
441
+ control:|@|
442
+ EOL
443
+
444
+ assert_invalid_ldif("control type is missing",
445
+ ldif_source, 3, 9, ldif_source_with_error_mark)
446
+ end
447
+
448
+ def test_change_type_is_missing
449
+ ldif_source = <<-EOL
450
+ version: 1
451
+ dn: ou=Product Development, dc=airius, dc=com
452
+ control: 1.2.840.113556.1.4.805 true
453
+ EOL
454
+
455
+ ldif_source_with_error_mark = <<-EOL.chomp
456
+ control: 1.2.840.113556.1.4.805 true
457
+ |@|
458
+ EOL
459
+
460
+ assert_invalid_ldif("change type is missing",
461
+ ldif_source, 4, 1, ldif_source_with_error_mark)
462
+ end
463
+
464
+ def test_invalid_dn
465
+ ldif_source = <<-EOL
466
+ version: 1
467
+ dn: ou=o=Airius
468
+ EOL
469
+
470
+ ldif_source_with_error_mark = <<-EOL
471
+ dn: ou=o=Airius|@|
472
+ EOL
473
+
474
+ assert_invalid_ldif(["DN is invalid: %s: %s",
475
+ "ou=o=Airius", "attribute type is missing"],
476
+ ldif_source, 2, 16, ldif_source_with_error_mark)
477
+ end
478
+
479
+ def test_invalid_dn_value
480
+ ldif_source = <<-EOL
481
+ version: 1
482
+ # dn:: ou=<JapaneseOU>,o=Airius
483
+ dn: ou=営業部,o=Airius
484
+ EOL
485
+
486
+ ldif_source_with_error_mark = <<-EOL
487
+ dn: ou=|@|営業部,o=Airius
488
+ EOL
489
+
490
+ assert_invalid_ldif(["DN has an invalid character: %s", "営"],
491
+ ldif_source, 3, 8, ldif_source_with_error_mark)
492
+ end
493
+
494
+ def test_multi_records_without_separator
495
+ ldif_source = <<-EOL
496
+ version: 1
497
+ dn: ou=Product Development, dc=airius, dc=com
498
+ changetype: delete
499
+ dn: cn=Fiona Jensen, ou=Marketing, dc=airius, dc=com
500
+ seealso:
501
+ description::
502
+ EOL
503
+
504
+ ldif_source_with_error_mark = <<-EOL
505
+ |@|dn: cn=Fiona Jensen, ou=Marketing, dc=airius, dc=com
506
+ EOL
507
+
508
+ assert_invalid_ldif("separator is missing", ldif_source,
509
+ 4, 1, ldif_source_with_error_mark)
510
+ end
511
+
512
+ def test_to_s_with_blank_value
513
+ ldif_source = <<-EOL
514
+ version: 1
515
+ dn: ou=Product Development,dc=airius,dc=com
516
+ seealso:
517
+ description::
518
+ EOL
519
+
520
+ assert_ldif_to_s(<<-EOL, ldif_source)
521
+ version: 1
522
+ dn: ou=Product Development,dc=airius,dc=com
523
+ description:
524
+ seealso:
525
+ EOL
526
+ end
527
+
528
+ def test_to_s_with_last_space
529
+ ldif_source = <<-EOL
530
+ version: 1
531
+ # 'ou=Product Development,dc=airius,dc=com '
532
+ dn:: b3U9UHJvZHVjdCBEZXZlbG9wbWVudCwgZGM9YWlyaXVzLCBkYz1jb20g
533
+ # 'ou=Product Development,dc=airius,dc=com '
534
+ description:: b3U9UHJvZHVjdCBEZXZlbG9wbWVudCwgZGM9YWlyaXVzLCBkYz1jb20g
535
+ EOL
536
+
537
+ assert_ldif_to_s(<<-EOL, ldif_source)
538
+ version: 1
539
+ dn: ou=Product Development,dc=airius,dc="com "
540
+ description:: b3U9UHJvZHVjdCBEZXZlbG9wbWVudCwgZGM9YWlyaXVzLCBkYz1jb20g
541
+ EOL
542
+ end
543
+
544
+ def test_change_record_with_control
545
+ ldif_source = <<-EOL
546
+ version: 1
547
+ # Delete an entry. The operation will attach the LDAPv3
548
+ # Tree Delete Control defined in [9]. The criticality
549
+ # field is "true" and the controlValue field is
550
+ # absent, as required by [9].
551
+ dn: ou=Product Development, dc=airius, dc=com
552
+ control: 1.2.840.113556.1.4.805 true
553
+ changetype: delete
554
+ EOL
555
+
556
+ change_attributes = {
557
+ "dn" => "ou=Product Development,dc=airius,dc=com",
558
+ }
559
+
560
+ ldif = assert_ldif(1, [change_attributes], ldif_source)
561
+ record = ldif.records[0]
562
+ assert_equal("delete", record.change_type)
563
+ assert_true(record.delete?)
564
+ assert_equal([{
565
+ :type => "1.2.840.113556.1.4.805",
566
+ :criticality => true,
567
+ :value => nil
568
+ }],
569
+ record.controls.collect {|control| control.to_hash})
570
+
571
+ control = record.controls[0]
572
+ assert_equal("1.2.840.113556.1.4.805", control.type)
573
+ assert_true(control.criticality?)
574
+ assert_nil(control.value)
575
+ end
576
+
577
+ def test_change_record_with_control_to_s
578
+ ldif_source = <<-EOL
579
+ version: 1
580
+ # Delete an entry. The operation will attach the LDAPv3
581
+ # Tree Delete Control defined in [9]. The criticality
582
+ # field is "true" and the controlValue field is
583
+ # absent, as required by [9].
584
+ dn: ou=Product Development, dc=airius, dc=com
585
+ control: 1.2.840.113556.1.4.805 true
586
+ changetype: delete
587
+ EOL
588
+
589
+ assert_ldif_to_s(<<-EOL, ldif_source)
590
+ version: 1
591
+ dn: ou=Product Development,dc=airius,dc=com
592
+ control: 1.2.840.113556.1.4.805 true
593
+ changetype: delete
594
+ EOL
595
+ end
596
+
597
+ def test_multi_change_type_records
598
+ ldif_source = <<-EOL
599
+ version: 1
600
+ # Add a new entry
601
+ dn: cn=Fiona Jensen, ou=Marketing, dc=airius, dc=com
602
+ changetype: add
603
+ objectclass: top
604
+ objectclass: person
605
+ objectclass: organizationalPerson
606
+ cn: Fiona Jensen
607
+ sn: Jensen
608
+ uid: fiona
609
+ telephonenumber: +1 408 555 1212
610
+
611
+ # Delete an existing entry
612
+ dn: cn=Robert Jensen, ou=Marketing, dc=airius, dc=com
613
+ changetype: delete
614
+
615
+ # Modify an entry's relative distinguished name
616
+ dn: cn=Paul Jensen, ou=Product Development, dc=airius, dc=com
617
+ changetype: modrdn
618
+ newrdn: cn=Paula Jensen
619
+ deleteoldrdn: 1
620
+
621
+ # Rename an entry and move all of its children to a new location in
622
+ # the directory tree (only implemented by LDAPv3 servers).
623
+ dn: ou=PD Accountants, ou=Product Development, dc=airius, dc=com
624
+ changetype: modrdn
625
+ newrdn: ou=Product Development Accountants
626
+ deleteoldrdn: 0
627
+ newsuperior: ou=Accounting, dc=airius, dc=com
628
+
629
+ # Modify an entry: add an additional value to the postaladdress
630
+ # attribute, completely delete the description attribute, replace
631
+ # the telephonenumber attribute with two values, and delete a specific
632
+ # value from the facsimiletelephonenumber attribute
633
+ dn: cn=Paula Jensen, ou=Product Development, dc=airius, dc=com
634
+ changetype: modify
635
+ add: postaladdress
636
+ postaladdress: 123 Anystreet $ Sunnyvale, CA $ 94086
637
+ -
638
+ delete: description
639
+ -
640
+ replace: telephonenumber
641
+ telephonenumber: +1 408 555 1234
642
+ telephonenumber: +1 408 555 5678
643
+ -
644
+ delete: facsimiletelephonenumber
645
+ facsimiletelephonenumber: +1 408 555 9876
646
+ -
647
+
648
+ # Modify an entry: replace the postaladdress attribute with an empty
649
+ # set of values (which will cause the attribute to be removed), and
650
+ # delete the entire description attribute. Note that the first will
651
+ # always succeed, while the second will only succeed if at least
652
+ # one value for the description attribute is present.
653
+ dn: cn=Ingrid Jensen, ou=Product Support, dc=airius, dc=com
654
+ changetype: modify
655
+ replace: postaladdress
656
+ -
657
+ delete: description
658
+ -
659
+ EOL
660
+
661
+ assert_ldif_to_s(<<-EOL, ldif_source)
662
+ version: 1
663
+ dn: cn=Fiona Jensen,ou=Marketing,dc=airius,dc=com
664
+ changetype: add
665
+ cn: Fiona Jensen
666
+ objectclass: organizationalPerson
667
+ objectclass: person
668
+ objectclass: top
669
+ sn: Jensen
670
+ telephonenumber: +1 408 555 1212
671
+ uid: fiona
672
+
673
+ dn: cn=Robert Jensen,ou=Marketing,dc=airius,dc=com
674
+ changetype: delete
675
+
676
+ dn: cn=Paul Jensen,ou=Product Development,dc=airius,dc=com
677
+ changetype: modrdn
678
+ newrdn: cn=Paula Jensen
679
+ deleteoldrdn: 1
680
+
681
+ dn: ou=PD Accountants,ou=Product Development,dc=airius,dc=com
682
+ changetype: modrdn
683
+ newrdn: ou=Product Development Accountants
684
+ deleteoldrdn: 0
685
+ newsuperior: ou=Accounting,dc=airius,dc=com
686
+
687
+ dn: cn=Paula Jensen,ou=Product Development,dc=airius,dc=com
688
+ changetype: modify
689
+ add: postaladdress
690
+ postaladdress: 123 Anystreet $ Sunnyvale, CA $ 94086
691
+ -
692
+ delete: description
693
+ -
694
+ replace: telephonenumber
695
+ telephonenumber: +1 408 555 1234
696
+ telephonenumber: +1 408 555 5678
697
+ -
698
+ delete: facsimiletelephonenumber
699
+ facsimiletelephonenumber: +1 408 555 9876
700
+ -
701
+
702
+ dn: cn=Ingrid Jensen,ou=Product Support,dc=airius,dc=com
703
+ changetype: modify
704
+ replace: postaladdress
705
+ -
706
+ delete: description
707
+ -
708
+ EOL
709
+
710
+ change_attributes_add = {
711
+ "dn" => "cn=Fiona Jensen,ou=Marketing,dc=airius,dc=com",
712
+ "objectclass" => ["top", "person", "organizationalPerson"],
713
+ "cn" => ["Fiona Jensen"],
714
+ "sn" => ["Jensen"],
715
+ "uid" => ["fiona"],
716
+ "telephonenumber" => ["+1 408 555 1212"],
717
+ }
718
+
719
+ change_attributes_delete = {
720
+ "dn" => "cn=Robert Jensen,ou=Marketing,dc=airius,dc=com",
721
+ }
722
+
723
+ change_attributes_modrdn = {
724
+ "dn" => "cn=Paul Jensen,ou=Product Development,dc=airius,dc=com",
725
+ }
726
+
727
+ change_attributes_modrdn_with_new_superior = {
728
+ "dn" => "ou=PD Accountants,ou=Product Development,dc=airius,dc=com",
729
+ }
730
+
731
+ change_attributes_modify = {
732
+ "dn" => "cn=Paula Jensen,ou=Product Development,dc=airius,dc=com",
733
+ }
734
+
735
+ change_attributes_modify_with_empty_replace = {
736
+ "dn" => "cn=Ingrid Jensen,ou=Product Support,dc=airius,dc=com",
737
+ }
738
+
739
+ ldif = assert_ldif(1,
740
+ [change_attributes_add,
741
+ change_attributes_delete,
742
+ change_attributes_modrdn,
743
+ change_attributes_modrdn_with_new_superior,
744
+ change_attributes_modify,
745
+ change_attributes_modify_with_empty_replace],
746
+ ldif_source)
747
+ record = ldif.records[0]
748
+ assert_equal("add", record.change_type)
749
+ assert_true(record.add?)
750
+
751
+ record = ldif.records[1]
752
+ assert_equal("delete", record.change_type)
753
+ assert_true(record.delete?)
754
+
755
+ record = ldif.records[2]
756
+ assert_equal("modrdn", record.change_type)
757
+ assert_true(record.modify_rdn?)
758
+ assert_equal("cn=Paula Jensen", record.new_rdn)
759
+ assert_true(record.delete_old_rdn?)
760
+ assert_nil(record.new_superior)
761
+
762
+ record = ldif.records[3]
763
+ assert_equal("modrdn", record.change_type)
764
+ assert_true(record.modify_rdn?)
765
+ assert_equal("ou=Product Development Accountants", record.new_rdn)
766
+ assert_false(record.delete_old_rdn?)
767
+ assert_equal("ou=Accounting,dc=airius,dc=com", record.new_superior)
768
+
769
+ record = ldif.records[4]
770
+ assert_equal("modify", record.change_type)
771
+ assert_true(record.modify?)
772
+ operations = [
773
+ ["add", "postaladdress",
774
+ {"postaladdress" =>
775
+ ["123 Anystreet $ Sunnyvale, CA $ 94086"]}],
776
+ ["delete", "description", {}],
777
+ ["replace", "telephonenumber",
778
+ {"telephonenumber" => [
779
+ "+1 408 555 1234",
780
+ "+1 408 555 5678",
781
+ ]}],
782
+ ["delete", "facsimiletelephonenumber",
783
+ {"facsimiletelephonenumber" => ["+1 408 555 9876"]}],
784
+ ]
785
+ i = -1
786
+ actual = record.operations.collect do |operation|
787
+ i += 1
788
+ type = operations[i][0]
789
+ [operation.send("#{type}?"),
790
+ [operation.type, operation.attribute, operation.attributes]]
791
+ end
792
+ assert_equal(operations.collect {|operation| [true, operation]},
793
+ actual)
794
+
795
+ record = ldif.records[5]
796
+ assert_equal("modify", record.change_type)
797
+ assert_true(record.modify?)
798
+ operations = [
799
+ ["replace", "postaladdress", {}],
800
+ ["delete", "description", {}],
801
+ ]
802
+ i = -1
803
+ actual = record.operations.collect do |operation|
804
+ i += 1
805
+ type = operations[i][0]
806
+ [operation.send("#{type}?"),
807
+ [operation.type, operation.attribute, operation.attributes]]
808
+ end
809
+ assert_equal(operations.collect {|operation| [true, operation]},
810
+ actual)
811
+ end
812
+
813
+ def test_modify_record
814
+ ldif_source = <<-EOL
815
+ version: 1
816
+ # Modify an entry: add an additional value to the postaladdress
817
+ # attribute, completely delete the description attribute, replace
818
+ # the telephonenumber attribute with two values, and delete a specific
819
+ # value from the facsimiletelephonenumber attribute
820
+ dn: cn=Paula Jensen, ou=Product Development, dc=airius, dc=com
821
+ changetype: modify
822
+ add: postaladdress
823
+ postaladdress: 123 Anystreet $ Sunnyvale, CA $ 94086
824
+ -
825
+ delete: description
826
+ -
827
+ replace: telephonenumber
828
+ telephonenumber: +1 408 555 1234
829
+ telephonenumber: +1 408 555 5678
830
+ -
831
+ delete: facsimiletelephonenumber
832
+ facsimiletelephonenumber: +1 408 555 9876
833
+ -
834
+ EOL
835
+
836
+ change_attributes = {
837
+ "dn" => "cn=Paula Jensen,ou=Product Development,dc=airius,dc=com",
838
+ }
839
+
840
+ ldif = assert_ldif(1, [change_attributes], ldif_source)
841
+ record = ldif.records[0]
842
+ assert_equal("modify", record.change_type)
843
+ assert_true(record.modify?)
844
+
845
+ operations = [
846
+ ["add", "postaladdress",
847
+ {"postaladdress" =>
848
+ ["123 Anystreet $ Sunnyvale, CA $ 94086"]}],
849
+ ["delete", "description", {}],
850
+ ["replace", "telephonenumber",
851
+ {"telephonenumber" => [
852
+ "+1 408 555 1234",
853
+ "+1 408 555 5678",
854
+ ]}],
855
+ ["delete", "facsimiletelephonenumber",
856
+ {"facsimiletelephonenumber" => ["+1 408 555 9876"]}],
857
+ ]
858
+ i = -1
859
+ actual = record.operations.collect do |operation|
860
+ i += 1
861
+ type = operations[i][0]
862
+ [operation.send("#{type}?"),
863
+ [operation.type, operation.attribute, operation.attributes]]
864
+ end
865
+ assert_equal(operations.collect {|operation| [true, operation]},
866
+ actual)
867
+ end
868
+
869
+ def test_modify_record_to_s
870
+ ldif_source = <<-EOL
871
+ version: 1
872
+ # Modify an entry: add an additional value to the postaladdress
873
+ # attribute, completely delete the description attribute, replace
874
+ # the telephonenumber attribute with two values, and delete a specific
875
+ # value from the facsimiletelephonenumber attribute
876
+ dn: cn=Paula Jensen, ou=Product Development, dc=airius, dc=com
877
+ changetype: modify
878
+ add: postaladdress
879
+ postaladdress: 123 Anystreet $ Sunnyvale, CA $ 94086
880
+ -
881
+ delete: description
882
+ -
883
+ replace: telephonenumber
884
+ telephonenumber: +1 408 555 1234
885
+ telephonenumber: +1 408 555 5678
886
+ -
887
+ delete: facsimiletelephonenumber
888
+ facsimiletelephonenumber: +1 408 555 9876
889
+ -
890
+ EOL
891
+
892
+ assert_ldif_to_s(<<-EOL, ldif_source)
893
+ version: 1
894
+ dn: cn=Paula Jensen,ou=Product Development,dc=airius,dc=com
895
+ changetype: modify
896
+ add: postaladdress
897
+ postaladdress: 123 Anystreet $ Sunnyvale, CA $ 94086
898
+ -
899
+ delete: description
900
+ -
901
+ replace: telephonenumber
902
+ telephonenumber: +1 408 555 1234
903
+ telephonenumber: +1 408 555 5678
904
+ -
905
+ delete: facsimiletelephonenumber
906
+ facsimiletelephonenumber: +1 408 555 9876
907
+ -
908
+ EOL
909
+ end
910
+
911
+ def test_modrdn_record_with_newsuperior
912
+ ldif_source = <<-EOL
913
+ version: 1
914
+ # Rename an entry and move all of its children to a new location in
915
+ # the directory tree (only implemented by LDAPv3 servers).
916
+ dn: ou=PD Accountants, ou=Product Development, dc=airius, dc=com
917
+ changetype: modrdn
918
+ newrdn: ou=Product Development Accountants
919
+ deleteoldrdn: 0
920
+ newsuperior: ou=Accounting, dc=airius, dc=com
921
+ EOL
922
+
923
+ change_attributes = {
924
+ "dn" => "ou=PD Accountants,ou=Product Development,dc=airius,dc=com",
925
+ }
926
+
927
+ ldif = assert_ldif(1, [change_attributes], ldif_source)
928
+ record = ldif.records[0]
929
+ assert_equal("modrdn", record.change_type)
930
+ assert_true(record.modify_rdn?)
931
+ assert_equal("ou=Product Development Accountants", record.new_rdn)
932
+ assert_false(record.delete_old_rdn?)
933
+ assert_equal("ou=Accounting,dc=airius,dc=com", record.new_superior)
934
+ end
935
+
936
+ def test_modrdn_record_with_newsuperior_to_s
937
+ ldif_source = <<-EOL
938
+ version: 1
939
+ # Rename an entry and move all of its children to a new location in
940
+ # the directory tree (only implemented by LDAPv3 servers).
941
+ dn: ou=PD Accountants, ou=Product Development, dc=airius, dc=com
942
+ changetype: modrdn
943
+ newrdn: ou=Product Development Accountants
944
+ deleteoldrdn: 0
945
+ newsuperior: ou=Accounting, dc=airius, dc=com
946
+ EOL
947
+
948
+ assert_ldif_to_s(<<-EOL, ldif_source)
949
+ version: 1
950
+ dn: ou=PD Accountants,ou=Product Development,dc=airius,dc=com
951
+ changetype: modrdn
952
+ newrdn: ou=Product Development Accountants
953
+ deleteoldrdn: 0
954
+ newsuperior: ou=Accounting,dc=airius,dc=com
955
+ EOL
956
+ end
957
+
958
+ def test_modrdn_record
959
+ ldif_source = <<-EOL
960
+ version: 1
961
+ # Modify an entry's relative distinguished name
962
+ dn: cn=Paul Jensen, ou=Product Development, dc=airius, dc=com
963
+ changetype: modrdn
964
+ newrdn: cn=Paula Jensen
965
+ deleteoldrdn: 1
966
+ EOL
967
+
968
+ change_attributes = {
969
+ "dn" => "cn=Paul Jensen,ou=Product Development,dc=airius,dc=com",
970
+ }
971
+
972
+ ldif = assert_ldif(1, [change_attributes], ldif_source)
973
+ record = ldif.records[0]
974
+ assert_equal("modrdn", record.change_type)
975
+ assert_true(record.modify_rdn?)
976
+ assert_equal("cn=Paula Jensen", record.new_rdn)
977
+ assert_true(record.delete_old_rdn?)
978
+ assert_nil(record.new_superior)
979
+ end
980
+
981
+ def test_modrdn_record_to_s
982
+ ldif_source = <<-EOL
983
+ version: 1
984
+ # Modify an entry's relative distinguished name
985
+ dn: cn=Paul Jensen, ou=Product Development, dc=airius, dc=com
986
+ changetype: modrdn
987
+ newrdn: cn=Paula Jensen
988
+ deleteoldrdn: 1
989
+ EOL
990
+
991
+ assert_ldif_to_s(<<-EOL, ldif_source)
992
+ version: 1
993
+ dn: cn=Paul Jensen,ou=Product Development,dc=airius,dc=com
994
+ changetype: modrdn
995
+ newrdn: cn=Paula Jensen
996
+ deleteoldrdn: 1
997
+ EOL
998
+ end
999
+
1000
+ def test_moddn_record_with_newsuperior
1001
+ ldif_source = <<-EOL
1002
+ version: 1
1003
+ # Rename an entry and move all of its children to a new location in
1004
+ # the directory tree (only implemented by LDAPv3 servers).
1005
+ dn: ou=PD Accountants, ou=Product Development, dc=airius, dc=com
1006
+ changetype: moddn
1007
+ newrdn: ou=Product Development Accountants
1008
+ deleteoldrdn: 0
1009
+ newsuperior: ou=Accounting, dc=airius, dc=com
1010
+ EOL
1011
+
1012
+ change_attributes = {
1013
+ "dn" => "ou=PD Accountants,ou=Product Development,dc=airius,dc=com",
1014
+ }
1015
+
1016
+ ldif = assert_ldif(1, [change_attributes], ldif_source)
1017
+ record = ldif.records[0]
1018
+ assert_equal("moddn", record.change_type)
1019
+ assert_true(record.modify_dn?)
1020
+ assert_equal("ou=Product Development Accountants", record.new_rdn)
1021
+ assert_false(record.delete_old_rdn?)
1022
+ assert_equal("ou=Accounting,dc=airius,dc=com", record.new_superior)
1023
+ end
1024
+
1025
+ def test_moddn_record_with_newsuperior_to_s
1026
+ ldif_source = <<-EOL
1027
+ version: 1
1028
+ # Rename an entry and move all of its children to a new location in
1029
+ # the directory tree (only implemented by LDAPv3 servers).
1030
+ dn: ou=PD Accountants, ou=Product Development, dc=airius, dc=com
1031
+ changetype: moddn
1032
+ newrdn: ou=Product Development Accountants
1033
+ deleteoldrdn: 0
1034
+ newsuperior: ou=Accounting, dc=airius, dc=com
1035
+ EOL
1036
+
1037
+ assert_ldif_to_s(<<-EOL, ldif_source)
1038
+ version: 1
1039
+ dn: ou=PD Accountants,ou=Product Development,dc=airius,dc=com
1040
+ changetype: moddn
1041
+ newrdn: ou=Product Development Accountants
1042
+ deleteoldrdn: 0
1043
+ newsuperior: ou=Accounting,dc=airius,dc=com
1044
+ EOL
1045
+ end
1046
+
1047
+ def test_moddn_record
1048
+ ldif_source = <<-EOL
1049
+ version: 1
1050
+ # Modify an entry's relative distinguished name
1051
+ dn: cn=Paul Jensen, ou=Product Development, dc=airius, dc=com
1052
+ changetype: moddn
1053
+ newrdn: cn=Paula Jensen
1054
+ deleteoldrdn: 1
1055
+ EOL
1056
+
1057
+ change_attributes = {
1058
+ "dn" => "cn=Paul Jensen,ou=Product Development,dc=airius,dc=com",
1059
+ }
1060
+
1061
+ ldif = assert_ldif(1, [change_attributes], ldif_source)
1062
+ record = ldif.records[0]
1063
+ assert_equal("moddn", record.change_type)
1064
+ assert_true(record.modify_dn?)
1065
+ assert_equal("cn=Paula Jensen", record.new_rdn)
1066
+ assert_true(record.delete_old_rdn?)
1067
+ assert_nil(record.new_superior)
1068
+ end
1069
+
1070
+ def test_moddn_record_to_s
1071
+ ldif_source = <<-EOL
1072
+ version: 1
1073
+ # Modify an entry's relative distinguished name
1074
+ dn: cn=Paul Jensen, ou=Product Development, dc=airius, dc=com
1075
+ changetype: moddn
1076
+ newrdn: cn=Paula Jensen
1077
+ deleteoldrdn: 1
1078
+ EOL
1079
+
1080
+ assert_ldif_to_s(<<-EOL, ldif_source)
1081
+ version: 1
1082
+ dn: cn=Paul Jensen,ou=Product Development,dc=airius,dc=com
1083
+ changetype: moddn
1084
+ newrdn: cn=Paula Jensen
1085
+ deleteoldrdn: 1
1086
+ EOL
1087
+ end
1088
+
1089
+ def test_delete_record
1090
+ ldif_source = <<-EOL
1091
+ version: 1
1092
+ # Delete an existing entry
1093
+ dn: cn=Robert Jensen, ou=Marketing, dc=airius, dc=com
1094
+ changetype: delete
1095
+ EOL
1096
+
1097
+ change_attributes = {
1098
+ "dn" => "cn=Robert Jensen,ou=Marketing,dc=airius,dc=com",
1099
+ }
1100
+
1101
+ ldif = assert_ldif(1, [change_attributes], ldif_source)
1102
+ record = ldif.records[0]
1103
+ assert_equal("delete", record.change_type)
1104
+ assert_true(record.delete?)
1105
+ end
1106
+
1107
+ def test_delete_record_to_s
1108
+ ldif_source = <<-EOL
1109
+ version: 1
1110
+ # Delete an existing entry
1111
+ dn: cn=Robert Jensen, ou=Marketing, dc=airius, dc=com
1112
+ changetype: delete
1113
+ EOL
1114
+
1115
+ assert_ldif_to_s(<<-EOL, ldif_source)
1116
+ version: 1
1117
+ dn: cn=Robert Jensen,ou=Marketing,dc=airius,dc=com
1118
+ changetype: delete
1119
+ EOL
1120
+ end
1121
+
1122
+ def test_add_record
1123
+ ldif_source = <<-EOL
1124
+ version: 1
1125
+ # Add a new entry
1126
+ dn: cn=Fiona Jensen, ou=Marketing, dc=airius, dc=com
1127
+ changetype: add
1128
+ objectclass: top
1129
+ objectclass: person
1130
+ objectclass: organizationalPerson
1131
+ cn: Fiona Jensen
1132
+ sn: Jensen
1133
+ uid: fiona
1134
+ telephonenumber: +1 408 555 1212
1135
+ EOL
1136
+
1137
+ change_attributes = {
1138
+ "dn" => "cn=Fiona Jensen,ou=Marketing,dc=airius,dc=com",
1139
+ "objectclass" => ["top", "person", "organizationalPerson"],
1140
+ "cn" => ["Fiona Jensen"],
1141
+ "sn" => ["Jensen"],
1142
+ "uid" => ["fiona"],
1143
+ "telephonenumber" => ["+1 408 555 1212"],
1144
+ }
1145
+
1146
+ ldif = assert_ldif(1, [change_attributes], ldif_source)
1147
+ record = ldif.records[0]
1148
+ assert_equal("add", record.change_type)
1149
+ assert_true(record.add?)
1150
+ end
1151
+
1152
+ def test_add_record_to_s
1153
+ ldif_source = <<-EOL
1154
+ version: 1
1155
+ # Add a new entry
1156
+ dn: cn=Fiona Jensen, ou=Marketing, dc=airius, dc=com
1157
+ changetype: add
1158
+ objectclass: top
1159
+ objectclass: person
1160
+ objectclass: organizationalPerson
1161
+ cn: Fiona Jensen
1162
+ sn: Jensen
1163
+ uid: fiona
1164
+ telephonenumber: +1 408 555 1212
1165
+ EOL
1166
+
1167
+ assert_ldif_to_s(<<-EOL, ldif_source)
1168
+ version: 1
1169
+ dn: cn=Fiona Jensen,ou=Marketing,dc=airius,dc=com
1170
+ changetype: add
1171
+ cn: Fiona Jensen
1172
+ objectclass: organizationalPerson
1173
+ objectclass: person
1174
+ objectclass: top
1175
+ sn: Jensen
1176
+ telephonenumber: +1 408 555 1212
1177
+ uid: fiona
1178
+ EOL
1179
+ end
1180
+
1181
+ def test_records_with_external_file_reference
1182
+ ldif_source = <<-EOL
1183
+ version: 1
1184
+ dn: cn=Horatio Jensen, ou=Product Testing, dc=airius, dc=com
1185
+ objectclass: top
1186
+ objectclass: person
1187
+ objectclass: organizationalPerson
1188
+ cn: Horatio Jensen
1189
+ cn: Horatio N Jensen
1190
+ sn: Jensen
1191
+ uid: hjensen
1192
+ telephonenumber: +1 408 555 1212
1193
+ jpegphoto:< file://#{jpeg_photo_path}
1194
+ EOL
1195
+
1196
+ record = {
1197
+ "dn" => "cn=Horatio Jensen,ou=Product Testing,dc=airius,dc=com",
1198
+ "objectclass" => ["top", "person", "organizationalPerson"],
1199
+ "cn" => ["Horatio Jensen", "Horatio N Jensen"],
1200
+ "sn" => ["Jensen"],
1201
+ "uid" => ["hjensen"],
1202
+ "telephonenumber" => ["+1 408 555 1212"],
1203
+ "jpegphoto" => [jpeg_photo],
1204
+ }
1205
+
1206
+ assert_ldif(1, [record], ldif_source)
1207
+ end
1208
+
1209
+ def test_records_with_external_file_reference_to_s
1210
+ ldif_source = <<-EOL
1211
+ version: 1
1212
+ dn: cn=Horatio Jensen, ou=Product Testing, dc=airius, dc=com
1213
+ objectclass: top
1214
+ objectclass: person
1215
+ objectclass: organizationalPerson
1216
+ cn: Horatio Jensen
1217
+ cn: Horatio N Jensen
1218
+ sn: Jensen
1219
+ uid: hjensen
1220
+ telephonenumber: +1 408 555 1212
1221
+ jpegphoto:< file://#{jpeg_photo_path}
1222
+ EOL
1223
+ set_encoding(ldif_source, "utf-8")
1224
+
1225
+ jpeg_photo_attribute = "jpegphoto:: "
1226
+ value = [jpeg_photo].pack("m").gsub(/\n/, '')
1227
+ first_line_value_size = 75 - jpeg_photo_attribute.size
1228
+ jpeg_photo_attribute << value[0, first_line_value_size] + "\n"
1229
+ value = value[first_line_value_size..-1]
1230
+ value.scan(/.{1,74}/).each do |line|
1231
+ jpeg_photo_attribute << " #{line}\n"
1232
+ end
1233
+ jpeg_photo_attribute = jpeg_photo_attribute.chomp
1234
+
1235
+ assert_ldif_to_s(<<-EOL, ldif_source)
1236
+ version: 1
1237
+ dn: cn=Horatio Jensen,ou=Product Testing,dc=airius,dc=com
1238
+ cn: Horatio Jensen
1239
+ cn: Horatio N Jensen
1240
+ #{jpeg_photo_attribute}
1241
+ objectclass: organizationalPerson
1242
+ objectclass: person
1243
+ objectclass: top
1244
+ sn: Jensen
1245
+ telephonenumber: +1 408 555 1212
1246
+ uid: hjensen
1247
+ EOL
1248
+ end
1249
+
1250
+ def test_records_with_option_attributes
1251
+ ldif_source = <<-EOL
1252
+ version: 1
1253
+ dn:: b3U95Za25qWt6YOoLG89QWlyaXVz
1254
+ # dn:: ou=<JapaneseOU>,o=Airius
1255
+ objectclass: top
1256
+ objectclass: organizationalUnit
1257
+ ou:: 5Za25qWt6YOo
1258
+ # ou:: <JapaneseOU>
1259
+ ou;lang-ja:: 5Za25qWt6YOo
1260
+ # ou;lang-ja:: <JapaneseOU>
1261
+ ou;lang-ja;phonetic:: 44GI44GE44GO44KH44GG44G2
1262
+ # ou;lang-ja:: <JapaneseOU_in_phonetic_representation>
1263
+ ou;lang-en: Sales
1264
+ description: Japanese office
1265
+
1266
+ dn:: dWlkPXJvZ2FzYXdhcmEsb3U95Za25qWt6YOoLG89QWlyaXVz
1267
+ # dn:: uid=<uid>,ou=<JapaneseOU>,o=Airius
1268
+ userpassword: {SHA}O3HSv1MusyL4kTjP+HKI5uxuNoM=
1269
+ objectclass: top
1270
+ objectclass: person
1271
+ objectclass: organizationalPerson
1272
+ objectclass: inetOrgPerson
1273
+ uid: rogasawara
1274
+ mail: rogasawara@airius.co.jp
1275
+ givenname;lang-ja:: 44Ot44OJ44OL44O8
1276
+ # givenname;lang-ja:: <JapaneseGivenname>
1277
+ sn;lang-ja:: 5bCP56yg5Y6f
1278
+ # sn;lang-ja:: <JapaneseSn>
1279
+ cn;lang-ja:: 5bCP56yg5Y6fIOODreODieODi+ODvA==
1280
+ # cn;lang-ja:: <JapaneseCn>
1281
+ title;lang-ja:: 5Za25qWt6YOoIOmDqOmVtw==
1282
+ # title;lang-ja:: <JapaneseTitle>
1283
+ preferredlanguage: ja
1284
+ givenname:: 44Ot44OJ44OL44O8
1285
+ # givenname:: <JapaneseGivenname>
1286
+ sn:: 5bCP56yg5Y6f
1287
+ # sn:: <JapaneseSn>
1288
+ cn:: 5bCP56yg5Y6fIOODreODieODi+ODvA==
1289
+ # cn:: <JapaneseCn>
1290
+ title:: 5Za25qWt6YOoIOmDqOmVtw==
1291
+ # title:: <JapaneseTitle>
1292
+ givenname;lang-ja;phonetic:: 44KN44Gp44Gr44O8
1293
+ # givenname;lang-ja;phonetic::
1294
+ <JapaneseGivenname_in_phonetic_representation_kana>
1295
+ sn;lang-ja;phonetic:: 44GK44GM44GV44KP44KJ
1296
+ # sn;lang-ja;phonetic:: <JapaneseSn_in_phonetic_representation_kana>
1297
+ cn;lang-ja;phonetic:: 44GK44GM44GV44KP44KJIOOCjeOBqeOBq+ODvA==
1298
+ # cn;lang-ja;phonetic:: <JapaneseCn_in_phonetic_representation_kana>
1299
+ title;lang-ja;phonetic:: 44GI44GE44GO44KH44GG44G2IOOBtuOBoeOCh+OBhg==
1300
+ # title;lang-ja;phonetic::
1301
+ # <JapaneseTitle_in_phonetic_representation_kana>
1302
+ givenname;lang-en: Rodney
1303
+ sn;lang-en: Ogasawara
1304
+ cn;lang-en: Rodney Ogasawara
1305
+ title;lang-en: Sales, Director
1306
+ EOL
1307
+ set_encoding(ldif_source, "utf-8")
1308
+
1309
+ record1 = {
1310
+ "dn" => "ou=営業部,o=Airius",
1311
+ "objectclass" => ["top", "organizationalUnit"],
1312
+ "ou" => [
1313
+ "営業部",
1314
+ {"lang-ja" =>
1315
+ [
1316
+ "営業部",
1317
+ {"phonetic" => ["えいぎょうぶ"]},
1318
+ ],
1319
+ },
1320
+ {"lang-en" => ["Sales"]},
1321
+ ],
1322
+ "description" => ["Japanese office"],
1323
+ }
1324
+
1325
+ record2 = {
1326
+ "dn" => "uid=rogasawara,ou=営業部,o=Airius",
1327
+ "userpassword" => ["{SHA}O3HSv1MusyL4kTjP+HKI5uxuNoM="],
1328
+ "objectclass" => ["top", "person",
1329
+ "organizationalPerson", "inetOrgPerson"],
1330
+ "uid" => ["rogasawara"],
1331
+ "mail" => ["rogasawara@airius.co.jp"],
1332
+ "givenname" => [
1333
+ {"lang-ja" =>
1334
+ [
1335
+ "ロドニー",
1336
+ {"phonetic" => ["ろどにー"]},
1337
+ ]
1338
+ },
1339
+ "ロドニー",
1340
+ {"lang-en" => ["Rodney"]},
1341
+ ],
1342
+ "sn" => [
1343
+ {"lang-ja" =>
1344
+ [
1345
+ "小笠原",
1346
+ {"phonetic" => ["おがさわら"]},
1347
+ ]
1348
+ },
1349
+ "小笠原",
1350
+ {"lang-en" => ["Ogasawara"]},
1351
+ ],
1352
+ "cn" => [
1353
+ {"lang-ja" =>
1354
+ [
1355
+ "小笠原 ロドニー",
1356
+ {"phonetic" => ["おがさわら ろどにー"]},
1357
+ ],
1358
+ },
1359
+ "小笠原 ロドニー",
1360
+ {"lang-en" => ["Rodney Ogasawara"]},
1361
+ ],
1362
+ "title" => [
1363
+ {"lang-ja" =>
1364
+ [
1365
+ "営業部 部長",
1366
+ {"phonetic" => ["えいぎょうぶ ぶちょう"]}
1367
+ ]
1368
+ },
1369
+ "営業部 部長",
1370
+ {"lang-en" => ["Sales, Director"]},
1371
+ ],
1372
+ "preferredlanguage" => ["ja"],
1373
+ }
1374
+
1375
+ assert_ldif(1, [record1, record2], ldif_source)
1376
+ end
1377
+
1378
+ def test_records_with_option_attributes_to_s
1379
+ ldif_source = <<-EOL
1380
+ version: 1
1381
+ dn:: b3U95Za25qWt6YOoLG89QWlyaXVz
1382
+ # dn:: ou=<JapaneseOU>,o=Airius
1383
+ objectclass: top
1384
+ objectclass: organizationalUnit
1385
+ ou:: 5Za25qWt6YOo
1386
+ # ou:: <JapaneseOU>
1387
+ ou;lang-ja:: 5Za25qWt6YOo
1388
+ # ou;lang-ja:: <JapaneseOU>
1389
+ ou;lang-ja;phonetic:: 44GI44GE44GO44KH44GG44G2
1390
+ # ou;lang-ja:: <JapaneseOU_in_phonetic_representation>
1391
+ ou;lang-en: Sales
1392
+ description: Japanese office
1393
+
1394
+ dn:: dWlkPXJvZ2FzYXdhcmEsb3U95Za25qWt6YOoLG89QWlyaXVz
1395
+ # dn:: uid=<uid>,ou=<JapaneseOU>,o=Airius
1396
+ userpassword: {SHA}O3HSv1MusyL4kTjP+HKI5uxuNoM=
1397
+ objectclass: top
1398
+ objectclass: person
1399
+ objectclass: organizationalPerson
1400
+ objectclass: inetOrgPerson
1401
+ uid: rogasawara
1402
+ mail: rogasawara@airius.co.jp
1403
+ givenname;lang-ja:: 44Ot44OJ44OL44O8
1404
+ # givenname;lang-ja:: <JapaneseGivenname>
1405
+ sn;lang-ja:: 5bCP56yg5Y6f
1406
+ # sn;lang-ja:: <JapaneseSn>
1407
+ cn;lang-ja:: 5bCP56yg5Y6fIOODreODieODi+ODvA==
1408
+ # cn;lang-ja:: <JapaneseCn>
1409
+ title;lang-ja:: 5Za25qWt6YOoIOmDqOmVtw==
1410
+ # title;lang-ja:: <JapaneseTitle>
1411
+ preferredlanguage: ja
1412
+ givenname:: 44Ot44OJ44OL44O8
1413
+ # givenname:: <JapaneseGivenname>
1414
+ sn:: 5bCP56yg5Y6f
1415
+ # sn:: <JapaneseSn>
1416
+ cn:: 5bCP56yg5Y6fIOODreODieODi+ODvA==
1417
+ # cn:: <JapaneseCn>
1418
+ title:: 5Za25qWt6YOoIOmDqOmVtw==
1419
+ # title:: <JapaneseTitle>
1420
+ givenname;lang-ja;phonetic:: 44KN44Gp44Gr44O8
1421
+ # givenname;lang-ja;phonetic::
1422
+ <JapaneseGivenname_in_phonetic_representation_kana>
1423
+ sn;lang-ja;phonetic:: 44GK44GM44GV44KP44KJ
1424
+ # sn;lang-ja;phonetic:: <JapaneseSn_in_phonetic_representation_kana>
1425
+ cn;lang-ja;phonetic:: 44GK44GM44GV44KP44KJIOOCjeOBqeOBq+ODvA==
1426
+ # cn;lang-ja;phonetic:: <JapaneseCn_in_phonetic_representation_kana>
1427
+ title;lang-ja;phonetic:: 44GI44GE44GO44KH44GG44G2IOOBtuOBoeOCh+OBhg==
1428
+ # title;lang-ja;phonetic::
1429
+ # <JapaneseTitle_in_phonetic_representation_kana>
1430
+ givenname;lang-en: Rodney
1431
+ sn;lang-en: Ogasawara
1432
+ cn;lang-en: Rodney Ogasawara
1433
+ title;lang-en: Sales, Director
1434
+ EOL
1435
+ set_encoding(ldif_source, "utf-8")
1436
+
1437
+ assert_ldif_to_s(<<-EOL, ldif_source)
1438
+ version: 1
1439
+ dn:: b3U95Za25qWt6YOoLG89QWlyaXVz
1440
+ description: Japanese office
1441
+ objectclass: organizationalUnit
1442
+ objectclass: top
1443
+ ou:: 5Za25qWt6YOo
1444
+ ou;lang-en: Sales
1445
+ ou;lang-ja:: 5Za25qWt6YOo
1446
+ ou;lang-ja;phonetic:: 44GI44GE44GO44KH44GG44G2
1447
+
1448
+ dn:: dWlkPXJvZ2FzYXdhcmEsb3U95Za25qWt6YOoLG89QWlyaXVz
1449
+ cn:: 5bCP56yg5Y6fIOODreODieODi+ODvA==
1450
+ cn;lang-en: Rodney Ogasawara
1451
+ cn;lang-ja:: 5bCP56yg5Y6fIOODreODieODi+ODvA==
1452
+ cn;lang-ja;phonetic:: 44GK44GM44GV44KP44KJIOOCjeOBqeOBq+ODvA==
1453
+ givenname:: 44Ot44OJ44OL44O8
1454
+ givenname;lang-en: Rodney
1455
+ givenname;lang-ja:: 44Ot44OJ44OL44O8
1456
+ givenname;lang-ja;phonetic:: 44KN44Gp44Gr44O8
1457
+ mail: rogasawara@airius.co.jp
1458
+ objectclass: inetOrgPerson
1459
+ objectclass: organizationalPerson
1460
+ objectclass: person
1461
+ objectclass: top
1462
+ preferredlanguage: ja
1463
+ sn:: 5bCP56yg5Y6f
1464
+ sn;lang-en: Ogasawara
1465
+ sn;lang-ja:: 5bCP56yg5Y6f
1466
+ sn;lang-ja;phonetic:: 44GK44GM44GV44KP44KJ
1467
+ title:: 5Za25qWt6YOoIOmDqOmVtw==
1468
+ title;lang-en: Sales, Director
1469
+ title;lang-ja:: 5Za25qWt6YOoIOmDqOmVtw==
1470
+ title;lang-ja;phonetic:: 44GI44GE44GO44KH44GG44G2IOOBtuOBoeOCh+OBhg==
1471
+ uid: rogasawara
1472
+ userpassword: {SHA}O3HSv1MusyL4kTjP+HKI5uxuNoM=
1473
+ EOL
1474
+ end
1475
+
1476
+ def test_an_record_with_base64_encoded_value
1477
+ ldif_source = <<-EOL
1478
+ version: 1
1479
+ dn: cn=Gern Jensen, ou=Product Testing, dc=airius, dc=com
1480
+ objectclass: top
1481
+ objectclass: person
1482
+ objectclass: organizationalPerson
1483
+ cn: Gern Jensen
1484
+ cn: Gern O Jensen
1485
+ sn: Jensen
1486
+ uid: gernj
1487
+ telephonenumber: +1 408 555 1212
1488
+ description:: V2hhdCBhIGNhcmVmdWwgcmVhZGVyIHlvdSBhcmUhICBUaGlzIHZhbHVl
1489
+ IGlzIGJhc2UtNjQtZW5jb2RlZCBiZWNhdXNlIGl0IGhhcyBhIGNvbnRyb2wgY2hhcmFjdG
1490
+ VyIGluIGl0IChhIENSKS4NICBCeSB0aGUgd2F5LCB5b3Ugc2hvdWxkIHJlYWxseSBnZXQg
1491
+ b3V0IG1vcmUu
1492
+ EOL
1493
+
1494
+ record = {
1495
+ "dn" => "cn=Gern Jensen,ou=Product Testing,dc=airius,dc=com",
1496
+ "objectclass" => ["top", "person", "organizationalPerson"],
1497
+ "cn" => ["Gern Jensen", "Gern O Jensen"],
1498
+ "sn" => ["Jensen"],
1499
+ "uid" => ["gernj"],
1500
+ "telephonenumber" => ["+1 408 555 1212"],
1501
+ "description" => ["What a careful reader you are! " +
1502
+ "This value is base-64-encoded because it has a " +
1503
+ "control character in it (a CR).\r By the way, " +
1504
+ "you should really get out more."],
1505
+ }
1506
+ assert_ldif(1, [record], ldif_source)
1507
+ end
1508
+
1509
+ def test_an_record_with_base64_encoded_value_to_s
1510
+ ldif_source = <<-EOL
1511
+ version: 1
1512
+ dn: cn=Gern Jensen, ou=Product Testing, dc=airius, dc=com
1513
+ objectclass: top
1514
+ objectclass: person
1515
+ objectclass: organizationalPerson
1516
+ cn: Gern Jensen
1517
+ cn: Gern O Jensen
1518
+ sn: Jensen
1519
+ uid: gernj
1520
+ telephonenumber: +1 408 555 1212
1521
+ description:: V2hhdCBhIGNhcmVmdWwgcmVhZGVyIHlvdSBhcmUhICBUaGlzIHZhbHVl
1522
+ IGlzIGJhc2UtNjQtZW5jb2RlZCBiZWNhdXNlIGl0IGhhcyBhIGNvbnRyb2wgY2hhcmFjdG
1523
+ VyIGluIGl0IChhIENSKS4NICBCeSB0aGUgd2F5LCB5b3Ugc2hvdWxkIHJlYWxseSBnZXQg
1524
+ b3V0IG1vcmUu
1525
+ EOL
1526
+
1527
+ assert_ldif_to_s(<<-EOL, ldif_source)
1528
+ version: 1
1529
+ dn: cn=Gern Jensen,ou=Product Testing,dc=airius,dc=com
1530
+ cn: Gern Jensen
1531
+ cn: Gern O Jensen
1532
+ description:: V2hhdCBhIGNhcmVmdWwgcmVhZGVyIHlvdSBhcmUhICBUaGlzIHZhbHVlIGlzI
1533
+ GJhc2UtNjQtZW5jb2RlZCBiZWNhdXNlIGl0IGhhcyBhIGNvbnRyb2wgY2hhcmFjdGVyIGluIGl
1534
+ 0IChhIENSKS4NICBCeSB0aGUgd2F5LCB5b3Ugc2hvdWxkIHJlYWxseSBnZXQgb3V0IG1vcmUu
1535
+ objectclass: organizationalPerson
1536
+ objectclass: person
1537
+ objectclass: top
1538
+ sn: Jensen
1539
+ telephonenumber: +1 408 555 1212
1540
+ uid: gernj
1541
+ EOL
1542
+ end
1543
+
1544
+ def test_an_record_with_folded_attribute_value
1545
+ ldif_source = <<-EOL
1546
+ version: 1
1547
+ dn:cn=Barbara Jensen, ou=Product Development, dc=airius, dc=com
1548
+ objectclass:top
1549
+ objectclass:person
1550
+ objectclass:organizationalPerson
1551
+ cn:Barbara Jensen
1552
+ cn:Barbara J Jensen
1553
+ cn:Babs Jensen
1554
+ sn:Jensen
1555
+ uid:bjensen
1556
+ telephonenumber:+1 408 555 1212
1557
+ description:Babs is a big sailing fan, and travels extensively in sea
1558
+ rch of perfect sailing conditions.
1559
+ title:Product Manager, Rod and Reel Division
1560
+ EOL
1561
+
1562
+ record = {
1563
+ "dn" => "cn=Barbara Jensen,ou=Product Development,dc=airius,dc=com",
1564
+ "objectclass" => ["top", "person", "organizationalPerson"],
1565
+ "cn" => ["Barbara Jensen", "Barbara J Jensen", "Babs Jensen"],
1566
+ "sn" => ["Jensen"],
1567
+ "uid" => ["bjensen"],
1568
+ "telephonenumber" => ["+1 408 555 1212"],
1569
+ "description" => ["Babs is a big sailing fan, and travels extensively " +
1570
+ "in search of perfect sailing conditions."],
1571
+ "title" => ["Product Manager, Rod and Reel Division"],
1572
+ }
1573
+ assert_ldif(1, [record], ldif_source)
1574
+ end
1575
+
1576
+ def test_an_record_with_folded_attribute_value_to_s
1577
+ ldif_source = <<-EOL
1578
+ version: 1
1579
+ dn:cn=Barbara Jensen, ou=Product Development, dc=airius, dc=com
1580
+ objectclass:top
1581
+ objectclass:person
1582
+ objectclass:organizationalPerson
1583
+ cn:Barbara Jensen
1584
+ cn:Barbara J Jensen
1585
+ cn:Babs Jensen
1586
+ sn:Jensen
1587
+ uid:bjensen
1588
+ telephonenumber:+1 408 555 1212
1589
+ description:Babs is a big sailing fan, and travels extensively in sea
1590
+ rch of perfect sailing conditions.
1591
+ title:Product Manager, Rod and Reel Division
1592
+ EOL
1593
+
1594
+ assert_ldif_to_s(<<-EOL, ldif_source)
1595
+ version: 1
1596
+ dn: cn=Barbara Jensen,ou=Product Development,dc=airius,dc=com
1597
+ cn: Babs Jensen
1598
+ cn: Barbara J Jensen
1599
+ cn: Barbara Jensen
1600
+ description: Babs is a big sailing fan, and travels extensively in search o
1601
+ f perfect sailing conditions.
1602
+ objectclass: organizationalPerson
1603
+ objectclass: person
1604
+ objectclass: top
1605
+ sn: Jensen
1606
+ telephonenumber: +1 408 555 1212
1607
+ title: Product Manager, Rod and Reel Division
1608
+ uid: bjensen
1609
+ EOL
1610
+ end
1611
+
1612
+ def test_records
1613
+ ldif_source = <<-EOL
1614
+ version: 1
1615
+ dn: cn=Barbara Jensen, ou=Product Development, dc=airius, dc=com
1616
+ objectclass: top
1617
+ objectclass: person
1618
+ objectclass: organizationalPerson
1619
+ cn: Barbara Jensen
1620
+ cn: Barbara J Jensen
1621
+ cn: Babs Jensen
1622
+ sn: Jensen
1623
+ uid: bjensen
1624
+ telephonenumber: +1 408 555 1212
1625
+ description: A big sailing fan.
1626
+
1627
+ dn: cn=Bjorn Jensen, ou=Accounting, dc=airius, dc=com
1628
+ objectclass: top
1629
+ objectclass: person
1630
+ objectclass: organizationalPerson
1631
+ cn: Bjorn Jensen
1632
+ sn: Jensen
1633
+ telephonenumber: +1 408 555 1212
1634
+ EOL
1635
+
1636
+ record1 = {
1637
+ "dn" => "cn=Barbara Jensen,ou=Product Development,dc=airius,dc=com",
1638
+ "objectclass" => ["top", "person", "organizationalPerson"],
1639
+ "cn" => ["Barbara Jensen", "Barbara J Jensen", "Babs Jensen"],
1640
+ "sn" => ["Jensen"],
1641
+ "uid" => ["bjensen"],
1642
+ "telephonenumber" => ["+1 408 555 1212"],
1643
+ "description" => ["A big sailing fan."],
1644
+ }
1645
+ record2 = {
1646
+ "dn" => "cn=Bjorn Jensen,ou=Accounting,dc=airius,dc=com",
1647
+ "objectclass" => ["top", "person", "organizationalPerson"],
1648
+ "cn" => ["Bjorn Jensen"],
1649
+ "sn" => ["Jensen"],
1650
+ "telephonenumber" => ["+1 408 555 1212"],
1651
+ }
1652
+ assert_ldif(1, [record1, record2], ldif_source)
1653
+ end
1654
+
1655
+ def test_records_to_s
1656
+ ldif_source = <<-EOL
1657
+ version: 1
1658
+ dn: cn=Barbara Jensen, ou=Product Development, dc=airius, dc=com
1659
+ objectclass: top
1660
+ objectclass: person
1661
+ objectclass: organizationalPerson
1662
+ cn: Barbara Jensen
1663
+ cn: Barbara J Jensen
1664
+ cn: Babs Jensen
1665
+ sn: Jensen
1666
+ uid: bjensen
1667
+ telephonenumber: +1 408 555 1212
1668
+ description: A big sailing fan.
1669
+
1670
+ dn: cn=Bjorn Jensen, ou=Accounting, dc=airius, dc=com
1671
+ objectclass: top
1672
+ objectclass: person
1673
+ objectclass: organizationalPerson
1674
+ cn: Bjorn Jensen
1675
+ sn: Jensen
1676
+ telephonenumber: +1 408 555 1212
1677
+ EOL
1678
+
1679
+ assert_ldif_to_s(<<-EOL, ldif_source)
1680
+ version: 1
1681
+ dn: cn=Barbara Jensen,ou=Product Development,dc=airius,dc=com
1682
+ cn: Babs Jensen
1683
+ cn: Barbara J Jensen
1684
+ cn: Barbara Jensen
1685
+ description: A big sailing fan.
1686
+ objectclass: organizationalPerson
1687
+ objectclass: person
1688
+ objectclass: top
1689
+ sn: Jensen
1690
+ telephonenumber: +1 408 555 1212
1691
+ uid: bjensen
1692
+
1693
+ dn: cn=Bjorn Jensen,ou=Accounting,dc=airius,dc=com
1694
+ cn: Bjorn Jensen
1695
+ objectclass: organizationalPerson
1696
+ objectclass: person
1697
+ objectclass: top
1698
+ sn: Jensen
1699
+ telephonenumber: +1 408 555 1212
1700
+ EOL
1701
+ end
1702
+
1703
+ def test_an_record
1704
+ ldif_source = <<-EOL
1705
+ version: 1
1706
+ dn: cn=Barbara Jensen, ou=Product Development, dc=airius, dc=com
1707
+ objectclass: top
1708
+ objectclass: person
1709
+ objectclass: organizationalPerson
1710
+ cn: Barbara Jensen
1711
+ cn: Barbara J Jensen
1712
+ cn: Babs Jensen
1713
+ sn: Jensen
1714
+ uid: bjensen
1715
+ telephonenumber: +1 408 555 1212
1716
+ description: A big sailing fan.
1717
+ EOL
1718
+
1719
+ record = {
1720
+ "dn" => "cn=Barbara Jensen,ou=Product Development,dc=airius,dc=com",
1721
+ "objectclass" => ["top", "person", "organizationalPerson"],
1722
+ "cn" => ["Barbara Jensen", "Barbara J Jensen", "Babs Jensen"],
1723
+ "sn" => ["Jensen"],
1724
+ "uid" => ["bjensen"],
1725
+ "telephonenumber" => ["+1 408 555 1212"],
1726
+ "description" => ["A big sailing fan."],
1727
+ }
1728
+ assert_ldif(1, [record], ldif_source)
1729
+ end
1730
+
1731
+ def test_an_record_to_s
1732
+ ldif_source = <<-EOL
1733
+ version: 1
1734
+ dn: cn=Barbara Jensen, ou=Product Development, dc=airius, dc=com
1735
+ objectclass: top
1736
+ objectclass: person
1737
+ objectclass: organizationalPerson
1738
+ cn: Barbara Jensen
1739
+ cn: Barbara J Jensen
1740
+ cn: Babs Jensen
1741
+ sn: Jensen
1742
+ uid: bjensen
1743
+ telephonenumber: +1 408 555 1212
1744
+ description: A big sailing fan.
1745
+ EOL
1746
+
1747
+ assert_ldif_to_s(<<-EOL, ldif_source)
1748
+ version: 1
1749
+ dn: cn=Barbara Jensen,ou=Product Development,dc=airius,dc=com
1750
+ cn: Babs Jensen
1751
+ cn: Barbara J Jensen
1752
+ cn: Barbara Jensen
1753
+ description: A big sailing fan.
1754
+ objectclass: organizationalPerson
1755
+ objectclass: person
1756
+ objectclass: top
1757
+ sn: Jensen
1758
+ telephonenumber: +1 408 555 1212
1759
+ uid: bjensen
1760
+ EOL
1761
+ end
1762
+
1763
+ def test_comment
1764
+ ldif_source = <<-EOL
1765
+ version: 1
1766
+ dn: cn=Barbara Jensen, ou=Product Development, dc=airius, dc=com
1767
+ objectclass: top
1768
+ # objectclass: person
1769
+ #objectcl
1770
+ ass: organizationalPerson
1771
+ EOL
1772
+
1773
+ record = {
1774
+ "dn" => "cn=Barbara Jensen,ou=Product Development,dc=airius,dc=com",
1775
+ "objectclass" => ["top"],
1776
+ }
1777
+ assert_ldif(1, [record], ldif_source)
1778
+ end
1779
+
1780
+ def test_comment_to_s
1781
+ ldif_source = <<-EOL
1782
+ version: 1
1783
+ dn: cn=Barbara Jensen, ou=Product Development, dc=airius, dc=com
1784
+ objectclass: top
1785
+ # objectclass: person
1786
+ #objectcl
1787
+ ass: organizationalPerson
1788
+ EOL
1789
+
1790
+ assert_ldif_to_s(<<-EOL, ldif_source)
1791
+ version: 1
1792
+ dn: cn=Barbara Jensen,ou=Product Development,dc=airius,dc=com
1793
+ objectclass: top
1794
+ EOL
1795
+ end
1796
+
1797
+ def test_dn_spec
1798
+ assert_invalid_ldif("'dn:' is missing",
1799
+ "version: 1\n", 2, 1, "version: 1\n|@|")
1800
+ assert_invalid_ldif("DN is missing",
1801
+ "version: 1\ndn:", 2, 4, "dn:|@|")
1802
+ assert_invalid_ldif("DN is missing",
1803
+ "version: 1\ndn::", 2, 5, "dn::|@|")
1804
+ assert_invalid_ldif("DN is missing",
1805
+ "version: 1\ndn:\n", 2, 4, "dn:|@|\n")
1806
+ assert_invalid_ldif("DN is missing",
1807
+ "version: 1\ndn: \n", 2, 5, "dn: |@|\n")
1808
+
1809
+ dn = "cn=Barbara Jensen,ou=Product Development,dc=example,dc=com"
1810
+ cn = "Barbara Jensen"
1811
+ assert_valid_dn(dn, "version: 1\ndn: #{dn}\ncn:#{cn}\n")
1812
+
1813
+ encoded_dn = Base64.encode64(dn).gsub(/\n/, "\n ")
1814
+ encoded_cn = Base64.encode64(cn).gsub(/\n/, "\n ")
1815
+ assert_valid_dn(dn, "version: 1\ndn:: #{encoded_dn}\ncn::#{encoded_cn}\n")
1816
+ end
1817
+
1818
+ def test_version_number
1819
+ assert_valid_version(1, "version: 1\ndn: dc=com\ndc: com")
1820
+ assert_valid_version(1, "version: 1\r\ndn: dc=com\ndc: com\n")
1821
+ assert_valid_version(1, "version: 1\r\n\n\r\n\ndn: dc=com\ndc: com\n")
1822
+
1823
+ assert_invalid_ldif(["unsupported version: %d", 0],
1824
+ "version: 0", 1, 11, "version: 0|@|")
1825
+ assert_invalid_ldif(["unsupported version: %d", 2],
1826
+ "version: 2", 1, 11, "version: 2|@|")
1827
+
1828
+ assert_invalid_ldif("separator is missing",
1829
+ "version: 1", 1, 11, "version: 1|@|")
1830
+ end
1831
+
1832
+ def test_version_spec
1833
+ assert_invalid_ldif("version spec is missing",
1834
+ "", 1, 1, "|@|")
1835
+ assert_invalid_ldif("version spec is missing",
1836
+ "VERSION: 1", 1, 1, "|@|VERSION: 1")
1837
+ assert_invalid_ldif("version number is missing",
1838
+ "version:", 1, 9, "version:|@|")
1839
+ assert_invalid_ldif("version number is missing",
1840
+ "version: ", 1, 10, "version: |@|")
1841
+ assert_invalid_ldif("version number is missing",
1842
+ "version: XXX", 1, 10, "version: |@|XXX")
1843
+ end
1844
+
1845
+ private
1846
+ def assert_ldif(version, records, ldif_source)
1847
+ encoding = ldif_source.encoding if ldif_source.respond_to?(:encoding)
1848
+ ldif = ActiveLdap::Ldif.parse(ldif_source)
1849
+ assert_equal(version, ldif.version)
1850
+ assert_equal(records,
1851
+ ldif.records.collect {|record| record.to_hash})
1852
+
1853
+ regenerated_ldif = ldif.to_s
1854
+ set_encoding(regenerated_ldif, encoding)
1855
+ reparsed_ldif = ActiveLdap::Ldif.parse(regenerated_ldif)
1856
+ assert_equal(ldif, reparsed_ldif)
1857
+
1858
+ ldif
1859
+ end
1860
+
1861
+ def assert_valid_dn(dn, ldif_source)
1862
+ ldif = ActiveLdap::Ldif.parse(ldif_source)
1863
+ assert_equal([dn], ldif.records.collect {|record| record.dn})
1864
+ end
1865
+
1866
+ def assert_valid_version(version, ldif_source)
1867
+ ldif = ActiveLdap::Ldif.parse(ldif_source)
1868
+ assert_equal(version, ldif.version)
1869
+ end
1870
+
1871
+ def assert_invalid_ldif(reason, ldif, line, column, nearest)
1872
+ exception = assert_raise(ActiveLdap::LdifInvalid) do
1873
+ ActiveLdap::Ldif.parse(ldif)
1874
+ end
1875
+ reason, *params = reason
1876
+ params = params.collect {|param| param.is_a?(String) ? _(param) : param}
1877
+ assert_equal([_(reason) % params, line, column, nearest, ldif],
1878
+ [exception.reason, exception.line, exception.column,
1879
+ exception.nearest, exception.ldif])
1880
+ end
1881
+
1882
+ def assert_ldif_to_s(expected_ldif_source, original_ldif_source)
1883
+ ldif = ActiveLdap::Ldif.parse(original_ldif_source)
1884
+ assert_equal(expected_ldif_source, ldif.to_s)
1885
+ end
1886
+
1887
+ def set_encoding(string, encoding)
1888
+ string.force_encoding("utf-8") if string.respond_to?(:force_encoding)
1889
+ end
1890
+ end