evva 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.
@@ -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