roadforest 0.5 → 0.7

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 (63) hide show
  1. checksums.yaml +4 -4
  2. data/examples/file-management.rb +70 -58
  3. data/lib/roadforest/application.rb +9 -17
  4. data/lib/roadforest/application/dispatcher.rb +76 -9
  5. data/lib/roadforest/application/parameters.rb +9 -1
  6. data/lib/roadforest/application/path-provider.rb +30 -3
  7. data/lib/roadforest/application/route-adapter.rb +96 -14
  8. data/lib/roadforest/application/services-host.rb +21 -3
  9. data/lib/roadforest/augment/affordance.rb +82 -11
  10. data/lib/roadforest/augment/augmentation.rb +24 -6
  11. data/lib/roadforest/augment/augmenter.rb +12 -3
  12. data/lib/roadforest/authorization.rb +7 -229
  13. data/lib/roadforest/authorization/auth-entity.rb +26 -0
  14. data/lib/roadforest/authorization/authentication-chain.rb +79 -0
  15. data/lib/roadforest/authorization/default-authentication-store.rb +33 -0
  16. data/lib/roadforest/authorization/grant-builder.rb +23 -0
  17. data/lib/roadforest/authorization/grants-holder.rb +58 -0
  18. data/lib/roadforest/authorization/manager.rb +85 -0
  19. data/lib/roadforest/authorization/policy.rb +19 -0
  20. data/lib/roadforest/graph/access-manager.rb +25 -2
  21. data/lib/roadforest/graph/focus-list.rb +4 -0
  22. data/lib/roadforest/graph/graph-focus.rb +30 -13
  23. data/lib/roadforest/graph/nav-affordance-builder.rb +62 -0
  24. data/lib/roadforest/graph/normalization.rb +3 -3
  25. data/lib/roadforest/graph/path-vocabulary.rb +64 -0
  26. data/lib/roadforest/graph/post-focus.rb +5 -0
  27. data/lib/roadforest/graph/vocabulary.rb +4 -1
  28. data/lib/roadforest/http/adapters/excon.rb +4 -0
  29. data/lib/roadforest/http/graph-transfer.rb +17 -1
  30. data/lib/roadforest/http/keychain.rb +121 -33
  31. data/lib/roadforest/http/user-agent.rb +5 -3
  32. data/lib/roadforest/interface/application.rb +25 -8
  33. data/lib/roadforest/interface/rdf.rb +114 -15
  34. data/lib/roadforest/interface/utility.rb +3 -0
  35. data/lib/roadforest/interface/utility/backfill.rb +63 -0
  36. data/lib/roadforest/interface/utility/grant-list.rb +45 -0
  37. data/lib/roadforest/interface/utility/grant.rb +22 -0
  38. data/lib/roadforest/interfaces.rb +1 -0
  39. data/lib/roadforest/path-matcher.rb +471 -0
  40. data/lib/roadforest/remote-host.rb +159 -35
  41. data/lib/roadforest/resource/read-only.rb +23 -4
  42. data/lib/roadforest/server.rb +32 -3
  43. data/lib/roadforest/source-rigor/graph-store.rb +0 -2
  44. data/lib/roadforest/source-rigor/rigorous-access.rb +138 -21
  45. data/lib/roadforest/templates/affordance-property-values.haml +3 -0
  46. data/lib/roadforest/templates/rdfpost-curie.haml +1 -1
  47. data/lib/roadforest/test-support/matchers.rb +41 -12
  48. data/lib/roadforest/test-support/remote-host.rb +3 -3
  49. data/lib/roadforest/type-handlers/rdfa-writer/environment-decorator.rb +1 -1
  50. data/lib/roadforest/type-handlers/rdfa-writer/render-engine.rb +40 -27
  51. data/lib/roadforest/type-handlers/rdfa.rb +10 -3
  52. data/lib/roadforest/utility/class-registry.rb +44 -4
  53. data/spec/affordance-augmenter.rb +46 -19
  54. data/spec/affordances-flow.rb +46 -30
  55. data/spec/authorization.rb +16 -4
  56. data/spec/client.rb +22 -4
  57. data/spec/focus-list.rb +24 -0
  58. data/spec/full-integration.rb +8 -3
  59. data/spec/graph-store.rb +8 -0
  60. data/spec/keychain.rb +18 -14
  61. data/spec/rdf-normalization.rb +32 -6
  62. data/spec/update-focus.rb +36 -39
  63. metadata +19 -5
