gdocs_features 0.1.0

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 (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