gdocs_features 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. data/README +0 -0
  2. data/Rakefile +35 -0
  3. data/VERSION +1 -0
  4. data/bin/remotefeatures +7 -0
  5. data/cucumber.yml +2 -0
  6. data/features/patch_local_files_from_gdocs.feature +33 -0
  7. data/features/step_definitions/diff_steps.rb +19 -0
  8. data/features/step_definitions/google_steps.rb +19 -0
  9. data/features/step_definitions/local_steps.rb +16 -0
  10. data/features/support/env.rb +5 -0
  11. data/gdocs_features.gemspec +97 -0
  12. data/lib/difference.rb +31 -0
  13. data/lib/feature.rb +26 -0
  14. data/lib/feature_diff.rb +46 -0
  15. data/lib/file_feature.rb +37 -0
  16. data/lib/file_feature_store.rb +17 -0
  17. data/lib/google_authorization.rb +18 -0
  18. data/lib/google_docs_client.rb +20 -0
  19. data/lib/google_feature.rb +51 -0
  20. data/lib/google_feature_store.rb +44 -0
  21. data/lib/google_resource.rb +11 -0
  22. data/lib/remote_features/cli/main.rb +30 -0
  23. data/lib/remote_features/dialogue.rb +25 -0
  24. data/pkg/gdocs_features-0.1.0.gem +0 -0
  25. data/spec/cli_spec.rb +69 -0
  26. data/spec/dialogue_spec.rb +69 -0
  27. data/spec/feature_diff_spec.rb +80 -0
  28. data/spec/feature_reformat_spec.rb +40 -0
  29. data/spec/file_feature_spec.rb +23 -0
  30. data/spec/file_feature_store_spec.rb +33 -0
  31. data/spec/google_authorization_spec.rb +26 -0
  32. data/spec/google_docs_client_spec.rb +32 -0
  33. data/spec/google_feature_spec.rb +46 -0
  34. data/spec/google_feature_store_spec.rb +64 -0
  35. data/spec/google_resource_spec.rb +25 -0
  36. data/spec/integration_spec.rb +42 -0
  37. data/spec/spec_helper.rb +5 -0
  38. data/spec/stubs/documents.atom.xml +36 -0
  39. data/spec/stubs/example.feature +16 -0
  40. data/spec/stubs/folders.atom.xml +69 -0
  41. data/spec/temp_file_system.rb +19 -0
  42. data/spec/temp_file_system_spec.rb +28 -0
  43. metadata +117 -0