@@ -19,7 +19,10 @@ describe "The full affordances flow" do
19
19
  Aff = RoadForest::Graph::Af
20
20
 
21
21
  let :service_host do
22
- RoadForest::Application::ServicesHost.new
22
+ RoadForest::Application::ServicesHost.new.tap do |services|
23
+ services.root_url = "http://example.com/a"
24
+ services.authz.cleartext_grants!
25
+ end
23
26
  end
24
27
 
25
28
  let :content_engine do
@@ -38,10 +41,7 @@ describe "The full affordances flow" do
38
41
  end
39
42
 
40
43
  let :augmenter do
41
- RoadForest::Augment::Augmenter.new.tap do |augmenter|
42
- augmenter.router = router
43
- augmenter.canonical_uri = Addressable::URI.parse("http://example.com/a")
44
- end
44
+ RoadForest::Augment::Augmenter.new(service_host)
45
45
  end
46
46
 
47
47
  let :rdfa do
@@ -138,7 +138,7 @@ describe "The full affordances flow" do
138
138
  end
139
139
 
140
140
  let :put_uri do
141
- EX.a.join("put").to_s
141
+ (EX.a / "put").to_s
142
142
  end
143
143
 
144
144
  it "should parse RDFa back to base_graph" do
@@ -206,11 +206,9 @@ describe "The full affordances flow" do
206
206
  class TestInterface < RoadForest::Interface::RDF
207
207
  end
208
208
 
209
- let :router do
210
- RoadForest::Dispatcher.new(application).tap do |router|
211
- router.add :test, ["a"], :parent, TestInterface
212
- router.add :target, ["z"], :parent, TestInterface
213
- end
209
+ before :each do
210
+ service_host.router.add :test, ["a"], :parent, TestInterface
211
+ service_host.router.add :target, ["z"], :parent, TestInterface
214
212
  end
215
213
 
216
214
  let :base_graph do
@@ -229,14 +227,19 @@ describe "The full affordances flow" do
229
227
  RDF::Repository.new.tap do |graph|
230
228
  graph << [caff, ::RDF.type, Aff.Update]
231
229
  graph << [caff, Aff.target, EX.a]
230
+ graph << [caff, Aff.authorizedBy, "admin"]
232
231
  graph << [uaff, ::RDF.type, Aff.Create]
233
232
  graph << [uaff, Aff.target, EX.a]
233
+ graph << [uaff, Aff.authorizedBy, "admin"]
234
234
  graph << [daff, ::RDF.type, Aff.Remove]
235
235
  graph << [daff, Aff.target, EX.a]
236
+ graph << [daff, Aff.authorizedBy, "admin"]
236
237
  graph << [naff, ::RDF.type, Aff.Navigate]
237
238
  graph << [naff, Aff.target, EX.a]
239
+ graph << [naff, Aff.authorizedBy, "admin"]
238
240
  graph << [onaff, ::RDF.type, Aff.Navigate]
239
241
  graph << [onaff, Aff.target, EX.z]
242
+ graph << [onaff, Aff.authorizedBy, "admin"]
240
243
  end
241
244
  end
242
245
 
@@ -249,10 +252,8 @@ describe "The full affordances flow" do
249
252
  class TestInterface < RoadForest::Interface::RDF
250
253
  end
251
254
 
252
- let :router do
253
- RoadForest::Dispatcher.new(application).tap do |router|
254
- router.add :test, ["a"], :parent, TestInterface
255
- end
255
+ before :each do
256
+ service_host.router.add :test, ["a"], :parent, TestInterface
256
257
  end
257
258
 
258
259
  let :base_graph do
@@ -266,17 +267,20 @@ describe "The full affordances flow" do
266
267
  uaff = ::RDF::Node.new(:uaff)
267
268
  naff = ::RDF::Node.new(:naff)
268
269
  daff = ::RDF::Node.new(:daff)
269
- zaff = ::RDF::Node.new(:zaff)
270
270
 
271
271
  RDF::Repository.new.tap do |graph|
272
272
  graph << [caff, ::RDF.type, Aff.Update]
273
273
  graph << [caff, Aff.target, EX.a]
274
+ graph << [caff, Aff.authorizedBy, "admin"]
274
275
  graph << [uaff, ::RDF.type, Aff.Create]
275
276
  graph << [uaff, Aff.target, EX.a]
277
+ graph << [uaff, Aff.authorizedBy, "admin"]
276
278
  graph << [daff, ::RDF.type, Aff.Remove]
277
279
  graph << [daff, Aff.target, EX.a]
