├── .gitignore ├── .rubocop.yml ├── .travis.yml ├── CHANGELOG.md ├── MIT-LICENSE ├── PluginGemfile ├── README.md ├── app └── views │ └── hooks │ └── _view_custom_fields_form_upper_box.html.erb ├── config ├── database.yml.travis └── locales │ ├── en.yml │ ├── es.yml │ ├── fr.yml │ ├── pl.yml │ ├── pt-BR.yml │ ├── ru.yml │ └── zh.yml ├── db └── migrate │ ├── 20161229192026_add_custom_fields_formula.rb │ ├── 20161229192027_add_custom_fields_is_computed.rb │ └── 20170205204732_convert_custom_fields.rb ├── init.rb ├── lib ├── computed_custom_field.rb └── computed_custom_field │ ├── custom_field_patch.rb │ ├── custom_fields_helper_patch.rb │ ├── formula_validator.rb │ ├── hooks.rb │ ├── issue_patch.rb │ └── model_patch.rb └── test ├── fixtures_helper.rb ├── gemfile_locks ├── 2.5.3 │ └── Gemfile.lock ├── 2.6.10 │ └── Gemfile.lock ├── 3.0.7 │ └── Gemfile.lock ├── 3.1.7 │ └── Gemfile.lock ├── 3.2.9 │ └── Gemfile.lock ├── 3.3.9 │ └── Gemfile.lock ├── 3.4.7 │ └── Gemfile.lock └── 4.0.0 │ └── Gemfile.lock ├── methods_helper.rb ├── test_helper.rb ├── ui ├── computed_custom_field_test.rb └── issue_test.rb └── unit ├── computed_custom_field_test.rb ├── custom_field_test.rb └── model_patch_test.rb /.gitignore: -------------------------------------------------------------------------------- 1 | .bundle/ 2 | log/*.log 3 | pkg/ 4 | test/dummy/db/*.sqlite3 5 | test/dummy/db/*.sqlite3-journal 6 | test/dummy/log/*.log 7 | test/dummy/tmp/ 8 | test/dummy/.sass-cache 9 | -------------------------------------------------------------------------------- /.rubocop.yml: -------------------------------------------------------------------------------- 1 | AllCops: 2 | Exclude: 3 | - 'db/**/*' 4 | DisplayCopNames: true 5 | DisplayStyleGuide: true 6 | TargetRubyVersion: 2.1 7 | 8 | Lint/RescueException: 9 | Enabled: false 10 | 11 | Metrics/AbcSize: 12 | Exclude: 13 | - 'test/**/*' 14 | 15 | Metrics/MethodLength: 16 | Exclude: 17 | - 'test/**/*' 18 | 19 | Metrics/LineLength: 20 | Max: 120 21 | 22 | Style/ClassAndModuleChildren: 23 | Enabled: false 24 | 25 | Style/Documentation: 26 | Enabled: false 27 | 28 | Style/ExpandPathArguments: 29 | Enabled: false 30 | 31 | Style/FrozenStringLiteralComment: 32 | Enabled: false 33 | 34 | Style/PredicateName: 35 | Enabled: false 36 | 37 | Style/SymbolArray: 38 | Enabled: false 39 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | dist: trusty 2 | language: ruby 3 | 4 | rvm: 2.1.5 5 | 6 | env: 7 | - REDMINE_VER=3.4.7 8 | - REDMINE_VER=3.3.9 9 | - REDMINE_VER=3.2.9 10 | - REDMINE_VER=3.1.7 11 | - REDMINE_VER=3.0.7 12 | - REDMINE_VER=2.6.10 13 | 14 | addons: 15 | chrome: stable 16 | 17 | matrix: 18 | include: 19 | - rvm: 1.9.3 20 | env: REDMINE_VER=2.5.3 21 | - rvm: 2.2.3 22 | env: REDMINE_VER=4.0.0 23 | 24 | before_install: 25 | - export DISPLAY=:99.0 26 | - sh -e /etc/init.d/xvfb start 27 | - if [[ $REDMINE_VER = '4.0.0' ]]; then 28 | wget -N http://chromedriver.storage.googleapis.com/2.40/chromedriver_linux64.zip -P ~/; 29 | unzip ~/chromedriver_linux64.zip -d ~/; 30 | rm ~/chromedriver_linux64.zip; 31 | sudo mv -f ~/chromedriver /usr/local/share/; 32 | sudo chmod +x /usr/local/share/chromedriver; 33 | sudo ln -s /usr/local/share/chromedriver /usr/local/bin/chromedriver; 34 | google-chrome-stable --headless --disable-gpu --remote-debugging-port=9222 http://localhost & 35 | else 36 | phantomjs --webdriver 4444 & 37 | fi 38 | - export RUBYOPT="-W0" 39 | - export PLUGIN_NAME=computed_custom_field 40 | - export REDMINE_PATH=$HOME/redmine 41 | - git clone -b "$REDMINE_VER" --single-branch https://github.com/redmine/redmine.git $REDMINE_PATH 42 | - ln -s $TRAVIS_BUILD_DIR $REDMINE_PATH/plugins/$PLUGIN_NAME 43 | - cp config/database.yml.travis $REDMINE_PATH/config/database.yml 44 | - cp test/gemfile_locks/$REDMINE_VER/Gemfile.lock $REDMINE_PATH/Gemfile.lock 45 | - cd $REDMINE_PATH 46 | - if [[ $REDMINE_VER < '3.2.9' ]]; then 47 | echo "$(curl http://www.redmine.org/projects/redmine/repository/revisions/14891/diff/trunk/lib/tasks/redmine.rake?format=diff)" > redmine.rake.patch; 48 | patch lib/tasks/redmine.rake redmine.rake.patch; fi 49 | - bundle install --without development 50 | 51 | install: true 52 | 53 | before_script: 54 | - bundle exec rake db:create 55 | - bundle exec rake db:migrate 56 | - bundle exec rake redmine:plugins:migrate 57 | 58 | script: 59 | - bundle exec rake redmine:plugins:test:units NAME=$PLUGIN_NAME 60 | - bundle exec rake redmine:plugins:test:ui NAME=$PLUGIN_NAME 61 | 62 | notifications: 63 | email: false 64 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | ## [1.0.7](https://github.com/annikoff/redmine_plugin_computed_custom_field/releases/tag/v1.0.7) - 2019-01-13 4 | ### Added 5 | - Redmine 4.0.x support. 6 | 7 | ### Changed 8 | - README. 9 | - Refactor code. 10 | 11 | ### Fixed 12 | - Tests. 13 | 14 | ### Removed 15 | - hound.yml 16 | 17 | ## [1.0.6](https://github.com/annikoff/redmine_plugin_computed_custom_field/releases/tag/v1.0.6) - 2017-08-07 18 | ### Added 19 | - Redmine 3.4.x support. 20 | 21 | ## [1.0.5](https://github.com/annikoff/redmine_plugin_computed_custom_field/releases/tag/v1.0.5) - 2017-03-21 22 | ### Changed 23 | - PluginGemfile 24 | 25 | ## [1.0.4](https://github.com/annikoff/redmine_plugin_computed_custom_field/releases/tag/v1.0.4) - 2017-02-24 26 | ### Added 27 | - pl translation from [Ralph Gutkowski](https://github.com/rgtk). 28 | 29 | ## [1.0.3](https://github.com/annikoff/redmine_plugin_computed_custom_field/releases/tag/v1.0.3) - 2017-02-20 30 | ### Added 31 | - An additional information for available fields list. 32 | 33 | ## [1.0.2](https://github.com/annikoff/redmine_plugin_computed_custom_field/releases/tag/v1.0.2) - 2017-02-20 34 | ### Fixed 35 | - Migration. 36 | 37 | ## [1.0.1](https://github.com/annikoff/redmine_plugin_computed_custom_field/releases/tag/v1.0.1) - 2017-02-20 38 | ### Fixed 39 | - Migration. 40 | 41 | ## [1.0.0](https://github.com/annikoff/redmine_plugin_computed_custom_field/releases/tag/v1.0.0) - 2017-02-15 42 | ### Added 43 | - New formula constructions `cfs[cf_id]`. Thanks to [ecanuto](https://github.com/ecanuto) for the idea. 44 | - Tests. 45 | - CHANGELOG. 46 | - Redmine 2.5.x support. 47 | 48 | ### Changed 49 | - Code has been rewritten from scratch. 50 | - No backward compatibility with older versions. 51 | - There is no separate computed format anymore. Custom field of any built-in format can be created as computed. 52 | - README. 53 | 54 | ### Removed 55 | - Old formula constructions `%{cf_id}`. 56 | - Output formats. 57 | 58 | ## [0.0.8](https://github.com/annikoff/redmine_plugin_computed_custom_field/releases/tag/v0.0.8) - 2016-11-27 59 | ### Added 60 | - Error handling to prevent internal server errors. From [swiehr](https://github.com/swiehr). 61 | - zh translation from [archonwang](https://github.com/archonwang). 62 | 63 | ### Changed 64 | - README. 65 | 66 | ### Fixed 67 | - Link formatting. 68 | 69 | ## [0.0.7](https://github.com/annikoff/redmine_plugin_computed_custom_field/releases/tag/v0.0.7) - 2016-08-29 70 | ### Added 71 | - Markdown link format support. 72 | - Grouping functionality for queries. From [plotterie](https://github.com/plotterie). 73 | 74 | ### Changed 75 | - README. 76 | 77 | ### Fixed 78 | - Typo in a custom field form. From [swiehr](https://github.com/swiehr). 79 | - Error when validating DateTime. 80 | 81 | ## [0.0.6](https://github.com/annikoff/redmine_plugin_computed_custom_field/releases/tag/v0.0.6) - 2016-01-15 82 | ### Added 83 | - Totalable support for Redmine 3.x. 84 | 85 | ### Fixed 86 | - Error when trying to save iIssue from TimeEntry if Issue does not present. 87 | 88 | ## [0.0.5](https://github.com/annikoff/redmine_plugin_computed_custom_field/releases/tag/v0.0.5) - 2015-12-21 89 | ### Added 90 | - Link output format. 91 | - pt-br translation from [Adriano Ceccarelli](https://github.com/aceccarelli). 92 | 93 | ### Changed 94 | - README. 95 | - Error message about formula computing. 96 | 97 | ### Fixed 98 | - Exclude Document class from list of classes for a patch. 99 | 100 | ## [0.0.4](https://github.com/annikoff/redmine_plugin_computed_custom_field/releases/tag/v0.0.4) - 2015-10-22 101 | ### Added 102 | - Boolean and Percentage output formats. 103 | - TimeEntry callbacks to re-save Issue. 104 | - fr translation from [Atmis](https://github.com/Atmis). 105 | 106 | ### Removed 107 | - Tests examples 108 | 109 | ### Fixed 110 | - Bug when formula validation 111 | 112 | ## [0.0.3](https://github.com/annikoff/redmine_plugin_computed_custom_field/releases/tag/v0.0.3) - 2015-09-23 113 | ### Added 114 | - String and Datetime output formats. 115 | - Query filter options. 116 | 117 | ### Fixed 118 | - Formula validation is evaluated in proper context. 119 | 120 | ## [0.0.2](https://github.com/annikoff/redmine_plugin_computed_custom_field/releases/tag/v0.0.2) - 2015-09-20 121 | ### Added 122 | - Int and Float output formats. 123 | - en translation. 124 | - es translation from [lublasco](https://github.com/lublasco). 125 | - Formula validation. 126 | 127 | ### Changed 128 | - List of classes for a patch. 129 | - README. 130 | - Excluded CF own id from available fields list. 131 | 132 | ### Removed 133 | - Groups of custom fields from creation form. 134 | 135 | ### Fixed 136 | - Conversion error when formula computation 137 | 138 | ## [0.0.1](https://github.com/annikoff/redmine_plugin_computed_custom_field/releases/tag/v0.0.1) - 2015-08-13 139 | ### Added 140 | - Base functionality. 141 | -------------------------------------------------------------------------------- /MIT-LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2015 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /PluginGemfile: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dpalic/redmine_plugin_computed_custom_field/ecf1d5d7593481634cee530fed7469ea6e9b936a/PluginGemfile -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # This project was taken over from annikoff 2 | 3 | see also 4 | 5 | ## ComputedCustomField plugin for Redmine 6 | 7 | [](https://travis-ci.org/annikoff/redmine_plugin_computed_custom_field) 8 | [](https://codeclimate.com/github/annikoff/redmine_plugin_computed_custom_field) 9 | 10 | ### Description: 11 | 12 | This plugin provides a possibility to create a computed custom field. 13 | The value of the computed field can be set by formula. 14 | In formula constructions like `cfs[cf_id]` are replaced by IDs of custom fields. 15 | A valid formula is a valid Ruby code executed when a customized object is updated. 16 | To put a field ID in the formula, double-click on an item in the list of available fields. 17 | 18 | 19 |  20 | 21 | ### Changelog: 22 | 23 | Plugin's changelog is available [here](CHANGELOG.md). 24 | 25 | ### Important information 26 | 27 | This is a new version of the plugin. Since version 1.0.0 it is not compatible with previous versions. 28 | The following constructions in formula `%{cf_id}` are no longer supported. Instead use `cfs[cf_id]`. 29 | If you need to upgrade from older versions, please check out migration section. 30 | 31 | > ### Notes: 32 | > - cfs[cf_id] — must be an ID of existing custom field. 33 | > - Be careful with code in a formula, if it would wrong your application can be crashed. 34 | > - If a computed custom field was created after creating of a customized object you need to re-save an object to evaluate computations. 35 | > - After updating of formula customized objects should be re-saved. 36 | 37 | ### Installation: 38 | 39 | Clone from GitHub 40 | ```sh 41 | # Latest version 42 | git clone https://github.com/annikoff/redmine_plugin_computed_custom_field.git computed_custom_field 43 | ``` 44 | 45 | Or download [ZIP-archive](https://github.com/annikoff/redmine_plugin_computed_custom_field/archive/master.zip) and extract it into "computed_custom_field" directory. 46 | 47 | Run migrations 48 | ```sh 49 | rake redmine:plugins:migrate 50 | ``` 51 | 52 | ### Migration: 53 | - Navigate to plugin folder. 54 | - Run `git pull` 55 | - Run `rake redmine:plugins:migrate` 56 | - In computed CF's formulas replace `%{cf_id}` constructions by `cfs[cf_id]`. 57 | 58 | ### Compatibility 59 | 60 | The plugins supports the following Redmine versions: 4.0.x, 3.4.x, 3.3.x, 3.2.x, 3.1.x, 3.0.x, 2.6.x, 2.5.x. 61 | 62 | ### Examples: 63 | ```ruby 64 | cfs[1]*2+cfs[2] 65 | # means 66 | # custom_field_value(1) * 2 + custom_field_value(2) 67 | ``` 68 | 69 | ```ruby 70 | (cfs[1]/3.14).round(2) 71 | ``` 72 | 73 | ```ruby 74 | if cfs[1].zero? 75 | cfs[2]/2 76 | else 77 | cfs[3]/2 78 | end 79 | ``` 80 | 81 | ```ruby 82 | # For IssueCustomField 83 | (self.estimated_hours || 0) * 2 84 | ``` 85 | 86 | ```ruby 87 | # For ProjectCustomField 88 | self.parent_id == 2 89 | ``` 90 | 91 | ```ruby 92 | # If format of Custom Field is Link 93 | "/projects/#{self.project_id.to_s}/issues/new?issue[subject]=Review+request+[##{self.id.to_s} #{self.subject}]&issue[tracker_id]=3" 94 | ``` 95 | 96 | ```ruby 97 | # Retrieve a value from Key/value list custom field 98 | cfs[1].try(:id) 99 | ``` 100 | 101 | To write formulas this documentation can be helpful: 102 | - [Issue](http://www.rubydoc.info/github/edavis10/redmine/Issue) 103 | - [Project](http://www.rubydoc.info/github/edavis10/redmine/Project) 104 | - [User](http://www.rubydoc.info/github/edavis10/redmine/User) 105 | - [TimeEntry](http://www.rubydoc.info/github/edavis10/redmine/TimeEntry) 106 | - [Version](http://www.rubydoc.info/github/edavis10/redmine/Version) 107 | - [Group](http://www.rubydoc.info/github/edavis10/redmine/Group) 108 | - [Document](http://www.rubydoc.info/github/edavis10/redmine/Document) 109 | - [TimeEntryActivity, IssuePriority, DocumentCategory](http://www.rubydoc.info/github/edavis10/redmine/Enumeration) 110 | 111 | 112 | ### Getting help 113 | 114 | If you need help with a formula's code read [FAQ](https://github.com/annikoff/redmine_plugin_computed_custom_field/wiki/FAQ) 115 | and check out [existing issues](https://github.com/annikoff/redmine_plugin_computed_custom_field/issues?utf8=%E2%9C%93&q=is%3Aissue+label%3Aquestion+) 116 | or ask [Redmine community](https://www.redmine.org/projects/redmine/boards/2). 117 | 118 | Licensed under the [MIT-LICENSE](MIT-LICENSE) 119 | -------------------------------------------------------------------------------- /app/views/hooks/_view_custom_fields_form_upper_box.html.erb: -------------------------------------------------------------------------------- 1 | <% if custom_field.new_record? || custom_field.is_computed? %> 2 |
<%= form.check_box :is_computed, 3 | data: { enables: '#custom_field_formula, #available_cfs' }, 4 | disabled: !custom_field.new_record? %>
5 |<%= form.text_area :formula, rows: 7 %>
6 |7 | <%= label_tag l(:label_available_custom_fields) %> 8 | <%= render_computed_custom_fields_select custom_field %> 9 |
10 | 11 | 21 | <% end %> 22 | -------------------------------------------------------------------------------- /config/database.yml.travis: -------------------------------------------------------------------------------- 1 | test: 2 | adapter: sqlite3 3 | database: redmine 4 | -------------------------------------------------------------------------------- /config/locales/en.yml: -------------------------------------------------------------------------------- 1 | en: 2 | field_is_computed: Computed 3 | field_formula: Formula 4 | label_available_custom_fields: Available custom fields 5 | error_while_formula_computing: 'Error while formula computing in field "%{custom_field_name}": %{message}' 6 | -------------------------------------------------------------------------------- /config/locales/es.yml: -------------------------------------------------------------------------------- 1 | # Spanish translation by lublasco (https://github.com/lublasco) 2 | es: 3 | field_is_computed: Calculado 4 | field_formula: Fórmula 5 | label_available_custom_fields: Campos personalizados disponibles 6 | error_while_formula_computing: 'Error al aplicar la fórmula al campo "%{custom_field_name}": %{message}' 7 | -------------------------------------------------------------------------------- /config/locales/fr.yml: -------------------------------------------------------------------------------- 1 | # Translated by Atmis (https://github.com/Atmis) 2 | fr: 3 | field_is_computed: Calculé 4 | field_formula: Formule 5 | label_available_custom_fields: Champs personnalisés disponibles 6 | error_while_formula_computing: 'Erreur pendant le calcul de la formule du champ "%{custom_field_name}": %{message}' 7 | -------------------------------------------------------------------------------- /config/locales/pl.yml: -------------------------------------------------------------------------------- 1 | pl: 2 | field_is_computed: Obliczany 3 | field_formula: Formuła 4 | label_available_custom_fields: Dostępne pola niestandardowe 5 | error_while_formula_computing: 'Błąd podczas obliczania pola "%{custom_field_name}": %{message}' 6 | -------------------------------------------------------------------------------- /config/locales/pt-BR.yml: -------------------------------------------------------------------------------- 1 | # Translated by Adriano Ceccarelli (https://github.com/aceccarelli) 2 | pt-BR: 3 | field_is_computed: Calculado 4 | field_formula: Fórmula 5 | label_available_custom_fields: Campos customizados disponíveis 6 | error_while_formula_computing: 'Erro enquanto executa fórmula no campo "%{custom_field_name}": %{message}' 7 | -------------------------------------------------------------------------------- /config/locales/ru.yml: -------------------------------------------------------------------------------- 1 | ru: 2 | field_is_computed: Вычисляемое 3 | field_formula: Формула 4 | label_available_custom_fields: Доступные поля 5 | error_while_formula_computing: 'Ошибка вычисления по формуле в поле "%{custom_field_name}": %{message}' 6 | -------------------------------------------------------------------------------- /config/locales/zh.yml: -------------------------------------------------------------------------------- 1 | zh: 2 | field_is_computed: 动态计算变量 3 | field_formula: 公式 4 | label_available_custom_fields: 可用自定义字段 5 | error_while_formula_computing: 当公式使用字段:"%{custom_field_name}" 计算时报错。错误信息:%{message} 6 | -------------------------------------------------------------------------------- /db/migrate/20161229192026_add_custom_fields_formula.rb: -------------------------------------------------------------------------------- 1 | class AddCustomFieldsFormula < PLUGIN_MIGRATION_CLASS 2 | def up 3 | add_column :custom_fields, :formula, :text 4 | end 5 | 6 | def down 7 | remove_column :custom_fields, :formula 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /db/migrate/20161229192027_add_custom_fields_is_computed.rb: -------------------------------------------------------------------------------- 1 | class AddCustomFieldsIsComputed < PLUGIN_MIGRATION_CLASS 2 | def up 3 | add_column :custom_fields, :is_computed, :boolean, default: false 4 | end 5 | 6 | def down 7 | remove_column :custom_fields, :is_computed 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /db/migrate/20170205204732_convert_custom_fields.rb: -------------------------------------------------------------------------------- 1 | class ConvertCustomFields < PLUGIN_MIGRATION_CLASS 2 | def up 3 | fields = CustomField.where(field_format: 'computed') 4 | fields.each do |field| 5 | field.update_attribute(:formula, field.format_store[:formula]) 6 | format = case field.format_store[:output_format] 7 | when 'integer' 8 | 'int' 9 | when 'percentage' 10 | 'float' 11 | else 12 | field.format_store[:output_format] 13 | end 14 | sql = "UPDATE #{CustomField.table_name} SET " 15 | sql << "is_computed = '1', field_format = '#{format}' WHERE id = #{field.id}" 16 | ActiveRecord::Base.connection.execute(sql) 17 | end 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /init.rb: -------------------------------------------------------------------------------- 1 | Redmine::Plugin.register :computed_custom_field do 2 | name 'Computed custom field' 3 | author 'Yakov Annikov' 4 | url 'https://github.com/annikoff/redmine_plugin_computed_custom_field' 5 | description '' 6 | version '1.0.7' 7 | settings default: {} 8 | end 9 | 10 | $LOAD_PATH.unshift "#{File.dirname(__FILE__)}/lib" 11 | require 'computed_custom_field' 12 | #require 'computed_custom_field/custom_field_patch' 13 | require 'computed_custom_field/custom_fields_helper_patch' 14 | #require 'computed_custom_field/model_patch' 15 | #require 'computed_custom_field/issue_patch' 16 | require 'computed_custom_field/hooks' 17 | 18 | RedmineApp::Application.configure do 19 | config.after_initialize do 20 | ComputedCustomField.patch_models 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /lib/computed_custom_field.rb: -------------------------------------------------------------------------------- 1 | module ComputedCustomField 2 | def self.patch_models 3 | models = [ 4 | Enumeration, Group, Issue, Project, 5 | TimeEntry, User, Version 6 | ] 7 | models.each do |model| 8 | if model.included_modules 9 | .exclude?(ComputedCustomField::ModelPatch) 10 | model.send :include, ComputedCustomField::ModelPatch 11 | end 12 | end 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /lib/computed_custom_field/custom_field_patch.rb: -------------------------------------------------------------------------------- 1 | module ComputedCustomField 2 | module CustomFieldPatch 3 | extend ActiveSupport::Concern 4 | 5 | included do 6 | before_validation -> { self.formula ||= '' }, if: :is_computed? 7 | validates_with FormulaValidator, if: :is_computed? 8 | safe_attributes 'is_computed', 'formula' if CustomField.respond_to? 'safe_attributes' 9 | end 10 | 11 | def is_computed=(arg) 12 | # cannot change is_computed of a saved custom field 13 | super if new_record? 14 | end 15 | end 16 | end 17 | 18 | unless CustomField.included_modules 19 | .include?(ComputedCustomField::CustomFieldPatch) 20 | CustomField.send :include, ComputedCustomField::CustomFieldPatch 21 | end 22 | -------------------------------------------------------------------------------- /lib/computed_custom_field/custom_fields_helper_patch.rb: -------------------------------------------------------------------------------- 1 | module ComputedCustomField 2 | module CustomFieldsHelperPatch 3 | def render_computed_custom_fields_select(custom_field) 4 | options = render_options_for_computed_custom_fields_select(custom_field) 5 | select_tag '', options, size: 5, multiple: true, id: 'available_cfs' 6 | end 7 | 8 | def render_options_for_computed_custom_fields_select(custom_field) 9 | options = custom_fields_for_options(custom_field).map do |field| 10 | is_computed = field.is_computed? ? ", #{l(:field_is_computed)}" : '' 11 | format = I18n.t(field.format.label) 12 | title = "#{field.name} (#{format}#{is_computed})" 13 | content_tag(:option, title, value: field.id, title: title) 14 | end 15 | options.join.html_safe 16 | end 17 | 18 | def custom_fields_for_options(custom_field) 19 | CustomField.where(type: custom_field.type).where('custom_fields.id != ?', custom_field.id || 0) 20 | end 21 | end 22 | end 23 | 24 | unless CustomFieldsHelper.included_modules 25 | .include?(ComputedCustomField::CustomFieldsHelperPatch) 26 | CustomFieldsHelper.send :include, ComputedCustomField::CustomFieldsHelperPatch 27 | end 28 | -------------------------------------------------------------------------------- /lib/computed_custom_field/formula_validator.rb: -------------------------------------------------------------------------------- 1 | module ComputedCustomField 2 | # rubocop:disable Lint/UselessAssignment, Security/Eval 3 | class FormulaValidator < ActiveModel::Validator 4 | def validate(record) 5 | object = custom_field_instance(record) 6 | define_validate_record_method(object) 7 | object.validate_record record 8 | rescue Exception => e 9 | record.errors[:formula] << e.message 10 | end 11 | 12 | private 13 | 14 | def custom_field_instance(record) 15 | eval(record.type.sub('CustomField', '')).new 16 | end 17 | 18 | def grouped_custom_fields 19 | @grouped_custom_fields ||= CustomField.all.group_by(&:id) 20 | end 21 | 22 | def custom_field_ids(record) 23 | record.formula.scan(/cfs\[(\d+)\]/).flatten.map(&:to_i) 24 | end 25 | 26 | def define_validate_record_method(object) 27 | def object.validate_record(record) 28 | grouped_cfs = CustomField.all.group_by(&:id) 29 | cf_ids = record.formula.scan(/cfs\[(\d+)\]/).flatten.map(&:to_i) 30 | cfs = cf_ids.each_with_object({}) do |cf_id, hash| 31 | hash[cf_id] = grouped_cfs[cf_id].first.cast_value '1' 32 | end 33 | eval record.formula 34 | end 35 | end 36 | end 37 | # rubocop:enable Lint/UselessAssignment, Security/Eval 38 | end 39 | -------------------------------------------------------------------------------- /lib/computed_custom_field/hooks.rb: -------------------------------------------------------------------------------- 1 | module ComputedCustomField 2 | class Hooks < Redmine::Hook::ViewListener 3 | render_on :view_custom_fields_form_upper_box, 4 | partial: 'hooks/view_custom_fields_form_upper_box' 5 | end 6 | end 7 | -------------------------------------------------------------------------------- /lib/computed_custom_field/issue_patch.rb: -------------------------------------------------------------------------------- 1 | module ComputedCustomField 2 | module IssuePatch 3 | extend ActiveSupport::Concern 4 | 5 | included do 6 | alias_method :read_only_attribute_names_without_computed_cf_ids, :read_only_attribute_names 7 | alias_method :read_only_attribute_names, :read_only_attribute_names_with_computed_cf_ids 8 | end 9 | 10 | def read_only_attribute_names_with_computed_cf_ids(user = nil) 11 | cf_ids = CustomField.where(is_computed: true).pluck(:id).map(&:to_s) 12 | attributes = read_only_attribute_names_without_computed_cf_ids(user) 13 | (attributes + cf_ids).uniq 14 | end 15 | end 16 | end 17 | 18 | unless Issue.included_modules.include?(ComputedCustomField::IssuePatch) 19 | Issue.send :include, ComputedCustomField::IssuePatch 20 | end 21 | -------------------------------------------------------------------------------- /lib/computed_custom_field/model_patch.rb: -------------------------------------------------------------------------------- 1 | module ComputedCustomField 2 | module ModelPatch 3 | extend ActiveSupport::Concern 4 | 5 | included do 6 | before_validation :eval_computed_fields 7 | end 8 | 9 | private 10 | 11 | def eval_computed_fields 12 | custom_field_values.each do |value| 13 | next unless value.custom_field.is_computed? 14 | eval_computed_field value.custom_field 15 | end 16 | end 17 | 18 | # rubocop:disable Lint/UselessAssignment, Security/Eval 19 | def eval_computed_field(custom_field) 20 | cfs = parse_computed_field_formula custom_field.formula 21 | value = eval custom_field.formula 22 | self.custom_field_values = { 23 | custom_field.id => prepare_computed_value(custom_field, value) 24 | } 25 | rescue Exception => e 26 | errors.add :base, l(:error_while_formula_computing, 27 | custom_field_name: custom_field.name, 28 | message: e.message) 29 | end 30 | # rubocop:enable Lint/UselessAssignment, Security/Eval 31 | 32 | def parse_computed_field_formula(formula) 33 | @grouped_cfvs ||= custom_field_values 34 | .group_by { |cfv| cfv.custom_field.id } 35 | cf_ids = formula.scan(/cfs\[(\d+)\]/).flatten.map(&:to_i) 36 | cf_ids.each_with_object({}) do |cf_id, hash| 37 | cfv = @grouped_cfvs[cf_id].first 38 | hash[cf_id] = cfv ? cfv.custom_field.cast_value(cfv.value) : nil 39 | end 40 | end 41 | 42 | def prepare_computed_value(custom_field, value) 43 | return value.map { |v| prepare_computed_value(custom_field, v) } if value.is_a? Array 44 | 45 | result = case custom_field.field_format 46 | when 'bool' 47 | value.is_a?(TrueClass) ? '1' : '0' 48 | when 'int' 49 | value.to_i 50 | else 51 | value.respond_to?(:id) ? value.id : value 52 | end 53 | result.to_s 54 | end 55 | end 56 | end 57 | -------------------------------------------------------------------------------- /test/fixtures_helper.rb: -------------------------------------------------------------------------------- 1 | module FixturesHelper 2 | def self.fixtures 3 | [:custom_fields, :issues, :trackers, 4 | :projects, :custom_fields_trackers, 5 | :time_entries, :enumerations, :custom_values, 6 | :issue_statuses, :users] 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /test/gemfile_locks/2.5.3/Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | actionmailer (3.2.19) 5 | actionpack (= 3.2.19) 6 | mail (~> 2.5.4) 7 | actionpack (3.2.19) 8 | activemodel (= 3.2.19) 9 | activesupport (= 3.2.19) 10 | builder (~> 3.0.0) 11 | erubis (~> 2.7.0) 12 | journey (~> 1.0.4) 13 | rack (~> 1.4.5) 14 | rack-cache (~> 1.2) 15 | rack-test (~> 0.6.1) 16 | sprockets (~> 2.2.1) 17 | activemodel (3.2.19) 18 | activesupport (= 3.2.19) 19 | builder (~> 3.0.0) 20 | activerecord (3.2.19) 21 | activemodel (= 3.2.19) 22 | activesupport (= 3.2.19) 23 | arel (~> 3.0.2) 24 | tzinfo (~> 0.3.29) 25 | activeresource (3.2.19) 26 | activemodel (= 3.2.19) 27 | activesupport (= 3.2.19) 28 | activesupport (3.2.19) 29 | i18n (~> 0.6, >= 0.6.4) 30 | multi_json (~> 1.0) 31 | arel (3.0.3) 32 | awesome_nested_set (2.1.6) 33 | activerecord (>= 3.0.0) 34 | builder (3.0.0) 35 | capybara (2.1.0) 36 | mime-types (>= 1.16) 37 | nokogiri (>= 1.3.3) 38 | rack (>= 1.0.0) 39 | rack-test (>= 0.5.4) 40 | xpath (~> 2.0) 41 | childprocess (0.9.0) 42 | ffi (~> 1.0, >= 1.0.11) 43 | coderay (1.1.2) 44 | concurrent-ruby (1.1.4) 45 | erubis (2.7.0) 46 | fastercsv (1.5.5) 47 | ffi (1.10.0) 48 | hike (1.2.3) 49 | i18n (0.9.5) 50 | concurrent-ruby (~> 1.0) 51 | journey (1.0.4) 52 | jquery-rails (2.0.3) 53 | railties (>= 3.1.0, < 5.0) 54 | thor (~> 0.14) 55 | json (1.8.6) 56 | mail (2.5.5) 57 | mime-types (~> 1.16) 58 | treetop (~> 1.4.8) 59 | metaclass (0.0.4) 60 | mime-types (1.25.1) 61 | mini_portile2 (2.1.0) 62 | mocha (1.0.0) 63 | metaclass (~> 0.0.1) 64 | multi_json (1.13.1) 65 | net-ldap (0.3.1) 66 | nokogiri (1.6.8.1) 67 | mini_portile2 (~> 2.1.0) 68 | polyglot (0.3.5) 69 | rack (1.4.7) 70 | rack-cache (1.7.1) 71 | rack (>= 0.4) 72 | rack-openid (1.4.2) 73 | rack (>= 1.1.0) 74 | ruby-openid (>= 2.1.8) 75 | rack-ssl (1.3.4) 76 | rack 77 | rack-test (0.6.3) 78 | rack (>= 1.0) 79 | rails (3.2.19) 80 | actionmailer (= 3.2.19) 81 | actionpack (= 3.2.19) 82 | activerecord (= 3.2.19) 83 | activeresource (= 3.2.19) 84 | activesupport (= 3.2.19) 85 | bundler (~> 1.0) 86 | railties (= 3.2.19) 87 | railties (3.2.19) 88 | actionpack (= 3.2.19) 89 | activesupport (= 3.2.19) 90 | rack-ssl (~> 1.3.2) 91 | rake (>= 0.8.7) 92 | rdoc (~> 3.4) 93 | thor (>= 0.14.6, < 2.0) 94 | rake (10.1.1) 95 | rdoc (3.12.2) 96 | json (~> 1.4) 97 | redcarpet (2.3.0) 98 | rmagick (2.16.0) 99 | ruby-openid (2.3.0) 100 | rubyzip (1.2.2) 101 | selenium-webdriver (2.53.4) 102 | childprocess (~> 0.5) 103 | rubyzip (~> 1.0) 104 | websocket (~> 1.0) 105 | shoulda (3.3.2) 106 | shoulda-context (~> 1.0.1) 107 | shoulda-matchers (~> 1.4.1) 108 | shoulda-context (1.0.2) 109 | shoulda-matchers (1.4.1) 110 | activesupport (>= 3.0.0) 111 | sprockets (2.2.3) 112 | hike (~> 1.2) 113 | multi_json (~> 1.0) 114 | rack (~> 1.0) 115 | tilt (~> 1.1, != 1.3.0) 116 | sqlite3 (1.3.13) 117 | thor (0.20.3) 118 | tilt (1.4.1) 119 | treetop (1.4.15) 120 | polyglot 121 | polyglot (>= 0.3.1) 122 | tzinfo (0.3.55) 123 | websocket (1.2.4) 124 | xpath (2.1.0) 125 | nokogiri (~> 1.3) 126 | yard (0.9.16) 127 | 128 | PLATFORMS 129 | ruby 130 | 131 | DEPENDENCIES 132 | activerecord-jdbc-adapter (~> 1.3.2) 133 | activerecord-jdbcsqlite3-adapter 134 | awesome_nested_set (= 2.1.6) 135 | builder (= 3.0.0) 136 | capybara (~> 2.1.0) 137 | coderay (~> 1.1.0) 138 | fastercsv (~> 1.5.0) 139 | jquery-rails (~> 2.0.2) 140 | mime-types 141 | mocha (~> 1.0.0) 142 | net-ldap (~> 0.3.1) 143 | rack-openid 144 | rails (= 3.2.19) 145 | rake (~> 10.1.1) 146 | rdoc (>= 2.4.2) 147 | redcarpet (~> 2.3.0) 148 | rmagick (>= 2.0.0) 149 | ruby-openid (~> 2.3.0) 150 | selenium-webdriver (= 2.53.4) 151 | shoulda (~> 3.3.2) 152 | sqlite3 153 | yard 154 | 155 | BUNDLED WITH 156 | 1.17.3 157 | -------------------------------------------------------------------------------- /test/gemfile_locks/2.6.10/Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | actionmailer (3.2.22.2) 5 | actionpack (= 3.2.22.2) 6 | mail (~> 2.5.4) 7 | actionpack (3.2.22.2) 8 | activemodel (= 3.2.22.2) 9 | activesupport (= 3.2.22.2) 10 | builder (~> 3.0.0) 11 | erubis (~> 2.7.0) 12 | journey (~> 1.0.4) 13 | rack (~> 1.4.5) 14 | rack-cache (~> 1.2) 15 | rack-test (~> 0.6.1) 16 | sprockets (~> 2.2.1) 17 | activemodel (3.2.22.2) 18 | activesupport (= 3.2.22.2) 19 | builder (~> 3.0.0) 20 | activerecord (3.2.22.2) 21 | activemodel (= 3.2.22.2) 22 | activesupport (= 3.2.22.2) 23 | arel (~> 3.0.2) 24 | tzinfo (~> 0.3.29) 25 | activeresource (3.2.22.2) 26 | activemodel (= 3.2.22.2) 27 | activesupport (= 3.2.22.2) 28 | activesupport (3.2.22.2) 29 | i18n (~> 0.6, >= 0.6.4) 30 | multi_json (~> 1.0) 31 | addressable (2.5.2) 32 | public_suffix (>= 2.0.2, < 4.0) 33 | arel (3.0.3) 34 | builder (3.0.4) 35 | capybara (2.18.0) 36 | addressable 37 | mini_mime (>= 0.1.3) 38 | nokogiri (>= 1.3.3) 39 | rack (>= 1.0.0) 40 | rack-test (>= 0.5.4) 41 | xpath (>= 2.0, < 4.0) 42 | childprocess (0.9.0) 43 | ffi (~> 1.0, >= 1.0.11) 44 | coderay (1.1.2) 45 | erubis (2.7.0) 46 | fastercsv (1.5.5) 47 | ffi (1.10.0) 48 | hike (1.2.3) 49 | htmlentities (4.3.1) 50 | i18n (0.6.11) 51 | journey (1.0.4) 52 | jquery-rails (3.1.5) 53 | railties (>= 3.0, < 5.0) 54 | thor (>= 0.14, < 2.0) 55 | json (1.8.6) 56 | mail (2.5.5) 57 | mime-types (~> 1.16) 58 | treetop (~> 1.4.8) 59 | metaclass (0.0.4) 60 | mime-types (1.25.1) 61 | mini_mime (1.0.1) 62 | mini_portile2 (2.4.0) 63 | minitest (5.11.3) 64 | mocha (1.0.0) 65 | metaclass (~> 0.0.1) 66 | multi_json (1.13.1) 67 | net-ldap (0.3.1) 68 | nokogiri (1.9.1) 69 | mini_portile2 (~> 2.4.0) 70 | polyglot (0.3.5) 71 | power_assert (1.1.3) 72 | public_suffix (3.0.3) 73 | rack (1.4.7) 74 | rack-cache (1.8.0) 75 | rack (>= 0.4) 76 | rack-openid (1.4.2) 77 | rack (>= 1.1.0) 78 | ruby-openid (>= 2.1.8) 79 | rack-ssl (1.3.4) 80 | rack 81 | rack-test (0.6.3) 82 | rack (>= 1.0) 83 | rails (3.2.22.2) 84 | actionmailer (= 3.2.22.2) 85 | actionpack (= 3.2.22.2) 86 | activerecord (= 3.2.22.2) 87 | activeresource (= 3.2.22.2) 88 | activesupport (= 3.2.22.2) 89 | bundler (~> 1.0) 90 | railties (= 3.2.22.2) 91 | railties (3.2.22.2) 92 | actionpack (= 3.2.22.2) 93 | activesupport (= 3.2.22.2) 94 | rack-ssl (~> 1.3.2) 95 | rake (>= 0.8.7) 96 | rdoc (~> 3.4) 97 | thor (>= 0.14.6, < 2.0) 98 | rake (12.3.2) 99 | rbpdf (1.18.7) 100 | htmlentities (= 4.3.1) 101 | rdoc (3.12.2) 102 | json (~> 1.4) 103 | redcarpet (3.3.4) 104 | request_store (1.0.5) 105 | rmagick (2.13.4) 106 | ruby-openid (2.3.0) 107 | rubyzip (1.2.2) 108 | selenium-webdriver (3.141.0) 109 | childprocess (~> 0.5) 110 | rubyzip (~> 1.2, >= 1.2.2) 111 | shoulda (3.3.2) 112 | shoulda-context (~> 1.0.1) 113 | shoulda-matchers (~> 1.4.1) 114 | shoulda-context (1.0.2) 115 | shoulda-matchers (1.4.1) 116 | activesupport (>= 3.0.0) 117 | sprockets (2.2.3) 118 | hike (~> 1.2) 119 | multi_json (~> 1.0) 120 | rack (~> 1.0) 121 | tilt (~> 1.1, != 1.3.0) 122 | sqlite3 (1.3.13) 123 | test-unit (3.2.9) 124 | power_assert 125 | thor (0.20.3) 126 | tilt (1.4.1) 127 | treetop (1.4.15) 128 | polyglot 129 | polyglot (>= 0.3.1) 130 | tzinfo (0.3.55) 131 | xpath (2.1.0) 132 | nokogiri (~> 1.3) 133 | yard (0.9.16) 134 | 135 | PLATFORMS 136 | ruby 137 | 138 | DEPENDENCIES 139 | activerecord-jdbc-adapter (~> 1.3.2) 140 | activerecord-jdbcsqlite3-adapter 141 | builder (>= 3.0.4) 142 | capybara 143 | coderay (~> 1.1.0) 144 | fastercsv (~> 1.5.0) 145 | i18n (~> 0.6.11) 146 | jdbc-sqlite3 (>= 3.8.10.1) 147 | jquery-rails (~> 3.1.4) 148 | mime-types 149 | minitest 150 | mocha (~> 1.0.0) 151 | net-ldap (~> 0.3.1) 152 | nokogiri (>= 1.6.7.2) 153 | rack-openid 154 | rails (= 3.2.22.2) 155 | rbpdf (~> 1.18.7) 156 | rdoc (>= 2.4.2) 157 | redcarpet (~> 3.3.2) 158 | request_store (= 1.0.5) 159 | rmagick (~> 2.13.4) 160 | ruby-openid (~> 2.3.0) 161 | selenium-webdriver 162 | shoulda (~> 3.3.2) 163 | shoulda-matchers (= 1.4.1) 164 | sqlite3 165 | test-unit (~> 3.0) 166 | yard 167 | 168 | BUNDLED WITH 169 | 1.17.3 170 | -------------------------------------------------------------------------------- /test/gemfile_locks/3.0.7/Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | actionmailer (4.2.3) 5 | actionpack (= 4.2.3) 6 | actionview (= 4.2.3) 7 | activejob (= 4.2.3) 8 | mail (~> 2.5, >= 2.5.4) 9 | rails-dom-testing (~> 1.0, >= 1.0.5) 10 | actionpack (4.2.3) 11 | actionview (= 4.2.3) 12 | activesupport (= 4.2.3) 13 | rack (~> 1.6) 14 | rack-test (~> 0.6.2) 15 | rails-dom-testing (~> 1.0, >= 1.0.5) 16 | rails-html-sanitizer (~> 1.0, >= 1.0.2) 17 | actionpack-action_caching (1.2.0) 18 | actionpack (>= 4.0.0, < 6) 19 | actionpack-xml_parser (1.0.2) 20 | actionpack (>= 4.0.0, < 5) 21 | actionview (4.2.3) 22 | activesupport (= 4.2.3) 23 | builder (~> 3.1) 24 | erubis (~> 2.7.0) 25 | rails-dom-testing (~> 1.0, >= 1.0.5) 26 | rails-html-sanitizer (~> 1.0, >= 1.0.2) 27 | activejob (4.2.3) 28 | activesupport (= 4.2.3) 29 | globalid (>= 0.3.0) 30 | activemodel (4.2.3) 31 | activesupport (= 4.2.3) 32 | builder (~> 3.1) 33 | activerecord (4.2.3) 34 | activemodel (= 4.2.3) 35 | activesupport (= 4.2.3) 36 | arel (~> 6.0) 37 | activesupport (4.2.3) 38 | i18n (~> 0.7) 39 | json (~> 1.7, >= 1.7.7) 40 | minitest (~> 5.1) 41 | thread_safe (~> 0.3, >= 0.3.4) 42 | tzinfo (~> 1.1) 43 | addressable (2.5.2) 44 | public_suffix (>= 2.0.2, < 4.0) 45 | arel (6.0.4) 46 | builder (3.2.3) 47 | capybara (2.18.0) 48 | addressable 49 | mini_mime (>= 0.1.3) 50 | nokogiri (>= 1.3.3) 51 | rack (>= 1.0.0) 52 | rack-test (>= 0.5.4) 53 | xpath (>= 2.0, < 4.0) 54 | childprocess (0.9.0) 55 | ffi (~> 1.0, >= 1.0.11) 56 | coderay (1.1.2) 57 | concurrent-ruby (1.1.4) 58 | crass (1.0.4) 59 | docile (1.1.5) 60 | erubis (2.7.0) 61 | ffi (1.10.0) 62 | globalid (0.4.1) 63 | activesupport (>= 4.2.0) 64 | htmlentities (4.3.1) 65 | i18n (0.9.5) 66 | concurrent-ruby (~> 1.0) 67 | jquery-rails (3.1.5) 68 | railties (>= 3.0, < 5.0) 69 | thor (>= 0.14, < 2.0) 70 | json (1.8.6) 71 | loofah (2.2.3) 72 | crass (~> 1.0.2) 73 | nokogiri (>= 1.5.9) 74 | mail (2.7.1) 75 | mini_mime (>= 0.1.1) 76 | metaclass (0.0.4) 77 | mime-types (3.2.2) 78 | mime-types-data (~> 3.2015) 79 | mime-types-data (3.2018.0812) 80 | mini_mime (1.0.1) 81 | mini_portile2 (2.4.0) 82 | minitest (5.11.3) 83 | mocha (1.7.0) 84 | metaclass (~> 0.0.1) 85 | multi_json (1.13.1) 86 | net-ldap (0.3.1) 87 | nokogiri (1.9.1) 88 | mini_portile2 (~> 2.4.0) 89 | protected_attributes (1.1.4) 90 | activemodel (>= 4.0.1, < 5.0) 91 | public_suffix (3.0.3) 92 | rack (1.6.11) 93 | rack-openid (1.4.2) 94 | rack (>= 1.1.0) 95 | ruby-openid (>= 2.1.8) 96 | rack-test (0.6.3) 97 | rack (>= 1.0) 98 | rails (4.2.3) 99 | actionmailer (= 4.2.3) 100 | actionpack (= 4.2.3) 101 | actionview (= 4.2.3) 102 | activejob (= 4.2.3) 103 | activemodel (= 4.2.3) 104 | activerecord (= 4.2.3) 105 | activesupport (= 4.2.3) 106 | bundler (>= 1.3.0, < 2.0) 107 | railties (= 4.2.3) 108 | sprockets-rails 109 | rails-deprecated_sanitizer (1.0.3) 110 | activesupport (>= 4.2.0.alpha) 111 | rails-dom-testing (1.0.9) 112 | activesupport (>= 4.2.0, < 5.0) 113 | nokogiri (~> 1.6) 114 | rails-deprecated_sanitizer (>= 1.0.1) 115 | rails-html-sanitizer (1.0.4) 116 | loofah (~> 2.2, >= 2.2.2) 117 | railties (4.2.3) 118 | actionpack (= 4.2.3) 119 | activesupport (= 4.2.3) 120 | rake (>= 0.8.7) 121 | thor (>= 0.18.1, < 2.0) 122 | rake (12.3.2) 123 | rbpdf (1.18.7) 124 | htmlentities (= 4.3.1) 125 | rdoc (5.1.0) 126 | redcarpet (3.3.4) 127 | request_store (1.0.5) 128 | rmagick (2.13.4) 129 | ruby-openid (2.3.0) 130 | rubyzip (1.2.2) 131 | selenium-webdriver (3.141.0) 132 | childprocess (~> 0.5) 133 | rubyzip (~> 1.2, >= 1.2.2) 134 | simplecov (0.9.2) 135 | docile (~> 1.1.0) 136 | multi_json (~> 1.0) 137 | simplecov-html (~> 0.9.0) 138 | simplecov-html (0.9.0) 139 | sprockets (3.7.2) 140 | concurrent-ruby (~> 1.0) 141 | rack (> 1, < 3) 142 | sprockets-rails (3.2.1) 143 | actionpack (>= 4.0) 144 | activesupport (>= 4.0) 145 | sprockets (>= 3.0.0) 146 | sqlite3 (1.3.13) 147 | thor (0.20.3) 148 | thread_safe (0.3.6) 149 | tzinfo (1.2.5) 150 | thread_safe (~> 0.1) 151 | xpath (2.1.0) 152 | nokogiri (~> 1.3) 153 | yard (0.9.16) 154 | 155 | PLATFORMS 156 | ruby 157 | 158 | DEPENDENCIES 159 | actionpack-action_caching 160 | actionpack-xml_parser 161 | activerecord-jdbc-adapter (~> 1.3.2) 162 | activerecord-jdbcsqlite3-adapter 163 | builder (>= 3.0.4) 164 | capybara 165 | coderay (~> 1.1.0) 166 | jdbc-sqlite3 (>= 3.8.10.1) 167 | jquery-rails (~> 3.1.4) 168 | mime-types 169 | minitest 170 | mocha 171 | net-ldap (~> 0.3.1) 172 | protected_attributes 173 | rack-openid 174 | rails (= 4.2.3) 175 | rails-dom-testing 176 | rbpdf (~> 1.18.7) 177 | rdoc (>= 2.4.2) 178 | redcarpet (~> 3.3.2) 179 | request_store (= 1.0.5) 180 | rmagick (~> 2.13.4) 181 | ruby-openid (~> 2.3.0) 182 | selenium-webdriver 183 | simplecov (~> 0.9.1) 184 | sqlite3 185 | tzinfo-data 186 | yard 187 | 188 | BUNDLED WITH 189 | 1.17.3 190 | -------------------------------------------------------------------------------- /test/gemfile_locks/3.1.7/Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | actionmailer (4.2.7.1) 5 | actionpack (= 4.2.7.1) 6 | actionview (= 4.2.7.1) 7 | activejob (= 4.2.7.1) 8 | mail (~> 2.5, >= 2.5.4) 9 | rails-dom-testing (~> 1.0, >= 1.0.5) 10 | actionpack (4.2.7.1) 11 | actionview (= 4.2.7.1) 12 | activesupport (= 4.2.7.1) 13 | rack (~> 1.6) 14 | rack-test (~> 0.6.2) 15 | rails-dom-testing (~> 1.0, >= 1.0.5) 16 | rails-html-sanitizer (~> 1.0, >= 1.0.2) 17 | actionpack-action_caching (1.2.0) 18 | actionpack (>= 4.0.0, < 6) 19 | actionpack-xml_parser (1.0.2) 20 | actionpack (>= 4.0.0, < 5) 21 | actionview (4.2.7.1) 22 | activesupport (= 4.2.7.1) 23 | builder (~> 3.1) 24 | erubis (~> 2.7.0) 25 | rails-dom-testing (~> 1.0, >= 1.0.5) 26 | rails-html-sanitizer (~> 1.0, >= 1.0.2) 27 | activejob (4.2.7.1) 28 | activesupport (= 4.2.7.1) 29 | globalid (>= 0.3.0) 30 | activemodel (4.2.7.1) 31 | activesupport (= 4.2.7.1) 32 | builder (~> 3.1) 33 | activerecord (4.2.7.1) 34 | activemodel (= 4.2.7.1) 35 | activesupport (= 4.2.7.1) 36 | arel (~> 6.0) 37 | activesupport (4.2.7.1) 38 | i18n (~> 0.7) 39 | json (~> 1.7, >= 1.7.7) 40 | minitest (~> 5.1) 41 | thread_safe (~> 0.3, >= 0.3.4) 42 | tzinfo (~> 1.1) 43 | addressable (2.5.2) 44 | public_suffix (>= 2.0.2, < 4.0) 45 | arel (6.0.4) 46 | ast (2.4.0) 47 | builder (3.2.3) 48 | capybara (2.18.0) 49 | addressable 50 | mini_mime (>= 0.1.3) 51 | nokogiri (>= 1.3.3) 52 | rack (>= 1.0.0) 53 | rack-test (>= 0.5.4) 54 | xpath (>= 2.0, < 4.0) 55 | childprocess (0.9.0) 56 | ffi (~> 1.0, >= 1.0.11) 57 | coderay (1.1.2) 58 | concurrent-ruby (1.1.4) 59 | crass (1.0.4) 60 | docile (1.1.5) 61 | erubis (2.7.0) 62 | ffi (1.10.0) 63 | globalid (0.4.1) 64 | activesupport (>= 4.2.0) 65 | htmlentities (4.3.1) 66 | i18n (0.9.5) 67 | concurrent-ruby (~> 1.0) 68 | jaro_winkler (1.5.2) 69 | jquery-rails (3.1.5) 70 | railties (>= 3.0, < 5.0) 71 | thor (>= 0.14, < 2.0) 72 | json (1.8.6) 73 | loofah (2.2.3) 74 | crass (~> 1.0.2) 75 | nokogiri (>= 1.5.9) 76 | mail (2.7.1) 77 | mini_mime (>= 0.1.1) 78 | metaclass (0.0.4) 79 | mime-types (3.2.2) 80 | mime-types-data (~> 3.2015) 81 | mime-types-data (3.2018.0812) 82 | mimemagic (0.3.3) 83 | mini_mime (1.0.1) 84 | mini_portile2 (2.4.0) 85 | minitest (5.11.3) 86 | mocha (1.7.0) 87 | metaclass (~> 0.0.1) 88 | multi_json (1.13.1) 89 | net-ldap (0.3.1) 90 | nokogiri (1.9.1) 91 | mini_portile2 (~> 2.4.0) 92 | parallel (1.12.1) 93 | parser (2.5.3.0) 94 | ast (~> 2.4.0) 95 | pg (0.18.4) 96 | powerpack (0.1.2) 97 | protected_attributes (1.1.4) 98 | activemodel (>= 4.0.1, < 5.0) 99 | public_suffix (3.0.3) 100 | rack (1.6.11) 101 | rack-openid (1.4.2) 102 | rack (>= 1.1.0) 103 | ruby-openid (>= 2.1.8) 104 | rack-test (0.6.3) 105 | rack (>= 1.0) 106 | rails (4.2.7.1) 107 | actionmailer (= 4.2.7.1) 108 | actionpack (= 4.2.7.1) 109 | actionview (= 4.2.7.1) 110 | activejob (= 4.2.7.1) 111 | activemodel (= 4.2.7.1) 112 | activerecord (= 4.2.7.1) 113 | activesupport (= 4.2.7.1) 114 | bundler (>= 1.3.0, < 2.0) 115 | railties (= 4.2.7.1) 116 | sprockets-rails 117 | rails-deprecated_sanitizer (1.0.3) 118 | activesupport (>= 4.2.0.alpha) 119 | rails-dom-testing (1.0.9) 120 | activesupport (>= 4.2.0, < 5.0) 121 | nokogiri (~> 1.6) 122 | rails-deprecated_sanitizer (>= 1.0.1) 123 | rails-html-sanitizer (1.0.4) 124 | loofah (~> 2.2, >= 2.2.2) 125 | railties (4.2.7.1) 126 | actionpack (= 4.2.7.1) 127 | activesupport (= 4.2.7.1) 128 | rake (>= 0.8.7) 129 | thor (>= 0.18.1, < 2.0) 130 | rainbow (3.0.0) 131 | rake (12.3.2) 132 | rbpdf (1.18.7) 133 | htmlentities (= 4.3.1) 134 | rdoc (5.1.0) 135 | redcarpet (3.3.4) 136 | request_store (1.0.5) 137 | rmagick (2.16.0) 138 | rubocop (0.57.2) 139 | jaro_winkler (~> 1.5.1) 140 | parallel (~> 1.10) 141 | parser (>= 2.5) 142 | powerpack (~> 0.1) 143 | rainbow (>= 2.2.2, < 4.0) 144 | ruby-progressbar (~> 1.7) 145 | unicode-display_width (~> 1.0, >= 1.0.1) 146 | ruby-openid (2.3.0) 147 | ruby-progressbar (1.10.0) 148 | rubyzip (1.2.2) 149 | selenium-webdriver (3.141.0) 150 | childprocess (~> 0.5) 151 | rubyzip (~> 1.2, >= 1.2.2) 152 | simplecov (0.9.2) 153 | docile (~> 1.1.0) 154 | multi_json (~> 1.0) 155 | simplecov-html (~> 0.9.0) 156 | simplecov-html (0.9.0) 157 | sprockets (3.7.2) 158 | concurrent-ruby (~> 1.0) 159 | rack (> 1, < 3) 160 | sprockets-rails (3.2.1) 161 | actionpack (>= 4.0) 162 | activesupport (>= 4.0) 163 | sprockets (>= 3.0.0) 164 | thor (0.20.3) 165 | thread_safe (0.3.6) 166 | tzinfo (1.2.5) 167 | thread_safe (~> 0.1) 168 | unicode-display_width (1.4.1) 169 | xpath (2.1.0) 170 | nokogiri (~> 1.3) 171 | yard (0.9.16) 172 | 173 | PLATFORMS 174 | ruby 175 | 176 | DEPENDENCIES 177 | actionpack-action_caching 178 | actionpack-xml_parser 179 | activerecord-jdbc-adapter (~> 1.3.2) 180 | activerecord-jdbcpostgresql-adapter 181 | builder (>= 3.0.4) 182 | capybara 183 | coderay (~> 1.1.0) 184 | jquery-rails (~> 3.1.4) 185 | loofah (~> 2.0) 186 | mime-types (~> 3.0) 187 | mimemagic 188 | minitest 189 | mocha 190 | net-ldap (~> 0.3.1) 191 | nokogiri (>= 1.6.7.2) 192 | pg (~> 0.18.1) 193 | protected_attributes 194 | rack-openid 195 | rails (= 4.2.7.1) 196 | rails-dom-testing 197 | rails-html-sanitizer (>= 1.0.3) 198 | rbpdf (~> 1.18.7) 199 | rdoc (>= 2.4.2) 200 | redcarpet (~> 3.3.2) 201 | request_store (= 1.0.5) 202 | rmagick (>= 2.14.0) 203 | rubocop 204 | ruby-openid (~> 2.3.0) 205 | selenium-webdriver 206 | simplecov (~> 0.9.1) 207 | tzinfo-data 208 | yard 209 | 210 | BUNDLED WITH 211 | 1.17.3 212 | -------------------------------------------------------------------------------- /test/gemfile_locks/3.2.9/Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | actionmailer (4.2.7.1) 5 | actionpack (= 4.2.7.1) 6 | actionview (= 4.2.7.1) 7 | activejob (= 4.2.7.1) 8 | mail (~> 2.5, >= 2.5.4) 9 | rails-dom-testing (~> 1.0, >= 1.0.5) 10 | actionpack (4.2.7.1) 11 | actionview (= 4.2.7.1) 12 | activesupport (= 4.2.7.1) 13 | rack (~> 1.6) 14 | rack-test (~> 0.6.2) 15 | rails-dom-testing (~> 1.0, >= 1.0.5) 16 | rails-html-sanitizer (~> 1.0, >= 1.0.2) 17 | actionpack-action_caching (1.2.0) 18 | actionpack (>= 4.0.0, < 6) 19 | actionpack-xml_parser (1.0.2) 20 | actionpack (>= 4.0.0, < 5) 21 | actionview (4.2.7.1) 22 | activesupport (= 4.2.7.1) 23 | builder (~> 3.1) 24 | erubis (~> 2.7.0) 25 | rails-dom-testing (~> 1.0, >= 1.0.5) 26 | rails-html-sanitizer (~> 1.0, >= 1.0.2) 27 | activejob (4.2.7.1) 28 | activesupport (= 4.2.7.1) 29 | globalid (>= 0.3.0) 30 | activemodel (4.2.7.1) 31 | activesupport (= 4.2.7.1) 32 | builder (~> 3.1) 33 | activerecord (4.2.7.1) 34 | activemodel (= 4.2.7.1) 35 | activesupport (= 4.2.7.1) 36 | arel (~> 6.0) 37 | activesupport (4.2.7.1) 38 | i18n (~> 0.7) 39 | json (~> 1.7, >= 1.7.7) 40 | minitest (~> 5.1) 41 | thread_safe (~> 0.3, >= 0.3.4) 42 | tzinfo (~> 1.1) 43 | addressable (2.5.2) 44 | public_suffix (>= 2.0.2, < 4.0) 45 | arel (6.0.4) 46 | builder (3.2.3) 47 | capybara (2.18.0) 48 | addressable 49 | mini_mime (>= 0.1.3) 50 | nokogiri (>= 1.3.3) 51 | rack (>= 1.0.0) 52 | rack-test (>= 0.5.4) 53 | xpath (>= 2.0, < 4.0) 54 | childprocess (0.9.0) 55 | ffi (~> 1.0, >= 1.0.11) 56 | coderay (1.1.2) 57 | concurrent-ruby (1.1.4) 58 | crass (1.0.4) 59 | css_parser (1.6.0) 60 | addressable 61 | docile (1.1.5) 62 | erubis (2.7.0) 63 | ffi (1.10.0) 64 | globalid (0.4.1) 65 | activesupport (>= 4.2.0) 66 | htmlentities (4.3.4) 67 | i18n (0.7.0) 68 | jquery-rails (3.1.5) 69 | railties (>= 3.0, < 5.0) 70 | thor (>= 0.14, < 2.0) 71 | json (1.8.6) 72 | loofah (2.2.3) 73 | crass (~> 1.0.2) 74 | nokogiri (>= 1.5.9) 75 | mail (2.6.6) 76 | mime-types (>= 1.16, < 4) 77 | metaclass (0.0.4) 78 | mime-types (3.2.2) 79 | mime-types-data (~> 3.2015) 80 | mime-types-data (3.2018.0812) 81 | mimemagic (0.3.3) 82 | mini_mime (1.0.1) 83 | mini_portile2 (2.1.0) 84 | minitest (5.11.3) 85 | mocha (1.7.0) 86 | metaclass (~> 0.0.1) 87 | multi_json (1.13.1) 88 | net-ldap (0.12.1) 89 | nokogiri (1.7.2) 90 | mini_portile2 (~> 2.1.0) 91 | protected_attributes (1.1.4) 92 | activemodel (>= 4.0.1, < 5.0) 93 | public_suffix (3.0.3) 94 | rack (1.6.11) 95 | rack-openid (1.4.2) 96 | rack (>= 1.1.0) 97 | ruby-openid (>= 2.1.8) 98 | rack-test (0.6.3) 99 | rack (>= 1.0) 100 | rails (4.2.7.1) 101 | actionmailer (= 4.2.7.1) 102 | actionpack (= 4.2.7.1) 103 | actionview (= 4.2.7.1) 104 | activejob (= 4.2.7.1) 105 | activemodel (= 4.2.7.1) 106 | activerecord (= 4.2.7.1) 107 | activesupport (= 4.2.7.1) 108 | bundler (>= 1.3.0, < 2.0) 109 | railties (= 4.2.7.1) 110 | sprockets-rails 111 | rails-deprecated_sanitizer (1.0.3) 112 | activesupport (>= 4.2.0.alpha) 113 | rails-dom-testing (1.0.9) 114 | activesupport (>= 4.2.0, < 5.0) 115 | nokogiri (~> 1.6) 116 | rails-deprecated_sanitizer (>= 1.0.1) 117 | rails-html-sanitizer (1.0.4) 118 | loofah (~> 2.2, >= 2.2.2) 119 | railties (4.2.7.1) 120 | actionpack (= 4.2.7.1) 121 | activesupport (= 4.2.7.1) 122 | rake (>= 0.8.7) 123 | thor (>= 0.18.1, < 2.0) 124 | rake (12.3.2) 125 | rbpdf (1.19.6) 126 | htmlentities 127 | rbpdf-font (~> 1.19.0) 128 | rbpdf-font (1.19.1) 129 | rdoc (4.3.0) 130 | redcarpet (3.3.4) 131 | request_store (1.0.5) 132 | rmagick (2.16.0) 133 | roadie (3.2.2) 134 | css_parser (~> 1.4) 135 | nokogiri (~> 1.5) 136 | roadie-rails (1.1.1) 137 | railties (>= 3.0, < 5.1) 138 | roadie (~> 3.1) 139 | ruby-openid (2.3.0) 140 | rubyzip (1.2.2) 141 | selenium-webdriver (2.53.4) 142 | childprocess (~> 0.5) 143 | rubyzip (~> 1.0) 144 | websocket (~> 1.0) 145 | simplecov (0.9.2) 146 | docile (~> 1.1.0) 147 | multi_json (~> 1.0) 148 | simplecov-html (~> 0.9.0) 149 | simplecov-html (0.9.0) 150 | sprockets (3.7.2) 151 | concurrent-ruby (~> 1.0) 152 | rack (> 1, < 3) 153 | sprockets-rails (3.2.1) 154 | actionpack (>= 4.0) 155 | activesupport (>= 4.0) 156 | sprockets (>= 3.0.0) 157 | sqlite3 (1.3.13) 158 | thor (0.20.3) 159 | thread_safe (0.3.6) 160 | tzinfo (1.2.5) 161 | thread_safe (~> 0.1) 162 | websocket (1.2.8) 163 | xpath (2.1.0) 164 | nokogiri (~> 1.3) 165 | yard (0.9.16) 166 | 167 | PLATFORMS 168 | ruby 169 | 170 | DEPENDENCIES 171 | actionpack-action_caching 172 | actionpack-xml_parser 173 | activerecord-jdbc-adapter (~> 1.3.2) 174 | activerecord-jdbcsqlite3-adapter 175 | builder (>= 3.0.4) 176 | capybara 177 | coderay (~> 1.1.0) 178 | i18n (~> 0.7.0) 179 | jdbc-sqlite3 (>= 3.8.10.1) 180 | jquery-rails (~> 3.1.4) 181 | mail (~> 2.6.4) 182 | mime-types (~> 3.0) 183 | mimemagic 184 | minitest 185 | mocha 186 | net-ldap (~> 0.12.0) 187 | nokogiri (~> 1.7.2) 188 | protected_attributes 189 | rack-openid 190 | rails (= 4.2.7.1) 191 | rails-dom-testing 192 | rails-html-sanitizer (>= 1.0.3) 193 | rbpdf (~> 1.19.2) 194 | rdoc (~> 4.3) 195 | redcarpet (~> 3.3.2) 196 | request_store (= 1.0.5) 197 | rmagick (>= 2.14.0) 198 | roadie (~> 3.2.1) 199 | roadie-rails (~> 1.1.1) 200 | ruby-openid (~> 2.3.0) 201 | selenium-webdriver (~> 2.53.4) 202 | simplecov (~> 0.9.1) 203 | sqlite3 (~> 1.3.12) 204 | tzinfo-data 205 | yard 206 | 207 | BUNDLED WITH 208 | 1.17.3 209 | -------------------------------------------------------------------------------- /test/gemfile_locks/3.3.9/Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | actionmailer (4.2.11) 5 | actionpack (= 4.2.11) 6 | actionview (= 4.2.11) 7 | activejob (= 4.2.11) 8 | mail (~> 2.5, >= 2.5.4) 9 | rails-dom-testing (~> 1.0, >= 1.0.5) 10 | actionpack (4.2.11) 11 | actionview (= 4.2.11) 12 | activesupport (= 4.2.11) 13 | rack (~> 1.6) 14 | rack-test (~> 0.6.2) 15 | rails-dom-testing (~> 1.0, >= 1.0.5) 16 | rails-html-sanitizer (~> 1.0, >= 1.0.2) 17 | actionpack-action_caching (1.2.0) 18 | actionpack (>= 4.0.0, < 6) 19 | actionpack-xml_parser (1.0.2) 20 | actionpack (>= 4.0.0, < 5) 21 | actionview (4.2.11) 22 | activesupport (= 4.2.11) 23 | builder (~> 3.1) 24 | erubis (~> 2.7.0) 25 | rails-dom-testing (~> 1.0, >= 1.0.5) 26 | rails-html-sanitizer (~> 1.0, >= 1.0.3) 27 | activejob (4.2.11) 28 | activesupport (= 4.2.11) 29 | globalid (>= 0.3.0) 30 | activemodel (4.2.11) 31 | activesupport (= 4.2.11) 32 | builder (~> 3.1) 33 | activerecord (4.2.11) 34 | activemodel (= 4.2.11) 35 | activesupport (= 4.2.11) 36 | arel (~> 6.0) 37 | activesupport (4.2.11) 38 | i18n (~> 0.7) 39 | minitest (~> 5.1) 40 | thread_safe (~> 0.3, >= 0.3.4) 41 | tzinfo (~> 1.1) 42 | addressable (2.5.2) 43 | public_suffix (>= 2.0.2, < 4.0) 44 | arel (6.0.4) 45 | builder (3.2.3) 46 | capybara (2.18.0) 47 | addressable 48 | mini_mime (>= 0.1.3) 49 | nokogiri (>= 1.3.3) 50 | rack (>= 1.0.0) 51 | rack-test (>= 0.5.4) 52 | xpath (>= 2.0, < 4.0) 53 | childprocess (0.9.0) 54 | ffi (~> 1.0, >= 1.0.11) 55 | coderay (1.1.2) 56 | concurrent-ruby (1.1.4) 57 | crass (1.0.4) 58 | css_parser (1.6.0) 59 | addressable 60 | docile (1.1.5) 61 | erubis (2.7.0) 62 | ffi (1.10.0) 63 | globalid (0.4.1) 64 | activesupport (>= 4.2.0) 65 | htmlentities (4.3.4) 66 | i18n (0.7.0) 67 | jquery-rails (3.1.5) 68 | railties (>= 3.0, < 5.0) 69 | thor (>= 0.14, < 2.0) 70 | loofah (2.2.3) 71 | crass (~> 1.0.2) 72 | nokogiri (>= 1.5.9) 73 | mail (2.6.6) 74 | mime-types (>= 1.16, < 4) 75 | metaclass (0.0.4) 76 | mime-types (3.2.2) 77 | mime-types-data (~> 3.2015) 78 | mime-types-data (3.2018.0812) 79 | mimemagic (0.3.3) 80 | mini_mime (1.0.1) 81 | mini_portile2 (2.1.0) 82 | minitest (5.11.3) 83 | mocha (1.7.0) 84 | metaclass (~> 0.0.1) 85 | multi_json (1.13.1) 86 | net-ldap (0.12.1) 87 | nokogiri (1.7.2) 88 | mini_portile2 (~> 2.1.0) 89 | protected_attributes (1.1.4) 90 | activemodel (>= 4.0.1, < 5.0) 91 | public_suffix (3.0.3) 92 | rack (1.6.11) 93 | rack-openid (1.4.2) 94 | rack (>= 1.1.0) 95 | ruby-openid (>= 2.1.8) 96 | rack-test (0.6.3) 97 | rack (>= 1.0) 98 | rails (4.2.11) 99 | actionmailer (= 4.2.11) 100 | actionpack (= 4.2.11) 101 | actionview (= 4.2.11) 102 | activejob (= 4.2.11) 103 | activemodel (= 4.2.11) 104 | activerecord (= 4.2.11) 105 | activesupport (= 4.2.11) 106 | bundler (>= 1.3.0, < 2.0) 107 | railties (= 4.2.11) 108 | sprockets-rails 109 | rails-deprecated_sanitizer (1.0.3) 110 | activesupport (>= 4.2.0.alpha) 111 | rails-dom-testing (1.0.9) 112 | activesupport (>= 4.2.0, < 5.0) 113 | nokogiri (~> 1.6) 114 | rails-deprecated_sanitizer (>= 1.0.1) 115 | rails-html-sanitizer (1.0.4) 116 | loofah (~> 2.2, >= 2.2.2) 117 | railties (4.2.11) 118 | actionpack (= 4.2.11) 119 | activesupport (= 4.2.11) 120 | rake (>= 0.8.7) 121 | thor (>= 0.18.1, < 2.0) 122 | rake (12.3.2) 123 | rbpdf (1.19.6) 124 | htmlentities 125 | rbpdf-font (~> 1.19.0) 126 | rbpdf-font (1.19.1) 127 | rdoc (4.3.0) 128 | redcarpet (3.3.4) 129 | request_store (1.0.5) 130 | rmagick (2.16.0) 131 | roadie (3.2.2) 132 | css_parser (~> 1.4) 133 | nokogiri (~> 1.5) 134 | roadie-rails (1.1.1) 135 | railties (>= 3.0, < 5.1) 136 | roadie (~> 3.1) 137 | ruby-openid (2.3.0) 138 | rubyzip (1.2.2) 139 | selenium-webdriver (2.53.4) 140 | childprocess (~> 0.5) 141 | rubyzip (~> 1.0) 142 | websocket (~> 1.0) 143 | simplecov (0.9.2) 144 | docile (~> 1.1.0) 145 | multi_json (~> 1.0) 146 | simplecov-html (~> 0.9.0) 147 | simplecov-html (0.9.0) 148 | sprockets (3.7.2) 149 | concurrent-ruby (~> 1.0) 150 | rack (> 1, < 3) 151 | sprockets-rails (3.2.1) 152 | actionpack (>= 4.0) 153 | activesupport (>= 4.0) 154 | sprockets (>= 3.0.0) 155 | sqlite3 (1.3.13) 156 | thor (0.20.3) 157 | thread_safe (0.3.6) 158 | tzinfo (1.2.5) 159 | thread_safe (~> 0.1) 160 | websocket (1.2.8) 161 | xpath (2.1.0) 162 | nokogiri (~> 1.3) 163 | yard (0.9.16) 164 | 165 | PLATFORMS 166 | ruby 167 | 168 | DEPENDENCIES 169 | actionpack-action_caching 170 | actionpack-xml_parser 171 | activerecord-jdbc-adapter (~> 1.3.2) 172 | activerecord-jdbcsqlite3-adapter 173 | builder (>= 3.0.4) 174 | capybara 175 | coderay (~> 1.1.1) 176 | i18n (~> 0.7.0) 177 | jdbc-sqlite3 (>= 3.8.10.1) 178 | jquery-rails (~> 3.1.4) 179 | mail (~> 2.6.4) 180 | mime-types (~> 3.0) 181 | mimemagic 182 | minitest 183 | mocha 184 | net-ldap (~> 0.12.0) 185 | nokogiri (~> 1.7.2) 186 | protected_attributes 187 | rack-openid 188 | rails (= 4.2.11) 189 | rails-dom-testing 190 | rails-html-sanitizer (>= 1.0.3) 191 | rbpdf (~> 1.19.6) 192 | rdoc (~> 4.3) 193 | redcarpet (~> 3.3.2) 194 | request_store (= 1.0.5) 195 | rmagick (>= 2.14.0) 196 | roadie (~> 3.2.1) 197 | roadie-rails (~> 1.1.1) 198 | ruby-openid (~> 2.3.0) 199 | selenium-webdriver (~> 2.53.4) 200 | simplecov (~> 0.9.1) 201 | sqlite3 (~> 1.3.12) 202 | tzinfo-data 203 | yard 204 | 205 | BUNDLED WITH 206 | 1.17.3 207 | -------------------------------------------------------------------------------- /test/gemfile_locks/3.4.7/Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | actionmailer (4.2.11) 5 | actionpack (= 4.2.11) 6 | actionview (= 4.2.11) 7 | activejob (= 4.2.11) 8 | mail (~> 2.5, >= 2.5.4) 9 | rails-dom-testing (~> 1.0, >= 1.0.5) 10 | actionpack (4.2.11) 11 | actionview (= 4.2.11) 12 | activesupport (= 4.2.11) 13 | rack (~> 1.6) 14 | rack-test (~> 0.6.2) 15 | rails-dom-testing (~> 1.0, >= 1.0.5) 16 | rails-html-sanitizer (~> 1.0, >= 1.0.2) 17 | actionpack-xml_parser (1.0.2) 18 | actionpack (>= 4.0.0, < 5) 19 | actionview (4.2.11) 20 | activesupport (= 4.2.11) 21 | builder (~> 3.1) 22 | erubis (~> 2.7.0) 23 | rails-dom-testing (~> 1.0, >= 1.0.5) 24 | rails-html-sanitizer (~> 1.0, >= 1.0.3) 25 | activejob (4.2.11) 26 | activesupport (= 4.2.11) 27 | globalid (>= 0.3.0) 28 | activemodel (4.2.11) 29 | activesupport (= 4.2.11) 30 | builder (~> 3.1) 31 | activerecord (4.2.11) 32 | activemodel (= 4.2.11) 33 | activesupport (= 4.2.11) 34 | arel (~> 6.0) 35 | activesupport (4.2.11) 36 | i18n (~> 0.7) 37 | minitest (~> 5.1) 38 | thread_safe (~> 0.3, >= 0.3.4) 39 | tzinfo (~> 1.1) 40 | addressable (2.5.2) 41 | public_suffix (>= 2.0.2, < 4.0) 42 | arel (6.0.4) 43 | builder (3.2.3) 44 | capybara (2.18.0) 45 | addressable 46 | mini_mime (>= 0.1.3) 47 | nokogiri (>= 1.3.3) 48 | rack (>= 1.0.0) 49 | rack-test (>= 0.5.4) 50 | xpath (>= 2.0, < 4.0) 51 | childprocess (0.9.0) 52 | ffi (~> 1.0, >= 1.0.11) 53 | coderay (1.1.2) 54 | concurrent-ruby (1.1.4) 55 | crass (1.0.4) 56 | css_parser (1.6.0) 57 | addressable 58 | docile (1.1.5) 59 | erubis (2.7.0) 60 | ffi (1.10.0) 61 | globalid (0.4.1) 62 | activesupport (>= 4.2.0) 63 | htmlentities (4.3.4) 64 | i18n (0.7.0) 65 | jquery-rails (3.1.5) 66 | railties (>= 3.0, < 5.0) 67 | thor (>= 0.14, < 2.0) 68 | loofah (2.2.3) 69 | crass (~> 1.0.2) 70 | nokogiri (>= 1.5.9) 71 | mail (2.6.6) 72 | mime-types (>= 1.16, < 4) 73 | metaclass (0.0.4) 74 | mime-types (3.2.2) 75 | mime-types-data (~> 3.2015) 76 | mime-types-data (3.2018.0812) 77 | mimemagic (0.3.3) 78 | mini_mime (1.0.1) 79 | mini_portile2 (2.3.0) 80 | minitest (5.11.3) 81 | mocha (1.7.0) 82 | metaclass (~> 0.0.1) 83 | multi_json (1.13.1) 84 | net-ldap (0.12.1) 85 | nokogiri (1.8.5) 86 | mini_portile2 (~> 2.3.0) 87 | protected_attributes (1.1.4) 88 | activemodel (>= 4.0.1, < 5.0) 89 | public_suffix (3.0.3) 90 | rack (1.6.11) 91 | rack-openid (1.4.2) 92 | rack (>= 1.1.0) 93 | ruby-openid (>= 2.1.8) 94 | rack-test (0.6.3) 95 | rack (>= 1.0) 96 | rails (4.2.11) 97 | actionmailer (= 4.2.11) 98 | actionpack (= 4.2.11) 99 | actionview (= 4.2.11) 100 | activejob (= 4.2.11) 101 | activemodel (= 4.2.11) 102 | activerecord (= 4.2.11) 103 | activesupport (= 4.2.11) 104 | bundler (>= 1.3.0, < 2.0) 105 | railties (= 4.2.11) 106 | sprockets-rails 107 | rails-deprecated_sanitizer (1.0.3) 108 | activesupport (>= 4.2.0.alpha) 109 | rails-dom-testing (1.0.9) 110 | activesupport (>= 4.2.0, < 5.0) 111 | nokogiri (~> 1.6) 112 | rails-deprecated_sanitizer (>= 1.0.1) 113 | rails-html-sanitizer (1.0.4) 114 | loofah (~> 2.2, >= 2.2.2) 115 | railties (4.2.11) 116 | actionpack (= 4.2.11) 117 | activesupport (= 4.2.11) 118 | rake (>= 0.8.7) 119 | thor (>= 0.18.1, < 2.0) 120 | rake (12.3.2) 121 | rbpdf (1.19.6) 122 | htmlentities 123 | rbpdf-font (~> 1.19.0) 124 | rbpdf-font (1.19.1) 125 | rdoc (4.3.0) 126 | redcarpet (3.4.0) 127 | request_store (1.0.5) 128 | rmagick (2.16.0) 129 | roadie (3.2.2) 130 | css_parser (~> 1.4) 131 | nokogiri (~> 1.5) 132 | roadie-rails (1.1.1) 133 | railties (>= 3.0, < 5.1) 134 | roadie (~> 3.1) 135 | ruby-openid (2.3.0) 136 | rubyzip (1.2.2) 137 | selenium-webdriver (2.53.4) 138 | childprocess (~> 0.5) 139 | rubyzip (~> 1.0) 140 | websocket (~> 1.0) 141 | simplecov (0.9.2) 142 | docile (~> 1.1.0) 143 | multi_json (~> 1.0) 144 | simplecov-html (~> 0.9.0) 145 | simplecov-html (0.9.0) 146 | sprockets (3.7.2) 147 | concurrent-ruby (~> 1.0) 148 | rack (> 1, < 3) 149 | sprockets-rails (3.2.1) 150 | actionpack (>= 4.0) 151 | activesupport (>= 4.0) 152 | sprockets (>= 3.0.0) 153 | sqlite3 (1.3.13) 154 | test_after_commit (0.4.2) 155 | activerecord (>= 3.2) 156 | thor (0.20.3) 157 | thread_safe (0.3.6) 158 | tzinfo (1.2.5) 159 | thread_safe (~> 0.1) 160 | websocket (1.2.8) 161 | xpath (2.1.0) 162 | nokogiri (~> 1.3) 163 | yard (0.9.16) 164 | 165 | PLATFORMS 166 | ruby 167 | 168 | DEPENDENCIES 169 | actionpack-xml_parser 170 | capybara (~> 2.13) 171 | coderay (~> 1.1.1) 172 | i18n (~> 0.7.0) 173 | jquery-rails (~> 3.1.4) 174 | mail (~> 2.6.4) 175 | mime-types (~> 3.0) 176 | mimemagic 177 | minitest 178 | mocha 179 | net-ldap (~> 0.12.0) 180 | nokogiri (~> 1.8.1) 181 | protected_attributes 182 | rack-openid 183 | rails (= 4.2.11) 184 | rails-dom-testing 185 | rails-html-sanitizer (>= 1.0.3) 186 | rbpdf (~> 1.19.6) 187 | rdoc (~> 4.3) 188 | redcarpet (~> 3.4.0) 189 | request_store (= 1.0.5) 190 | rmagick (>= 2.14.0) 191 | roadie (~> 3.2.1) 192 | roadie-rails (~> 1.1.1) 193 | ruby-openid (~> 2.3.0) 194 | selenium-webdriver (~> 2.53.4) 195 | simplecov (~> 0.9.1) 196 | sqlite3 (~> 1.3.12) 197 | test_after_commit (~> 0.4.2) 198 | tzinfo-data 199 | yard 200 | 201 | BUNDLED WITH 202 | 1.17.3 203 | -------------------------------------------------------------------------------- /test/gemfile_locks/4.0.0/Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | actioncable (5.2.2) 5 | actionpack (= 5.2.2) 6 | nio4r (~> 2.0) 7 | websocket-driver (>= 0.6.1) 8 | actionmailer (5.2.2) 9 | actionpack (= 5.2.2) 10 | actionview (= 5.2.2) 11 | activejob (= 5.2.2) 12 | mail (~> 2.5, >= 2.5.4) 13 | rails-dom-testing (~> 2.0) 14 | actionpack (5.2.2) 15 | actionview (= 5.2.2) 16 | activesupport (= 5.2.2) 17 | rack (~> 2.0) 18 | rack-test (>= 0.6.3) 19 | rails-dom-testing (~> 2.0) 20 | rails-html-sanitizer (~> 1.0, >= 1.0.2) 21 | actionpack-xml_parser (2.0.1) 22 | actionpack (>= 5.0) 23 | railties (>= 5.0) 24 | actionview (5.2.2) 25 | activesupport (= 5.2.2) 26 | builder (~> 3.1) 27 | erubi (~> 1.4) 28 | rails-dom-testing (~> 2.0) 29 | rails-html-sanitizer (~> 1.0, >= 1.0.3) 30 | activejob (5.2.2) 31 | activesupport (= 5.2.2) 32 | globalid (>= 0.3.6) 33 | activemodel (5.2.2) 34 | activesupport (= 5.2.2) 35 | activerecord (5.2.2) 36 | activemodel (= 5.2.2) 37 | activesupport (= 5.2.2) 38 | arel (>= 9.0) 39 | activestorage (5.2.2) 40 | actionpack (= 5.2.2) 41 | activerecord (= 5.2.2) 42 | marcel (~> 0.3.1) 43 | activesupport (5.2.2) 44 | concurrent-ruby (~> 1.0, >= 1.0.2) 45 | i18n (>= 0.7, < 2) 46 | minitest (~> 5.1) 47 | tzinfo (~> 1.1) 48 | addressable (2.5.2) 49 | public_suffix (>= 2.0.2, < 4.0) 50 | arel (9.0.0) 51 | builder (3.2.3) 52 | capybara (2.18.0) 53 | addressable 54 | mini_mime (>= 0.1.3) 55 | nokogiri (>= 1.3.3) 56 | rack (>= 1.0.0) 57 | rack-test (>= 0.5.4) 58 | xpath (>= 2.0, < 4.0) 59 | childprocess (0.9.0) 60 | ffi (~> 1.0, >= 1.0.11) 61 | concurrent-ruby (1.1.4) 62 | crass (1.0.4) 63 | css_parser (1.6.0) 64 | addressable 65 | docile (1.1.5) 66 | erubi (1.8.0) 67 | ffi (1.10.0) 68 | globalid (0.4.1) 69 | activesupport (>= 4.2.0) 70 | htmlentities (4.3.4) 71 | i18n (0.7.0) 72 | json (2.1.0) 73 | loofah (2.2.3) 74 | crass (~> 1.0.2) 75 | nokogiri (>= 1.5.9) 76 | mail (2.7.1) 77 | mini_mime (>= 0.1.1) 78 | marcel (0.3.3) 79 | mimemagic (~> 0.3.2) 80 | metaclass (0.0.4) 81 | method_source (0.9.2) 82 | mimemagic (0.3.3) 83 | mini_mime (1.0.1) 84 | mini_portile2 (2.3.0) 85 | minitest (5.11.3) 86 | mocha (1.7.0) 87 | metaclass (~> 0.0.1) 88 | net-ldap (0.16.1) 89 | nio4r (2.3.1) 90 | nokogiri (1.8.5) 91 | mini_portile2 (~> 2.3.0) 92 | public_suffix (3.0.3) 93 | puma (3.12.0) 94 | rack (2.0.6) 95 | rack-openid (1.4.2) 96 | rack (>= 1.1.0) 97 | ruby-openid (>= 2.1.8) 98 | rack-test (1.1.0) 99 | rack (>= 1.0, < 3) 100 | rails (5.2.2) 101 | actioncable (= 5.2.2) 102 | actionmailer (= 5.2.2) 103 | actionpack (= 5.2.2) 104 | actionview (= 5.2.2) 105 | activejob (= 5.2.2) 106 | activemodel (= 5.2.2) 107 | activerecord (= 5.2.2) 108 | activestorage (= 5.2.2) 109 | activesupport (= 5.2.2) 110 | bundler (>= 1.3.0) 111 | railties (= 5.2.2) 112 | sprockets-rails (>= 2.0.0) 113 | rails-dom-testing (2.0.3) 114 | activesupport (>= 4.2.0) 115 | nokogiri (>= 1.6) 116 | rails-html-sanitizer (1.0.4) 117 | loofah (~> 2.2, >= 2.2.2) 118 | railties (5.2.2) 119 | actionpack (= 5.2.2) 120 | activesupport (= 5.2.2) 121 | method_source 122 | rake (>= 0.8.7) 123 | thor (>= 0.19.0, < 2.0) 124 | rake (12.3.2) 125 | rbpdf (1.19.6) 126 | htmlentities 127 | rbpdf-font (~> 1.19.0) 128 | rbpdf-font (1.19.1) 129 | rdoc (6.1.1) 130 | redcarpet (3.4.0) 131 | request_store (1.0.5) 132 | rmagick (2.16.0) 133 | roadie (3.4.0) 134 | css_parser (~> 1.4) 135 | nokogiri (~> 1.5) 136 | roadie-rails (1.3.0) 137 | railties (>= 3.0, < 5.3) 138 | roadie (~> 3.1) 139 | rouge (3.3.0) 140 | ruby-openid (2.3.0) 141 | rubyzip (1.2.2) 142 | selenium-webdriver (3.141.0) 143 | childprocess (~> 0.5) 144 | rubyzip (~> 1.2, >= 1.2.2) 145 | simplecov (0.14.1) 146 | docile (~> 1.1.0) 147 | json (>= 1.8, < 3) 148 | simplecov-html (~> 0.10.0) 149 | simplecov-html (0.10.2) 150 | sprockets (3.7.2) 151 | concurrent-ruby (~> 1.0) 152 | rack (> 1, < 3) 153 | sprockets-rails (3.2.1) 154 | actionpack (>= 4.0) 155 | activesupport (>= 4.0) 156 | sprockets (>= 3.0.0) 157 | sqlite3 (1.3.13) 158 | thor (0.20.3) 159 | thread_safe (0.3.6) 160 | tzinfo (1.2.5) 161 | thread_safe (~> 0.1) 162 | websocket-driver (0.7.0) 163 | websocket-extensions (>= 0.1.0) 164 | websocket-extensions (0.1.3) 165 | xpath (3.1.0) 166 | nokogiri (~> 1.8) 167 | yard (0.9.16) 168 | 169 | PLATFORMS 170 | ruby 171 | 172 | DEPENDENCIES 173 | actionpack-xml_parser 174 | capybara (~> 2.13) 175 | i18n (~> 0.7.0) 176 | mail (~> 2.7.1) 177 | mimemagic 178 | mini_mime (~> 1.0.1) 179 | mocha 180 | net-ldap (~> 0.16.0) 181 | nokogiri (~> 1.8.0) 182 | puma (~> 3.7) 183 | rack-openid 184 | rails (= 5.2.2) 185 | rails-dom-testing 186 | rbpdf (~> 1.19.6) 187 | rdoc 188 | redcarpet (~> 3.4.0) 189 | request_store (= 1.0.5) 190 | rmagick (>= 2.14.0) 191 | roadie-rails (~> 1.3.0) 192 | rouge (~> 3.3.0) 193 | ruby-openid (~> 2.3.0) 194 | selenium-webdriver 195 | simplecov (~> 0.14.1) 196 | sqlite3 (~> 1.3.12) 197 | tzinfo-data 198 | yard 199 | 200 | BUNDLED WITH 201 | 1.17.3 202 | -------------------------------------------------------------------------------- /test/methods_helper.rb: -------------------------------------------------------------------------------- 1 | module MethodsHelper 2 | def issue 3 | Issue.find 3 4 | end 5 | 6 | def project 7 | Project.find 1 8 | end 9 | 10 | def field_with_string_format 11 | computed_field 'string' 12 | end 13 | 14 | def field_with_list_format 15 | computed_field 'list', possible_values: %w[Stable Beta Alpha] 16 | end 17 | 18 | def field_with_float_format 19 | computed_field 'float' 20 | end 21 | 22 | def field_with_int_format 23 | computed_field 'int' 24 | end 25 | 26 | def field_with_bool_format 27 | computed_field 'bool' 28 | end 29 | 30 | def field_with_date_format 31 | computed_field 'date' 32 | end 33 | 34 | def field_with_user_format 35 | computed_field 'user' 36 | end 37 | 38 | def field_with_link_format 39 | computed_field 'link' 40 | end 41 | 42 | def computed_field(format, attributes = {}) 43 | params = attributes.merge(name: format, is_computed: true, 44 | field_format: format, is_for_all: true) 45 | field = IssueCustomField.create params 46 | field.trackers << Tracker.first if field.is_a? IssueCustomField 47 | field 48 | end 49 | end 50 | -------------------------------------------------------------------------------- /test/test_helper.rb: -------------------------------------------------------------------------------- 1 | require File.expand_path(File.dirname(__FILE__) + '/../../../test/test_helper') 2 | require File.expand_path('../fixtures_helper', __FILE__) 3 | require File.expand_path('../methods_helper', __FILE__) 4 | 5 | class ComputedCustomFieldTestCase < ActiveSupport::TestCase 6 | fixtures FixturesHelper.fixtures 7 | include MethodsHelper 8 | end 9 | 10 | UI_TEST_CASE_CLASS = if Rails::VERSION::MAJOR >= 5 11 | require File.expand_path(File.dirname(__FILE__) + '/../../../test/application_system_test_case') 12 | ApplicationSystemTestCase 13 | else 14 | require File.expand_path(File.dirname(__FILE__) + '/../../../test/ui/base') 15 | Redmine::UiTest::Base 16 | end 17 | -------------------------------------------------------------------------------- /test/ui/computed_custom_field_test.rb: -------------------------------------------------------------------------------- 1 | require File.expand_path('../../test_helper', __FILE__) 2 | 3 | class ComputedCustomFieldTest < UI_TEST_CASE_CLASS 4 | fixtures FixturesHelper.fixtures 5 | 6 | def setup 7 | log_user 'admin', 'admin' 8 | end 9 | 10 | def test_new_custom_field_page_should_have_additional_fields 11 | visit new_custom_field_path type: 'IssueCustomField' 12 | 13 | assert page.has_css?('input#custom_field_is_computed') 14 | assert page.has_css?('textarea#custom_field_formula') 15 | assert page.has_css?('select#available_cfs') 16 | end 17 | 18 | def test_disabled_fields 19 | visit new_custom_field_path type: 'IssueCustomField' 20 | 21 | assert formula_element.disabled? 22 | assert available_cfs_element.disabled? 23 | end 24 | 25 | def test_fields_enabling 26 | visit new_custom_field_path type: 'IssueCustomField' 27 | 28 | is_computed_element.click 29 | refute formula_element.disabled? 30 | refute available_cfs_element.disabled? 31 | 32 | is_computed_element.click 33 | assert formula_element.disabled? 34 | assert available_cfs_element.disabled? 35 | end 36 | 37 | def test_common_custom_field_has_no_computed_fields 38 | visit edit_custom_field_path id: 1 39 | 40 | assert page.has_no_css?('#custom_field_is_computed') 41 | assert page.has_no_css?('#custom_field_formula') 42 | assert page.has_no_css?('#available_cfs') 43 | end 44 | 45 | def test_create_computed_custom_field 46 | formula = '"text"' 47 | visit new_custom_field_path type: 'IssueCustomField' 48 | page.fill_in('Name', with: 'Computed') 49 | is_computed_element.click 50 | page.fill_in('Formula', with: formula) 51 | click_button 'Save' 52 | assert page.has_text?('Successful creation') 53 | 54 | visit edit_custom_field_path(CustomField.last) 55 | assert_equal formula, formula_element.value 56 | assert is_computed_element.disabled? 57 | refute formula_element.disabled? 58 | refute available_cfs_element.disabled? 59 | end 60 | 61 | def test_available_cfs 62 | visit new_custom_field_path type: 'IssueCustomField' 63 | 64 | is_computed_element.click 65 | if Redmine::VERSION.to_s > '2.6' 66 | available_cfs_element.double_click 67 | assert_equal 'cfs[6]', formula_element.value 68 | end 69 | assert_equal IssueCustomField.all.size, page.all('#available_cfs option').size 70 | end 71 | 72 | private 73 | 74 | def is_computed_element 75 | page.first('#custom_field_is_computed') 76 | end 77 | 78 | def formula_element 79 | page.first('#custom_field_formula') 80 | end 81 | 82 | def available_cfs_element 83 | page.first('#available_cfs') 84 | end 85 | end 86 | -------------------------------------------------------------------------------- /test/ui/issue_test.rb: -------------------------------------------------------------------------------- 1 | require File.expand_path('../../test_helper', __FILE__) 2 | 3 | class ComputedCustomFieldTest < UI_TEST_CASE_CLASS 4 | fixtures FixturesHelper.fixtures 5 | include MethodsHelper 6 | 7 | def setup 8 | log_user 'admin', 'admin' 9 | end 10 | 11 | def test_computed_cfs_should_be_readonly 12 | field = field_with_string_format 13 | visit new_issue_path project: project 14 | assert page.has_no_css?("issue_custom_field_values_#{field.id}") 15 | 16 | visit issue_path issue 17 | assert page.has_no_css?("issue_custom_field_values_#{field.id}") 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /test/unit/computed_custom_field_test.rb: -------------------------------------------------------------------------------- 1 | require File.expand_path('../../test_helper', __FILE__) 2 | 3 | class ComputedCustomFieldTest < ComputedCustomFieldTestCase 4 | def test_patch_models 5 | models = [Enumeration, Group, Issue, Project, TimeEntry, User, Version] 6 | models.each do |model| 7 | assert model.included_modules.include?(ComputedCustomField::ModelPatch) 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /test/unit/custom_field_test.rb: -------------------------------------------------------------------------------- 1 | require File.expand_path('../../test_helper', __FILE__) 2 | 3 | class CustomFieldTest < ComputedCustomFieldTestCase 4 | def test_valid_formulas 5 | field = field_with_string_format 6 | field.formula = 'cfs[1] == "MySQL" ? "This is MySQL" : ""' 7 | assert field.valid? 8 | 9 | field.formula = 'custom_field_value(1).present?' 10 | assert field.valid? 11 | field.formula = 'cfs[6].round(2)' 12 | assert field.valid? 13 | end 14 | 15 | def test_invalid_formula 16 | field = field_with_float_format 17 | field.formula = '1/0' 18 | exception = assert_raise ActiveRecord::RecordInvalid do 19 | field.save! 20 | end 21 | assert_match(/divided by 0/, exception.message) 22 | end 23 | 24 | def test_computed_custom_field_callbacks 25 | field = CustomField.find(1).dup 26 | field.name = 'Test field' 27 | 28 | assert_nil field.formula 29 | refute field.is_computed? 30 | field.is_computed = true 31 | 32 | assert field.save 33 | assert field.is_computed? 34 | assert_equal '', field.formula 35 | 36 | assert field.update_attributes(is_computed: false, editable: true, formula: nil) 37 | 38 | assert field.is_computed? 39 | assert_equal '', field.formula 40 | end 41 | end 42 | -------------------------------------------------------------------------------- /test/unit/model_patch_test.rb: -------------------------------------------------------------------------------- 1 | require File.expand_path('../../test_helper', __FILE__) 2 | 3 | class ModelPatchTest < ComputedCustomFieldTestCase 4 | def test_invalid_computation 5 | field = field_with_string_format 6 | field.update_attribute(:formula, '1/0') 7 | exception = assert_raise ActiveRecord::RecordInvalid do 8 | issue.save! 9 | end 10 | message = 'Validation failed: Error while formula computing in field ' \ 11 | "\"#{field.name}\": divided by 0" 12 | assert_equal message, exception.message 13 | end 14 | 15 | def test_bool_computation 16 | field = field_with_bool_format 17 | field.update_attributes(formula: '1 == 1') 18 | issue.save 19 | assert_equal '1', issue.custom_field_value(field.id) 20 | 21 | field.update_attributes(formula: '1 == 0') 22 | issue.save 23 | assert_equal '0', issue.custom_field_value(field.id) 24 | end 25 | 26 | def test_string_computation 27 | field = field_with_string_format 28 | field.update_attribute(:formula, 'cfs[1]') 29 | issue.save 30 | assert_equal 'MySQL', issue.custom_field_value(field.id) 31 | end 32 | 33 | def test_list_computation 34 | field = field_with_list_format 35 | formula = '"Stable" if id == 3' 36 | field.update_attribute(:formula, formula) 37 | issue.save 38 | assert_equal 'Stable', issue.custom_field_value(field.id) 39 | end 40 | 41 | def test_multiple_list_computation 42 | field = field_with_list_format 43 | formula = "['Stable', 'Beta'] if id == #{issue.id}" 44 | field.update_attributes(formula: formula, multiple: true) 45 | issue.save! 46 | assert_equal %w[Beta Stable], issue.custom_field_value(field.id).sort 47 | end 48 | 49 | def test_float_computation 50 | field = field_with_float_format 51 | field.update_attribute(:formula, 'id/2.0') 52 | issue.save 53 | assert_equal '1.5', issue.custom_field_value(field.id) 54 | end 55 | 56 | def test_int_computation 57 | field = field_with_int_format 58 | field.update_attribute(:formula, 'id/2.0') 59 | issue.save 60 | assert_equal '1', issue.custom_field_value(field.id) 61 | end 62 | 63 | def test_date_computation 64 | field = field_with_date_format 65 | field.update_attribute(:formula, 'Date.new(2017, 1, 18)') 66 | issue.save 67 | assert_equal '2017-01-18', issue.custom_field_value(field.id) 68 | end 69 | 70 | def test_user_computation 71 | field = field_with_user_format 72 | field.update_attribute(:formula, 'assigned_to') 73 | issue.save 74 | assert_equal '3', issue.custom_field_value(field.id) 75 | end 76 | 77 | def test_multiple_user_computation 78 | field = field_with_user_format 79 | field.update_attributes(formula: '[assigned_to, author_id]', multiple: true) 80 | issue.save 81 | assert_equal %w[2 3], issue.custom_field_value(field.id).sort 82 | end 83 | 84 | def test_link_computation 85 | return if Redmine::VERSION.to_s < '2.5' 86 | field = field_with_link_format 87 | field.update_attribute(:formula, '"http://example.com/"') 88 | issue.save 89 | assert_equal 'http://example.com/', issue.custom_field_value(field.id) 90 | end 91 | end 92 | --------------------------------------------------------------------------------