Module: io-test-suite Synopsis: IO library test suite Author: Andy Armstrong, et al... Copyright: Original Code is Copyright (c) 1995-2004 Functional Objects, Inc. All rights reserved. License: Functional Objects Library Public License Version 1.0 Dual-license: GNU Lesser General Public License Warranty: Distributed WITHOUT WARRANTY OF ANY KIND /// Useful constants define constant $default-string = "abcdefghijklmnopqrstuvwxyz"; /// Stream convenience function tests register-stream-test(, test-read-character, direction: #"input"); register-stream-test(, test-read-text, direction: #"input"); register-stream-test(, test-read-text-into!, direction: #"input"); register-stream-test(, test-read-line, direction: #"input"); register-stream-test(, test-read-line-into!, direction: #"input"); register-stream-test(, test-read-to, direction: #"input"); register-stream-test(, test-read-through, direction: #"input"); register-stream-test(, test-read-to-end, direction: #"input"); register-stream-test(, test-skip-through, direction: #"input"); register-stream-test(, test-write-text, direction: #"output"); register-stream-test(, test-write-line, direction: #"output"); register-stream-test(, test-new-line, direction: #"output"); // Don't test the functions we're already testing... there must be a better way! define streams function-test read-character () end; define streams function-test read-text () end; define streams function-test read-text-into! () end; define streams function-test read-line () end; define streams function-test read-line-into! () end; define streams function-test read-to () end; define streams function-test read-through () end; define streams function-test read-to-end () end; define streams function-test skip-through () end; define streams function-test write-text () end; define streams function-test write-line () end; define streams function-test new-line () end; define method test-read-character (info :: , stream :: ) => () //---*** Fill this in... end method test-read-character; define method test-read-text (info :: , stream :: ) => () //---*** Fill this in... end method test-read-text; define method test-read-text-into! (info :: , stream :: ) => () //---*** Fill this in... end method test-read-text-into!; define method test-read-line (info :: , stream :: ) => () //---*** Fill this in... end method test-read-line; define method test-read-line-into! (info :: , stream :: ) => () //---*** Fill this in... end method test-read-line-into!; define method test-read-to (info :: , stream :: ) => () //---*** Fill this in... end method test-read-to; define method test-read-through (info :: , stream :: ) => () //---*** Fill this in... end method test-read-through; define method test-read-to-end (info :: , stream :: ) => () //---*** Fill this in... end method test-read-to-end; define method test-skip-through (info :: , stream :: ) => () //---*** Fill this in... end method test-skip-through; define method test-write-text (info :: , stream :: ) => () //---*** Fill this in... end method test-write-text; define method test-write-line (info :: , stream :: ) => () //---*** Fill this in... end method test-write-line; define method test-new-line (info :: , stream :: ) => () //---*** Fill this in... end method test-new-line; /// Positionable stream convenience function tests register-stream-test(, test-current-position); register-stream-test(, test-current-position-setter); register-stream-test(, test-initial-position); register-stream-test(, test-final-position); // Don't test the functions we're already testing... there must be a better way! define streams function-test current-position () end; define streams function-test current-position-setter () end; define streams function-test initial-position () end; define streams function-test final-position () end; define method test-current-position (info :: , stream :: ) => () //---*** Fill this in... end method test-current-position; define method test-current-position-setter (info :: , stream :: ) => () //---*** Fill this in... end method test-current-position-setter; define method test-initial-position (info :: , stream :: ) => () //---*** Fill this in... end method test-initial-position; define method test-final-position (info :: , stream :: ) => () //---*** Fill this in... end method test-final-position; /// Buffered stream tests register-stream-test(, test-get-input-buffer, direction: #"input"); register-stream-test(, test-release-input-buffer, direction: #"input"); register-stream-test(, test-with-input-buffer, direction: #"input"); register-stream-test(, test-input-available-at-source?, direction: #"input"); register-stream-test(, test-get-output-buffer, direction: #"output"); register-stream-test(, test-release-output-buffer, direction: #"output"); register-stream-test(, test-next-output-buffer, direction: #"output"); register-stream-test(, test-with-output-buffer, direction: #"output"); register-stream-test(, test-force-output-buffers, direction: #"output"); // Don't test the functions we're already testing... there must be a better way! define streams function-test get-input-buffer () end; define streams function-test release-input-buffer () end; define streams function-test input-available-at-source? () end; define streams function-test get-output-buffer () end; define streams function-test release-output-buffer () end; define streams function-test next-output-buffer () end; define streams function-test force-output-buffers () end; define streams macro-test with-input-buffer-test () end; define streams macro-test with-output-buffer-test () end; define method test-get-input-buffer (info :: , stream :: ) => () //---*** Fill this in... end method test-get-input-buffer; define method test-release-input-buffer (info :: , stream :: ) => () //---*** Fill this in... end method test-release-input-buffer; define method test-with-input-buffer (info :: , stream :: ) => () //---*** Fill this in... end method test-with-input-buffer; define method test-input-available-at-source? (info :: , stream :: ) => () //---*** Fill this in... end method test-input-available-at-source?; define method test-get-output-buffer (info :: , stream :: ) => () //---*** Fill this in... end method test-get-output-buffer; define method test-release-output-buffer (info :: , stream :: ) => () //---*** Fill this in... end method test-release-output-buffer; define method test-next-output-buffer (info :: , stream :: ) => () //---*** Fill this in... end method test-next-output-buffer; define method test-with-output-buffer (info :: , stream :: ) => () //---*** Fill this in... end method test-with-output-buffer; define method test-force-output-buffers (info :: , stream :: ) => () //---*** Fill this in... end method test-force-output-buffers; /// Sequence stream tests register-stream-test(, test-type-for-sequence-stream); register-stream-test(, test-stream-limit); register-stream-test(, test-stream-limit-setter); // Don't test the functions we're already testing... there must be a better way! define streams function-test type-for-sequence-stream () end; define streams function-test stream-limit () end; define streams function-test stream-limit-setter () end; define method test-type-for-sequence-stream (info :: , stream :: ) => () //---*** Fill this in... end method test-type-for-sequence-stream; define method test-stream-limit (info :: , stream :: ) => () //---*** Fill this in... end method test-stream-limit; define method test-stream-limit-setter (info :: , stream :: ) => () //---*** Fill this in... end method test-stream-limit-setter; register-stream-class-info("", , input-stream?: #t, output-stream?: #t, element-type: ); define sideways method make-stream-tests-of-size (class :: subclass(), stream-size :: ) => (streams :: ) let class-info = stream-class-info(class); let tests :: = make(); let integer-sequence = range(from: 1, to: stream-size); let character-sequence = copy-sequence($default-string, end: stream-size); local method add-stream-test-info (class :: subclass(), sequence :: , element-type :: , direction :: ) => () add!(tests, make(, test-name: format-to-string("%s %s on %s size %d", direction, class-info.info-class-name, class, stream-size), class-info: class-info, contents: sequence, direction: direction, make-function: method () => (stream :: ) make(, contents: as(class, sequence), element-type: element-type, direction: direction) end)) end method add-stream-test-info; add-stream-test-info(, integer-sequence, , #"input"); add-stream-test-info(, integer-sequence, , #"output"); add-stream-test-info(, character-sequence, , #"input"); add-stream-test-info(, character-sequence, , #"output"); for (collection-class :: in vector(, , )) let integer-contents = as(collection-class, integer-sequence); add-stream-test-info(collection-class, integer-sequence, , #"input"); add-stream-test-info(collection-class, integer-sequence, , #"output"); add-stream-test-info(collection-class, character-sequence, , #"input"); add-stream-test-info(collection-class, character-sequence, , #"output"); end; tests end method make-stream-tests-of-size; register-stream-class-info("", , input-stream?: #t, output-stream?: #t, element-type: ); register-stream-class-info("", , input-stream?: #t, output-stream?: #t, element-type: ); define sideways method make-stream-tests-of-size (class :: subclass(), stream-size :: ) => (tests :: ) let class-info = stream-class-info(class); let tests :: = make(); let character-sequence = copy-sequence($default-string, end: stream-size); local method add-stream-test-info (direction :: ) => () add!(tests, make(, test-name: format-to-string("%s %s size %d", direction, class-info.info-class-name, stream-size), class-info: class-info, contents: character-sequence, direction: direction, make-function: method () => (stream :: ) make(class, contents: character-sequence, element-type: , direction: direction) end)) end method add-stream-test-info; add-stream-test-info(#"input"); add-stream-test-info(#"output"); tests end method make-stream-tests-of-size; /*---*** andrewa: not yet... register-stream-class-info("", , input-stream?: #t, output-stream?: #t, element-type: ); */ /// Wrapper stream testing register-stream-test(, test-inner-stream); register-stream-test(, test-inner-stream-setter); // Don't test the functions we're already testing... there must be a better way! define streams function-test inner-stream () end; define streams function-test inner-stream-setter () end; define method test-inner-stream (info :: , stream :: ) => () //---*** Fill this in... end method test-inner-stream; define method test-inner-stream-setter (info :: , stream :: ) => () //---*** Fill this in... end method test-inner-stream-setter; register-stream-class-info("", , input-stream?: #t, output-stream?: #t, element-type: ); define sideways method make-stream-tests-of-size (class == , stream-size :: ) => (streams :: ) let class-info = stream-class-info(); let tests :: = make(); local method add-wrapper-stream-test (test :: ) => (test :: ) let test = make(, test-name: format-to-string("%s for %s", class-info.info-class-name, test.info-test-name), class-info: class-info, contents: test.info-contents, direction: test.info-direction, make-function: method () let stream = test.info-make-function(); make(, inner-stream: stream) end); add!(tests, test); test end method add-wrapper-stream-test; for (class :: subclass() in registered-stream-classes()) if (class ~== ) let inner-stream-tests = make-stream-tests-of-size(, stream-size); // First create single layer wrappers let tests = map(add-wrapper-stream-test, inner-stream-tests); // Then create wrappers on wrappers! do(add-wrapper-stream-test, tests) end end; add!(tests, make(, test-name: " for ", class-info: stream-class-info(), contents: $default-string, direction: #"input", make-function: method () let stream = make(, test-sequence: $default-string); make(, inner-stream: stream) end)); tests end method make-stream-tests-of-size; /// Test wrapper stream subclass define class () end class ; register-stream-class-info("", , input-stream?: #t, output-stream?: #t, element-type: ); define method read-element (stream :: , #rest keys, #key on-end-of-stream) => (element :: ) let char :: = next-method(); as-uppercase(char) end method read-element; define method write-element (stream :: , elt :: ) => () write-element(stream.inner-stream, as-uppercase(elt)) end method write-element; /// Miscellaneous stream testing // Note: Refs to and have been // commented out since they are not yet implemented. 1997-06-19 define streams constant-test () // ---*** Fill this in. end; define streams constant-test () // ---*** Fill this in. end; define streams constant-test () // ---*** Fill this in. end; /* define streams constant-test () // ---*** Fill this in. end; */ define sideways method make-test-instance (class == ) => (vector :: ) make(, size: 1, fill: 0) end method make-test-instance; define streams class-test () // ---*** Fill this in. end; define streams class-test () // ---*** Fill this in. end; define streams class-test () // ---*** Fill this in. end; define streams function-test stream-lock () // ---*** Fill this in. end; define streams function-test stream-lock-setter () // ---*** Fill this in. end; define streams function-test outer-stream () // ---*** Fill this in. end; define streams function-test outer-stream-setter () // ---*** Fill this in. end; define streams function-test buffer-next () // ---*** Fill this in. end; define streams function-test buffer-next-setter () // ---*** Fill this in. end; define streams function-test buffer-end () // ---*** Fill this in. end; define streams function-test buffer-end-setter () // ---*** Fill this in. end; define streams function-test buffer-subsequence () // ---*** Fill this in. end; define streams function-test copy-into-buffer! () // ---*** Fill this in. end; define streams function-test copy-from-buffer! () // ---*** Fill this in. end; define streams function-test do-get-input-buffer () // ---*** Fill this in. end; define streams function-test do-get-output-buffer () // ---*** Fill this in. end; define streams function-test do-input-available-at-source? () // ---*** Fill this in. end; define streams function-test next-input-buffer () // ---*** Fill this in. end; define streams function-test do-next-input-buffer () // ---*** Fill this in. end; define streams function-test do-next-output-buffer () // ---*** Fill this in. end; define streams function-test do-release-input-buffer () // ---*** Fill this in. end; define streams function-test do-release-output-buffer () // ---*** Fill this in. end; define streams macro-test with-output-to-string-test () let test-string = "Hello world"; check-equal("with-output-to-string test", with-output-to-string (stream) write(stream, test-string) end, test-string) end; /// Miscellaneous stream tests /*---*** andrewa: not currently used define constant $line-end :: = select ($os-name) #"win32" => "\r\n"; #"carbon" => "\r"; otherwise => "\n"; end; define constant $line-boundary :: = $line-end.first; */ // This is a hack to replace the uses of stream-contents in the existing // test suite. Stream contents can't be used on output file streams. // There are problems with opening multiple streams to a single // file on the PC. define method stream-contents-and-close (stream :: ) => (the-contents :: ) let the-contents :: false-or() = stream-contents(stream); close(stream); the-contents end method stream-contents-and-close; define function default-stream-setup-function (stream, #key direction = #"input", contents = "") => (stream :: ) if (contents ~= "") make(stream, direction: direction, contents: contents); else make(stream, direction: direction); end if; end function; define function default-stream-cleanup-function (stream :: ) => () ignore(stream); end function; define method line-test (class :: subclass(), tester-without-line-end :: , line-end :: , #key setup-function = default-stream-setup-function, cleanup-function = default-stream-cleanup-function) let tester = concatenate(tester-without-line-end, line-end); let s = setup-function(class, direction: #"input", contents: tester); if (member?('\n', tester)) check("read-line", \=, read-line(s), tester-without-line-end); else check-condition("read-line condition", , read-line(s)); end if; cleanup-function(s); s := setup-function(class, direction: #"output"); write-line(s, tester-without-line-end); if (line-end.size = 2) let the-contents = stream-contents-and-close(s); check-true("write line worked?", (last(the-contents) = second(line-end)) & (the-contents[the-contents.size - 2] = first(line-end))); else check("write line worked?", \=, last(stream-contents-and-close(s)), line-end.last); end if; cleanup-function(s); // one read-write test s := setup-function(class, direction: #"input-output", contents: tester); if (size(tester) > 0) check("read-write read check", \=, read-element(s), first(tester)); write-element(s, third(tester)); second(tester) := third(tester); check("read-write write check", \=, stream-contents-and-close(s), tester); end if; cleanup-function(s); end method; define method positionable-stream-test (class :: subclass(), tester, #key setup-function = default-stream-setup-function, cleanup-function = default-stream-cleanup-function) => () let s = setup-function(class, direction: #"input", contents: tester); check("stream position is zero?", zero?, as(, stream-position(s))); check("stream position is end?", \=, size(tester), as(, adjust-stream-position(s, size(tester), from: #"start"))); if (size(tester) > 2) stream-position-setter(2, s); check("stream position works?", \=, read-element(s), third(tester)); end if; check("stream-size works?", \=, size(tester), stream-size(s)); // unless (instance?(s, )) stream-contents(s, clear-contents?: #t); check("clear contents", zero?, stream-size(s)); // end unless; cleanup-function(s); end method positionable-stream-test; define test test-line-functions () // String streams always use the "platform independent" terminator line-test(, "hello there!", "\n"); /* line-test(, "hello there!", $line-end, setup-function: create-file-stream, cleanup-function: destroy-file-stream); */ end test; define test test-position-string-streams () positionable-stream-test(, "hello there"); positionable-stream-test(, ""); end test; define test test-position-sequence-stream () positionable-stream-test(, #(1, 2, 3)); positionable-stream-test(, #()); end test; define test test-position-alt-string-streams () positionable-stream-test(, "yo baby!"); /* positionable-stream-test(, concatenate("here we go baby", $line-end)); */ end test; define test test-stretchy-stream (description: " stretchy vector tests") begin let sv = make(); let s = make(, contents: sv, direction: #"output"); write(s, #(1, 2, 3)); write(s, #(4, 5, 6)); check-true("stretchy vector streched", sv = #(1, 2, 3, 4, 5, 6)); check("stretchy vector", \=, stream-contents(s), as(, list(1,2,3,4,5,6)) ); end; begin let v = make(, size: 3); let s = make(, contents: v, direction: #"output"); write(s, #(1, 2, 3)); write(s, #(4, 5, 6)); check-true("test vector",v = #[1, 2, 3]); check("test stream with vector", \=, stream-contents(s), #[1,2,3,4,5,6]); end; begin let sv = make(); let s = make(, contents: sv, direction: #"output"); write(s, #(1, 2, 3)); write(s, #(4, 5, 6)); check("test stream with stretchy vector", \=, stream-contents(s), as(, list(1,2,3,4,5,6))); end; begin let v = make(, size: 3); let s = make(, contents: v, direction: #"output"); write(s, #(1, 2, 3)); write(s, #(4, 5, 6)); check-true("test vector #2",v = #[1, 2, 3]); check-true("test stream vector", stream-contents(s) = #[1,2,3,4,5,6]); end; end; define suite universal-streams-suite () test test-line-functions; end suite universal-streams-suite; define suite additional-streams-suite () test test-position-string-streams; test test-position-sequence-stream; test test-position-alt-string-streams; test test-stretchy-stream; end suite additional-streams-suite;