280
+ graph << [daff, Aff.authorizedBy, "admin"]
278
281
  graph << [naff, ::RDF.type, Aff.Navigate]
279
282
  graph << [naff, Aff.target, EX.a]
283
+ graph << [naff, Aff.authorizedBy, "admin"]
280
284
  end
281
285
  end
282
286
 
@@ -289,10 +293,8 @@ describe "The full affordances flow" do
289
293
  class TestInterface < RoadForest::Interface::RDF
290
294
  end
291
295
 
292
- let :router do
293
- RoadForest::Dispatcher.new(application).tap do |router|
294
- router.add :test, ["a"], :parent, TestInterface
295
- end
296
+ before :each do
297
+ service_host.router.add :test, ["a"], :parent, TestInterface
296
298
  end
297
299
 
298
300
  let :base_graph do
@@ -311,12 +313,20 @@ describe "The full affordances flow" do
311
313
  RDF::Repository.new.tap do |graph|
312
314
  graph << [caff, ::RDF.type, Aff.Update]
313
315
  graph << [caff, Aff.target, EX.a]
316
+ graph << [caff, Aff.authorizedBy, "admin"]
317
+
314
318
  graph << [uaff, ::RDF.type, Aff.Create]
315
319
  graph << [uaff, Aff.target, EX.a]
320
+ graph << [uaff, Aff.authorizedBy, "admin"]
321
+
316
322
  graph << [daff, ::RDF.type, Aff.Remove]
317
323
  graph << [daff, Aff.target, EX.a]
324
+ graph << [daff, Aff.authorizedBy, "admin"]
325
+
318
326
  graph << [naff, ::RDF.type, Aff.Navigate]
319
327
  graph << [naff, Aff.target, EX.a]
328
+ graph << [naff, Aff.authorizedBy, "admin"]
329
+
320
330
  graph << [zaff, ::RDF.type, Aff.Null]
321
331
  graph << [zaff, Aff.target, EX.z]
322
332
  end
@@ -334,12 +344,10 @@ describe "The full affordances flow" do
334
344
  class Blobby < RoadForest::Interface::Blob
335
345
  end
336
346
 
337
- let :router do
338
- RoadForest::Dispatcher.new(application).tap do |router|
339
- router.add :test, ["a"], :parent, TestInterface
340
- router.add :blob, ["z"], :leaf, RoadForest::Interface::Blob do |route|
341
- route.content_engine = RoadForest::ContentHandling.images_engine
342
- end
347
+ before :each do
348
+ service_host.router.add :test, ["a"], :parent, TestInterface
349
+ service_host.router.add :blob, ["z"], :leaf, RoadForest::Interface::Blob do |route|
350
+ route.content_engine = RoadForest::ContentHandling.images_engine
343
351
  end
344
352
  end
345
353
 
@@ -359,14 +367,19 @@ describe "The full affordances flow" do
359
367
  RDF::Repository.new.tap do |graph|
360
368
  graph << [caff, ::RDF.type, Aff.Update]
361
369
  graph << [caff, Aff.target, EX.a]
370
+ graph << [caff, Aff.authorizedBy, "admin"]
362
371
  graph << [uaff, ::RDF.type, Aff.Create]
363
372
  graph << [uaff, Aff.target, EX.a]
373
+ graph << [uaff, Aff.authorizedBy, "admin"]
364
374
  graph << [daff, ::RDF.type, Aff.Remove]
365
375
  graph << [daff, Aff.target, EX.a]
376
+ graph << [daff, Aff.authorizedBy, "admin"]
366
377
  graph << [naff, ::RDF.type, Aff.Navigate]
367
378
  graph << [naff, Aff.target, EX.a]
379
+ graph << [naff, Aff.authorizedBy, "admin"]
368
380
  graph << [eaff, ::RDF.type, Aff.Embed]
369
381
  graph << [eaff, Aff.target, EX.z]
382
+ graph << [eaff, Aff.authorizedBy, "admin"]
370
383
  end
371
384
  end
372
385
 
@@ -379,10 +392,8 @@ describe "The full affordances flow" do
379
392
  class TestInterface < RoadForest::Interface::RDF
380
393
  end
381
394
 
382
- let :router do
383
- RoadForest::Dispatcher.new(application).tap do |router|
384
- router.add :test, ["a"], :parent, TestInterface
385
- end
395
+ before :each do
396
+ service_host.router.add :test, ["a"], :parent, TestInterface
386
397
  end
387
398
 
