123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384(*****************************************************************************)(* *)(* SPDX-License-Identifier: MIT *)(* SPDX-FileCopyrightText: 2023 Nomadic Labs <contact@nomadic-labs.com> *)(* *)(*****************************************************************************)includeTeztopenBasemoduleUses=structtypet={tag:string;path:string}letmake~tag~path={tag;path}letpath_handler:(t->unit)ref=ref(fun_->())letpathuses=!path_handleruses;uses.pathlettaguses=uses.tagend(* Prepare parameters of a [Test.register]-like function. *)letwrap~file~title~tags~uses~run_test=(* Add [uses] into [tags]. *)letuses_tags=String_set.of_list(List.map(fun(uses:Uses.t)->uses.tag)uses)inletall_tags=String_set.union(String_set.of_listtags)uses_tagsin(* Wrap [run_test] to check tags.
In the future, we could use [Unix.chroot] to implement a sandbox
that prevents using files that were not declared in [uses].
Or even just [Unix.chdir], if we assume that we only use relative paths,
in which case we need to override [Tezt.Base.project_root] though.
[chdir] would let tests use [/tmp] and system executables more easily. *)letunused_uses_tags=refuses_tagsinletrun_test()=(* Set hook so that tests can only call [Uses.path] on allowed paths. *)(Uses.path_handler:=funuses->(* Do *not* use [Uses.path uses] here; use [uses.path].
Otherwise you'll get a stack overflow as the hook will trigger itself. *)unused_uses_tags:=String_set.removeuses.tag!unused_uses_tags;ifnot(String_set.memuses.taguses_tags)thenLog.warn"In %S, test %S is not allowed to use %S. Try to add '%s' to its \
~uses."filetitleuses.pathuses.tag);(* Actually run the test. *)let*()=run_test()in(* Check for unused tags. *)String_set.iter(Log.warn"In %S, test %S was declared with '%s' in its ~uses but did not call \
Uses.path on it."filetitle)!unused_uses_tags;unitin(* Return information that will be needed to register tests. *)(String_set.elementsall_tags,run_test)moduleTest=structincludeTestletregister~__FILE__:file~title~tags?(uses=[])?seedrun_test=lettags,run_test=wrap~file~title~tags~uses~run_testinTest.register~__FILE__:file~title~tags?seedrun_testendmoduleRegression=structincludeRegressionletregister~__FILE__:file~title~tags?(uses=[])?file:output_filerun_test=lettags,run_test=wrap~file~title~tags~uses~run_testinRegression.register~__FILE__:file~title~tags?file:output_filerun_testend