marty 0.5.15 → 0.5.16
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +27 -0
- data/.rspec +3 -0
- data/.travis.yml +23 -0
- data/Gemfile +23 -0
- data/INDEPENDENCE_ISSUES.md +23 -0
- data/app/assets/images/marty/.gitkeep +0 -0
- data/app/components/marty/report_form.rb +9 -4
- data/gemini_deprecations.md +6 -0
- data/lib/marty/data_change.rb +99 -0
- data/lib/marty/data_conversion.rb +11 -3
- data/lib/marty/data_exporter.rb +9 -0
- data/lib/marty/version.rb +1 -1
- data/marty.gemspec +35 -0
- data/script/rails +8 -0
- data/spec/controllers/application_controller_spec.rb +52 -0
- data/spec/controllers/job_controller_spec.rb +226 -0
- data/spec/controllers/rpc_controller_spec.rb +379 -0
- data/spec/controllers/rpc_import_spec.rb +45 -0
- data/spec/dummy/README.rdoc +261 -0
- data/spec/dummy/Rakefile +7 -0
- data/spec/dummy/app/assets/javascripts/application.js +15 -0
- data/spec/dummy/app/assets/stylesheets/application.css +13 -0
- data/spec/dummy/app/controllers/application_controller.rb +3 -0
- data/spec/dummy/app/controllers/components_controller.rb +7 -0
- data/spec/dummy/app/helpers/application_helper.rb +2 -0
- data/spec/dummy/app/mailers/.gitkeep +0 -0
- data/spec/dummy/app/models/.gitkeep +0 -0
- data/spec/dummy/app/models/gemini/amortization_type.rb +5 -0
- data/spec/dummy/app/models/gemini/bud_category.rb +7 -0
- data/spec/dummy/app/models/gemini/entity.rb +2 -0
- data/spec/dummy/app/models/gemini/extras/data_import.rb +5 -0
- data/spec/dummy/app/models/gemini/extras/settlement_import.rb +28 -0
- data/spec/dummy/app/models/gemini/fannie_bup.rb +29 -0
- data/spec/dummy/app/models/gemini/grouping.rb +8 -0
- data/spec/dummy/app/models/gemini/grouping_head_version.rb +14 -0
- data/spec/dummy/app/models/gemini/head.rb +7 -0
- data/spec/dummy/app/models/gemini/head_version.rb +14 -0
- data/spec/dummy/app/models/gemini/helper.rb +44 -0
- data/spec/dummy/app/models/gemini/loan_program.rb +11 -0
- data/spec/dummy/app/models/gemini/mortgage_type.rb +5 -0
- data/spec/dummy/app/models/gemini/simple.rb +6 -0
- data/spec/dummy/app/models/gemini/streamline_type.rb +16 -0
- data/spec/dummy/app/views/layouts/application.html.erb +14 -0
- data/spec/dummy/config.ru +4 -0
- data/spec/dummy/config/application.rb +82 -0
- data/spec/dummy/config/boot.rb +10 -0
- data/spec/dummy/config/database.yml.example +10 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/development.rb +35 -0
- data/spec/dummy/config/environments/production.rb +69 -0
- data/spec/dummy/config/environments/test.rb +39 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy/config/initializers/delayed_job.rb +5 -0
- data/spec/dummy/config/initializers/inflections.rb +15 -0
- data/spec/dummy/config/initializers/mime_types.rb +5 -0
- data/spec/dummy/config/initializers/secret_token.rb +7 -0
- data/spec/dummy/config/initializers/session_store.rb +8 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/spec/dummy/config/locales/en.yml +5 -0
- data/spec/dummy/config/routes.rb +12 -0
- data/spec/dummy/db/migrate/20140801000000_create_groupings.rb +11 -0
- data/spec/dummy/db/migrate/20150406171536_create_categories.rb +27 -0
- data/spec/dummy/db/migrate/20150408200916_create_loan_programs.rb +26 -0
- data/spec/dummy/db/migrate/20150408201429_create_types.rb +21 -0
- data/spec/dummy/db/migrate/20150420000001_create_heads.rb +14 -0
- data/spec/dummy/db/migrate/20150420000002_create_head_versions.rb +15 -0
- data/spec/dummy/db/migrate/20150420000003_create_grouping_head_versions.rb +12 -0
- data/spec/dummy/db/migrate/20151023000001_create_simple.rb +12 -0
- data/spec/dummy/db/seeds.rb +8 -0
- data/spec/dummy/delorean/blame_report.dl +171 -0
- data/spec/dummy/delorean/data_report.dl +105 -0
- data/spec/dummy/delorean/fields.dl +52 -0
- data/spec/dummy/delorean/styles.dl +134 -0
- data/spec/dummy/lib/assets/.gitkeep +0 -0
- data/spec/dummy/lib/class_list.rb +3 -0
- data/spec/dummy/log/.gitkeep +0 -0
- data/spec/dummy/public/404.html +26 -0
- data/spec/dummy/public/422.html +26 -0
- data/spec/dummy/public/500.html +25 -0
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/dummy/public/icons/READ.txt +3 -0
- data/spec/dummy/public/icons/application_cascade.png +0 -0
- data/spec/dummy/public/icons/application_delete.png +0 -0
- data/spec/dummy/public/icons/application_put.png +0 -0
- data/spec/dummy/public/icons/application_view_detail.png +0 -0
- data/spec/dummy/public/icons/arrow_in.png +0 -0
- data/spec/dummy/public/icons/arrow_refresh.png +0 -0
- data/spec/dummy/public/icons/database_save.png +0 -0
- data/spec/dummy/public/icons/door_in.png +0 -0
- data/spec/dummy/public/icons/door_out.png +0 -0
- data/spec/dummy/public/icons/group.png +0 -0
- data/spec/dummy/public/icons/page_lightning.png +0 -0
- data/spec/dummy/public/icons/printer.png +0 -0
- data/spec/dummy/public/icons/report_disk.png +0 -0
- data/spec/dummy/public/icons/report_go.png +0 -0
- data/spec/dummy/public/icons/report_magnify.png +0 -0
- data/spec/dummy/public/icons/script.png +0 -0
- data/spec/dummy/public/icons/script_add.png +0 -0
- data/spec/dummy/public/icons/script_go.png +0 -0
- data/spec/dummy/public/icons/script_key.png +0 -0
- data/spec/dummy/public/icons/table_go.png +0 -0
- data/spec/dummy/public/icons/time.png +0 -0
- data/spec/dummy/public/icons/time_add.png +0 -0
- data/spec/dummy/public/icons/time_go.png +0 -0
- data/spec/dummy/public/icons/timeline_marker.png +0 -0
- data/spec/dummy/public/icons/user_add.png +0 -0
- data/spec/dummy/public/icons/user_delete.png +0 -0
- data/spec/dummy/public/icons/user_edit.png +0 -0
- data/spec/dummy/public/icons/wrench.png +0 -0
- data/spec/dummy/script/delayed_job +6 -0
- data/spec/dummy/script/rails +6 -0
- data/spec/features/javascripts/job_dashboard_live_search.js.coffee +8 -0
- data/spec/features/javascripts/login.js.coffee +8 -0
- data/spec/features/jobs_dashboard_netzke_spec.rb +24 -0
- data/spec/features/jobs_dashboard_spec.rb +49 -0
- data/spec/fixtures/scripts/load_tests/script1.dl +2 -0
- data/spec/fixtures/scripts/load_tests/script2.dl +2 -0
- data/spec/job_helper.rb +102 -0
- data/spec/lib/data_exporter_spec.rb +71 -0
- data/spec/lib/data_importer_spec.rb +461 -0
- data/spec/lib/xl_spec.rb +198 -0
- data/spec/lib/xl_styles_spec.rb +115 -0
- data/spec/models/api_auth_spec.rb +187 -0
- data/spec/models/posting_spec.rb +107 -0
- data/spec/models/promise_spec.rb +65 -0
- data/spec/models/script_spec.rb +187 -0
- data/spec/models/user_spec.rb +68 -0
- data/spec/requests/routes_spec.rb +12 -0
- data/spec/spec_helper.rb +61 -0
- data/spec/support/clean_db_helpers.rb +18 -0
- data/spec/support/delayed_job_helpers.rb +12 -0
- data/spec/support/user_helpers.rb +12 -0
- metadata +139 -89
- data/app/components/marty/auth_app.rb~ +0 -51
- data/app/components/marty/auth_app/javascripts/auth_app.js~ +0 -91
- data/app/components/marty/cm_form_panel.rb~ +0 -5
- data/app/components/marty/cm_grid_panel.rb~ +0 -35
- data/app/components/marty/data_import_view.rb~ +0 -142
- data/app/components/marty/extras/layout.rb~ +0 -46
- data/app/components/marty/live_search_grid_panel.rb~ +0 -49
- data/app/components/marty/main_auth_app.rb~ +0 -238
- data/app/components/marty/mcfly_grid_panel.rb~ +0 -80
- data/app/components/marty/new_posting_form.rb~ +0 -46
- data/app/components/marty/new_posting_window.rb~ +0 -21
- data/app/components/marty/pivot_grid.rb +0 -52
- data/app/components/marty/pivot_grid/endpoints.rb +0 -45
- data/app/components/marty/pivot_grid/javascripts/extensions.js +0 -150
- data/app/components/marty/pivot_grid/javascripts/pivot_grid.js +0 -86
- data/app/components/marty/pivot_grid/services.rb +0 -44
- data/app/components/marty/posting_grid.rb~ +0 -140
- data/app/components/marty/promise_view.rb~ +0 -157
- data/app/components/marty/promise_view/stylesheets/promise_view.css~ +0 -15
- data/app/components/marty/report_form.rb~ +0 -217
- data/app/components/marty/report_select.rb~ +0 -133
- data/app/components/marty/reporting.rb~ +0 -39
- data/app/components/marty/script_detail.rb~ +0 -430
- data/app/components/marty/script_form.rb~ +0 -233
- data/app/components/marty/script_form/javascripts/Ext.ux.form.field.CodeMirror.js~ +0 -909
- data/app/components/marty/script_grid.rb~ +0 -99
- data/app/components/marty/script_tester.rb~ +0 -213
- data/app/components/marty/scripting.rb~ +0 -124
- data/app/components/marty/select_report.rb~ +0 -143
- data/app/components/marty/simple_app.rb~ +0 -101
- data/app/components/marty/tag_grid.rb~ +0 -89
- data/app/components/marty/tree_panel.rb~ +0 -256
- data/app/components/marty/tree_panel/javascripts/tree_panel.js~ +0 -317
- data/app/components/marty/user_pivot.rb +0 -128
- data/app/components/marty/user_view.rb~ +0 -188
- data/app/controllers/marty/application_controller.rb~ +0 -133
- data/app/controllers/marty/components_controller.rb~ +0 -37
- data/app/controllers/marty/job_controller.rb~ +0 -28
- data/app/controllers/marty/rpc_controller.rb~ +0 -61
- data/app/helpers/marty/script_set.rb~ +0 -59
- data/app/models/marty/api_auth.rb~ +0 -48
- data/app/models/marty/data_change.rb~ +0 -141
- data/app/models/marty/enum.rb~ +0 -16
- data/app/models/marty/import_type.rb~ +0 -48
- data/app/models/marty/poop.rb~ +0 -169
- data/app/models/marty/posting.rb~ +0 -86
- data/app/models/marty/posting_type.rb~ +0 -21
- data/app/models/marty/promise.rb~ +0 -196
- data/app/models/marty/role.rb~ +0 -10
- data/app/models/marty/script.rb~ +0 -62
- data/app/models/marty/tag.rb~ +0 -91
- data/app/models/marty/user.rb~ +0 -148
- data/app/models/marty/user_role.rb~ +0 -13
- data/app/views/layouts/marty/application.html.erb~ +0 -11
- data/config/routes.rb~ +0 -10
- data/db/migrate/019_create_marty_postings.rb~ +0 -19
- data/db/migrate/095_create_marty_tags.rb~ +0 -19
- data/lib/marty.rb~ +0 -13
- data/lib/marty/content_handler.rb~ +0 -93
- data/lib/marty/data_exporter.rb~ +0 -137
- data/lib/marty/data_importer.rb~ +0 -114
- data/lib/marty/data_row_processor.rb~ +0 -206
- data/lib/marty/drop_folder_hook.rb~ +0 -17
- data/lib/marty/folder_hook.rb~ +0 -9
- data/lib/marty/lazy_column_loader.rb~ +0 -47
- data/lib/marty/mcfly_query.rb~ +0 -188
- data/lib/marty/migrations.rb~ +0 -65
- data/lib/marty/monkey.rb~ +0 -160
- data/lib/marty/permissions.rb~ +0 -69
- data/lib/marty/promise.rb~ +0 -41
- data/lib/marty/promise_job.rb~ +0 -121
- data/lib/marty/promise_proxy.rb~ +0 -69
- data/lib/marty/util.rb~ +0 -80
- data/lib/marty/version.rb~ +0 -3
- data/lib/marty/xl.rb~ +0 -526
- data/lib/pyxll/README.txt~ +0 -16
- data/lib/pyxll/gemini.py~ +0 -110
- data/lib/pyxll/pyxll.cfg~ +0 -12
data/spec/lib/xl_spec.rb
ADDED
@@ -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
|