marty 0.5.15 → 0.5.16

Sign up to get free protection for your applications and to get access to all the features.
Files changed (212) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +27 -0
  3. data/.rspec +3 -0
  4. data/.travis.yml +23 -0
  5. data/Gemfile +23 -0
  6. data/INDEPENDENCE_ISSUES.md +23 -0
  7. data/app/assets/images/marty/.gitkeep +0 -0
  8. data/app/components/marty/report_form.rb +9 -4
  9. data/gemini_deprecations.md +6 -0
  10. data/lib/marty/data_change.rb +99 -0
  11. data/lib/marty/data_conversion.rb +11 -3
  12. data/lib/marty/data_exporter.rb +9 -0
  13. data/lib/marty/version.rb +1 -1
  14. data/marty.gemspec +35 -0
  15. data/script/rails +8 -0
  16. data/spec/controllers/application_controller_spec.rb +52 -0
  17. data/spec/controllers/job_controller_spec.rb +226 -0
  18. data/spec/controllers/rpc_controller_spec.rb +379 -0
  19. data/spec/controllers/rpc_import_spec.rb +45 -0
  20. data/spec/dummy/README.rdoc +261 -0
  21. data/spec/dummy/Rakefile +7 -0
  22. data/spec/dummy/app/assets/javascripts/application.js +15 -0
  23. data/spec/dummy/app/assets/stylesheets/application.css +13 -0
  24. data/spec/dummy/app/controllers/application_controller.rb +3 -0
  25. data/spec/dummy/app/controllers/components_controller.rb +7 -0
  26. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  27. data/spec/dummy/app/mailers/.gitkeep +0 -0
  28. data/spec/dummy/app/models/.gitkeep +0 -0
  29. data/spec/dummy/app/models/gemini/amortization_type.rb +5 -0
  30. data/spec/dummy/app/models/gemini/bud_category.rb +7 -0
  31. data/spec/dummy/app/models/gemini/entity.rb +2 -0
  32. data/spec/dummy/app/models/gemini/extras/data_import.rb +5 -0
  33. data/spec/dummy/app/models/gemini/extras/settlement_import.rb +28 -0
  34. data/spec/dummy/app/models/gemini/fannie_bup.rb +29 -0
  35. data/spec/dummy/app/models/gemini/grouping.rb +8 -0
  36. data/spec/dummy/app/models/gemini/grouping_head_version.rb +14 -0
  37. data/spec/dummy/app/models/gemini/head.rb +7 -0
  38. data/spec/dummy/app/models/gemini/head_version.rb +14 -0
  39. data/spec/dummy/app/models/gemini/helper.rb +44 -0
  40. data/spec/dummy/app/models/gemini/loan_program.rb +11 -0
  41. data/spec/dummy/app/models/gemini/mortgage_type.rb +5 -0
  42. data/spec/dummy/app/models/gemini/simple.rb +6 -0
  43. data/spec/dummy/app/models/gemini/streamline_type.rb +16 -0
  44. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  45. data/spec/dummy/config.ru +4 -0
  46. data/spec/dummy/config/application.rb +82 -0
  47. data/spec/dummy/config/boot.rb +10 -0
  48. data/spec/dummy/config/database.yml.example +10 -0
  49. data/spec/dummy/config/environment.rb +5 -0
  50. data/spec/dummy/config/environments/development.rb +35 -0
  51. data/spec/dummy/config/environments/production.rb +69 -0
  52. data/spec/dummy/config/environments/test.rb +39 -0
  53. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  54. data/spec/dummy/config/initializers/delayed_job.rb +5 -0
  55. data/spec/dummy/config/initializers/inflections.rb +15 -0
  56. data/spec/dummy/config/initializers/mime_types.rb +5 -0
  57. data/spec/dummy/config/initializers/secret_token.rb +7 -0
  58. data/spec/dummy/config/initializers/session_store.rb +8 -0
  59. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  60. data/spec/dummy/config/locales/en.yml +5 -0
  61. data/spec/dummy/config/routes.rb +12 -0
  62. data/spec/dummy/db/migrate/20140801000000_create_groupings.rb +11 -0
  63. data/spec/dummy/db/migrate/20150406171536_create_categories.rb +27 -0
  64. data/spec/dummy/db/migrate/20150408200916_create_loan_programs.rb +26 -0
  65. data/spec/dummy/db/migrate/20150408201429_create_types.rb +21 -0
  66. data/spec/dummy/db/migrate/20150420000001_create_heads.rb +14 -0
  67. data/spec/dummy/db/migrate/20150420000002_create_head_versions.rb +15 -0
  68. data/spec/dummy/db/migrate/20150420000003_create_grouping_head_versions.rb +12 -0
  69. data/spec/dummy/db/migrate/20151023000001_create_simple.rb +12 -0
  70. data/spec/dummy/db/seeds.rb +8 -0
  71. data/spec/dummy/delorean/blame_report.dl +171 -0
  72. data/spec/dummy/delorean/data_report.dl +105 -0
  73. data/spec/dummy/delorean/fields.dl +52 -0
  74. data/spec/dummy/delorean/styles.dl +134 -0
  75. data/spec/dummy/lib/assets/.gitkeep +0 -0
  76. data/spec/dummy/lib/class_list.rb +3 -0
  77. data/spec/dummy/log/.gitkeep +0 -0
  78. data/spec/dummy/public/404.html +26 -0
  79. data/spec/dummy/public/422.html +26 -0
  80. data/spec/dummy/public/500.html +25 -0
  81. data/spec/dummy/public/favicon.ico +0 -0
  82. data/spec/dummy/public/icons/READ.txt +3 -0
  83. data/spec/dummy/public/icons/application_cascade.png +0 -0
  84. data/spec/dummy/public/icons/application_delete.png +0 -0
  85. data/spec/dummy/public/icons/application_put.png +0 -0
  86. data/spec/dummy/public/icons/application_view_detail.png +0 -0
  87. data/spec/dummy/public/icons/arrow_in.png +0 -0
  88. data/spec/dummy/public/icons/arrow_refresh.png +0 -0
  89. data/spec/dummy/public/icons/database_save.png +0 -0
  90. data/spec/dummy/public/icons/door_in.png +0 -0
  91. data/spec/dummy/public/icons/door_out.png +0 -0
  92. data/spec/dummy/public/icons/group.png +0 -0
  93. data/spec/dummy/public/icons/page_lightning.png +0 -0
  94. data/spec/dummy/public/icons/printer.png +0 -0
  95. data/spec/dummy/public/icons/report_disk.png +0 -0
  96. data/spec/dummy/public/icons/report_go.png +0 -0
  97. data/spec/dummy/public/icons/report_magnify.png +0 -0
  98. data/spec/dummy/public/icons/script.png +0 -0
  99. data/spec/dummy/public/icons/script_add.png +0 -0
  100. data/spec/dummy/public/icons/script_go.png +0 -0
  101. data/spec/dummy/public/icons/script_key.png +0 -0
  102. data/spec/dummy/public/icons/table_go.png +0 -0
  103. data/spec/dummy/public/icons/time.png +0 -0
  104. data/spec/dummy/public/icons/time_add.png +0 -0
  105. data/spec/dummy/public/icons/time_go.png +0 -0
  106. data/spec/dummy/public/icons/timeline_marker.png +0 -0
  107. data/spec/dummy/public/icons/user_add.png +0 -0
  108. data/spec/dummy/public/icons/user_delete.png +0 -0
  109. data/spec/dummy/public/icons/user_edit.png +0 -0
  110. data/spec/dummy/public/icons/wrench.png +0 -0
  111. data/spec/dummy/script/delayed_job +6 -0
  112. data/spec/dummy/script/rails +6 -0
  113. data/spec/features/javascripts/job_dashboard_live_search.js.coffee +8 -0
  114. data/spec/features/javascripts/login.js.coffee +8 -0
  115. data/spec/features/jobs_dashboard_netzke_spec.rb +24 -0
  116. data/spec/features/jobs_dashboard_spec.rb +49 -0
  117. data/spec/fixtures/scripts/load_tests/script1.dl +2 -0
  118. data/spec/fixtures/scripts/load_tests/script2.dl +2 -0
  119. data/spec/job_helper.rb +102 -0
  120. data/spec/lib/data_exporter_spec.rb +71 -0
  121. data/spec/lib/data_importer_spec.rb +461 -0
  122. data/spec/lib/xl_spec.rb +198 -0
  123. data/spec/lib/xl_styles_spec.rb +115 -0
  124. data/spec/models/api_auth_spec.rb +187 -0
  125. data/spec/models/posting_spec.rb +107 -0
  126. data/spec/models/promise_spec.rb +65 -0
  127. data/spec/models/script_spec.rb +187 -0
  128. data/spec/models/user_spec.rb +68 -0
  129. data/spec/requests/routes_spec.rb +12 -0
  130. data/spec/spec_helper.rb +61 -0
  131. data/spec/support/clean_db_helpers.rb +18 -0
  132. data/spec/support/delayed_job_helpers.rb +12 -0
  133. data/spec/support/user_helpers.rb +12 -0
  134. metadata +139 -89
  135. data/app/components/marty/auth_app.rb~ +0 -51
  136. data/app/components/marty/auth_app/javascripts/auth_app.js~ +0 -91
  137. data/app/components/marty/cm_form_panel.rb~ +0 -5
  138. data/app/components/marty/cm_grid_panel.rb~ +0 -35
  139. data/app/components/marty/data_import_view.rb~ +0 -142
  140. data/app/components/marty/extras/layout.rb~ +0 -46
  141. data/app/components/marty/live_search_grid_panel.rb~ +0 -49
  142. data/app/components/marty/main_auth_app.rb~ +0 -238
  143. data/app/components/marty/mcfly_grid_panel.rb~ +0 -80
  144. data/app/components/marty/new_posting_form.rb~ +0 -46
  145. data/app/components/marty/new_posting_window.rb~ +0 -21
  146. data/app/components/marty/pivot_grid.rb +0 -52
  147. data/app/components/marty/pivot_grid/endpoints.rb +0 -45
  148. data/app/components/marty/pivot_grid/javascripts/extensions.js +0 -150
  149. data/app/components/marty/pivot_grid/javascripts/pivot_grid.js +0 -86
  150. data/app/components/marty/pivot_grid/services.rb +0 -44
  151. data/app/components/marty/posting_grid.rb~ +0 -140
  152. data/app/components/marty/promise_view.rb~ +0 -157
  153. data/app/components/marty/promise_view/stylesheets/promise_view.css~ +0 -15
  154. data/app/components/marty/report_form.rb~ +0 -217
  155. data/app/components/marty/report_select.rb~ +0 -133
  156. data/app/components/marty/reporting.rb~ +0 -39
  157. data/app/components/marty/script_detail.rb~ +0 -430
  158. data/app/components/marty/script_form.rb~ +0 -233
  159. data/app/components/marty/script_form/javascripts/Ext.ux.form.field.CodeMirror.js~ +0 -909
  160. data/app/components/marty/script_grid.rb~ +0 -99
  161. data/app/components/marty/script_tester.rb~ +0 -213
  162. data/app/components/marty/scripting.rb~ +0 -124
  163. data/app/components/marty/select_report.rb~ +0 -143
  164. data/app/components/marty/simple_app.rb~ +0 -101
  165. data/app/components/marty/tag_grid.rb~ +0 -89
  166. data/app/components/marty/tree_panel.rb~ +0 -256
  167. data/app/components/marty/tree_panel/javascripts/tree_panel.js~ +0 -317
  168. data/app/components/marty/user_pivot.rb +0 -128
  169. data/app/components/marty/user_view.rb~ +0 -188
  170. data/app/controllers/marty/application_controller.rb~ +0 -133
  171. data/app/controllers/marty/components_controller.rb~ +0 -37
  172. data/app/controllers/marty/job_controller.rb~ +0 -28
  173. data/app/controllers/marty/rpc_controller.rb~ +0 -61
  174. data/app/helpers/marty/script_set.rb~ +0 -59
  175. data/app/models/marty/api_auth.rb~ +0 -48
  176. data/app/models/marty/data_change.rb~ +0 -141
  177. data/app/models/marty/enum.rb~ +0 -16
  178. data/app/models/marty/import_type.rb~ +0 -48
  179. data/app/models/marty/poop.rb~ +0 -169
  180. data/app/models/marty/posting.rb~ +0 -86
  181. data/app/models/marty/posting_type.rb~ +0 -21
  182. data/app/models/marty/promise.rb~ +0 -196
  183. data/app/models/marty/role.rb~ +0 -10
  184. data/app/models/marty/script.rb~ +0 -62
  185. data/app/models/marty/tag.rb~ +0 -91
  186. data/app/models/marty/user.rb~ +0 -148
  187. data/app/models/marty/user_role.rb~ +0 -13
  188. data/app/views/layouts/marty/application.html.erb~ +0 -11
  189. data/config/routes.rb~ +0 -10
  190. data/db/migrate/019_create_marty_postings.rb~ +0 -19
  191. data/db/migrate/095_create_marty_tags.rb~ +0 -19
  192. data/lib/marty.rb~ +0 -13
  193. data/lib/marty/content_handler.rb~ +0 -93
  194. data/lib/marty/data_exporter.rb~ +0 -137
  195. data/lib/marty/data_importer.rb~ +0 -114
  196. data/lib/marty/data_row_processor.rb~ +0 -206
  197. data/lib/marty/drop_folder_hook.rb~ +0 -17
  198. data/lib/marty/folder_hook.rb~ +0 -9
  199. data/lib/marty/lazy_column_loader.rb~ +0 -47
  200. data/lib/marty/mcfly_query.rb~ +0 -188
  201. data/lib/marty/migrations.rb~ +0 -65
  202. data/lib/marty/monkey.rb~ +0 -160
  203. data/lib/marty/permissions.rb~ +0 -69
  204. data/lib/marty/promise.rb~ +0 -41
  205. data/lib/marty/promise_job.rb~ +0 -121
  206. data/lib/marty/promise_proxy.rb~ +0 -69
  207. data/lib/marty/util.rb~ +0 -80
  208. data/lib/marty/version.rb~ +0 -3
  209. data/lib/marty/xl.rb~ +0 -526
  210. data/lib/pyxll/README.txt~ +0 -16
  211. data/lib/pyxll/gemini.py~ +0 -110
  212. data/lib/pyxll/pyxll.cfg~ +0 -12
