activeldap 0.9.0 → 0.10.0

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