data/spec/cli_spec.rb ADDED
@@ -0,0 +1,69 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ require 'file_feature_store'
4
+ require 'google_feature_store'
5
+ require 'remote_features/cli/main'
6
+ require 'remote_features/dialogue'
7
+
8
+ describe RemoteFeatures::Cli::Main do
9
+ before do
10
+ $stdout.stub!(:puts)
11
+ Kernel.stub!(:exit)
12
+ RemoteFeatures::Dialogue.stub!(:new).and_return(mock("dialogue", :start => nil))
13
+ end
14
+
15
+ it "should create a file feature store with the first argument as the path" do
16
+ file_store = mock("file_store")
17
+ gdocs_store = mock("gdocs_store")
18
+ FileFeatureStore.should_receive(:new).with("some/dir").and_return(file_store)
19
+ GoogleFeatureStore.stub!(:new).and_return(gdocs_store)
20
+ RemoteFeatures::Cli::Main.execute(["some/dir", "joshski:pass@docs.google.com"])
21
+ end
22
+
23
+ it "should create a google feature store when argument 2 matches user:pass@docs.google.com" do
24
+ file_store = mock("file_store")
25
+ gdocs_store = mock("gdocs_store")
26
+ client = mock("client")
27
+ FileFeatureStore.stub!(:new).and_return(file_store)
28
+ GoogleDocsClient.should_receive(:new).with("joshski", "pass").and_return(client)
29
+ GoogleFeatureStore.should_receive(:new).with(client).and_return(gdocs_store)
30
+ RemoteFeatures::Cli::Main.execute(["some/dir", "joshski:pass@docs.google.com"])
31
+ end
32
+
33
+ describe "with invalid arguments", :shared => true do
34
+ it "should show usage" do
35
+ [FileFeatureStore, GoogleFeatureStore, GoogleDocsClient].each { |c| c.stub!(:new) }
36
+ $stdout.should_receive(:puts).with("Usage: remotefeatures <directory> <user:password@host>")
37
+ RemoteFeatures::Cli::Main.execute(@args)
38
+ end
39
+
40
+ it "should not create anything" do
41
+ [FileFeatureStore, GoogleFeatureStore, GoogleDocsClient].each do |c|
42
+ c.should_not_receive(:new)
43
+ end
44
+ RemoteFeatures::Cli::Main.execute(@args)
45
+ RemoteFeatures::Dialogue.should_not_receive(:new)
46
+ end
47
+ end
48
+
49
+ describe "with no arguments" do
50
+ before { @args = [] }
51
+ it_should_behave_like "with invalid arguments"
52
+ end
53
+
54
+ describe "with only first argument" do
55
+ before { @args = ["."] }
56
+ it_should_behave_like "with invalid arguments"
57
+ end
58
+
59
+ describe "with three arguments" do
60
+ before { @args = ["valid", "valid:valid@valid.com", "invalid"] }
61
+ it_should_behave_like "with invalid arguments"
62
+ end
63
+
64
+ describe "with invalid url argument" do
65
+ before { @args = ["valid", "in-valid@valid.com"] }
66
+ it_should_behave_like "with invalid arguments"
67
+ end
68
+
69
+ end
@@ -0,0 +1,69 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ require 'remote_features/dialogue'
4
+ require 'feature_diff'
5
+
6
+ describe RemoteFeatures::Dialogue do
7
+
8
+ before do
9
+ @local_store = mock("local_store")
10
+ @remote_store = mock("remote_store")
11
+ @io = mock("io", :puts => nil, :gets => "")
12
+ @diff = mock("diff", :differences => {}, :patch => nil)
13
+ @dialogue = RemoteFeatures::Dialogue.new(@io, @io, @local_store, @remote_store)
14
+ FeatureDiff.stub!(:new).with(@local_store, @remote_store).and_return(@diff)
15
+
16
+ @first_local_feature = mock("first_local_feature", :path => 'first/example.feature')
17
+ @first_remote_feature = mock("first_remote_feature", :path => 'first/example.feature')
18
+ @second_local_feature = mock("second_local_feature", :path => 'second/example.feature')
19
+ @second_remote_feature = mock("second_remote_feature", :path => 'second/example.feature')
20
+ @first_difference = Difference.new(@first_local_feature, @first_remote_feature, @local_store)
21
+ @second_difference = Difference.new(@second_local_feature, @second_remote_feature, @local_store)
22
+ @diff.stub!(:differences).and_return({
23
+ @first_difference.path => @first_difference,
24
+ @second_difference.path => @second_difference
25
+ })
26
+ @expected_diff_output = "1) updated - first/example.feature\n2) updated - second/example.feature"
27
+ end
28
+
29
+ it "should perform a feature diff" do
30
+ FeatureDiff.should_receive(:new).with(@local_store, @remote_store).and_return(@diff)
31
+ @dialogue.start
32
+ end
33
+
34
+ it "should render the results of the feature diff to the output" do
35
+ @io.should_receive(:puts).with(@expected_diff_output)
36
+ @dialogue.start
37
+ end
38
+
39
+ it "should prompt for patch numbers to apply" do
40
+ @io.stub!(:puts).with(@expected_diff_output)
41
+ @io.should_receive(:puts).with("Enter changes to apply, 'all' to apply all, or blank to exit")
42
+ @dialogue.start
43
+ end
44
+
45
+ it "should accept a list of change numbers to apply" do
46
+ @io.should_receive(:gets).and_return("1 67 99\n")
47
+ @dialogue.start
48
+ end
49
+
50
+ it "should apply the selected patches" do
51
+ @io.stub!(:gets).and_return("1 67 99\n")
52
+ @diff.should_receive(:patch).with([1, 67, 99])
53
+ @dialogue.start
54
+ end
55
+
56
+ it "should exit when there are no differences" do
57
+ @diff.stub!(:differences).and_return({})
58
+ Kernel.should_receive(:exit)
59
+ @dialogue.start
60
+ end
61
+
62
+ it "should write a message when there are no differences" do
63
+ @diff.stub!(:differences).and_return({})
64
+ Kernel.stub!(:exit)
65
+ @io.should_receive(:puts)
66
+ @dialogue.start
67
+ end
68
+
69
+ end
@@ -0,0 +1,80 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ require 'feature_diff'
4
+ require 'google_docs_client'
5
+ require 'google_feature_store'
6
+ require 'file_feature_store'
7
+
8
+ describe FeatureDiff do
9
+
10
+ it "should find updated features where versions are different" do
11
+ local_feature = mock("local_feature", :path => '/the/same.feature', :version => '123')
12
+ remote_feature = mock("remote_feature", :path => '/the/same.feature', :version => '124')
13
+ local_store = mock("local_store", :features => [local_feature])
14
+ remote_store = mock("remote_store", :features => [remote_feature])
15
+ diff = FeatureDiff.new(local_store, remote_store)
16
+ diff['/the/same.feature'].local.should == local_feature
17
+ diff['/the/same.feature'].remote.should == remote_feature
18
+ end
19
+
20
+ it "should find remote only features" do
21
+ remote_feature = mock("remote_feature", :path => '/remote/only.feature', :version => '123')
22
+ local_store = mock("local_store", :features => [])
23
+ remote_store = mock("remote_store", :features => [remote_feature])
24
+ diff = FeatureDiff.new(local_store, remote_store)
25
+ diff['/remote/only.feature'].remote.should == remote_feature
26
+ diff['/remote/only.feature'].local.should be_nil
27
+ end
28
+
29
+ it "should find local only features" do
30
+ local_feature = mock("local_feature", :path => '/local/only.feature', :version => '123')
31
+ local_store = mock("local_store", :features => [local_feature])
32
+ remote_store = mock("remote_store", :features => [])
33
+ diff = FeatureDiff.new(local_store, remote_store)
34
+ diff['/local/only.feature'].local.should == local_feature
35
+ diff['/local/only.feature'].remote.should be_nil
36
+ end
37
+
38
+ it "should patch remote only features" do
39
+ remote_feature = mock("remote_feature", :path => 'any/old.feature', :version => '789', :reformat => 'OK!')
40
+ local_store = mock("local_store", :features => [])
41
+ remote_store = mock("remote_store", :features => [remote_feature])
42
+ diff = FeatureDiff.new(local_store, remote_store)
43
+ local_store.should_receive(:create_feature).with('any/old.feature', '789', 'OK!')
44
+ diff.patch
45
+ end
46
+
47
+ it "should patch updated features" do
48
+ local_feature = mock("local_feature", :path => '/the/same.feature', :version => '123')
49
+ remote_feature = mock("remote_feature", :path => '/the/same.feature', :version => '124')
50
+ local_store = mock("local_store", :features => [local_feature])
51
+ remote_store = mock("remote_store", :features => [remote_feature])
52
+ diff = FeatureDiff.new(local_store, remote_store)
53
+ local_feature.should_receive(:patch_from).with(remote_feature)
54
+ diff.patch
55
+ end
56
+
57
+ it "should patch subset of differences" do
58
+ local_one = mock("local_one", :path => '/the/one.feature', :version => '123')
59
+ local_two = mock("local_two", :path => '/the/two.feature', :version => '123')
60
+ remote_one = mock("remote_one", :path => '/the/one.feature', :version => 'higher')
61
+ remote_two = mock("remote_two", :path => '/the/two.feature', :version => 'higher')
62
+ local_store = mock("local_store", :features => [local_one, local_two])
63
+ remote_store = mock("remote_store", :features => [remote_one, remote_two])
64
+ diff = FeatureDiff.new(local_store, remote_store)
65
+ local_one.should_receive(:patch_from).with(remote_one)
66
+ local_two.should_not_receive(:patch_from).with(remote_two)
67
+ diff.patch([1])
68
+ end
69
+
70
+ it "should not patch local only features" do
71
+ local_feature = mock("local_feature", :path => '/the/same.feature', :version => '123')
72
+ local_store = mock("local_store", :features => [local_feature])
73
+ remote_store = mock("remote_store", :features => [])
74
+ diff = FeatureDiff.new(local_store, remote_store)
75
+ local_feature.should_not_receive(:patch_from)
76
+ diff.patch
77
+ end
78
+
79
+ end
80
+
@@ -0,0 +1,40 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ $reformatted = %{Feature: Washing up
4
+
5
+ In order to reduce infection
6
+ As a user of kitchenware
7
+ I want to wash up after use
8
+
9
+ Scenario: Wash dishes
10
+
11
+ Given there is a dish
12
+ And it is dirty
13
+ Then I should wash it up
14
+
15
+ Scenario: Dishwasher
16
+
17
+ Given there are lots of dirty dishes
18
+ When I put them into the dishwasher
19
+ And I turn it on
20
+ Then it should wash the dishes}
21
+
22
+ require 'feature'
23
+
24
+ describe Feature, "reformat" do
25
+
26
+ class StubFeature < Feature
27
+ def body
28
+ $reformatted.map { |line| line.strip }.reject { |l| l == "" }
29
+ end
30
+
31
+ def version
32
+ 123
33
+ end
34
+ end
35
+
36
+ it "should reformat feature body" do
37
+ StubFeature.new.reformat.should == $reformatted
38
+ end
39
+
40
+ end
@@ -0,0 +1,23 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ require 'file_feature'
4
+
5
+ describe FileFeature do
6
+
7
+ before do
8
+ @feature = FileFeature.new(File.dirname(__FILE__), "stubs/example.feature")
9
+ end
10
+
11
+ it "should expose a body from the file" do
12
+ @feature.body.first.should == "Feature: Example"
13
+ end
14
+
15
+ it "should expose a title from the filename" do
16
+ @feature.title.should == "example"
17
+ end
18
+
19
+ it "should get the version from the first line of comment in the file" do
20
+ @feature.version.should == "123"
21
+ end
22
+
23
+ end
@@ -0,0 +1,33 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+ require File.dirname(__FILE__) + '/temp_file_system'
3
+
4
+ require 'file_feature_store'
5
+
6
+ describe FileFeatureStore do
7
+
8
+ before do
9
+ @fs = TempFileSystem.new(
10
+ 'my/stuff/banana.feature' => 'OK'
11
+ )
12
+ end
13
+
14
+ after do
15
+ @fs.destroy
16
+ end
17
+
18
+ it "should find files with .feature extension" do
19
+ store = FileFeatureStore.new("/some/dir")
20
+ Dir.should_receive(:glob).with("/some/dir/**/*.feature").and_return([])
21
+ store.features
22
+ end
23
+
24
+ describe "with a physical file store" do
25
+
26
+ it "should find features" do
27
+ store = FileFeatureStore.new(@fs.root)
28
+ store.features.first.title.should == "banana"
29
+ end
30
+
31
+ end
32
+
33
+ end
@@ -0,0 +1,26 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ require 'google_authorization'
4
+
5
+ describe GoogleAuthorization do
6
+
7
+ it "should post to the authorization resource once on first access of header" do
8
+ RestClient.stub!(:post).and_return("xxxAuth=ABC")
9
+ auth = GoogleAuthorization.new("email", "pass")
10
+ auth.header.should == "GoogleLogin auth=ABC"
11
+ RestClient.stub!(:post).and_raise "shouldn't post twice"
12
+ auth.header
13
+ end
14
+
15
+ it "should post the correct url and parameters when authorizing" do
16
+ url = "https://www.google.com/accounts/ClientLogin"
17
+ params = { "accountType" => "HOSTED_OR_GOOGLE", "Email" => "email", "Passwd" => "pass", "service" => "writely" }
18
+ RestClient.should_receive(:post).with(url, hash_including(params))
19
+ GoogleAuthorization.new("email", "pass").authorize
20
+ end
21
+
22
+ it "should authorize with a real rest client" do
23
+ GoogleAuthorization.new("restapitest@googlemail.com", "testrestapi").authorize.size.should > 100
24
+ end
25
+
26
+ end
@@ -0,0 +1,32 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ require 'google_docs_client'
4
+
5
+ describe GoogleDocsClient do
6
+
7
+ it "should get the documents feed as a resource" do
8
+ client = GoogleDocsClient.new("restapitest", "testrestapi")
9
+ resource = mock("resource")
10
+ GoogleResource.should_receive(:new).and_return(resource)
11
+ resource.should_receive(:get).and_return("OK")
12
+ client.documents_feed.get.to_s.should == "OK"
13
+ end
14
+
15
+ describe "connected to Google" do
16
+
17
+ before do
18
+ @client = GoogleDocsClient.new("restapitest@googlemail.com", "testrestapi")
19
+ end
20
+
21
+ it "should get the documents feed" do
22
+ @client.documents_feed.get.to_s.should =~ /<feed/
23
+ end
24
+
25
+ it "should get folders" do
26
+ @client.folders.get.to_s.should =~ /<feed/
27
+ end
28
+
29
+ end
30
+
31
+ end
32
+
@@ -0,0 +1,46 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ $reformatted = %{Feature: Washing up
4
+
5
+ In order to reduce infection
6
+ As a user of kitchenware
7
+ I want to wash up after use
8
+
9
+ Scenario: Wash dishes
10
+
11
+ Given there is a dish
12
+ And it is dirty
13
+ Then I should wash it up
14
+
15
+ Scenario: Dishwasher
16
+
17
+ Given there are lots of dirty dishes
18
+ When I put them into the dishwasher
19
+ And I turn it on
20
+ Then it should wash the dishes}
21
+
22
+ require 'google_feature'
23
+
24
+ describe Feature, "reformat" do
25
+
26
+ class StubFeature < GoogleFeature
27
+ def body
28
+ $reformatted.map { |line| line.strip }.reject { |l| l == "" }
29
+ end
30
+
31
+ def version
32
+ 123
33
+ end
34
+ end
35
+
36
+ it "should reformat feature body" do
37
+ it "should not have css in the file" do
38
+ auth = mock("auth", :header => "xxx")
39
+ RestClient.should_receive(:get).with("url", hash_including("Authorization" => "xxx"))
40
+ GoogleFeature.new(auth, "url").get
41
+
42
+ end
43
+ StubFeature.new.reformat.should == $reformatted
44
+ end
45
+
46
+ end
@@ -0,0 +1,64 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ require 'google_feature_store'
4
+ require 'google_docs_client'
5
+
6
+ def relative_path(path)
7
+ File.join(File.dirname(__FILE__), path)
8
+ end
9
+
10
+ def stub_folders_feed
11
+ mock("folders_feed", :get => File.readlines(relative_path('./stubs/folders.atom.xml')).map {|l| l.rstrip})
12
+ end
13
+
14
+ def stub_documents_feed
15
+ mock("documents_feed", :get => File.readlines(relative_path('./stubs/documents.atom.xml')).map {|l| l.rstrip})
16
+ end
17
+
18
+ describe GoogleFeatureStore do
19
+
20
+ describe "creating features from feed" do
21
+
22
+ before do
23
+ @body = "happy"
24
+ client = mock("client",
25
+ :folders => stub_folders_feed,
26
+ :documents_feed => stub_documents_feed,
27
+ :document_body => mock("document_body", :get => @body))
28
+ @features = GoogleFeatureStore.new(client).features
29
+ @banana = @features.first
30
+ end
31
+
32
+ it "should expose a list of features" do
33
+ @features.size.should == 1
34
+ end
35
+
36
+ it "should expose a body from a resource" do
37
+ @banana.body.should == [@body]
38
+ end
39
+
40
+ it "should expose a body from the entry" do
41
+ @banana.title.should == "banana"
42
+ end
43
+
44
+ it "should expose a version from the entry modified date" do
45
+ @banana.version.should == "2009-02-19T23:36:34.402Z"
46
+ end
47
+
48
+ end
49
+
50
+ it "should get a folder hierarchy from a feed" do
51
+ client = mock("client", :folders => stub_folders_feed, :documents_feed => stub_documents_feed)
52
+ folders = GoogleFeatureStore.new(client).folders
53
+ yellow = "http://docs.google.com/feeds/documents/private/full/folder%3Aa58446b0-772d-4ff7-bcb5-eb280b0cf53a"
54
+ folders[yellow].should == "fruit/yellow"
55
+ end
56
+
57
+ it "should attach paths to features" do
58
+ client = mock("client", :folders => stub_folders_feed, :documents_feed => stub_documents_feed)
59
+ features = GoogleFeatureStore.new(client).features
60
+ features.find_all { | f | f.path == "fruit/yellow/banana.feature" }.size.should == 1
61
+ end
62
+
63
+ end
64
+
@@ -0,0 +1,25 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ require 'google_resource'
4
+
5
+ describe GoogleResource do
6
+
7
+ it "should include the authorization header on get" do
8
+ auth = mock("auth", :header => "xxx")
9
+ RestClient.should_receive(:get).with("url", hash_including("Authorization" => "xxx"))
10
+ GoogleResource.new(auth, "url").get
11
+ end
12
+
13
+ it "should include additional headers on get" do
14
+ auth = mock("auth", :header => "xxx")
15
+ RestClient.should_receive(:get).with("url", hash_including("another" => "zzz"))
16
+ GoogleResource.new(auth, "url").get("another" => "zzz")
17
+ end
18
+
19
+ it "should include constructor headers on get" do
20
+ auth = mock("auth", :header => "xxx")
21
+ RestClient.should_receive(:get).with("url", hash_including("another" => "zzz"))
22
+ GoogleResource.new(auth, "url", {"another" => "zzz"}).get
23
+ end
24
+
25
+ end
@@ -0,0 +1,42 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+ require File.dirname(__FILE__) + '/temp_file_system'
3
+
4
+ require 'google_feature_store'
5
+ require 'google_docs_client'
6
+ require 'file_feature_store'
7
+ require 'feature_diff'
8
+
9
+ describe "integration with Google" do
10
+
11
+ before(:all) do
12
+ @client = GoogleDocsClient.new("restapitest@googlemail.com", "testrestapi")
13
+ @remote_store = GoogleFeatureStore.new(@client)
14
+ @features = @remote_store.features
15
+ @fs = TempFileSystem.new(
16
+ 'fruit/yellow/banana.feature' => %{#version:123
17
+ Some other text
18
+ }
19
+ )
20
+ end
21
+
22
+ after(:all) do
23
+ @fs.destroy
24
+ end
25
+
26
+ it "should get features" do
27
+ @features.size.should > 1
28
+ banana = @features.find { |f| f.title == "banana" }
29
+ banana.path.should == 'fruit/yellow/banana.feature'
30
+ end
31
+
32
+ it "should patch differences" do
33
+ local_store = FileFeatureStore.new(@fs.root)
34
+ diff = FeatureDiff.new(local_store, @remote_store)
35
+ banana = diff["fruit/yellow/banana.feature"]
36
+ banana.local.version.should == "123"
37
+ banana.remote.version.should_not == "123"
38
+ banana.patch
39
+ banana.local.version.should == banana.remote.version
40
+ end
41
+
42
+ end
@@ -0,0 +1,5 @@
1
+ lib_path = File.expand_path("#{File.dirname(__FILE__)}/../lib")
2
+ $LOAD_PATH.unshift lib_path unless $LOAD_PATH.include?(lib_path)
3
+
4
+ require 'rubygems'
5
+ require 'spec'
@@ -0,0 +1,36 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <feed xmlns="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearchrss/1.0/" xmlns:gd="http://schemas.google.com/g/2005">
3
+ <id>http://docs.google.com/feeds/documents/private/full</id>
4
+ <updated>2009-02-19T23:42:26.569Z</updated>
5
+ <title type="text">Available Documents - restapitest@googlemail.com</title>
6
+ <link rel="alternate" type="text/html" href="http://docs.google.com"/>
7
+ <link rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml" href="http://docs.google.com/feeds/documents/private/full"/>
8
+ <link rel="http://schemas.google.com/g/2005#post" type="application/atom+xml" href="http://docs.google.com/feeds/documents/private/full"/>
9
+ <link rel="self" type="application/atom+xml" href="http://docs.google.com/feeds/documents/private/full"/>
10
+ <author>
11
+ <name>restapitest</name>
12
+ <email>restapitest@googlemail.com</email>
13
+ </author>
14
+ <openSearch:totalResults>1</openSearch:totalResults>
15
+ <openSearch:startIndex>1</openSearch:startIndex>
16
+ <entry>
17
+ <id>http://docs.google.com/feeds/documents/private/full/document%3Adhmn2mkk_0d4rbv8d8</id>
18
+ <published>2009-02-19T23:04:11.560Z</published>
19
+ <updated>2009-02-19T23:36:34.402Z</updated>
20
+ <category scheme="http://schemas.google.com/g/2005#kind" term="http://schemas.google.com/docs/2007#document" label="document"/>
21
+ <category scheme="http://schemas.google.com/docs/2007/folders/restapitest@googlemail.com" term="yellow" label="yellow"/>
22
+ <title type="text">Banana</title>
23
+ <content type="text/html" src="http://docs.google.com/feeds/download/documents/RawDocContents?action=fetch&amp;justBody=false&amp;revision=_latest&amp;editMode=false&amp;docID=dhmn2mkk_0d4rbv8d8"/>
24
+ <link rel="http://schemas.google.com/docs/2007#parent" type="application/atom+xml" href="http://docs.google.com/feeds/documents/private/full/folder%3Aa58446b0-772d-4ff7-bcb5-eb280b0cf53a" title="yellow"/>
25
+ <link rel="alternate" type="text/html" href="http://docs.google.com/Doc?id=dhmn2mkk_0d4rbv8d8"/>
26
+ <link rel="self" type="application/atom+xml" href="http://docs.google.com/feeds/documents/private/full/document%3Adhmn2mkk_0d4rbv8d8"/>
27
+ <link rel="edit" type="application/atom+xml" href="http://docs.google.com/feeds/documents/private/full/document%3Adhmn2mkk_0d4rbv8d8/fre2o3fm"/>
28
+ <link rel="edit-media" type="text/html" href="http://docs.google.com/feeds/media/private/full/document%3Adhmn2mkk_0d4rbv8d8/fre2o3fm"/>
29
+ <author>
30
+ <name>restapitest</name>
31
+ <email>restapitest@gmail.com</email>
32
+ </author>
33
+ <gd:feedLink rel="http://schemas.google.com/acl/2007#accessControlList" href="http://docs.google.com/feeds/acl/private/full/document%3Adhmn2mkk_0d4rbv8d8"/>
34
+ </entry>
35
+ </feed>
36
+
@@ -0,0 +1,16 @@
1
+ # version:123
2
+
3
+ Feature: Example
4
+
5
+ Narrative 1
6
+ Narrative 2
7
+
8
+ Scenario: First
9
+
10
+ Step 1
11
+ Step 2
12
+
13
+ Scenario: Second
14
+
15
+ Step 3
16
+ Step 4