388
399
  let :base_graph do
@@ -406,6 +417,11 @@ describe "The full affordances flow" do
406
417
  graph << [daff, Aff.target, EX.a]
407
418
  graph << [naff, ::RDF.type, Aff.Navigate]
408
419
  graph << [naff, Aff.target, EX.a]
420
+
421
+ graph << [caff, Aff.authorizedBy, "admin"]
422
+ graph << [uaff, Aff.authorizedBy, "admin"]
423
+ graph << [daff, Aff.authorizedBy, "admin"]
424
+ graph << [naff, Aff.authorizedBy, "admin"]
409
425
  end
410
426
  end
411
427
 
@@ -7,6 +7,19 @@ describe RoadForest::Authorization do
7
7
  end
8
8
  end
9
9
 
10
+ def req_with_header(header)
11
+ req = double("Webmachine::Request")
12
+ req.stub(:headers).and_return({"Authorization" => header})
13
+ req
14
+ end
15
+
16
+ def req_with_cert(file)
17
+ cert = OpenSSL::X509::Certificate.new(File.read(file))
18
+ req = double("Webmachine::Request")
19
+ req.stub(:headers).and_return({})
20
+ req.stub(:client_cert).and_return(cert)
21
+ end
22
+
10
23
  describe "default setup" do
11
24
  let :requires_admin do
12
25
  manager.build_grants do |grants|
@@ -15,20 +28,19 @@ describe RoadForest::Authorization do
15
28
  end
16
29
 
17
30
  it "should refuse an unauthenticated user" do
18
- manager.authorization(nil, requires_admin).should == :refused
31
+ manager.authorization(req_with_header(nil), requires_admin).should == :refused
19
32
  end
20
33
 
21
34
  it "should grant an authenticated user" do
22
- manager.authorization("Basic #{Base64.encode64("user:secret")}", requires_admin).should == :granted
35
+ manager.authorization(req_with_header("Basic #{Base64.encode64("user:secret")}"), requires_admin).should == :granted
23
36
  end
24
37
 
25
38
  it "should refuse a garbage authentication header" do
26
- manager.authorization("some garbage here", requires_admin).should == :refused
39
+ manager.authorization(req_with_header("some garbage here"), requires_admin).should == :refused
27
40
  end
28
41
 
29
42
  it "should construct a valid challenge header" do
30
43
  manager.challenge(:realm => "This test here").should == 'Basic realm="This test here"'
31
-
32
44
  end
33
45
  end
34
46
  end
@@ -12,21 +12,39 @@ describe RoadForest::RemoteHost do
12
12
 
13
13
  let :services do
14
14
  require 'logger'
15
+ require 'roadforest/type-handlers/jsonld'
16
+ require 'roadforest/type-handlers/rdfa'
15
17
  FileManagementExample::ServicesHost.new.tap do |host|
18
+ host.root_url = "http://localhost:8778/" # +/- a '/' at the end is finicky.
16
19
  host.file_records = [
17
20
  FileManagementExample::FileRecord.new("one", false),
18
21
  FileManagementExample::FileRecord.new("two", false),
19
22
  FileManagementExample::FileRecord.new("three", false)
20
23
  ]
24
+
25
+ rdfa = RoadForest::TypeHandlers::RDFa.new
26
+ rdfa.haml_options = {:ugly => false}
27
+ jsonld = RoadForest::TypeHandlers::JSONLD.new
28
+
29
+ host.default_content_engine = RoadForest::ContentHandling::Engine.new.tap do |engine|
30
+ engine.add rdfa, "text/html;q=1;rdfa=1"
31
+ engine.add rdfa, "application/xhtml+xml;q=1;rdfa=1"
32
+ engine.add jsonld, "application/ld+json"
33
+ engine.add rdfa, "text/html;q=0.5"
34
+ engine.add rdfa, "application/xhtml+xml;q=0.5"
35
+ end
36
+
21
37
  host.destination_dir = destination_dir
22
38
  host.authz.authenticator.add_account("user", "secret", "token")
39
+ host.authz.cleartext_grants!
23
40
  end
24
41
  end
25
42
 
26
43
  let :base_server do
27
- RoadForest::TestSupport::RemoteHost.new(FileManagementExample::Application.new("http://localhost:8778", services)).tap do |server|
44
+ RoadForest::TestSupport::RemoteHost.new(services).tap do |server|
28
45
  server.add_credentials("user", "secret")
29
- # server.trace = true
46
+ #server.http_trace = true
47
+ #server.graph_trace = true
30
48
  end
