# encoding: utf-8 require File.join(File.expand_path(File.dirname(__FILE__)), "spec_helper") module CellHelpers # Build, but do not draw, a cell on @pdf. def cell(options={}) at = options[:at] || [0, @pdf.cursor] Prawn::Table::Cell::Text.new(@pdf, at, options) end end describe "Prawn::Table::Cell" do before(:each) do @pdf = Prawn::Document.new end describe "Prawn::Document#cell" do include CellHelpers it "should draw the cell" do Prawn::Table::Cell::Text.any_instance.expects(:draw).once @pdf.cell(:content => "text") end it "should return a Cell" do @pdf.cell(:content => "text").should be_a_kind_of Prawn::Table::Cell end it "accepts :content => nil in a hash" do @pdf.cell(:content => nil).should be_a_kind_of(Prawn::Table::Cell::Text) @pdf.make_cell(:content => nil).should be_a_kind_of(Prawn::Table::Cell::Text) end it "should convert nil, Numeric, and Date values to strings" do [nil, 123, 123.45, Date.today].each do |value| c = @pdf.cell(:content => value) c.should be_a_kind_of Prawn::Table::Cell::Text c.content.should == value.to_s end end it "should allow inline styling with a hash argument" do # used for table([[{:text => "...", :font_style => :bold, ...}, ...]]) c = Prawn::Table::Cell.make(@pdf, {:content => 'hello', :font_style => :bold}) c.should be_a_kind_of Prawn::Table::Cell::Text c.content.should == "hello" c.font.name.should == 'Helvetica-Bold' end it "should draw text at the given point plus padding, with the given " + "size and style" do @pdf.expects(:bounding_box).yields @pdf.expects(:move_down) @pdf.expects(:draw_text!).with { |text, options| text == "hello world" } @pdf.cell(:content => "hello world", :at => [10, 20], :padding => [30, 40], :size => 7, :font_style => :bold) end end describe "Prawn::Document#make_cell" do it "should not draw the cell" do Prawn::Table::Cell::Text.any_instance.expects(:draw).never @pdf.make_cell("text") end it "should return a Cell" do @pdf.make_cell("text", :size => 7).should be_a_kind_of Prawn::Table::Cell end end describe "#style" do include CellHelpers it "should set each property in turn" do c = cell(:content => "text") c.expects(:padding=).with(50) c.expects(:size=).with(7) c.style(:padding => 50, :size => 7) end end describe "cell width" do include CellHelpers it "should be calculated for text" do c = cell(:content => "text") c.width.should == @pdf.width_of("text") + c.padding[1] + c.padding[3] end it "should be overridden by manual :width" do c = cell(:content => "text", :width => 400) c.width.should == 400 end it "should incorporate padding when specified" do c = cell(:content => "text", :padding => [1, 2, 3, 4]) c.width.should be_within(0.01).of(@pdf.width_of("text") + 6) end it "should allow width to be reset after it has been calculated" do # to ensure that if we memoize width, it can still be overridden c = cell(:content => "text") c.width c.width = 400 c.width.should == 400 end it "should return proper width with size set" do text = "text " * 4 c = cell(:content => text, :size => 7) c.width.should == @pdf.width_of(text, :size => 7) + c.padding[1] + c.padding[3] end it "content_width should exclude padding" do c = cell(:content => "text", :padding => 10) c.content_width.should == @pdf.width_of("text") end it "content_width should exclude padding even with manual :width" do c = cell(:content => "text", :padding => 10, :width => 400) c.content_width.should be_within(0.01).of(380) end it "should have a reasonable minimum width that can fit @content" do c = cell(:content => "text", :padding => 10) min_content_width = c.min_width - c.padding[1] - c.padding[3] lambda { @pdf.height_of("text", :width => min_content_width) }. should_not raise_error(Prawn::Errors::CannotFit) @pdf.height_of("text", :width => min_content_width).should be < (5 * @pdf.height_of("text")) end it "should defer min_width's evaluation of padding" do c = cell(:content => "text", :padding => 100) c.padding = 0 # Make sure we use the new value of padding in calculating min_width c.min_width.should be < 100 end it "should defer min_width's evaluation of size" do c = cell(:content => "text", :size => 50) c.size = 8 c.padding = 0 c.min_width.should be < 10 end end describe "cell height" do include CellHelpers it "should be calculated for text" do c = cell(:content => "text") c.height.should == @pdf.height_of("text", :width => @pdf.width_of("text")) + c.padding[0] + c.padding[3] end it "should be overridden by manual :height" do c = cell(:content => "text", :height => 400) c.height.should == 400 end it "should incorporate :padding when specified" do c = cell(:content => "text", :padding => [1, 2, 3, 4]) c.height.should be_within(0.01).of(1 + 3 + @pdf.height_of("text", :width => @pdf.width_of("text"))) end it "should allow height to be reset after it has been calculated" do # to ensure that if we memoize height, it can still be overridden c = cell(:content => "text") c.height c.height = 400 c.height.should == 400 end it "should return proper height for blocks of text" do content = "words " * 10 c = cell(:content => content, :width => 100) c.height.should == @pdf.height_of(content, :width => 100) + c.padding[0] + c.padding[2] end it "should return proper height for blocks of text with size set" do content = "words " * 10 c = cell(:content => content, :width => 100, :size => 7) correct_content_height = nil @pdf.font_size(7) do correct_content_height = @pdf.height_of(content, :width => 100) end c.height.should == correct_content_height + c.padding[0] + c.padding[2] end it "content_height should exclude padding" do c = cell(:content => "text", :padding => 10) c.content_height.should == @pdf.height_of("text") end it "content_height should exclude padding even with manual :height" do c = cell(:content => "text", :padding => 10, :height => 400) c.content_height.should be_within(0.01).of(380) end end describe "cell padding" do include CellHelpers it "should default to zero" do c = cell(:content => "text") c.padding.should == [5, 5, 5, 5] end it "should accept a numeric value, setting all padding" do c = cell(:content => "text", :padding => 10) c.padding.should == [10, 10, 10, 10] end it "should accept [v,h]" do c = cell(:content => "text", :padding => [20, 30]) c.padding.should == [20, 30, 20, 30] end it "should accept [t,h,b]" do c = cell(:content => "text", :padding => [10, 20, 30]) c.padding.should == [10, 20, 30, 20] end it "should accept [t,l,b,r]" do c = cell(:content => "text", :padding => [10, 20, 30, 40]) c.padding.should == [10, 20, 30, 40] end it "should reject other formats" do lambda{ cell(:content => "text", :padding => [10]) }.should raise_error(ArgumentError) end end describe "background_color" do include CellHelpers it "should fill a rectangle with the given background color" do @pdf.stubs(:mask).yields @pdf.expects(:mask).with(:fill_color).yields @pdf.stubs(:fill_color) @pdf.expects(:fill_color).with('123456') @pdf.expects(:fill_rectangle).checking do |(x, y), w, h| x.should be_within(0.01).of(0) y.should be_within(0.01).of(@pdf.cursor) w.should be_within(0.01).of(29.344) h.should be_within(0.01).of(23.872) end @pdf.cell(:content => "text", :background_color => '123456') end it "should draw the background in the right place if cell is drawn at a " + "different location" do @pdf.stubs(:mask).yields @pdf.expects(:mask).with(:fill_color).yields @pdf.stubs(:fill_color) @pdf.expects(:fill_color).with('123456') @pdf.expects(:fill_rectangle).checking do |(x, y), w, h| x.should be_within(0.01).of(12.0) y.should be_within(0.01).of(34.0) w.should be_within(0.01).of(29.344) h.should be_within(0.01).of(23.872) end c = @pdf.make_cell(:content => "text", :background_color => '123456') c.draw([12.0, 34.0]) end end describe "color" do it "should set fill color when :text_color is provided" do pdf = Prawn::Document.new pdf.stubs(:fill_color) pdf.expects(:fill_color).with('555555') pdf.cell :content => 'foo', :text_color => '555555' end it "should reset the fill color to the original one" do pdf = Prawn::Document.new pdf.fill_color = '333333' pdf.cell :content => 'foo', :text_color => '555555' pdf.fill_color.should == '333333' end end describe "Borders" do it "should draw all borders by default" do @pdf.expects(:stroke_line).times(4) @pdf.cell(:content => "text") end it "should draw all borders when requested" do @pdf.expects(:stroke_line).times(4) @pdf.cell(:content => "text", :borders => [:top, :right, :bottom, :left]) end # Only roughly verifying the integer coordinates so that we don't have to # do any FP closeness arithmetic. Can plug in that math later if this goes # wrong. it "should draw top border when requested" do @pdf.expects(:stroke_line).checking do |from, to| @pdf.map_to_absolute(from).map{|x| x.round}.should == [36, 756] @pdf.map_to_absolute(to).map{|x| x.round}.should == [65, 756] end @pdf.cell(:content => "text", :borders => [:top]) end it "should draw bottom border when requested" do @pdf.expects(:stroke_line).checking do |from, to| @pdf.map_to_absolute(from).map{|x| x.round}.should == [36, 732] @pdf.map_to_absolute(to).map{|x| x.round}.should == [65, 732] end @pdf.cell(:content => "text", :borders => [:bottom]) end it "should draw left border when requested" do @pdf.expects(:stroke_line).checking do |from, to| @pdf.map_to_absolute(from).map{|x| x.round}.should == [36, 756] @pdf.map_to_absolute(to).map{|x| x.round}.should == [36, 732] end @pdf.cell(:content => "text", :borders => [:left]) end it "should draw right border when requested" do @pdf.expects(:stroke_line).checking do |from, to| @pdf.map_to_absolute(from).map{|x| x.round}.should == [65, 756] @pdf.map_to_absolute(to).map{|x| x.round}.should == [65, 732] end @pdf.cell(:content => "text", :borders => [:right]) end it "should draw borders at the same location when in or out of bbox" do @pdf.expects(:stroke_line).checking do |from, to| @pdf.map_to_absolute(from).map{|x| x.round}.should == [36, 756] @pdf.map_to_absolute(to).map{|x| x.round}.should == [65, 756] end @pdf.bounding_box([0, @pdf.cursor], :width => @pdf.bounds.width) do @pdf.cell(:content => "text", :borders => [:top]) end end it "should set border color with :border_..._color" do @pdf.ignores(:stroke_color=).with("000000") @pdf.expects(:stroke_color=).with("ff0000") c = @pdf.cell(:content => "text", :border_top_color => "ff0000") c.border_top_color.should == "ff0000" c.border_colors[0].should == "ff0000" end it "should set border colors with :border_color" do @pdf.ignores(:stroke_color=).with("000000") @pdf.expects(:stroke_color=).with("ff0000") @pdf.expects(:stroke_color=).with("00ff00") @pdf.expects(:stroke_color=).with("0000ff") @pdf.expects(:stroke_color=).with("ff00ff") c = @pdf.cell(:content => "text", :border_color => %w[ff0000 00ff00 0000ff ff00ff]) c.border_colors.should == %w[ff0000 00ff00 0000ff ff00ff] end it "border_..._width should return 0 if border not selected" do c = @pdf.cell(:content => "text", :borders => [:top]) c.border_bottom_width.should == 0 end it "should set border width with :border_..._width" do @pdf.ignores(:line_width=).with(1) @pdf.expects(:line_width=).with(2) c = @pdf.cell(:content => "text", :border_bottom_width => 2) c.border_bottom_width.should == 2 c.border_widths[2].should == 2 end it "should set border widths with :border_width" do @pdf.ignores(:line_width=).with(1) @pdf.expects(:line_width=).with(2) @pdf.expects(:line_width=).with(3) @pdf.expects(:line_width=).with(4) @pdf.expects(:line_width=).with(5) c = @pdf.cell(:content => "text", :border_width => [2, 3, 4, 5]) c.border_widths.should == [2, 3, 4, 5] end it "should set default border lines to :solid" do c = @pdf.cell(:content => "text") c.border_top_line.should == :solid c.border_right_line.should == :solid c.border_bottom_line.should == :solid c.border_left_line.should == :solid c.border_lines.should == [:solid] * 4 end it "should set border line with :border_..._line" do c = @pdf.cell(:content => "text", :border_bottom_line => :dotted) c.border_bottom_line.should == :dotted c.border_lines[2].should == :dotted end it "should set border lines with :border_lines" do c = @pdf.cell(:content => "text", :border_lines => [:solid, :dotted, :dashed, :solid]) c.border_lines.should == [:solid, :dotted, :dashed, :solid] end end describe "Text cell attributes" do include CellHelpers it "should pass through text options like :align to Text::Box" do c = cell(:content => "text", :align => :right) box = Prawn::Text::Box.new("text", :document => @pdf) Prawn::Text::Box.expects(:new).checking do |text, options| text.should == "text" options[:align].should == :right end.at_least_once.returns(box) c.draw end it "should use font_style for Text::Box#style" do c = cell(:content => "text", :font_style => :bold) box = Prawn::Text::Box.new("text", :document => @pdf) Prawn::Text::Box.expects(:new).checking do |text, options| text.should == "text" options[:style].should == :bold end.at_least_once.returns(box) c.draw end it "should allow inline formatting in cells" do c = cell(:content => "foo bar baz", :inline_format => true) box = Prawn::Text::Formatted::Box.new([], :document => @pdf) Prawn::Text::Formatted::Box.expects(:new).checking do |array, options| array[0][:text].should == "foo " array[0][:styles].should == [] array[1][:text].should == "bar" array[1][:styles].should == [:bold] array[2][:text].should == " baz" array[2][:styles].should == [] end.at_least_once.returns(box) c.draw end end describe "Font handling" do include CellHelpers it "should allow only :font_style to be specified, defaulting to the " + "document's font" do c = cell(:content => "text", :font_style => :bold) c.font.name.should == 'Helvetica-Bold' end it "should accept a font name for :font" do c = cell(:content => "text", :font => 'Helvetica-Bold') c.font.name.should == 'Helvetica-Bold' end it "should allow style to be changed after initialize" do c = cell(:content => "text") c.font_style = :bold c.font.name.should == 'Helvetica-Bold' end it "should default to the document's font, if none is specified" do c = cell(:content => "text") c.font.should == @pdf.font end it "should use the metrics of the selected font (even if it is a variant " + "of the document's font) to calculate width" do c = cell(:content => "text", :font_style => :bold) font = @pdf.find_font('Helvetica-Bold') c.content_width.should == font.compute_width_of("text") end it "should properly calculate inline-formatted text" do c = cell(:content => "text", :inline_format => true) font = @pdf.find_font('Helvetica-Bold') c.content_width.should == font.compute_width_of("text") end end end describe "Image cells" do before(:each) do create_pdf end describe "with default options" do before(:each) do @cell = Prawn::Table::Cell.make(@pdf, :image => "#{Prawn::DATADIR}/images/prawn.png") end it "should create a Cell::Image" do @cell.should be_a_kind_of(Prawn::Table::Cell::Image) end it "should pull the natural width and height from the image" do @cell.natural_content_width.should == 141 @cell.natural_content_height.should == 142 end end describe "hash syntax" do before(:each) do @table = @pdf.make_table([[{ :image => "#{Prawn::DATADIR}/images/prawn.png", :scale => 2, :fit => [100, 200], :image_width => 123, :image_height => 456, :position => :center, :vposition => :center }]]) @cell = @table.cells[0, 0] end it "should create a Cell::Image" do @cell.should be_a_kind_of(Prawn::Table::Cell::Image) end it "should pass through image options" do @pdf.expects(:embed_image).checking do |_, _, options| options[:scale].should == 2 options[:fit].should == [100, 200] options[:width].should == 123 options[:height].should == 456 options[:position].should == :center options[:vposition].should == :center end @table.draw end end end