require 'test_helper' require 'better_html/tokenizer/html_erb' module BetterHtml module Tokenizer class HtmlErbTest < ActiveSupport::TestCase test "text" do scanner = HtmlErb.new(buffer("just some text")) assert_equal 1, scanner.tokens.size assert_attributes ({ type: :text, loc: { begin_pos: 0, end_pos: 14, source: 'just some text' } }), scanner.tokens[0] end test "statement" do scanner = HtmlErb.new(buffer("<% statement %>")) assert_equal 3, scanner.tokens.size assert_attributes ({ type: :erb_begin, loc: { begin_pos: 0, end_pos: 2, source: '<%' } }), scanner.tokens[0] assert_attributes ({ type: :code, loc: { begin_pos: 2, end_pos: 13, source: ' statement ' } }), scanner.tokens[1] assert_attributes ({ type: :erb_end, loc: { begin_pos: 13, end_pos: 15, source: '%>' } }), scanner.tokens[2] end test "debug statement" do scanner = HtmlErb.new(buffer("<%# statement %>")) assert_equal 4, scanner.tokens.size assert_attributes ({ type: :erb_begin, loc: { begin_pos: 0, end_pos: 2, source: '<%' } }), scanner.tokens[0] assert_attributes ({ type: :indicator, loc: { begin_pos: 2, end_pos: 3, source: '#' } }), scanner.tokens[1] assert_attributes ({ type: :code, loc: { begin_pos: 3, end_pos: 14, source: ' statement ' } }), scanner.tokens[2] assert_attributes ({ type: :erb_end, loc: { begin_pos: 14, end_pos: 16, source: '%>' } }), scanner.tokens[3] end test "when multi byte characters are present in erb" do code = "<% ui_helper 'your store’s' %>" scanner = HtmlErb.new(buffer(code)) assert_equal 3, scanner.tokens.size assert_attributes ({ type: :erb_begin, loc: { begin_pos: 0, end_pos: 2, source: '<%' } }), scanner.tokens[0] assert_attributes ({ type: :code, loc: { begin_pos: 2, end_pos: 28, source: " ui_helper 'your store’s' " } }), scanner.tokens[1] assert_attributes ({ type: :erb_end, loc: { begin_pos: 28, end_pos: 30, source: '%>' } }), scanner.tokens[2] assert_equal code.length, scanner.current_position end test "when multi byte characters are present in text" do code = "your store’s" scanner = HtmlErb.new(buffer(code)) assert_equal 1, scanner.tokens.size assert_attributes ({ type: :text, loc: { begin_pos: 0, end_pos: 12, source: 'your store’s' } }), scanner.tokens[0] assert_equal code.length, scanner.current_position end test "when multi byte characters are present in html" do code = "
foo
" scanner = HtmlErb.new(buffer(code)) assert_equal 14, scanner.tokens.size assert_attributes ({ type: :tag_start, loc: { begin_pos: 0, end_pos: 1, source: '<' } }), scanner.tokens[0] assert_attributes ({ type: :tag_name, loc: { begin_pos: 1, end_pos: 4, source: "div" } }), scanner.tokens[1] assert_attributes ({ type: :whitespace, loc: { begin_pos: 4, end_pos: 5, source: " " } }), scanner.tokens[2] assert_attributes ({ type: :attribute_name, loc: { begin_pos: 5, end_pos: 10, source: "title" } }), scanner.tokens[3] assert_attributes ({ type: :equal, loc: { begin_pos: 10, end_pos: 11, source: "=" } }), scanner.tokens[4] assert_attributes ({ type: :attribute_quoted_value_start, loc: { begin_pos: 11, end_pos: 12, source: "'" } }), scanner.tokens[5] assert_attributes ({ type: :attribute_quoted_value, loc: { begin_pos: 12, end_pos: 24, source: "your store’s" } }), scanner.tokens[6] assert_attributes ({ type: :attribute_quoted_value_end, loc: { begin_pos: 24, end_pos: 25, source: "'" } }), scanner.tokens[7] assert_equal code.length, scanner.current_position end test "expression literal" do scanner = HtmlErb.new(buffer("<%= literal %>")) assert_equal 4, scanner.tokens.size assert_attributes ({ type: :erb_begin, loc: { begin_pos: 0, end_pos: 2, source: '<%' } }), scanner.tokens[0] assert_attributes ({ type: :indicator, loc: { begin_pos: 2, end_pos: 3, source: '=' } }), scanner.tokens[1] assert_attributes ({ type: :code, loc: { begin_pos: 3, end_pos: 12, source: ' literal ' } }), scanner.tokens[2] assert_attributes ({ type: :erb_end, loc: { begin_pos: 12, end_pos: 14, source: '%>' } }), scanner.tokens[3] end test "expression escaped" do scanner = HtmlErb.new(buffer("<%== escaped %>")) assert_equal 4, scanner.tokens.size assert_attributes ({ type: :erb_begin, loc: { begin_pos: 0, end_pos: 2, source: '<%' } }), scanner.tokens[0] assert_attributes ({ type: :indicator, loc: { begin_pos: 2, end_pos: 4, source: '==' } }), scanner.tokens[1] assert_attributes ({ type: :code, loc: { begin_pos: 4, end_pos: 13, source: ' escaped ' } }), scanner.tokens[2] assert_attributes ({ type: :erb_end, loc: { begin_pos: 13, end_pos: 15, source: '%>' } }), scanner.tokens[3] end test "line number for multi-line statements" do scanner = HtmlErb.new(buffer("before <% multi\nline %> after")) assert_equal 5, scanner.tokens.size assert_attributes ({ type: :text, loc: { line: 1, source: 'before ' } }), scanner.tokens[0] assert_attributes ({ type: :erb_begin, loc: { line: 1, source: '<%' } }), scanner.tokens[1] assert_attributes ({ type: :code, loc: { line: 1, start_line: 1, stop_line: 2, source: " multi\nline " } }), scanner.tokens[2] assert_attributes ({ type: :erb_end, loc: { line: 2, source: "%>" } }), scanner.tokens[3] assert_attributes ({ type: :text, loc: { line: 2, source: " after" } }), scanner.tokens[4] end test "multi-line statements with trim" do scanner = HtmlErb.new(buffer("before\n<% multi\nline -%>\nafter")) assert_equal 7, scanner.tokens.size assert_attributes ({ type: :text, loc: { line: 1, source: "before\n" } }), scanner.tokens[0] assert_attributes ({ type: :erb_begin, loc: { line: 2, source: '<%' } }), scanner.tokens[1] assert_attributes ({ type: :code, loc: { line: 2, source: " multi\nline " } }), scanner.tokens[2] assert_attributes ({ type: :trim, loc: { line: 3, source: "-" } }), scanner.tokens[3] assert_attributes ({ type: :erb_end, loc: { line: 3, source: "%>" } }), scanner.tokens[4] assert_attributes ({ type: :text, loc: { line: 3, source: "\n" } }), scanner.tokens[5] assert_attributes ({ type: :text, loc: { line: 4, source: "after" } }), scanner.tokens[6] end test "right trim with =%>" do scanner = HtmlErb.new(buffer("<% trim =%>")) assert_equal 4, scanner.tokens.size assert_attributes ({ type: :erb_begin, loc: { line: 1, source: '<%' } }), scanner.tokens[0] assert_attributes ({ type: :code, loc: { line: 1, source: " trim " } }), scanner.tokens[1] assert_attributes ({ type: :trim, loc: { line: 1, source: "=" } }), scanner.tokens[2] assert_attributes ({ type: :erb_end, loc: { line: 1, source: "%>" } }), scanner.tokens[3] end test "multi-line expression with trim" do scanner = HtmlErb.new(buffer("before\n<%= multi\nline -%>\nafter")) assert_equal 8, scanner.tokens.size assert_attributes ({ type: :text, loc: { line: 1, source: "before\n" } }), scanner.tokens[0] assert_attributes ({ type: :erb_begin, loc: { line: 2, source: '<%' } }), scanner.tokens[1] assert_attributes ({ type: :indicator, loc: { line: 2, source: '=' } }), scanner.tokens[2] assert_attributes ({ type: :code, loc: { line: 2, source: " multi\nline " } }), scanner.tokens[3] assert_attributes ({ type: :trim, loc: { line: 3, source: "-" } }), scanner.tokens[4] assert_attributes ({ type: :erb_end, loc: { line: 3, source: "%>" } }), scanner.tokens[5] assert_attributes ({ type: :text, loc: { line: 3, source: "\n" } }), scanner.tokens[6] assert_attributes ({ type: :text, loc: { line: 4, source: "after" } }), scanner.tokens[7] end test "line counts with comments" do scanner = HtmlErb.new(buffer("before\n<%# BO$$ Mode %>\nafter")) assert_equal 7, scanner.tokens.size assert_attributes ({ type: :text, loc: { line: 1, source: "before\n" } }), scanner.tokens[0] assert_attributes ({ type: :erb_begin, loc: { line: 2, source: '<%' } }), scanner.tokens[1] assert_attributes ({ type: :indicator, loc: { line: 2, source: '#' } }), scanner.tokens[2] assert_attributes ({ type: :code, loc: { line: 2, source: " BO$$ Mode " } }), scanner.tokens[3] assert_attributes ({ type: :erb_end, loc: { line: 2, source: "%>" } }), scanner.tokens[4] assert_attributes ({ type: :text, loc: { line: 2, source: "\n" } }), scanner.tokens[5] assert_attributes ({ type: :text, loc: { line: 3, source: "after" } }), scanner.tokens[6] end test "escaped opening ERB tag <%%" do scanner = HtmlErb.new(buffer("just some <%%= text %> no erb")) assert_equal 6, scanner.tokens.size assert_attributes ({ type: :text, loc: { line: 1, source: "just some " } }), scanner.tokens[0] assert_attributes ({ type: :erb_begin, loc: { line: 1, source: '<%' } }), scanner.tokens[1] assert_attributes ({ type: :indicator, loc: { line: 1, source: "%" } }), scanner.tokens[2] assert_attributes ({ type: :code, loc: { line: 1, source: "= text " } }), scanner.tokens[3] assert_attributes ({ type: :erb_end, loc: { line: 1, source: "%>" } }), scanner.tokens[4] assert_attributes ({ type: :text, loc: { line: 1, source: " no erb" } }), scanner.tokens[5] end private def assert_attributes(attributes, token) attributes.each do |key, value| if value.nil? assert_nil token.send(key) elsif value.is_a?(Hash) assert_attributes(value, token.send(key)) else assert_equal value, token.send(key) end end end end end end