11require " yaml"
22require " ../spec_helper"
33
4+ # [golden-liquid](https://github.com/jg-rp/golden-liquid) is a test suite for
5+ # liquid template, tests are found in spec/integration/golden_liquid.yaml, a
6+ # list of tests that are expected to fail can be found at
7+ # spec/integration/golden_liquid.pending.
8+ #
9+ # All golden liquid tests are tagged with `golden`. Tests are run in two modes,
10+ # using the render visitor directly (tagged with `render`) and using the
11+ # codegen visitor (tagged with `codegen`), besides a numeric tag for each test.
12+ #
13+ # For code gen tests Crystal code is written in files like
14+ # `spec/integration/codegen-test-XXX.cr` where XXX is the test number.
415class GoldenTest
516 include YAML ::Serializable
617
@@ -25,6 +36,40 @@ class GoldenTest
2536 ctx
2637 end
2738
39+ private def context_to_code (context : Liquid ::Context ) : String
40+ String .build do |str |
41+ str << " Liquid::Context{"
42+ context.each do |key , value |
43+ key.inspect(str)
44+ str << " => " << any_to_code(value)
45+ str << " , "
46+ end
47+ str << " }"
48+ end
49+ end
50+
51+ private def any_to_code (any : Liquid ::Any ) : String
52+ raw = any.raw
53+ String .build do |str |
54+ str << " Liquid::Any.new("
55+
56+ if raw.is_a?(Array )
57+ str << " ["
58+ raw.each { |item | str << any_to_code(item) << " , " }
59+ str << " ] of Liquid::Any"
60+ elsif raw.is_a?(Hash )
61+ str << " {"
62+ raw.each do |key , value |
63+ str << key.inspect << " =>" << any_to_code(value) << " , "
64+ end
65+ str << " } of String => Liquid::Any"
66+ else
67+ raw.inspect(str)
68+ end
69+ str << " )"
70+ end
71+ end
72+
2873 def test !
2974 if @error
3075 expect_raises(LiquidException ) do
@@ -34,6 +79,55 @@ class GoldenTest
3479 Parser .parse(@template ).render(context).should eq(@want )
3580 end
3681 end
82+
83+ def codegen_test !(test_group, test_number)
84+ test_path = Path [__DIR__, " codegen-test-#{ test_number } .cr" ]
85+ test = File .open(test_path, " w" )
86+ test.puts(" # #{ test_group.name } .#{ @name } \n\n " )
87+ generate_codegen_test_source(test)
88+ output = ` crystal run #{ Process .quote(test.path)} --error-trace`
89+ $? .exit_code.should eq(0 )
90+ output.should eq(@want ) unless @error
91+ end
92+
93+ private def generate_codegen_test_source (io ) : Nil
94+ error_mode = @strict || @error ? Context ::ErrorMode ::Strict : Context ::ErrorMode ::Lax
95+
96+ io.puts(<<-CRYSTAL )
97+ require "../../src/liquid"
98+
99+ TEMPLATE =<<-LIQUID
100+ #{ Liquid ::CodeGenVisitor .escape(@template )}
101+ LIQUID
102+
103+ WANT =<<-TEXT
104+ #{ Liquid ::CodeGenVisitor .escape(@want )}
105+ TEXT
106+
107+ # CONTEXT
108+ expects_error = #{ @error }
109+ context = #{ context_to_code(context) }
110+ context.error_mode = :#{ error_mode }
111+
112+ # CODEGEN OUTPUT
113+ CRYSTAL
114+
115+ tpl = Liquid ::Template .parse(@template )
116+ visitor = CodeGenVisitor .new(io)
117+ tpl.root.accept(visitor)
118+ io.puts(<<-CRYSTAL )
119+ begin
120+ Liquid::Template.new(root).render(context, STDOUT)
121+ rescue ex : Liquid::InvalidExpression
122+ raise ex unless expects_error
123+ end
124+ CRYSTAL
125+
126+ rescue ex : Liquid ::LiquidException
127+ io << " abort(" << ex.message.inspect << " ) unless expects_error\n "
128+ ensure
129+ io.close
130+ end
37131end
38132
39133class GoldenTestGroup
@@ -68,7 +162,6 @@ private def yaml_any_to_liquid_any(yaml : YAML::Any) : Liquid::Any
68162 end
69163end
70164
71- # FIXME: One all tests pass we must remove this class
72165class PendingGold
73166 @@pending : Array (String )?
74167
84177describe " Golden Liquid Tests" do
85178 i = 1
86179 skip_pending_tests = ENV [" SKIP_PENDING" ]?
180+
87181 GoldenLiquid .from_yaml(File .read(File .join(__DIR__, " golden_liquid.yaml" ))).test_groups.each do |test_group |
88- describe test_group.name do
182+ describe test_group.name, tags: " golden " do
89183 test_group.tests.each do |test |
90184 if PendingGold .pending?(test_group.name, test.name)
91185 pending(test.name, line: i) unless skip_pending_tests
92186 else
93- it test.name, line: i do
187+ it " #{ test.name } [test- #{ i } render] " , tags: [ " test- #{ i } " , " render " ] do
94188 test.test!
95189 end
190+
191+ i += 1
192+ dup_i = i
193+ it " #{ test.name } [test-#{ i } codegen]" , tags: [" test-#{ i } " , " codegen" ] do
194+ test.codegen_test!(test_group, dup_i)
195+ end
96196 end
97197 i += 1
98198 end
0 commit comments