31
49
  end
32
50
 
@@ -102,7 +120,7 @@ describe RoadForest::RemoteHost do
102
120
  end
103
121
  end
104
122
  ensure
105
- dump_trace
123
+ #dump_trace
106
124
  end
107
125
  end
108
126
 
@@ -170,7 +188,7 @@ describe RoadForest::RemoteHost do
170
188
 
171
189
  it "should return correct content-type" do
172
190
  server.http_exchanges.each do |exchange|
173
- exchange.response.headers["Content-Type"].should == content_type
191
+ [content_type, nil].should include(exchange.response.headers["Content-Type"])
174
192
  end
175
193
  end
176
194
  end
@@ -21,6 +21,30 @@ describe RoadForest::Graph::FocusList do
21
21
  focus.as_list
22
22
  end
23
23
 
24
+ it "should render correctly empty" do
25
+ focus.add_list(:rdf, :value)
26
+
27
+ graph.should match_query { |query|
28
+ query.pattern(:object => RDF.nil)
29
+ }
30
+ end
31
+
32
+ it "should raise error if trying to append to an empty list" do
33
+ list = focus.add_list(:rdf, :value)
34
+
35
+ expect{ list.append_node("#1") }.to raise_error
36
+ end
37
+
38
+ it "should append nodes in an added list" do
39
+ focus.add_list(:rdf, :value) do |list|
40
+ list.append_node("#1")
41
+ end
42
+
43
+ graph.should match_query { |query|
44
+ query.pattern(:object => RDF::URI.new("urn:root#1"))
45
+ }
46
+ end
47
+
24
48
  it "should add an item to graph" do
25
49
  list.append_node("#test")
26
50
 
@@ -31,8 +31,8 @@ describe "RoadForest integration", :integration => true do
31
31
  require 'logger'
32
32
 
