Login
gpcr/spec/cli_cgi_spec.cr
Login

[edit]

spec/cli_cgi_spec.cr @ trunk

spec

require 'spec'
scale = 0.75
fontscale = 1.500
box wid 1.380 ht 0.340 with .nw at (0.035, -0.035) fill 0xCBD5E1 color 0xCBD5E1
box wid 1.380 ht 0.340 with .nw at (0.000, 0.000) fill 0x7C83E6 color 0x7C83E6
box wid 0.300 ht 0.065 rad 0.018 at (0.370, -0.022) fill 0xffffff color 0xffffff
line from (0.140, 0.000) to (0.140, -0.340) color white
line from (1.240, 0.000) to (1.240, -0.340) color white
text "require 'spec'" color white at (0.690, -0.170)

crystal source

require "spec"

json block

{
  "kind": "require",
  "name": "spec",
  "doc": null,
  "children": []
}

private def fossil_checkout_hash : String?
  buf = IO::Memory.new
  status = Process.run("fossil", ["info"], output: buf, error: Process::Redirect::Close)
  return nil unless status.success?
  line = buf.to_s.lines.find(&.starts_with?("checkout:"))
  line.try { |l| l.split(/\s+/)[1]? }
end

private def gpcr_bin : String
  File.join(Dir.current, "bin", "gpcr")
end

describe "gpcr render with reflected faces" do
  bin = gpcr_bin

  unless File.exists?(bin)
    pending "gpcr binary not present — skipping render-with-faces tests"
    next
  end

  it "renders on_start as 'on start' (hat label filled, not raw def name)" do
    buf = IO::Memory.new
    Process.run(bin, ["render", "examples/blink.cr"], output: buf, error: Process::Redirect::Close)
    buf.to_s.should contain("on start")
  end

  it "renders set_user_led with its slot as a filled input pill" do
    buf = IO::Memory.new
    Process.run(bin, ["render", "examples/blink.cr"], output: buf, error: Process::Redirect::Close)
    md = buf.to_s
    md.should contain(%(text "set user LED " color white))
    md.should contain(%(text "true" color 0x263238))
  end

  it "renders wait with its numeric slot as a filled input pill" do
    buf = IO::Memory.new
    Process.run(bin, ["render", "examples/blink.cr"], output: buf, error: Process::Redirect::Close)
    md = buf.to_s
    md.should contain(%(text "wait " color white))
    md.should contain(%(text "0.5" color 0x263238))
    md.should contain(%(text " seconds" color white))
  end
end

describe "gpcr render gallery.cr" do
  bin = gpcr_bin

  unless File.exists?(bin)
    pending "gpcr binary not present — skipping gallery render tests"
    next
  end

  it "renders all gallery shape labels" do
    buf = IO::Memory.new
    Process.run(bin, ["render", "src/gpcr/gallery.cr"], output: buf, error: Process::Redirect::Close)
    out = buf.to_s
    ["hat shape", "command shape", "reporter shape", "boolean shape",
     "predefined process shape", "document shape", "stop script", "ring shape"].each do |label|
      out.should contain(label)
    end
  end

  it "renders all structure node kinds in the gallery_structures graph" do
    buf = IO::Memory.new
    Process.run(bin, ["render", "src/gpcr/gallery.cr"], output: buf, error: Process::Redirect::Close)
    out = buf.to_s
    out.should contain(%(text "if " color white))
    out.should contain(%(text "while " color white))
    out.should contain(%(text "match " color white))
    out.should contain(%(text "gallery_boolean" color 0x263238))
    out.should contain(%(text "gallery_reporter" color 0x263238))
    out.should contain("forever")
  end
end

# Ticket ca825f45f6: the design gallery capstone requires BOTH visual token
# styles to be reachable on the live page, not just that render_source CAN
# take a token_set argument. These run the compiled binary through the real
# CGI dispatch path (PATH_INFO=gallery, QUERY_STRING=tokens=...) exactly as
# Fossil's CGI would invoke it — no real fossil repo needed, since the
# gallery branch never reads FOSSIL_REPOSITORY beyond checking it's set.
private def run_gallery_cgi(bin : String, query : String) : String
  buf = IO::Memory.new
  scrubbed_env = {
    "PATH"                => "/usr/bin:/bin",
    "GATEWAY_INTERFACE"   => "CGI/1.1",
    "REQUEST_METHOD"      => "GET",
    "PATH_INFO"           => "gallery",
    "QUERY_STRING"        => query,
    "SCRIPT_NAME"         => "/x/ext/gpcr",
    "FOSSIL_REPOSITORY"   => "unused-but-must-be-set",
    "FOSSIL_CAPABILITIES" => "oh",
  }
  Process.run(bin, env: scrubbed_env, clear_env: true, output: buf, error: Process::Redirect::Close)
  buf.to_s