@@ -0,0 +1,198 @@
1
+ require 'spec_helper'
2
+ require 'marty'
3
+ require 'delorean_lang'
4
+
5
+ CODE =<<EOS
6
+ M:
7
+ cfmt = {
8
+ "type": ":cellIs",
9
+ "priority": 1,
10
+ "operator": ":greaterThan",
11
+ "dxfId" : {
12
+ "fg_color": "FFF8696B",
13
+ "type": ":dxf",
14
+ "b": true,
15
+ },
16
+ "formula": "$B$1",
17
+ }
18
+
19
+ hdr_style = {
20
+ "font_name": "Calibri",
21
+ "color": "FFFFFF",
22
+ "b": true,
23
+ "sz": 14,
24
+ "style": {
25
+ "bg_color": "0D056F",
26
+ "fg_color": "FFFFFF",
27
+ "alignment": {
28
+ "horizontal": ":center",
29
+ }
30
+ },
31
+ }
32
+
33
+ #handles cell style
34
+ c_style = {"style": [{"bg_color": "C5D9F1"}]}
35
+
36
+ hi_style = {
37
+ "b": true,
38
+ "bg_color": "0D056F",
39
+ "fg_color": "FFFFFF",
40
+ }
41
+
42
+ threshold_rows = [
43
+ ["row", ["Threshold", 5], {"style": [hi_style, {}]}],
44
+ ]
45
+
46
+ title_header = [
47
+ ["row", ["Sec Inst Name","Market Change Sec Inst"], hdr_style],
48
+ ]
49
+ rdata = [
50
+ ["title", 2, 4, 5, 6, 8 ],
51
+ ["text", 12, 4, 15, 6, 18 ],
52
+ ["text", 22, 4, 25, 6, 28 ],
53
+ ["text", 32, 4, 35, 6, 38 ],
54
+ ["text", 42, 4, 45, 6, 48 ],
55
+ ["text", 52, 4, 55, 6, 58 ],
56
+ ["text", 62, 4, 65, 6, 68 ],
57
+ ["text", 72, 4, 75, 6, 78 ]
58
+ ]
59
+
60
+ height = rdata.length()
61
+ width = rdata[0].length()
62
+
63
+ rows = [ ["row", r, c_style] for r in rdata ]
64
+
65
+ raw = title_header +
66
+ [["merge", [1, {"off": 0}, width - 1, {"off": 0}]]] +
67
+ [["conditional_formatting",
68
+ [1, {"off": 1}, width, {"off": height }], cfmt]] +
69
+ rows
70
+
71
+ ws = ["A Sheet",
72
+ [
73
+ ["pos", [0, 0], threshold_rows ],
74
+ ["pos", C1, raw ],
75
+ ["pos", C2, raw ],
76
+ ]
77
+ ]
78
+
79
+ title = "Per-Secutiry Market Change Report"
80
+ form = []
81
+
82
+ result = [ws]
83
+ format = "xlsx"
84
+ EOS
85
+
86
+
87
+ describe Marty::Xl do
88
+
89
+ let(:engine) {
90
+ Delorean::Engine.new "YYY"
91
+ }
92
+
93
+ def worksheet(ind, c)
94
+ code = CODE.clone
95
+ map = {'C1' => c[0].to_s, 'C2' => c[1].to_s}
96
+ map.each { |k,v| code.sub!(k,v) }
97
+ engine.parse(code)
98
+ engine.evaluate_attrs("M", ["result"]).flatten(1)
99
+ end
100
+
101
+ before(:all) do
102
+ @coords = [
103
+ [[9, 5], [2, 5]], # coords for non-overlaping datasets
104
+ [[5, 8], [2, 5]], # coords for overlaping datasets
105
+ ]
106
+ end
107
+
108
+ it "should be able to create a spreadsheet that includes multiple datasets that don't overlap " do
109
+ ws = worksheet(0, @coords[0])
110
+ sp = Marty::Xl.spreadsheet(ws)
111
+ file = Tempfile.new('file.xlsx')
112
+ lambda { sp.serialize(file) }.should_not raise_error()
113
+
114
+ sp.workbook.worksheets[0].rows[0].cells[0..1].map { |c| c.value }.should ==
115
+ ["Threshold", 5]
116
+
117
+ sp.workbook.worksheets[0].rows[1].cells[0..1].map { |c| c.value }.should ==
118
+ ["", ""]
119
+
120
+ sp.workbook.worksheets[0].rows[5].cells[0..15].map { |c| c.value }.should ==
121
+ ["", "", "Sec Inst Name", "Market Change Sec Inst", "", "", "", "", "", "Sec Inst Name", "Market Change Sec Inst", "","", "", ""]
122
+
123
+ sp.workbook.worksheets[0].rows[6].cells[0..15].map { |c| c.value }.should ==
124
+ ["", "", "title", 2, 4, 5, 6, 8, "", "title", 2, 4, 5, 6, 8]
125
+
126
+ sp.workbook.worksheets[0].rows[7].cells[0..15].map { |c| c.value }.should ==
127
+ ["", "", "text", 12, 4, 15, 6, 18, "", "text", 12, 4, 15, 6, 18]
128
+
129
+ sp.workbook.worksheets[0].rows[8].cells[0..15].map { |c| c.value }.should ==
130
+ ["", "", "text", 22, 4, 25, 6, 28, "", "text", 22, 4, 25, 6, 28]
131
+
132
+ sp.workbook.worksheets[0].rows[9].cells[0..15].map { |c| c.value }.should ==
133
+ ["", "", "text", 32, 4, 35, 6, 38, "", "text", 32, 4, 35, 6, 38]
134
+
135
+ sp.workbook.worksheets[0].rows[10].cells[0..15].map { |c| c.value }.should ==
136
+ ["", "", "text", 42, 4, 45, 6, 48, "", "text", 42, 4, 45, 6, 48]
137
+
138
+ sp.workbook.worksheets[0].rows[11].cells[0..15].map { |c| c.value }.should ==
139
+ ["", "", "text", 52, 4, 55, 6, 58, "", "text", 52, 4, 55, 6, 58]
140
+
141
+ sp.workbook.worksheets[0].rows[12].cells[0..15].map { |c| c.value }.should ==
142
+ ["", "", "text", 62, 4, 65, 6, 68, "", "text", 62, 4, 65, 6, 68]
143
+
144
+ sp.workbook.worksheets[0].rows[13].cells[0..15].map { |c| c.value }.should ==
145
+ ["", "", "text", 72, 4, 75, 6, 78, "", "text", 72, 4, 75, 6, 78]
146
+
147
+ end
148
+
149
+ it "should be able to create a spreadsheet that includes multiple datasets that overlap " do
150
+ ws = worksheet(1, @coords[1])
151
+ sp = Marty::Xl.spreadsheet(ws)
152
+ file = Tempfile.new('file.xlsx')
153
+ lambda { sp.serialize(file) }.should_not raise_error()
154
+
155
+ sp.workbook.worksheets[0].rows[0].cells[0..1].map { |c| c.value }.should ==
156
+ ["Threshold", 5]
157
+
158
+ sp.workbook.worksheets[0].rows[1].cells[0..1].map { |c| c.value }.should ==
159
+ ["", ""]
160
+
161
+ sp.workbook.worksheets[0].rows[5].cells[0..11].map { |c| c.value }.should ==
162
+ ["", "", "Sec Inst Name", "Market Change Sec Inst", "", "", "", "", "", "", ""]
163
+
164
+ sp.workbook.worksheets[0].rows[6].cells[0..11].map { |c| c.value }.should ==
165
+ ["", "", "title", 2, 4, 5, 6, 8, "", "", ""]
166
+
167
+ sp.workbook.worksheets[0].rows[7].cells[0..11].map { |c| c.value }.should ==
168
+ ["", "", "text", 12, 4, 15, 6, 18, "", "", ""]
169
+
170
+ sp.workbook.worksheets[0].rows[8].cells[0..11].map { |c| c.value }.should ==
171
+ ["", "", "text", 22, 4, "Sec Inst Name", "Market Change Sec Inst", 28, "", "", ""]
172
+
173
+ sp.workbook.worksheets[0].rows[9].cells[0..11].map { |c| c.value }.should ==
174
+ ["", "", "text", 32, 4, "title", 2, 4, 5, 6, 8]
175
+
176
+ sp.workbook.worksheets[0].rows[10].cells[0..11].map { |c| c.value }.should ==
177
+ ["", "", "text", 42, 4, "text", 12, 4, 15, 6, 18]
178
+
179
+ sp.workbook.worksheets[0].rows[11].cells[0..11].map { |c| c.value }.should ==
180
+ ["", "", "text", 52, 4, "text", 22, 4, 25, 6, 28]
181
+
182
+ sp.workbook.worksheets[0].rows[12].cells[0..11].map { |c| c.value }.should ==
183
+ ["", "", "text", 62, 4, "text", 32, 4, 35, 6, 38]
184
+
185
+ sp.workbook.worksheets[0].rows[13].cells[0..11].map { |c| c.value }.should ==
186
+ ["", "", "text", 72, 4, "text", 42, 4, 45, 6, 48]
187
+
188
+ sp.workbook.worksheets[0].rows[14].cells[0..11].map { |c| c.value }.should ==
189
+ ["", "", "", "", "", "text", 52, 4, 55, 6, 58]
190
+
191
+ sp.workbook.worksheets[0].rows[15].cells[0..11].map { |c| c.value }.should ==
192
+ ["", "", "", "", "", "text", 62, 4, 65, 6, 68]
193
+
194
+ sp.workbook.worksheets[0].rows[16].cells[0..11].map { |c| c.value }.should ==
195
+ ["", "", "", "", "", "text", 72, 4, 75, 6, 78]
196
+ end
197
+
198
+ end
@@ -0,0 +1,115 @@
1
+ require 'spec_helper'
2
+ require 'marty'
3
+ require 'delorean_lang'
4
+
5
+
6
+ STYLE_CODE =<<EOS
7
+ S:
8
+ data =
9
+ [
10
+ [1, 2],
11
+ [3, 4],
12
+ ]
13
+
14
+ raw = [ [ "border", [1,0,1,2], {
15
+ "style" : ":thin",
16
+ "color" : "000000"
17
+ } ]
18
+ ] +
19
+ [ [ "border", [0,1,2,1], {
20
+ "style" : ":thick",
21
+ "color" : "FF0000"
22
+ } ]
23
+ ] +
24
+ [
25
+ ["row", r]
26
+ for r in data
27
+ ]
28
+
29
+ ws = ["BorderExample", [ ["pos", [1, 1], raw] ] ]
30
+
31
+ title = "Border Example"
32
+ form = []
33
+ format = "xlsx"
34
+ result = [ws]
35
+ EOS
36
+
37
+ describe Marty::Xl do
38
+
39
+ let(:engine) {
40
+ Delorean::Engine.new "YYY"
41
+ }
42
+
43
+ before(:each) do
44
+ code = STYLE_CODE.clone
45
+ engine.parse(code)
46
+ @ws = engine.evaluate_attrs("S", ["result"]).flatten(1)
47
+ end
48
+
49
+ it "should be able to create a spreadsheet with overlapping border styles" do
50
+ sp = Marty::Xl.spreadsheet(@ws)
51
+ wb = sp.workbook
52
+
53
+ file = Tempfile.new('file2.xlsx')
54
+ lambda { sp.serialize(file) }.should_not raise_error()
55
+
56
+ def border_details(b)
57
+ edges = []
58
+ b.prs.each do |pr|
59
+ edges << [pr.name, pr.style, pr.color.rgb]
60
+ end
61
+ edges.sort_by{ |k| k[0] }
62
+ end
63
+
64
+ sp.workbook.worksheets[0].rows[0].cells[0..1].map { |c| c.value }.should ==
65
+ ["", ""]
66
+
67
+ sp.workbook.worksheets[0].rows[1].cells[0..2].map { |c| c.value }.should ==
68
+ ["", 1, 2]
69
+
70
+ sp.workbook.worksheets[0].rows[2].cells[0..2].map { |c| c.value }.should ==
71
+ ["", 3, 4]
72
+
73
+ wb.worksheets[0].styles.borders.count.should >= 4
74
+
75
+ wb.worksheets[0].styles.borders.each_index do |i|
76
+ b = border_details(wb.worksheets[0].styles.borders[i])
77
+
78
+ case i
79
+ when 0
80
+ b.should == []
81
+ when 2
82
+ b.should == [[:left, :thin, "FF000000"]]
83
+ when 3
84
+ b.should == [[:top, :thick, "FFFF0000"]]
85
+ when 4
86
+ b.should == [[:left, :thin, "FF000000"], [:top, :thick, "FFFF0000"]]
87
+ else
88
+ next
89
+ end
90
+ end
91
+
92
+ wb.worksheets[0].styles.cellXfs.count.should >= 8
93
+
94
+ wb.worksheets[0].styles.cellXfs.each_index do |i|
95
+ c = wb.worksheets[0].styles.cellXfs[i]
96
+ case i
97
+ when 3
98
+ c.borderId.should == 0
99
+ when 4
100
+ c.borderId.should == 0
101
+ when 5
102
+ c.borderId.should == 2
103
+ when 6
104
+ c.borderId.should == 0
105
+ when 7
106
+ c.borderId.should == 3
107
+ when 8
108
+ c.borderId.should == 4
109
+ else
110
+ next
111
+ end
112
+ end
113
+
114
+ end
115
+ end
@@ -0,0 +1,187 @@
1
+ require 'spec_helper'
2
+
3
+ module Marty
4
+ describe ApiAuth do
5
+ before(:each) do
6
+ Marty::Script.load_script_bodies({
7
+ "Script1" => "A:\n a = 1\n",
8
+ "NewScript1" => "B:\n b = 0\n",
9
+ }, Date.today)
10
+
11
+ @api = ApiAuth.new
12
+ @api.app_name = 'TestApp'
13
+ @api.script_name = 'Script1'
14
+ @api.save!
15
+ @api.reload
16
+ end
17
+
18
+ describe "validations" do
19
+ it "should require app name, api key and script name" do
20
+ api = ApiAuth.new
21
+ expect(api).to_not be_valid
22
+ expect(api.errors[:app_name].any?).to be true
23
+ expect(api.errors[:api_key].any?).to be false # auto-set if nil
24
+ expect(api.errors[:script_name].any?).to be true
25
+ end
26
+
27
+ it "should require unique app name/script name" do
28
+ api = @api.dup
29
+ expect(api).to_not be_valid
30
+ expect(api.errors[:app_name].to_s).to include('already been taken')
31
+ api.script_name = 'NewScript1'
32
+ expect(api).to be_valid
33
+ end
34
+
35
+ it "should require unique api key/script name" do
36
+ api = @api.dup
37
+ expect(api).to_not be_valid
38
+ expect(api.errors[:api_key].to_s).to include('must be unique')
39
+ api.script_name = 'NewScript1'
40
+ expect(api).to be_valid
41
+ end
42
+
43
+ it "should require a valid associated script name" do
44
+ api = ApiAuth.new
45
+ api.app_name = 'NewApp'
46
+ api.script_name = @api.script_name + 'Bad'
47
+ expect(api).to_not be_valid
48
+ expect(api.errors[:base].to_s).to include('reference a valid script')
49
+ end
50
+
51
+ it "should allow a tagged script version to be associated when a DEV " +
52
+ "version of that script also exists" do
53
+ s = Marty::Script.lookup('infinity', 'Script1')
54
+ s.body = "A:\n a = 3\n"
55
+ s.save!
56
+
57
+ api = ApiAuth.new
58
+ api.app_name = 'NewApp'
59
+ api.script_name = s.name
60
+ expect(api).to be_valid
61
+ end
62
+
63
+ it "should not allow a DEV script to be associated if there is no " +
64
+ "tagged version of that script" do
65
+ s = Marty::Script.new
66
+ s.name = 'TestScript'
67
+ s.body = '-- Test3'
68
+ # Creates a script in the future - no tag exists
69
+ s.created_dt = Time.now + 1.minute
70
+ s.save!
71
+
72
+ api = ApiAuth.new
73
+ api.app_name = 'NewApp'
74
+ api.script_name = s.name
75
+ expect(api).to_not be_valid
76
+ expect(api.errors[:base].to_s).to include('reference a valid script')
77
+ end
78
+ end
79
+
80
+ describe "key management" do
81
+ it "should require a 38 character key" do
82
+ expect(@api.api_key.length).to eq(38)
83
+
84
+ @api.api_key = "123456789"
85
+ expect(@api).to_not be_valid
86
+ expect(@api.errors[:base].to_s).to include('length must be 38')
87
+ end
88
+
89
+ it "should create the api key if necessary when the record is created" do
90
+ a = ApiAuth.new
91
+ a.app_name = 'MyApp'
92
+ a.script_name = 'NewScript1'
93
+ expect(a.api_key).to be_nil
94
+ a.save!
95
+ expect(a.api_key).to_not be_nil
96
+ end
97
+
98
+ it "should allow api key to be updated for an existing record" do
99
+ old = @api.api_key
100
+ @api.api_key = ApiAuth.generate_key
101
+ new = @api.api_key
102
+ expect(@api.api_key).to_not eq(old)
103
+ expect(@api).to be_valid
104
+ @api.save!
105
+ # Verifies that validation and saving does not create new key
106
+ expect(@api.api_key).to eq(new)
107
+ end
108
+
109
+ it "should generate new api key if old one is cleared" do
110
+ old = @api.api_key
111
+ @api.api_key = ''
112
+ @api.app_name += 'x'
113
+ @api.save!
114
+ expect(@api.api_key).to_not eq(old)
115
+ end
116
+
117
+ it "should generate new api key if old one is cleared (2)" do
118
+ old = @api.api_key
119
+ @api.api_key = nil
120
+ @api.app_name += 'x'
121
+ @api.save!
122
+ expect(@api.api_key).to_not eq(old)
123
+ end
124
+ end
125
+
126
+ describe "authorization" do
127
+ it "should pass when script is not secured" do
128
+ # Script is not secured by any entries
129
+ expect(ApiAuth.authorized?('SomeScript','SomeKey')).to be true
130
+ end
131
+
132
+ it "should pass when script is secured and key is valid" do
133
+ expect(@api.script_name).to include('Script1')
134
+ expect(ApiAuth.authorized?(@api.script_name,@api.api_key)).to be true
135
+ end
136
+
137
+ it "should pass when script is secured and key is valid 2" do
138
+ a = ApiAuth.new
139
+ a.app_name = @api.app_name + 'x'
140
+ a.script_name = 'NewScript1'
141
+ a.save!
142
+ expect(ApiAuth.authorized?('NewScript1',a.api_key)).to be true
143
+ end
144
+
145
+ it "should match on exact script name" do
146
+ a = ApiAuth.new
147
+ a.app_name = @api.app_name + 'x'
148
+ a.script_name = 'NewScript1'
149
+ a.save!
150
+ expect(ApiAuth.authorized?('Script1',a.api_key)).to be false
151
+ end
152
+
153
+ it "should fail when script is secured and key is invalid" do
154
+ expect(ApiAuth.authorized?('Script1','SomeKey')).to be false
155
+ end
156
+
157
+ it "should fail when script is secured and key is invalid (2)" do
158
+ a = ApiAuth.new
159
+ a.app_name = @api.app_name + 'x'
160
+ a.script_name = 'NewScript1'
161
+ a.save!
162
+ expect(ApiAuth.authorized?('NewScript1',@api.api_key)).to be false
163
+ end
164
+
165
+ it "should fail when script is secured and key is not specified" do
166
+ expect(ApiAuth.authorized?('Script1',nil)).to be false
167
+ expect(ApiAuth.authorized?('Script1','')).to be false
168
+ end
169
+
170
+ it "should pass when api_auth is deleted and no other auths exist" do
171
+ expect(ApiAuth.authorized?(@api.script_name,@api.api_key)).to be true
172
+ @api.delete
173
+ expect(ApiAuth.authorized?(@api.script_name,@api.api_key)).to be true
174
+ end
175
+
176
+ it "should fail when api_auth is deleted and another auth exists" do
177
+ api = @api.dup
178
+ api.app_name += 'x'
179
+ api.api_key = nil
180
+ api.save!
181
+ expect(ApiAuth.authorized?(@api.script_name,@api.api_key)).to be true
182
+ @api.delete
183
+ expect(ApiAuth.authorized?(@api.script_name,@api.api_key)).to be false
184
+ end
185
+ end
186
+ end
187
+ end