diff --git a/.codacy.yml b/.codacy.yml index 6225d8753c..0608595481 100644 --- a/.codacy.yml +++ b/.codacy.yml @@ -25,4 +25,7 @@ # package name contains capital letter and such names are conventional. --- exclude_paths: - - "eo-runtime/src/test/java/org/eolang/SnippetTestCase.java" + - "eo-runtime/src/test/java/EOorg/EOeolang/EOtxt/EOsprintfTest.java" + - "eo-runtime/src/test/java/EOorg/EOeolang/EOtxt/package-info.java" + - "eo-runtime/src/main/java/EOorg/EOeolang/EOtxt/EOsprintf.java" + - "eo-runtime/src/main/java/EOorg/EOeolang/EOtxt/package-info.java" diff --git a/eo-maven-plugin/pom.xml b/eo-maven-plugin/pom.xml index 7cdb9ddfa9..59df46e3da 100644 --- a/eo-maven-plugin/pom.xml +++ b/eo-maven-plugin/pom.xml @@ -306,6 +306,7 @@ SOFTWARE. rewritten_sources/pom.xml duplicate_classes/pom.xml simple/pom.xml + hash_package_layer/pom.xml diff --git a/eo-parser/src/main/resources/org/eolang/parser/stars-to-tuples.xsl b/eo-parser/src/main/resources/org/eolang/parser/stars-to-tuples.xsl index 89a7a9c656..633a796b72 100644 --- a/eo-parser/src/main/resources/org/eolang/parser/stars-to-tuples.xsl +++ b/eo-parser/src/main/resources/org/eolang/parser/stars-to-tuples.xsl @@ -28,7 +28,7 @@ SOFTWARE. - + diff --git a/eo-parser/src/test/resources/org/eolang/parser/packs/syntax/tuples.yaml b/eo-parser/src/test/resources/org/eolang/parser/packs/syntax/tuples.yaml index 378e3c6b48..db27bec7e2 100644 --- a/eo-parser/src/test/resources/org/eolang/parser/packs/syntax/tuples.yaml +++ b/eo-parser/src/test/resources/org/eolang/parser/packs/syntax/tuples.yaml @@ -43,6 +43,7 @@ tests: - //o[@base='tuple' and @line=5]/o[@base='tuple']/o[@base='tuple']/o[@base='.empty' and @method] - //o[@base='arr']/o[@base='tuple' and @line=9 and @pos=5] - //o[@base='arr']/o[@base='.empty' and @line=9 and @pos=6] + - //o[@name='y' and @base='.reduced']/o[@base='tuple' and not(@star)]/following-sibling::o[@base='.empty' and @method] eo: | * > xs * 1 > xl @@ -53,3 +54,7 @@ eo: | d.e.f g.h.i (arr *).elements + list + .reduced > y + * + [x] diff --git a/eo-runtime/src/main/eo/org/eolang/structs/list.eo b/eo-runtime/src/main/eo/org/eolang/structs/list.eo new file mode 100644 index 0000000000..e62ccd8b73 --- /dev/null +++ b/eo-runtime/src/main/eo/org/eolang/structs/list.eo @@ -0,0 +1,289 @@ +# The MIT License (MIT) +# +# Copyright (c) 2016-2024 Objectionary.com +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + ++architect yegor256@gmail.com ++home https://github.com/objectionary/eo ++package org.eolang.structs ++rt jvm org.eolang:eo-runtime:0.0.0 ++rt node eo2js-runtime:0.0.0 ++version 0.0.0 + +# List implements based operations on collections like reducing, mapping, filtering, etc. +# Decorates and extends `tuple`. +[origin] > list + origin > @ + + # Is it empty? + 0.eq ^.origin.length > [] > is-empty + + # Create a new list with this element added to the end of it. + [x] > with + list > @ + with. + ^.origin + x + + # Create a new list with an element inserted by the provided index. + [index item] > withi + concat. > @ + with. + ^.head index + item + ^.tail + ^.origin.length.minus index + + # Reduce with index from "start" using the function "func". + # Here "func" must be an abstract object with three free attributes. + # The first one for the accumulator, the second one + # for the element of the collection and the third one for the index. + [start func] > reducedi + ^.origin.length > origin-len! + if. > @ + 0.eq origin-len + start + rec-reduced start 0.as-bytes + + [accum index] > rec-reduced + if. > @ + eq. + 1.plus > next-index! + index.as-int > idx-as-int + ^.origin-len + ^.func > accumulated + accum + ^.^.origin.at idx-as-int + idx-as-int + ^.rec-reduced + accumulated + next-index + + # Reduce from "start" using the function "func". + # Here "func" must be an abstract object with two free attributes. + # The first one for the accumulator, the second one for the element + # of the collection. + [start func] > reduced + ^.reducedi > @ + start + ^.func accum item > [accum item idx] >> + + # Map with index. Here "func" must be an abstract + # object with two free attributes. The first + # one for the element of the collection, the second one + # for the index. + [func] > mappedi + list > @ + ^.reducedi + * + [accum item idx] >> + with. > @ + accum + ^.func item idx + + # Map without index. Here "func" must be an abstract + # object with one free attribute, for the element + # of the collection. + [func] > mapped + ^.mappedi > @ + ^.func item > [item idx] >> + + # For each collection element dataize the object + # Here "func" must be an abstract object with + # two free attributes: the element of the + # collection and its index. + # The result of `func` must be dataizable. + [func] > eachi + ^.reducedi > @ + true + [acc item index] >> + seq > @ + * + acc + ^.func item index + + # For each collection element dataize the object + # Here "func" must be an abstract object with + # one free attribute, the element of the collection. + [func] > each + ^.eachi > @ + ^.func item > [item index] >> + + # Create a new list without the i-th element. + [i] > withouti + list > @ + ^.reducedi + * + [accum item idx] >> + if. > @ + ^.i.eq idx + accum + accum.with item + + # Create a new list without the `element` which is `.eq` to given one. + [element] > without + list > @ + ^.reduced + * + [accum item] >> + if. > @ + ^.element.eq item + accum + accum.with item + + # Checks if all elements of the current list are `.eq` + # to the all elements of given collection. + [other] > eq + and. > @ + eq. + ^.origin.length + other.length + ^.reducedi + true + [accum item idx] >> + and. > @ + accum + eq. + item + ^.other.at idx + + # Concatenates current list with given one. + [passed] > concat + reduced. > @ + list + passed + ^ + accum.with item > [accum item] + + # Returns index of the first particular item in list. + # If the list has no this item, index-of returns -1 + [wanted] > index-of + ^.reducedi > @ + -1 + [accum item index] >> + if. > @ + and. + -1.eq accum + item.eq ^.wanted + index + accum + + # Returns index of the last particular item in list. + # If the list has no this item, returns -1 + [wanted] > last-index-of + ^.reducedi > @ + -1 + [accum item index] >> + if. > @ + item.eq ^.wanted + index + accum + + # Returns `true` if the list contains `element`. + # Otherwise, `false`. + [element] > contains + not. > @ + eq. + -1 + ^.index-of element + + # Returns a new list sorted via `.lt` method. + # @todo #3251:30min The object does not work. After moving `list` object + # to eo-runtime this is the only method which does not work because it's quite + # hard to implement properly, especially after big changes in EO semantic. + # We need to get it done and write some tests for it. + ^ > [] > sorted + + # Filter list with index with the function `func`. + # Here `func` must be an abstract + # object with two attributes. The first + # one for the element, the second one + # for the index. The result of dataization + # the `func` should be boolean, that is `true` or `false`. + [func] > filteredi + ^.origin.length > origin-length! + list > @ + rec-filtered 0.as-bytes * + + [idx-as-bytes accum] > rec-filtered + ^.^.origin > original + if. > @ + idx-as-bytes.eq ^.origin-length + accum + ^.rec-filtered + as-bytes. + 1.plus + idx-as-bytes.as-int > index + if. + ^.func + ^.^.origin.at index > item + index + accum.with item + accum + + # Filter list without index with the function `func`. + # Here `func` must be an abstract object + # with one attribute for the element. + # The result of dataization the `func` + # should be boolean, that is `true` or `false`. + [func] > filtered + ^.filteredi > @ + ^.func item > [item index] >> + + # Get the first `index` elements from the start of the list. + [index] > head + index > idx! + switch > @ + * + * + 0.eq idx + list * + * + 0.gt idx + ^.tail index.as-int.neg + * + ^.origin.length.lte idx + ^ + * + true + list + ^.reducedi + * + [accum item index] >> + if. > @ + index.gte ^.idx + accum + accum.with item + + # Get the last `index` elements from the end of the list. + [index] > tail + index > idx! + ^.origin.length.minus idx.as-int > start! + if. > @ + 0.gt start + ^ + list + ^.reducedi + * + [accum item idx] >> + if. > @ + idx.gte ^.start + accum.with item + accum diff --git a/eo-runtime/src/main/eo/org/eolang/tuple.eo b/eo-runtime/src/main/eo/org/eolang/tuple.eo index 519b2da26b..e19433db53 100644 --- a/eo-runtime/src/main/eo/org/eolang/tuple.eo +++ b/eo-runtime/src/main/eo/org/eolang/tuple.eo @@ -33,8 +33,7 @@ [] > empty 0 > length - [i] > at - error "Can't get an object from the empty tuple" > @ + error "Can't get an object from the empty tuple" > [i] > at [x] > with tuple > @ diff --git a/eo-runtime/src/main/eo/org/eolang/txt/sprintf.eo b/eo-runtime/src/main/eo/org/eolang/txt/sprintf.eo new file mode 100644 index 0000000000..d41f5c4584 --- /dev/null +++ b/eo-runtime/src/main/eo/org/eolang/txt/sprintf.eo @@ -0,0 +1,39 @@ +# The MIT License (MIT) +# +# Copyright (c) 2016-2024 Objectionary.com +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + ++architect yegor256@gmail.com ++home https://github.com/objectionary/eo ++package org.eolang.txt ++rt jvm org.eolang:eo-runtime:0.0.0 ++rt node eo2js-runtime:0.0.0 ++version 0.0.0 + +# The sprintf object allows you to format and output text depending +# on the arguments passed to it. +# When arguments are processed - they're dataized and converted to objects +# depending on next flags: +# - %s - converts object to `string` +# - %d - converts object to `int` +# - %f - converts object to `float` +# - %x - converts object to `bytes` +# - %b - converts object to boolean, `true` or `false`. +[format args] > sprintf /string diff --git a/eo-runtime/src/main/java/EOorg/EOeolang/EOio/EOstdin$EOnext_line.java b/eo-runtime/src/main/java/EOorg/EOeolang/EOio/EOstdin$EOnext_line.java index bd77c68d0d..76039234c1 100644 --- a/eo-runtime/src/main/java/EOorg/EOeolang/EOio/EOstdin$EOnext_line.java +++ b/eo-runtime/src/main/java/EOorg/EOeolang/EOio/EOstdin$EOnext_line.java @@ -34,6 +34,7 @@ import org.eolang.PhDefault; import org.eolang.Phi; import org.eolang.Versionized; +import org.eolang.XmirObject; /** * Standard Input. Consumes only one line. @@ -42,6 +43,7 @@ * @checkstyle TypeNameCheck (5 lines) */ @Versionized +@XmirObject(oname = "stdin.next-line") public final class EOstdin$EOnext_line extends PhDefault implements Atom { @Override public Phi lambda() { diff --git "a/eo-runtime/src/main/java/EOorg/EOeolang/EOio/EOstdin$EO\317\206.java" "b/eo-runtime/src/main/java/EOorg/EOeolang/EOio/EOstdin$EO\317\206.java" index 881dd66ef5..1ed52c1646 100644 --- "a/eo-runtime/src/main/java/EOorg/EOeolang/EOio/EOstdin$EO\317\206.java" +++ "b/eo-runtime/src/main/java/EOorg/EOeolang/EOio/EOstdin$EO\317\206.java" @@ -32,6 +32,7 @@ import org.eolang.PhDefault; import org.eolang.Phi; import org.eolang.Versionized; +import org.eolang.XmirObject; /** * Standard Input. Consumes all data. @@ -40,6 +41,7 @@ * @checkstyle TypeNameCheck (5 lines) */ @Versionized +@XmirObject(oname = "stdin.@") public final class EOstdin$EOφ extends PhDefault implements Atom { @Override public Phi lambda() { diff --git a/eo-runtime/src/main/java/EOorg/EOeolang/EOtxt/EOsprintf.java b/eo-runtime/src/main/java/EOorg/EOeolang/EOtxt/EOsprintf.java new file mode 100644 index 0000000000..36672da669 --- /dev/null +++ b/eo-runtime/src/main/java/EOorg/EOeolang/EOtxt/EOsprintf.java @@ -0,0 +1,162 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2016-2024 Objectionary.com + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* + * @checkstyle PackageNameCheck (4 lines) + */ +package EOorg.EOeolang.EOtxt; + +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; +import java.util.StringJoiner; +import org.eolang.AtVoid; +import org.eolang.Atom; +import org.eolang.Data; +import org.eolang.Dataized; +import org.eolang.ExFailure; +import org.eolang.Param; +import org.eolang.PhDefault; +import org.eolang.Phi; +import org.eolang.XmirObject; + +/** + * Sprintf. + * + * @since 0.39.0 + * @checkstyle TypeNameCheck (5 lines) + */ +@XmirObject(oname = "sprintf") +public final class EOsprintf extends PhDefault implements Atom { + /** + * Ctor. + */ + public EOsprintf() { + this.add("format", new AtVoid("format")); + this.add("args", new AtVoid("args")); + } + + @Override + public Phi lambda() throws Exception { + final String format = new Param(this, "format").strong(String.class); + final Phi args = this.take("args"); + final Phi retriever = args.take("at"); + final Long length = new Param(args, "length").strong(Long.class); + final List arguments = new ArrayList<>(0); + String pattern = format; + long index = 0; + while (true) { + final int idx = pattern.indexOf('%'); + if (idx == -1) { + break; + } + if (index == length) { + throw new ExFailure( + String.format( + "The amount of arguments %d does not match the amount of format occurrences %d", + length, + EOsprintf.percents(format) + ) + ); + } + final char sym = pattern.charAt(idx + 1); + final Phi taken = retriever.copy(); + taken.put(0, new Data.ToPhi(index)); + arguments.add(EOsprintf.formatted(sym, new Dataized(taken))); + pattern = pattern.substring(idx + 1); + ++index; + } + return new ToPhi( + String.format( + Locale.US, + format.replaceAll("%x", "%s"), + arguments.toArray() + ) + ); + } + + /** + * Convert byte array to hex string. + * @param bytes Byte array + * @return Bytes as hex string + */ + private static String bytesToHex(final byte[] bytes) { + final StringJoiner out = new StringJoiner("-"); + for (final byte bty : bytes) { + out.add(String.format("%02X", bty)); + } + return out.toString(); + } + + /** + * Format given {@code element} depending on format char. + * @param symbol Format char + * @param element Element ready for formatting + * @return Formatted object + */ + private static Object formatted(final char symbol, final Dataized element) { + final Object result; + switch (symbol) { + case 's': + result = element.take(String.class); + break; + case 'd': + result = element.take(Long.class); + break; + case 'f': + result = element.take(Double.class); + break; + case 'x': + result = EOsprintf.bytesToHex(element.take()); + break; + case 'b': + result = element.take(Boolean.class); + break; + default: + throw new ExFailure( + String.format( + "The format %c is unsupported, only %s formats can be used", + symbol, + "%s, %d, %f, %x, %b" + ) + ); + } + return result; + } + + /** + * Count amount of '%' char occurrences. + * @param str Given string + * @return Amount of '%' in string + */ + private static int percents(final String str) { + int count = 0; + for (int idx = 0; idx < str.length(); ++idx) { + if (str.charAt(idx) == '%') { + ++count; + } + } + return count; + } +} diff --git a/eo-runtime/src/main/java/EOorg/EOeolang/EOtxt/package-info.java b/eo-runtime/src/main/java/EOorg/EOeolang/EOtxt/package-info.java new file mode 100644 index 0000000000..fd3647da08 --- /dev/null +++ b/eo-runtime/src/main/java/EOorg/EOeolang/EOtxt/package-info.java @@ -0,0 +1,31 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2016-2024 Objectionary.com + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/** + * EO runtime, TXT. + * + * @since 0.39 + * @checkstyle PackageNameCheck (4 lines) + */ +package EOorg.EOeolang.EOtxt; diff --git a/eo-runtime/src/main/java/org/eolang/Data.java b/eo-runtime/src/main/java/org/eolang/Data.java index 877abcb13b..82b38fca5f 100644 --- a/eo-runtime/src/main/java/org/eolang/Data.java +++ b/eo-runtime/src/main/java/org/eolang/Data.java @@ -142,6 +142,7 @@ public byte[] delta() { * @param obj Object to convert * @return Constructed Phi */ + @SuppressWarnings("PMD.CognitiveComplexity") private static Phi toPhi(final Object obj) { final Phi phi; final Phi eolang = Phi.Φ.take("org").take("eolang"); @@ -151,6 +152,17 @@ private static Phi toPhi(final Object obj) { } else { phi = eolang.take("false"); } + } else if (obj instanceof Phi[]) { + final Phi tuple = eolang.take("tuple"); + Phi argument = tuple.take("empty"); + Phi tup; + for (final Phi element : (Phi[]) obj) { + tup = tuple.copy(); + tup.put(0, argument); + tup.put(1, element); + argument = tup; + } + phi = argument; } else if (obj instanceof byte[]) { phi = eolang.take("bytes").copy(); phi.attach((byte[]) obj); diff --git a/eo-runtime/src/test/eo/org/eolang/structs/list-tests.eo b/eo-runtime/src/test/eo/org/eolang/structs/list-tests.eo new file mode 100644 index 0000000000..d7382e9a56 --- /dev/null +++ b/eo-runtime/src/test/eo/org/eolang/structs/list-tests.eo @@ -0,0 +1,538 @@ +# The MIT License (MIT) +# +# Copyright (c) 2016-2024 Objectionary.com +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + ++alias org.eolang.io.stdout ++alias org.eolang.structs.list ++alias org.eolang.txt.sprintf ++architect yegor256@gmail.com ++home https://github.com/objectionary/eo ++tests ++package org.eolang.structs ++version 0.0.0 + +# Test. +[] > list-should-not-be-empty + not. > @ + is-empty. + list + * 1 2 + +# Test. +(list *).is-empty > [] > list-should-be-empty + +# Test. +[] > list-should-not-be-empty-with-three-objects + * > xs + [x] + [y] + [z] + (list xs).is-empty.not > @ + +# Test. +[] > list-should-not-be-empty-with-one-anon-object + * > xs + [f] + (list xs).is-empty.not > @ + +# Test. +[] > list-simple-with + eq. > @ + with. + list + * 1 2 + 3 + * 1 2 3 + +# Test. +[] > simple-insert + eq. > @ + withi. + list + * 1 2 3 4 5 + 3 + "hello" + * 1 2 3 "hello" 4 5 + +# Test. +[] > insert-with-zero-index + eq. > @ + withi. + list + * 1 2 3 4 5 + 0 + "hello" + * "hello" 1 2 3 4 5 + +# Test. +[] > reduce-list-with-index + * 2 2 > src + eq. > @ + 6 + reducedi. + list + * 1 1 + 0 + [a x i] >> + plus. > @ + x + a.plus + ^.src.at i + +# Test. +[] > list-reducedi-long-int-array + eq. > @ + reducedi. + list + * 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 + 0 + x.plus a > [a x i] + 1 + +# Test. +[] > list-reducedi-bools-array + not. > @ + reducedi. + list + * true true false + true + x.and a > [a x i] + +# Test. +[] > list-reducedi-nested-functions + eq. > @ + reducedi. + list + * 10 500 + 0 + [acc x i] + check x > @ + [el] > check + if. > @ + ^.x.lt 100 + ^.acc.plus x + ^.acc.minus x + plus. + 10 + 0.minus 500 + +# Test. +[] > list-reduce-without-index + eq. > @ + reduced. + list + * 1 2 3 4 + -1 + a.times x > [a x] + -24 + +# Test. Should print "0\n1\n" +[] > list-reduced-printing + reduced. > @ + list + * 0 1 + true + [acc item] + seq > @ + * + acc + stdout + sprintf + "%d\n" + * item + +# Test. +[] > complex-objects-list-comparison + list > res + * + list (* 0 1) + list (* 4 0) + list (* 7 3) + .eq > @ + * + * 0 1 + * 4 0 + * 7 3 + +# Test. +[] > list-mappedi-should-work + eq. > @ + mappedi. + list + * 1 2 3 4 + i.times x > [x i] + * 0 2 6 12 + +# Test. +[] > simple-list-mapping + eq. > @ + mapped. + list + * 1 2 3 + x.times 2 > [x] + * 2 4 6 + +# Test. +[] > iterates-with-eachi + list + * + "one" + "two" + "three" + .eachi > @ + [item index] + stdout > @ + sprintf + "[%d]: %s\n" + * index item + +# Test. +[] > iterates-with-each + list + * + "one" + "two" + "three" + .each > @ + stdout i > [i] + +# Test. +[] > list-withouti + eq. > @ + withouti. + list + * 1 2 3 + 1 + * 1 3 + +# Test. +[] > list-withouti-complex-case + [a] > foo + withouti. > @ + list a + 0 + eq. > @ + foo + * 1 "text" "f" + * "text" "f" + +# Test. +[] > list-withouti-nested-array + * 3 2 1 > nested + eq. > @ + withouti. + list + * "smthg" 27 nested + 2 + * "smthg" 27 + +# Test. +[] > list-without + eq. > @ + without. + list + * 1 2 1 2 1 5 + 2 + * 1 1 1 5 + +# Test. +[] > equality-test + eq. > @ + list + * 1 2 3 + * 1 2 3 + +# Test. +[] > not-equality-test + not. > @ + eq. + list + * 1 2 3 + * 3 2 1 + +# Test. +[] > concatenates-lists + list (* 0 1) > list1 + list (* 2 3) > list2 + withouti. > list3 + concat. + list1 + list2 + 0 + and. > @ + eq. + 1 + list3.at 0 + eq. + list3 + * 1 2 3 + +# Test. +[] > concatenates-with-tuple + eq. > @ + concat. + list + * 0 1 + * 2 4 + * 0 1 2 4 + +# Test. +[] > returns-index-of + eq. > @ + 1 + index-of. + list + * 1 2 3 + 2 + +# Test. +[] > returns-first-index-of-element + eq. > @ + 0 + index-of. + list + * -1 2 -1 + -1 + +# Test. +[] > does-not-find-index-of + eq. > @ + -1 + index-of. + list + * "qwerty" 2 3 + 7 + +# Test. +[] > finds-index-of-string + eq. > @ + 1 + index-of. + list + * "asdfgh" "qwerty" 3 + "qwerty" + +# Test. +[] > finds-last-index-of + eq. > @ + 1 + last-index-of. + list + * "qwerty" 2 3 + 2 + +# Test. +[] > finds-last-index-of-repeated + eq. > @ + 2 + last-index-of. + list + * 24 42 24 + 24 + +# Test. +[] > last-index-of-not-found + eq. > @ + -1 + last-index-of. + list + * 1 2 3 + 0 + +# Test. +[] > last-index-of-empty + eq. > @ + -1 + last-index-of. + list * + "abc" + +# Test. +[] > last-index-of-unicode + eq. > @ + 3 + last-index-of. + list + * "Hi" "Привет" "Hola" "Привет" "こんにちわ" + "Привет" + +# Test. +[] > list-contains-string + contains. > @ + list + * "qwerty" "asdfgh" 3 "qwerty" + "qwerty" + +# Test. +[] > list-contains-number + contains. > @ + list + * "qwerty" "asdfgh" 3 "qwerty" + 3 + +# Test. +[] > list-does-not-contain + not. > @ + contains. + list + * "Привет" "asdfgh" 3 "qwerty" + "Hi" + +# Test. +[] > filteredi-with-lt + eq. > @ + filteredi. + list + * 3 1 4 2 5 + v.lt 3 > [v i] + * 1 2 + +# Test. +[] > filteredi-with-string-length + eq. > @ + filteredi. + list + * "Hello" "Name" "EO" "List" + v.length.gt 4 > [v i] + * "Hello" + +# Test. +[] > filteredi-with-empty-list + is-empty. > @ + filteredi. + list + * + v.lt 3 > [v i] + +# Test. +[] > filteredi-by-index + eq. > @ + filteredi. + list + * 3 1 4 + i.gt 0 > [v i] + * 1 4 + +# Test. +[] > filteredi-with-bools + eq. > @ + filteredi. + list + * true false true + v.not > [v i] + * false + +# Test. +[] > simple-filtered + eq. > @ + filtered. + list + * 3 1 4 2 5 + v.gt 2 > [v] + * 3 4 5 + +# Test. +[] > filtered-with-bools + eq. > @ + filtered. + list + * true false true + v.not > [v] + * false + +# Test. +[] > simple-head + eq. > @ + head. + list + * 1 2 3 4 5 + 1 + * 1 + +# Test. +[] > list-head-with-zero-index + is-empty. > @ + head. + list + * 1 2 3 + 0 + +# Test. +[] > list-head-with-length-index + eq. > @ + head. + list + * 1 2 3 + 3 + * 1 2 3 + +# Test. +[] > complex-head + eq. > @ + head. + list + * "foo" 2.2 00-01 "bar" + 2 + * "foo" 2.2 + +# Test. +[] > head-with-negative + eq. > @ + head. + list + * 1 2 3 + -1 + * 3 + +# Test. +[] > complex-head-with-negative + eq. > @ + head. + list + * "foo" 2.2 00-01 "bar" + -3 + * 2.2 00-01 "bar" + +# Test. +[] > simple-tail + eq. > @ + tail. + list + * 1 2 3 4 5 + 2 + * 4 5 + +# Test. +[] > zero-index-in-tail + is-empty. > @ + tail. + list + * 1 2 3 4 5 + 0 + +# Test. +[] > large-index-in-tail + eq. > @ + tail. + list + * 1 2 3 4 5 + 10 + * 1 2 3 4 5 diff --git a/eo-runtime/src/test/eo/org/eolang/txt/sprintf-tests.eo b/eo-runtime/src/test/eo/org/eolang/txt/sprintf-tests.eo new file mode 100644 index 0000000000..49f67de154 --- /dev/null +++ b/eo-runtime/src/test/eo/org/eolang/txt/sprintf-tests.eo @@ -0,0 +1,52 @@ +# The MIT License (MIT) +# +# Copyright (c) 2016-2024 Objectionary.com +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + ++alias org.eolang.txt.sprintf ++architect yegor256@gmail.com ++home https://github.com/objectionary/eo ++tests ++package org.eolang.txt ++version 0.0.0 + +# Test. +[] > prints-simple-string + eq. > @ + "Hello, Jeffrey!" + sprintf + "Hello, %s!" + * "Jeffrey" + +# Test. +[] > prints-complex-string + eq. > @ + "Привет 3.140000 Jeff X!" + sprintf + "Привет %f %s %s!" + * 3.14 "Jeff" "X" + +# Test. +[] > prints-bytes-string + eq. > @ + "00-00-00-00-00-00-00-2A" + sprintf + "%x" + * 42.as-bytes diff --git a/eo-runtime/src/test/java/EOorg/EOeolang/EOio/package-info.java b/eo-runtime/src/test/java/EOorg/EOeolang/EOio/package-info.java index 451d3d96fc..d7b51ecb64 100644 --- a/eo-runtime/src/test/java/EOorg/EOeolang/EOio/package-info.java +++ b/eo-runtime/src/test/java/EOorg/EOeolang/EOio/package-info.java @@ -27,7 +27,7 @@ */ /** - * EO runtime, tests. + * EO-io, tests. * * @since 0.1 */ diff --git a/eo-runtime/src/test/java/EOorg/EOeolang/EOtxt/EOsprintfTest.java b/eo-runtime/src/test/java/EOorg/EOeolang/EOtxt/EOsprintfTest.java new file mode 100644 index 0000000000..0726260df4 --- /dev/null +++ b/eo-runtime/src/test/java/EOorg/EOeolang/EOtxt/EOsprintfTest.java @@ -0,0 +1,122 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2016-2024 Objectionary.com + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* + * @checkstyle PackageNameCheck (10 lines) + */ +package EOorg.EOeolang.EOtxt; + +import EOorg.EOeolang.EOerror; +import java.nio.charset.StandardCharsets; +import org.eolang.Data; +import org.eolang.Dataized; +import org.eolang.Phi; +import org.hamcrest.MatcherAssert; +import org.hamcrest.Matchers; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +/** + * Test case for {@link EOsprintf}. + * + * @since 0.39 + * @checkstyle TypeNameCheck (4 lines) + */ +final class EOsprintfTest { + @Test + void returnsValidFormattedString() { + final Phi sprintf = new EOsprintf(); + sprintf.put(0, new Data.ToPhi("string %s, bytes %x, float %f, int %d, bool %b")); + sprintf.put( + 1, + new Data.ToPhi( + new Phi[] { + new Data.ToPhi("Jeff"), + new Data.ToPhi("Jeff".getBytes(StandardCharsets.UTF_8)), + new Data.ToPhi(42.3), + new Data.ToPhi(14L), + new Data.ToPhi(false), + } + ) + ); + MatcherAssert.assertThat( + "All types should be formatted successfully", + new Dataized(sprintf).take(String.class), + Matchers.equalTo( + "string Jeff, bytes 4A-65-66-66, float 42.300000, int 14, bool false" + ) + ); + } + + @Test + void failsIfAmountOfArgumentsDoesNotMatch() { + final Phi sprintf = new EOsprintf(); + sprintf.put(0, new Data.ToPhi("%s%s")); + sprintf.put(1, new Data.ToPhi(new Phi[] {new Data.ToPhi("Hey")})); + final Throwable exception = Assertions.assertThrows( + EOerror.ExError.class, + () -> new Dataized(sprintf).take(), + "Dataization of sprintf should fail if formats < arguments" + ); + MatcherAssert.assertThat( + "The exception message should contain an info about arguments and format occurrences amount", + exception.getMessage(), + Matchers.containsString( + "The amount of arguments 1 does not match the amount of format occurrences 2" + ) + ); + } + + @Test + void doesNotFailIfArgumentsMoreThanFormats() { + final Phi sprintf = new EOsprintf(); + sprintf.put(0, new Data.ToPhi("%s")); + sprintf.put( + 1, + new Data.ToPhi( + new Phi[] { + new Data.ToPhi("Hey"), + new Data.ToPhi("Hey"), + } + ) + ); + MatcherAssert.assertThat( + "The second argument should be ignored", + new Dataized(sprintf).take(String.class), + Matchers.equalTo("Hey") + ); + } + + @Test + void failsOnUnsupportedFormat() { + final Phi sprintf = new EOsprintf(); + sprintf.put(0, new Data.ToPhi("%o")); + sprintf.put(1, Phi.Φ.take("org.eolang.tuple").take("empty")); + Assertions.assertThrows( + EOerror.ExError.class, + () -> new Dataized(sprintf).take(), + "Sprintf dataization should fail because of unsupported format %o" + ); + } +} diff --git a/eo-runtime/src/test/java/EOorg/EOeolang/EOtxt/package-info.java b/eo-runtime/src/test/java/EOorg/EOeolang/EOtxt/package-info.java new file mode 100644 index 0000000000..c4232f8a7d --- /dev/null +++ b/eo-runtime/src/test/java/EOorg/EOeolang/EOtxt/package-info.java @@ -0,0 +1,34 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2016-2024 Objectionary.com + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* + * @checkstyle PackageNameCheck (20 lines) + */ + +/** + * EO-txt, tests. + * + * @since 0.39 + */ +package EOorg.EOeolang.EOtxt;