evva 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1 @@
1
+ <?xml version='1.0' encoding='UTF-8'?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:gsx='http://schemas.google.com/spreadsheets/2006/extended'><id>https://spreadsheets.google.com/feeds/list/1LaJd68os3g_GFlerogC64grNIlXb2iukMznOvdml7A4/osju1vh/public/full</id><updated>2017-08-22T10:31:52.161Z</updated><category scheme='http://schemas.google.com/spreadsheets/2006' term='http://schemas.google.com/spreadsheets/2006#list'/><title type='text'>Enums</title><link rel='alternate' type='application/atom+xml' href='https://docs.google.com/a/hole19golf.com/spreadsheets/d/1LaJd68os3g_GFlerogC64grNIlXb2iukMznOvdml7A4/pubhtml'/><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='https://spreadsheets.google.com/feeds/list/1LaJd68os3g_GFlerogC64grNIlXb2iukMznOvdml7A4/osju1vh/public/full'/><link rel='http://schemas.google.com/g/2005#post' type='application/atom+xml' href='https://spreadsheets.google.com/feeds/list/1LaJd68os3g_GFlerogC64grNIlXb2iukMznOvdml7A4/osju1vh/public/full'/><link rel='self' type='application/atom+xml' href='https://spreadsheets.google.com/feeds/list/1LaJd68os3g_GFlerogC64grNIlXb2iukMznOvdml7A4/osju1vh/public/full'/><author><name>ricardo.trindade</name><email>ricardo.trindade@hole19golf.com</email></author><openSearch:totalResults>2</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><entry><id>https://spreadsheets.google.com/feeds/list/1LaJd68os3g_GFlerogC64grNIlXb2iukMznOvdml7A4/osju1vh/public/full/cokwr</id><updated>2017-08-22T10:31:52.161Z</updated><category scheme='http://schemas.google.com/spreadsheets/2006' term='http://schemas.google.com/spreadsheets/2006#list'/><title type='text'>PageViewSourceScreen</title><content type='text'>values: course_discovery,synced_courses,nearby,deal</content><link rel='self' type='application/atom+xml' href='https://spreadsheets.google.com/feeds/list/1LaJd68os3g_GFlerogC64grNIlXb2iukMznOvdml7A4/osju1vh/public/full/cokwr'/><gsx:enum>PageViewSourceScreen</gsx:enum><gsx:values>course_discovery,synced_courses,nearby,deal</gsx:values></entry><entry><id>https://spreadsheets.google.com/feeds/list/1LaJd68os3g_GFlerogC64grNIlXb2iukMznOvdml7A4/osju1vh/public/full/cpzh4</id><updated>2017-08-22T10:31:52.161Z</updated><category scheme='http://schemas.google.com/spreadsheets/2006' term='http://schemas.google.com/spreadsheets/2006#list'/><title type='text'>PremiumClickBuy</title><content type='text'>values: notes,hi_res_maps,whatever</content><link rel='self' type='application/atom+xml' href='https://spreadsheets.google.com/feeds/list/1LaJd68os3g_GFlerogC64grNIlXb2iukMznOvdml7A4/osju1vh/public/full/cpzh4'/><gsx:enum>PremiumClickBuy</gsx:enum><gsx:values>notes,hi_res_maps,whatever</gsx:values></entry></feed>
@@ -0,0 +1 @@
1
+ <?xml version='1.0' encoding='UTF-8'?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:gs='http://schemas.google.com/spreadsheets/2006'><id>https://spreadsheets.google.com/feeds/worksheets/abcdefgh/public/full</id><updated>2017-08-22T10:31:52.161Z</updated><category scheme='http://schemas.google.com/spreadsheets/2006' term='http://schemas.google.com/spreadsheets/2006#worksheet'/><title type='text'>TestingEvva</title><link rel='alternate' type='application/atom+xml' href='https://docs.google.com/a/hole19golf.com/spreadsheets/d/abc1234567890/pubhtml'/><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='https://spreadsheets.google.com/feeds/worksheets/abc1234567890/public/full'/><link rel='http://schemas.google.com/g/2005#post' type='application/atom+xml' href='https://spreadsheets.google.com/feeds/worksheets/abc1234567890/public/full'/><link rel='self' type='application/atom+xml' href='https://spreadsheets.google.com/feeds/worksheets/abc1234567890/public/full'/><author><name>ricardo.trindade</name><email>ricardo.trindade@hole19golf.com</email></author><openSearch:totalResults>3</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><entry><id>https://spreadsheets.google.com/feeds/worksheets/abc1234567890/public/full/od6</id><updated>2017-08-22T10:31:52.161Z</updated><category scheme='http://schemas.google.com/spreadsheets/2006' term='http://schemas.google.com/spreadsheets/2006#worksheet'/><title type='text'>Events</title><content type='text'>Events</content><link rel='http://schemas.google.com/spreadsheets/2006#listfeed' type='application/atom+xml' href='https://spreadsheets.google.com/feeds/list/abc1234567890/od6/public/full'/><link rel='http://schemas.google.com/spreadsheets/2006#cellsfeed' type='application/atom+xml' href='https://spreadsheets.google.com/feeds/cells/abc1234567890/od6/public/full'/><link rel='http://schemas.google.com/visualization/2008#visualizationApi' type='application/atom+xml' href='https://docs.google.com/a/hole19golf.com/spreadsheets/d/abc1234567890/gviz/tq?gid=0&amp;pub=1'/><link rel='http://schemas.google.com/spreadsheets/2006#exportcsv' type='text/csv' href='https://docs.google.com/a/hole19golf.com/spreadsheets/d/abc1234567890/export?gid=0&amp;format=csv'/><link rel='self' type='application/atom+xml' href='https://spreadsheets.google.com/feeds/worksheets/abc1234567890/public/full/od6'/><gs:colCount>26</gs:colCount><gs:rowCount>1000</gs:rowCount></entry><entry><id>https://spreadsheets.google.com/feeds/worksheets/abc1234567890/public/full/ojyi830</id><updated>2017-08-22T10:31:52.161Z</updated><category scheme='http://schemas.google.com/spreadsheets/2006' term='http://schemas.google.com/spreadsheets/2006#worksheet'/><title type='text'>PeopleProperties</title><content type='text'>PeopleProperties</content><link rel='http://schemas.google.com/spreadsheets/2006#listfeed' type='application/atom+xml' href='https://spreadsheets.google.com/feeds/list/abc1234567890/ojyi830/public/full'/><link rel='http://schemas.google.com/spreadsheets/2006#cellsfeed' type='application/atom+xml' href='https://spreadsheets.google.com/feeds/cells/abc1234567890/ojyi830/public/full'/><link rel='http://schemas.google.com/visualization/2008#visualizationApi' type='application/atom+xml' href='https://docs.google.com/a/hole19golf.com/spreadsheets/d/abc1234567890/gviz/tq?gid=1206814390&amp;pub=1'/><link rel='http://schemas.google.com/spreadsheets/2006#exportcsv' type='text/csv' href='https://docs.google.com/a/hole19golf.com/spreadsheets/d/abc1234567890/export?gid=1206814390&amp;format=csv'/><link rel='self' type='application/atom+xml' href='https://spreadsheets.google.com/feeds/worksheets/abc1234567890/public/full/ojyi830'/><gs:colCount>26</gs:colCount><gs:rowCount>1000</gs:rowCount></entry><entry><id>https://spreadsheets.google.com/feeds/worksheets/abc1234567890/public/full/osju1vh</id><updated>2017-08-22T10:31:52.161Z</updated><category scheme='http://schemas.google.com/spreadsheets/2006' term='http://schemas.google.com/spreadsheets/2006#worksheet'/><title type='text'>Enums</title><content type='text'>Enums</content><link rel='http://schemas.google.com/spreadsheets/2006#listfeed' type='application/atom+xml' href='https://spreadsheets.google.com/feeds/list/abc1234567890/osju1vh/public/full'/><link rel='http://schemas.google.com/spreadsheets/2006#cellsfeed' type='application/atom+xml' href='https://spreadsheets.google.com/feeds/cells/abc1234567890/osju1vh/public/full'/><link rel='http://schemas.google.com/visualization/2008#visualizationApi' type='application/atom+xml' href='https://docs.google.com/a/hole19golf.com/spreadsheets/d/abc1234567890/gviz/tq?gid=1726367271&amp;pub=1'/><link rel='http://schemas.google.com/spreadsheets/2006#exportcsv' type='text/csv' href='https://docs.google.com/a/hole19golf.com/spreadsheets/d/abc1234567890/export?gid=1726367271&amp;format=csv'/><link rel='self' type='application/atom+xml' href='https://spreadsheets.google.com/feeds/worksheets/abc1234567890/public/full/osju1vh'/><gs:colCount>26</gs:colCount><gs:rowCount>1000</gs:rowCount></entry></feed>
@@ -0,0 +1 @@
1
+ <?xml version='1.0' encoding='UTF-8'?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:gsx='http://schemas.google.com/spreadsheets/2006/extended'><id>https://spreadsheets.google.com/feeds/list/1LaJd68os3g_GFlerogC64grNIlXb2iukMznOvdml7A4/ojyi830/public/full</id><updated>2017-09-06T13:27:41.023Z</updated><category scheme='http://schemas.google.com/spreadsheets/2006' term='http://schemas.google.com/spreadsheets/2006#list'/><title type='text'>PeopleProperties</title><link rel='alternate' type='application/atom+xml' href='https://docs.google.com/a/hole19golf.com/spreadsheets/d/1LaJd68os3g_GFlerogC64grNIlXb2iukMznOvdml7A4/pubhtml'/><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='https://spreadsheets.google.com/feeds/list/1LaJd68os3g_GFlerogC64grNIlXb2iukMznOvdml7A4/ojyi830/public/full'/><link rel='http://schemas.google.com/g/2005#post' type='application/atom+xml' href='https://spreadsheets.google.com/feeds/list/1LaJd68os3g_GFlerogC64grNIlXb2iukMznOvdml7A4/ojyi830/public/full'/><link rel='self' type='application/atom+xml' href='https://spreadsheets.google.com/feeds/list/1LaJd68os3g_GFlerogC64grNIlXb2iukMznOvdml7A4/ojyi830/public/full'/><author><name>ricardo.trindade</name><email>ricardo.trindade@hole19golf.com</email></author><openSearch:totalResults>2</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><entry><id>https://spreadsheets.google.com/feeds/list/1LaJd68os3g_GFlerogC64grNIlXb2iukMznOvdml7A4/ojyi830/public/full/cokwr</id><updated>2017-09-06T13:27:41.023Z</updated><category scheme='http://schemas.google.com/spreadsheets/2006' term='http://schemas.google.com/spreadsheets/2006#list'/><title type='text'>roundsWithWear</title><content type='text'>value: rounds_with_wear</content><link rel='self' type='application/atom+xml' href='https://spreadsheets.google.com/feeds/list/1LaJd68os3g_GFlerogC64grNIlXb2iukMznOvdml7A4/ojyi830/public/full/cokwr'/><gsx:properties>roundsWithWear</gsx:properties><gsx:value>rounds_with_wear</gsx:value></entry><entry><id>https://spreadsheets.google.com/feeds/list/1LaJd68os3g_GFlerogC64grNIlXb2iukMznOvdml7A4/ojyi830/public/full/cpzh4</id><updated>2017-09-06T13:27:41.023Z</updated><category scheme='http://schemas.google.com/spreadsheets/2006' term='http://schemas.google.com/spreadsheets/2006#list'/><title type='text'>totalFriends</title><content type='text'>value: total_friends</content><link rel='self' type='application/atom+xml' href='https://spreadsheets.google.com/feeds/list/1LaJd68os3g_GFlerogC64grNIlXb2iukMznOvdml7A4/ojyi830/public/full/cpzh4'/><gsx:properties>totalFriends</gsx:properties><gsx:value>total_friends</gsx:value></entry></feed>
@@ -0,0 +1 @@
1
+ <?xml version='1.0' encoding='UTF-8'?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:gsx='http://schemas.google.com/spreadsheets/2006/extended'><id>https://spreadsheets.google.com/feeds/list/abc1234567890/od6/public/full</id><updated>2017-08-22T10:31:52.161Z</updated><category scheme='http://schemas.google.com/spreadsheets/2006' term='http://schemas.google.com/spreadsheets/2006#list'/><title type='text'>Events</title><link rel='alternate' type='application/atom+xml' href='https://docs.google.com/a/hole19golf.com/spreadsheets/d/abc1234567890/pubhtml'/><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='https://spreadsheets.google.com/feeds/list/abc1234567890/od6/public/full'/><link rel='http://schemas.google.com/g/2005#post' type='application/atom+xml' href='https://spreadsheets.google.com/feeds/list/abc1234567890/od6/public/full'/><link rel='self' type='application/atom+xml' href='https://spreadsheets.google.com/feeds/list/abc1234567890/od6/public/full'/><author><name>ricardo.trindade</name><email>ricardo.trindade@hole19golf.com</email></author><openSearch:totalResults>3</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><entry><id>https://spreadsheets.google.com/feeds/list/abc1234567890/od6/public/full/cokwr</id><updated>2017-08-22T10:31:52.161Z</updated><category scheme='http://schemas.google.com/spreadsheets/2006' term='http://schemas.google.com/spreadsheets/2006#list'/><title type='text'>trackCpPageView</title><content type='text'>eventname: cp_page_view, props: course_id:Long,course_name:String</content><link rel='self' type='application/atom+xml' href='https://spreadsheets.google.com/feeds/list/abc1234567890/od6/public/full/cokwr'/><gsx:functionname>trackCpPageView</gsx:functionname><gsx:eventname>cp_page_view</gsx:eventname><gsx:props>course_id:Long,course_name:String</gsx:props></entry><entry><id>https://spreadsheets.google.com/feeds/list/abc1234567890/od6/public/full/cpzh4</id><updated>2017-08-22T10:31:52.161Z</updated><category scheme='http://schemas.google.com/spreadsheets/2006' term='http://schemas.google.com/spreadsheets/2006#list'/><title type='text'>trackNavFeedTap</title><content type='text'>eventname: nav_feed_tap</content><link rel='self' type='application/atom+xml' href='https://spreadsheets.google.com/feeds/list/abc1234567890/od6/public/full/cpzh4'/><gsx:functionname>trackNavFeedTap</gsx:functionname><gsx:eventname>nav_feed_tap</gsx:eventname><gsx:props></gsx:props></entry><entry><id>https://spreadsheets.google.com/feeds/list/abc1234567890/od6/public/full/cre1l</id><updated>2017-08-22T10:31:52.161Z</updated><category scheme='http://schemas.google.com/spreadsheets/2006' term='http://schemas.google.com/spreadsheets/2006#list'/><title type='text'>trackCpViewScorecard</title><content type='text'>eventname: cp_view_scorecard, props: course_id:Long,course_name:String</content><link rel='self' type='application/atom+xml' href='https://spreadsheets.google.com/feeds/list/abc1234567890/od6/public/full/cre1l'/><gsx:functionname>trackCpViewScorecard</gsx:functionname><gsx:eventname>cp_view_scorecard</gsx:eventname><gsx:props>course_id:Long,course_name:String</gsx:props></entry></feed>
@@ -0,0 +1,10 @@
1
+ type: Android
2
+
3
+ data_source:
4
+ type: google_sheet
5
+ sheet_id: 1LaJd68os3g_GFlerogC64grNIlXb2iukMznOvdml7A4
6
+
7
+ out_path: analytics
8
+ event_file_name: MixpanelAnalytics
9
+ event_enum_file_name: MixpanelEvent
10
+ people_file_name: MixpanelProperties
@@ -0,0 +1,135 @@
1
+ describe Evva::AndroidGenerator do
2
+ let(:generator) { described_class.new }
3
+
4
+ def trim_spaces(str)
5
+ str.gsub(/^[ \t]+/, '')
6
+ .gsub(/[ \t]+$/, '')
7
+ end
8
+
9
+ describe '#kotlin_function' do
10
+ subject { trim_spaces(generator.kotlin_function(event)) }
11
+
12
+ context 'when the event has no properties' do
13
+ let(:event) { Evva::MixpanelEvent.new('nav_feed_tap') }
14
+ let(:expected) { <<-Kotlin
15
+ open fun trackNavFeedTap() {
16
+ mixpanelMask.trackEvent(MixpanelEvent.NAV_FEED_TAP)
17
+ }
18
+ Kotlin
19
+ }
20
+ it { should eq trim_spaces(expected) }
21
+ end
22
+
23
+ context 'event has properties' do
24
+ let(:event) { Evva::MixpanelEvent.new('cp_page_view', { course_id: 'Long', course_name: 'String' }) }
25
+ let(:expected) { <<-Kotlin
26
+ open fun trackCpPageView(course_id: Long, course_name: String) {
27
+ val properties = JSONObject().apply {
28
+ put("course_id", course_id)
29
+ put("course_name", course_name)
30
+ }
31
+ mixpanelMask.trackEvent(MixpanelEvent.CP_PAGE_VIEW, properties)
32
+ }
33
+ Kotlin
34
+ }
35
+ it { should eq trim_spaces(expected) }
36
+ end
37
+
38
+ context 'event has special properties' do
39
+ let(:event) { Evva::MixpanelEvent.new('cp_page_view', { course_id: 'Long', course_name: 'String', from_screen: 'CourseProfileSource' }) }
40
+ let(:expected) { <<-Kotlin
41
+ open fun trackCpPageView(course_id: Long, course_name: String, from_screen: CourseProfileSource) {
42
+ val properties = JSONObject().apply {
43
+ put("course_id", course_id)
44
+ put("course_name", course_name)
45
+ put("from_screen", from_screen.key)
46
+ }
47
+ mixpanelMask.trackEvent(MixpanelEvent.CP_PAGE_VIEW, properties)
48
+ }
49
+ Kotlin
50
+ }
51
+ it { should eq trim_spaces(expected) }
52
+ end
53
+
54
+ context 'event has optional properties' do
55
+ let(:event) { Evva::MixpanelEvent.new('cp_page_view', { course_id: 'Long', course_name: 'String', from_screen: 'CourseProfileSource?' }) }
56
+ let(:expected) { <<-Kotlin
57
+ open fun trackCpPageView(course_id: Long, course_name: String, from_screen: CourseProfileSource?) {
58
+ val properties = JSONObject().apply {
59
+ put("course_id", course_id)
60
+ put("course_name", course_name)
61
+ from_screen?.let { put("from_screen", it.key) }
62
+ }
63
+ mixpanelMask.trackEvent(MixpanelEvent.CP_PAGE_VIEW, properties)
64
+ }
65
+ Kotlin
66
+ }
67
+ it { should eq trim_spaces(expected) }
68
+ end
69
+
70
+ context 'event has optional but not special properties' do
71
+ let(:event) { Evva::MixpanelEvent.new('cp_page_view', { course_id: 'Long?', course_name: 'String' }) }
72
+ let(:expected) { <<-Kotlin
73
+ open fun trackCpPageView(course_id: Long?, course_name: String) {
74
+ val properties = JSONObject().apply {
75
+ course_id?.let { put("course_id", it) }
76
+ put("course_name", course_name)
77
+ }
78
+ mixpanelMask.trackEvent(MixpanelEvent.CP_PAGE_VIEW, properties)
79
+ }
80
+ Kotlin
81
+ }
82
+ it { should eq trim_spaces(expected) }
83
+ end
84
+ end
85
+
86
+ describe '#special_property_enum' do
87
+ subject { trim_spaces(generator.special_property_enum(enum)) }
88
+ let(:enum) { Evva::MixpanelEnum.new('CourseProfileSource', ['course_discovery','synced_courses']) }
89
+ let(:expected) { <<-Kotlin
90
+ package com.hole19golf.hole19.analytics
91
+
92
+ enum class CourseProfileSource(val key: String) {
93
+ COURSE_DISCOVERY("course_discovery"),
94
+ SYNCED_COURSES("synced_courses")
95
+ }
96
+ Kotlin
97
+ }
98
+ it { should eq trim_spaces(expected) }
99
+ end
100
+
101
+ describe '#event_enum' do
102
+ subject { trim_spaces(generator.event_enum(event_bundle)) }
103
+ let(:event_bundle) { [
104
+ Evva::MixpanelEvent.new('nav_feed_tap', {}),
105
+ Evva::MixpanelEvent.new('nav_performance_tap', {})
106
+ ] }
107
+ let(:expected) { <<-Kotlin
108
+ package com.hole19golf.hole19.analytics
109
+ import com.hole19golf.hole19.analytics.Event
110
+
111
+ enum class MixpanelEvent(override val key: String) : Event {
112
+ NAV_FEED_TAP("nav_feed_tap"),
113
+ NAV_PERFORMANCE_TAP("nav_performance_tap")
114
+ }
115
+ Kotlin
116
+ }
117
+ it { should eq trim_spaces(expected) }
118
+ end
119
+
120
+ describe '#people_properties' do
121
+ subject { trim_spaces(generator.people_properties(people_bundle)) }
122
+ let(:people_bundle) { ['rounds_with_wear', 'friends_from_facebook'] }
123
+ let(:expected) { <<-Kotlin
124
+ package com.hole19golf.hole19.analytics
125
+ import com.hole19golf.hole19.analytics.Event
126
+
127
+ enum class MixpanelProperties(val key: String) {
128
+ ROUNDS_WITH_WEAR("rounds_with_wear"),
129
+ FRIENDS_FROM_FACEBOOK("friends_from_facebook");
130
+ }
131
+ Kotlin
132
+ }
133
+ it { should eq trim_spaces(expected) }
134
+ end
135
+ end
@@ -0,0 +1,40 @@
1
+ describe Evva::Config do
2
+ subject(:config) { Evva::Config.new(hash: hash) }
3
+
4
+ let(:hash) do
5
+ {
6
+ type: 'EvvaOS',
7
+ data_source: {
8
+ type: 'google_sheet',
9
+ sheet_id: 'abc1234567890'
10
+ },
11
+ out_path: 'clear/path/to/event',
12
+ event_file_name: 'event/file/name',
13
+ people_file_name: 'people/file/name',
14
+ event_enum_file_name: 'event/enum/file'
15
+ }
16
+ end
17
+
18
+ context 'when hash is missing params' do
19
+ before { hash.delete(:type) }
20
+ it { expect { config }.to raise_error /missing keys/i }
21
+ end
22
+
23
+ its(:to_h) { should eq(hash) }
24
+ its(:type) { should eq('EvvaOS') }
25
+ its(:out_path) { should eq('clear/path/to/event') }
26
+ its(:event_file_name) { should eq('event/file/name') }
27
+ its(:people_file_name) { should eq('people/file/name') }
28
+ its(:event_enum_file_name) { should eq 'event/enum/file' }
29
+
30
+ describe '#data_source' do
31
+ subject(:data_source) { config.data_source }
32
+
33
+ it { should eq(type: 'google_sheet', sheet_id: 'abc1234567890') }
34
+
35
+ context 'when given an unknown type data source' do
36
+ before { hash[:data_source] = { type: 'i_dunno' } }
37
+ it { expect { config }.to raise_error /unknown data source type 'i_dunno'/i }
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,28 @@
1
+ describe Evva::DataSource do
2
+ subject(:dict) { Evva::DataSource.new(keys) }
3
+
4
+ describe '.initialize' do
5
+ let(:keys) { { 'event' => { 'kNo1' => 'text' } } }
6
+ it { expect { subject }.not_to raise_error }
7
+
8
+ context 'when created with invalid type parameters' do
9
+ let(:keys) { 'cenas' }
10
+ it { expect { subject }.to raise_error /expected Hash/ }
11
+ end
12
+
13
+ context 'when created with an invalid json schema' do
14
+ let(:keys) { { 'event' => 'text' } }
15
+ it { expect { subject }.to raise_error /event.+expected Hash/ }
16
+ end
17
+
18
+ context 'when created with an invalid json schema' do
19
+ let(:keys) { { 'a-event' => { 'kNo1' => { 'wtvr' => 'text' } } } }
20
+ it { expect { subject }.to raise_error /a-event.+kNo1.+expected String/ }
21
+ end
22
+
23
+ context 'when given empty translations' do
24
+ let(:keys) { { 'event' => { 'kNo1' => nil } } }
25
+ it { expect { subject }.not_to raise_error }
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,107 @@
1
+ describe Evva::GoogleSheet do
2
+ let(:sheet) { Evva::GoogleSheet.new(sheet_id) }
3
+ let(:sheet_id) { 'abc1234567890' }
4
+ let(:url_info) { "https://spreadsheets.google.com/feeds/worksheets/#{sheet_id}/public/full" }
5
+ let(:url_sheet) { "https://spreadsheets.google.com/feeds/list/#{sheet_id}/od6/public/full" }
6
+ let(:enum_sheet) { "https://spreadsheets.google.com/feeds/list/#{sheet_id}/osju1vh/public/full" }
7
+ let(:people_sheet) { "https://spreadsheets.google.com/feeds/list/#{sheet_id}/ojyi830/public/full" }
8
+ let(:file_info) { File.read('spec/fixtures/sample_public_info.html') }
9
+ let(:file_sheet) { File.read('spec/fixtures/sample_public_sheet.html') }
10
+ let(:enum_file) { File.read('spec/fixtures/sample_public_enums.html') }
11
+ let(:people_file) { File.read('spec/fixtures/sample_public_people_properties.html') }
12
+
13
+ describe '#events' do
14
+ subject(:events) { sheet.events }
15
+ before do
16
+ stub_request(:get, url_info).to_return(status: 200, body: file_info, headers: {})
17
+ stub_request(:get, url_sheet).to_return(status: 200, body: file_sheet, headers: {})
18
+ end
19
+
20
+ context 'when given a valid sheet' do
21
+ it do
22
+ expect { events }.not_to raise_error
23
+ end
24
+
25
+ it 'returns an array with the corresponding events' do
26
+ expected = [Evva::MixpanelEvent.new('cp_page_view', { course_id: 'Long', course_name: 'String' }),
27
+ Evva::MixpanelEvent.new('nav_feed_tap', {}),
28
+ Evva::MixpanelEvent.new('cp_view_scorecard', { course_id: 'Long', course_name: 'String' })]
29
+ expect(events).to eq(expected)
30
+ end
31
+ end
32
+
33
+ context 'when given an inexistent sheet' do
34
+ before { stub_request(:get, url_info).to_return(status: 400, body: 'Not Found', headers: {}) }
35
+
36
+ it do
37
+ expect { events }.to raise_error /Cannot access sheet/
38
+ end
39
+ end
40
+
41
+ context 'when given a private sheet' do
42
+ before { stub_request(:get, url_info).to_return(status: 302, body: '<HTML></HTML>', headers: {}) }
43
+
44
+ it do
45
+ expect { events }.to raise_error /Cannot access sheet/
46
+ end
47
+ end
48
+
49
+ context 'when url content is not XML' do
50
+ before { stub_request(:get, url_info).to_return(status: 200, body: 'This is not XML; { this: "is json" }', headers: {}) }
51
+
52
+ it do
53
+ expect { events }.to raise_error /Cannot parse. Expected XML/
54
+ end
55
+ end
56
+ end
57
+
58
+ describe '#enum_classes' do
59
+ subject(:enum_classes) { sheet.enum_classes }
60
+ let(:expected_enum) do
61
+ [
62
+ Evva::MixpanelEnum.new('PageViewSourceScreen', ['course_discovery','synced_courses','nearby','deal']),
63
+ Evva::MixpanelEnum.new('PremiumClickBuy', ['notes','hi_res_maps','whatever'])
64
+ ]
65
+ end
66
+
67
+ context 'when given a valid sheet' do
68
+ before do
69
+ stub_request(:get, url_info).to_return(status: 200, body: file_info, headers: {})
70
+ stub_request(:get, enum_sheet).to_return(status: 200, body: enum_file, headers: {})
71
+ end
72
+
73
+ it do
74
+ expect { enum_classes }.not_to raise_error
75
+ end
76
+
77
+ it 'returns an array with the corresponding events' do
78
+ expect(enum_classes).to eq expected_enum
79
+ end
80
+ end
81
+ end
82
+
83
+ describe '#people_properties' do
84
+ subject(:people_properties) { sheet.people_properties }
85
+ let(:expected_people_properties) do
86
+ [
87
+ 'rounds_with_wear',
88
+ 'total_friends'
89
+ ]
90
+ end
91
+
92
+ context 'when given a valid sheet' do
93
+ before do
94
+ stub_request(:get, url_info).to_return(status: 200, body: file_info, headers: {})
95
+ stub_request(:get, people_sheet).to_return(status: 200, body: people_file, headers: {})
96
+ end
97
+
98
+ it do
99
+ expect { people_properties }.not_to raise_error
100
+ end
101
+
102
+ it 'returns an array with the corresponding events' do
103
+ expect(people_properties).to eq expected_people_properties
104
+ end
105
+ end
106
+ end
107
+ end
@@ -0,0 +1,36 @@
1
+ describe Evva::Logger do
2
+ let(:summary) { Evva::Logger.summary }
3
+ let(:info) { summary[:info] }
4
+ let(:warn) { summary[:warn] }
5
+ let(:error) { summary[:error] }
6
+
7
+ context 'when logging to info' do
8
+ before { Evva::Logger.info 'msg' }
9
+
10
+ it 'returns the expected totals' do
11
+ expect(info).to eq 1
12
+ expect(warn).to eq 0
13
+ expect(error).to eq 0
14
+ end
15
+ end
16
+
17
+ context 'when logging to warn' do
18
+ before { Evva::Logger.warn 'msg' }
19
+
20
+ it 'returns the expected totals' do
21
+ expect(info).to eq 0
22
+ expect(warn).to eq 1
23
+ expect(error).to eq 0
24
+ end
25
+ end
26
+
27
+ context 'when logging to error' do
28
+ before { Evva::Logger.error 'msg' }
29
+
30
+ it 'returns the expected totals' do
31
+ expect(info).to eq 0
32
+ expect(warn).to eq 0
33
+ expect(error).to eq 1
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,99 @@
1
+ describe Object do
2
+ describe '#deep_symbolize' do
3
+ subject { obj.deep_symbolize }
4
+
5
+ context 'when object is an Hash' do
6
+ let(:obj) { { 'key1' => 'value1', key2: 'value2' } }
7
+ it { should eq(key1: 'value1', key2: 'value2') }
8
+
9
+ context 'with inner Hashes' do
10
+ before { obj['key2'] = { 'key3' => { 'key4' => 'value4' } } }
11
+ it { should eq(key1: 'value1', key2: { key3: { key4: 'value4' } }) }
12
+ end
13
+ end
14
+
15
+ context 'when object is an Array' do
16
+ let(:obj) { ['value1'] }
17
+ it { should eq obj }
18
+
19
+ context 'with inner Hashes' do
20
+ let(:obj) { [{ 'key1' => 'value1' }, { 'key2' => 'value2' }] }
21
+ it { should eq([{ key1: 'value1' }, { key2: 'value2' }]) }
22
+ end
23
+ end
24
+
25
+ context 'when object is something else' do
26
+ let(:obj) { 'value1' }
27
+ it { should eq obj }
28
+ end
29
+ end
30
+
31
+ describe '#validate_structure!' do
32
+ subject { obj.validate_structure!(structure) }
33
+
34
+ context 'when object type differs of the structure type' do
35
+ let(:obj) { 'a string' }
36
+ let(:structure) { { type: Integer } }
37
+ it { expect { subject }.to raise_error /expected Integer, got String/i }
38
+ end
39
+
40
+ context 'when object is a Nil' do
41
+ let(:obj) { nil }
42
+ let(:structure) { { type: Integer } }
43
+ it { expect { subject }.to raise_error /expected Integer, got NilClass/i }
44
+
45
+ context 'but is also optional' do
46
+ before { structure[:optional] = true }
47
+ it { expect { subject }.not_to raise_error }
48
+ end
49
+ end
50
+
51
+ context 'when object is an Array' do
52
+ let(:obj) { %w[elem1 elem2] }
53
+ let(:structure) { { type: Array } }
54
+ it { expect { subject }.not_to raise_error }
55
+
56
+ context 'given an element structure' do
57
+ before { structure[:elements] = { type: String } }
58
+ it { expect { subject }.not_to raise_error }
59
+
60
+ context 'which is not respected' do
61
+ before { structure[:elements] = { type: Integer } }
62
+ it { expect { subject }.to raise_error /expected Integer, got String/i }
63
+ end
64
+ end
65
+ end
66
+
67
+ context 'when object is an Hash' do
68
+ let(:obj) { { key1: 'value1', key2: 'value2', key3: 'value3' } }
69
+ let(:structure) { { type: Hash } }
70
+ it { expect { subject }.not_to raise_error }
71
+
72
+ context 'when given an element structure' do
73
+ let(:structure) { { type: Hash, elements: { key1: { type: String }, key2: { type: String }, key3: { type: String } } } }
74
+ it { expect { subject }.not_to raise_error }
75
+
76
+ context 'which is not respected' do
77
+ before { obj[:key2] = {} }
78
+ it { expect { subject }.to raise_error /expected String, got Hash/i }
79
+ end
80
+
81
+ context 'when missing keys' do
82
+ before do
83
+ obj.delete(:key1)
84
+ obj.delete(:key3)
85
+ end
86
+ it { expect { subject }.to raise_error /missing keys: key1, key3/i }
87
+
88
+ context 'which are optional' do
89
+ before do
90
+ structure[:elements][:key1][:optional] = true
91
+ structure[:elements][:key3][:optional] = true
92
+ end
93
+ it { expect { subject }.not_to raise_error }
94
+ end
95
+ end
96
+ end
97
+ end
98
+ end
99
+ end