anchor.diff:          {<<"bytes=100-300,500-500,-300">>, ?HTTP_206_PARTIAL_CONTENT, [
               {100, 201}, {500, 1}, {FileSize - 300, 300}
           ]},
  -
  +        
           {<<"unicorns">>, ?HTTP_416_RANGE_NOT_SATISFIABLE},
           {<<"bytes:5-10">>, ?HTTP_416_RANGE_NOT_SATISFIABLE},
           {<<"bytes=5=10">>, ?HTTP_416_RANGE_NOT_SATISFIABLE},
  
positive.code: %%% Internal functions
  %%%===================================================================
  
  
  %% @private
  -spec build_download_file_setup_fun(
      api_test_memory:mem_ref(),
      FileContent :: binary(),
      api_test_utils:file_type()
  ) ->
      onenv_api_test_runner:setup_fun().
  build_download_file_setup_fun(MemRef, Content, FileType) ->
      SpaceId = oct_background:get_space_id(space_krk_par),
      FileSpec = #file_spec{mode = 8#604, content = Content},
  
      fun() ->
          {Guid, FileGuid, FileGuid2, ShareId} = case FileType of
              <<"file">> ->
                  #object{guid = G1, shares = [S]} = onenv_file_test_utils:create_and_sync_file_tree(
                          user3, SpaceId, FileSpec#file_spec{shares = [#share_spec{}]}, krakow),
                  #object{guid = G2} = onenv_file_test_utils:create_and_sync_file_tree(user3, SpaceId, FileSpec, krakow),
                  {G1, G1, G2, S};
              <<"dir">> ->
                  #object{guid = DirGuid, shares = [S], children = Children} = onenv_file_test_utils:create_and_sync_file_tree(
                      user3, SpaceId, #dir_spec{shares = [#share_spec{}], mode = 8#705, children = [FileSpec, FileSpec]}, krakow),
                  [G1, G2] = lists:map(fun(#object{guid = Guid}) ->
                      Guid
                  end, Children),
                  {DirGuid, G1, G2, S}
          end,
          
          %% @TODO VFS-7475 use structure from onenv_file_test_utils
          api_test_memory:set(MemRef, guid, Guid),
          api_test_memory:set(MemRef, file_guid, FileGuid),
          api_test_memory:set(MemRef, file_guid2, FileGuid2),
          api_test_memory:set(MemRef, share_id, ShareId)
      end.
  
  
  %% @private
  -spec get_file_guid(api_test_memory:mem_ref(), test_mode()) -> file_id:file_guid().
  get_file_guid(MemRef, TestMode) ->
      get_file_guid(MemRef, guid, TestMode).
  
  
  %% @private
  -spec get_file_guid(api_test_memory:mem_ref(), atom(), test_mode()) -> file_id:file_guid().
  get_file_guid(MemRef, Placeholder, TestMode) ->
      BareGuid = api_test_memory:get(MemRef, Placeholder),
      case TestMode of
          normal_mode ->
              BareGuid;
          share_mode ->
              ShareId = api_test_memory:get(MemRef, share_id),
              file_id:guid_to_share_guid(BareGuid, ShareId)
      end.
  
  
  %% @TODO VFS-7475 check against provided structure, not hardcoded
  %%--------------------------------------------------------------------
  %% @private
  %% @doc
  %% Compares provided tarball (as gzip compressed Bytes) against expected 
  %% structure created in `build_download_file_setup_fun`:
  %%      directory -> expects files in directory;
  %%      multiple_files -> expects files in tarball root.
  %% Files strategy describes how files check should be performed:
  %%      files_exist -> checks that appropriate files are in tarball and have proper content;
  %%      no_files -> checks that there are no files.
  %% @end
  %%--------------------------------------------------------------------
  -spec check_tarball(api_test_memory:mem_ref(), binary(), binary(), directory | multiple_files) -> ok.
  check_tarball(MemRef, Bytes, ExpContent, Type) ->
      check_tarball(MemRef, Bytes, ExpContent, Type, files_exist).
  
  %% @private
  -spec check_tarball(api_test_memory:mem_ref(), binary(), binary(), directory | multiple_files, no_files | files_exist) -> ok.
  check_tarball(MemRef, Bytes, ExpContent, directory, FilesStrategy) ->
      ?assertEqual(ok, erl_tar:extract({binary, Bytes}, [compressed, {cwd, "/tmp/"}])),
      {ok, TmpDirContentAfter} = file:list_dir("/tmp"),
      DirGuid = api_test_memory:get(MemRef, guid),
      [Node] = oct_background:get_provider_nodes(krakow),
      {ok, #file_attr{name = Dirname}} = lfm_proxy:stat(Node, ?ROOT_SESS_ID, {guid, DirGuid}),
      ?assertEqual(true, lists:member(binary_to_list(Dirname), TmpDirContentAfter)),
      check_tarball_files_content(MemRef, ExpContent, Dirname, FilesStrategy);
  check_tarball(MemRef, Bytes, ExpContent, multiple_files, FilesStrategy) ->
      ?assertEqual(ok, erl_tar:extract({binary, Bytes}, [compressed, {cwd, "/tmp/"}])),
      check_tarball_files_content(MemRef, ExpContent, <<>>, FilesStrategy).
  
  
  %% @private
  -spec check_tarball_files_content(api_test_memory:mem_ref(), binary(), binary(), no_files | files_exist) -> ok.
  check_tarball_files_content(MemRef, ExpContent, ParentName, FilesStrategy) ->
      {ok, DirContentAfter} = file:list_dir(filename:join("/tmp", ParentName)),
      [Node] = oct_background:get_provider_nodes(krakow),
      lists:foreach(fun(Placeholder) ->
          Guid = api_test_memory:get(MemRef, Placeholder),
          {ok, #file_attr{name = Filename}} = lfm_proxy:stat(Node, ?ROOT_SESS_ID, {guid, Guid}),
          case FilesStrategy of
              no_files -> ?assertEqual(false, lists:member(binary_to_list(Filename), DirContentAfter));
              files_exist -> ?assertEqual({ok, ExpContent}, file:read_file(filename:join(["/tmp", ParentName, Filename])))
          end
      end, [file_guid, file_guid2]).
  
  
  %%%===================================================================
  %%% SetUp and TearDown functions
  %%%===================================================================
  
  
  init_per_suite(Config) ->
      oct_background:init_per_suite(Config, #onenv_test_config{
  
negative.code:             type = {rest_with_shared_guid, file_id:guid_to_space_id(DirGuid)},
              target_nodes = Providers,
              client_spec = ?CLIENT_SPEC_FOR_SHARES,
              
              setup_fun = SetupFun,
              prepare_args_fun = build_rest_download_prepare_args_fun(MemRef, share_mode),
              validate_result_fun = ValidateCallResultFun,
              verify_fun = VerifyFun,
              
              data_spec = api_test_utils:add_file_id_errors_for_operations_available_in_share_mode(
                  DirGuid, DirShareId, #data_spec{
                      optional = [<<"range">>],
                      correct_values = #{<<"range">> => RangesToTestPart2}
                  }
              )
          }
      ])).
  
  
  rest_download_dir_test(Config) ->
      Providers = ?config(op_worker_nodes, Config),
      
      {_FileType, _DirPath, DirGuid, DirShareId} = api_test_utils:create_and_sync_shared_file_in_space_krk_par(
          <<"dir">>, 8#704
      ),
      
      MemRef = api_test_memory:init(),
      
      DirSpec = #dir_spec{mode = 8#705, shares = [#share_spec{}], children = [#dir_spec{}, #file_spec{content = ?CONTENT}]},
      SetupFun = build_download_file_setup_fun(MemRef, DirSpec),
      ValidateCallResultFun = fun(#api_test_ctx{client = Client}, {ok, RespCode, _RespHeaders, RespBody}) ->
          ?assertEqual(?HTTP_200_OK, RespCode),
          [FileTreeObject] = api_test_memory:get(MemRef, file_tree_object),
          User4Id = oct_background:get_user_id(user4),
          case {Client, api_test_memory:get(MemRef, test_mode)} of
              {?USER(User4Id), normal_mode} -> check_tarball(RespBody, FileTreeObject, no_files);
              _ -> check_tarball(RespBody, FileTreeObject)
          end
      end,
      
      ?assert(onenv_api_test_runner:run_tests([
          #scenario_spec{
              name = <<"Download file using rest endpoint">>,
              type = rest,
              target_nodes = Providers,
              client_spec = #client_spec{
                  correct = [
                      user2,  % space owner - doesn't need any perms
                      user3,  % files owner
                      user4   % forbidden user in space is allowed to download an empty tarball - files without access are ignored
                  ],
                  unauthorized = [nobody],
                  forbidden_not_in_space = [user1]
              },
              
              setup_fun = SetupFun,
              prepare_args_fun = build_rest_download_prepare_args_fun(MemRef, normal_mode),
              validate_result_fun = ValidateCallResultFun,
              
              data_spec = api_test_utils:add_file_id_errors_for_operations_available_in_share_mode(
                  DirGuid, undefined, #data_spec{})
          },
          #scenario_spec{
              name = <<"Download shared file using rest endpoint">>,
              type = {rest_with_shared_guid, file_id:guid_to_space_id(DirGuid)},
              target_nodes = Providers,
              client_spec = ?CLIENT_SPEC_FOR_SHARES,
              
              setup_fun = SetupFun,
              prepare_args_fun = build_rest_download_prepare_args_fun(MemRef, share_mode),
              validate_result_fun = ValidateCallResultFun,
              
              data_spec = api_test_utils:add_file_id_errors_for_operations_available_in_share_mode(
                  DirGuid, DirShareId, #data_spec{}
              )
          }
      ])).
  
  
  %%%===================================================================
  %%% REST download spec functions
  %%%===================================================================
  
  %% @private
  -spec build_rest_download_prepare_args_fun(api_test_memory:mem_ref(), test_mode()) ->
      onenv_api_test_runner:prepare_args_fun().
  build_rest_download_prepare_args_fun(MemRef, TestMode) ->
      fun(#api_test_ctx{data = Data0}) ->
          api_test_memory:set(MemRef, test_mode, TestMode),
          [#object{guid = Guid, shares = Shares}] = api_test_memory:get(MemRef, file_tree_object),
          FileGuid = case TestMode of
              normal_mode -> Guid;
              share_mode ->
                  case Shares of
                      [ShareId | _] -> file_id:guid_to_share_guid(Guid, ShareId);
                      _ -> Guid
                  end
          end,
          {ok, FileObjectId} = file_id:guid_to_objectid(FileGuid),
          {Id, Data1} = api_test_utils:maybe_substitute_bad_id(FileObjectId, Data0),
  
  