config/license.yml
config/test_layout
lib/test/temp/
+db/migrate/*_creative_commons_v??_licenses_attributes.rb
+db/migrate/*_pettan_commons_v??_licenses_attributes.rb
+db/migrate/*_pettan_protected_v??_licenses_attributes.rb
+db/migrate/*_pettan_public_v??_licenses_attributes.rb
+db/migrate/*_public_domain_v??_licenses_attributes.rb
+db/migrate/*_unknown_v??_licenses_attributes.rb
gem 'validates_existence'
gem "validate_url"
gem "standard_licenses"
-gem "creative_commons_v30_licenses", '>= 0.0.4'
+gem "creative_commons_v30_licenses"
+gem 'pettan_commons_v01_licenses'
+gem 'pettan_protected_v01_licenses'
+gem 'pettan_public_v01_licenses'
+gem 'public_domain_v01_licenses'
+gem 'unknown_v01_licenses'
# Bundle edge Rails instead:
# gem 'rails', :git => 'git://github.com/rails/rails.git'
multi_json (1.3.6)
nokogiri (1.5.5-x86-mingw32)
orm_adapter (0.0.7)
+ pettan_commons_v01_licenses (0.0.5)
+ rails (~> 3.1.1)
+ pettan_protected_v01_licenses (0.0.5)
+ rails (~> 3.1.1)
+ pettan_public_v01_licenses (0.0.5)
+ rails (~> 3.1.1)
pg (0.14.0-x86-mingw32)
polyglot (0.3.3)
+ public_domain_v01_licenses (0.0.5)
+ rails (~> 3.1.1)
rack (1.3.6)
rack-cache (1.2)
rack (>= 0.4)
uglifier (1.2.6)
execjs (>= 0.3.0)
multi_json (~> 1.3)
+ unknown_v01_licenses (0.0.5)
+ rails (~> 3.1.1)
validate_url (0.2.0)
activemodel (>= 3.0.0)
validates_existence (0.7.1)
autotest
aws-s3
coffee-rails (~> 3.1.1)
- creative_commons_v30_licenses (>= 0.0.4)
+ creative_commons_v30_licenses
cucumber
cucumber-rails
database_cleaner
factory_girl
jquery-rails
moro-miso
+ pettan_commons_v01_licenses
+ pettan_protected_v01_licenses
+ pettan_public_v01_licenses
pg
+ public_domain_v01_licenses
rails (= 3.1.1)
rails-erd
rmagick
standard_licenses
therubyracer-heroku
uglifier (>= 1.0.3)
+ unknown_v01_licenses
validate_url
validates_existence
webrat
--- /dev/null
+/**
+ * http://d.hatena.ne.jp/ofk/20080904/1220485969
+ * @author ofk
+ */
+
+Function.prototype.apply || (Function.prototype.apply = function (x, y) {
+ x = x || window;
+ y = y ||[];
+ x.__apply = this;
+ if (!x.__apply) x.constructor.prototype.__apply = this;
+ var r, j = y.length;
+ switch (j) {
+ case 0: r = x.__apply(); break;
+ case 1: r = x.__apply(y[0]); break;
+ case 2: r = x.__apply(y[0], y[1]); break;
+ case 3: r = x.__apply(y[0], y[1], y[2]); break;
+ case 4: r = x.__apply(y[0], y[1], y[2], y[3]); break;
+ case 5: r = x.__apply(y[0], y[1], y[2], y[3], y[4]); break;
+ case 6: r = x.__apply(y[0], y[1], y[2], y[3], y[4], y[5]); break;
+ case 7: r = x.__apply(y[0], y[1], y[2], y[3], y[4], y[5], y[6]); break;
+ case 8: r = x.__apply(y[0], y[1], y[2], y[3], y[4], y[5], y[6], y[7]); break;
+ case 9: r = x.__apply(y[0], y[1], y[2], y[3], y[4], y[5], y[6], y[7], y[8]); break;
+ default:
+ var a = [];
+ for (var i = 0; i < j; ++i)
+ a[i] = 'y[' + i + ']';
+ r = eval('x.__apply(' + a.join(',') + ')');
+ break;
+ }
+ delete x.__apply ? x.__apply : x.constructor.prototype.__apply;
+ return r;
+});
+Function.prototype.call || (Function.prototype.call = function () {
+ var a = arguments, x = a[0], y = [];
+ for (var i = 1, j = a.length; i < j; ++i)
+ y[i - 1] = a[i]
+ return this.apply(x, y);
+});
+Array.prototype.pop || (Array.prototype.pop = function () {
+ var r = this[this.length - 1];
+ --this.length;
+ return r;
+});
+Array.prototype.push || (Array.prototype.push = function () {
+ for (var a = arguments, i = 0, j = a.length, l = this.length; i < j; ++i)
+ this[l + i] = a[i];
+ return this.length;
+});
+Array.prototype.shift || (Array.prototype.shift = function () {
+ var r = this[0];
+ for(var i = 1, j = this.length; i < j; ++i)
+ this[i - 1] = this[i];
+ --this.length;
+ return r;
+});
+Array.prototype.unshift || (Array.prototype.unshift = function () {
+ var a = arguments, l = a.length, j = this.length += l - 1;
+ for (var i = j; i >= l; --i)
+ this[i] = this[i - l];
+ for (var i = 0; i < l; ++i)
+ this[i] = a[i];
+ return j;
+});
+Array.prototype.splice || (Array.prototype.splice = function (x, y) {
+ var a = arguments, s = a.length - 2 - y, r = this.slice(x, x + y);
+ if (s > 0) {
+ for (var i = this.length - 1, j = x + y; i >= j; --i)
+ this[i + s] = this[i];
+ }
+ else if (s < 0) {
+ for (var i = x + y, j = this.length; i < j; ++i)
+ this[i + s] = this[i];
+ this.length += s;
+ }
+ for (var i = 2, j = a.length; i < j; ++i)
+ this[i - 2 + x] = a[i];
+ return r;
+});
@artist = if @author and @author.artist?
@author.artist
else
- Artist.new author_id: @author.id, email: @user.email, name: @author.name, default_license_id: 1
+ Artist.new author_id: @author.id, email: @user.email, name: @author.name
end
end
end
true
else
respond_to do |format|
- format.html { redirect_to new_artist_path, :status => :found }
+ format.html { redirect_to main_app.new_artist_path, :status => :found }
format.js { render "artists/new" }
format.json {
raise ActiveRecord::Forbidden
# GET /artists/new.json
def new
@artist = Artist.new
+ @artist.supply_default
respond_to do |format|
format.html # new.html.erb
# GET /artists/1/edit
def edit
- @artist = Artist.find(params[:id])
+ @artist = Artist.edit(params[:id], @author)
end
# POST /artists
# POST /artists.json
def create
- @artist = Artist.new(params[:artist])
- @artist.author_id = @author.id
+ @artist = Artist.new()
+ @artist.supply_default
+ @artist.attributes = params[:artist]
+ @artist.overwrite @author
respond_to do |format|
if @artist.save
format.html { redirect_to @artist, notice: 'Artist was successfully created.' }
# PUT /artists/1
# PUT /artists/1.json
def update
- @artist = Artist.find(params[:id])
+ @artist = Artist.edit(params[:id], @author)
+ @artist.attributes = params[:artist]
+ @artist.overwrite @author
respond_to do |format|
- if @artist.update_attributes(params[:artist])
+ if @artist.save
format.html { redirect_to @artist, notice: 'Artist was successfully updated.' }
format.json { head :ok }
else
# DELETE /artists/1
# DELETE /artists/1.json
def destroy
- @artist = Artist.find(params[:id])
+ @artist = Artist.edit(params[:id], @author)
@artist.destroy
respond_to do |format|
--- /dev/null
+class ColorsController < ApplicationController
+ layout 'test' if Pettanr::TestLayout
+
+ # GET /colors
+ # GET /colors.json
+ def index
+ @page = PanelColor.page params[:page]
+ @page_size = PanelColor.page_size params[:page_size]
+ @colors = Color.list({}, @page, @page_size)
+
+ respond_to do |format|
+ format.html # index.html.erb
+ format.json { render json: @colors.to_json(Color.list_json_opt) }
+ end
+ end
+end
end
before_filter :authenticate_admin!, :only => [:list, :browse]
- private
-
- def treat_param comic
- comic.author_id = @author.id
- end
-
- public
-
def top
@new_comics = Comic.find(:all,
:include => :author, :conditions => ['visible > 0'], :order => 'updated_at desc', :limit => 5
# GET /comics/1/edit
# GET /comics/1.js/edit
def edit
- @comic = Comic.show(params[:id], @author)
+ @comic = Comic.edit(params[:id], @author)
@comic.supply_default
respond_to do |format|
format.html
# POST /comics.json
def create
params[:comic].merge! author_id: @author.id
- @comic = Comic.new params[:comic]
+ @comic = Comic.new
@comic.supply_default
+ @comic.attributes = params[:comic]
+ @comic.overwrite @author
respond_to do |format|
if @comic.save
# PUT /comics/1
# PUT /comics/1.json
def update
- params[:comic].merge! author_id: @author.id
- @comic = Comic.show(params[:id], @author)
+ @comic = Comic.edit(params[:id], @author)
+ @comic.attributes = params[:comic]
+ @comic.overwrite @author
respond_to do |format|
- if @comic.update_attributes(params[:comic])
+ if @comic.save
format.html { redirect_to @comic, notice: 'Comic was successfully updated.' }
format.json { head :ok }
else
# DELETE /comics/1
# DELETE /comics/1.json
def destroy
- @comic = Comic.find(params[:id])
- if @comic.own? @author
- @comic.destroy
- respond_to do |format|
- format.html { redirect_to comics_url }
- format.json { head :ok }
- end
- else
- format.html { render action: "edit" }
- format.json { render json: @comic.errors, status: :unprocessable_entity }
+ @comic = Comic.edit(params[:id], @author)
+ @comic.destroy
+ respond_to do |format|
+ format.html { redirect_to comics_url }
+ format.json { head :ok }
end
end
end
--- /dev/null
+class GroundColorsController < ApplicationController
+ layout 'test' if Pettanr::TestLayout
+ before_filter :authenticate_user!, :only => [:index]
+
+ # GET /ground_colors
+ # GET /ground_colors.json
+ def index
+ @page = GroundColor.page params[:page]
+ @page_size = GroundColor.page_size params[:page_size]
+ @ground_colors = GroundColor.list({}, @page, @page_size)
+
+ respond_to do |format|
+ format.html # index.html.erb
+ format.json { render :json => @ground_colors.to_json(GroundColor.list_json_opt) }
+ end
+ end
+end
--- /dev/null
+class GroundPicturesController < ApplicationController
+ layout 'test' if Pettanr::TestLayout
+ before_filter :authenticate_user!, :only => [:index]
+
+ # GET /ground_pictures
+ # GET /ground_pictures.json
+ def index
+ @page = GroundPicture.page params[:page]
+ @page_size = GroundPicture.page_size params[:page_size]
+ @ground_pictures = GroundPicture.list({}, @page, @page_size)
+
+ respond_to do |format|
+ format.html # index.html.erb
+ format.json { render :json => @ground_pictures.to_json(GroundPicture.list_json_opt) }
+ end
+ end
+
+end
#原画
class OriginalPicturesController < ApplicationController
layout 'test' if Pettanr::TestLayout
- before_filter :authenticate_user!, :only => [:index, :show, :new, :edit, :create, :update, :destroy]
+ before_filter :authenticate_user!, :only => [:index, :show, :history, :new, :edit, :create, :update, :destroy]
before_filter :authenticate_admin!, :only => [:list, :browse]
- before_filter :authenticate_artist, :only => [:index, :show, :new, :edit, :create, :update, :destroy]
+ before_filter :authenticate_artist, :only => [:index, :show, :history, :new, :edit, :create, :update, :destroy]
private
end
end
+ def history
+ @original_picture = OriginalPicture.show(params[:id], @artist)
+ @history = @original_picture.history
+
+ respond_to do |format|
+ format.html # index.html.erb
+ format.json { render json: @history.to_json }
+ end
+ end
+
def list
@original_pictures = OriginalPicture.all
# GET /original_pictures/1/edit
def edit
- @original_picture = OriginalPicture.show(params[:id], @author)
+ @original_picture = OriginalPicture.edit(params[:id], @author)
respond_to do |format|
format.html
format.js
def update
@picture_data = set_image params[:original_picture][:file]
@original_picture = OriginalPicture.edit(params[:id], @author)
- @original_picture.supply_default @artist
respond_to do |format|
if @original_picture.store(@picture_data, @artist)
--- /dev/null
+class PanelColorsController < ApplicationController
+ layout 'test' if Pettanr::TestLayout
+ before_filter :authenticate_user!, :only => [:index]
+
+ # GET /ground_pictures
+ # GET /ground_pictures.json
+ def index
+ @page = PanelColor.page params[:page]
+ @page_size = PanelColor.page_size params[:page_size]
+ @panel_colors = PanelColor.list({}, @page, @page_size)
+
+ respond_to do |format|
+ format.html # index.html.erb
+ format.json { render :json => @panel_colors.to_json(PanelColor.list_json_opt) }
+ end
+ end
+
+end
end
def edit
- @panel = Panel.show(params[:id], @author)
+ @panel = Panel.edit(params[:id], @author)
respond_to do |format|
format.html
format.js
end
end
- def move
- @panel = Panel.find(params[:id])
- @new_seq = params[:panel][:t].to_i
- respond_to do |format|
- Panel.transaction do
- if @panel.move_to(@new_t)
- format.html { redirect_to @panel, notice: 'Panel was successfully moved.' }
- format.json { head :ok }
- else
- format.html { render action: "show" }
- format.json { render json: @panel.errors, status: :unprocessable_entity }
- end
- end
- end
- end
-
end
format.png { send_data(@picture.restore(params[:subdir]), opt ) }
format.gif { send_data(@picture.restore(params[:subdir]), opt ) }
format.jpeg { send_data(@picture.restore(params[:subdir]), opt ) }
+ format.html
format.json { render :json => @picture.to_json}
end
end
# GET /stories/1/edit
# GET /stories/1.js/edit
def edit
- @story = Story.show(params[:id], @author)
+ @story = Story.edit(params[:id], @author)
respond_to do |format|
format.html
format.js
--- /dev/null
+module ColorsHelper
+end
--- /dev/null
+module GroundColorsHelper
+end
--- /dev/null
+module GroundPicturesHelper
+end
--- /dev/null
+module PanelColorsHelper
+end
validates :name, :presence => true, :length => {:maximum => 30}
# validates :default_license_id, :presence => true, :numericality => true, :existence => true
- \r
+
def supply_default
self.name = 'no name' if self.name.blank?
end
+ def overwrite au
+ return false unless au
+ self.author_id = au.id
+ end
+
+ def own? author
+ return false unless author
+ self.author_id == author.id
+ end
+
+ def self.edit sid, au
+ res = Artist.find sid
+ raise ActiveRecord::Forbidden unless res.own?(au)
+ res
+ end
+
def self.find_by_author author
Artist.find( :first, :conditions => ['author_id = ?', author.id])
end
page_size
end
+ def self.default_ground_picture_page_size
+ 30
+ end
+
+ def self.ground_picture_max_page_size
+ 200
+ end
+
+ def self.ground_picture_page_size prm = self.default_ground_picture_page_size
+ page_size = prm.to_i
+ page_size = self.ground_picture_max_page_size if page_size > self.ground_picture_max_page_size
+ page_size = self.default_ground_picture_page_size if page_size < 1
+ page_size
+ end
+
+ def self.default_ground_color_page_size
+ 30
+ end
+
+ def self.ground_color_max_page_size
+ 200
+ end
+
+ def self.ground_color_page_size prm = self.default_ground_color_page_size
+ page_size = prm.to_i
+ page_size = self.ground_color_max_page_size if page_size > self.ground_color_max_page_size
+ page_size = self.default_ground_color_page_size if page_size < 1
+ page_size
+ end
+
+ def self.default_panel_color_page_size
+ 30
+ end
+
+ def self.panel_color_max_page_size
+ 200
+ end
+
+ def self.panel_color_page_size prm = self.default_panel_color_page_size
+ page_size = prm.to_i
+ page_size = self.panel_color_max_page_size if page_size > self.panel_color_max_page_size
+ page_size = self.default_panel_color_page_size if page_size < 1
+ page_size
+ end
+
def self.show aid, opt = {}
a = Author.find(aid, :include => self.show_include_opt(opt))
# raise ActiveRecord::Forbidden unless c.visible?(au)
--- /dev/null
+class Color < ActiveRecord::Base
+ belongs_to :ground_color
+
+ validates :name, :presence => true, :length => {:maximum => 50}, :uniqueness => true
+ validates :code, :presence => true, :numericality => {:greater_than_or_equal_to => 0, :less_than => 0x1000000}
+ validates :t, :presence => true, :numericality => {:greater_than_or_equal_to => 0}
+
+ def self.import filename
+ Color.import_file(filename) {|name, attr| Color.store(name, attr)}
+ end
+
+ def self.store name, attr
+ r = Color.modify_object name, attr
+ r.save
+ r
+ end
+
+ def self.default_page_size
+ 25
+ end
+
+ def self.max_page_size
+ 100
+ end
+
+ def self.default_panel_size
+ 30
+ end
+
+ def self.page prm = nil
+ page = prm.to_i
+ page = 1 if page < 1
+ page
+ end
+
+ def self.page_size prm = self.default_page_size
+ page_size = prm.to_i
+ page_size = self.max_page_size if page_size > self.max_page_size
+ page_size = self.default_page_size if page_size < 1
+ page_size
+ end
+
+ def self.list opt = {}, page = 1, page_size = self.default_page_size
+ opt.merge!({:order => 'colors.t', :limit => page_size, :offset => (page -1) * page_size})
+ Color.find(:all, opt)
+ end
+
+ def self.list_opt
+ {:include => {:ground_color => {:panel => {:author => {}}} }}
+ end
+
+ def self.list_json_opt
+ {:include => {:ground_color => {:panel => {:author => {}}} }}
+ end
+
+ def self.show cid
+ c = Color.find(cid)
+ c
+ end
+
+end
belongs_to :author
validates :title, :presence => true, :length => {:maximum => 100}
- validates :width, :presence => true, :numericality => true, :natural_number => true
- validates :height, :presence => true, :numericality => true, :natural_number => true
validates :visible, :presence => true, :numericality => true, :inclusion => {:in => 0..3}
before_save do |r|
self.visible = 0 if self.visible.blank?
end
+ def overwrite au
+ return false unless au
+ self.author_id = au.id
+ end
+
def own? author
return false unless author
self.author_id == author.id
c
end
+ def self.edit cid, au, opt = {}
+ c = Comic.find(cid, :include => self.show_include_opt(opt))
+ raise ActiveRecord::Forbidden unless c.own?(au)
+ c
+ end
+
def self.show_include_opt opt = {}
res = {:stories => {:panel => {}}, :author => {}}
res.push(opt[:include]) if opt[:include]
--- /dev/null
+class GroundColor < ActiveRecord::Base
+ belongs_to :panel
+ belongs_to :color
+
+ validates :panel_id, :numericality => {:allow_blank => true}
+ validates :color_id, :numericality => true, :existence => true
+ validates :z, :presence => true, :numericality => {:greater_than => 0}
+
+ def self.default_page_size
+ 25
+ end
+
+ def self.max_page_size
+ 100
+ end
+
+ def self.page prm = nil
+ page = prm.to_i
+ page = 1 if page < 1
+ page
+ end
+
+ def self.page_size prm = self.default_page_size
+ page_size = prm.to_i
+ page_size = self.max_page_size if page_size > self.max_page_size
+ page_size = self.default_page_size if page_size < 1
+ page_size
+ end
+
+ def self.offset cnt, prm = nil
+ offset = prm.to_i
+ offset = cnt - 1 if offset >= cnt
+ offset = cnt - offset.abs if offset < 0
+ offset = 0 if offset < 0
+ offset
+ end
+
+ def self.list opt = {}, page = 1, page_size = self.default_page_size
+ opt.merge!(self.list_opt) unless opt[:include]
+ opt.merge!({:conditions => 'panels.publish > 0', :order => 'ground_colors.updated_at desc', :limit => page_size, :offset => (page -1) * page_size})
+ GroundColor.find(:all, opt)
+ end
+
+ def self.list_opt
+ {:include => {:panel => {:author => {}}, :color => {} }}
+ end
+
+ def self.list_json_opt
+ {:include => {:panel => {:author => {}}, :color => {} }}
+ end
+
+ def self.mylist au, opt = {}, page = 1, ground_color_page_size = Author.default_ground_color_page_size
+ opt.merge!(self.list_opt) unless opt[:include]
+ opt.merge!({:conditions => ['panels.author_id = ?', au.id], :order => 'ground_colors.updated_at desc', :limit => page_size, :offset => (page -1) * ground_color_page_size})
+ GroundColor.find(:all, opt)
+ end
+
+end
--- /dev/null
+class GroundPicture < ActiveRecord::Base
+ belongs_to :panel
+ belongs_to :picture
+
+ validates :panel_id, :numericality => {:allow_blank => true}
+ validates :picture_id, :numericality => true, :existence => true
+ validates :z, :presence => true, :numericality => {:greater_than => 0}
+
+ def self.default_page_size
+ 25
+ end
+
+ def self.max_page_size
+ 100
+ end
+
+ def self.page prm = nil
+ page = prm.to_i
+ page = 1 if page < 1
+ page
+ end
+
+ def self.page_size prm = self.default_page_size
+ page_size = prm.to_i
+ page_size = self.max_page_size if page_size > self.max_page_size
+ page_size = self.default_page_size if page_size < 1
+ page_size
+ end
+
+ def self.offset cnt, prm = nil
+ offset = prm.to_i
+ offset = cnt - 1 if offset >= cnt
+ offset = cnt - offset.abs if offset < 0
+ offset = 0 if offset < 0
+ offset
+ end
+
+ def self.list opt = {}, page = 1, page_size = self.default_page_size
+ opt.merge!(self.list_opt) unless opt[:include]
+ opt.merge!({:conditions => 'panels.publish > 0', :order => 'ground_pictures.updated_at desc', :limit => page_size, :offset => (page -1) * page_size})
+ GroundPicture.find(:all, opt)
+ end
+
+ def self.list_opt
+ {:include => {:panel => {:author => {}}, :picture => {:artist => {}, :license => {}}}}
+ end
+
+ def self.list_json_opt
+ {:include => {:panel => {:author => {}}, :picture => {:artist => {}, :license => {}}}}
+ end
+
+ def self.mylist au, opt = {}, page = 1, ground_picture_page_size = Author.default_ground_picture_page_size
+ opt.merge!(self.list_opt) unless opt[:include]
+ opt.merge!({:conditions => ['panels.author_id = ?', au.id], :order => 'ground_pictures.updated_at desc', :limit => page_size, :offset => (page -1) * ground_picture_page_size})
+ GroundPicture.find(:all, opt)
+ end
+
+end
{:include => {:licenses => {}}}
end
+ def self.disp_import_error r
+ if r == false
+ puts "json file error. file does not exist or broken"
+ else
+ unless r.empty?
+ r.each do |lg|
+ put lg.errors.full_messages
+ end
+ end
+ end
+ end
end
belongs_to :artist
belongs_to :original_picture_license_group
has_one :resource_picture
+ has_many :pictures
- validates :ext, :presence => true, :length => {:maximum => 4}, :inclusion => {:in => ['png', 'jpeg', 'gif']}\r
+ 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 :artist_id, :presence => true, :numericality => true, :existence => true
+ validates :md5, :presence => true, :length => {:maximum => 32}
before_destroy :destroy_with_file
def supply_default art
end
+ def overwrite art
+ return false unless art
+ self.artist_id = art.id
+ end
+
def self.default_page_size
25
end
OriginalPicture.find(:all, opt)
end
+ def history
+ Picture.find(:all, {:conditions => ['pictures.original_picture_id = ?', self.id], :order => 'pictures.revision desc'} )
+ end
+
def self.list_opt
- {:include => {:resource_picture => {}}}
+ {:include => {:resource_picture => {}, :pictures => {}}}
end
def self.list_json_opt
- {:include => {:resource_picture => {}}}
+ {:include => {:resource_picture => {}, :pictures => {}}}
end
def self.show cid, artist, opt = {}
- pic = OriginalPicture.find(cid, :include => self.show_include_opt(opt))
+ pic = OriginalPicture.find(cid, self.show_include_opt)
raise ActiveRecord::Forbidden unless pic.own?(artist)
pic
end
def self.edit cid, artist, opt = {}
- pic = OriginalPicture.find(cid, :include => self.show_include_opt(opt))
+ pic = OriginalPicture.find(cid, self.show_include_opt)
raise ActiveRecord::Forbidden unless pic.own?(artist)
pic
end
- def self.show_include_opt opt = {}
- res = {:resource_picture => {}}
- res.merge!(opt[:include]) if opt[:include]
- res
+ def self.show_include_opt
+ {:include => {:resource_picture => {}, :pictures => {}}}
end
def self.show_json_include_opt
- {:include => {:resource_picture => {}}}
+ {:include => {:resource_picture => {}, :pictures => {}}}
end
def destroy_with_file
'/original_pictures/' + filename
end
+ def opt_img_tag
+ tw, th = ResourcePicture.fix_size_both(MagicNumber['thumbnail_width'], MagicNumber['thumbnail_height'], self.width, self.height)
+ {:src => self.url, :width => tw, :height => th}
+ end
+
def data_to_mgk picture_data
begin
mgk = Magick::Image.from_blob(picture_data).shift
self.attributes = {:ext => mgk.format.downcase, :width => mgk.columns, :height => mgk.rows,
:filesize => mgk.filesize, :artist_id => art.id
}
+ self.md5 = Digest::MD5.hexdigest(picture_data)
+ self.overwrite art
OriginalPicture.transaction do
if res = self.save
if res = PictureIO.original_picture_io.put(picture_data, self.filename)
class Panel < ActiveRecord::Base
belongs_to :author
belongs_to :resource_picture
-# belongs_to :background_picture, :class_name => 'ResourcePicture'
has_many :stories
has_many :panel_pictures, :dependent => :destroy
has_many :speech_balloons, :dependent => :destroy
+ has_many :ground_pictures, :dependent => :destroy
+ has_many :ground_colors, :dependent => :destroy
+ has_many :panel_colors, :dependent => :destroy
accepts_nested_attributes_for :panel_pictures, :allow_destroy => true
accepts_nested_attributes_for :speech_balloons, :allow_destroy => true
+ accepts_nested_attributes_for :ground_pictures, :allow_destroy => true
+ accepts_nested_attributes_for :ground_colors, :allow_destroy => true
+ accepts_nested_attributes_for :panel_colors, :allow_destroy => true
validates :width, :presence => true, :numericality => true, :natural_number => true
validates :height, :presence => true, :numericality => true, :natural_number => true
:picture => {:artist => {}, :license => {}}
},
:speech_balloons => {:balloons => {}, :speeches => {}},
+ :ground_pictures => {
+ :picture => {:artist => {}, :license => {}}
+ },
+ :ground_colors => {
+ :color => {}
+ },
+ :panel_colors => {
+ },
:author => {}
}}
end
:picture => {:artist => {}, :license => {}}
},
:speech_balloons => {:balloons => {}, :speeches => {}},
+ :ground_pictures => {
+ :picture => {:artist => {}, :license => {}}
+ },
+ :ground_colors => {
+ :color => {}
+ },
+ :panel_colors => {
+ },
:author => {}
}}
end
:picture => {:artist => {}, :license => {}}
},
:speech_balloons => {:balloons => {}, :speeches => {}},
+ :ground_pictures => {
+ :picture => {:artist => {}, :license => {}}
+ },
+ :ground_colors => {
+ :color => {}
+ },
+ :panel_colors => {
+ },
:author => {}
}
res.merge!(opt[:include]) if opt[:include]
:picture => {:artist => {}, :license => {}}
},
:speech_balloons => {:balloons => {}, :speeches => {}},
+ :ground_pictures => {
+ :picture => {:artist => {}, :license => {}}
+ },
+ :ground_colors => {
+ :color => {}
+ },
+ :panel_colors => {
+ },
:author => {}
}}
end
pe
end
+ def each_ground
+ (self.ground_colors || []) + (self.ground_pictures || []) + (self.panel_colors || []).each do |e|
+ yield e
+ end
+ end
+
def each_element
self.sort_by_time.each do |e|
yield e
res = []
self.each_element do |elm|
if elm.kind_of?(PanelPicture)
- res[elm.t] = elm.to_json({:include => :resource_picture})
+ res[elm.t] = elm.to_json({:include => {:picture => {:artist => {}, :license => {}}}})
end
if elm.kind_of?(SpeechBalloon)
res[elm.t] = elm.to_json({:include => {:balloons => {}, :speeches => {}}})
end
end
+ self.each_ground do |elm|
+ if elm.kind_of?(GroundColor)
+ res << elm.to_json({:include => :color})
+ end
+ if elm.kind_of?(GroundPicture)
+ res << elm.to_json({:include => {:picture => {:artist => {}, :license => {}}}})
+ end
+ if elm.kind_of?(PanelColor)
+ res << elm.to_json({:include => {}})
+ end
+ end
res
end
--- /dev/null
+class PanelColor < ActiveRecord::Base
+ belongs_to :panel
+
+ validates :panel_id, :numericality => {:allow_blank => true}
+ validates :z, :presence => true, :numericality => {:greater_than => 0}
+ validates :code, :presence => true, :numericality => {:greater_than_or_equal_to => 0, :less_than => 0x1000000}
+
+ def self.default_page_size
+ 25
+ end
+
+ def self.max_page_size
+ 100
+ end
+
+ def self.page prm = nil
+ page = prm.to_i
+ page = 1 if page < 1
+ page
+ end
+
+ def self.page_size prm = self.default_page_size
+ page_size = prm.to_i
+ page_size = self.max_page_size if page_size > self.max_page_size
+ page_size = self.default_page_size if page_size < 1
+ page_size
+ end
+
+ def self.offset cnt, prm = nil
+ offset = prm.to_i
+ offset = cnt - 1 if offset >= cnt
+ offset = cnt - offset.abs if offset < 0
+ offset = 0 if offset < 0
+ offset
+ end
+
+ def self.list opt = {}, page = 1, page_size = self.default_page_size
+ opt.merge!(self.list_opt) unless opt[:include]
+ opt.merge!({:conditions => 'panels.publish > 0', :order => 'panel_colors.updated_at desc', :limit => page_size, :offset => (page -1) * page_size})
+ PanelColor.find(:all, opt)
+ end
+
+ def self.list_opt
+ {:include => {:panel => {:author => {}} }}
+ end
+
+ def self.list_json_opt
+ {:include => {:panel => {:author => {}} }}
+ end
+
+ def self.mylist au, opt = {}, page = 1, panel_color_page_size = Author.default_panel_color_page_size
+ opt.merge!(self.list_opt) unless opt[:include]
+ opt.merge!({:conditions => ['panels.author_id = ?', au.id], :order => 'panel_colors.updated_at desc', :limit => page_size, :offset => (page -1) * panel_color_page_size})
+ PanelColor.find(:all, opt)
+ end
+
+end
belongs_to :picture
validates :panel_id, :numericality => {:allow_blank => true}
+ validates :picture_id, :numericality => true, :existence => true
validates :link, :length => {:maximum => 200}
validates :x, :presence => true, :numericality => true
validates :y, :presence => true, :numericality => true
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}
validates :license_id, :presence => true, :numericality => true, :existence => true
validates :artist_id, :presence => true, :numericality => true, :existence => true
validates :artist_name, :presence => true
"image/#{self.dext}"
end
+ def dext
+ self.ext.downcase
+ end
+
+ def url
+ '/pictures/' + filename
+ end
+
+ def self.list_by_md5 md5, opid
+ r = Picture.find :all, :conditions => ['pictures.md5 = ? and pictures.original_picture_id <> ?', md5, opid], :order => 'pictures.updated_at desc'
+ end
+
+ def self.exist_by_md5 md5, opid
+ Picture.list_by_md5(md5, opid).empty? ? false : true
+ end
+
+ def head?
+ r = self.resource_picture
+ r ? true : false
+ end
+
def new_revision
Picture.maximum(:revision, :conditions => ['original_picture_id = ?', self.original_picture_id]).to_i + 1
end
def copy_data(rp)
attr = {:width => rp.width, :height => rp.height, :ext => rp.ext, :filesize => rp.filesize,
:original_picture_id => rp.original_picture_id, :license_id => rp.license_id, :artist_id => rp.artist_id,
- :artist_name => rp.artist_name, :classname => rp.classname, :credit => rp.credit, :settings => rp.settings
+ :md5 => rp.md5, :artist_name => rp.artist_name, :classname => rp.classname, :credit => rp.credit, :settings => rp.settings
}
self.attributes = attr
end
end
def restore(subdir = nil)
- PictureIO.resource_picture_io.get self.filename, subdir
+ PictureIO.picture_io.get self.filename, subdir
end
def self.show pid
ResourcePicture.resize(rimg.to_blob, tw, th).to_blob
end
+ def opt_img_tag
+ tw, th = ResourcePicture.fix_size_both(MagicNumber['thumbnail_width'], MagicNumber['thumbnail_height'], self.width, self.height)
+ {:src => self.url, :width => tw, :height => th}
+ end
+
def copy_data(op)
attr = {:width => op.width, :height => op.height, :ext => op.ext, :filesize => op.filesize,
- :original_picture_id => op.id, :artist_id => op.artist_id
+ :original_picture_id => op.id, :artist_id => op.artist_id, :md5 => op.md5
}
self.attributes = attr
end
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
+ self.md5 = Digest::MD5.hexdigest(picture_data)
SystemPicture.transaction do
if res = self.save
res = PictureIO.system_picture_io.put(picture_data, self.filename)
<%= f.label :name %><br />
<%= f.text_field :name %><br />
- <%= f.label :default_license_id %><br />
- <%= f.number_field :default_license_id %>
</div>
<div class="actions">
<%= f.submit %>
<th>name</th>
<th>homepage_url</th>
<th>api_url</th>
- <th>default_license</th>
<th>crowled_at</th>
<th>author_id</th>
<th>created_at</th>
<td><%= h artist.name %></td>
<td><%= h artist.homepage_url %></td>
<td><%= h artist.api_url %></td>
- <td><%= link_to artist.default_license_id, :controller => 'licenses', :action => :browse, :id => artist.default_license_id %></td>
<td><%= artist.crowled_at %></td>
<td><%= link_to artist.author_id, :controller => 'authors', :action => :browse, :id => artist.author_id %></td>
<td><%= artist.created_at %></td>
--- /dev/null
+<h1>Listing Colors</h1>
+
+<table>
+ <tr>
+ <th>id</th>
+ <th>name</th>
+ <th>code</th>
+ <th>t</th>
+ </tr>
+
+<% @colors.each do |c| %>
+ <tr>
+ <td><%= c.id %></td>
+ <td><%= h c.name %></td>
+ <td><%= c.code %><font color="<%= c.code %>">*****</font></td>
+ <td><%= c.t %></td>
+ </tr>
+<% end -%>
+</table>
<%= f.text_field :title %>
</div>
<div class="field">
- <%= f.label :width %><br />
- <%= f.number_field :width %>
- </div>
- <div class="field">
- <%= f.label :height %><br />
- <%= f.number_field :height %>
- </div>
- <div class="field">
<%= f.label :visible %><br />
<%= f.collection_select :visible, [['only me', 0], ['everyone', 3]], :last, :first, :html => {:selected => @comic.visible} %>
</div>
</p>
<p>
- <b>width:</b>
- <%= @comic.width %>
-</p>
-
-<p>
- <b>height:</b>
- <%= @comic.height %>
-</p>
-
-<p>
<b>visible:</b>
<%= @comic.visible %>
</p>
<tr>
<th>id</th>
<th>Title</th>
- <th>width</th>
- <th>height</th>
<th>visible</th>
<th>author_id</th>
<th>created_at</th>
<tr>
<td><%= link_to comic.id, :action => :browse, :id => comic.id %></td>
<td><%= h comic.title %></td>
- <td><%= comic.width %></td>
- <td><%= comic.height %></td>
<td><%= comic.visible %></td>
<td><%= link_to comic.author_id, :controller => '/authors', :action => :browse, :id => comic.author_id %></td>
<td><%= comic.created_at %></td>
</p>
<p>
- <b>width:</b>
- <%= @comic.width %>
-</p>
-
-<p>
- <b>height:</b>
- <%= @comic.height %>
-</p>
-
-<p>
<b>visible:</b>
<%= @comic.visible %>
</p>
--- /dev/null
+<h1>Listing Ground Colors</h1>
+
+<table>
+ <tr>
+ <th>id</th>
+ <th>panel_id</th>
+ <th>color_id</th>
+ <th>z</th>
+ </tr>
+
+<% @ground_colors.each do |gc| %>
+ <tr>
+ <td><%= gc.id %></td>
+ <td><%= link_to gc.panel_id, panel_path(gc.panel_id) %></td>
+ <td><%= link_to gc.color_id, color_path(gc.color_id) %></td>
+ <td><%= gc.z %></td>
+ </tr>
+<% end -%>
+</table>
--- /dev/null
+<h1>Listing Ground Pictures</h1>
+
+<table>
+ <tr>
+ <th>id</th>
+ <th>panel_id</th>
+ <th>picture_id</th>
+ <th>z</th>
+ </tr>
+
+<% @ground_pictures.each do |gp| %>
+ <tr>
+ <td><%= gp.id %></td>
+ <td><%= link_to gp.panel_id, panel_path(gp.panel_id) %></td>
+ <td><%= link_to gp.picture_id, color_path(gp.picture_id) %></td>
+ <td><%= gp.z %></td>
+ </tr>
+<% end -%>
+</table>
<%= f.label :name %><br />
<%= f.text_field :name %><br />
- <p>素材をアップロードするときのデフォルトライセンスを選択します。</p>
- <%= f.label :default_license_id %><br />
- <%= f.select :default_license_id, License.all.map {|l| [l.name, l.id] }, :html => {:selected => @artist.default_license_id} %>
<%= f.hidden_field :author_id, :value => @artist.author_id %>
</div>
<div class="actions">
<head>
<title>Pettanr</title>
<%= stylesheet_link_tag "application" %>
- <%# javascript_include_tag "application" %>
+ <%= javascript_include_tag "application" %>
<%= csrf_meta_tags %>
</head>
<body>
<head>\r
<title>Pettanr</title>\r
<%= stylesheet_link_tag "application" %>\r
+ <%= javascript_include_tag "application" %>\r
<%= csrf_meta_tags %>\r
</head>\r
<body>\r
<%= link_to 'speeches', main_app.speeches_path %>\r
: \r
<%= link_to 'speech_balloon_templates', main_app.speech_balloon_templates_path %>\r
+<%= link_to 'colors', main_app.colors_path %>\r
: \r
<%= link_to 'artists', main_app.artists_path %>\r
<%= link_to 'system_pictures', main_app.system_pictures_path %>\r
<%= f.label :name %><br />
<%= f.text_field :name %><br />
- <%= f.label :default_license_id %><br />
- <%= f.number_field :default_license_id %>
<%= f.hidden_field :author_id, :value => @artist.author_id %>
</div>
<div class="actions">
--- /dev/null
+<% case exist -%>
+<% when true -%>
+ この画像は既に公開されています
+<% end -%>
--- /dev/null
+<% history.each do |picture| -%>
+ <h3>revision:<%= picture.revision %></h3>
+ <div>licensed at <%= picture.created_at %></div>
+ <img src="<%= picture.url -%>">
+ <%= render picture.credit_template, :picture => picture %>
+<% end -%>
<%= @original_picture.artist_id %>
</p>
+<p>
+ <b>md5:</b>
+ <%= @original_picture.md5 %>
+</p>
+
<img src="<%= @original_picture.url -%>">
<p>
<a href="<%= @original_picture.url %>">browse picture</a>
</p>
-<p>
-<%= link_to '再生成', :action => :refresh, :id => @original_picture.id %>
-</p>
<% if @original_picture.own? @author -%>
<p>
Replace picture
--- /dev/null
+History of Original Picture <%= @original_picture.id %>
+<%= render 'history_list', :history => @history %>
<table>
<tr>
<th>picture</th>
+ <th>revisions</th>
<th>filename</th>
<th>Width</th>
<th>Height</th>
<th>filesize</th>
+ <th>md5</th>
+ <th>history</th>
</tr>
<% @original_pictures.each do |original_picture| %>
<div>
</div>
<tr>
<td>
- <%= link_to tag(:img, :src => original_picture.url, :width => 50, :height => 50), original_picture %>
+ <%= link_to tag(:img, original_picture.opt_img_tag), original_picture %>
</td>
+ <td><%= original_picture.pictures.empty? ? '' : original_picture.history.first.revision %></td>
<td><%= original_picture.filename %></td>
<td><%= original_picture.width %></td>
<td><%= original_picture.height %></td>
<td><%= original_picture.filesize %></td>
+ <td><%= original_picture.md5 %></td>
+ <td><%= link_to '...', :controller => 'original_pictures', :action => :history, :id => original_picture.id %></td>
</tr>
<% end %>
</table>
<th>Height</th>
<th>filesize</th>
<th>artist</th>
+ <th>md5</th>
<th>created_at</th>
<th>updated_at</th>
<th></th>
<td><%= original_picture.height %></td>
<td><%= original_picture.filesize %></td>
<td><%= link_to original_picture.artist_id, :controller => 'artists', :action => :browse, :id => original_picture.artist_id %></td>
+ <td><%= original_picture.md5 %></td>
<td><%= original_picture.created_at %></td>
<td><%= original_picture.updated_at %></td>
<td>
+<%= render 'exist', :exist => Picture.exist_by_md5(@original_picture.md5, @original_picture.id) %>
<p id="notice"><%= notice %></p>
<p>
</p>
<p>
+ <b>md5:</b>
+ <%= @original_picture.md5 %>
+</p>
+
+<p>
<b>artist:</b>
<%= @original_picture.artist_id %>
</p>
<%= f.submit 'replace' %>
</div>
<% end %>
+<div>
+ <p>
+ History
+ </p>
+ <%= render 'history_list', :history => @original_picture.history %>
+</div>
<%= link_to 'Back', original_pictures_path %>
--- /dev/null
+<h1>Listing Panel Colors</h1>
+
+<table>
+ <tr>
+ <th>id</th>
+ <th>panel_id</th>
+ <th>code</th>
+ <th>z</th>
+ </tr>
+
+<% @panel_colors.each do |pc| %>
+ <tr>
+ <td><%= pc.id %></td>
+ <td><%= link_to pc.panel_id, panel_path(pc.panel_id) %></td>
+ <td><%= pc.code %><font color="<%= pc.code %>">*****</font></td>
+ <td><%= pc.z %></td>
+ </tr>
+<% end -%>
+</table>
--- /dev/null
+<img src="<%= picture.url -%>">
+<%= render picture.credit_template, :picture => picture %>
+<div>revision:<%= picture.revision %></div>
--- /dev/null
+この画像は既に改訂されています <%= link_to 'Head', resource_picture_path(picture.resource_picture ) %>
+<div>revision:<%= picture.revision %></div>
--- /dev/null
+<p>
+ <b>Ext:</b>
+ <%= @original_picture.ext %>
+</p>
+
+<p>
+ <b>Width:</b>
+ <%= @original_picture.width %>
+</p>
+
+<p>
+ <b>Height:</b>
+ <%= @original_picture.height %>
+</p>
+
+<p>
+ <b>filesize:</b>
+ <%= @original_picture.filesize %>
+</p>
+
+<p>
+ <b>md5:</b>
+ <%= @original_picture.md5 %>
+</p>
+
+<p>
+ <b>artist:</b>
+ <%= @original_picture.artist_id %>
+</p>
+
+<% if @picture.head? %>
+ <%= render 'head', :picture => @picture %>
+<% else %>
+ <%= render 'tail', :picture => @picture %>
+<% end %>
+
<% @resource_picture = resource_picture %>
<div>
<%= link_to resource_picture.filename, resource_picture_path(resource_picture) %>
- <%= tag :img, :src => resource_picture.url, :width => MagicNumber['thumbnail_width'], :height => MagicNumber['thumbnail_height'] %>
+ <%= tag :img, resource_picture.opt_img_tag %>
<%= resource_picture.width %>x<%= resource_picture.height %>
<%= resource_picture.filesize %>bytes
<%= render resource_picture.credit_template, :picture => resource_picture %>
<p id="notice"><%= notice %></p>
-<%= render @resource_picture.credit_template, :picture => @resource_picture %>
-<p>
- <a href="<%= @resource_picture.url %>">ノーマル</a>
- <img src="<%= @resource_picture.url -%>">
-</p>
-<p>
- <a href="<%= @resource_picture.url :thumbnail%>">サムネ</a>
- <img src="<%= @resource_picture.url :full -%>">
-</p>
+ <%= render 'pictures/head', :picture => @resource_picture.picture %>
<%= link_to 'Back', resource_pictures_path %>
<%= link_to 'speeches', :controller => 'speeches', :action => :list %>
</td>
</tr>
+ <tr>
+ <td>
+ <%= link_to 'colors', :controller => 'colors' %>
+ </td>
+ </tr>
</table>
フキダシテンプレート関連
<table>
# Load the rails application
require File.expand_path('../application', __FILE__)
-begin
- require 'RMagick'
-rescue LoadError
- require 'DMagick'
-end
+require 'RMagick'
# Initialize the rails application
Pettanr::Application.initialize!
collection do
get :index
get :show
+ get :history
post :create
get :list
get :browse
post :create
end
end
+ resources :colors do
+ collection do
+ get :index
+ end
+ member do
+ end
+ end
+ resources :panel_colors do
+ collection do
+ get :index
+ end
+ member do
+ end
+ end
+ resources :ground_colors do
+ collection do
+ get :index
+ end
+ member do
+ end
+ end
+ resources :ground_pictures do
+ collection do
+ get :index
+ end
+ member do
+ end
+ end
resources :panels do
new do
get :new
--- /dev/null
+{\r
+ "white": {\r
+ "code": 255,\r
+ "t": 0\r
+ },\r
+ "black": {\r
+ "code": 0,\r
+ "t": 1\r
+ }\r
+}\r
--- /dev/null
+class AddMd5 < ActiveRecord::Migration
+ def up
+ add_column :original_pictures, :md5, :string, :null => false, :limit => 32, :default => '00000000000000000000000000000000'
+ add_column :pictures, :md5, :string, :null => false, :limit => 32, :default => '00000000000000000000000000000000'
+ add_column :resource_pictures, :md5, :string, :null => false, :limit => 32, :default => '00000000000000000000000000000000'
+ end
+
+ def down
+ remove_column :original_pictures, :md5
+ remove_column :pictures, :md5
+ remove_column :resource_pictures, :md5
+ end
+end
--- /dev/null
+class RmDefaultLsOnArtist < ActiveRecord::Migration
+ def up
+ remove_column :artists, :default_license_id
+ end
+
+ def down
+ remove_column :artists, :default_license_id, :integer , :null => false, :default => 0
+ end
+end
--- /dev/null
+class RmDefaultSizeOnComic < ActiveRecord::Migration
+ def up
+ remove_column :comics, :width
+ remove_column :comics, :height
+ end
+
+ def down
+ add_column :comics, :width, :integer , :null => false, :default => 0
+ add_column :comics, :height, :integer , :null => false, :default => 0
+ end
+end
--- /dev/null
+class CreateColors < ActiveRecord::Migration
+ def change
+ create_table :colors do |t|
+ t.string :name, :null => false, :limit => 50, :default => 'no name'
+ t.integer :code, :null => false, :default => 0
+ t.integer :t, :null => false, :default => 0
+
+ t.timestamps
+ end
+ end
+end
--- /dev/null
+class CreateGroundColors < ActiveRecord::Migration
+ def change
+ create_table :ground_colors do |t|
+ t.integer :panel_id, :null => false, :default => 0
+ t.integer :color_id, :null => false, :default => 0
+ t.integer :author_id, :null => false, :default => 0
+ t.integer :z, :null => false, :default => 0
+
+ t.timestamps
+ end
+ end
+end
--- /dev/null
+class CreatePanelColors < ActiveRecord::Migration
+ def change
+ create_table :panel_colors do |t|
+ t.integer :panel_id, :null => false, :default => 0
+ t.integer :z, :null => false, :default => 0
+ t.integer :code, :null => false, :default => 0
+
+ t.timestamps
+ end
+ end
+end
--- /dev/null
+class CreateGroundPictures < ActiveRecord::Migration
+ def change
+ create_table :ground_pictures do |t|
+ t.integer :panel_id, :null => false, :default => 0
+ t.integer :picture_id, :null => false, :default => 0
+ t.integer :z, :null => false, :default => 0
+
+ t.timestamps
+ end
+ end
+end
--- /dev/null
+namespace :licenses do
+ desc "Import json format license data in license engine"
+ task :import => :environment do
+ licenses = YAML.load(open(Rails.root + 'config/license.yml').read)
+ licenses.each do |name, klass|
+ puts name + "\n"
+ system 'rake ' + name + ':import'
+ end
+ end
+
+ desc "Copy migration file for license "
+ task :install => :environment do
+ licenses = YAML.load(open(Rails.root + 'config/license.yml').read)
+ licenses.each do |name, klass|
+ puts name + "\n"
+ system 'rake ' + name + ':install:migrations'
+ end
+ puts "run 'rake db:migrate' if you can migrate database\n"
+ end
+end
class ResizeValidator < ActiveModel::EachValidator\r
def validate_each(record, attribute, value)\r
- if record.picture.flag_resize < 0\r
+ if record.picture and record.picture.flag_resize < 0\r
record.errors[attribute] << (options[:message] || "no resize") unless value == record.picture[attribute]\r
end\r
end\r
class ReverseValidator < ActiveModel::EachValidator\r
def validate_each(record, attribute, value)\r
- if record.picture.flag_reverse < 0\r
+ if record.picture and record.picture.flag_reverse < 0\r
record.errors[attribute] << (options[:message] || "no reverse") if value < 0\r
end\r
end\r
class SyncVhValidator < ActiveModel::EachValidator\r
def validate_each(record, attribute, value)\r
- if record.picture.flag_sync_vh < 0\r
+ if record.picture and record.picture.flag_sync_vh < 0\r
record.errors[attribute] << (options[:message] || "sync_vh") unless sync?(record)\r
end\r
end\r
--- /dev/null
+#ライセンスのgemファイルを作るサポートツール\r
+#Yamlファイルからコンバートする\r
+if ARGV.size < 1\r
+ puts "gem_builder.rb dir"\r
+ puts "build to gem on child dirs"\r
+ exit\r
+end\r
+\r
+dirname = File.expand_path ARGV[0]\r
+Dir.glob dirname + '/*' do |filename|\r
+ if File.directory?(filename)\r
+ fn = Dir.glob(filename + '/*.gemspec').first\r
+ c = "gem build " + fn\r
+ Dir.chdir filename do\r
+ puts c\r
+ system c\r
+ end\r
+ gem = Dir.glob(filename + '/*.gem').sort.last\r
+ c = "gem install " + gem\r
+ puts c\r
+ system c\r
+ end\r
+end\r
--- /dev/null
+#ライセンスのjsonファイルを作るサポートツール\r
+#Yamlファイルからコンバートする\r
+if ARGV.size < 1\r
+ puts "ls_helper.rb ls.yml [work dir=current dir]"\r
+ puts "generate to ls.json"\r
+ exit\r
+end\r
+\r
+require 'yaml'\r
+require 'json'\r
+require 'base64'\r
+\r
+filename = ARGV[0]\r
+lg = YAML.load(open(filename).read)\r
+fn = File.basename filename, ".*"\r
+wd = ARGV[1] ? File.expand_path(ARGV[1]) : File.dirname(filename)\r
+o = wd + '/' + fn + '.json'\r
+\r
+lg.each do |k, g|\r
+ puts k\r
+ g['licenses_attributes'].each do |lk, l|\r
+ puts lk\r
+ if l['settings']\r
+ puts 'settings to json'\r
+ l['settings'] = l['settings'].to_json.to_s\r
+ end\r
+ if l['system_picture_file']\r
+ fn = File.expand_path(wd + '/' + l['system_picture_file'])\r
+ puts 'open system picture file ' + fn\r
+ d = File.open(fn, 'rb').read\r
+ b = Base64.encode64(d).gsub(/\r/, '').gsub(/\n/, '')\r
+ l['system_picture'] = b\r
+ l.delete 'system_picture_file'\r
+ end\r
+ end\r
+end\r
+puts "generating " + o\r
+File.open(o, 'wb') do |f|\r
+ f.write lg.to_json.to_s\r
+end\r
"publish": 1,\r
"panel_pictures_attributes": {\r
"new1": {\r
- "resource_picture_id": 3,\r
+ "picture_id": 3,\r
"x": 10,\r
"y": 135,\r
"z": 3,\r
"width": 100,\r
"height": 103\r
}\r
+ },\r
+ "ground_pictures_attributes": {\r
+ "new1": {\r
+ "picture_id": 1,\r
+ "z": 1\r
+ }\r
+ },\r
+ "ground_colors_attributes": {\r
+ "new1": {\r
+ "color_id": 1,\r
+ "z": 1\r
+ }\r
+ },\r
+ "panel_colors_attributes": {\r
+ "new1": {\r
+ "code": 1,\r
+ "z": 1\r
+ }\r
}\r
},\r
- "auth_token": "vX7rc33zxVJSQPKjp2vc"\r
+ "auth_token": "3d3Fvz9RafTPcpzLrYSW"\r
}
\ No newline at end of file
--- /dev/null
+# -*- encoding: utf-8 -*-
+require 'spec_helper'
+#色マスター
+
+describe ColorsController do
+ before do
+ @admin = FactoryGirl.create :admin
+ @user = FactoryGirl.create( :user_yas)
+ @sp = FactoryGirl.create :system_picture
+ @lg = FactoryGirl.create :license_group, :name => 'peta'
+ @license = FactoryGirl.create :license, :license_group_id => @lg.id, :system_picture_id => @sp.id
+ end
+
+ describe '一覧表示に於いて' do
+ before do
+ sign_in @user
+ @color = FactoryGirl.create :color
+ Color.stub(:list).and_return([@color, @color, @color])
+ end
+ context 'パラメータpageについて' do
+ it '@pageに値が入る' do
+ get :index, :page => 5
+ assigns(:page).should eq 5
+ end
+ it '省略されると@pageに1値が入る' do
+ get :index
+ assigns(:page).should eq 1
+ end
+ it '与えられたpage_sizeがセットされている' do
+ get :index, :page_size => 15
+ assigns(:page_size).should eq 15
+ end
+ it '省略されると@page_sizeにデフォルト値が入る' do
+ get :index
+ assigns(:page_size).should eq Color.default_page_size
+ end
+ it '最大を超えると@page_sizeにデフォルト最大値が入る' do
+ get :index, :page_size => 1500
+ assigns(:page_size).should eq Color.max_page_size
+ end
+ it '不正な値が入ると@page_sizeにデフォルト最大値が入る' do
+ get :index, :page_size => 0
+ assigns(:page_size).should eq Color.default_page_size
+ end
+ end
+ context 'つつがなく終わるとき' do
+ it 'ステータスコード200 OKを返す' do
+ get :index
+ response.should be_success
+ end
+ it '色モデルに一覧を問い合わせている' do
+ Color.should_receive(:list).exactly(1)
+ get :index
+ end
+ it '@colorsにリストを取得している' do
+ get :index
+ assigns(:colors).should have_at_least(3).items
+ end
+ context 'html形式' do
+ it 'indexテンプレートを描画する' do
+ get :index
+ response.should render_template("index")
+ end
+ end
+ context 'json形式' do
+ it 'jsonデータを返す' do
+ get :index, :format => :json
+ lambda{JSON.parse(response.body)}.should_not raise_error(JSON::ParserError)
+ end
+ it 'データがリスト構造になっている' do
+ get :index, :format => :json
+ json = JSON.parse response.body
+ json.should have_at_least(3).items
+ end
+ it 'リストの先頭くらいは色っぽいものであって欲しい' do
+ get :index, :format => :json
+ json = JSON.parse response.body
+ json.first.has_key?("name").should be_true
+ json.first.has_key?("code").should be_true
+ json.first.has_key?("t").should be_true
+ end
+ end
+ end
+ context '作家権限がないとき' do
+ before do
+ sign_out @user
+ end
+ it 'ステータスコード200 okを返す' do
+ get :index
+ response.status.should eq 200
+ end
+ end
+ end
+
+end
# -*- encoding: utf-8 -*-\r
-require 'spec_helper'
-
-describe ComicsController do
- before do
- FactoryGirl.create :admin
- @sp = FactoryGirl.create :system_picture
- @lg = FactoryGirl.create :license_group
- @license = FactoryGirl.create :license, :license_group_id => @lg.id, :system_picture_id => @sp.id
+require 'spec_helper'\r
+\r
+describe ComicsController do\r
+ before do\r
+ FactoryGirl.create :admin\r
+ @sp = FactoryGirl.create :system_picture\r
+ @lg = FactoryGirl.create :license_group\r
+ @license = FactoryGirl.create :license, :license_group_id => @lg.id, :system_picture_id => @sp.id\r
@user = FactoryGirl.create :user_yas\r
@author = @user.author #ユーザ作成時に連動して作成される\r
end\r
before do\r
@comic = FactoryGirl.create :comic, :author_id => @user.author.id\r
sign_in @user\r
- Comic.stub(:show).and_return(@comic)\r
+ Comic.stub(:edit).and_return(@comic)\r
end\r
context 'つつがなく終わるとき' do\r
it 'ステータスコード200 OKを返す' do\r
get :edit, :id => @comic.id\r
response.should be_success \r
end\r
- it 'コミックモデルに単体取得を問い合わせている' do\r
- Comic.should_receive(:show).exactly(1)\r
+ it 'コミックモデルに編集取得を問い合わせている' do\r
+ Comic.should_receive(:edit).exactly(1)\r
get :edit, :id => @comic.id\r
end\r
it '@comicにデータを用意している' do\r
sign_in @user\r
end\r
context '事前チェックしておく' do\r
- it 'コミックモデルに単体取得を問い合わせている' do\r
- Comic.stub(:show).with(any_args()).and_return @comic\r
- Comic.should_receive(:show).exactly(1)\r
+ it 'コミックモデルに編集取得を問い合わせている' do\r
+ Comic.stub(:edit).with(any_args()).and_return @comic\r
+ Comic.should_receive(:edit).exactly(1)\r
put :update, :id => @comic.id, :comic => @attr\r
end\r
it 'モデルに更新を依頼する' do\r
- Comic.any_instance.should_receive(:update_attributes).with(any_args)\r
+ Comic.any_instance.stub(:save).with(any_args).and_return true\r
+ Comic.any_instance.should_receive(:save).exactly(1)\r
put :update, :id => @comic.id, :comic => @attr\r
end\r
it '@comicにアレを取得している' do\r
end\r
context 'html形式' do\r
it 'ステータスコード302 Foundを返す' do\r
- Comic.any_instance.stub(:update_attributes).with(any_args()).and_return(true)\r
+ Comic.any_instance.stub(:save).with(any_args()).and_return(true)\r
put :update, :id => @comic.id, :comic => @attr\r
response.status.should eq 302\r
end\r
end\r
context 'json形式' do\r
it 'ステータスコード200 OKを返す' do\r
- Comic.any_instance.stub(:update_attributes).with(any_args()).and_return(true)\r
+ Comic.any_instance.stub(:save).with(any_args()).and_return(true)\r
put :update, :id => @comic.id, :comic => @attr, :format => :json\r
response.should be_success \r
end\r
it 'ページ本体は特に返さない' do\r
- Comic.any_instance.stub(:update_attributes).with(any_args()).and_return(true)\r
+ Comic.any_instance.stub(:save).with(any_args()).and_return(true)\r
put :update, :id => @comic.id, :comic => @attr, :format => :json\r
response.body.should match /./\r
end\r
end\r
context '検証、保存に失敗したとき' do\r
before do\r
- Comic.any_instance.stub(:update_attributes).and_return(false)\r
+ Comic.any_instance.stub(:save).and_return(false)\r
end\r
context 'html形式' do\r
it 'ステータスコード200 Okを返す' do\r
end\r
context 'json形式' do\r
it 'ステータスコード422 unprocessable_entity を返す' do\r
- Comic.any_instance.stub(:update_attributes).and_return(false)\r
+ Comic.any_instance.stub(:save).and_return(false)\r
put :update, :id => @comic.id, :comic => @attr, :format => :json\r
response.status.should eq 422\r
end\r
--- /dev/null
+# -*- encoding: utf-8 -*-
+require 'spec_helper'
+#コマの間接背景
+
+describe GroundColorsController do
+ before do
+ @admin = FactoryGirl.create :admin
+ @user = FactoryGirl.create( :user_yas)
+ @sp = FactoryGirl.create :system_picture
+ @lg = FactoryGirl.create :license_group, :name => 'peta'
+ @license = FactoryGirl.create :license, :license_group_id => @lg.id, :system_picture_id => @sp.id
+ @author = @user.author
+ @artist = FactoryGirl.create :artist_yas, :author_id => @author.id
+ @panel = FactoryGirl.create :panel, :author_id => @author.id
+ @color = FactoryGirl.create :color
+ end
+
+ describe '一覧表示に於いて' do
+ before do
+ sign_in @user
+ @gc = FactoryGirl.create :ground_color
+ GroundColor.stub(:list).and_return([@gc, @gc, @gc])
+ end
+ context 'パラメータpageについて' do
+ it '@pageに値が入る' do
+ get :index, :page => 5
+ assigns(:page).should eq 5
+ end
+ it '省略されると@pageに1値が入る' do
+ get :index
+ assigns(:page).should eq 1
+ end
+ it '与えられたpage_sizeがセットされている' do
+ get :index, :page_size => 15
+ assigns(:page_size).should eq 15
+ end
+ it '省略されると@page_sizeにデフォルト値が入る' do
+ get :index
+ assigns(:page_size).should eq GroundColor.default_page_size
+ end
+ it '最大を超えると@page_sizeにデフォルト最大値が入る' do
+ get :index, :page_size => 1500
+ assigns(:page_size).should eq GroundColor.max_page_size
+ end
+ it '不正な値が入ると@page_sizeにデフォルト最大値が入る' do
+ get :index, :page_size => 0
+ assigns(:page_size).should eq GroundColor.default_page_size
+ end
+ end
+ context 'つつがなく終わるとき' do
+ it 'ステータスコード200 OKを返す' do
+ get :index
+ response.should be_success
+ end
+ it '間接背景モデルに一覧を問い合わせている' do
+ GroundColor.should_receive(:list).exactly(1)
+ get :index
+ end
+ it '@ground_colorsにリストを取得している' do
+ get :index
+ assigns(:ground_colors).should have_at_least(3).items
+ end
+ context 'html形式' do
+ it 'indexテンプレートを描画する' do
+ get :index
+ response.should render_template("index")
+ end
+ end
+ context 'json形式' do
+ it 'jsonデータを返す' do
+ get :index, :format => :json
+ lambda{JSON.parse(response.body)}.should_not raise_error(JSON::ParserError)
+ end
+ it 'データがリスト構造になっている' do
+ get :index, :format => :json
+ json = JSON.parse response.body
+ json.should have_at_least(3).items
+ end
+ it 'リストの先頭くらいは間接背景っぽいものであって欲しい' do
+ get :index, :format => :json
+ json = JSON.parse response.body
+ json.first.has_key?("panel").should be_true
+ json.first.has_key?("color_id").should be_true
+ json.first.has_key?("z").should be_true
+ end
+ end
+ end
+ context '作家権限がないとき' do
+ before do
+ sign_out @user
+ end
+ context 'html形式' do
+ it 'ステータスコード302 Foundを返す' do
+ get :index
+ response.status.should eq 302
+ end
+ it 'サインインページへ遷移する' do
+ get :index
+ response.should redirect_to '/users/sign_in'
+ end
+ end
+ context 'json形式' do
+ it 'ステータスコード401 Unauthorizedを返す' do
+ get :index, :format => :json
+ response.status.should eq 401
+ end
+ it '応答メッセージにUnauthorizedを返す' do
+ get :index, :format => :json
+ response.message.should match(/Unauthorized/)
+ end
+ end
+ end
+ end
+
+end
--- /dev/null
+# -*- encoding: utf-8 -*-
+require 'spec_helper'
+#コマの画像背景
+
+describe GroundPicturesController do
+ before do
+ @admin = FactoryGirl.create :admin
+ @user = FactoryGirl.create( :user_yas)
+ @sp = FactoryGirl.create :system_picture
+ @lg = FactoryGirl.create :license_group, :name => 'peta'
+ @license = FactoryGirl.create :license, :license_group_id => @lg.id, :system_picture_id => @sp.id
+ @author = @user.author
+ @artist = FactoryGirl.create :artist_yas, :author_id => @author.id
+ @op = FactoryGirl.create :original_picture, :artist_id => @artist.id
+ @p = FactoryGirl.create :picture, :original_picture_id => @op.id, :license_id => @license.id, :artist_id => @artist.id
+ @rp = FactoryGirl.create :resource_picture, :artist_id => @artist.id, :license_id => @license.id, :original_picture_id => @op.id, :picture_id => @p.id
+ @panel = FactoryGirl.create :panel, :author_id => @author.id
+ end
+
+ describe '一覧表示に於いて' do
+ before do
+ sign_in @user
+ @gp = FactoryGirl.create :ground_picture, :panel_id => @panel.id, :picture_id => @p.id
+ GroundPicture.stub(:list).and_return([@gp, @gp, @gp])
+ end
+ context 'パラメータpageについて' do
+ it '@pageに値が入る' do
+ get :index, :page => 5
+ assigns(:page).should eq 5
+ end
+ it '省略されると@pageに1値が入る' do
+ get :index
+ assigns(:page).should eq 1
+ end
+ it '与えられたpage_sizeがセットされている' do
+ get :index, :page_size => 15
+ assigns(:page_size).should eq 15
+ end
+ it '省略されると@page_sizeにデフォルト値が入る' do
+ get :index
+ assigns(:page_size).should eq GroundPicture.default_page_size
+ end
+ it '最大を超えると@page_sizeにデフォルト最大値が入る' do
+ get :index, :page_size => 1500
+ assigns(:page_size).should eq GroundPicture.max_page_size
+ end
+ it '不正な値が入ると@page_sizeにデフォルト最大値が入る' do
+ get :index, :page_size => 0
+ assigns(:page_size).should eq GroundPicture.default_page_size
+ end
+ end
+ context 'つつがなく終わるとき' do
+ it 'ステータスコード200 OKを返す' do
+ get :index
+ response.should be_success
+ end
+ it 'コマの画像背景モデルに一覧を問い合わせている' do
+ GroundPicture.should_receive(:list).exactly(1)
+ get :index
+ end
+ it '@ground_picturesにリストを取得している' do
+ get :index
+ assigns(:ground_pictures).should have_at_least(3).items
+ end
+ context 'html形式' do
+ it 'indexテンプレートを描画する' do
+ get :index
+ response.should render_template("index")
+ end
+ end
+ context 'json形式' do
+ it 'jsonデータを返す' do
+ get :index, :format => :json
+ lambda{JSON.parse(response.body)}.should_not raise_error(JSON::ParserError)
+ end
+ it 'データがリスト構造になっている' do
+ get :index, :format => :json
+ json = JSON.parse response.body
+ json.should have_at_least(3).items
+ end
+ it 'リストの先頭くらいは画像背景っぽいものであって欲しい' do
+ get :index, :format => :json
+ json = JSON.parse response.body
+ json.first.has_key?("panel_id").should be_true
+ json.first.has_key?("picture_id").should be_true
+ json.first.has_key?("z").should be_true
+ end
+ end
+ end
+ context '作家権限がないとき' do
+ before do
+ sign_out @user
+ end
+ context 'html形式' do
+ it 'ステータスコード302 Foundを返す' do
+ get :index
+ response.status.should eq 302
+ end
+ it 'サインインページへ遷移する' do
+ get :index
+ response.should redirect_to '/users/sign_in'
+ end
+ end
+ context 'json形式' do
+ it 'ステータスコード401 Unauthorizedを返す' do
+ get :index, :format => :json
+ response.status.should eq 401
+ end
+ it '応答メッセージにUnauthorizedを返す' do
+ get :index, :format => :json
+ response.message.should match(/Unauthorized/)
+ end
+ end
+ end
+ end
+
+end
end
it '省略されると@page_sizeにデフォルト値が入る' do
get :index
- assigns(:page_size).should eq OriginalPicture.default_page_size\r
+ assigns(:page_size).should eq OriginalPicture.default_page_size
end
it '最大を超えると@page_sizeにデフォルト最大値が入る' do
get :index, :page_size => 1500
response.should be_success
end
it '原画モデルに一覧を問い合わせている' do
- OriginalPicture.should_receive(:list).exactly(1)\r
+ OriginalPicture.should_receive(:list).exactly(1)
get :index
end
it '@original_picturesにリストを取得している' do
response.should be_success
end
it '原画モデルに単体取得を問い合わせている' do
- OriginalPicture.should_receive(:show).exactly(1)\r
+ OriginalPicture.should_receive(:show).exactly(1)
get :show
end
it '@original_pictureにアレを取得している' do
#スタブをおいてsend_dataがデータを返す体裁でテストする。
context 'png形式' do
it '画像モデルに画像データを問い合わせる' do
- OriginalPicture.any_instance.should_receive(:restore).exactly(1)\r
+ OriginalPicture.any_instance.should_receive(:restore).exactly(1)
get :show, :id => @pic.id, :format => :png
end
it '画像を送信する' do
- OriginalPicture.any_instance.stub(:restore).and_return('aaa')\r
+ OriginalPicture.any_instance.stub(:restore).and_return('aaa')
get :show, :id => @pic.id, :format => :png
response.body.should eq 'aaa'
end
end
context 'gif形式' do
it '画像モデルに画像データを問い合わせる' do
- OriginalPicture.any_instance.should_receive(:restore).exactly(1)\r
+ OriginalPicture.any_instance.should_receive(:restore).exactly(1)
get :show, :id => @pic.id, :format => :gif
end
it '画像を送信する' do
- OriginalPicture.any_instance.stub(:restore).and_return('bbb')\r
+ OriginalPicture.any_instance.stub(:restore).and_return('bbb')
get :show, :id => @pic.id, :format => :gif
response.body.should eq 'bbb'
end
end
context 'jpeg形式' do
it '画像モデルに画像データを問い合わせる' do
- OriginalPicture.any_instance.should_receive(:restore).exactly(1)\r
+ OriginalPicture.any_instance.should_receive(:restore).exactly(1)
get :show, :id => @pic.id, :format => :jpeg
end
it '画像を送信する' do
- OriginalPicture.any_instance.stub(:restore).and_return('ccc')\r
+ OriginalPicture.any_instance.stub(:restore).and_return('ccc')
get :show, :id => @pic.id, :format => :jpeg
response.body.should eq 'ccc'
end
=end
end
+ describe '履歴一覧表示に於いて' do
+ before do
+ @op = FactoryGirl.create :original_picture, :artist_id => @artist.id
+ @p = FactoryGirl.create :picture, :artist_id => @artist.id, :license_id => @license.id, :revision => 0,
+ :original_picture_id => @op.id
+ sign_in @user
+ OriginalPicture.stub(:show).and_return(@op)
+ OriginalPicture.any_instance.stub(:history).and_return([@p, @p, @p])
+ end
+ context 'つつがなく終わるとき' do
+ it 'ステータスコード200 OKを返す' do
+ get :history, :id => @op.id
+ response.should be_success
+ end
+ it '原画モデルに単体取得を問い合わせている' do
+ OriginalPicture.should_receive(:show).exactly(1)
+ get :history, :id => @op.id
+ end
+ it '自身に履歴一覧を問い合わせている' do
+ OriginalPicture.any_instance.should_receive(:history).exactly(1)
+ get :history
+ end
+ it '@historyにリストを取得している' do
+ get :history, :id => @op.id
+ assigns(:history).should have_at_least(3).items
+ end
+ context 'html形式' do
+ it 'historyテンプレートを描画する' do
+ get :history, :id => @op.id
+ response.should render_template("history")
+ end
+ end
+ context 'json形式' do
+ it 'jsonデータを返す' do
+ get :history, :id => @op.id, :format => :json
+ lambda{JSON.parse(response.body)}.should_not raise_error(JSON::ParserError)
+ end
+ it 'データがリスト構造になっている' do
+ get :history, :id => @op.id, :format => :json
+ json = JSON.parse response.body
+ json.should have_at_least(3).items
+ end
+ it 'リストの先頭くらいは原画っぽいものであって欲しい' do
+ get :history, :id => @op.id, :format => :json
+ json = JSON.parse response.body
+ json.first.has_key?("ext").should be_true
+ end
+ end
+ end
+ context '作家権限がないとき' do
+ before do
+ sign_out @user
+ end
+ context 'html形式' do
+ it 'ステータスコード302 Foundを返す' do
+ get :history, :id => @op.id
+ response.status.should eq 302
+ end
+ it 'サインインページへ遷移する' do
+ get :history, :id => @op.id
+ response.should redirect_to '/users/sign_in'
+ end
+ end
+ context 'json形式' do
+ it 'ステータスコード401 Unauthorizedを返す' do
+ get :history, :id => @op.id, :format => :json
+ response.status.should eq 401
+ end
+ it '応答メッセージにUnauthorizedを返す' do
+ get :history, :id => @op.id, :format => :json
+ response.message.should match(/Unauthorized/)
+ end
+ end
+ end
+ context '作家が絵師でないとき' do
+ before do
+ Author.any_instance.stub(:artist?).and_return(false)
+ end
+ context 'html形式' do
+ it 'ステータスコード302 Foundを返す' do
+ get :history, :id => @op.id
+ response.status.should eq 302
+ end
+ it '絵師登録ページへ遷移する' do
+ get :history, :id => @op.id
+ response.should redirect_to new_artist_path
+ end
+ end
+ context 'json形式' do
+ it '例外403 forbiddenを返す' do
+ lambda{
+ get :history, :id => @op.id, :format => :json
+ }.should raise_error(ActiveRecord::Forbidden)
+ end
+ end
+ end
+ end
+
describe '新規作成フォーム表示に於いて' do
before do
sign_in @user
assigns(:original_picture).should be_a_new(OriginalPicture)
end
it '原画モデルにデフォルト値補充を依頼している' do
- OriginalPicture.any_instance.should_receive(:supply_default).exactly(1)\r
+ OriginalPicture.any_instance.should_receive(:supply_default).exactly(1)
get :new
end
context 'html形式' do
get :edit, :id => @pic.id
response.should be_success
end
- it '原画モデルに単体取得を問い合わせている' do
- OriginalPicture.should_receive(:show).exactly(1)\r
+ it '原画モデルに編集取得を問い合わせている' do
+ OriginalPicture.should_receive(:edit).exactly(1)
get :edit, :id => @pic.id
end
it '@original_pictureにデータを用意している' do
OriginalPicture.any_instance.stub(:store).with(any_args()).and_return(true)
end
it '原画モデルに単体取得を問い合わせている' do
- OriginalPicture.should_receive(:edit).exactly(1)\r
+ OriginalPicture.should_receive(:edit).exactly(1)
put :update, :id => @pic.id, :original_picture => FactoryGirl.attributes_for(:original_picture)
end
it 'モデルに更新を依頼する' do
--- /dev/null
+# -*- encoding: utf-8 -*-
+require 'spec_helper'
+#コマの色背景
+
+describe PanelColorsController do
+ before do
+ @admin = FactoryGirl.create :admin
+ @user = FactoryGirl.create( :user_yas)
+ @sp = FactoryGirl.create :system_picture
+ @lg = FactoryGirl.create :license_group, :name => 'peta'
+ @license = FactoryGirl.create :license, :license_group_id => @lg.id, :system_picture_id => @sp.id
+ @author = @user.author
+ @artist = FactoryGirl.create :artist_yas, :author_id => @author.id
+ @panel = FactoryGirl.create :panel, :author_id => @author.id
+ end
+
+ describe '一覧表示に於いて' do
+ before do
+ sign_in @user
+ @pc = FactoryGirl.create :panel_color, :panel_id => @panel.id
+ PanelColor.stub(:list).and_return([@pc, @pc, @pc])
+ end
+ context 'パラメータpageについて' do
+ it '@pageに値が入る' do
+ get :index, :page => 5
+ assigns(:page).should eq 5
+ end
+ it '省略されると@pageに1値が入る' do
+ get :index
+ assigns(:page).should eq 1
+ end
+ it '与えられたpage_sizeがセットされている' do
+ get :index, :page_size => 15
+ assigns(:page_size).should eq 15
+ end
+ it '省略されると@page_sizeにデフォルト値が入る' do
+ get :index
+ assigns(:page_size).should eq PanelColor.default_page_size
+ end
+ it '最大を超えると@page_sizeにデフォルト最大値が入る' do
+ get :index, :page_size => 1500
+ assigns(:page_size).should eq PanelColor.max_page_size
+ end
+ it '不正な値が入ると@page_sizeにデフォルト最大値が入る' do
+ get :index, :page_size => 0
+ assigns(:page_size).should eq PanelColor.default_page_size
+ end
+ end
+ context 'つつがなく終わるとき' do
+ it 'ステータスコード200 OKを返す' do
+ get :index
+ response.should be_success
+ end
+ it '色背景モデルに一覧を問い合わせている' do
+ PanelColor.should_receive(:list).exactly(1)
+ get :index
+ end
+ it '@panel_colorsにリストを取得している' do
+ get :index
+ assigns(:panel_colors).should have_at_least(3).items
+ end
+ context 'html形式' do
+ it 'indexテンプレートを描画する' do
+ get :index
+ response.should render_template("index")
+ end
+ end
+ context 'json形式' do
+ it 'jsonデータを返す' do
+ get :index, :format => :json
+ lambda{JSON.parse(response.body)}.should_not raise_error(JSON::ParserError)
+ end
+ it 'データがリスト構造になっている' do
+ get :index, :format => :json
+ json = JSON.parse response.body
+ json.should have_at_least(3).items
+ end
+ it 'リストの先頭くらいは色背景っぽいものであって欲しい' do
+ get :index, :format => :json
+ json = JSON.parse response.body
+ json.first.has_key?("panel_id").should be_true
+ json.first.has_key?("code").should be_true
+ json.first.has_key?("z").should be_true
+ end
+ end
+ end
+ context '作家権限がないとき' do
+ before do
+ sign_out @user
+ end
+ context 'html形式' do
+ it 'ステータスコード302 Foundを返す' do
+ get :index
+ response.status.should eq 302
+ end
+ it 'サインインページへ遷移する' do
+ get :index
+ response.should redirect_to '/users/sign_in'
+ end
+ end
+ context 'json形式' do
+ it 'ステータスコード401 Unauthorizedを返す' do
+ get :index, :format => :json
+ response.status.should eq 401
+ end
+ it '応答メッセージにUnauthorizedを返す' do
+ get :index, :format => :json
+ response.message.should match(/Unauthorized/)
+ end
+ end
+ end
+ end
+
+end
describe PanelsController do\r
before do\r
FactoryGirl.create :admin\r
- @sp = FactoryGirl.create :system_picture
- @lg = FactoryGirl.create :license_group
- @license = FactoryGirl.create :license, :license_group_id => @lg.id, :system_picture_id => @sp.id
+ @sp = FactoryGirl.create :system_picture\r
+ @lg = FactoryGirl.create :license_group\r
+ @license = FactoryGirl.create :license, :license_group_id => @lg.id, :system_picture_id => @sp.id\r
@user = FactoryGirl.create :user_yas\r
@author = @user.author #ユーザ作成時に連動して作成される\r
end\r
get :edit, :id => @panel.id\r
response.should be_success \r
end\r
- it 'コマモデルに単体取得を問い合わせている' do\r
- Panel.should_receive(:show).exactly(1)\r
+ it 'コマモデルに編集取得を問い合わせている' do\r
+ Panel.should_receive(:edit).exactly(1)\r
get :edit, :id => @panel.id\r
end\r
it '@panelにデータを用意している' do\r
get :show, :id => @p.id, :format => :json
assigns(:picture).id.should eq(@p.id)
end
+ context 'html形式' do
+ it 'showテンプレートを描画する' do
+ get :show, :id => @p.id
+ response.should render_template("show")
+ end
+ end
context 'json形式' do
it 'jsonデータを返す' do
get :show, :id => @p.id, :format => :json
=end
end
- describe 'クレジット表示に於いて' do\r
- before do\r
+ describe 'クレジット表示に於いて' do
+ before do
@p = FactoryGirl.create :picture, :original_picture_id => @op.id, :license_id => @license.id, :artist_id => @artist.id
sign_in @user
Picture.stub(:show).and_return(@p)
- end\r
- context 'つつがなく終わるとき' do\r
- it 'ステータスコード200 OKを返す' do\r
- get :credit, :id => @p.id\r
- response.should be_success\r
- end\r
- it '実素材モデルに単体取得を問い合わせている' do\r
- Picture.should_receive(:show).exactly(1)\r
- get :credit, :id => @p.id\r
- end\r
- it '@pictureにアレを取得している' do\r
- get :credit, :id => @p.id\r
- assigns(:picture).id.should eq(@p.id)\r
- end\r
- context 'html形式' do\r
- it 'creditテンプレートを描画する' do\r
- get :credit, :id => @p.id\r
- response.should render_template("credit")\r
- end\r
- end\r
- context 'json形式' do\r
- it 'jsonデータを返す' do\r
- get :credit, :id => @p.id, :format => :json\r
- lambda{JSON.parse(response.body)}.should_not raise_error(JSON::ParserError)\r
- end\r
- it 'データがアレになっている' do\r
- get :credit, :id => @p.id, :format => :json\r
- json = JSON.parse response.body\r
- json["ext"].should match(/png/)\r
- end\r
- end\r
- end\r
- context '作家権限がないとき' do\r
- before do\r
- sign_out @user\r
- end\r
- context 'html形式' do\r
- it 'ステータスコード302 Foundを返す' do\r
- get :credit, :id => @p.id\r
- response.status.should eq 302\r
- end\r
- it 'サインインページへ遷移する' do\r
- get :credit, :id => @p.id\r
- response.body.should redirect_to '/users/sign_in'\r
- end\r
- end\r
- context 'json形式' do\r
- it 'ステータスコード401 Unauthorizedを返す' do\r
- get :credit, :id => @p.id, :format => :json\r
- response.status.should eq 401\r
- end\r
- it '応答メッセージにUnauthorizedを返す' do\r
- get :credit, :id => @p.id, :format => :json\r
- response.message.should match(/Unauthorized/)\r
- end\r
- end\r
- end\r
-=begin\r
- context '対象素材がないとき' do\r
- before do\r
- Picture.unstub(:show)\r
- end\r
- context 'html形式' do\r
- it '例外404 not_foundを返す' do\r
- lambda{\r
- get :show, :id => 0\r
- }.should raise_error(ActiveRecord::RecordNotFound)\r
- end\r
- end\r
- context 'json形式' do\r
- it '例外404 not_foundを返す' do\r
- lambda{ \r
- get :show, :id => 0, :format => :json\r
- }.should raise_error(ActiveRecord::RecordNotFound)\r
- end\r
- end\r
- end\r
-=end\r
- end\r
+ end
+ context 'つつがなく終わるとき' do
+ it 'ステータスコード200 OKを返す' do
+ get :credit, :id => @p.id
+ response.should be_success
+ end
+ it '実素材モデルに単体取得を問い合わせている' do
+ Picture.should_receive(:show).exactly(1)
+ get :credit, :id => @p.id
+ end
+ it '@pictureにアレを取得している' do
+ get :credit, :id => @p.id
+ assigns(:picture).id.should eq(@p.id)
+ end
+ context 'html形式' do
+ it 'creditテンプレートを描画する' do
+ get :credit, :id => @p.id
+ response.should render_template("credit")
+ end
+ end
+ context 'json形式' do
+ it 'jsonデータを返す' do
+ get :credit, :id => @p.id, :format => :json
+ lambda{JSON.parse(response.body)}.should_not raise_error(JSON::ParserError)
+ end
+ it 'データがアレになっている' do
+ get :credit, :id => @p.id, :format => :json
+ json = JSON.parse response.body
+ json["ext"].should match(/png/)
+ end
+ end
+ end
+ context '作家権限がないとき' do
+ before do
+ sign_out @user
+ end
+ context 'html形式' do
+ it 'ステータスコード302 Foundを返す' do
+ get :credit, :id => @p.id
+ response.status.should eq 302
+ end
+ it 'サインインページへ遷移する' do
+ get :credit, :id => @p.id
+ response.body.should redirect_to '/users/sign_in'
+ end
+ end
+ context 'json形式' do
+ it 'ステータスコード401 Unauthorizedを返す' do
+ get :credit, :id => @p.id, :format => :json
+ response.status.should eq 401
+ end
+ it '応答メッセージにUnauthorizedを返す' do
+ get :credit, :id => @p.id, :format => :json
+ response.message.should match(/Unauthorized/)
+ end
+ end
+ end
+=begin
+ context '対象素材がないとき' do
+ before do
+ Picture.unstub(:show)
+ end
+ context 'html形式' do
+ it '例外404 not_foundを返す' do
+ lambda{
+ get :show, :id => 0
+ }.should raise_error(ActiveRecord::RecordNotFound)
+ end
+ end
+ context 'json形式' do
+ it '例外404 not_foundを返す' do
+ lambda{
+ get :show, :id => 0, :format => :json
+ }.should raise_error(ActiveRecord::RecordNotFound)
+ end
+ end
+ end
+=end
+ end
end
get :edit, :id => @story.id
response.should be_success
end
- it 'コマモデルに単体取得を問い合わせている' do
- Story.should_receive(:show).exactly(1)
+ it 'コマモデルに編集取得を問い合わせている' do
+ Story.should_receive(:edit).exactly(1)
get :edit, :id => @story.id
end
it '@storyにデータを用意している' do
end
end
- describe '削除に於いて' do\r
- before do\r
+ describe '削除に於いて' do
+ before do
@story = FactoryGirl.create :story, :author_id => @author.id
sign_in @user
- Story.stub(:edit).and_return(@story)\r
- end\r
- context 'つつがなく終わるとき' do\r
- it 'ストーリーモデルに編集取得を問い合わせている' do\r
- Story.should_receive(:edit).exactly(1)\r
- delete :destroy, :id => @story.id\r
- end\r
- it '@storyにアレを取得している' do\r
- delete :destroy, :id => @story.id\r
- assigns(:story).id.should eq(@story.id)\r
- end\r
- it 'そのストーリーを一つのトランザクションで削除する' do\r
- lambda {\r
- delete :destroy, :id => @story.id\r
- }.should change(Story, :count)\r
- end\r
- context 'html形式' do\r
- it 'ステータスコード302 Foundを返す' do\r
- delete :destroy, :id => @story.id\r
- response.status.should eq 302\r
- end\r
- it 'ストーリー一覧ページへ遷移する' do\r
- delete :destroy, :id => @story.id\r
- response.should redirect_to(story_path(@story.comic_id))\r
- end\r
- end\r
- context 'json形式' do\r
- it 'ステータスコード200 OKを返す' do\r
- delete :destroy, :id => @story.id, :format => :json\r
- response.should be_success\r
- end\r
- end\r
- end\r
- context '作家権限がないとき' do\r
- before do\r
- sign_out @user\r
- end\r
- context 'html形式' do\r
- it 'ステータスコード302 Foundを返す' do\r
- delete :destroy, :id => @story.id\r
- response.status.should eq 302\r
- end\r
- it 'サインインページへ遷移する' do\r
- delete :destroy, :id => @story.id\r
- response.body.should redirect_to '/users/sign_in'\r
- end\r
- end\r
- context 'json形式' do\r
- it 'ステータスコード401 Unauthorizedを返す' do\r
- delete :destroy, :id => @story.id, :format => :json\r
- response.status.should eq 401\r
- end\r
- it '応答メッセージにUnauthorizedを返す' do\r
- delete :destroy, :id => @story.id, :format => :json\r
- response.message.should match(/Unauthorized/)\r
- end\r
- end\r
- end\r
-=begin\r
- context '対象ストーリーがないとき' do\r
- end\r
- context '他人のストーリーだったとき' do\r
- end\r
-=end\r
- end\r
- \r
+ Story.stub(:edit).and_return(@story)
+ end
+ context 'つつがなく終わるとき' do
+ it 'ストーリーモデルに編集取得を問い合わせている' do
+ Story.should_receive(:edit).exactly(1)
+ delete :destroy, :id => @story.id
+ end
+ it '@storyにアレを取得している' do
+ delete :destroy, :id => @story.id
+ assigns(:story).id.should eq(@story.id)
+ end
+ it 'そのストーリーを一つのトランザクションで削除する' do
+ lambda {
+ delete :destroy, :id => @story.id
+ }.should change(Story, :count)
+ end
+ context 'html形式' do
+ it 'ステータスコード302 Foundを返す' do
+ delete :destroy, :id => @story.id
+ response.status.should eq 302
+ end
+ it 'ストーリー一覧ページへ遷移する' do
+ delete :destroy, :id => @story.id
+ response.should redirect_to(story_path(@story.comic_id))
+ end
+ end
+ context 'json形式' do
+ it 'ステータスコード200 OKを返す' do
+ delete :destroy, :id => @story.id, :format => :json
+ response.should be_success
+ end
+ end
+ end
+ context '作家権限がないとき' do
+ before do
+ sign_out @user
+ end
+ context 'html形式' do
+ it 'ステータスコード302 Foundを返す' do
+ delete :destroy, :id => @story.id
+ response.status.should eq 302
+ end
+ it 'サインインページへ遷移する' do
+ delete :destroy, :id => @story.id
+ response.body.should redirect_to '/users/sign_in'
+ end
+ end
+ context 'json形式' do
+ it 'ステータスコード401 Unauthorizedを返す' do
+ delete :destroy, :id => @story.id, :format => :json
+ response.status.should eq 401
+ end
+ it '応答メッセージにUnauthorizedを返す' do
+ delete :destroy, :id => @story.id, :format => :json
+ response.message.should match(/Unauthorized/)
+ end
+ end
+ end
+=begin
+ context '対象ストーリーがないとき' do
+ end
+ context '他人のストーリーだったとき' do
+ end
+=end
+ end
+
end
license.system_picture_id 1
end
+ factory :color, :class => Color do |color|
+ color.name 'black'
+ color.code 0
+ color.t 0
+ end
+
factory :comic, :class => Comic do |comic|
comic.title "comic"
- comic.width 100
- comic.height 10
comic.visible 3
end
op.height 111
op.filesize 100000
op.artist_id 1
+ op.md5 'op8f6bcd4621d373cade4e832627b4f6'
end
factory :oplg, :class => OriginalPictureLicenseGroup do |oplg|
rp.width 222
rp.height 111
rp.filesize 100000
+ rp.md5 'rp8f6bcd4621d373cade4e832627b4f6'
rp.artist_id 1
rp.license_id 1
rp.classname 'StandardLicense'
p.width 222
p.height 111
p.filesize 100000
+ p.md5 'ap8f6bcd4621d373cade4e832627b4f6'
p.artist_id 1
p.license_id 1
p.artist_name 'no name'
pp.height 300
end
+ factory :panel_color, :class => PanelColor do |pc|
+ pc.panel_id 1
+ pc.z 1
+ pc.code 1
+ end
+
+ factory :ground_color, :class => GroundColor do |gc|
+ gc.panel_id 1
+ gc.color_id 1
+ gc.z 1
+ end
+
+ factory :ground_picture, :class => GroundPicture do |gp|
+ gp.panel_id 1
+ gp.picture_id 1
+ gp.z 1
+ end
+
factory :panel, :class => Panel do |panel|
panel.border 1
panel.x nil
+# -*- encoding: utf-8 -*-
+#
require 'spec_helper'
# Specs in this file have access to a helper object that includes
# end
# end
describe ArtistsHelper do
- pending "add some examples to (or delete) #{__FILE__}"
end
+# -*- encoding: utf-8 -*-
+#
require 'spec_helper'
# Specs in this file have access to a helper object that includes
# end
# end
describe AuthorsHelper do
- pending "add some examples to (or delete) #{__FILE__}"
end
+# -*- encoding: utf-8 -*-
+#
require 'spec_helper'
# Specs in this file have access to a helper object that includes
# end
# end
describe BalloonsHelper do
- pending "add some examples to (or delete) #{__FILE__}"
end
--- /dev/null
+# -*- encoding: utf-8 -*-
+#
+require 'spec_helper'
+
+# Specs in this file have access to a helper object that includes
+# the ColorsHelper. For example:
+#
+# describe ColorsHelper do
+# describe "string concat" do
+# it "concats two strings with spaces" do
+# helper.concat_strings("this","that").should == "this that"
+# end
+# end
+# end
+describe ColorsHelper do
+end
+# -*- encoding: utf-8 -*-
+#
require 'spec_helper'
# Specs in this file have access to a helper object that includes
# end
# end
describe ComicsHelper do
- pending "add some examples to (or delete) #{__FILE__}"
end
--- /dev/null
+# -*- encoding: utf-8 -*-
+#
+require 'spec_helper'
+
+# Specs in this file have access to a helper object that includes
+# the GroundColorsHelper. For example:
+#
+# describe GroundColorsHelper do
+# describe "string concat" do
+# it "concats two strings with spaces" do
+# helper.concat_strings("this","that").should == "this that"
+# end
+# end
+# end
+describe GroundColorsHelper do
+end
--- /dev/null
+require 'spec_helper'
+
+# Specs in this file have access to a helper object that includes
+# the GroundPicturesHelper. For example:
+#
+# describe GroundPicturesHelper do
+# describe "string concat" do
+# it "concats two strings with spaces" do
+# helper.concat_strings("this","that").should == "this that"
+# end
+# end
+# end
+describe GroundPicturesHelper do
+end
+# -*- encoding: utf-8 -*-
+#
require 'spec_helper'
# Specs in this file have access to a helper object that includes
# end
# end
describe HomeHelper do
- pending "add some examples to (or delete) #{__FILE__}"
end
+# -*- encoding: utf-8 -*-
+#
require 'spec_helper'
# Specs in this file have access to a helper object that includes
# end
# end
describe LicenseGroupsHelper do
- pending "add some examples to (or delete) #{__FILE__}"
end
+# -*- encoding: utf-8 -*-
+#
require 'spec_helper'
# Specs in this file have access to a helper object that includes
# end
# end
describe LicensesHelper do
- pending "add some examples to (or delete) #{__FILE__}"
end
+# -*- encoding: utf-8 -*-
+#
require 'spec_helper'
# Specs in this file have access to a helper object that includes
# end
# end
describe OriginalPictureLicenseGroupsHelper do
- pending "add some examples to (or delete) #{__FILE__}"
end
+# -*- encoding: utf-8 -*-
+#
require 'spec_helper'
# Specs in this file have access to a helper object that includes
# end
# end
describe OriginalPicturesHelper do
- pending "add some examples to (or delete) #{__FILE__}"
end
--- /dev/null
+# -*- encoding: utf-8 -*-
+#
+require 'spec_helper'
+
+# Specs in this file have access to a helper object that includes
+# the PanelColorsHelper. For example:
+#
+# describe PanelColorsHelper do
+# describe "string concat" do
+# it "concats two strings with spaces" do
+# helper.concat_strings("this","that").should == "this that"
+# end
+# end
+# end
+describe PanelColorsHelper do
+end
+# -*- encoding: utf-8 -*-
+#
require 'spec_helper'
# Specs in this file have access to a helper object that includes
# end
# end
describe PanelPicturesHelper do
- pending "add some examples to (or delete) #{__FILE__}"
end
+# -*- encoding: utf-8 -*-
+#
require 'spec_helper'
# Specs in this file have access to a helper object that includes
# end
# end
describe PanelsHelper do
- pending "add some examples to (or delete) #{__FILE__}"
end
+# -*- encoding: utf-8 -*-
+#
require 'spec_helper'
# Specs in this file have access to a helper object that includes
# end
# end
describe PicturesHelper do
- pending "add some examples to (or delete) #{__FILE__}"
end
+# -*- encoding: utf-8 -*-
+#
require 'spec_helper'
# Specs in this file have access to a helper object that includes
# end
# end
describe ResourcePicturesHelper do
- pending "add some examples to (or delete) #{__FILE__}"
end
+# -*- encoding: utf-8 -*-
+#
require 'spec_helper'
# Specs in this file have access to a helper object that includes
# end
# end
describe SpeechBalloonTemplatesHelper do
- pending "add some examples to (or delete) #{__FILE__}"
end
+# -*- encoding: utf-8 -*-
+#
require 'spec_helper'
# Specs in this file have access to a helper object that includes
# end
# end
describe SpeechBalloonsHelper do
- pending "add some examples to (or delete) #{__FILE__}"
end
+# -*- encoding: utf-8 -*-
+#
require 'spec_helper'
# Specs in this file have access to a helper object that includes
# end
# end
describe SpeechesHelper do
- pending "add some examples to (or delete) #{__FILE__}"
end
+# -*- encoding: utf-8 -*-
+#
require 'spec_helper'
# Specs in this file have access to a helper object that includes
# end
# end
describe SystemHelper do
- pending "add some examples to (or delete) #{__FILE__}"
end
+# -*- encoding: utf-8 -*-
+#
require 'spec_helper'
# Specs in this file have access to a helper object that includes
# end
# end
describe SystemPicturesHelper do
- pending "add some examples to (or delete) #{__FILE__}"
end
--- /dev/null
+{\r
+ "white": {\r
+ "code": 0,\r
+ "t": 0\r
+ }\r
+}\r
--- /dev/null
+{\r
+ "white": {\r
+ "code": 255,\r
+ "t": 0\r
+ },\r
+ "black": {\r
+ "code": 0,\r
+ "t": 1\r
+ }\r
+}\r
"PublicDomain": {\r
"caption": "Public Domain", \r
"url": "http://test.com/",\r
- "system_picture": "Data"\r
+ "system_picture": "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"\r
}\r
}\r
}\r
"UnknownF1": {\r
"caption": "Unknown Flag1", \r
"url": "http://test.com/f1",\r
- "system_picture": "Dataf1"\r
+ "system_picture": "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"\r
},\r
"UnknownF2": {\r
"caption": "Unknown Flag2", \r
"url": "http://test.com/f2",\r
- "system_picture": "Dataf2"\r
+ "system_picture": "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"\r
}\r
}\r
}\r
+# -*- encoding: utf-8 -*-
+#管理者
require 'spec_helper'
describe Admin do
- pending "add some examples to (or delete) #{__FILE__}"
end
end
it 'オーソドックスなデータなら通る' do
- @artist = FactoryGirl.build :artist, :author_id => @author.id, :default_license_id => @license.id
+ @artist = FactoryGirl.build :artist, :author_id => @author.id
@artist.should be_valid
end
context 'nameを検証するとき' do
it 'nullなら失敗する' do
- @artist = FactoryGirl.build :artist, :author_id => @author.id, :default_license_id => @license.id, :name => nil
+ @artist = FactoryGirl.build :artist, :author_id => @author.id, :name => nil
@artist.should_not be_valid
end
it '30文字以上なら失敗する' do
- @artist = FactoryGirl.build :artist, :author_id => @author.id, :default_license_id => @license.id, :name => 'a'*31
+ @artist = FactoryGirl.build :artist, :author_id => @author.id, :name => 'a'*31
@artist.should_not be_valid
end
end
describe '単体取得に於いて' do
before do
- @artist = FactoryGirl.create :artist, :author_id => @author.id, :default_license_id => @license.id
+ @artist = FactoryGirl.create :artist, :author_id => @author.id
end
it '指定の絵師を返す' do
a = Artist.show @artist.id
end
end
end
+ describe '編集取得に於いて' do
+ before do
+ @artist = FactoryGirl.create :artist, :author_id => @author.id
+ end
+ it '指定の絵師を返す' do
+ Artist.any_instance.stub(:own?).and_return(true)
+ r = Artist.edit @artist.id, @author.id
+ r.should eq @artist
+ end
+ context '他人の絵師を開こうとしたとき' do
+ it '403Forbidden例外を返す' do
+ Artist.any_instance.stub(:own?).and_return(false)
+ lambda{
+ Artist.edit @artist.id, @author
+ }.should raise_error(ActiveRecord::Forbidden)
+ end
+ end
+ context '存在しない絵師を開こうとしたとき' do
+ it '404RecordNotFound例外を返す' do
+ lambda{
+ Artist.edit 110, @author
+ }.should raise_error(ActiveRecord::RecordNotFound)
+ end
+ end
+ end
describe '一覧取得に於いて' do
before do
- @artist = FactoryGirl.create :artist, :author_id => @author.id, :default_license_id => @license.id
+ @artist = FactoryGirl.create :artist, :author_id => @author.id
end
context 'page補正について' do
it '文字列から数値に変換される' do
--- /dev/null
+# -*- encoding: utf-8 -*-
+require 'spec_helper'
+#色マスター
+
+describe Color do
+ before do
+ @f = Rails.root + 'spec/json/color.json'
+ @fs = Rails.root + 'spec/json/colors.json'
+ FactoryGirl.create :admin
+ @user = FactoryGirl.create( :user_yas)
+ @author = @user.author
+ @artist = FactoryGirl.create :artist_yas, :author_id => @author.id
+ @other_user = FactoryGirl.create( :user_yas)
+ @other_author = @other_user.author
+ @other_artist = FactoryGirl.create :artist_yas, :author_id => @other_author.id
+ @sp = FactoryGirl.create :system_picture
+ @lg = FactoryGirl.create :license_group
+ @license = FactoryGirl.create :license, :license_group_id => @lg.id, :system_picture_id => @sp.id
+ end
+
+ describe '検証に於いて' do
+ before do
+ end
+
+ it 'オーソドックスなデータなら通る' do
+ @c = FactoryGirl.build :color
+ @c.should be_valid
+ end
+
+ context 'nameを検証するとき' do
+ before do
+ @c = FactoryGirl.build :color
+ end
+ it 'テストデータの確認' do
+ @c.name = 'a'*50
+ @c.should be_valid
+ end
+ it 'nullなら失敗する' do
+ @c.name = ''
+ @c.should_not be_valid
+ end
+ it '51文字以上なら失敗する' do
+ @c.name = 'a'*51
+ @c.should_not be_valid
+ end
+ it '重複していたら失敗する' do
+ l = FactoryGirl.create :color
+ @c.should_not be_valid
+ end
+ end
+ context 'codeを検証するとき' do
+ before do
+ @c = FactoryGirl.build :color
+ end
+ it 'テストデータの確認' do
+ @c.code = 0xffffff
+ @c.should be_valid
+ end
+ it 'nullなら失敗する' do
+ @c.code = nil
+ @c.should_not be_valid
+ end
+ it '数値でなければ失敗する' do
+ @c.code = 'a'
+ @c.should_not be_valid
+ end
+ it '負なら失敗する' do
+ @c.code = -1
+ @c.should_not be_valid
+ end
+ it '24bit colorでなければ失敗する' do
+ @c.code = 0x1000000
+ @c.should_not be_valid
+ end
+ end
+ context 'tを検証するとき' do
+ before do
+ @c = FactoryGirl.build :color
+ end
+ it 'テストデータの確認' do
+ @c.t = '1'
+ @c.should be_valid
+ end
+ it '数値でなければ失敗する' do
+ @c.t = 'a'
+ @c.should_not be_valid
+ end
+ it '0なら通る' do
+ @c.t = '0'
+ @c.should be_valid
+ end
+ it '負なら失敗する' do
+ @c.t = -1
+ @c.should_not be_valid
+ end
+ end
+ end
+
+ describe 'インポートに於いて' do
+ before do
+ end
+ context 'つつがなく終わるとき' do
+ it 'ファイルインポートを依頼する' do
+ Color.should_receive(:import_file).with(any_args).exactly(1)
+ Color.stub(:import_file).with(any_args).and_return([])
+ Color.import(@f)
+ end
+ it '色更新を一回依頼する' do
+ Color.stub(:store).with(any_args).and_return(Color.new)
+ Color.should_receive(:store).with(any_args).exactly(1)
+ Color.import(@f)
+ end
+ it '色が追加される' do
+ lambda {
+ Color.import(@f)
+ }.should change Color, :count
+ end
+ it '[]を返す' do
+ r = Color.import(@f)
+ r.should eq []
+ end
+ end
+ context '複数データがつつがなく終わるとき' do
+ it '色更新を二回依頼する' do
+ Color.stub(:store).with(any_args).and_return(Color.new)
+ Color.should_receive(:store).with(any_args).exactly(2)
+ Color.import(@fs)
+ end
+ it '色が二個追加される' do
+ lambda {
+ r = Color.import(@fs)
+ }.should change(Color, :count).by 2
+ end
+ it '[]を返す' do
+ r = Color.import(@fs)
+ r.should eq []
+ end
+ end
+ end
+
+ describe '単体取得に於いて' do
+ before do
+ @c = FactoryGirl.create :color
+ end
+ it '指定の色を返す' do
+ c = Color.show @c.id
+ c.should eq @c
+ end
+ context '存在しない色を開こうとしたとき' do
+ it '404RecordNotFound例外を返す' do
+ lambda{
+ Color.show 110
+ }.should raise_error(ActiveRecord::RecordNotFound)
+ end
+ end
+ end
+
+ describe '一覧取得に於いて' do
+ before do
+ @color = FactoryGirl.create :color
+ end
+ context 'page補正について' do
+ it '文字列から数値に変換される' do
+ Color.page('8').should eq 8
+ end
+ it 'nilの場合は1になる' do
+ Color.page().should eq 1
+ end
+ it '0以下の場合は1になる' do
+ Color.page('0').should eq 1
+ end
+ end
+ context 'page_size補正について' do
+ it '文字列から数値に変換される' do
+ Color.page_size('7').should eq 7
+ end
+ it 'nilの場合はColor.default_page_sizeになる' do
+ Color.page_size().should eq Color.default_page_size
+ end
+ it '0以下の場合はColor.default_page_sizeになる' do
+ Color.page_size('0').should eq Color.default_page_size
+ end
+ it 'Color.max_page_sizeを超えた場合はColor.max_page_sizeになる' do
+ Color.page_size('1000').should eq Color.max_page_size
+ end
+ end
+ it 'リストを返す' do
+ cl = Color.list
+ cl.should eq [@color]
+ end
+ it 'tで並んでいる' do
+ ncl = FactoryGirl.create :color, :t => 1, :name => 'name a'
+ cl = Color.list
+ cl.should eq [@color, ncl]
+ end
+ context 'DBに5件あって1ページの件数を2件に変えたとして' do
+ before do
+ @nc2 = FactoryGirl.create :color, :t => 1, :name => 'name a'
+ @nc3 = FactoryGirl.create :color, :t => 3, :name => 'name b'
+ @nc4 = FactoryGirl.create :color, :t => 2, :name => 'name c'
+ @nc5 = FactoryGirl.create :color, :t => 4, :name => 'name d'
+ Color.stub(:default_page_size).and_return(2)
+ end
+ it '通常は2件を返す' do
+ cl = Color.list
+ cl.should have(2).items
+ end
+ it 'page=1なら末尾2件を返す' do
+ #時系列で並んでいる
+ cl = Color.list( {}, 1)
+ cl.should eq [@color, @nc2]
+ end
+ it 'page=2なら中間2件を返す' do
+ cl = Color.list({}, 2)
+ cl.should eq [@nc4, @nc3]
+ end
+ it 'page=3なら先頭1件を返す' do
+ cl = Color.list({}, 3)
+ cl.should eq [@nc5]
+ end
+ end
+ end
+
+end
@comic.should_not be_valid
end
end
- context 'widthを検証するとき' do
- it 'nullなら失敗する' do
- @comic = FactoryGirl.build :comic, :author_id => @author.id, :width => nil
- @comic.should_not be_valid
- end
- it '0なら失敗する' do
- @comic = FactoryGirl.build :comic, :author_id => @author.id, :width => 0
- @comic.should_not be_valid
- end
- it '負でも失敗する' do
- @comic = FactoryGirl.build :comic, :author_id => @author.id, :width => -1
- @comic.should_not be_valid
- end
- it '正なら通る' do
- @comic = FactoryGirl.build :comic, :author_id => @author.id, :width => 1
- @comic.should be_valid
- end
- end
- context 'heightを検証するとき' do
- it 'nullなら失敗する' do
- @comic = FactoryGirl.build :comic, :author_id => @author.id, :height => nil
- @comic.should_not be_valid
- end
- it '0なら失敗する' do
- @comic = FactoryGirl.build :comic, :author_id => @author.id, :height => 0
- @comic.should_not be_valid
- end
- it '負でも失敗する' do
- @comic = FactoryGirl.build :comic, :author_id => @author.id, :height => -1
- @comic.should_not be_valid
- end
- it '正なら通る' do
- @comic = FactoryGirl.build :comic, :author_id => @author.id, :height => 1
- @comic.should be_valid
- end
- end
context 'visibleを検証するとき' do
it 'nullなら失敗する' do
@comic = FactoryGirl.build :comic, :author_id => @author.id, :visible => nil
c.should eq @comic
end
end
+ describe '編集取得に於いて' do
+ before do
+ @comic = FactoryGirl.create :comic, :author_id => @author.id
+ end
+ it '指定のコミックを返す' do
+ Comic.any_instance.stub(:own?).and_return(true)
+ c = Comic.edit @comic.id, @author.id
+ c.should eq @comic
+ end
+ context '他人のコミックを開こうとしたとき' do
+ it '403Forbidden例外を返す' do
+ Comic.any_instance.stub(:own?).and_return(false)
+ lambda{
+ Comic.edit @comic.id, @author
+ }.should raise_error(ActiveRecord::Forbidden)
+ end
+ end
+ context '存在しないコミックを開こうとしたとき' do
+ it '404RecordNotFound例外を返す' do
+ lambda{
+ Comic.edit 110, @author
+ }.should raise_error(ActiveRecord::RecordNotFound)
+ end
+ end
+ end
describe '関連テーブルプションに於いて' do
context 'オプションがないとき' do
it '2つの項目を含んでいる' do
--- /dev/null
+# -*- encoding: utf-8 -*-
+require 'spec_helper'
+#コマの背景間接
+
+describe GroundColor do
+ before do
+ FactoryGirl.create :admin
+ @user = FactoryGirl.create( :user_yas)
+ @author = @user.author
+ @artist = FactoryGirl.create :artist_yas, :author_id => @author.id
+ @other_user = FactoryGirl.create( :user_yas)
+ @other_author = @other_user.author
+ @other_artist = FactoryGirl.create :artist_yas, :author_id => @other_author.id
+ @sp = FactoryGirl.create :system_picture
+ @lg = FactoryGirl.create :license_group
+ @license = FactoryGirl.create :license, :license_group_id => @lg.id, :system_picture_id => @sp.id
+ @op = FactoryGirl.create :original_picture, :artist_id => @artist.id
+ @p = FactoryGirl.create :picture, :original_picture_id => @op.id, :license_id => @license.id, :artist_id => @artist.id
+ @rp = FactoryGirl.create :resource_picture, :artist_id => @artist.id, :license_id => @license.id, :original_picture_id => @op.id, :picture_id => @p.id
+ @panel = FactoryGirl.create :panel, :author_id => @author.id
+ @color = FactoryGirl.create :color
+ end
+
+ describe '検証に於いて' do
+ before do
+ @gc = FactoryGirl.build :ground_color, :panel_id => @panel.id, :color_id => @color.id
+ end
+ it 'オーソドックスなデータなら通る' do
+ @gc.save
+ @gc.should be_valid
+ end
+
+ context 'panel_idを検証するとき' do
+ #ネストの保存はnilを許可しなければならないので数値チェックだけ
+ it 'テストデータの確認' do
+ @gc.panel_id = @panel.id
+ @gc.should be_valid
+ end
+ it '数値でなければ失敗する' do
+ @gc.panel_id = 'a'
+ @gc.should_not be_valid
+ end
+ end
+ context 'color_idを検証するとき' do
+ it 'テストデータの確認' do
+ @gc.color_id = @color.id
+ @gc.should be_valid
+ end
+ it 'nullなら失敗する' do
+ @gc.color_id = nil
+ @gc.should_not be_valid
+ end
+ it '数値でなければ失敗する' do
+ @gc.color_id = 'a'
+ @gc.should_not be_valid
+ end
+ it '存在する実素材でなければ失敗する' do
+ @gc.color_id = 0
+ @gc.should_not be_valid
+ end
+ end
+ context 'zを検証するとき' do
+ it 'テストデータの確認' do
+ @gc.z = 1
+ @gc.should be_valid
+ end
+ it 'nullなら失敗する' do
+ @gc.z = nil
+ @gc.should_not be_valid
+ end
+ it '数値でなければ失敗する' do
+ @gc.z = 'a'
+ @gc.should_not be_valid
+ end
+ it '負なら失敗する' do
+ @gc.z = -1
+ @gc.should_not be_valid
+ end
+ it '負なら失敗する' do
+ @gc.z = 0
+ @gc.should_not be_valid
+ end
+ end
+ end
+ describe '一覧取得に於いて' do
+ before do
+ @gc = FactoryGirl.create :ground_color, :panel_id => @panel.id, :color_id => @color.id
+ end
+ context 'page補正について' do
+ it '文字列から数値に変換される' do
+ GroundColor.page('8').should eq 8
+ end
+ it 'nilの場合は1になる' do
+ GroundColor.page().should eq 1
+ end
+ it '0以下の場合は1になる' do
+ GroundColor.page('0').should eq 1
+ end
+ end
+ context 'page_size補正について' do
+ it '文字列から数値に変換される' do
+ GroundColor.page_size('7').should eq 7
+ end
+ it 'nilの場合はGroundColor.default_page_sizeになる' do
+ GroundColor.page_size().should eq GroundColor.default_page_size
+ end
+ it '0以下の場合はGroundColor.default_page_sizeになる' do
+ GroundColor.page_size('0').should eq GroundColor.default_page_size
+ end
+ it 'GroundColor.max_page_sizeを超えた場合はGroundColor.max_page_sizeになる' do
+ GroundColor.page_size('1000').should eq GroundColor.max_page_size
+ end
+ end
+ it 'リストを返す' do
+ pl = GroundColor.list
+ pl.should eq [@gc]
+ end
+ it '時系列で並んでいる' do
+ npl = FactoryGirl.create :ground_color, :panel_id => @panel.id, :color_id => @color.id, :z => 2, :updated_at => Time.now + 100
+ pl = GroundColor.list
+ pl.should eq [npl, @gc]
+ end
+ it '非公開のコマの景色は含まない' do
+ hpl = FactoryGirl.create :panel, :author_id => @author.id, :publish => 0
+ npl = FactoryGirl.create :ground_color, :panel_id => hpl.id, :color_id => @color.id, :updated_at => Time.now + 100
+ pl = GroundColor.list
+ pl.should eq [@gc]
+ end
+ context 'DBに5件あって1ページの件数を2件に変えたとして' do
+ before do
+ @npl2 = FactoryGirl.create :ground_color, :panel_id => @panel.id, :z => 1, :color_id => @color.id, :updated_at => Time.now + 100
+ @npl3 = FactoryGirl.create :ground_color, :panel_id => @panel.id, :z => 2, :color_id => @color.id, :updated_at => Time.now + 200
+ @npl4 = FactoryGirl.create :ground_color, :panel_id => @panel.id, :z => 3, :color_id => @color.id, :updated_at => Time.now + 300
+ @npl5 = FactoryGirl.create :ground_color, :panel_id => @panel.id, :z => 4, :color_id => @color.id, :updated_at => Time.now + 400
+ GroundColor.stub(:default_page_size).and_return(2)
+ end
+ it '通常は2件を返す' do
+ pl = GroundColor.list
+ pl.should have(2).items
+ end
+ it 'page=1なら末尾2件を返す' do
+ #時系列で並んでいる
+ pl = GroundColor.list( {}, 1)
+ pl.should eq [@npl5, @npl4]
+ end
+ it 'page=2なら中間2件を返す' do
+ pl = GroundColor.list({}, 2)
+ pl.should eq [@npl3, @npl2]
+ end
+ it 'page=3なら先頭1件を返す' do
+ pl = GroundColor.list({}, 3)
+ pl.should eq [@gc]
+ end
+ end
+ end
+ describe 'list関連テーブルプションに於いて' do
+ it 'includeキーを含んでいる' do
+ r = GroundColor.list_opt
+ r.has_key?(:include).should be_true
+ end
+ it '2つの項目を含んでいる' do
+ r = GroundColor.list_opt[:include]
+ r.should have(2).items
+ end
+ it 'コマを含んでいる' do
+ r = GroundColor.list_opt[:include]
+ r.has_key?(:panel).should be_true
+ end
+ it 'コマは作家を含んでいる' do
+ r = GroundColor.list_opt[:include]
+ r[:panel].has_key?(:author).should be_true
+ end
+ it '色を含んでいる' do
+ r = GroundColor.list_opt[:include]
+ r.has_key?(:color).should be_true
+ end
+ end
+ describe 'json一覧出力オプションに於いて' do
+ it 'includeキーを含んでいる' do
+ r = GroundColor.list_json_opt
+ r.has_key?(:include).should be_true
+ end
+ it '2つの項目を含んでいる' do
+ r = GroundColor.list_json_opt[:include]
+ r.should have(2).items
+ end
+ it 'コマを含んでいる' do
+ r = GroundColor.list_json_opt[:include]
+ r.has_key?(:panel).should be_true
+ end
+ it 'コマは作家を含んでいる' do
+ r = GroundColor.list_json_opt[:include]
+ r[:panel].has_key?(:author).should be_true
+ end
+ it '色を含んでいる' do
+ r = GroundColor.list_json_opt[:include]
+ r.has_key?(:color).should be_true
+ end
+ end
+
+ describe '自分のコマで使った色一覧取得に於いて' do
+ before do
+ @gc = FactoryGirl.create :ground_color, :panel_id => @panel.id, :color_id => @color.id
+ end
+ it 'リストを返す' do
+ pl = GroundColor.mylist @author
+ pl.should eq [@gc]
+ end
+ it '時系列で並んでいる' do
+ npl = FactoryGirl.create :ground_color, :panel_id => @panel.id, :color_id => @color.id, :z => 2, :updated_at => Time.now + 100
+ pl = GroundColor.mylist @author
+ pl.should eq [npl, @gc]
+ end
+ it '他人のコマの景色は公開でも含まない' do
+ hpl = FactoryGirl.create :panel, :author_id => @other_author.id, :publish => 1
+ npl = FactoryGirl.create :ground_color, :panel_id => hpl.id, :color_id => @color.id
+ pl = GroundColor.mylist @author
+ pl.should eq [@gc]
+ end
+ end
+
+end
--- /dev/null
+# -*- encoding: utf-8 -*-
+require 'spec_helper'
+#コマの画像背景
+
+describe GroundPicture do
+ before do
+ FactoryGirl.create :admin
+ @user = FactoryGirl.create( :user_yas)
+ @author = @user.author
+ @artist = FactoryGirl.create :artist_yas, :author_id => @author.id
+ @other_user = FactoryGirl.create( :user_yas)
+ @other_author = @other_user.author
+ @other_artist = FactoryGirl.create :artist_yas, :author_id => @other_author.id
+ @sp = FactoryGirl.create :system_picture
+ @lg = FactoryGirl.create :license_group
+ @license = FactoryGirl.create :license, :license_group_id => @lg.id, :system_picture_id => @sp.id
+ @op = FactoryGirl.create :original_picture, :artist_id => @artist.id
+ @p = FactoryGirl.create :picture, :original_picture_id => @op.id, :license_id => @license.id, :artist_id => @artist.id
+ @rp = FactoryGirl.create :resource_picture, :artist_id => @artist.id, :license_id => @license.id, :original_picture_id => @op.id, :picture_id => @p.id
+ @panel = FactoryGirl.create :panel, :author_id => @author.id
+ end
+
+ describe '検証に於いて' do
+ before do
+ @gp = FactoryGirl.build :ground_picture, :panel_id => @panel.id, :picture_id => @p.id
+ end
+ it 'オーソドックスなデータなら通る' do
+ @gp.save
+ @gp.should be_valid
+ end
+
+ context 'panel_idを検証するとき' do
+ #ネストの保存はnilを許可しなければならないので数値チェックだけ
+ it 'テストデータの確認' do
+ @gp.panel_id = @panel.id
+ @gp.should be_valid
+ end
+ it '数値でなければ失敗する' do
+ @gp.panel_id = 'a'
+ @gp.should_not be_valid
+ end
+ end
+ context 'picture_idを検証するとき' do
+ it 'テストデータの確認' do
+ @gp.picture_id = @panel.id
+ @gp.should be_valid
+ end
+ it 'nullなら失敗する' do
+ @gp.picture_id = nil
+ @gp.should_not be_valid
+ end
+ it '数値でなければ失敗する' do
+ @gp.picture_id = 'a'
+ @gp.should_not be_valid
+ end
+ it '存在する実素材でなければ失敗する' do
+ @gp.picture_id = 0
+ @gp.should_not be_valid
+ end
+ end
+ context 'zを検証するとき' do
+ it 'テストデータの確認' do
+ @gp.z = 1
+ @gp.should be_valid
+ end
+ it 'nullなら失敗する' do
+ @gp.z = nil
+ @gp.should_not be_valid
+ end
+ it '数値でなければ失敗する' do
+ @gp.z = 'a'
+ @gp.should_not be_valid
+ end
+ it '負なら失敗する' do
+ @gp.z = -1
+ @gp.should_not be_valid
+ end
+ it '負なら失敗する' do
+ @gp.z = 0
+ @gp.should_not be_valid
+ end
+ end
+ end
+ describe '一覧取得に於いて' do
+ before do
+ @gp = FactoryGirl.create :ground_picture, :panel_id => @panel.id, :picture_id => @p.id
+ end
+ context 'page補正について' do
+ it '文字列から数値に変換される' do
+ GroundPicture.page('8').should eq 8
+ end
+ it 'nilの場合は1になる' do
+ GroundPicture.page().should eq 1
+ end
+ it '0以下の場合は1になる' do
+ GroundPicture.page('0').should eq 1
+ end
+ end
+ context 'page_size補正について' do
+ it '文字列から数値に変換される' do
+ GroundPicture.page_size('7').should eq 7
+ end
+ it 'nilの場合はGroundPicture.default_page_sizeになる' do
+ GroundPicture.page_size().should eq GroundPicture.default_page_size
+ end
+ it '0以下の場合はGroundPicture.default_page_sizeになる' do
+ GroundPicture.page_size('0').should eq GroundPicture.default_page_size
+ end
+ it 'GroundPicture.max_page_sizeを超えた場合はGroundPicture.max_page_sizeになる' do
+ GroundPicture.page_size('1000').should eq GroundPicture.max_page_size
+ end
+ end
+ it 'リストを返す' do
+ pl = GroundPicture.list
+ pl.should eq [@gp]
+ end
+ it '時系列で並んでいる' do
+ npl = FactoryGirl.create :ground_picture, :panel_id => @panel.id, :picture_id => @p.id, :z => 2, :updated_at => Time.now + 100
+ pl = GroundPicture.list
+ pl.should eq [npl, @gp]
+ end
+ it '非公開のコマの景色は含まない' do
+ hpl = FactoryGirl.create :panel, :author_id => @author.id, :publish => 0
+ npl = FactoryGirl.create :ground_picture, :panel_id => hpl.id, :picture_id => @p.id, :updated_at => Time.now + 100
+ pl = GroundPicture.list
+ pl.should eq [@gp]
+ end
+ context 'DBに5件あって1ページの件数を2件に変えたとして' do
+ before do
+ @npl2 = FactoryGirl.create :ground_picture, :panel_id => @panel.id, :z => 1, :picture_id => @p.id, :updated_at => Time.now + 100
+ @npl3 = FactoryGirl.create :ground_picture, :panel_id => @panel.id, :z => 2, :picture_id => @p.id, :updated_at => Time.now + 200
+ @npl4 = FactoryGirl.create :ground_picture, :panel_id => @panel.id, :z => 3, :picture_id => @p.id, :updated_at => Time.now + 300
+ @npl5 = FactoryGirl.create :ground_picture, :panel_id => @panel.id, :z => 4, :picture_id => @p.id, :updated_at => Time.now + 400
+ GroundPicture.stub(:default_page_size).and_return(2)
+ end
+ it '通常は2件を返す' do
+ pl = GroundPicture.list
+ pl.should have(2).items
+ end
+ it 'page=1なら末尾2件を返す' do
+ #時系列で並んでいる
+ pl = GroundPicture.list( {}, 1)
+ pl.should eq [@npl5, @npl4]
+ end
+ it 'page=2なら中間2件を返す' do
+ pl = GroundPicture.list({}, 2)
+ pl.should eq [@npl3, @npl2]
+ end
+ it 'page=3なら先頭1件を返す' do
+ pl = GroundPicture.list({}, 3)
+ pl.should eq [@gp]
+ end
+ end
+ end
+ describe 'list関連テーブルプションに於いて' do
+ it 'includeキーを含んでいる' do
+ r = GroundPicture.list_opt
+ r.has_key?(:include).should be_true
+ end
+ it '2つの項目を含んでいる' do
+ r = GroundPicture.list_opt[:include]
+ r.should have(2).items
+ end
+ it 'コマを含んでいる' do
+ r = GroundPicture.list_opt[:include]
+ r.has_key?(:panel).should be_true
+ end
+ it 'コマは作家を含んでいる' do
+ r = GroundPicture.list_opt[:include]
+ r[:panel].has_key?(:author).should be_true
+ end
+ it '実素材を含んでいる' do
+ r = GroundPicture.list_opt[:include]
+ r.has_key?(:picture).should be_true
+ end
+ it '実素材は絵師を含んでいる' do
+ r = GroundPicture.list_opt[:include]
+ r[:picture].has_key?(:artist).should be_true
+ end
+ it '実素材はライセンスを含んでいる' do
+ r = GroundPicture.list_opt[:include]
+ r[:picture].has_key?(:license).should be_true
+ end
+ end
+ describe 'json一覧出力オプションに於いて' do
+ it 'includeキーを含んでいる' do
+ r = GroundPicture.list_json_opt
+ r.has_key?(:include).should be_true
+ end
+ it '2つの項目を含んでいる' do
+ r = GroundPicture.list_json_opt[:include]
+ r.should have(2).items
+ end
+ it 'コマを含んでいる' do
+ r = GroundPicture.list_json_opt[:include]
+ r.has_key?(:panel).should be_true
+ end
+ it 'コマは作家を含んでいる' do
+ r = GroundPicture.list_json_opt[:include]
+ r[:panel].has_key?(:author).should be_true
+ end
+ it '実素材を含んでいる' do
+ r = GroundPicture.list_json_opt[:include]
+ r.has_key?(:picture).should be_true
+ end
+ it '実素材は絵師を含んでいる' do
+ r = GroundPicture.list_json_opt[:include]
+ r[:picture].has_key?(:artist).should be_true
+ end
+ it '実素材はライセンスを含んでいる' do
+ r = GroundPicture.list_json_opt[:include]
+ r[:picture].has_key?(:license).should be_true
+ end
+ end
+
+ describe '自分のコマで使った景色画像一覧取得に於いて' do
+ before do
+ @gp = FactoryGirl.create :ground_picture, :panel_id => @panel.id, :picture_id => @p.id
+ end
+ it 'リストを返す' do
+ pl = GroundPicture.mylist @author
+ pl.should eq [@gp]
+ end
+ it '時系列で並んでいる' do
+ npl = FactoryGirl.create :ground_picture, :panel_id => @panel.id, :picture_id => @p.id, :z => 2, :updated_at => Time.now + 100
+ pl = GroundPicture.mylist @author
+ pl.should eq [npl, @gp]
+ end
+ it '他人のコマの景色は公開でも含まない' do
+ hpl = FactoryGirl.create :panel, :author_id => @other_author.id, :publish => 1
+ npl = FactoryGirl.create :ground_picture, :panel_id => hpl.id, :picture_id => @p.id
+ pl = GroundPicture.mylist @author
+ pl.should eq [@gp]
+ end
+ end
+
+end
# -*- encoding: utf-8 -*-
+#原画
require 'spec_helper'
describe OriginalPicture do
@op.should_not be_valid
end
end
+ context 'md5を検証するとき' do
+ before do
+ @op = FactoryGirl.build :original_picture
+ end
+ it 'テストデータの確認' do
+ @op.md5 = 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'
+ @op.should be_valid
+ end
+ it 'nullなら失敗する' do
+ @op.md5 = ''
+ @op.should_not be_valid
+ end
+ it '32文字以上なら失敗する' do
+ @op.md5 = 'a'*33
+ @op.should_not be_valid
+ end
+ end
end
describe 'データ補充に於いて' do
end
end
end
+ describe '単体出力オプションに於いて' do
+ it 'includeキーを含んでいる' do
+ r = OriginalPicture.show_include_opt
+ r.has_key?(:include).should be_true
+ end
+ it '2つの項目を含んでいる' do
+ r = OriginalPicture.show_include_opt[:include]
+ r.should have(2).items
+ end
+ it '素材を含んでいる' do
+ r = OriginalPicture.show_include_opt[:include]
+ r.has_key?(:resource_picture).should be_true
+ end
+ it '実素材を含んでいる' do
+ r = OriginalPicture.show_include_opt[:include]
+ r.has_key?(:pictures).should be_true
+ end
+ end
describe 'json単体出力オプションに於いて' do
- it 'includeキーを含んでいる' do\r
- r = OriginalPicture.show_json_include_opt\r
- r.has_key?(:include).should be_true\r
- end\r
- it '1つの項目を含んでいる' do\r
- r = OriginalPicture.show_json_include_opt[:include]\r
- r.should have(1).items\r
- end\r
- it '素材を含んでいる' do\r
- r = OriginalPicture.show_json_include_opt[:include]\r
- r.has_key?(:resource_picture).should be_true\r
- end\r
+ it 'includeキーを含んでいる' do
+ r = OriginalPicture.show_json_include_opt
+ r.has_key?(:include).should be_true
+ end
+ it '2つの項目を含んでいる' do
+ r = OriginalPicture.show_json_include_opt[:include]
+ r.should have(2).items
+ end
+ it '素材を含んでいる' do
+ r = OriginalPicture.show_json_include_opt[:include]
+ r.has_key?(:resource_picture).should be_true
+ end
+ it '実素材を含んでいる' do
+ r = OriginalPicture.show_json_include_opt[:include]
+ r.has_key?(:pictures).should be_true
+ end
end
describe '一覧取得に於いて' do
before do
end
end
end
- describe 'list関連テーブルプションに於いて' do\r
- it 'includeキーを含んでいる' do\r
- r = OriginalPicture.list_opt\r
- r.has_key?(:include).should be_true\r
- end\r
- it '1つの項目を含んでいる' do\r
- r = OriginalPicture.list_opt[:include]\r
- r.should have(1).items\r
- end\r
- it '素材を含んでいる' do\r
- r = OriginalPicture.list_opt[:include]\r
- r.has_key?(:resource_picture).should be_true\r
- end\r
+ describe 'list関連テーブルプションに於いて' do
+ it 'includeキーを含んでいる' do
+ r = OriginalPicture.list_opt
+ r.has_key?(:include).should be_true
+ end
+ it '2つの項目を含んでいる' do
+ r = OriginalPicture.list_opt[:include]
+ r.should have(2).items
+ end
+ it '素材を含んでいる' do
+ r = OriginalPicture.list_opt[:include]
+ r.has_key?(:resource_picture).should be_true
+ end
+ it '実素材を含んでいる' do
+ r = OriginalPicture.list_opt[:include]
+ r.has_key?(:pictures).should be_true
+ end
+ end
+ describe 'json一覧出力オプションに於いて' do
+ it 'includeキーを含んでいる' do
+ r = OriginalPicture.list_json_opt
+ r.has_key?(:include).should be_true
+ end
+ it '2つの項目を含んでいる' do
+ r = OriginalPicture.list_json_opt[:include]
+ r.should have(2).items
+ end
+ it '素材を含んでいる' do
+ r = OriginalPicture.list_json_opt[:include]
+ r.has_key?(:resource_picture).should be_true
+ end
+ it '実素材を含んでいる' do
+ r = OriginalPicture.list_json_opt[:include]
+ r.has_key?(:pictures).should be_true
+ end
+ end
+ describe '更新履歴一覧取得に於いて' do
+ before do
+ @op = FactoryGirl.create :original_picture, :artist_id => @artist.id
+ @p = FactoryGirl.create :picture, :artist_id => @artist.id, :license_id => @license.id, :revision => 0,
+ :original_picture_id => @op.id
+ @op2 = FactoryGirl.create :original_picture, :artist_id => @artist.id
+ end
+ it 'リストを返す' do
+ r = @op.history
+ r.should eq [@p]
+ end
+ it '他の原画の実素材は含んでいない' do
+ @p2 = FactoryGirl.create :picture, :artist_id => @artist.id, :license_id => @license.id, :revision => 0,
+ :original_picture_id => @op2.id
+ r = @op.history
+ r.should eq [@p]
+ end
+ it 'revisionで並んでいる' do
+ @p2 = FactoryGirl.create :picture, :artist_id => @artist.id, :license_id => @license.id, :revision => 1,
+ :original_picture_id => @op.id
+ r = @op.history
+ r.should eq [@p2, @p]
+ end
end
- describe 'json一覧出力オプションに於いて' do\r
- it 'includeキーを含んでいる' do\r
- r = OriginalPicture.list_json_opt\r
- r.has_key?(:include).should be_true\r
- end\r
- it '1つの項目を含んでいる' do\r
- r = OriginalPicture.list_json_opt[:include]\r
- r.should have(1).items\r
- end\r
- it '素材を含んでいる' do\r
- r = OriginalPicture.list_json_opt[:include]\r
- r.has_key?(:resource_picture).should be_true\r
- end\r
- end\r
describe 'RMagick変換に於いて' do
before do
@op = FactoryGirl.build :original_picture, :artist_id => @artist.id
#すべての処理が正常パターンで通過すれば、一番深い分岐まで通る。
#それで外部のメソッド呼び出しだけに着目してテストする。
OriginalPicture.any_instance.stub(:data_to_mgk).with(any_args).and_return(Mgk.new)
- OriginalPicture.any_instance.stub(:save).with(any_args).and_return(true)\r
+ OriginalPicture.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
OriginalPicture.any_instance.should_receive(:data_to_mgk).exactly(1)
- @op.store 'bindata', @artist\r
+ @op.store 'bindata', @artist
end
it '自身に属性をセットしている' do
OriginalPicture.any_instance.should_receive(:attributes=).exactly(1)
- @op.store 'bindata', @artist\r
+ @op.store 'bindata', @artist
end
it '自身が保存されている' do
- OriginalPicture.any_instance.should_receive(:save).exactly(1)\r
- @op.store 'bindata', @artist\r
+ OriginalPicture.any_instance.should_receive(:save).exactly(1)
+ @op.store 'bindata', @artist
end
it 'PictureIoに画像データの保存を依頼している' do
PictureIO::LocalPicture.any_instance.should_receive(:put).with(any_args).exactly(1)
- @op.store 'bindata', @artist\r
+ @op.store 'bindata', @artist
end
end
context 'つつがなく終わるとき' do
before do
#すべての処理を正常パターンで通過させ、保存機能をチェックする。
OriginalPicture.any_instance.stub(:data_to_mgk).with(any_args).and_return(Mgk.new)
-# OriginalPicture.any_instance.stub(:save).with(any_args).and_return(true)\r
+# OriginalPicture.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 {
- @op.store 'bindata', @artist\r
+ @op.store 'bindata', @artist
}.should change @op, :filesize
end
it '原画モデルが作成されている' do
end
it '原画が保存されている' do
@op.store 'bindata', @artist
- OriginalPicture.find(@op).should_not be_nil\r
+ OriginalPicture.find(@op).should_not be_nil
end
it 'Trueを返す' do
- @op.store('bindata', @artist).should eq true\r
+ @op.store('bindata', @artist).should eq true
end
end
#以下から例外ケース。処理先頭から失敗させていく
OriginalPicture.any_instance.stub(:data_to_mgk).with(any_args).and_return(false)
end
it 'falseを返す' do
- @op.store('bindata', @artist).should be_false\r
+ @op.store('bindata', @artist).should be_false
end
it '自身の保存は呼ばれていない' do
- OriginalPicture.any_instance.should_not_receive(:save)\r
- @op.store('bindata', @artist)\r
+ OriginalPicture.any_instance.should_not_receive(:save)
+ @op.store('bindata', @artist)
end
end
context '自身の保存に失敗したとき' do
before do
OriginalPicture.any_instance.stub(:data_to_mgk).with(any_args).and_return(Mgk.new)
- OriginalPicture.any_instance.stub(:save).with(any_args).and_return(false)\r
+ OriginalPicture.any_instance.stub(:save).with(any_args).and_return(false)
end
it 'falseを返す' do
- @op.store('bindata', @artist).should be_false\r
+ @op.store('bindata', @artist).should be_false
end
it '更新されていない' do
@op.store('bindata', @artist)
- @op.should be_a_new OriginalPicture\r
+ @op.should be_a_new OriginalPicture
end
it '原画の保存は呼ばれていない' do
- PictureIO::LocalPicture.any_instance.should_not_receive(:put)\r
+ PictureIO::LocalPicture.any_instance.should_not_receive(:put)
end
end
context '原画の保存に失敗したとき' do
before do
OriginalPicture.any_instance.stub(:data_to_mgk).with(any_args).and_return(Mgk.new)
- OriginalPicture.any_instance.stub(:save).with(any_args).and_return(true)\r
+ OriginalPicture.any_instance.stub(:save).with(any_args).and_return(true)
PictureIO::LocalPicture.any_instance.stub(:put).with(any_args).and_return(false)
end
it 'falseを返す' do
- @op.store('bindata', @artist).should be_false\r
+ @op.store('bindata', @artist).should be_false
end
it '更新されていない' do
- @op.store('bindata', @artist)\r
- @op.should be_a_new OriginalPicture\r
+ @op.store('bindata', @artist)
+ @op.should be_a_new OriginalPicture
end
it '対象素材オブジェクトの保存は呼ばれていない' do
- ResourcePicture.any_instance.should_not_receive(:save)\r
- @op.store('bindata', @artist)\r
+ ResourcePicture.any_instance.should_not_receive(:save)
+ @op.store('bindata', @artist)
end
it '全体エラーメッセージがセットされている' do
lambda {
- @op.store('bindata', @artist)\r
+ @op.store('bindata', @artist)
}.should change(@op.errors[:base], :count)
end
end
--- /dev/null
+# -*- encoding: utf-8 -*-
+require 'spec_helper'
+#コマの色背景
+
+describe PanelColor do
+ before do
+ FactoryGirl.create :admin
+ @user = FactoryGirl.create( :user_yas)
+ @author = @user.author
+ @artist = FactoryGirl.create :artist_yas, :author_id => @author.id
+ @other_user = FactoryGirl.create( :user_yas)
+ @other_author = @other_user.author
+ @other_artist = FactoryGirl.create :artist_yas, :author_id => @other_author.id
+ @sp = FactoryGirl.create :system_picture
+ @lg = FactoryGirl.create :license_group
+ @license = FactoryGirl.create :license, :license_group_id => @lg.id, :system_picture_id => @sp.id
+ @op = FactoryGirl.create :original_picture, :artist_id => @artist.id
+ @p = FactoryGirl.create :picture, :original_picture_id => @op.id, :license_id => @license.id, :artist_id => @artist.id
+ @rp = FactoryGirl.create :resource_picture, :artist_id => @artist.id, :license_id => @license.id, :original_picture_id => @op.id, :picture_id => @p.id
+ @panel = FactoryGirl.create :panel, :author_id => @author.id
+ end
+
+ describe '検証に於いて' do
+ before do
+ @pc = FactoryGirl.build :panel_color, :panel_id => @panel.id
+ end
+ it 'オーソドックスなデータなら通る' do
+ @pc.save
+ @pc.should be_valid
+ end
+
+ context 'panel_idを検証するとき' do
+ #ネストの保存はnilを許可しなければならないので数値チェックだけ
+ it 'テストデータの確認' do
+ @pc.panel_id = @panel.id
+ @pc.should be_valid
+ end
+ it '数値でなければ失敗する' do
+ @pc.panel_id = 'a'
+ @pc.should_not be_valid
+ end
+ end
+ context 'codeを検証するとき' do
+ it 'テストデータの確認' do
+ @pc.code = 0xffffff
+ @pc.should be_valid
+ end
+ it 'nullなら失敗する' do
+ @pc.code = nil
+ @pc.should_not be_valid
+ end
+ it '数値でなければ失敗する' do
+ @pc.code = 'a'
+ @pc.should_not be_valid
+ end
+ it '負なら失敗する' do
+ @pc.code = -1
+ @pc.should_not be_valid
+ end
+ it '24bit colorでなければ失敗する' do
+ @pc.code = 0x1000000
+ @pc.should_not be_valid
+ end
+ end
+ context 'zを検証するとき' do
+ it 'テストデータの確認' do
+ @pc.z = 1
+ @pc.should be_valid
+ end
+ it 'nullなら失敗する' do
+ @pc.z = nil
+ @pc.should_not be_valid
+ end
+ it '数値でなければ失敗する' do
+ @pc.z = 'a'
+ @pc.should_not be_valid
+ end
+ it '負なら失敗する' do
+ @pc.z = -1
+ @pc.should_not be_valid
+ end
+ it '負なら失敗する' do
+ @pc.z = 0
+ @pc.should_not be_valid
+ end
+ end
+ end
+ describe '一覧取得に於いて' do
+ before do
+ @pc = FactoryGirl.create :panel_color, :panel_id => @panel.id
+ end
+ context 'page補正について' do
+ it '文字列から数値に変換される' do
+ PanelColor.page('8').should eq 8
+ end
+ it 'nilの場合は1になる' do
+ PanelColor.page().should eq 1
+ end
+ it '0以下の場合は1になる' do
+ PanelColor.page('0').should eq 1
+ end
+ end
+ context 'page_size補正について' do
+ it '文字列から数値に変換される' do
+ PanelColor.page_size('7').should eq 7
+ end
+ it 'nilの場合はPanelColor.default_page_sizeになる' do
+ PanelColor.page_size().should eq PanelColor.default_page_size
+ end
+ it '0以下の場合はPanelColor.default_page_sizeになる' do
+ PanelColor.page_size('0').should eq PanelColor.default_page_size
+ end
+ it 'PanelColor.max_page_sizeを超えた場合はPanelColor.max_page_sizeになる' do
+ PanelColor.page_size('1000').should eq PanelColor.max_page_size
+ end
+ end
+ it 'リストを返す' do
+ pl = PanelColor.list
+ pl.should eq [@pc]
+ end
+ it '時系列で並んでいる' do
+ npl = FactoryGirl.create :panel_color, :panel_id => @panel.id, :z => 2, :updated_at => Time.now + 100
+ pl = PanelColor.list
+ pl.should eq [npl, @pc]
+ end
+ it '非公開のコマの景色は含まない' do
+ hpl = FactoryGirl.create :panel, :author_id => @author.id, :publish => 0
+ npl = FactoryGirl.create :panel_color, :panel_id => hpl.id, :updated_at => Time.now + 100
+ pl = PanelColor.list
+ pl.should eq [@pc]
+ end
+ context 'DBに5件あって1ページの件数を2件に変えたとして' do
+ before do
+ @npl2 = FactoryGirl.create :panel_color, :panel_id => @panel.id, :z => 1, :updated_at => Time.now + 100
+ @npl3 = FactoryGirl.create :panel_color, :panel_id => @panel.id, :z => 2, :updated_at => Time.now + 200
+ @npl4 = FactoryGirl.create :panel_color, :panel_id => @panel.id, :z => 3, :updated_at => Time.now + 300
+ @npl5 = FactoryGirl.create :panel_color, :panel_id => @panel.id, :z => 4, :updated_at => Time.now + 400
+ PanelColor.stub(:default_page_size).and_return(2)
+ end
+ it '通常は2件を返す' do
+ pl = PanelColor.list
+ pl.should have(2).items
+ end
+ it 'page=1なら末尾2件を返す' do
+ #時系列で並んでいる
+ pl = PanelColor.list( {}, 1)
+ pl.should eq [@npl5, @npl4]
+ end
+ it 'page=2なら中間2件を返す' do
+ pl = PanelColor.list({}, 2)
+ pl.should eq [@npl3, @npl2]
+ end
+ it 'page=3なら先頭1件を返す' do
+ pl = PanelColor.list({}, 3)
+ pl.should eq [@pc]
+ end
+ end
+ end
+ describe 'list関連テーブルプションに於いて' do
+ it 'includeキーを含んでいる' do
+ r = PanelColor.list_opt
+ r.has_key?(:include).should be_true
+ end
+ it '1つの項目を含んでいる' do
+ r = PanelColor.list_opt[:include]
+ r.should have(1).items
+ end
+ it 'コマを含んでいる' do
+ r = PanelColor.list_opt[:include]
+ r.has_key?(:panel).should be_true
+ end
+ it 'コマは作家を含んでいる' do
+ r = PanelColor.list_opt[:include]
+ r[:panel].has_key?(:author).should be_true
+ end
+ end
+ describe 'json一覧出力オプションに於いて' do
+ it 'includeキーを含んでいる' do
+ r = PanelColor.list_json_opt
+ r.has_key?(:include).should be_true
+ end
+ it '1つの項目を含んでいる' do
+ r = PanelColor.list_json_opt[:include]
+ r.should have(1).items
+ end
+ it 'コマを含んでいる' do
+ r = PanelColor.list_json_opt[:include]
+ r.has_key?(:panel).should be_true
+ end
+ it 'コマは作家を含んでいる' do
+ r = PanelColor.list_json_opt[:include]
+ r[:panel].has_key?(:author).should be_true
+ end
+ end
+
+ describe '自分のコマで使った色一覧取得に於いて' do
+ before do
+ @pc = FactoryGirl.create :panel_color, :panel_id => @panel.id
+ end
+ it 'リストを返す' do
+ pl = PanelColor.mylist @author
+ pl.should eq [@pc]
+ end
+ it '時系列で並んでいる' do
+ npl = FactoryGirl.create :panel_color, :panel_id => @panel.id, :z => 2, :updated_at => Time.now + 100
+ pl = PanelColor.mylist @author
+ pl.should eq [npl, @pc]
+ end
+ it '他人のコマの景色は公開でも含まない' do
+ hpl = FactoryGirl.create :panel, :author_id => @other_author.id, :publish => 1
+ npl = FactoryGirl.create :panel_color, :panel_id => hpl.id
+ pl = PanelColor.mylist @author
+ pl.should eq [@pc]
+ end
+ end
+
+end
before do
@pp = FactoryGirl.build :panel_picture, :panel_id => @panel.id, :picture_id => @p.id,
:width => @p.width, :height => @p.height
+ Picture.any_instance.stub(:flag_reverse).with(any_args).and_return(0)
+ Picture.any_instance.stub(:flag_resize).with(any_args).and_return(0)
+ Picture.any_instance.stub(:flag_sync_vh).with(any_args).and_return(0)
end
it 'オーソドックスなデータなら通る' do
- @pp.save!
+ @pp.save
@pp.should be_valid
end
end
context 'widthを検証するとき' do
before do
- Picture.any_instance.stub(:flag_reverse).with(any_args).and_return(0)
- Picture.any_instance.stub(:flag_resize).with(any_args).and_return(0)
- Picture.any_instance.stub(:flag_sync_vh).with(any_args).and_return(0)
end
it 'テストデータの確認' do
@pp.width = 1
end
context '反転許可のとき' do
before do
- Picture.any_instance.stub(:flag_reverse).with(any_args).and_return(0)
end
it '負でも通る' do
@pp.width = -1
end
context 'サイズ変更許可のとき' do
before do
- Picture.any_instance.stub(:flag_resize).with(any_args).and_return(0)
end
it '実素材のサイズと違っても通る' do
@pp.width = @p.width-1
end
context '縦横比変更許可のとき' do
before do
- Picture.any_instance.stub(:flag_sync_vh).with(any_args).and_return(0)
end
it '実素材の縦横比と違っても通る' do
@pp.width = @p.width / 2
end
context 'heightを検証するとき' do
before do
- Picture.any_instance.stub(:flag_reverse).with(any_args).and_return(0)
- Picture.any_instance.stub(:flag_resize).with(any_args).and_return(0)
- Picture.any_instance.stub(:flag_sync_vh).with(any_args).and_return(0)
end
it 'テストデータの確認' do
@pp.height = '1'
end
context '反転許可のとき' do
before do
- Picture.any_instance.stub(:flag_reverse).with(any_args).and_return(0)
end
it '負でも通る' do
@pp.height = -1
end
context 'サイズ変更許可のとき' do
before do
- Picture.any_instance.stub(:flag_resize).with(any_args).and_return(0)
end
it '実素材のサイズと違っても通る' do
@pp.height = @p.height-1
end
context '縦横比変更許可のとき' do
before do
- Picture.any_instance.stub(:flag_sync_vh).with(any_args).and_return(0)
end
it '実素材の縦横比と違っても通る' do
@pp.height = @p.height / 2
@pp.should_not be_valid
end
end
+ context 'picture_idを検証するとき' do
+ it 'テストデータの確認' do
+ @pp.picture_id = @p.id
+ @pp.should be_valid
+ end
+ it 'nullなら失敗する' do
+ @pp.picture_id = nil
+ @pp.should_not be_valid
+ end
+ it '数値でなければ失敗する' do
+ @pp.picture_id = 'a'
+ @pp.should_not be_valid
+ end
+ it '存在する実素材でなければ失敗する' do
+ @pp.picture_id = 0
+ @pp.should_not be_valid
+ end
+ end
end
describe '一覧取得に於いて' do
before do
end\r
end\r
end\r
- describe '単体取得に於いて' do\r
+ describe '編集取得に於いて' do\r
before do\r
@panel = FactoryGirl.create :panel, :author_id => @author.id\r
end\r
end\r
end\r
describe '関連テーブルプションに於いて' do\r
- context 'オプションがないとき' do\r
- it '3つの項目を含んでいる' do\r
- r = Panel.show_include_opt\r
- r.should have(3).items\r
- end\r
- it 'コマ絵を含んでいる' do\r
+ it '6つの項目を含んでいる' do\r
+ r = Panel.show_include_opt\r
+ r.should have(6).items\r
+ end\r
+ it 'コマ絵を含んでいる' do\r
+ r = Panel.show_include_opt\r
+ r.has_key?(:panel_pictures).should be_true\r
+ end\r
+ it 'コマ絵は実素材を含んでいる' do\r
r = Panel.show_include_opt\r
- r.has_key?(:panel_pictures).should be_true\r
+ r[:panel_pictures].has_key?(:picture).should be_true\r
end\r
- it 'コマ絵は実素材を含んでいる' do\r
+ it '実素材は絵師を含んでいる' do\r
r = Panel.show_include_opt\r
- r[:panel_pictures].has_key?(:picture).should be_true\r
+ r[:panel_pictures][:picture].has_key?(:artist).should be_true\r
end\r
- it '実素材は絵師を含んでいる' do\r
- r = Panel.show_include_opt\r
- r[:panel_pictures][:picture].has_key?(:artist).should be_true\r
- end\r
- it '実素材はライセンスを含んでいる' do\r
- r = Panel.show_include_opt\r
- r[:panel_pictures][:picture].has_key?(:license).should be_true\r
- end\r
- it 'フキダシを含んでいる' do\r
+ it '実素材はライセンスを含んでいる' do\r
+ r = Panel.show_include_opt\r
+ r[:panel_pictures][:picture].has_key?(:license).should be_true\r
+ end\r
+ it 'フキダシを含んでいる' do\r
+ r = Panel.show_include_opt\r
+ r.has_key?(:speech_balloons).should be_true\r
+ end\r
+ it 'フキダシはフキダシ枠を含んでいる' do\r
+ r = Panel.show_include_opt\r
+ r[:speech_balloons].has_key?(:balloons).should be_true\r
+ end\r
+ it 'フキダシはセリフを含んでいる' do\r
r = Panel.show_include_opt\r
- r.has_key?(:speech_balloons).should be_true\r
+ r[:speech_balloons].has_key?(:speeches).should be_true\r
end\r
- it 'フキダシはフキダシ枠を含んでいる' do\r
+ it '景色画像を含んでいる' do\r
+ r = Panel.show_include_opt\r
+ r.has_key?(:ground_pictures).should be_true\r
+ end\r
+ it '景色画像は実素材を含んでいる' do\r
+ r = Panel.show_include_opt\r
+ r[:ground_pictures].has_key?(:picture).should be_true\r
+ end\r
+ it '実素材は絵師を含んでいる' do\r
r = Panel.show_include_opt\r
- r[:speech_balloons].has_key?(:balloons).should be_true\r
+ r[:ground_pictures][:picture].has_key?(:artist).should be_true\r
end\r
- it 'フキダシはセリフを含んでいる' do\r
+ it '実素材はライセンスを含んでいる' do\r
r = Panel.show_include_opt\r
- r[:speech_balloons].has_key?(:speeches).should be_true\r
+ r[:ground_pictures][:picture].has_key?(:license).should be_true\r
end\r
- it '作家を含んでいる' do\r
+ it '間接色を含んでいる' do\r
+ r = Panel.show_include_opt\r
+ r.has_key?(:ground_colors).should be_true\r
+ end\r
+ it '間接色は色を含んでいる' do\r
r = Panel.show_include_opt\r
- r.has_key?(:author).should be_true\r
+ r[:ground_colors].has_key?(:color).should be_true\r
end\r
+ it '景色を含んでいる' do\r
+ r = Panel.show_include_opt\r
+ r.has_key?(:panel_colors).should be_true\r
end\r
- context 'オプションで原画を含ませたとき' do\r
- it '4つの項目を含んでいる' do\r
- r = Panel.show_include_opt(:include => {:test => {}})\r
- r.should have(4).items\r
- end\r
- it 'testを含んでいる' do\r
- r = Panel.show_include_opt(:include => {:test => {}})\r
- r.has_key?(:test).should be_true\r
- end\r
+ it '作家を含んでいる' do\r
+ r = Panel.show_include_opt\r
+ r.has_key?(:author).should be_true\r
end\r
end\r
describe 'json単体出力オプションに於いて' do\r
r = Panel.show_json_include_opt\r
r.has_key?(:include).should be_true\r
end\r
- it '3つの項目を含んでいる' do\r
+ it '6つの項目を含んでいる' do\r
r = Panel.show_json_include_opt[:include]\r
- r.should have(3).items\r
+ r.should have(6).items\r
end\r
it 'コマ絵を含んでいる' do\r
r = Panel.show_json_include_opt[:include]\r
r[:panel_pictures][:picture].has_key?(:license).should be_true\r
end\r
it 'フキダシを含んでいる' do\r
- r = Panel.show_include_opt\r
+ r = Panel.show_json_include_opt[:include]\r
r.has_key?(:speech_balloons).should be_true\r
end\r
it 'フキダシはフキダシ枠を含んでいる' do\r
- r = Panel.show_include_opt\r
+ r = Panel.show_json_include_opt[:include]\r
r[:speech_balloons].has_key?(:balloons).should be_true\r
end\r
it 'フキダシはセリフを含んでいる' do\r
- r = Panel.show_include_opt\r
+ r = Panel.show_json_include_opt[:include]\r
r[:speech_balloons].has_key?(:speeches).should be_true\r
end\r
+ it '景色画像を含んでいる' do\r
+ r = Panel.show_json_include_opt[:include]\r
+ r.has_key?(:ground_pictures).should be_true\r
+ end\r
+ it '景色画像は実素材を含んでいる' do\r
+ r = Panel.show_json_include_opt[:include]\r
+ r[:ground_pictures].has_key?(:picture).should be_true\r
+ end\r
+ it '実素材は絵師を含んでいる' do\r
+ r = Panel.show_json_include_opt[:include]\r
+ r[:ground_pictures][:picture].has_key?(:artist).should be_true\r
+ end\r
+ it '実素材はライセンスを含んでいる' do\r
+ r = Panel.show_json_include_opt[:include]\r
+ r[:ground_pictures][:picture].has_key?(:license).should be_true\r
+ end\r
+ it '間接色を含んでいる' do\r
+ r = Panel.show_json_include_opt[:include]\r
+ r.has_key?(:ground_colors).should be_true\r
+ end\r
+ it '間接色は色を含んでいる' do\r
+ r = Panel.show_json_include_opt[:include]\r
+ r[:ground_colors].has_key?(:color).should be_true\r
+ end\r
+ it '景色を含んでいる' do\r
+ r = Panel.show_json_include_opt[:include]\r
+ r.has_key?(:panel_colors).should be_true\r
+ end\r
it '作家を含んでいる' do\r
r = Panel.show_json_include_opt[:include]\r
r.has_key?(:author).should be_true\r
r = Panel.list_opt\r
r.has_key?(:include).should be_true\r
end\r
- it '3つの項目を含んでいる' do\r
+ it '6つの項目を含んでいる' do\r
r = Panel.list_opt[:include]\r
- r.should have(3).items\r
+ r.should have(6).items\r
end\r
it 'コマ絵を含んでいる' do\r
r = Panel.list_opt[:include]\r
r[:panel_pictures][:picture].has_key?(:license).should be_true\r
end\r
it 'フキダシを含んでいる' do\r
- r = Panel.show_include_opt\r
+ r = Panel.list_opt[:include]\r
r.has_key?(:speech_balloons).should be_true\r
end\r
it 'フキダシはフキダシ枠を含んでいる' do\r
- r = Panel.show_include_opt\r
+ r = Panel.list_opt[:include]\r
r[:speech_balloons].has_key?(:balloons).should be_true\r
end\r
it 'フキダシはセリフを含んでいる' do\r
- r = Panel.show_include_opt\r
+ r = Panel.list_opt[:include]\r
r[:speech_balloons].has_key?(:speeches).should be_true\r
end\r
+ it '景色画像を含んでいる' do\r
+ r = Panel.list_opt[:include]\r
+ r.has_key?(:ground_pictures).should be_true\r
+ end\r
+ it '景色画像は実素材を含んでいる' do\r
+ r = Panel.list_opt[:include]\r
+ r[:ground_pictures].has_key?(:picture).should be_true\r
+ end\r
+ it '実素材は絵師を含んでいる' do\r
+ r = Panel.list_opt[:include]\r
+ r[:ground_pictures][:picture].has_key?(:artist).should be_true\r
+ end\r
+ it '実素材はライセンスを含んでいる' do\r
+ r = Panel.list_opt[:include]\r
+ r[:ground_pictures][:picture].has_key?(:license).should be_true\r
+ end\r
+ it '間接色を含んでいる' do\r
+ r = Panel.list_opt[:include]\r
+ r.has_key?(:ground_colors).should be_true\r
+ end\r
+ it '間接色は色を含んでいる' do\r
+ r = Panel.list_opt[:include]\r
+ r[:ground_colors].has_key?(:color).should be_true\r
+ end\r
+ it '景色を含んでいる' do\r
+ r = Panel.list_opt[:include]\r
+ r.has_key?(:panel_colors).should be_true\r
+ end\r
it '作家を含んでいる' do\r
r = Panel.list_opt[:include]\r
r.has_key?(:author).should be_true\r
r = Panel.list_json_opt\r
r.has_key?(:include).should be_true\r
end\r
- it '3つの項目を含んでいる' do\r
+ it '6つの項目を含んでいる' do\r
r = Panel.list_json_opt[:include]\r
- r.should have(3).items\r
+ r.should have(6).items\r
end\r
it 'コマ絵を含んでいる' do\r
r = Panel.list_json_opt[:include]\r
r[:panel_pictures][:picture].has_key?(:license).should be_true\r
end\r
it 'フキダシを含んでいる' do\r
- r = Panel.show_include_opt\r
+ r = Panel.list_json_opt[:include]\r
r.has_key?(:speech_balloons).should be_true\r
end\r
it 'フキダシはフキダシ枠を含んでいる' do\r
- r = Panel.show_include_opt\r
+ r = Panel.list_json_opt[:include]\r
r[:speech_balloons].has_key?(:balloons).should be_true\r
end\r
it 'フキダシはセリフを含んでいる' do\r
- r = Panel.show_include_opt\r
+ r = Panel.list_json_opt[:include]\r
r[:speech_balloons].has_key?(:speeches).should be_true\r
end\r
+ it '景色画像を含んでいる' do\r
+ r = Panel.list_json_opt[:include]\r
+ r.has_key?(:ground_pictures).should be_true\r
+ end\r
+ it '景色画像は実素材を含んでいる' do\r
+ r = Panel.list_json_opt[:include]\r
+ r[:ground_pictures].has_key?(:picture).should be_true\r
+ end\r
+ it '実素材は絵師を含んでいる' do\r
+ r = Panel.list_json_opt[:include]\r
+ r[:ground_pictures][:picture].has_key?(:artist).should be_true\r
+ end\r
+ it '実素材はライセンスを含んでいる' do\r
+ r = Panel.list_json_opt[:include]\r
+ r[:ground_pictures][:picture].has_key?(:license).should be_true\r
+ end\r
+ it '間接色を含んでいる' do\r
+ r = Panel.list_json_opt[:include]\r
+ r.has_key?(:ground_colors).should be_true\r
+ end\r
+ it '間接色は色を含んでいる' do\r
+ r = Panel.list_json_opt[:include]\r
+ r[:ground_colors].has_key?(:color).should be_true\r
+ end\r
+ it '景色を含んでいる' do\r
+ r = Panel.list_json_opt[:include]\r
+ r.has_key?(:panel_colors).should be_true\r
+ end\r
it '作家を含んでいる' do\r
r = Panel.list_json_opt[:include]\r
r.has_key?(:author).should be_true\r
@p.should_not be_valid
end
end
+ context 'md5を検証するとき' do
+ before do
+ @p = FactoryGirl.build :picture
+ end
+ it 'テストデータの確認' do
+ @p.md5 = 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'
+ @p.should be_valid
+ end
+ it 'nullなら失敗する' do
+ @p.md5 = ''
+ @p.should_not be_valid
+ end
+ it '32文字以上なら失敗する' do
+ @p.md5 = 'a'*33
+ @p.should_not be_valid
+ end
+ end
context 'license_idを検証するとき' do
before do
@p = FactoryGirl.build :picture, :original_picture_id => @op.id, :license_id => @license.id
@p.height.should eq 265
@p.filesize.should eq 266
@p.artist_id.should eq @artist.id
+ @p.md5.should eq @rp.md5
@p.license_id.should eq @license.id
@p.original_picture_id.should eq @op.id
@p.artist_name.should eq 'tester'
end
end
+ describe 'md5重複リストに於いて' do
+ before do
+ @op = FactoryGirl.create :original_picture, :artist_id => @artist.id
+ @p = FactoryGirl.create :picture, :artist_id => @artist.id, :license_id => @license.id, :revision => 0,
+ :original_picture_id => @op.id, :md5 => 'a' * 32
+ @rp = FactoryGirl.create :resource_picture, :artist_id => @artist.id, :original_picture_id => @op.id, :license_id => @license.id, :picture_id => @p.id
+ @op2 = FactoryGirl.create :original_picture, :artist_id => @artist.id
+ @p2 = FactoryGirl.create :picture, :artist_id => @artist.id, :license_id => @license.id, :revision => 0,
+ :original_picture_id => @op2.id, :md5 => 'b' * 32
+ @op3 = FactoryGirl.create :original_picture, :artist_id => @artist.id
+ end
+ it 'リストを返す' do
+ res = Picture.list_by_md5(@p.md5, @p.original_picture_id)
+ res.is_a?(Array).should be_true
+ end
+ it 'md5が違えば含まない' do
+ res = Picture.list_by_md5(@p.md5, @p.original_picture_id)
+ res.include?(@p2).should be_false
+ end
+ it '同一原画は含まない' do
+ res = Picture.list_by_md5(@p.md5, @p.original_picture_id)
+ res.empty?.should be_true
+ end
+ it '同一原画は旧版でも含まない' do
+ @p3 = FactoryGirl.create :picture, :artist_id => @artist.id, :license_id => @license.id, :revision => 1,
+ :original_picture_id => @op.id, :md5 => 'a' * 32
+ res = Picture.list_by_md5(@p.md5, @p.original_picture_id)
+ res.empty?.should be_true
+ end
+ it '他所の原画なら含む' do
+ @p3 = FactoryGirl.create :picture, :artist_id => @artist.id, :license_id => @license.id, :revision => 1,
+ :original_picture_id => @op2.id, :md5 => 'a' * 32
+ res = Picture.list_by_md5(@p.md5, @p.original_picture_id)
+ res.should eq [@p3]
+ end
+ it '他所の原画でもmd5が違えば含まない' do
+ @p3 = FactoryGirl.create :picture, :artist_id => @artist.id, :license_id => @license.id, :revision => 1,
+ :original_picture_id => @op2.id, :md5 => 'c' * 32
+ res = Picture.list_by_md5(@p.md5, @p.original_picture_id)
+ res.empty?.should be_true
+ end
+ it '更新日時順' do
+ @p3 = FactoryGirl.create :picture, :artist_id => @artist.id, :license_id => @license.id, :revision => 1,
+ :original_picture_id => @op2.id, :md5 => 'a' * 32
+ @p4 = FactoryGirl.create :picture, :artist_id => @artist.id, :license_id => @license.id, :revision => 1,
+ :original_picture_id => @op3.id, :md5 => 'a' * 32, :updated_at => Time.now + 100
+ res = Picture.list_by_md5(@p.md5, @p.original_picture_id)
+ res.should eq [@p4, @p3]
+ end
+ end
+
+ describe 'md5重複判定に於いて' do
+ before do
+ @op = FactoryGirl.create :original_picture, :artist_id => @artist.id
+ @op2 = FactoryGirl.create :original_picture, :artist_id => @artist.id
+ @p = FactoryGirl.create :picture, :artist_id => @artist.id, :original_picture_id => @op.id, :license_id => @license.id, :revision => 0
+ @rp = FactoryGirl.create :resource_picture, :artist_id => @artist.id, :original_picture_id => @op.id, :license_id => @license.id, :picture_id => @p.id
+ end
+ context '同一原画以外に同じ値があるとき' do
+ before do
+ @p2 = FactoryGirl.create :picture, :artist_id => @artist.id, :original_picture_id => @op2.id, :license_id => @license.id
+ end
+ it 'trueを返す' do
+ res = Picture.exist_by_md5(@p.md5, @p.original_picture_id)
+ res.should be_true
+ end
+ end
+ context '同一原画以外に同じ値がないとき' do
+ it 'falseを返す' do
+ res = Picture.exist_by_md5(@p.md5, @p.original_picture_id)
+ res.should be_false
+ end
+ end
+ context '同一原画に同じ値があるとき' do
+ before do
+ @p2 = FactoryGirl.create :picture, :artist_id => @artist.id, :original_picture_id => @op.id, :license_id => @license.id, :revision => 1
+ end
+ it 'falseを返す' do
+ res = Picture.exist_by_md5(@p.md5, @p.original_picture_id)
+ res.should be_false
+ end
+ end
+ end
+
+ describe 'head判定に於いて' do
+ before do
+ end
+ context '自身とリンクした素材があるとき' do
+ before do
+ @op = FactoryGirl.create :original_picture, :artist_id => @artist.id
+ @p = FactoryGirl.create :picture, :artist_id => @artist.id, :original_picture_id => @op.id, :license_id => @license.id
+ @rp = FactoryGirl.create :resource_picture, :artist_id => @artist.id, :original_picture_id => @op.id, :license_id => @license.id, :picture_id => @p.id
+ end
+ it 'trueを返す' do
+ res = @p.head?
+ res.should be_true
+ end
+ end
+ context '自身とリンクした素材がないとき' do
+ before do
+ @op = FactoryGirl.create :original_picture, :artist_id => @artist.id
+ @p = FactoryGirl.create :picture, :artist_id => @artist.id, :original_picture_id => @op.id, :license_id => @license.id, :revision => 0
+ @p2 = FactoryGirl.create :picture, :artist_id => @artist.id, :original_picture_id => @op.id, :license_id => @license.id, :revision => 1
+ @rp = FactoryGirl.create :resource_picture, :artist_id => @artist.id, :original_picture_id => @op.id, :license_id => @license.id, :picture_id => @p2.id
+ end
+ it 'falseを返す' do
+ res = @p.head?
+ res.should be_false
+ end
+ end
+ end
+
describe '作成に於いて' do
before do
#RMagickのスタブをおいておく
@rp.should_not be_valid\r
end\r
end\r
+ context 'md5を検証するとき' do\r
+ before do\r
+ @rp = FactoryGirl.build :picture\r
+ end\r
+ it 'テストデータの確認' do\r
+ @rp.md5 = 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'\r
+ @rp.should be_valid\r
+ end\r
+ it 'nullなら失敗する' do\r
+ @rp.md5 = ''\r
+ @rp.should_not be_valid\r
+ end\r
+ it '32文字以上なら失敗する' do\r
+ @rp.md5 = 'a'*33\r
+ @rp.should_not be_valid\r
+ end\r
+ end\r
context 'license_idを検証するとき' do\r
it 'テストデータの確認' do\r
@rp.license_id = @license.id\r
@rp.width.should eq 264\r
@rp.height.should eq 265\r
@rp.filesize.should eq 266\r
+ @rp.md5.should eq @op.md5\r
@rp.artist_id.should eq @artist.id\r
end\r
end\r
ResourcePicture.stub(:png_to_gif).with(any_args).and_return(@gifmgk)\r
end\r
it '画像ファイルの作成・更新機能で画像を保存している' do\r
- ResourcePicture.any_instance.stub(:filename).with(any_args).and_return('1.png')
+ ResourcePicture.any_instance.stub(:filename).with(any_args).and_return('1.png')\r
ResourcePicture.any_instance.should_receive(:store_picture).with(@mgk, '1.png').exactly(1)\r
res = @rp.store_picture_with_gif @mgk\r
end\r
end\r
it '画像ファイルの作成・更新機能でgif画像を保存している' do\r
#二回目の保存はgif変換の結果を渡す。\r
- ResourcePicture.any_instance.stub(:gifname).with(any_args).and_return('1.gif')
+ ResourcePicture.any_instance.stub(:gifname).with(any_args).and_return('1.gif')\r
ResourcePicture.any_instance.should_receive(:store_picture).with(@gifmgk, '1.gif').exactly(1)\r
res = @rp.store_picture_with_gif @mgk\r
end\r
end\r
context 'gif画像の保存に失敗したとき' do\r
before do\r
- ResourcePicture.any_instance.stub(:filename).with(any_args).and_return('1.png')
- ResourcePicture.any_instance.stub(:gifname).with(any_args).and_return('1.gif')
+ ResourcePicture.any_instance.stub(:filename).with(any_args).and_return('1.png')\r
+ ResourcePicture.any_instance.stub(:gifname).with(any_args).and_return('1.gif')\r
@mgk = Mgk.new\r
ResourcePicture.any_instance.stub(:store_picture).with(@mgk, '1.png').and_return(true)\r
ResourcePicture.any_instance.stub(:to_gif?).with(any_args).and_return(true)\r
#すべての処理を正常パターンで通過させ、保存機能をチェックする。\r
PictureIO.resource_picture_io.stub(:put).with(any_args).and_return(true)\r
ResourcePicture.any_instance.stub(:flag_thumbnail).with(any_args).and_return(1)\r
+ ResourcePicture.any_instance.stub(:thumbnail).with(any_args).and_return('tmbdata')\r
end\r
it 'Trueを返す' do\r
-# res = @rp.store_picture(Mgk.new, '1.gif')\r
-# res.should be_true\r
+ res = @rp.store_picture(Mgk.new, '1.gif')\r
+ res.should be_true\r
end\r
end\r
context '例外ケース' do\r
before do\r
ResourcePicture.any_instance.stub(:flag_thumbnail).with(any_args).and_return(1)\r
+ ResourcePicture.any_instance.stub(:thumbnail).with(any_args).and_return('tmbdata')\r
PictureIO.resource_picture_io.stub(:put).with(any_args).and_return(false)\r
end\r
- it 'Falseを返す' do\r
- # res = @rp.store_picture(Mgk.new, '1.gif')\r
- # res.should be_false\r
+ it '画像の保存に失敗したならFalseを返す' do\r
+ res = @rp.store_picture(Mgk.new, '1.gif')\r
+ res.should be_false\r
end\r
end\r
\r
@story.own?(nil).should == false
end
end
- describe '単体取得に於いて' do
+ describe '編集取得に於いて' do
before do
@comic = FactoryGirl.create :comic, :author_id => @author.id
@panel = FactoryGirl.create :panel, :author_id => @author.id