end

describe "gpcr CGI gallery route: both design token sets" do
  bin = gpcr_bin

  unless File.exists?(bin)
    pending "gpcr binary not present — skipping gallery token-set CGI tests"
    next
  end

  it "defaults to microblocks-compact (fontscale 1.500) with no tokens= param" do
    body = run_gallery_cgi(bin, "")
    body.should contain("fontscale = 1.500")
    body.should_not contain("fontscale = 2.000")
    body.should contain("Design Gallery (microblocks-compact")
    body.should contain("[view blockly-zelos](/ext/gpcr/gallery?tokens=blockly-zelos)")
  end

  it "renders blockly-zelos (fontscale 2.000, different geometry) when asked" do
    body = run_gallery_cgi(bin, "tokens=blockly-zelos")
    body.should contain("fontscale = 2.000")
    body.should_not contain("fontscale = 1.500")
    body.should contain("Design Gallery (blockly-zelos")
    body.should contain("[view microblocks-compact](/ext/gpcr/gallery?tokens=microblocks-compact)")
  end

  it "renders every gallery shape under blockly-zelos too, not just the default set" do
    body = run_gallery_cgi(bin, "tokens=blockly-zelos")
    ["hat shape", "command shape", "reporter shape", "boolean shape",
     "predefined process shape", "document shape", "stop script", "ring shape"].each do |label|
      body.should contain(label)
    end
  end
end

describe "gpcr CGI explorer default_ci" do
  bin = gpcr_bin
  fossil_repo = "/var/lib/fossil/gp-crystal.fossil"

  unless File.exists?(bin) && File.exists?(fossil_repo)
    pending "gpcr binary or fossil repo not present — skipping CGI env smoke test"
    next
  end

  expected_hash = fossil_checkout_hash
  unless expected_hash
    pending "not inside a fossil checkout — cannot verify default_ci hash"
    next
  end

  it "shows the checkout hash (not trunk) when HOME is absent from the CGI environment" do
    buf = IO::Memory.new
    # Simulate the CGI environment that the preview dispatcher creates:
    # PATH-only env, no HOME, no FOSSIL_HOME — the binary must set those itself.
    scrubbed_env = {
      "PATH"                => "/usr/bin:/bin",
      "GATEWAY_INTERFACE"   => "CGI/1.1",
      "REQUEST_METHOD"      => "GET",
      "PATH_INFO"           => "",
      "QUERY_STRING"        => "",
      "SCRIPT_NAME"         => "/x/ext/preview/id/test",
      "FOSSIL_REPOSITORY"   => fossil_repo,
      "FOSSIL_CAPABILITIES" => "o",
    }
    status = Process.run(bin, env: scrubbed_env, clear_env: true, output: buf, error: Process::Redirect::Close)
    status.success?.should be_true
    body = buf.to_s
    body.should contain("Revision: `#{expected_hash}`")
    body.should_not contain("Revision: `trunk`")
  end

  it "shows census metrics (gpcr_pct and block/primitive counts) on the main page" do
    buf = IO::Memory.new
    scrubbed_env = {
      "PATH"                => "/usr/bin:/bin",
      "GATEWAY_INTERFACE"   => "CGI/1.1",
      "REQUEST_METHOD"      => "GET",
      "PATH_INFO"           => "",
      "QUERY_STRING"        => "",
      "SCRIPT_NAME"         => "/x/ext/preview/id/test",
      "FOSSIL_REPOSITORY"   => fossil_repo,
      "FOSSIL_CAPABILITIES" => "o",
    }
    Process.run(bin, env: scrubbed_env, clear_env: true, output: buf, error: Process::Redirect::Close)
    body = buf.to_s
    body.should contain("**Census:**")
    body.should contain("% GPCR")
    body.should contain("blocks:")
    body.should contain("primitives:")
  end
end

# Ticket 57a83fc3c0: the Fossil skin's persistent nav menu links to the gpcr
# explorer. It must NOT hardcode ?ci=trunk — that overrides default_ci's
# correct per-checkout resolution (ticket 23d80447dc) and defeats "works the
# same way for any checkin being browsed." This only checks the TRACKED file
# fossil-skin/mainmenu; the live Fossil "mainmenu" setting is applied
# separately by an admin action outside source control and isn't re-checked
# here.
describe "fossil-skin/mainmenu: GPCR entry" do
  it "links to the explorer without overriding the checkin with ?ci=trunk" do
    content = File.read(File.join(__DIR__, "..", "fossil-skin", "mainmenu"))
    gpcr_line = content.lines.find(&.starts_with?("GPCR "))
    gpcr_line.should_not be_nil
    gpcr_line.not_nil!.should contain("/ext/gpcr/")
    gpcr_line.not_nil!.should_not contain("?ci=trunk")
  end
end