| #!/usr/bin/env escript |
| %% -*- erlang -*- |
| |
| % Licensed under the Apache License, Version 2.0 (the "License"); you may not |
| % use this file except in compliance with the License. You may obtain a copy of |
| % the License at |
| % |
| % http://www.apache.org/licenses/LICENSE-2.0 |
| % |
| % Unless required by applicable law or agreed to in writing, software |
| % distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
| % WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
| % License for the specific language governing permissions and limitations under |
| % the License. |
| |
| main(_) -> |
| test_util:init_code_path(), |
| etap:plan(13), |
| case (catch test()) of |
| ok -> |
| etap:end_tests(); |
| Other -> |
| etap:diag(io_lib:format("Test died abnormally: ~p", [Other])), |
| etap:bail(Other) |
| end, |
| ok. |
| |
| read_all(Fd, PosList) -> |
| Data = couch_stream:foldl(Fd, PosList, fun(Bin, Acc) -> [Bin, Acc] end, []), |
| iolist_to_binary(Data). |
| |
| test() -> |
| {ok, Fd} = couch_file:open("test/etap/temp.050", [create,overwrite]), |
| {ok, Stream} = couch_stream:open(Fd), |
| |
| etap:is(ok, couch_stream:write(Stream, <<"food">>), |
| "Writing to streams works."), |
| |
| etap:is(ok, couch_stream:write(Stream, <<"foob">>), |
| "Consecutive writing to streams works."), |
| |
| etap:is(ok, couch_stream:write(Stream, <<>>), |
| "Writing an empty binary does nothing."), |
| |
| {Ptrs, Length, _, _, _} = couch_stream:close(Stream), |
| etap:is(Ptrs, [0], "Close returns the file pointers."), |
| etap:is(Length, 8, "Close also returns the number of bytes written."), |
| etap:is(<<"foodfoob">>, read_all(Fd, Ptrs), "Returned pointers are valid."), |
| |
| % Remeber where we expect the pointer to be. |
| {ok, ExpPtr} = couch_file:bytes(Fd), |
| {ok, Stream2} = couch_stream:open(Fd), |
| OneBits = <<1:(8*10)>>, |
| etap:is(ok, couch_stream:write(Stream2, OneBits), |
| "Successfully wrote 80 1 bits."), |
| |
| ZeroBits = <<0:(8*10)>>, |
| etap:is(ok, couch_stream:write(Stream2, ZeroBits), |
| "Successfully wrote 80 0 bits."), |
| |
| {Ptrs2, Length2, _, _, _} = couch_stream:close(Stream2), |
| etap:is(Ptrs2, [ExpPtr], "Closing stream returns the file pointers."), |
| etap:is(Length2, 20, "Length written is 160 bytes."), |
| |
| AllBits = iolist_to_binary([OneBits,ZeroBits]), |
| etap:is(AllBits, read_all(Fd, Ptrs2), "Returned pointers are valid."), |
| |
| % Stream more the 4K chunk size. |
| {ok, ExpPtr2} = couch_file:bytes(Fd), |
| {ok, Stream3} = couch_stream:open(Fd), |
| Acc2 = lists:foldl(fun(_, Acc) -> |
| Data = <<"a1b2c">>, |
| couch_stream:write(Stream3, Data), |
| [Data | Acc] |
| end, [], lists:seq(1, 1024)), |
| {Ptrs3, Length3, _, _, _} = couch_stream:close(Stream3), |
| |
| % 4095 because of 5 * 4096 rem 5 (last write before exceeding threshold) |
| % + 5 puts us over the threshold |
| % + 4 bytes for the term_to_binary adding a length header |
| % + 1 byte every 4K for tail append headers |
| SecondPtr = ExpPtr2 + 4095 + 5 + 4 + 1, |
| etap:is(Ptrs3, [ExpPtr2, SecondPtr], "Pointers every 4K bytes."), |
| etap:is(Length3, 5120, "Wrote the expected 5K bytes."), |
| |
| couch_file:close(Fd), |
| ok. |