anchor.diff:    , HelloKeywordCheck
     , 2.5
     , WorldSymbolCheck
  -  } = clj_reader:read(<<"#[42, :hello, 2.5, world]">>),
  +  } = ReadFun(<<"#[42, :hello, 2.5, world]">>),
     true = clj_core:equiv(HelloKeyword, HelloKeywordCheck),
     true = clj_core:equiv(WorldSymbol, WorldSymbolCheck),
   
     ct:comment("Read a tuple whose first element is an keyword"),
  -  T = clj_reader:read(<<"#[:random, :hello, 2.5, 'world]">>),
  +  T = ReadFun(<<"#[:random, :hello, 2.5, 'world]">>),
     'clojerl.erlang.Tuple' = clj_core:type(T),
   
     {comments, ""}.
   
  -tagged(_Config) ->
  +tagged(Config) when is_list(Config) ->
  +  tagged(fun read/1),
  +  tagged(fun read_io/1);
  +tagged(ReadFun) ->
     DefaultDataReadersVar = 'clojerl.Var':?CONSTRUCTOR( <<"clojure.core">>
                                                       , <<"default-data-readers">>
                                                       ),
  
positive.code: 
    {comments, ""}.
  
  arg(_Config) ->
    ct:comment("Read % as a symbol"),
    ArgSymbol = clj_core:symbol(<<"%">>),
    true = clj_core:equiv(clj_reader:read(<<"%">>), ArgSymbol),
  
    ct:comment("Read %1 as a symbol"),
    ArgOneSymbol = clj_core:symbol(<<"%1">>),
    true = clj_core:equiv(clj_reader:read(<<"%1">>), ArgOneSymbol),
  
    erlang:put(arg_env, #{}),
  
    ct:comment("Read % as an argument"),
    ArgGenSymbol = clj_reader:read(<<"%">>),
    ArgGenName = clj_core:name(ArgGenSymbol),
    {match, _} = re:run(ArgGenName, "p1__\\d+#"),
  
    ArgGenSymbol2 = clj_reader:read(<<"% ">>),
    ArgGenName2 = clj_core:name(ArgGenSymbol2),
    {match, _} = re:run(ArgGenName2, "p1__\\d+#"),
  
    ct:comment("Read %1 as an argument"),
    ArgOneGenSymbol = clj_reader:read(<<"%1">>),
    ArgOneGenName = clj_core:name(ArgOneGenSymbol),
    {match, _} = re:run(ArgOneGenName, "p1__\\d+#"),
  
    ct:comment("Read %42 as an argument"),
    ArgFortyTwoGenSymbol = clj_reader:read(<<"%42">>),
    ArgFortyTwoGenName = clj_core:name(ArgFortyTwoGenSymbol),
    {match, _} = re:run(ArgFortyTwoGenName, "p42__\\d+#"),
  
    ct:comment("Read %& as an argument"),
    [ArgRestGenSymbol] = read_all(<<"%&">>),
    ArgRestGenName = clj_core:name(ArgRestGenSymbol),
    {match, _} = re:run(ArgRestGenName, "rest__\\d+#"),
  
    ct:comment("Invalid char after %"),
    ok = try clj_reader:read(<<"%a">>)
         catch _:<<"?:1:2: Arg literal must be %, %& or %integer">> -> ok
         end,
  
  
negative.code:                                     ),
  
    ok  = 'clojerl.Var':push_bindings(#{DataReadersVar => DataReaders}),
    bla = ReadFun(<<"#bla 1">>),
    ok  = 'clojerl.Var':pop_bindings(),
  
    ct:comment("Don't provide a symbol"),
    ok = try ReadFun(<<"#1">>), error
         catch _:<<"?:1:2: Reader tag must be a symbol">> -> ok end,
  
    ct:comment("Provide a missing reader"),
    ok = try ReadFun(<<"#bla 1">>), error
         catch _:<<"?:1:2: No reader function for tag bla">> -> ok end,
  
    meck:unload('clojure.core'),
  
    {comments, ""}.
  
  %%------------------------------------------------------------------------------
  %% Helper functions
  %%------------------------------------------------------------------------------
  
  -spec read_io(binary()) -> any().
  read_io(Src) ->
    Reader = 'erlang.io.StringReader':?CONSTRUCTOR(Src),
    clj_reader:read(<<>>, #{?OPT_IO_READER => Reader}).
  
  -spec read_io(binary(), clj_reader:opts()) -> any().
  read_io(Src, Opts) ->
    Reader = 'erlang.io.StringReader':?CONSTRUCTOR(Src),
    clj_reader:read(<<>>, Opts#{?OPT_IO_READER => Reader}).
  
  -spec read(binary()) -> any().
  read(Src) ->
    clj_reader:read(Src).
  
  -spec read(binary(), clj_reader:opts()) -> any().
  read(Src, Opts) ->
    clj_reader:read(Src, Opts).
  
  -spec read_all_io(binary()) -> any().
  read_all_io(Src) ->
  