# GET /speech_balloon_templates
# GET /speech_balloon_templates.json
def index
- @speech_balloon_templates = SpeechBalloon.all
+ @speech_balloon_templates = SpeechBalloonTemplate.all
respond_to do |format|
format.html # index.html.erb
# GET /speech_balloon_templates/1
# GET /speech_balloon_templates/1.json
def show
- @speech_balloon_template = SpeechBalloon.find(params[:id], include: {:balloon_templates => :speech_templates})
+ @speech_balloon_template = SpeechBalloonTemplate.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.json {
- render :json => @speech_balloon_template.to_json(include: {
- :balloon_templates => {:include => :speech_templates}
- })
+ render :json => @speech_balloon_template.to_json()
}
format.jsonp {
- render :json => "callback(" + @speech_balloon_template.to_json(include: {
- :balloon_templates => {:include => :speech_templates}
- }) + ")"
+ render :json => "callback(" + @speech_balloon_template.to_json() + ")"
}
end
end
def list
- @speech_balloon_templates = SpeechBalloon.all
+ @speech_balloon_templates = SpeechBalloonTemplate.all
respond_to do |format|
format.html { render layout: 'system' }
end
def browse
- @speech_balloon_template = SpeechBalloon.find(params[:id])
+ @speech_balloon_template = SpeechBalloonTemplate.find(params[:id])
respond_to do |format|
format.html { render layout: 'system' }
# POST /speech_balloon_templates
# POST /speech_balloon_templates.json
def create
- @speech_balloon_template = SpeechBalloon.new(params[:speech_balloon_template])
+ @speech_balloon_template = SpeechBalloonTemplate.new(params[:speech_balloon_template])
if em = validate_param(params[:speech_balloon_template])
respond_to do |format|
format.json { render json: em, status: :unprocessable_entity }
# DELETE /speech_balloon_templates/1
# DELETE /speech_balloon_templates/1.json
def destroy
- @speech_balloon_template = SpeechBalloon.find(params[:id])
+ @speech_balloon_template = SpeechBalloonTemplate.find(params[:id])
@speech_balloon_template.destroy
respond_to do |format|
- format.html { redirect_to speech_balloon_templates_url }
+ format.html { redirect_to :action => :list }
format.json { head :ok }
end
end
before_destroy :destroy_with_file
- def validate
- errors.add(:filesize, 'size over(1MB)') if self.filesize > 1000000
- end
-
def supply_default art
self.license_id = art.default_license_id if self.license_id.blank?
end
class SpeechBalloonTemplate < ActiveRecord::Base
- has_many :balloon_templates, :dependent => :destroy
- has_many :speech_templates, :dependent => :destroy
- accepts_nested_attributes_for :balloon_templates
- accepts_nested_attributes_for :speech_templates
+ has_many :speech_balloons
+
+ validates :name, :presence => true, :uniqueness => true, :length => {:maximum => 50}
+ validates :classname, :presence => true, :length => {:maximum => 50}
+ validates :caption, :presence => true, :length => {:maximum => 30}
+ validates :t, :presence => true, :numericality => {:greater_than_or_equal_to => 0}
+ validates :settings, :presence => true
+
before_create :supply_t
def supply_t
- self.t = SpeechBalloon.maximum(:t).to_i + 1
+ m = SpeechBalloonTemplate.maximum(:t)
+ t = m.blank? ? -1 : m.to_i
+ self.t = t + 1
+ end
+
+ def pic_rehash hash
+ res = true
+ hash["templates"].each do |n, v|
+ d = (v["balloon"] || {})["system_picture"]
+ next nil if d.blank?
+ sp = SystemPicture.store Base64.decode64(d.to_s)
+ unless sp
+ res = false
+ break
+ end
+ v["balloon"]["system_picture_id"] = sp.id
+ v["balloon"].delete "system_picture"
+ end
+ res
+ end
+
+ def store hash
+ res = nil
+ SpeechBalloonTemplate.transaction do
+ res = pic_rehash hash
+ if res
+ data = {:classname => hash["classname"], :caption => hash["caption"], :settings => hash.to_s}
+ self.attributes = data
+ res = self.save
+ end
+ raise ActiveRecord::Rollback unless res
+ end
+ res
+ end
+
+ def self.store name, hash
+ st = SpeechBalloonTemplate.find_by_name name
+ st = SpeechBalloonTemplate.new(:name => name) unless st
+ st.store hash
+ st
+ end
+
+ def self.parse(data)
+ res = data
+ begin
+ res = JSON.parse(data) if data.is_a?(String)
+ rescue
+ return false
+ end
+ res
+ end
+
+ def self.import(data)
+ d = SpeechBalloonTemplate.parse(data)
+ return false unless d
+ res = []
+ SpeechBalloonTemplate.transaction do
+ d.each do |name, hash|
+ st = SpeechBalloonTemplate.store name, hash
+ res.push(st) unless st.valid?
+ end
+ raise ActiveRecord::Rollback unless res.empty?
+ end
+ res
+ end
+
+ def self.import_file(filename)
+ t = nil
+ begin
+ t = File.open(filename, 'r').read
+ rescue
+ return false
+ end
+ SpeechBalloonTemplate.import t
end
end
has_many :balloons
has_many :balloon_templates
- before_destroy :destroy_with_file
+ validates :ext, :presence => true, :length => {:maximum => 4}, :inclusion => {:in => ['png', 'jpeg', 'gif']}
+ validates :width, :presence => true, :numericality => true, :natural_number => true
+ validates :height, :presence => true, :numericality => true, :natural_number => true
+ validates :filesize, :presence => true, :numericality => {:greater_than => 0, :less_than_or_equal_to => 2000000}, :natural_number => true
+ validates :md5, :presence => true, :length => {:maximum => 32}
- def validate
- errors.add(:filesize, 'size over(1MB)') if self.filesize > 1000000
- end
+ before_destroy :destroy_with_file
def destroy_with_file
PictureIO.system_picture_io.delete self.filename
'/system_pictures/' + filename
end
- def store(rimg)
- bindata = rimg.to_blob
- PictureIO.system_picture_io.put bindata, self.filename
- true
+ def data_to_mgk picture_data
+ begin
+ mgk = Magick::Image.from_blob(picture_data).shift
+ rescue
+ self.errors.add :base, 'magick failed'
+ return false
+ end
+ mgk
+ end
+
+ def store(picture_data)
+ mgk = data_to_mgk picture_data
+ return false unless mgk
+ res = false
+ self.attributes = {:ext => mgk.format.downcase, :width => mgk.columns, :height => mgk.rows,
+ :filesize => mgk.filesize
+ }
+ self.md5 = Digest::MD5.hexdigest(picture_data) unless self.md5
+ SystemPicture.transaction do
+ if res = self.save
+ res = PictureIO.system_picture_io.put(picture_data, self.filename)
+ end
+ end
+ res
+ end
+
+ def self.store(picture_data)
+ md5 = Digest::MD5.hexdigest(picture_data)
+ sp = SystemPicture.find_by_md5(md5)
+ sp = SystemPicture.new() unless sp
+ res = sp.store picture_data
+ res ? sp : nil
end
def restore(subdir = nil)
<p>
<b>Name:</b>
- <%= h @speech_balloon.name %>
+ <%= h @speech_balloon_template.name %>
</p>
<p>
- <b>Tail count:</b>
- <%= @speech_balloon.tail_count %>
+ <b>classname:</b>
+ <%= h @speech_balloon_template.classname %>
</p>
<p>
- <b>size count:</b>
- <%= @speech_balloon.size_count %>
+ <b>caption:</b>
+ <%= h @speech_balloon_template.caption %>
</p>
<p>
<b>t:</b>
- <%= @speech_balloon.t %>
+ <%= @speech_balloon_template.t %>
</p>
-<% @speech_balloon.balloon_templates.each do |balloon_template| -%>\r
- <div>\r
- <p>\r
- Tail:<%= balloon_template.tail -%>\r
- Size:<%= balloon_template.size -%>\r
- </p>\r
- <img src="<%= balloon_template.system_picture.url -%>" />\r
- </div>\r
-<% end -%>\r
+
+<p>
+ <b>settings:</b>
+ <%= h @speech_balloon_template.settings %>
+</p>
+
<%= link_to 'Back', :action => :list %>
-<h1>Listing speech_balloons</h1>
+<h1>Listing speech_balloon_templates</h1>
<table>
<tr>
<th>id</th>
<th>Name</th>
- <th>Tail count</th>
- <th>size count</th>
+ <th>classname</th>
+ <th>caption</th>
<th>t</th>
<th>created_at</th>
<th>updated_at</th>
<th></th>
</tr>
-<% @speech_balloons.each do |speech_balloon| %>
+<% @speech_balloon_templates.each do |speech_balloon_template| %>
<tr>
- <td><%= link_to speech_balloon.id, :action => :browse, :id => speech_balloon.id %></td>
- <td><%= h speech_balloon.name %></td>
- <td><%= speech_balloon.tail_count %></td>
- <td><%= speech_balloon.size_count %></td>
- <td><%= speech_balloon.t %></td>
- <td><%= speech_balloon.created_at %></td>
- <td><%= speech_balloon.updated_at %></td>
+ <td><%= link_to speech_balloon_template.id, :action => :browse, :id => speech_balloon_template.id %></td>
+ <td><%= h speech_balloon_template.name %></td>
+ <td><%= h speech_balloon_template.classname %></td>
+ <td><%= h speech_balloon_template.caption %></td>
+ <td><%= speech_balloon_template.t %></td>
+ <td><%= speech_balloon_template.created_at %></td>
+ <td><%= speech_balloon_template.updated_at %></td>
<td>
- <%= link_to 'Destroy', speech_balloon, confirm: 'Are you sure?', method: :delete %>
+ <%= link_to 'Destroy', speech_balloon_template, confirm: 'Are you sure?', method: :delete %>
</td>
</tr>
<% end %>
<p>
<b>Name:</b>
- <%= h @speech_balloon.name %>
+ <%= h @speech_balloon_template.name %>
</p>
<p>
- <b>Tail count:</b>
- <%= @speech_balloon.tail_count %>
+ <b>classname:</b>
+ <%= h @speech_balloon_template.classname %>
</p>
<p>
- <b>size count:</b>
- <%= @speech_balloon.size_count %>
+ <b>caption:</b>
+ <%= h @speech_balloon_template.caption %>
</p>
<p>
<b>t:</b>
- <%= @speech_balloon.t %>
+ <%= @speech_balloon_template.t %>
</p>
-<% @speech_balloon.balloon_templates.each do |balloon_template| -%>\r
- <div>\r
- <p>\r
- Tail:<%= balloon_template.tail -%>\r
- Size:<%= balloon_template.size -%>\r
- </p>\r
- <img src="<%= balloon_template.system_picture.url -%>" />\r
- </div>\r
-<% end -%>\r
-<%= link_to 'Back', speech_balloons_path %>
+
+<p>
+ <b>settings:</b>
+ <%= h @speech_balloon_template.settings %>
+</p>
+
+<%= link_to 'Back', speech_balloon_templates_path %>
</tr>
<tr>
<td>
+ <%= link_to 'speech_balloons', :controller => 'speech_balloons', :action => :list %>
+ </td>
+ </tr>
+ <tr>
+ <td>
<%= link_to 'balloons', :controller => 'balloons', :action => :list %>
</td>
</tr>
<table>
<tr>
<td>
- <%= link_to 'speech_balloons', :controller => 'speech_balloons', :action => :list %>
- </td>
- </tr>
- <tr>
- <td>
- <%= link_to 'balloon_templates', :controller => 'balloon_templates', :action => :list %>
- </td>
- </tr>
- <tr>
- <td>
- <%= link_to 'speech_templates', :controller => 'speech_templates', :action => :list %>
+ <%= link_to 'speech_balloon_templates', :controller => 'speech_balloon_templates', :action => :list %>
</td>
</tr>
</table>
require "active_resource/railtie"
require "sprockets/railtie"
# require "rails/test_unit/railtie"
+require 'digest/md5'
if defined?(Bundler)
# If you precompile assets before deploying to production, use this line
# Version of your assets, change this if you want to expire all your assets
config.assets.version = '1.0'
- config.autoload_paths += %W(#{config.root}/lib/validators)\r
+ config.autoload_paths += %W(#{config.root}/lib/validators)
end
end
module ActiveRecord
class Forbidden < ActiveRecordError
- end\r
+ end
end
-\r
+
t.integer :width, :null => false
t.integer :height, :null => false
t.integer :filesize, :null => false
+ t.string :md5, :null => false, :limit => 32
t.timestamps
end
class CreateSpeechBalloonTemplates < ActiveRecord::Migration
def change
create_table :speech_balloon_templates do |t|
+ t.string :name, :null => false, :limit => 50
+ t.string :classname, :null => false, :limit => 50
+ t.string :caption, :null => false, :limit => 30
+ t.integer :t, :null => false, :default => 0
+ t.string :settings, :null => false
t.timestamps
end
+ add_index :speech_balloon_templates, [:name], :unique => true, :name => 'speech_balloon_templates_name'
+ add_index :speech_balloon_templates, [:t], :unique => true, :name => 'speech_balloon_templates_t'
end
end
end\r
\r
create_table "speech_balloon_templates", :force => true do |t|\r
+ t.string "name", :limit => 50, :null => false\r
+ t.string "classname", :limit => 50, :null => false\r
+ t.string "caption", :limit => 30, :null => false\r
+ t.integer "t", :default => 0, :null => false\r
+ t.string "settings", :null => false\r
t.datetime "created_at"\r
t.datetime "updated_at"\r
end\r
\r
+ add_index "speech_balloon_templates", ["name"], :name => "speech_balloon_templates_name", :unique => true\r
+ add_index "speech_balloon_templates", ["t"], :name => "speech_balloon_templates_t", :unique => true\r
+\r
create_table "speech_balloons", :force => true do |t|\r
t.string "name", :null => false\r
t.integer "tail_count", :default => 1, :null => false\r
add_index "speeches", ["balloon_id"], :name => "index_speeches_on_balloon_id"\r
\r
create_table "system_pictures", :force => true do |t|\r
- t.string "ext", :null => false\r
- t.integer "width", :null => false\r
- t.integer "height", :null => false\r
- t.integer "filesize", :null => false\r
+ t.string "ext", :null => false\r
+ t.integer "width", :null => false\r
+ t.integer "height", :null => false\r
+ t.integer "filesize", :null => false\r
+ t.string "md5", :limit => 32, :null => false\r
t.datetime "created_at"\r
t.datetime "updated_at"\r
end\r
sp.ext 'png'
sp.width 222
sp.height 111
- sp.fileseze 100000
+ sp.filesize 100000
+ sp.md5 '098f6bcd4621d373cade4e832627b4f6'
end
+Factory.define :speech_balloon_template, :class => SpeechBalloonTemplate do |sbt|
+ sbt.name 'Plain@pettanr.com'
+ sbt.classname 'Plain'
+ sbt.caption 'normal fuki'
+ sbt.t 0
+ sbt.settings '{}'
+end
Factory.define :balloon, :class => Balloon do |balloon|
balloon.panel_id 1
balloon.balloon_template_id 1
--- /dev/null
+{\r
+ "square@pettan.com": {\r
+ "classname": "Square",\r
+ "caption": "\92·\95û\8c`",\r
+ "default_width": 150,\r
+ "default_height": 150,\r
+ "templates": {\r
+ "all": {\r
+ "balloon": {\r
+ "system_picture": "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"\r
+ },\r
+ "speech": {\r
+ "x_rate": 1,\r
+ "y_rate": 1,\r
+ "width_rate": 98,\r
+ "height_rate": 98\r
+ }\r
+ }\r
+ }\r
+ },\r
+ "square@pettan.com": {\r
+ "classname": "Square",\r
+ "caption": "\92·\95û\8c`",\r
+ "default_width": 150,\r
+ "default_height": 150,\r
+ "templates": {\r
+ "all": {\r
+ "balloon": {\r
+ "system_picture": "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"\r
+ },\r
+ "speech": {\r
+ "x_rate": 1,\r
+ "y_rate": 1,\r
+ "width_rate": 98,\r
+ "height_rate": 98\r
+ }\r
+ }\r
+ }\r
+ },\r
+ "square@pettan.com": {\r
+ "classname": "Square",\r
+ "caption": "\92·\95û\8c`",\r
+ "default_width": 150,\r
+ "default_height": 150,\r
+ "templates": {\r
+ "all": {\r
+ "balloon": {\r
+ "system_picture": "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"\r
+ },\r
+ "speech": {\r
+ "x_rate": 1,\r
+ "y_rate": 1,\r
+ "width_rate": 98,\r
+ "height_rate": 98\r
+ }\r
+ }\r
+ }\r
+ }\r
+}\r
--- /dev/null
+{\r
+ "square@pettan.com": {\r
+ "classname": "Square",\r
+ "caption": "長方形",\r
+ "default_width": 150,\r
+ "default_height": 150,\r
+ "templates": {\r
+ "all": {\r
+ "balloon": {\r
+ "system_picture": "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"\r
+ },\r
+ "speech": {\r
+ "x_rate": 1,\r
+ "y_rate": 1,\r
+ "width_rate": 98,\r
+ "height_rate": 98\r
+ }\r
+ }\r
+ }\r
+ }\r
+}\r
--- /dev/null
+{\r
+ "square@pettan.com": {\r
+ "classname": "Square",\r
+ "caption": "\92·\95û\8c`",\r
+ "default_width": 150,\r
+ "default_height": 150,\r
+ "templates": {\r
+ "all": {\r
+ "balloon": {\r
+ "system_picture": "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"\r
+ },\r
+ "speech": {\r
+ "x_rate": 1,\r
+ "y_rate": 1,\r
+ "width_rate": 98,\r
+ "height_rate": 98\r
+ }\r
+ }\r
+ }\r
+ },\r
+ "square with size@pettan.com": {\r
+ "classname": "SquareWithSize",\r
+ "caption": "\92·\95û\8c`\89ü",\r
+ "default_width": 150,\r
+ "default_height": 100,\r
+ "size_count": 3,\r
+ "width_offset": 0,\r
+ "height_offset": 0,\r
+ "width_step": 100,\r
+ "height_step": 100,\r
+ "templates": {\r
+ "small": {\r
+ "balloon": {\r
+ "size": 0,\r
+ "system_picture": "R0lGODlhZABkAPcAAAAAAAAAMwAAZgAAmQAAzAAA/wArAAArMwArZgArmQArzAAr/wBVAABVMwBVZgBVmQBVzABV/wCAAACAMwCAZgCAmQCAzACA/wCqAACqMwCqZgCqmQCqzACq/wDVAADVMwDVZgDVmQDVzADV/wD/AAD/MwD/ZgD/mQD/zAD//zMAADMAMzMAZjMAmTMAzDMA/zMrADMrMzMrZjMrmTMrzDMr/zNVADNVMzNVZjNVmTNVzDNV/zOAADOAMzOAZjOAmTOAzDOA/zOqADOqMzOqZjOqmTOqzDOq/zPVADPVMzPVZjPVmTPVzDPV/zP/ADP/MzP/ZjP/mTP/zDP//2YAAGYAM2YAZmYAmWYAzGYA/2YrAGYrM2YrZmYrmWYrzGYr/2ZVAGZVM2ZVZmZVmWZVzGZV/2aAAGaAM2aAZmaAmWaAzGaA/2aqAGaqM2aqZmaqmWaqzGaq/2bVAGbVM2bVZmbVmWbVzGbV/2b/AGb/M2b/Zmb/mWb/zGb//5kAAJkAM5kAZpkAmZkAzJkA/5krAJkrM5krZpkrmZkrzJkr/5lVAJlVM5lVZplVmZlVzJlV/5mAAJmAM5mAZpmAmZmAzJmA/5mqAJmqM5mqZpmqmZmqzJmq/5nVAJnVM5nVZpnVmZnVzJnV/5n/AJn/M5n/Zpn/mZn/zJn//8wAAMwAM8wAZswAmcwAzMwA/8wrAMwrM8wrZswrmcwrzMwr/8xVAMxVM8xVZsxVmcxVzMxV/8yAAMyAM8yAZsyAmcyAzMyA/8yqAMyqM8yqZsyqmcyqzMyq/8zVAMzVM8zVZszVmczVzMzV/8z/AMz/M8z/Zsz/mcz/zMz///8AAP8AM/8AZv8Amf8AzP8A//8rAP8rM/8rZv8rmf8rzP8r//9VAP9VM/9VZv9Vmf9VzP9V//+AAP+AM/+AZv+Amf+AzP+A//+qAP+qM/+qZv+qmf+qzP+q///VAP/VM//VZv/Vmf/VzP/V////AP//M///Zv//mf//zP///wAAAAAAAAAAAAAAACH5BAEAAPwALAAAAABkAGQAAAj/AAEIHEiwoMGDCBMqXMiwocOHECNKnEixosWLGAfu28ixo8ePIEOKHEmypMmOBU+qXMmypcqULmPKnFkSJs2bOGXazMmzJ8mdPoMK3Qd0qFGcRY8qjZl0qdOXBJ9Kbdl0qtWPVa9qJRp1q1ePWb9KDSvWKdmySs+iNap2rdC2bn3CjctzLl2kXe+OzavXLN++af8CZit48NvChuUiTlx3MWO8Gh8PtSv5JOXKNR1jZqp5M9XOnldeDg1yNGmwoE9njqx6punWXFnDdvm6dW3Vt0/nJr07dG/PvzcHxzy8cnHJxx8nZ7w8cXPDzwdHBzy9b3W91+9mp7s9bne339eGX0c7vmx5see/pve6fmt7re+vxrc6f2r9vbJns7z/lL/f/PpBBWCAJvm3lIGBDUjgT6ktyBGCR0FImIIOhiThZA1WeOFhFFaIVYYObhiUiIp16CFKGaWo4oostuhiQQEBADs="\r
+ },\r
+ "speech": {\r
+ "x_rate": 3,\r
+ "y_rate": 3,\r
+ "width_rate": 94,\r
+ "height_rate": 94\r
+ }\r
+ },\r
+ "middle": {\r
+ "balloon": {\r
+ "size": 1,\r
+ "system_picture": "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"\r
+ },\r
+ "speech": {\r
+ "x_rate": 2,\r
+ "y_rate": 2,\r
+ "width_rate": 96,\r
+ "height_rate": 96\r
+ }\r
+ },\r
+ "large": {\r
+ "balloon": {\r
+ "size": 2,\r
+ "system_picture": "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"\r
+ },\r
+ "speech": {\r
+ "x_rate": 1,\r
+ "y_rate": 1,\r
+ "width_rate": 98,\r
+ "height_rate": 98\r
+ }\r
+ }\r
+ }\r
+ }\r
+}\r
+# -*- encoding: utf-8 -*-
require 'spec_helper'
-
+#フキダシテンプレート
describe SpeechBalloonTemplate do
- pending "add some examples to (or delete) #{__FILE__}"
+ before do
+ #テストデータを用意してね
+ @f = Rails.root + 'spec/json/speech_balloon_template.json'
+ @t = File.open(@f, 'r').read
+ @j = JSON.parse @t
+ @fs = Rails.root + 'spec/json/speech_balloon_templates.json'
+ @ts = File.open(@fs, 'r').read
+ @js = JSON.parse @ts
+ @fes = Rails.root + 'spec/json/invalid_speech_balloon_templates.json'
+ @tes = File.open(@fes, 'r').read
+ @jes = JSON.parse @tes
+
+ @admin = Factory :admin
+ @license = Factory :license
+ end
+
+ describe '検証に於いて' do
+ before do
+ end
+
+ it 'オーソドックスなデータなら通る' do
+ @st = Factory.build :speech_balloon_template
+ @st.should be_valid
+ end
+
+ context 'nameを検証するとき' do
+ before do
+ @st = Factory.build :speech_balloon_template
+ end
+ it 'テストデータの確認' do
+ @st.name = 'abcdefghi0abcdefghi0abcdefghi0abcdefghi0abcdefghi0'
+ @st.should be_valid
+ end
+ it 'nullなら失敗する' do
+ @st.name = ''
+ @st.should_not be_valid
+ end
+ it '51文字以上なら失敗する' do
+ @st.name = 'a'*51
+ @st.should_not be_valid
+ end
+ end
+ context 'classnameを検証するとき' do
+ before do
+ @st = Factory.build :speech_balloon_template
+ end
+ it 'テストデータの確認' do
+ @st.classname = 'abcdefghi0abcdefghi0abcdefghi0abcdefghi0abcdefghi0'
+ @st.should be_valid
+ end
+ it 'nullなら失敗する' do
+ @st.classname = ''
+ @st.should_not be_valid
+ end
+ it '51文字以上なら失敗する' do
+ @st.classname = 'a'*51
+ @st.should_not be_valid
+ end
+ end
+ context 'captionを検証するとき' do
+ before do
+ @st = Factory.build :speech_balloon_template
+ end
+ it 'テストデータの確認' do
+ @st.caption = 'abcdefghi0abcdefghi0abcdefghi0'
+ @st.should be_valid
+ end
+ it 'nullなら失敗する' do
+ @st.caption = ''
+ @st.should_not be_valid
+ end
+ it '31文字以上なら失敗する' do
+ @st.caption = 'a'*31
+ @st.should_not be_valid
+ end
+ end
+ context 'tを検証するとき' do
+ before do
+ @st = Factory.build :speech_balloon_template
+ end
+ it 'テストデータの確認' do
+ @st.t = 0
+ @st.should be_valid
+ end
+ it 'nullなら失敗する' do
+ @st.t = nil
+ @st.should_not be_valid
+ end
+ it '数値でなければ失敗する' do
+ @st.t = 'a'
+ @st.should_not be_valid
+ end
+ it '負なら失敗する' do
+ @st.t = -1
+ @st.should_not be_valid
+ end
+ end
+ context 'settingsを検証するとき' do
+ before do
+ @st = Factory.build :speech_balloon_template
+ end
+ it 'テストデータの確認' do
+ @st.settings = '{}'
+ @st.should be_valid
+ end
+ it 'nullなら失敗する' do
+ @st.settings = nil
+ @st.should_not be_valid
+ end
+ end
+ end
+
+ describe 'データ補充に於いて' do
+ before do
+ end
+
+ end
+
+ describe 'Json解析に於いて' do
+ before do
+ end
+ context 'テキストを渡されたとき' do
+ it 'Json解析している' do
+ JSON.should_receive(:parse).with(@t).exactly(1)
+ r = SpeechBalloonTemplate.parse @t
+ end
+ it 'Hashで返す' do
+ r = SpeechBalloonTemplate.parse @t
+ r.is_a?(Hash).should be_true
+ end
+ end
+ context 'パース失敗したとき' do
+ it 'Falseを返す' do
+ JSON.should_receive(:parse).with(any_args).and_raise('StandardError')
+ r = SpeechBalloonTemplate.parse @t
+ r.should be_false
+ end
+ end
+ end
+
+ describe '対象フキダシテンプレートの取得に於いて' do
+ before do
+ @st = Factory :speech_balloon_template
+ end
+ context 'nameが一致するフキダシテンプレートがないとき' do
+ it '新規フキダシテンプレートを準備して返す' do
+ r = SpeechBalloonTemplate.update_speech_balloon_template 'newtemplate', {:classname => 'New'}
+ r.should be_a_new SpeechBalloonTemplate
+ r[:classname].should eq 'New'
+ end
+ end
+ context 'nameが一致するフキダシテンプレートがあるとき' do
+ it '該当フキダシテンプレートを値設定して返す' do
+ r = SpeechBalloonTemplate.update_speech_balloon_template @st.name, {:classname => 'Update'}
+ r.is_a?(SpeechBalloonTemplate).should be_true
+ r.should_not be_a_new SpeechBalloonTemplate
+ r[:classname].should eq 'Update'
+ end
+ end
+ end
+
+ describe 'フキダシテンプレート保存に於いて' do
+ before do
+ @st = Factory.build :speech_balloon_template
+ end
+ context 'つつがなく終わるとき' do
+ it '保存を問い合わせている' do
+ SpeechBalloonTemplate.any_instance.should_receive(:save).exactly(1)
+ @st.store
+ end
+ it 'フキダシテンプレートが作成されている' do
+ lambda {
+ @st.store
+ }.should change SpeechBalloonTemplate, :count
+ end
+ end
+ end
+
+ describe 'フキダシテンプレート更新に於いて' do
+ before do
+ @st = Factory :speech_balloon_template
+ @attr = {:name => @st.name, :classname => 'Update', :t => 0, :caption => 'yp', :settings => '{}'}
+ @newattr = {:name => @st.name, :classname => 'New', :t => 1, :caption => 'nw', :settings => '{}'}
+ end
+ context 'つつがなく終わるとき' do
+ it '対象フキダシテンプレートを問い合わせている' do
+ SpeechBalloonTemplate.stub(:update_speech_balloon_template).with(any_args).and_return(SpeechBalloonTemplate.new(@attr))
+ SpeechBalloonTemplate.should_receive(:update_speech_balloon_template).exactly(1)
+ SpeechBalloonTemplate.store @st.name, @attr
+ end
+ context '新規のとき' do
+ it 'フキダシテンプレートを保存しようとしている' do
+ SpeechBalloonTemplate.any_instance.should_receive(:save).exactly(1)
+ SpeechBalloonTemplate.store 'newtemplate', @newattr
+ end
+ it 'フキダシテンプレートが作成されている' do
+ lambda {
+ SpeechBalloonTemplate.store 'newtemplate', @newattr
+ }.should change SpeechBalloonTemplate, :count
+ end
+ end
+ context '更新のとき' do
+ it 'フキダシテンプレートを保存しようとしている' do
+ SpeechBalloonTemplate.any_instance.should_receive(:save).exactly(1)
+ SpeechBalloonTemplate.store @st.name, @attr
+ end
+ it 'フキダシテンプレートの数に変化がない' do
+ lambda {
+ SpeechBalloonTemplate.store @st.name, @attr
+ }.should_not change SpeechBalloonTemplate, :count
+ end
+ end
+ it '属性が一致している' do
+ r = SpeechBalloonTemplate.store 'newtemplate', @newattr
+ r.classname.should eq 'New'
+ end
+ it '保存されたSpeechBalloonTemplateオブジェクトを返す' do
+ r = SpeechBalloonTemplate.store 'newtemplate', @newattr
+p r.errors.full_messages
+ r.should_not be_a_new SpeechBalloonTemplate
+ end
+ end
+ context 'フキダシテンプレートの作成に失敗するとき' do
+ before do
+ SpeechBalloonTemplate.any_instance.stub(:save).with(any_args).and_return(false)
+ end
+ context '新規のとき' do
+ it 'フキダシテンプレートに変化がない' do
+ lambda {
+ r = SpeechBalloonTemplate.store 'newtemplate', @newattr
+ }.should_not change License, :count
+ end
+ end
+ context '更新のとき' do
+ it 'フキダシテンプレート属性に変化がない' do
+ lambda {
+ r = SpeechBalloonTemplate.store @st.name, @attr
+ }.should_not change License.find(@st.id), :classname
+ end
+ end
+ end
+ end
+
+ describe 'テキスト取り込みに於いて' do
+ #成功でTrue、パース失敗でFalse、失敗は保存エラーのモデルを配列で返す
+ before do
+ end
+ context 'つつがなく終わるとき' do
+ it 'Json解析を依頼する' do
+ SpeechBalloonTemplate.should_receive(:parse).with(any_args).exactly(1)
+ SpeechBalloonTemplate.stub(:parse).with(any_args).and_return(@j)
+ SpeechBalloonTemplate.import(@t)
+ end
+ it 'フキダシテンプレート更新を一回依頼する' do
+ SpeechBalloonTemplate.stub(:store).with(any_args).and_return(SpeechBalloonTemplate.new)
+ SpeechBalloonTemplate.any_instance.stub(:valid?).with(any_args).and_return(true)
+ SpeechBalloonTemplate.should_receive(:store).with(any_args).exactly(1)
+ SpeechBalloonTemplate.import(@t)
+ end
+ it 'フキダシテンプレートが追加される' do
+ lambda {
+ SpeechBalloonTemplate.import(@t)
+ }.should change SpeechBalloonTemplate, :count
+ end
+ it '[]を返す' do
+ SpeechBalloonTemplate.import(@t).should eq []
+ end
+ end
+ context '複数データがつつがなく終わるとき' do
+ it 'フキダシテンプレート更新を二回依頼する' do
+ SpeechBalloonTemplate.stub(:store).with(any_args).and_return(SpeechBalloonTemplate.new)
+ SpeechBalloonTemplate.any_instance.stub(:valid?).with(any_args).and_return(true)
+ SpeechBalloonTemplate.should_receive(:store).with(any_args).exactly(2)
+ SpeechBalloonTemplate.import(@ts)
+ end
+ it 'フキダシテンプレートが二個追加される' do
+ lambda {
+ SpeechBalloonTemplate.import(@ts)
+ }.should change(SpeechBalloonTemplate, :count).by 2
+ end
+ it '[]を返す' do
+ SpeechBalloonTemplate.import(@ts).should eq []
+ end
+ end
+ #例外ケース
+ context 'Json解析に失敗したとき' do
+ before do
+ SpeechBalloonTemplate.stub(:parse).with(any_args).and_return(false)
+ end
+ it 'フキダシテンプレートの数に変化がない' do
+ lambda {
+ SpeechBalloonTemplate.import(@t)
+ }.should_not change SpeechBalloonTemplate, :count
+ end
+ it 'Falseを返す' do
+ SpeechBalloonTemplate.import(@t).should be_false
+ end
+ end
+ context 'フキダシテンプレート作成に失敗したとき' do
+ before do
+ SpeechBalloonTemplate.any_instance.stub(:save).with(any_args).and_return(false)
+ SpeechBalloonTemplate.any_instance.stub(:valid?).with(any_args).and_return(false)
+ end
+ it 'フキダシテンプレートの数に変化がない' do
+ lambda {
+ SpeechBalloonTemplate.import(@t)
+ }.should_not change SpeechBalloonTemplate, :count
+ end
+ it '配列を返す' do
+ r = SpeechBalloonTemplate.import(@t)
+ r.is_a?(Array).should be_true
+ end
+ it '配列の中身は一件' do
+ r = SpeechBalloonTemplate.import(@t)
+ r.should have(1).items
+ end
+ it 'フキダシテンプレートオブジェクトが入っている' do
+ r = SpeechBalloonTemplate.import(@t)
+ r.first.is_a?(SpeechBalloonTemplate).should be_true
+ end
+ end
+ context '複数のフキダシテンプレート作成に失敗したとき' do
+ #三件中、二件の失敗、一件を成功させ、成功データは戻り値に含まないことを確認する
+ it 'フキダシテンプレートの数に変化がない' do
+ lambda {
+ SpeechBalloonTemplate.import(@tes)
+ }.should_not change SpeechBalloonTemplate, :count
+ end
+ it '途中で保存に失敗しても全件更新依頼する' do
+ SpeechBalloonTemplate.stub(:store).with(any_args).and_return(SpeechBalloonTemplate.new)
+ SpeechBalloonTemplate.should_receive(:store).with(any_args).exactly(3)
+ SpeechBalloonTemplate.import(@tes)
+ end
+ it '配列を返す' do
+ r = SpeechBalloonTemplate.import(@tes)
+ r.is_a?(Array).should be_true
+ end
+ it '配列の中身は2件' do
+ r = SpeechBalloonTemplate.import(@tes)
+ r.should have(2).items
+ end
+ it '配列の中身は失敗したフキダシテンプレートオブジェクトが入っている' do
+ r = SpeechBalloonTemplate.import(@tes)
+ r[0].is_a?(SpeechBalloonTemplate).should be_true
+ r[0]["name"].should eq 'fail1'
+ r[1].is_a?(SpeechBalloonTemplate).should be_true
+ r[1]["name"].should eq 'fail2'
+ end
+ end
+ end
+
+ describe 'インポートエラーの表示に於いて' do
+ end
+
+ describe 'ファイル取り込みに於いて' do
+ before do
+ SpeechBalloonTemplate.stub(:import).with(any_args).and_return(true)
+ end
+ context 'つつがなく終わるとき' do
+ before do
+ SpeechBalloonTemplate.stub(:import).with(any_args).and_return(true)
+ end
+ it 'ファイルを開いてテキストを読む' do
+ File.should_receive(:open).with(@f, 'r').exactly(1)
+ SpeechBalloonTemplate.import_file(@f)
+ end
+ it 'テキスト取り込みを依頼する' do
+ SpeechBalloonTemplate.should_receive(:import).with(any_args).exactly(1)
+ SpeechBalloonTemplate.import_file(@f)
+ end
+ #テキスト取り込み成功でTrueが返る
+ it 'Trueを返す' do
+ SpeechBalloonTemplate.import_file(@f).should be_true
+ end
+ end
+ context 'ファイルが開けないとき' do
+ before do
+ File.stub(:open).with(any_args).and_raise('StandardError')
+ end
+ it 'ファイルエラーのメッセージを出力する' do
+ pending
+ end
+ it 'Falseを返す' do
+ SpeechBalloonTemplate.import_file(@f).should be_false
+ end
+ end
+ #失敗したときは、失敗したフキダシテンプレートが配列で返る
+ context 'テキスト取り込みが失敗したとき' do
+ before do
+ SpeechBalloonTemplate.stub(:import).with(any_args).and_return(false)
+ end
+ it '各フキダシテンプレートのエラーメッセージを出力する' do
+ pending
+ end
+ it 'Falseを返す' do
+ SpeechBalloonTemplate.import_file(@f).should be_false
+ end
+ end
+ end
+
end
+# -*- encoding: utf-8 -*-
require 'spec_helper'
-
+#システム画像
describe SystemPicture do
- pending "add some examples to (or delete) #{__FILE__}"
+ before do
+ @admin = Factory :admin
+ @license = Factory :license
+ end
+
+ describe '検証に於いて' do
+ before do
+ end
+
+ it 'オーソドックスなデータなら通る' do
+ @sp = Factory.build :system_picture
+ @sp.should be_valid
+ end
+
+ context 'extを検証するとき' do
+ before do
+ @sp = Factory.build :system_picture
+ end
+ it 'テストデータの確認' do
+ @sp.ext = 'jpeg'
+ @sp.should be_valid
+ end
+ it 'nullなら失敗する' do
+ @sp.ext = ''
+ @sp.should_not be_valid
+ end
+ it '5文字以上なら失敗する' do
+ @sp.ext = 'a'*5
+ @sp.should_not be_valid
+ end
+ it 'png,gif,jpeg以外なら失敗する' do
+ @sp.ext = 'bmp'
+ @sp.should_not be_valid
+ end
+ end
+ context 'widthを検証するとき' do
+ before do
+ @sp = Factory.build :system_picture
+ end
+ it 'テストデータの確認' do
+ @sp.width = 1
+ @sp.should be_valid
+ end
+ it 'nullなら失敗する' do
+ @sp.width = nil
+ @sp.should_not be_valid
+ end
+ it '数値でなければ失敗する' do
+ @sp.width = 'a'
+ @sp.should_not be_valid
+ end
+ it '0なら失敗する' do
+ @sp.width = '0'
+ @sp.should_not be_valid
+ end
+ it '負でも失敗する' do
+ @sp.width = -1
+ @sp.should_not be_valid
+ end
+ end
+ context 'heightを検証するとき' do
+ before do
+ @sp = Factory.build :system_picture
+ end
+ it 'テストデータの確認' do
+ @sp.height = 1
+ @sp.should be_valid
+ end
+ it 'nullなら失敗する' do
+ @sp.height = nil
+ @sp.should_not be_valid
+ end
+ it '数値でなければ失敗する' do
+ @sp.height = 'a'
+ @sp.should_not be_valid
+ end
+ it '0なら失敗する' do
+ @sp.height = '0'
+ @sp.should_not be_valid
+ end
+ it '負でも失敗する' do
+ @sp.height = -1
+ @sp.should_not be_valid
+ end
+ end
+ context 'filesizeを検証するとき' do
+ before do
+ @sp = Factory.build :system_picture
+ end
+ it 'テストデータの確認' do
+ @sp.filesize = 1
+ @sp.should be_valid
+ end
+ it 'nullなら失敗する' do
+ @sp.filesize = nil
+ @sp.should_not be_valid
+ end
+ it '数値でなければ失敗する' do
+ @sp.filesize = 'a'
+ @sp.should_not be_valid
+ end
+ it '負なら失敗する' do
+ @sp.filesize = '-1'
+ @sp.should_not be_valid
+ end
+ it '2MB以上なら失敗する' do
+ @sp.filesize = 2000000+1
+ @sp.should_not be_valid
+ end
+ end
+ context 'md5を検証するとき' do
+ before do
+ @sp = Factory.build :system_picture
+ end
+ it 'テストデータの確認' do
+ @sp.md5 = 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'
+ @sp.should be_valid
+ end
+ it 'nullなら失敗する' do
+ @sp.md5 = ''
+ @sp.should_not be_valid
+ end
+ it '32文字以上なら失敗する' do
+ @sp.md5 = 'a'*33
+ @sp.should_not be_valid
+ end
+ end
+ end
+
+ describe 'データ補充に於いて' do
+ before do
+ end
+
+ end
+
+ describe '作成・更新に於いて' do
+ before do
+ @sp = Factory.build :system_picture
+ #RMagickのスタブをおいておく
+ class Mgk ; class Image ; end ; end
+ @filesize = 76543
+ Mgk::Image.stub(:from_blob).with(any_args).and_return([Mgk.new])
+ Mgk.any_instance.stub(:format).with(any_args).and_return('png')
+ Mgk.any_instance.stub(:rows).with(any_args).and_return(200)
+ Mgk.any_instance.stub(:columns).with(any_args).and_return(100)
+ Mgk.any_instance.stub(:filesize).with(any_args).and_return(@filesize)
+ Mgk.any_instance.stub(:to_blob).with(any_args).and_return('data')
+ end
+ context '事前チェック' do
+ before do
+ #すべての処理が正常パターンで通過すれば、一番深い分岐まで通る。
+ #それで外部のメソッド呼び出しだけに着目してテストする。
+ SystemPicture.any_instance.stub(:data_to_mgk).with(any_args).and_return(Mgk.new)
+ SystemPicture.any_instance.stub(:save).with(any_args).and_return(true)
+ PictureIO::LocalPicture.any_instance.stub(:put).with(any_args).and_return(true)
+ end
+ it 'RMagick変換を依頼している' do
+ SystemPicture.any_instance.should_receive(:data_to_mgk).exactly(1)
+ @sp.store 'bindata'
+ end
+ it '自身に属性をセットしている' do
+ SystemPicture.any_instance.should_receive(:attributes=).exactly(1)
+ @sp.store 'bindata'
+ end
+ it '自身が保存されている' do
+ SystemPicture.any_instance.should_receive(:save).exactly(1)
+ @sp.store 'bindata'
+ end
+ it 'PictureIoに画像データの保存を依頼している' do
+ PictureIO::LocalPicture.any_instance.should_receive(:put).with(any_args).exactly(1)
+ @sp.store 'bindata'
+ end
+ end
+ context 'つつがなく終わるとき' do
+ before do
+ #すべての処理を正常パターンで通過させ、保存機能をチェックする。
+ SystemPicture.any_instance.stub(:data_to_mgk).with(any_args).and_return(Mgk.new)
+# SystemPicture.any_instance.stub(:save).with(any_args).and_return(true)
+ PictureIO::LocalPicture.any_instance.stub(:put).with(any_args).and_return(true)
+ end
+ it '自身に属性をセットしている' do
+ lambda {
+ @sp.store 'bindata'
+ }.should change @sp, :filesize
+ end
+ it 'システム画像モデルが作成されている' do
+ lambda {
+ @sp.store 'bindata'
+ }.should change SystemPicture, :count
+ end
+ it 'システム画像が保存されている' do
+ @sp.store 'bindata'
+ SystemPicture.find(@sp).should_not be_nil
+ end
+ it 'Trueを返す' do
+ @sp.store('bindata').should eq true
+ end
+ end
+ #以下から例外ケース。処理先頭から失敗させていく
+ context 'RMagick変換が失敗したとき' do
+ before do
+ SystemPicture.any_instance.stub(:data_to_mgk).with(any_args).and_return(false)
+ end
+ it 'falseを返す' do
+ @sp.store('bindata').should be_false
+ end
+ it '自身の保存は呼ばれていない' do
+ SystemPicture.any_instance.should_not_receive(:save)
+ end
+ end
+ context '自身の保存に失敗したとき' do
+ before do
+ SystemPicture.any_instance.stub(:data_to_mgk).with(any_args).and_return(Mgk.new)
+ SystemPicture.any_instance.stub(:save).with(any_args).and_return(false)
+ end
+ it 'falseを返す' do
+ @sp.store('bindata').should be_false
+ end
+ it '更新されていない' do
+ @sp.store('bindata')
+ @sp.should be_a_new SystemPicture
+ end
+ it '原画の保存は呼ばれていない' do
+ PictureIO::LocalPicture.any_instance.should_not_receive(:put)
+ end
+ end
+ end
+
+ describe '置換に於いて' do
+ before do
+ @sp = Factory :system_picture
+ end
+ context '新規のとき' do
+ before do
+ SystemPicture.stub(:find_by_md5).with(any_args).and_return(nil)
+ SystemPicture.any_instance.stub(:store).with(any_args).and_return(true)
+ end
+ it '新規オブジェクト生成している' do
+ r = SystemPicture.store 'bindata'
+ r.should be_a_new SystemPicture
+ end
+ it '作成依頼している' do
+ SystemPicture.any_instance.should_receive(:store).with('bindata').exactly(1)
+ SystemPicture.store 'bindata'
+ end
+ it '保存された行を返す' do
+ r = SystemPicture.store 'bindata'
+ r.should_not eq @sp
+ end
+ end
+ context '既存のとき' do
+ before do
+ SystemPicture.stub(:find_by_md5).with(any_args).and_return(@sp)
+ SystemPicture.any_instance.stub(:store).with(any_args).and_return(true)
+ end
+ it '新規オブジェクト生成していない' do
+ SystemPicture.should_receive(:new).with(any_args).exactly(0)
+ SystemPicture.store 'bindata'
+ end
+ it '作成依頼している' do
+ SystemPicture.any_instance.should_receive(:store).with('bindata').exactly(1)
+ SystemPicture.store 'bindata'
+ end
+ it '保存された行を返す' do
+ r = SystemPicture.store 'bindata'
+ r.should eq @sp
+ end
+ end
+ context '保存失敗のとき' do
+ before do
+ SystemPicture.stub(:find_by_md5).with(any_args).and_return(@sp)
+ SystemPicture.any_instance.stub(:store).with(any_args).and_return(false)
+ end
+ it 'nilを返す' do
+ r = SystemPicture.store 'bindata'
+ r.should eq nil
+ end
+ end
+ end
end