-- Unit checks for the two avatar email filters, run under a standalone Lua -- by t0504-email-avatar.sh with the script path as the first argument. The -- two scripts differ only in the service they point at, so the expected host -- is picked from the script's name. The second argument chooses how the -- openssl.digest dependency is met, stub swaps in the deterministic fake -- from the harness, real uses an installed luaossl and adds the one check -- only a genuine SHA-256 can pass, and missing makes the module fail to -- load. local test_directory = arg[0]:match("^(.*)/") or "." local h = dofile(test_directory .. "/harness.lua") local script = arg[1] local mode = h.mode("stub", "missing", "real") local base_url = "https://gravatar.com/avatar/" if script:match("[^/]*$"):find("libravatar", 1, true) then base_url = "https://seccdn.libravatar.org/avatar/" end if mode == "stub" then h.stub_digest() elseif mode == "missing" then h.preload_failure("openssl.digest") end h.load(script) if mode == "missing" then h.equals("a missing luaossl is named in the error log", h.error_log(), "[cgit] Unable to load openssl.digest, so no avatar icons are drawn\n") else h.equals("with luaossl the error log stays empty", h.error_log(), "") end local function render(email, name) return h.run({ email, "commit" }, { name }) end if mode == "missing" then local out, ret = render("", "A U Thor") h.equals("without luaossl the name stands alone", out, "A U Thor") h.equals("and close still answers zero", ret, 0) h.finish() end local prefix = base_url:gsub("([%^%$%(%)%%%.%[%]%*%+%-%?])", "%%%1") local function hash_in(attribute, output) return output:match(attribute .. "='" .. prefix .. "([0-9a-f]+)%?") end local function hash_of(output) return hash_in("src", output) end local out, ret = render("", "A U Thor") h.contains("an icon is drawn for an address", out, " A U Thor") h.equals("close answers zero", ret, 0) h.check("the hash is hex", hash_of(out) ~= nil) h.equals("the dense image is of the same address", hash_in("srcset", out), hash_of(out)) if mode == "stub" then h.equals("the hash is of the bare address in two hex digits a byte", hash_of(out), "8318f94a3e09d48151cb849a783e6895") end -- The service hashes the trimmed lowercase address, so every spelling of one -- address has to reach it as the same hash. local plain = hash_of(render("author@example.com", "x")) local wrapped = hash_of(render("", "x")) local shouting = hash_of(render(" ", "x")) h.check("angle brackets do not change the hash", plain ~= nil and plain == wrapped) h.check("case and padding do not change the hash", plain == shouting) local other = hash_of(render("other@example.com", "x")) h.check("a different address hashes differently", other ~= nil and plain ~= other) out = render(nil, "A U Thor") h.equals("no address draws no icon", out, "A U Thor") out = render("", "A U Thor") h.equals("an empty address draws no icon", out, "A U Thor") out = render("<>", "A U Thor") h.equals("empty angle brackets draw no icon", out, "A U Thor") out = h.run({ "", "commit" }, { "A U ", "Thor" }) h.contains("the name is buffered across writes", out, "> A U Thor") -- cgit hands the name over already escaped. out = render("", "A & B") h.contains("a name keeps the escaping cgit gave it", out, "> A & B") h.excludes("and is not escaped again", out, "&amp;") -- A commit can carry any bytes in its address, and a log page runs the -- filter once per row, so trimming and unwrapping have to stay linear. local function address_only(text) return (render(text, "x")) end h.stays_linear("a long run of inner spaces is trimmed in linear time", address_only, function(count) return "" end, 10000) h.stays_linear("an address of open brackets is scanned in linear time", address_only, function(count) return string.rep("<", count) end, 10000) h.check("text around the brackets is dropped", hash_of(render("x y", "x")) == plain) if mode == "stub" then h.equals("the outermost brackets are the ones taken off", hash_of(render(" c>", "x")), "4c40a2581c18aec944a8caa7000e17fa") end local reversed = hash_of(render("a>b