from test/more import *;

requires_capability( "fs" );

from std/data/json import JSON;
from std/digest/sha import sha256_hex;
from std/io import Path;
from std/string import split;
from std/zuzuzoo import Zuzuzoo, format_json, verify;

function ensure_dir ( path ) {
	return true if path.exists();
	let parent := path.parent();
	ensure_dir(parent) if not parent.exists();
	path.mkdir();
	return true;
}

function root () {
	let dir := Path.tempdir();
	let lib := dir.child("lib");
	let bin := dir.child("bin");
	let meta := dir.child("meta");
	ensure_dir(lib);
	ensure_dir(bin);
	ensure_dir(meta);
	return {
		dir_obj: dir,
		lib_obj: lib,
		bin_obj: bin,
		meta_obj: meta,
		lib_dir: lib.to_String(),
		bin_dir: bin.to_String(),
		meta_dir: meta.to_String(),
	};
}

function write_text ( path, text ) {
	ensure_dir( path.parent() );
	path.spew_utf8(text);
	return sha256_hex(path.slurp());
}

function module_entry ( root, install_as, text ) {
	let path := root{lib_obj};
	for ( let part in split( install_as, "/" ) ) {
		path := path.child(part);
	}
	return {
		source: "modules/" _ install_as,
		install_as: install_as,
		sha256: write_text( path, text ),
	};
}

function script_entry ( root, install_as, text, wrappers := [] ) {
	let path := root{bin_obj}.child(install_as);
	return {
		source: "scripts/" _ install_as,
		install_as: install_as,
		sha256: write_text( path, text ),
		wrappers: wrappers,
	};
}

function write_installed ( root, name, version, modules, scripts ) {
	( new JSON( pretty: true ) ).dump(
		root{meta_obj}.child( name _ "-" _ version _ ".json" ),
		{
			name: name,
			version: version,
			author: "Example",
			license: "MIT",
			status: "stable",
			dependencies: {},
			installed: {
				zdf: "ZDF-1",
				lib_dir: root{lib_dir},
				bin_dir: root{bin_dir},
				meta_dir: root{meta_dir},
				modules: modules,
				scripts: scripts,
			},
		},
	);
}

let target := root();
let wrapper := target{bin_obj}.child("verify-tool.cmd");
wrapper.spew_utf8("@echo off\r\n");
write_installed(
	target,
	"verify-app",
	"1.0.0",
	[ module_entry( target, "verify/app.zzm", "// app\n" ) ],
	[
		script_entry(
			target,
			"verify-tool.zzs",
			"say \"verify\";\n",
			[ "verify-tool.cmd" ],
		),
	],
);

let zoo := new Zuzuzoo(
	lib_dir: target{lib_dir},
	bin_dir: target{bin_dir},
	meta_dir: target{meta_dir},
	home: Path.tempdir().to_String(),
);
let result := zoo.verify("verify/app");

ok( result{ok}, "verify succeeds for matching installed files" );
is( result{distributions}.length(), 1, "one distribution is verified" );
is( result{checked_files}.length(), 2, "module and script hashes are checked" );
is( result{wrapper_files}.length(), 1, "wrapper existence is checked" );
is( result{missing_files}.length(), 0, "no missing files are reported" );
is( result{hash_mismatches}.length(), 0, "no hash mismatches are reported" );
is( result{files}[2]{hash_ok}, null, "wrapper is not hash checked" );
like(
	format_json(result),
	/"checked_files"/,
	"format_json aliases canonical pretty JSON",
);

let top := verify(
	"verify/app",
	{
		lib_dir: target{lib_dir},
		bin_dir: target{bin_dir},
		meta_dir: target{meta_dir},
		home: Path.tempdir().to_String(),
	},
);
ok( top{ok}, "top-level verify wrapper works" );

done_testing();
