powerhome-activeldap 3.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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