33
33
  RoadForest.serve(
34
- FileManagementExample::Application.new("http://localhost:#{@server_port}"),
35
34
  FileManagementExample::ServicesHost.new.tap do |host|
35
+ host.root_url = "https://localhost:#{@server_port}"
36
36
  host.file_records = [
37
37
  FileManagementExample::FileRecord.new("one", false),
38
38
  FileManagementExample::FileRecord.new("two", false),
@@ -42,9 +42,13 @@ describe "RoadForest integration", :integration => true do
42
42
  host.logger = Logger.new("integration-test.log")
43
43
  host.logger.level = Logger::DEBUG
44
44
  host.authz.authenticator.add_account("admin", "passwerd", "toktok")
45
+ host.authz.authenticator.add_account("admin@test.com", nil, nil) #nil password cannot authn
45
46
  end
46
47
  ) do |config|
47
48
  config.port = @server_port
49
+ RoadForest::SSL.enable(config, "spec_support/fixtures/server-key.pem", "spec_support/fixtures/server.cert")
50
+ RoadForest::SSL.add_ca_cert(config, "spec_support/fixtures/ca.cert")
51
+ RoadForest::SSL.add_client_verify(config)
48
52
  end
49
53
  end
50
54
 
@@ -82,12 +86,13 @@ describe "RoadForest integration", :integration => true do
82
86
  end
83
87
 
84
88
  let :server_url do
85
- "http://localhost:#{@server_port}"
89
+ "https://localhost:#{@server_port}"
86
90
  end
87
91
 
88
92
  let :server do
89
93
  server = RoadForest::RemoteHost.new(server_url)
90
- server.add_credentials("admin","passwerd")
94
+ server.use_ca_cert("spec_support/fixtures/ca.cert")
95
+ server.use_client_tls("spec_support/fixtures/client-key.pem", "spec_support/fixtures/client.cert")
91
96
  #server.trace = true
92
97
  server
93
98
  end
@@ -152,5 +152,13 @@ describe RoadForest::Graph do
152
152
  query.pattern [:subject, RDF::DC.dateCopyrighted, :value]
153
153
  end.execute(graph_store).should_not be_empty
154
154
  end
155
+
156
+ it "should be able insert statement-ish items" do
157
+ node = ::RDF::Node.new
158
+ step << [ node, ::RDF.type, [:dc, :dateCopyrighted]]
159
+ graph_store.should match_query{
160
+ pattern [ :node, ::RDF.type, ::RDF::DC.dateCopyrighted ]
161
+ }
162
+ end
155
163
  end
156
164
  end
@@ -40,12 +40,21 @@ describe RoadForest::HTTP::Keychain do
40
40
  end
41
41
 
42
42
  describe "#preemptive_response" do
43
+ subject :source do
44
+ RoadForest::HTTP::PreparedCredentialSource.new.tap do |source|
45
+ source.add("http://example.com/test/", username, password)
46
+ end
47
+ end
43
48
  subject :keychain do
44
49
  RoadForest::HTTP::Keychain.new.tap do |chain|
45
- chain.add("http://example.com/test/", username, password)
50
+ chain.add_source(source)
46
51
  end
47
52
  end
48
53
 
54
+ before :each do
55
+ keychain.challenge_response("http://example.com/test/", "Basic Realm='testing'")
56
+ end
57
+
49
58
  it "should return matching creds" do
50
59
  creds = keychain.preemptive_response("http://example.com/test/under/here/")
51
60
  creds.should == expected_header
@@ -58,25 +67,20 @@ describe RoadForest::HTTP::Keychain do
58
67
  end
59
68
 
60
69
  describe "#challenge_response" do
70
+ subject :source do
71
+ RoadForest::HTTP::PreparedCredentialSource.new.tap do |source|
72
+ source.add("http://example.com/test/", username, password)
73
+ end
74
+ end
61
75
  subject :keychain do
62
76
  RoadForest::HTTP::Keychain.new.tap do |chain|
63
- chain.add("http://example.com/test/", username, password, "test")
77
+ chain.add_source(source)
64
78
  end
65
79
  end
66
80
 
67
- it "should return matching creds" do
68
- creds = keychain.challenge_response("http://example.com/", "Basic realm='test'")
69
- creds.should == expected_header
70
- end
71
-
72
- it "should not return covering creds" do
81
+ it "should prepared creds" do
73
82
  creds = keychain.challenge_response("http://example.com/test/under/here/", "Basic realm='other'")
74
- creds.should be_nil
75
- end
76
-
77
- it "should not return non-matching creds" do
78
- creds = keychain.challenge_response("http://example.com/", "Basic realm='other'")
79
- creds.should be_nil
83
+ creds.should == expected_header
80
84
  end
81
85
  end
82
86
  end
@@ -3,15 +3,41 @@ require 'roadforest/graph/normalization'
3
3
  describe RoadForest::Graph::Normalization do
4
4
  include described_class
5
5
 
6
- it "should match http://test.com and http://test.com/" do
7
- normalize_resource("http://test.com").to_s.should == normalize_resource("http://test.com/").to_s
6
+ describe "#normalize_term" do
7
+ it "should resolve a curie" do
8
+ normalize_term([:rf, "Impulse"]).to_s.should == "http://lrdesign.com/graph/roadforest#Impulse"
9
+ end
8
10
  end
9
11
 
10
- it "should match http://test.com:8888 and http://test.com:8888/" do
11
- normalize_resource("http://test.com:8888").to_s.should == "http://test.com:8888/"
12
+ describe "#normalize_resource" do
13
+ it "should match http://test.com and http://test.com/" do
14
+ normalize_resource("http://test.com").to_s.should == normalize_resource("http://test.com/").to_s
15
+ end
16
+
17
+ it "should match http://test.com:8888 and http://test.com:8888/" do
18
+ normalize_resource("http://test.com:8888").to_s.should == "http://test.com:8888/"
19
+ end
20
+
21
+ it "should match http://localhost:8778 and http://localhost:8778/" do
22
+ normalize_resource("http://localhost:8778").to_s.should == "http://localhost:8778/"
23
+ end
12
24
  end
13
25
 
14
- it "should match http://localhost:8778 and http://localhost:8778/" do
15
- normalize_resource("http://localhost:8778").to_s.should == "http://localhost:8778/"
26
+ describe "normalize_context" do
27
+ it "should remove fragment part" do
28
+ normalize_context("http://localhost:8778/place#fragment").to_s.should == "http://localhost:8778/place"
29
+ end
30
+
31
+ it "should remove the fragment from a frozen URL" do
32
+ uri = ::RDF::URI.new("http://localhost:8778/place#fragment").freeze
33
+
34
+ normalize_context(uri).to_s.should == "http://localhost:8778/place"
35
+ end
36
+
37
+ it "should remove the fragment from an array-wrapped frozen URL" do
38
+ uri = ::RDF::URI.new("http://localhost:8778/place#fragment").freeze
39
+
40
+ normalize_context([uri]).to_s.should == "http://localhost:8778/place"
41
+ end
16
42
  end
17
43
  end