├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md └── workflows │ └── validation.yml ├── .gitignore ├── code_of_conduct.md ├── contributing.md ├── license ├── readme.md ├── src ├── tasks │ ├── StreamTasks.java │ ├── StreamTasksExample.java │ ├── StreamTasksMain.java │ ├── package-info.java │ ├── solution │ │ ├── StreamTasksSolution.java │ │ └── package-info.java │ └── utils │ │ ├── Box.java │ │ ├── Item.java │ │ ├── Parcel.java │ │ └── package-info.java └── tests │ ├── InvocationResult.java │ ├── OutputAssertions.java │ ├── StreamTasksTests.java │ ├── TaskTests.java │ ├── TestInputGenerator.java │ ├── TestInvokerGenerator.java │ ├── TestVerdict.java │ ├── TestsPool.java │ ├── TestsRunner.java │ ├── inputs │ ├── ConstantValueProvider.java │ ├── ConsumerGenerator.java │ ├── ConsumerMode.java │ ├── SequenceWithStatistics.java │ ├── SupplierMode.java │ └── package-info.java │ ├── package-info.java │ ├── presets │ ├── Boxes.java │ ├── DataMappingPreset.java │ ├── DataPreset.java │ ├── HexStrNumbers.java │ ├── IntNumbers.java │ ├── IntStrNumbers.java │ ├── Items.java │ ├── Names.java │ └── package-info.java │ └── utils │ ├── F3.java │ ├── F4.java │ ├── F5.java │ ├── Pair.java │ ├── Test.java │ ├── TestInputCollection.java │ ├── TestInputConstant.java │ ├── TestInputConsumer.java │ ├── TestInputFunction.java │ ├── TestInputPredicate.java │ ├── TestInputSupplier.java │ ├── TestResult.java │ └── package-info.java ├── test.cmd └── test.sh /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: bug 6 | assignees: Shemplo 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **Expected behavior** 14 | A clear and concise description of what you expected to happen. 15 | 16 | **Screenshots** 17 | If applicable, add screenshots to help explain your problem. 18 | 19 | **Desktop (please complete the following information):** 20 | - OS: [e.g. Windows, iOS] 21 | - Other useful information aboul your platform 22 | 23 | **Additional context** 24 | Add any other context about the problem here. 25 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: enhancement 6 | assignees: Shemplo 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/workflows/validation.yml: -------------------------------------------------------------------------------- 1 | name: Solution validation 2 | 3 | on: 4 | push: 5 | branches: [ main ] 6 | pull_request: 7 | branches: [ main ] 8 | 9 | jobs: 10 | build: 11 | runs-on: ubuntu-latest 12 | 13 | steps: 14 | - uses: actions/checkout@v2 15 | - name: Set up JDK 11 16 | uses: actions/setup-java@v1 17 | with: 18 | java-version: 11 19 | - name: Run tests 20 | run: javac -sourcepath src -d bin src/tasks/StreamTasksMain.java && java -ea -cp bin tasks.StreamTasksMain validate 21 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /.settings/ 2 | /build/ 3 | /bin/ 4 | 5 | .classpath 6 | .project -------------------------------------------------------------------------------- /code_of_conduct.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, sex characteristics, gender identity and expression, 9 | level of experience, education, socio-economic status, nationality, personal 10 | appearance, race, religion, or sexual identity and orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | * Using welcoming and inclusive language 18 | * Being respectful of differing viewpoints and experiences 19 | * Gracefully accepting constructive criticism 20 | * Focusing on what is best for the community 21 | * Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | * The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | * Trolling, insulting/derogatory comments, and personal or political attacks 28 | * Public or private harassment 29 | * Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | * Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team at shemplo@outlook.com. All 59 | complaints will be reviewed and investigated and will result in a response that 60 | is deemed necessary and appropriate to the circumstances. The project team is 61 | obligated to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html 72 | 73 | [homepage]: https://www.contributor-covenant.org 74 | 75 | For answers to common questions about this code of conduct, see 76 | https://www.contributor-covenant.org/faq 77 | -------------------------------------------------------------------------------- /contributing.md: -------------------------------------------------------------------------------- 1 | **Everybody is welcome to contribute** 2 | 3 | Key statements: 4 | * Applying changes should be related to the main goal of this repository - education 5 | * All applying changes should be accepted by code owners 6 | * Be polite, do not swear 7 | -------------------------------------------------------------------------------- /license: -------------------------------------------------------------------------------- 1 | Eclipse Public License - v 2.0 2 | 3 | THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE 4 | PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION 5 | OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. 6 | 7 | 1. DEFINITIONS 8 | 9 | "Contribution" means: 10 | 11 | a) in the case of the initial Contributor, the initial content 12 | Distributed under this Agreement, and 13 | 14 | b) in the case of each subsequent Contributor: 15 | i) changes to the Program, and 16 | ii) additions to the Program; 17 | where such changes and/or additions to the Program originate from 18 | and are Distributed by that particular Contributor. A Contribution 19 | "originates" from a Contributor if it was added to the Program by 20 | such Contributor itself or anyone acting on such Contributor's behalf. 21 | Contributions do not include changes or additions to the Program that 22 | are not Modified Works. 23 | 24 | "Contributor" means any person or entity that Distributes the Program. 25 | 26 | "Licensed Patents" mean patent claims licensable by a Contributor which 27 | are necessarily infringed by the use or sale of its Contribution alone 28 | or when combined with the Program. 29 | 30 | "Program" means the Contributions Distributed in accordance with this 31 | Agreement. 32 | 33 | "Recipient" means anyone who receives the Program under this Agreement 34 | or any Secondary License (as applicable), including Contributors. 35 | 36 | "Derivative Works" shall mean any work, whether in Source Code or other 37 | form, that is based on (or derived from) the Program and for which the 38 | editorial revisions, annotations, elaborations, or other modifications 39 | represent, as a whole, an original work of authorship. 40 | 41 | "Modified Works" shall mean any work in Source Code or other form that 42 | results from an addition to, deletion from, or modification of the 43 | contents of the Program, including, for purposes of clarity any new file 44 | in Source Code form that contains any contents of the Program. Modified 45 | Works shall not include works that contain only declarations, 46 | interfaces, types, classes, structures, or files of the Program solely 47 | in each case in order to link to, bind by name, or subclass the Program 48 | or Modified Works thereof. 49 | 50 | "Distribute" means the acts of a) distributing or b) making available 51 | in any manner that enables the transfer of a copy. 52 | 53 | "Source Code" means the form of a Program preferred for making 54 | modifications, including but not limited to software source code, 55 | documentation source, and configuration files. 56 | 57 | "Secondary License" means either the GNU General Public License, 58 | Version 2.0, or any later versions of that license, including any 59 | exceptions or additional permissions as identified by the initial 60 | Contributor. 61 | 62 | 2. GRANT OF RIGHTS 63 | 64 | a) Subject to the terms of this Agreement, each Contributor hereby 65 | grants Recipient a non-exclusive, worldwide, royalty-free copyright 66 | license to reproduce, prepare Derivative Works of, publicly display, 67 | publicly perform, Distribute and sublicense the Contribution of such 68 | Contributor, if any, and such Derivative Works. 69 | 70 | b) Subject to the terms of this Agreement, each Contributor hereby 71 | grants Recipient a non-exclusive, worldwide, royalty-free patent 72 | license under Licensed Patents to make, use, sell, offer to sell, 73 | import and otherwise transfer the Contribution of such Contributor, 74 | if any, in Source Code or other form. This patent license shall 75 | apply to the combination of the Contribution and the Program if, at 76 | the time the Contribution is added by the Contributor, such addition 77 | of the Contribution causes such combination to be covered by the 78 | Licensed Patents. The patent license shall not apply to any other 79 | combinations which include the Contribution. No hardware per se is 80 | licensed hereunder. 81 | 82 | c) Recipient understands that although each Contributor grants the 83 | licenses to its Contributions set forth herein, no assurances are 84 | provided by any Contributor that the Program does not infringe the 85 | patent or other intellectual property rights of any other entity. 86 | Each Contributor disclaims any liability to Recipient for claims 87 | brought by any other entity based on infringement of intellectual 88 | property rights or otherwise. As a condition to exercising the 89 | rights and licenses granted hereunder, each Recipient hereby 90 | assumes sole responsibility to secure any other intellectual 91 | property rights needed, if any. For example, if a third party 92 | patent license is required to allow Recipient to Distribute the 93 | Program, it is Recipient's responsibility to acquire that license 94 | before distributing the Program. 95 | 96 | d) Each Contributor represents that to its knowledge it has 97 | sufficient copyright rights in its Contribution, if any, to grant 98 | the copyright license set forth in this Agreement. 99 | 100 | e) Notwithstanding the terms of any Secondary License, no 101 | Contributor makes additional grants to any Recipient (other than 102 | those set forth in this Agreement) as a result of such Recipient's 103 | receipt of the Program under the terms of a Secondary License 104 | (if permitted under the terms of Section 3). 105 | 106 | 3. REQUIREMENTS 107 | 108 | 3.1 If a Contributor Distributes the Program in any form, then: 109 | 110 | a) the Program must also be made available as Source Code, in 111 | accordance with section 3.2, and the Contributor must accompany 112 | the Program with a statement that the Source Code for the Program 113 | is available under this Agreement, and informs Recipients how to 114 | obtain it in a reasonable manner on or through a medium customarily 115 | used for software exchange; and 116 | 117 | b) the Contributor may Distribute the Program under a license 118 | different than this Agreement, provided that such license: 119 | i) effectively disclaims on behalf of all other Contributors all 120 | warranties and conditions, express and implied, including 121 | warranties or conditions of title and non-infringement, and 122 | implied warranties or conditions of merchantability and fitness 123 | for a particular purpose; 124 | 125 | ii) effectively excludes on behalf of all other Contributors all 126 | liability for damages, including direct, indirect, special, 127 | incidental and consequential damages, such as lost profits; 128 | 129 | iii) does not attempt to limit or alter the recipients' rights 130 | in the Source Code under section 3.2; and 131 | 132 | iv) requires any subsequent distribution of the Program by any 133 | party to be under a license that satisfies the requirements 134 | of this section 3. 135 | 136 | 3.2 When the Program is Distributed as Source Code: 137 | 138 | a) it must be made available under this Agreement, or if the 139 | Program (i) is combined with other material in a separate file or 140 | files made available under a Secondary License, and (ii) the initial 141 | Contributor attached to the Source Code the notice described in 142 | Exhibit A of this Agreement, then the Program may be made available 143 | under the terms of such Secondary Licenses, and 144 | 145 | b) a copy of this Agreement must be included with each copy of 146 | the Program. 147 | 148 | 3.3 Contributors may not remove or alter any copyright, patent, 149 | trademark, attribution notices, disclaimers of warranty, or limitations 150 | of liability ("notices") contained within the Program from any copy of 151 | the Program which they Distribute, provided that Contributors may add 152 | their own appropriate notices. 153 | 154 | 4. COMMERCIAL DISTRIBUTION 155 | 156 | Commercial distributors of software may accept certain responsibilities 157 | with respect to end users, business partners and the like. While this 158 | license is intended to facilitate the commercial use of the Program, 159 | the Contributor who includes the Program in a commercial product 160 | offering should do so in a manner which does not create potential 161 | liability for other Contributors. Therefore, if a Contributor includes 162 | the Program in a commercial product offering, such Contributor 163 | ("Commercial Contributor") hereby agrees to defend and indemnify every 164 | other Contributor ("Indemnified Contributor") against any losses, 165 | damages and costs (collectively "Losses") arising from claims, lawsuits 166 | and other legal actions brought by a third party against the Indemnified 167 | Contributor to the extent caused by the acts or omissions of such 168 | Commercial Contributor in connection with its distribution of the Program 169 | in a commercial product offering. The obligations in this section do not 170 | apply to any claims or Losses relating to any actual or alleged 171 | intellectual property infringement. In order to qualify, an Indemnified 172 | Contributor must: a) promptly notify the Commercial Contributor in 173 | writing of such claim, and b) allow the Commercial Contributor to control, 174 | and cooperate with the Commercial Contributor in, the defense and any 175 | related settlement negotiations. The Indemnified Contributor may 176 | participate in any such claim at its own expense. 177 | 178 | For example, a Contributor might include the Program in a commercial 179 | product offering, Product X. That Contributor is then a Commercial 180 | Contributor. If that Commercial Contributor then makes performance 181 | claims, or offers warranties related to Product X, those performance 182 | claims and warranties are such Commercial Contributor's responsibility 183 | alone. Under this section, the Commercial Contributor would have to 184 | defend claims against the other Contributors related to those performance 185 | claims and warranties, and if a court requires any other Contributor to 186 | pay any damages as a result, the Commercial Contributor must pay 187 | those damages. 188 | 189 | 5. NO WARRANTY 190 | 191 | EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT 192 | PERMITTED BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN "AS IS" 193 | BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR 194 | IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF 195 | TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR 196 | PURPOSE. Each Recipient is solely responsible for determining the 197 | appropriateness of using and distributing the Program and assumes all 198 | risks associated with its exercise of rights under this Agreement, 199 | including but not limited to the risks and costs of program errors, 200 | compliance with applicable laws, damage to or loss of data, programs 201 | or equipment, and unavailability or interruption of operations. 202 | 203 | 6. DISCLAIMER OF LIABILITY 204 | 205 | EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT 206 | PERMITTED BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS 207 | SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 208 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST 209 | PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 210 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 211 | ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE 212 | EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE 213 | POSSIBILITY OF SUCH DAMAGES. 214 | 215 | 7. GENERAL 216 | 217 | If any provision of this Agreement is invalid or unenforceable under 218 | applicable law, it shall not affect the validity or enforceability of 219 | the remainder of the terms of this Agreement, and without further 220 | action by the parties hereto, such provision shall be reformed to the 221 | minimum extent necessary to make such provision valid and enforceable. 222 | 223 | If Recipient institutes patent litigation against any entity 224 | (including a cross-claim or counterclaim in a lawsuit) alleging that the 225 | Program itself (excluding combinations of the Program with other software 226 | or hardware) infringes such Recipient's patent(s), then such Recipient's 227 | rights granted under Section 2(b) shall terminate as of the date such 228 | litigation is filed. 229 | 230 | All Recipient's rights under this Agreement shall terminate if it 231 | fails to comply with any of the material terms or conditions of this 232 | Agreement and does not cure such failure in a reasonable period of 233 | time after becoming aware of such noncompliance. If all Recipient's 234 | rights under this Agreement terminate, Recipient agrees to cease use 235 | and distribution of the Program as soon as reasonably practicable. 236 | However, Recipient's obligations under this Agreement and any licenses 237 | granted by Recipient relating to the Program shall continue and survive. 238 | 239 | Everyone is permitted to copy and distribute copies of this Agreement, 240 | but in order to avoid inconsistency the Agreement is copyrighted and 241 | may only be modified in the following manner. The Agreement Steward 242 | reserves the right to publish new versions (including revisions) of 243 | this Agreement from time to time. No one other than the Agreement 244 | Steward has the right to modify this Agreement. The Eclipse Foundation 245 | is the initial Agreement Steward. The Eclipse Foundation may assign the 246 | responsibility to serve as the Agreement Steward to a suitable separate 247 | entity. Each new version of the Agreement will be given a distinguishing 248 | version number. The Program (including Contributions) may always be 249 | Distributed subject to the version of the Agreement under which it was 250 | received. In addition, after a new version of the Agreement is published, 251 | Contributor may elect to Distribute the Program (including its 252 | Contributions) under the new version. 253 | 254 | Except as expressly stated in Sections 2(a) and 2(b) above, Recipient 255 | receives no rights or licenses to the intellectual property of any 256 | Contributor under this Agreement, whether expressly, by implication, 257 | estoppel or otherwise. All rights in the Program not expressly granted 258 | under this Agreement are reserved. Nothing in this Agreement is intended 259 | to be enforceable by any entity that is not a Contributor or Recipient. 260 | No third-party beneficiary rights are created under this Agreement. 261 | 262 | Exhibit A - Form of Secondary Licenses Notice 263 | 264 | "This Source Code may also be made available under the following 265 | Secondary Licenses when the conditions for such availability set forth 266 | in the Eclipse Public License, v. 2.0 are satisfied: {name license(s), 267 | version(s), and exceptions or additional permissions here}." 268 | 269 | Simply including a copy of this Agreement, including this Exhibit A 270 | is not sufficient to license the Source Code under Secondary Licenses. 271 | 272 | If it is not possible or desirable to put the notice in a particular 273 | file, then You may include the notice in a location (such as a LICENSE 274 | file in a relevant directory) where a recipient would be likely to 275 | look for such a notice. 276 | 277 | You may add additional accurate notices of copyright ownership. 278 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | ## Java Streams Etudes 2 | 3 | [![Language](https://img.shields.io/badge/language-java-red.svg)](https://github.com/Shemplo/Java-Streams-Etudes/blob/master/) 4 | [![GitHub license](https://img.shields.io/github/license/Shemplo/Java-Streams-Etudes.svg)](https://github.com/Shemplo/Java-Streams-Etudes/blob/master/LICENSE) 5 | [![GitHub stars](https://img.shields.io/github/stars/Shemplo/Java-Streams-Etudes.svg)](https://github.com/Shemplo/Java-Streams-Etudes/stargazers) 6 | 7 | Do you know how to use Java Stream API? 8 | 9 | * If **NO** but you are interested in it then you can use this project as a roadmap of things to learn 10 | * If **YES** then you can have a practice here to check your skills 11 | 12 | Apply you knowledge of _streams_, _lambdas_, _method handlers_ and other functional Java things. 13 | 14 | There are also some tasks that will make think even experienced programmers. Try to solve them all. 15 | 16 | > **25** tasks are available now 17 | 18 | ### What to do 19 | 20 | > Clone repository → implement methods → run tests → fix mistakes 21 | 22 | Methods to implement are placed in class `tasks.StreamTasks` in `src` folder. 23 | Initially they are stubbed with standard `UnsupportedOperationException` (and tests know about that). 24 | You need to replace such lines with solution consists of stream flow or something related to it 25 | (description and hints for each task are provided). 26 | 27 | It's **prohibited** to use standard cycles (`for`, `while`, `do-while`, recursion) at all and 28 | conditions (`if`, `if-else`, ...) out of stream operations. The main goal of this project is to 29 | teach you how to use functional approach in practice. One **possible exclusion** from pure functional 30 | paradigm is declaring and usage of local variables. 31 | 32 | ### Running tests 33 | 34 | Due to this project is orientated to beginners **no dependent libraries** are required. 35 | If you know how to add dependencies and really know for what then you can do it manually 36 | (but, be pointed, all tasks can be solved using only standard Java library). 37 | 38 | > Main requirement is **JVM of 11 version (or higher)** 39 | 40 | Run main method from `tasks.StreamTasksMain` class in your preferred IDE or run a script file `test.(cmd|sh)`. 41 | 42 | Flag `-ea` is required to enable `assert` key word for tests checker. Otherwise all tests will not be run properly. 43 | 44 | #### Check program and verdicts 45 | 46 | Check program will run tests for all tasks and then write verdict for each of tasks. 47 | 48 | Possible verdicts: 49 | 50 | * **accepted** - you solved this task 51 | * **wrong answer** - you almost solved this task (code compiles but logic is wrong) 52 | * **not implemented** - you didn't start to implement this task 53 | * **missed NULL check** - you forgot to check something for `null` reference 54 | * **runtime exception** - something goes extremely bad 55 | 56 | Until you solved all tasks with verdict `accepted` the program will finish with non-zero exit code. 57 | 58 | ##### Examples 59 | 60 | You can run check program with argument `example`. 61 | For that add `example` word to passing arguments in IDE or to the end of running scripts: 62 | `test.cmd example` (for Windows) and `./test.sh example` (for Unix) 63 | 64 | There are some implemented tasks in class `tasks.StreamTasksExample`, so they would be tested in `example` mode. 65 | 66 | > Not guaranteed that implementation is correct or in optimal way ;) 67 | 68 | #### Solutions 69 | 70 | In case you don't know how to solve some task than you can see solution in `tasks.solution.StreamTasksSolution` 71 | class in `src` folder. This class is used as reference solution to check answers, so you can copy-paste code to the 72 | task and this task will be accepted. 73 | 74 | Try to avoid any interaction with solutions until you completed all tasks :) 75 | 76 | #### Challenges 77 | 78 | You can also use tasks from this project for different challenges. 79 | For example, you can check how many tasks you can do in **limited time** 80 | or how much time you will need to **solve them all**, etc. 81 | 82 | ##### Good luck, have fun progress! 83 | 84 |
85 | 86 | Version 0.1.0 is available [here](https://github.com/Shemplo/Java-Streams-Etudes/tree/7206e9138a3c2ae0347d983696dfaf56002485a0) 87 | 88 | * The first draft of this project 89 | * It has different 60 tasks 90 | 91 |
92 | 93 | Future plans: 94 | 95 | * `[ ]` Rise number of tasks to 100 96 | * `[~]` Add more input generators to test engine 97 | * `[✓]` For `Map ` type 98 | * `[✓]` For `List >` type (and any enclosure level) 99 | * `[ ]` Else 100 | * `[ ]` Add more input variations to test engine (f.e. collection as extension of another parameter that is collection too) 101 | * `[~]` Сome up with some new task ideas 102 | * `[ ]` Split tasks to several classes by topics 103 | -------------------------------------------------------------------------------- /src/tasks/StreamTasks.java: -------------------------------------------------------------------------------- 1 | package tasks; 2 | import java.util.Collection; 3 | import java.util.List; 4 | import java.util.Set; 5 | import java.util.function.Function; 6 | import java.util.function.IntFunction; 7 | import java.util.function.IntPredicate; 8 | import java.util.function.IntUnaryOperator; 9 | import java.util.function.Predicate; 10 | import java.util.stream.IntStream; 11 | import java.util.stream.Stream; 12 | 13 | import tests.StreamTasksTests; 14 | 15 | public class StreamTasks extends StreamTasksTests { 16 | 17 | // INTRODUCTION // 18 | 19 | /** 20 | * @return List of given constants [a, b + c - a, c] 21 | * @see List#of() 22 | * @lines 1 23 | */ 24 | public List task1 (int a, int b, int c) { 25 | throw new UnsupportedOperationException ("Implement method instead of this line"); 26 | } 27 | 28 | /** 29 | * @return Set of given constants [a, b, c] 30 | * @see Set#of() 31 | * @lines 1 32 | */ 33 | public Set task2 (int a, int b, int c) { 34 | throw new UnsupportedOperationException ("Implement method instead of this line"); 35 | } 36 | 37 | /** 38 | * @return Set of values from given list 39 | * @see Set#copyOf(Collection) 40 | * @lines 1 41 | */ 42 | public Set task3 (List values) { 43 | throw new UnsupportedOperationException ("Implement method instead of this line"); 44 | } 45 | 46 | /** 47 | * @return Stream of values from given list 48 | * @see Collection#stream() 49 | * @lines 1 50 | */ 51 | public Stream task4 (List values) { 52 | throw new UnsupportedOperationException ("Implement method instead of this line"); 53 | } 54 | 55 | /** 56 | * @return Stream of values from given set 57 | * @see Collection#stream() 58 | * @lines 1 59 | */ 60 | public Stream task5 (Set values) { 61 | throw new UnsupportedOperationException ("Implement method instead of this line"); 62 | } 63 | 64 | /** 65 | * @return Number of elements in the stream 66 | * @see Stream#count() 67 | * @lines 1 68 | */ 69 | public int task6 (Stream values) { 70 | throw new UnsupportedOperationException ("Implement method instead of this line"); 71 | } 72 | 73 | /** 74 | * @return Given stream that is limited by size 75 | * @see Stream#limit(long) 76 | * @lines 1 77 | */ 78 | public Stream task7 (Stream values, int limit) { 79 | throw new UnsupportedOperationException ("Implement method instead of this line"); 80 | } 81 | 82 | /** 83 | * @return Stream that contains last `n` elements of sequence with general `size` size from given stream 84 | * @example input: [A, B, C, D, E, F, G, H, I, ...], 3, 7 -> output: [E, F, G] 85 | * @see Stream#skip(long) 86 | * @lines 1 87 | */ 88 | public Stream task8 (Stream values, int n, int size) { 89 | throw new UnsupportedOperationException ("Implement method instead of this line"); 90 | } 91 | 92 | /** 93 | * @return Stream that contains all values from given streams 94 | * @see Stream#concat(Stream, Stream) 95 | * @lines 1 96 | */ 97 | public Stream task9 (Stream values1, Stream values2) { 98 | throw new UnsupportedOperationException ("Implement method instead of this line"); 99 | } 100 | 101 | /** 102 | * @return Stream that contains all values from given streams 103 | * @lines 1 104 | */ 105 | public Stream task10 (Stream values1, Stream values2, Stream values3) { 106 | throw new UnsupportedOperationException ("Implement method instead of this line"); 107 | } 108 | 109 | // FIRST FLOWS // 110 | 111 | /** 112 | * @return Stream that contains only values accepted by predicate (condition) 113 | * @see Stream#filter(Predicate) 114 | * @lines 1 115 | */ 116 | public Stream task11 (Stream numbers, Predicate condition) { 117 | throw new UnsupportedOperationException ("Implement method instead of this line"); 118 | } 119 | 120 | /** 121 | * @return Predicate that will accept numbers in segment [from, to] 122 | * @lines 1 123 | */ 124 | public Predicate task12 (int from, int to) { 125 | throw new UnsupportedOperationException ("Implement method instead of this line"); 126 | } 127 | 128 | /** 129 | * @return Predicate that combine two: `positive` as well and negation of `negative` 130 | * @see Predicate#and(Predicate) 131 | * @see Predicate#negate() 132 | * @lines 1 133 | */ 134 | public Predicate task13 (Predicate positive, Predicate negative) { 135 | throw new UnsupportedOperationException ("Implement method instead of this line"); 136 | } 137 | 138 | /** 139 | * @return Stream that contains converted values by `converter` 140 | * @see Stream#map(Function) 141 | * @lines 1 142 | */ 143 | public Stream task14 (Stream numbers, Function converter) { 144 | throw new UnsupportedOperationException ("Implement method instead of this line"); 145 | } 146 | 147 | /** 148 | * @return Function that convert each element (x) to expression: k * x + b 149 | * @lines 1 150 | */ 151 | public Function task15 (int k, int b) { 152 | throw new UnsupportedOperationException ("Implement method instead of this line"); 153 | } 154 | 155 | /** 156 | * @return Function that convert each element (x) to expression: g (f (x) + 1) 157 | * @see Function#compose(Function) 158 | * @lines 1 159 | */ 160 | public Function task16 (Function f, Function g) { 161 | throw new UnsupportedOperationException ("Implement method instead of this line"); 162 | } 163 | 164 | /** 165 | * @return Stream of parsed integer numbers from its' string representation 166 | * @see Integer#parseInt(String) 167 | * @lines 1 168 | */ 169 | public Stream task17 (Stream numbers) { 170 | throw new UnsupportedOperationException ("Implement method instead of this line"); 171 | } 172 | 173 | /** 174 | * @return Stream of parsed hex integer numbers from its' string representation 175 | * @hint Hex numbers starts from '0x', don't forget to remove this prefix 176 | * @see Integer#parseInt(String, int) 177 | * @lines 1 178 | */ 179 | public Stream task18 (Stream numbers) { 180 | throw new UnsupportedOperationException ("Implement method instead of this line"); 181 | } 182 | 183 | /** 184 | * @return Sorted stream (ascending) of unique numbers 185 | * @see Stream#distinct() 186 | * @see Stream#sorted() 187 | * @lines 1 188 | */ 189 | public Stream task19 (Stream numbers) { 190 | throw new UnsupportedOperationException ("Implement method instead of this line"); 191 | } 192 | 193 | /** 194 | * @return Sorted stream (ascending) of numbers whose square doesn't exceed `limit` (less or equal) 195 | * @lines 1 196 | */ 197 | public Stream task20 (Stream numbers, int limit) { 198 | throw new UnsupportedOperationException ("Implement method instead of this line"); 199 | } 200 | 201 | // INT STREAMS // 202 | 203 | /** 204 | * @return Stream of integers from segment [0, `to`] 205 | * @see IntStream#range(int, int) 206 | * @lines 1 207 | */ 208 | public IntStream task21 (int to) { 209 | throw new UnsupportedOperationException ("Implement method instead of this line"); 210 | } 211 | 212 | /** 213 | * @return Stream of integer numbers from given list with added index: `numbers` [i] + i 214 | * @see IntStream#map(IntUnaryOperator) 215 | * @lines 1 216 | */ 217 | public IntStream task22 (List numbers) { 218 | throw new UnsupportedOperationException ("Implement method instead of this line"); 219 | } 220 | 221 | /** 222 | * @return Stream of integer numbers on `offset` positions (0 position included) 223 | * @see IntStream#iterate(int, IntPredicate, IntUnaryOperator) 224 | * @example [0, 1, 2, 3, 4, 5, 6, 7, 8], 3 -> [0, 3, 6] 225 | * @lines 1 226 | */ 227 | public IntStream task23 (List numbers, int offset) { 228 | throw new UnsupportedOperationException ("Implement method instead of this line"); 229 | } 230 | 231 | /** 232 | * @return Infinite stream of integers (cycled on given `numbers`) 233 | * @see IntStream#iterate(int, IntUnaryOperator) 234 | * @see IntStream#mapToObj(IntFunction) 235 | * @see IntStream#boxed() 236 | * @example [0, 1, 2, 3, 4] -> [0, 1, 2, 3, 4, 0, 1, 2, 3, 4, 0, 1, 2, 3, ...] 237 | * @lines 1 238 | */ 239 | public Stream task24 (List numbers) { 240 | throw new UnsupportedOperationException ("Implement method instead of this line"); 241 | } 242 | 243 | /** 244 | * @return Stream of summed values on the same positions from given lists of numbers 245 | * (only positions that there are in both lists) 246 | * @example [0, 1, 2, 3, 4], [10, 12, 14] -> [10, 13, 16] 247 | * @lines 1 248 | */ 249 | public IntStream task25 (List numbers1, List numbers2) { 250 | throw new UnsupportedOperationException ("Implement method instead of this line"); 251 | } 252 | 253 | } 254 | -------------------------------------------------------------------------------- /src/tasks/StreamTasksExample.java: -------------------------------------------------------------------------------- 1 | package tasks; 2 | 3 | public class StreamTasksExample extends StreamTasks { 4 | 5 | } 6 | -------------------------------------------------------------------------------- /src/tasks/StreamTasksMain.java: -------------------------------------------------------------------------------- 1 | package tasks; 2 | import java.util.Locale; 3 | 4 | import tasks.solution.StreamTasksSolution; 5 | import tests.StreamTasksTests; 6 | import tests.TestsRunner; 7 | 8 | public class StreamTasksMain { 9 | 10 | /*******************************/ 11 | /* DO NOT TOUCH METHODS BELLOW */ 12 | /*******************************/ 13 | 14 | public static void main (String ... args) { 15 | Locale.setDefault (Locale.ENGLISH); 16 | 17 | try { 18 | assert false; 19 | System.out.println ("JVM flag `-ea` is not enabled"); 20 | System.exit (1); 21 | } catch (AssertionError ae) { 22 | // This is necessary to check whether -ea flag is set 23 | } 24 | 25 | StreamTasksTests implementation = null; 26 | if (args.length > 0 && "validate".equals (args [0])) { 27 | implementation = new StreamTasksSolution (); 28 | } else if (args.length > 0 && "example".equals (args [0])) { 29 | implementation = new StreamTasksExample (); 30 | } else { 31 | implementation = new StreamTasks (); 32 | } 33 | 34 | int exitCode = new TestsRunner (implementation, new StreamTasksSolution ()).test (); 35 | System.exit (exitCode); 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /src/tasks/package-info.java: -------------------------------------------------------------------------------- 1 | package tasks; 2 | -------------------------------------------------------------------------------- /src/tasks/solution/StreamTasksSolution.java: -------------------------------------------------------------------------------- 1 | package tasks.solution; 2 | import java.util.List; 3 | import java.util.Set; 4 | import java.util.function.Function; 5 | import java.util.function.Predicate; 6 | import java.util.stream.IntStream; 7 | import java.util.stream.Stream; 8 | 9 | import tests.StreamTasksTests; 10 | 11 | public class StreamTasksSolution extends StreamTasksTests { 12 | 13 | @Override 14 | public List task1 (int a, int b, int c) { 15 | return List.of (a, b + c - a, c); 16 | } 17 | 18 | @Override 19 | public Set task2 (int a, int b, int c) { 20 | return Set.copyOf (List.of (a, b, c)); 21 | } 22 | 23 | @Override 24 | public Set task3 (List values) { 25 | return Set.copyOf (values); 26 | } 27 | 28 | @Override 29 | public Stream task4 (List values) { 30 | return values.stream (); 31 | } 32 | 33 | @Override 34 | public Stream task5 (Set values) { 35 | return values.stream (); 36 | } 37 | 38 | @Override 39 | public int task6 (Stream values) { 40 | return (int) values.count (); 41 | } 42 | 43 | @Override 44 | public Stream task7 (Stream values, int limit) { 45 | return values.limit (limit); 46 | } 47 | 48 | @Override 49 | public Stream task8 (Stream values, int n, int size) { 50 | return values.skip (size - n).limit (n); 51 | } 52 | 53 | @Override 54 | public Stream task9 (Stream values1, Stream values2) { 55 | return Stream.concat (values1, values2); 56 | } 57 | 58 | @Override 59 | public Stream task10 (Stream values1, Stream values2, Stream values3) { 60 | return Stream.concat (Stream.concat (values1, values2), values3); 61 | } 62 | 63 | @Override 64 | public Stream task11 (Stream numbers, Predicate condition) { 65 | return numbers.filter (condition); 66 | } 67 | 68 | @Override 69 | public Predicate task12 (int from, int to) { 70 | return i -> i >= from && i <= to; 71 | } 72 | 73 | @Override 74 | public Predicate task13 (Predicate positive, Predicate negative) { 75 | return positive.and (negative.negate ()); 76 | } 77 | 78 | @Override 79 | public Stream task14 (Stream numbers, Function converter) { 80 | return numbers.map (converter); 81 | } 82 | 83 | @Override 84 | public Function task15 (int k, int b) { 85 | return x -> k * x + b; 86 | } 87 | 88 | @Override 89 | public Function task16 (Function f, Function g) { 90 | return g.compose (x -> f.apply (x) + 1); 91 | } 92 | 93 | @Override 94 | public Stream task17 (Stream numbers) { 95 | return numbers.map (Integer::parseInt); 96 | } 97 | 98 | @Override 99 | public Stream task18 (Stream numbers) { 100 | return numbers.map (num -> num.substring (2)).map (num -> Integer.parseInt (num, 16)); 101 | } 102 | 103 | @Override 104 | public Stream task19 (Stream numbers) { 105 | return numbers.distinct ().sorted (); 106 | } 107 | 108 | @Override 109 | public Stream task20 (Stream numbers, int limit) { 110 | return numbers.filter (x -> x * x <= limit).sorted (); 111 | } 112 | 113 | @Override 114 | public IntStream task21 (int to) { 115 | return IntStream.range (0, to + 1); 116 | } 117 | 118 | @Override 119 | public IntStream task22 (List numbers) { 120 | return IntStream.range (0, numbers.size ()).map (i -> numbers.get (i) + i); 121 | } 122 | 123 | @Override 124 | public IntStream task23 (List numbers, int offset) { 125 | return IntStream.iterate (0, i -> i < numbers.size (), i -> i + offset).map (numbers::get); 126 | } 127 | 128 | @Override 129 | public Stream task24 (List numbers) { 130 | return IntStream.iterate (0, i -> (i + 1) % numbers.size ()).mapToObj (numbers::get); 131 | } 132 | 133 | @Override 134 | public IntStream task25 (List numbers1, List numbers2) { 135 | return IntStream.range (0, Math.min (numbers1.size (), numbers2.size ())) 136 | . map (i -> numbers1.get (i) + numbers2.get (i)); 137 | } 138 | 139 | } 140 | -------------------------------------------------------------------------------- /src/tasks/solution/package-info.java: -------------------------------------------------------------------------------- 1 | package tasks.solution; 2 | -------------------------------------------------------------------------------- /src/tasks/utils/Box.java: -------------------------------------------------------------------------------- 1 | package tasks.utils; 2 | 3 | import java.util.Collections; 4 | import java.util.LinkedList; 5 | import java.util.List; 6 | import java.util.stream.Collectors; 7 | 8 | public class Box extends Item { 9 | 10 | protected final List items = new LinkedList <> (); 11 | 12 | public Box addItem (Item item) { 13 | items.add (item); 14 | return this; 15 | } 16 | 17 | public Box addItems (List items) { 18 | this.items.addAll (items); 19 | return this; 20 | } 21 | 22 | public List getItems () { 23 | return Collections.unmodifiableList (items); 24 | } 25 | 26 | public int getItemsNumber () { 27 | return items.size (); 28 | } 29 | 30 | @Override 31 | public void setWeight (double weight) { 32 | throw new UnsupportedOperationException (); 33 | } 34 | 35 | @Override 36 | public double getWeight () { 37 | return items.stream ().mapToDouble (Item::getWeight).sum (); 38 | } 39 | 40 | @Override 41 | public void setCategory (char category) { 42 | throw new UnsupportedOperationException (); 43 | } 44 | 45 | @Override 46 | public char getCategory () { 47 | return '#'; 48 | } 49 | 50 | @Override 51 | public String toString () { 52 | return items.stream ().map (Item::toString).collect (Collectors.joining (", ", "Box[", "]")); 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /src/tasks/utils/Item.java: -------------------------------------------------------------------------------- 1 | package tasks.utils; 2 | 3 | 4 | public class Item { 5 | 6 | protected double weight; 7 | 8 | protected String description, barcode; 9 | 10 | protected char category = 'A'; 11 | 12 | public void setWeight (double weight) { 13 | this.weight = weight; 14 | } 15 | 16 | public double getWeight () { 17 | return weight; 18 | } 19 | 20 | public void setDescription (String description) { 21 | this.description = description; 22 | } 23 | 24 | public String getDescription () { 25 | return description; 26 | } 27 | 28 | public void setBarcode (String barcode) { 29 | this.barcode = barcode; 30 | } 31 | 32 | public String getBarcode () { 33 | return barcode; 34 | } 35 | 36 | public void setCategory (char category) { 37 | this.category = category; 38 | } 39 | 40 | public char getCategory () { 41 | return category; 42 | } 43 | 44 | @Override 45 | public String toString () { 46 | return String.format ("Item[%c; %s; %.3f; %s]", getCategory (), getBarcode (), getWeight (), getDescription ()); 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /src/tasks/utils/Parcel.java: -------------------------------------------------------------------------------- 1 | package tasks.utils; 2 | 3 | import java.util.stream.Collectors; 4 | 5 | public class Parcel extends Box { 6 | 7 | private String from, to; 8 | 9 | public void setFrom (String from) { 10 | this.from = from; 11 | } 12 | 13 | public String getFrom () { 14 | return from; 15 | } 16 | 17 | public void setTo (String to) { 18 | this.to = to; 19 | } 20 | 21 | public String getTo () { 22 | return to; 23 | } 24 | 25 | @Override 26 | public String toString () { 27 | final var prefix = String.format ("Parcel(%s -> %s)[", getFrom (), getTo ()); 28 | return items.stream ().map (Item::toString).collect (Collectors.joining (", ", prefix, "]")); 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /src/tasks/utils/package-info.java: -------------------------------------------------------------------------------- 1 | package tasks.utils; 2 | -------------------------------------------------------------------------------- /src/tests/InvocationResult.java: -------------------------------------------------------------------------------- 1 | package tests; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Collections; 5 | import java.util.List; 6 | 7 | public class InvocationResult { 8 | 9 | public final Object result; 10 | private long runtime; 11 | 12 | private final List consumers = new ArrayList <> (); 13 | 14 | public InvocationResult (Object result, long runtime, List consumerResults) { 15 | this.result = result; this.runtime = runtime; 16 | consumers.addAll (consumerResults); 17 | } 18 | 19 | public InvocationResult (Object result, long runtime) { 20 | this (result, runtime, List.of ()); 21 | } 22 | 23 | public InvocationResult addConsumerValue (Object value) { 24 | consumers.add (value); 25 | return this; 26 | } 27 | 28 | public InvocationResult addConsumerValues (List values) { 29 | consumers.addAll (values); 30 | return this; 31 | } 32 | 33 | public InvocationResult addRuntime (long delta) { 34 | runtime += delta; 35 | return this; 36 | } 37 | 38 | public InvocationResult addAnotherResult (InvocationResult result) { 39 | addConsumerValues (result.getConsumers ()); 40 | addRuntime (result.getRuntime ()); 41 | return this; 42 | } 43 | 44 | public long getRuntime () { 45 | return runtime; 46 | } 47 | 48 | 49 | public List getConsumers () { 50 | return Collections.unmodifiableList (consumers); 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /src/tests/OutputAssertions.java: -------------------------------------------------------------------------------- 1 | package tests; 2 | 3 | import java.util.HashSet; 4 | import java.util.List; 5 | import java.util.Map; 6 | import java.util.Objects; 7 | import java.util.Set; 8 | import java.util.stream.Collectors; 9 | import java.util.stream.IntStream; 10 | import java.util.stream.Stream; 11 | 12 | public class OutputAssertions { 13 | 14 | /*******************************/ 15 | /* DO NOT TOUCH METHODS BELLOW */ 16 | /*******************************/ 17 | 18 | public static void assertOutput (Set actual, Set expected) { 19 | final var tmp = new HashSet <> (expected); 20 | tmp.removeAll (actual); 21 | 22 | assert tmp.isEmpty () : String.format ( 23 | "Expected: %s (unordered)%n Actual: %s", expected, actual 24 | ); 25 | } 26 | 27 | public static void assertOutput (Set actual, List expected) { 28 | for (final var item : expected) { 29 | assert actual.contains (item) : String.format ( 30 | "Expected value `%s` in %s", item, actual 31 | ); 32 | } 33 | } 34 | 35 | public static void assertOutput (List actual, List expected) { 36 | assert actual.size () == expected.size () : String.format ( 37 | "Resulted list should contains %d elements (actual size: %d)", 38 | expected.size (), actual.size () 39 | ); 40 | 41 | for (int i = 0; i < expected.size (); i++) { 42 | assert Objects.equals (expected.get (i), actual.get (i)) : String.format ( 43 | "Value `%s` was expected on position %d (actual value: %s)", 44 | expected.get (i), i, actual.get (i) 45 | ); 46 | } 47 | } 48 | 49 | public static void assertOutput (List actual, Set expected) { 50 | assert actual.size () == expected.size () : String.format ( 51 | "Resulted list should contains %d elements (actual size: %d)", 52 | expected.size (), actual.size () 53 | ); 54 | 55 | for (int i = 0; i < expected.size (); i++) { 56 | assert expected.contains (actual.get (i)) : String.format ( 57 | "Value `%s` on position %d should not be in answer", 58 | actual.get (i), i 59 | ); 60 | } 61 | } 62 | 63 | public static void assertOutput (Integer actual, Integer expected) { 64 | assert Objects.equals (actual, expected) : String.format ( 65 | "Integer value `%d` was expected (actual given: %d)", 66 | expected, actual 67 | ); 68 | } 69 | 70 | public static void assertOutput (Stream actual, boolean parallel, List expected) { 71 | assert actual.isParallel () == parallel : String.format ( 72 | "Stream should%s be parallel", parallel ? "" : " not" 73 | ); 74 | 75 | assertOutput (actual.collect (Collectors.toList ()), expected); 76 | } 77 | 78 | public static void assertOutput (Stream actual, boolean parallel, Set expected) { 79 | assert actual.isParallel () == parallel : String.format ( 80 | "Stream should%s be parallel", parallel ? "" : " not" 81 | ); 82 | 83 | assertOutput (actual.collect (Collectors.toList ()), expected); 84 | } 85 | 86 | public static void assertOutput (IntStream actual, boolean parallel, List expected) { 87 | assert actual.isParallel () == parallel : String.format ( 88 | "Stream should%s be parallel", parallel ? "" : " not" 89 | ); 90 | 91 | assertOutput (actual.boxed ().collect (Collectors.toList ()), expected); 92 | } 93 | 94 | public static void assertOutput (IntStream actual, boolean parallel, Set expected) { 95 | assert actual.isParallel () == parallel : String.format ( 96 | "Stream should%s be parallel", parallel ? "" : " not" 97 | ); 98 | 99 | assertOutput (actual.boxed ().collect (Collectors.toList ()), expected); 100 | } 101 | 102 | @SuppressWarnings ("unchecked") 103 | public static void assertOutput (Map actual, Map expected) { 104 | assert actual.size () == expected.size () : String.format ( 105 | "Resulted map should contains %d elements (actual size: %d)", 106 | expected.size (), actual.size () 107 | ); 108 | 109 | for (final var entry : expected.entrySet ()) { 110 | assert actual.containsKey (entry.getKey ()) : String.format ( 111 | "Resulted map should contains key `%s`", entry.getKey () 112 | ); 113 | 114 | if (entry.getValue () instanceof Map) { 115 | final var actualMap = (Map ) actual.get (entry.getKey ()); 116 | final var expectedMap = (Map ) entry.getValue (); 117 | assertOutput (actualMap, expectedMap); 118 | } else if (entry.getValue () instanceof List) { 119 | final var actualList = (List ) actual.get (entry.getKey ()); 120 | final var expectedList = (List ) entry.getValue (); 121 | assertOutput (actualList, expectedList); 122 | } else if (entry.getValue () instanceof Set) { 123 | final var actualSet = (Set ) actual.get (entry.getKey ()); 124 | final var expectedSet = (Set ) entry.getValue (); 125 | assertOutput (actualSet, expectedSet); 126 | } 127 | } 128 | } 129 | 130 | } 131 | -------------------------------------------------------------------------------- /src/tests/StreamTasksTests.java: -------------------------------------------------------------------------------- 1 | package tests; 2 | 3 | import java.util.List; 4 | import java.util.Set; 5 | import java.util.function.Function; 6 | import java.util.function.Predicate; 7 | import java.util.stream.IntStream; 8 | import java.util.stream.Stream; 9 | 10 | import tests.presets.HexStrNumbers; 11 | import tests.presets.IntNumbers; 12 | import tests.presets.IntStrNumbers; 13 | import tests.presets.Names; 14 | import tests.utils.Test; 15 | import tests.utils.TestInputCollection; 16 | import tests.utils.TestInputConstant; 17 | import tests.utils.TestInputFunction; 18 | import tests.utils.TestInputPredicate; 19 | import tests.utils.TestResult; 20 | 21 | public abstract class StreamTasksTests { 22 | 23 | @Test (order = 0) 24 | @TestResult (repeat = 1) 25 | public abstract List task1 ( 26 | @TestInputConstant (constant = {1, 2, 3, 4, 5, 6}) int a, 27 | @TestInputConstant (constant = {6, 7, 8}) int b, 28 | @TestInputConstant (constant = {1, 9, 2, 8, 3, 7, 4}) int c 29 | ); 30 | 31 | @Test (order = 0) 32 | @TestResult (repeat = 1) 33 | public abstract Set task2 ( 34 | @TestInputConstant (constant = {6, 2, 8, 4, 0}) int a, 35 | @TestInputConstant (constant = {1, 3, 5, 7, 9}) int b, 36 | @TestInputConstant (constant = {1, 2, 5, 4, 3}) int c 37 | ); 38 | 39 | @Test (order = 0) 40 | @TestResult (repeat = 1) 41 | public abstract Set task3 ( 42 | @TestInputCollection (presets = {IntNumbers.class, Names.class}, constant = {5, 10, 20}, variation = 10) 43 | List values 44 | ); 45 | 46 | @Test (order = 0) 47 | @TestResult (repeat = 1, wrap = List.class) 48 | public abstract Stream task4 ( 49 | @TestInputCollection (presets = {IntNumbers.class, Names.class}, constant = {5, 10, 20}, variation = 10) 50 | List values 51 | ); 52 | 53 | @Test (order = 0) 54 | @TestResult (repeat = 1, wrap = List.class) 55 | public abstract Stream task5 ( 56 | @TestInputCollection (presets = {IntNumbers.class, Names.class}, constant = {5, 10, 20}, variation = 10) 57 | Set values 58 | ); 59 | 60 | @Test (order = 0) 61 | @TestResult (repeat = 1) 62 | public abstract int task6 ( 63 | @TestInputCollection (presets = {IntNumbers.class, Names.class}, constant = {5, 10, 20}, variation = 10) 64 | Stream values 65 | ); 66 | 67 | @Test (order = 0) 68 | @TestResult (repeat = 1, wrap = List.class) 69 | public abstract Stream task7 ( 70 | @TestInputCollection (presets = {IntNumbers.class, Names.class}, percentage = {1.0, 2.0, 3.0}, variation = 10) 71 | Stream values, 72 | @TestInputConstant (constant = {20, 30, 40}, variation = 10) 73 | int limit 74 | ); 75 | 76 | @Test (order = 0) 77 | @TestResult (repeat = 1, wrap = List.class) 78 | public abstract Stream task8 ( 79 | @TestInputCollection (presets = {IntNumbers.class, Names.class}, percentage = {1.0, 2.0, 3.0}, variation = 10) 80 | Stream values, 81 | @TestInputConstant (constant = {5, 10, 15}, variation = 5) 82 | int n, 83 | @TestInputConstant (constant = {20, 30, 40}, variation = 10) 84 | int batch 85 | ); 86 | 87 | @Test (order = 0) 88 | @TestResult (repeat = 1, wrap = List.class) 89 | public abstract Stream task9 ( 90 | @TestInputCollection (presets = {IntStrNumbers.class, Names.class}, percentage = {0.7, 0.8, 0.9}, variation = 10) 91 | Stream values1, 92 | @TestInputCollection (presets = {Names.class}, percentage = {0.1, 0.2, 0.3}, variation = 10) 93 | Stream values2 94 | ); 95 | 96 | @Test (order = 1) 97 | @TestResult (repeat = 1, wrap = List.class) 98 | public abstract Stream task10 ( 99 | @TestInputCollection (presets = {IntStrNumbers.class, Names.class}, percentage = {0.7, 0.8, 0.9}, variation = 10) 100 | Stream values1, 101 | @TestInputCollection (presets = {Names.class}, percentage = {0.1, 0.2, 0.3}, variation = 10) 102 | Stream values2, 103 | @TestInputCollection (presets = {IntStrNumbers.class}, percentage = {0.4, 0.5, 0.5}, variation = 10) 104 | Stream values3 105 | ); 106 | 107 | @Test (order = 1) 108 | @TestResult (repeat = 1, wrap = List.class) 109 | public abstract Stream task11 ( 110 | @TestInputCollection (presets = {IntNumbers.class}, percentage = {0.7, 0.8, 0.9, 1.7}, variation = 10) 111 | Stream numbers, 112 | @TestInputPredicate (indices = {1}) 113 | Predicate condition 114 | ); 115 | 116 | @Test (order = 1) 117 | @TestResult (repeat = 1, checkBy = 10, wrap = List.class) // TODO: fix wrapping in single invokers 118 | public abstract Predicate task12 ( 119 | @TestInputConstant (constant = {100, 200, 300}, variation = 50) 120 | int from, 121 | @TestInputConstant (constant = {500}, variation = 100) 122 | int to 123 | ); 124 | 125 | @Test (order = 1) 126 | @TestResult (repeat = 1, checkBy = 10, wrap = List.class) 127 | public abstract Predicate task13 ( 128 | @TestInputPredicate (indices = {2}) 129 | Predicate positive, 130 | @TestInputPredicate (indices = {3}) 131 | Predicate negative 132 | ); 133 | 134 | @Test (order = 1) 135 | @TestResult (repeat = 1, wrap = List.class) 136 | public abstract Stream task14 ( 137 | @TestInputCollection (presets = {IntNumbers.class}, percentage = {0.7, 0.8, 0.9, 1.7}, variation = 10) 138 | Stream numbers, 139 | @TestInputFunction (indices = {2}) 140 | Function converter 141 | ); 142 | 143 | @Test (order = 1) 144 | @TestResult (repeat = 1, checkBy = 13, wrap = List.class) 145 | public abstract Function task15 ( 146 | @TestInputConstant (constant = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, variation = 20) 147 | int k, 148 | @TestInputConstant (constant = {-250}, variation = 500) 149 | int b 150 | ); 151 | 152 | @Test (order = 1) 153 | @TestResult (repeat = 1, checkBy = 13, wrap = List.class) 154 | public abstract Function task16 ( 155 | @TestInputFunction (indices = {2, 4, 3}) 156 | Function f, 157 | @TestInputFunction (indices = {3}) 158 | Function g 159 | ); 160 | 161 | @Test (order = 1) 162 | @TestResult (repeat = 1, wrap = List.class) 163 | public abstract Stream task17 ( 164 | @TestInputCollection (presets = {IntStrNumbers.class}, percentage = {0.7, 0.8, 0.9, 1.7}, variation = 20) 165 | Stream numbers 166 | ); 167 | 168 | @Test (order = 1) 169 | @TestResult (repeat = 1, wrap = List.class) 170 | public abstract Stream task18 ( 171 | @TestInputCollection (presets = {HexStrNumbers.class}, percentage = {0.8, 0.9, 1.3, 1.7}, variation = 20) 172 | Stream numbers 173 | ); 174 | 175 | @Test (order = 1) 176 | @TestResult (repeat = 1, wrap = List.class) 177 | public abstract Stream task19 ( 178 | @TestInputCollection (presets = {IntNumbers.class}, percentage = {0.9, 1.2, 1.8, 1.9}, variation = 20) 179 | Stream numbers 180 | ); 181 | 182 | @Test (order = 2) 183 | @TestResult (repeat = 1, wrap = List.class) 184 | public abstract Stream task20 ( 185 | @TestInputCollection (presets = {IntNumbers.class}, percentage = {0.9, 1.2, 1.8, 1.9}, variation = 10) 186 | Stream numbers, 187 | @TestInputConstant (sequence = {0}, parameter = 2) 188 | int limit 189 | ); 190 | 191 | @Test (order = 2) 192 | @TestResult (repeat = 1, wrap = List.class) 193 | public abstract IntStream task21 ( 194 | @TestInputConstant (constant = {325, 5490, 3921, 53890}, variation = 500) 195 | int to 196 | ); 197 | 198 | @Test (order = 2) 199 | @TestResult (repeat = 1, wrap = List.class) 200 | public abstract IntStream task22 ( 201 | @TestInputCollection (presets = {IntNumbers.class}, percentage = {0.8, 0.9, 1.0}, variation = 10) 202 | List numbers 203 | ); 204 | 205 | @Test (order = 2) 206 | @TestResult (repeat = 1, wrap = List.class) 207 | public abstract IntStream task23 ( 208 | @TestInputCollection (presets = {IntNumbers.class}, percentage = {0.4, 0.5, 1.2, 1.7, 2.0}, variation = 10) 209 | List numbers, 210 | @TestInputConstant (constant = {2, 3, 4}) 211 | int offset 212 | ); 213 | 214 | @Test (order = 2) 215 | @TestResult (repeat = 1, checkBy = 6, wrap = List.class) 216 | public abstract Stream task24 ( 217 | @TestInputCollection (presets = {IntNumbers.class}, constant = {5, 10, 15}, variation = 10) 218 | List numbers 219 | ); 220 | 221 | @Test (order = 2) 222 | @TestResult (repeat = 1, wrap = List.class) 223 | public abstract IntStream task25 ( 224 | @TestInputCollection (presets = {IntNumbers.class}, constant = {5, 10, 15}, 225 | percentage = {1.3, 1.4}, variation = 10) 226 | List numbers1, 227 | @TestInputCollection (presets = {IntNumbers.class}, constant = {5, 10, 15}, 228 | percentage = {1.3, 1.4}, variation = 10) 229 | List numbers2 230 | ); 231 | 232 | } 233 | -------------------------------------------------------------------------------- /src/tests/TaskTests.java: -------------------------------------------------------------------------------- 1 | package tests; 2 | 3 | import java.lang.reflect.Method; 4 | import java.util.ArrayList; 5 | import java.util.Collections; 6 | import java.util.List; 7 | import java.util.function.BiFunction; 8 | 9 | public class TaskTests { 10 | 11 | /*******************************/ 12 | /* DO NOT TOUCH METHODS BELLOW */ 13 | /*******************************/ 14 | 15 | private final List inputs; 16 | private final Method method; 17 | 18 | public TaskTests (Method method, List inputs) { 19 | this.method = method; this.inputs = inputs; 20 | } 21 | 22 | private final List > cases = new ArrayList <> (); 23 | 24 | public TaskTests addCase (BiFunction caze) { 25 | cases.add (caze); 26 | return this; 27 | } 28 | 29 | public int getCasesNumber () { 30 | return cases.size (); 31 | } 32 | 33 | public Method getMethod () { 34 | return method; 35 | } 36 | 37 | public List getInputs () { 38 | return Collections.unmodifiableList (inputs); 39 | } 40 | 41 | public InvocationResult runTests (StreamTasksTests implementation, StreamTasksTests reference) { 42 | final var stub = new InvocationResult (null, 0); 43 | return cases.stream ().map (caze -> caze.apply (implementation, reference)) 44 | . reduce (stub, (a, b) -> a == stub && b != null ? b : a); 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /src/tests/TestInputGenerator.java: -------------------------------------------------------------------------------- 1 | package tests; 2 | 3 | import java.lang.reflect.InvocationTargetException; 4 | import java.lang.reflect.Parameter; 5 | import java.util.ArrayList; 6 | import java.util.Collections; 7 | import java.util.HashMap; 8 | import java.util.List; 9 | import java.util.Map; 10 | import java.util.Random; 11 | import java.util.concurrent.atomic.AtomicInteger; 12 | import java.util.function.Function; 13 | import java.util.function.Predicate; 14 | import java.util.function.Supplier; 15 | 16 | import tests.inputs.ConstantValueProvider; 17 | import tests.inputs.ConsumerGenerator; 18 | import tests.inputs.SequenceWithStatistics; 19 | import tests.inputs.SupplierMode; 20 | import tests.presets.DataMappingPreset; 21 | import tests.presets.DataPreset; 22 | import tests.utils.TestInputCollection; 23 | import tests.utils.TestInputConstant; 24 | import tests.utils.TestInputConsumer; 25 | import tests.utils.TestInputFunction; 26 | import tests.utils.TestInputPredicate; 27 | import tests.utils.TestInputSupplier; 28 | 29 | public class TestInputGenerator { 30 | 31 | private final Map >, DataPreset > presets = new HashMap <> (); 32 | 33 | private final List > functions = List.of ( 34 | (String s) -> s.concat (" Solk"), 35 | (String s) -> Integer.parseInt (s), 36 | (Integer i) -> i + 2, 37 | (Integer i) -> i * i, 38 | (Integer i) -> i * 7 39 | ); 40 | 41 | private final List > predicates = List.of ( 42 | (String s) -> s.toLowerCase ().contains ("a"), 43 | (Integer i) -> i >= 500, 44 | (Integer i) -> i % 2 == 0, 45 | (Integer i) -> i % 3 == 0 46 | ); 47 | 48 | public List prepareInputDataForParameter (Parameter parameter, Random random) { 49 | if (parameter.isAnnotationPresent (TestInputCollection.class)) { 50 | final var annotation = parameter.getAnnotation (TestInputCollection.class); 51 | return prepareCollectionInputForParameter (parameter, annotation, random); 52 | } else if (parameter.isAnnotationPresent (TestInputConstant.class)) { 53 | final var annotation = parameter.getAnnotation (TestInputConstant.class); 54 | return prepareConstantInputForParameter (parameter, annotation, random); 55 | } else if (parameter.isAnnotationPresent (TestInputSupplier.class)) { 56 | final var annotation = parameter.getAnnotation (TestInputSupplier.class); 57 | return prepareSupplierInputForParameter (parameter, annotation, random); 58 | } else if (parameter.isAnnotationPresent (TestInputPredicate.class)) { 59 | final var annotation = parameter.getAnnotation (TestInputPredicate.class); 60 | return preparePredicateInputForParameter (parameter, annotation, random); 61 | } else if (parameter.isAnnotationPresent (TestInputFunction.class)) { 62 | final var annotation = parameter.getAnnotation (TestInputFunction.class); 63 | return prepareFunctionInputForParameter (parameter, annotation, random); 64 | } else if (parameter.isAnnotationPresent (TestInputConsumer.class)) { 65 | final var annotation = parameter.getAnnotation (TestInputConsumer.class); 66 | return prepareConsumerInputForParameter (parameter, annotation, random); 67 | } 68 | 69 | return List.of (); 70 | } 71 | 72 | private List > prepareCollectionInputForParameter ( 73 | Parameter parameter, TestInputCollection annotation, Random random 74 | ) { 75 | final var inputsCollector = new ArrayList > (); 76 | final var parallel = annotation.parallel (); 77 | 78 | for (final var presetType : annotation.presets ()) { 79 | final var preset = getPreset (presetType, random); 80 | 81 | final var varation = annotation.variation () + 1; 82 | final var unique = annotation.allUnique (); 83 | 84 | for (final var constantInput : annotation.constant ()) { 85 | final var length = constantInput + random.nextInt (varation); 86 | inputsCollector.add (preset.getRandomSequence (length, random, unique) 87 | .setParallelStream (parallel)); 88 | } 89 | 90 | for (final var percentageInput : annotation.percentage ()) { 91 | final var percent = percentageInput + random.nextInt (varation) / 100.0; 92 | final var length = (int) Math.round (percent * preset.getSize ()); 93 | inputsCollector.add (preset.getRandomSequence (length, random, unique) 94 | .setParallelStream (parallel)); 95 | } 96 | } 97 | 98 | return inputsCollector; 99 | } 100 | 101 | private List prepareConstantInputForParameter ( 102 | Parameter parameter, TestInputConstant annotation, Random random 103 | ) { 104 | final var inputCollector = new ArrayList (); 105 | final var variation = annotation.variation (); 106 | 107 | for (final var constantInput : annotation.constant ()) { 108 | inputCollector.add (new ConstantValueProvider (constantInput, variation)); 109 | } 110 | 111 | final var sparam = annotation.parameter (); 112 | for (final var sequenceInput : annotation.sequence ()) { 113 | inputCollector.add (new ConstantValueProvider (sequenceInput, sparam, variation)); 114 | } 115 | 116 | return inputCollector; 117 | } 118 | 119 | private List >> prepareSupplierInputForParameter ( 120 | Parameter parameter, TestInputSupplier annotation, Random random 121 | ) { 122 | final var inputCollector = new ArrayList >> (); 123 | 124 | for (final var presetType : annotation.presets ()) { 125 | final var preset = getPreset (presetType, random); 126 | 127 | for (final var cycle : annotation.cycles ()) { 128 | if (annotation.mode () == SupplierMode.SEQUENTIAL) { 129 | inputCollector.add (R -> { 130 | final var sequence = cycle == -1 ? preset.getData () 131 | : preset.getRandomSequence (cycle, R, false).data; 132 | final var counter = new AtomicInteger (); 133 | 134 | return () -> sequence.get (counter.getAndUpdate ( 135 | v -> (v + 1) % sequence.size () 136 | )); 137 | }); 138 | } else if (annotation.mode () == SupplierMode.SHUFFLED_SEQUENTIAL) { 139 | inputCollector.add (R -> { 140 | final var rawSequence = cycle == -1 ? preset.getData () 141 | : preset.getRandomSequence (cycle, R, false).data; 142 | final var sequence = new ArrayList <> (rawSequence); 143 | final var counter = new AtomicInteger (); 144 | Collections.shuffle (sequence, R); 145 | 146 | return () -> sequence.get (counter.getAndUpdate ( 147 | v -> (v + 1) % sequence.size () 148 | )); 149 | }); 150 | } else if (annotation.mode () == SupplierMode.RANDOM) { 151 | final var data = preset.getData (); 152 | inputCollector.add (R -> () -> data.get (R.nextInt (data.size ()))); 153 | } 154 | } 155 | } 156 | 157 | return inputCollector; 158 | } 159 | 160 | private List > preparePredicateInputForParameter ( 161 | Parameter parameter, TestInputPredicate annotation, Random random 162 | ) { 163 | final var inputCollector = new ArrayList > (); 164 | for (final var index : annotation.indices ()) { 165 | inputCollector.add (predicates.get (index)); 166 | } 167 | 168 | return inputCollector; 169 | } 170 | 171 | private List > prepareFunctionInputForParameter ( 172 | Parameter parameter, TestInputFunction annotation, Random random 173 | ) { 174 | final var inputCollector = new ArrayList > (); 175 | for (final var index : annotation.indices ()) { 176 | inputCollector.add (functions.get (index)); 177 | } 178 | 179 | return inputCollector; 180 | } 181 | 182 | private List > prepareConsumerInputForParameter ( 183 | Parameter parameter, TestInputConsumer annotation, Random random 184 | ) { 185 | return List.of (new ConsumerGenerator <> (annotation.mode ())); 186 | } 187 | 188 | @SuppressWarnings ("unchecked") 189 | private DataPreset getPreset (Class > presetType, Random random) { 190 | final var preset = presets.get (presetType); 191 | if (preset != null) { return preset; } 192 | 193 | try { 194 | final var data = presetType.getConstructor ().newInstance (); 195 | if (DataMappingPreset.class.isAssignableFrom (presetType)) { 196 | final var mdata = (DataMappingPreset ) data; 197 | final var source = (DataPreset ) getPreset (mdata.getSourcePreset (), random); 198 | mdata.initialize (random, source); 199 | } else { 200 | data.initialize (random); 201 | } 202 | 203 | presets.put (presetType, data); 204 | return data; 205 | } catch ( 206 | InstantiationException | IllegalAccessException 207 | | IllegalArgumentException | InvocationTargetException 208 | | NoSuchMethodException | SecurityException 209 | e 210 | ) { 211 | return null; 212 | } 213 | } 214 | 215 | } 216 | -------------------------------------------------------------------------------- /src/tests/TestInvokerGenerator.java: -------------------------------------------------------------------------------- 1 | package tests; 2 | 3 | import java.lang.annotation.Annotation; 4 | import java.lang.reflect.InvocationTargetException; 5 | import java.lang.reflect.Method; 6 | import java.util.ArrayList; 7 | import java.util.Collection; 8 | import java.util.List; 9 | import java.util.Map; 10 | import java.util.Objects; 11 | import java.util.Random; 12 | import java.util.Set; 13 | import java.util.StringJoiner; 14 | import java.util.concurrent.atomic.AtomicInteger; 15 | import java.util.function.BiFunction; 16 | import java.util.function.Consumer; 17 | import java.util.function.Function; 18 | import java.util.function.Predicate; 19 | import java.util.function.Supplier; 20 | import java.util.stream.Collectors; 21 | import java.util.stream.IntStream; 22 | import java.util.stream.Stream; 23 | 24 | import tests.inputs.ConstantValueProvider; 25 | import tests.inputs.ConsumerGenerator; 26 | import tests.inputs.SequenceWithStatistics; 27 | import tests.utils.TestInputCollection; 28 | import tests.utils.TestInputConstant; 29 | import tests.utils.TestInputConsumer; 30 | import tests.utils.TestInputFunction; 31 | import tests.utils.TestInputPredicate; 32 | import tests.utils.TestInputSupplier; 33 | import tests.utils.TestResult; 34 | 35 | public class TestInvokerGenerator { 36 | 37 | public BiFunction prepareInvoker ( 38 | Method method, Object [] paramInput, Random random, TestResult result, 39 | TestsPool pool, List prepared 40 | ) { 41 | return (implementation, reference) -> { 42 | final var seed = random.nextLong (); 43 | 44 | final var resultImpl = prepareSingleInvoker ( 45 | method, paramInput, new Random (seed), result, pool, prepared, true 46 | ).apply (implementation, reference); 47 | 48 | final var resultRef = prepareSingleInvoker ( 49 | method, paramInput, new Random (seed), result, pool, prepared, false 50 | ).apply (implementation, reference); 51 | 52 | final var wrappedRef = wrapResult (result.wrap (), resultRef.result); 53 | if (method.getReturnType () != Void.class && method.getReturnType () != void.class 54 | && (resultImpl.result != null && wrappedRef != null)) { 55 | compareAnswers (resultImpl.result, wrappedRef, result.parallel ()); 56 | } 57 | 58 | final var consumersImpt = resultImpl.getConsumers (); 59 | final var consumersRef = resultRef.getConsumers (); 60 | 61 | assert consumersImpt.size () == consumersRef.size () : String.format ( 62 | "Number of consumer values are different: %d and %d", 63 | consumersImpt.size (), consumersRef.size () 64 | ); 65 | 66 | for (int i = 0; i < consumersRef.size (); i++) { 67 | compareConsumerAnswers (i, consumersImpt.get (i), consumersRef.get (i)); 68 | } 69 | 70 | return resultImpl; 71 | }; 72 | } 73 | 74 | public BiFunction prepareSingleInvoker ( 75 | Method method, Object [] paramInput, Random random, TestResult result, 76 | TestsPool pool, List prepared, boolean forImplementation 77 | ) { 78 | return (implementation, reference) -> { 79 | final var instance = forImplementation ? implementation : reference; 80 | final var seed = random.nextLong (); 81 | 82 | if (result.checkBy () == -1) { 83 | return prepareAndInvokeImplementation (instance, method, paramInput, seed); 84 | } else { 85 | final var value = prepareAndInvokeImplementation (instance, method, paramInput, seed); 86 | 87 | if (value.result == null) { 88 | throw new IllegalArgumentException ("You implementation should not return NULL as answer"); 89 | } 90 | 91 | return pool.prepareTestsForMethod ( 92 | null, random, prepared, result.checkBy (), value.result, forImplementation 93 | ).runTests (implementation, reference).addAnotherResult (value); 94 | } 95 | }; 96 | } 97 | 98 | private Object wrapResult (Class wrapper, Object result) { 99 | var resultWrapRef = result; 100 | 101 | if (wrapper == List.class) { 102 | if (result instanceof Collection) { 103 | resultWrapRef = List.copyOf ((Collection ) result); 104 | } else if (result instanceof Stream) { 105 | resultWrapRef = ((Stream ) result).collect (Collectors.toList ()); 106 | } else if (result instanceof IntStream) { 107 | resultWrapRef = ((IntStream) result).mapToObj (i -> i).collect (Collectors.toList ()); 108 | } else { 109 | resultWrapRef = List.of (result); 110 | } 111 | } else if (wrapper == Set.class) { 112 | if (result instanceof Collection) { 113 | resultWrapRef = Set.copyOf ((Collection ) result); 114 | } else if (result instanceof Stream) { 115 | resultWrapRef = ((Stream ) result).collect (Collectors.toSet ()); 116 | } else if (result instanceof IntStream) { 117 | resultWrapRef = ((IntStream) result).mapToObj (i -> i).collect (Collectors.toSet ()); 118 | } else { 119 | resultWrapRef = Set.of (result); 120 | } 121 | } 122 | 123 | return resultWrapRef; 124 | } 125 | 126 | private final Set > acceptablePrimitives = Set.of ( 127 | int.class, double.class, Integer.class, Double.class 128 | ); 129 | 130 | private InvocationResult prepareAndInvokeImplementation ( 131 | StreamTasksTests implementation, Method method, Object [] paramInput, long randomSeed 132 | ) { 133 | Object [] input = new Object [paramInput.length]; 134 | final var consumersValues = new ArrayList <> (); 135 | final var parameters = method.getParameters (); 136 | final var random = new Random (randomSeed); 137 | 138 | for (int i = 0; i < parameters.length; i++) { 139 | final var isIntStream = parameters [i].getType () == IntStream.class; 140 | 141 | if (parameters [i].getType () == List.class) { 142 | if (paramInput [i] instanceof SequenceWithStatistics) { 143 | input [i] = ((SequenceWithStatistics ) paramInput [i]).data; 144 | } else if (paramInput [i] instanceof List) { 145 | input [i] = paramInput [i]; 146 | } else { 147 | requestAnnotation (method, i, TestInputCollection.class); 148 | } 149 | } else if (parameters [i].getType () == Set.class) { 150 | if (paramInput [i] instanceof SequenceWithStatistics) { 151 | input [i] = Set.copyOf (((SequenceWithStatistics ) paramInput [i]).data); 152 | } else { 153 | requestAnnotation (method, i, TestInputCollection.class); 154 | } 155 | } else if (parameters [i].getType () == Stream.class || isIntStream) { 156 | if (paramInput [i] instanceof SequenceWithStatistics) { 157 | final var sws = (SequenceWithStatistics ) paramInput [i]; 158 | final var stream = sws.isParallelStream () ? sws.data.parallelStream () : sws.data.stream (); 159 | if (isIntStream) { 160 | input [i] = stream.mapToInt (num -> (Integer) num); 161 | } else { 162 | input [i] = stream; 163 | } 164 | } else if (paramInput [i] instanceof Stream) { 165 | input [i] = paramInput [i]; 166 | } else { 167 | requestAnnotation (method, i, TestInputCollection.class); 168 | } 169 | } else if (parameters [i].getType () == Supplier.class) { 170 | if (paramInput [i] instanceof Function) { 171 | @SuppressWarnings ("unchecked") 172 | final var supplier = (Function >) paramInput [i]; 173 | input [i] = supplier.apply (random); 174 | } else { 175 | requestAnnotation (method, i, TestInputSupplier.class); 176 | } 177 | } else if (parameters [i].getType () == Predicate.class) { 178 | if (paramInput [i] instanceof Predicate) { 179 | input [i] = paramInput [i]; 180 | } else { 181 | requestAnnotation (method, i, TestInputPredicate.class); 182 | } 183 | } else if (parameters [i].getType () == Function.class) { 184 | if (paramInput [i] instanceof Function) { 185 | input [i] = paramInput [i]; 186 | } else { 187 | requestAnnotation (method, i, TestInputFunction.class); 188 | } 189 | } else if (parameters [i].getType () == Consumer.class) { 190 | if (paramInput [i] instanceof ConsumerGenerator) { 191 | final var consumerNresult = ((ConsumerGenerator ) paramInput [i]).get (); 192 | consumersValues.add (consumerNresult.S); 193 | input [i] = consumerNresult.F; 194 | } else { 195 | requestAnnotation (method, i, TestInputConsumer.class); 196 | } 197 | } else if (parameters [i].getType () == int.class || parameters [i].getType () == double.class) { 198 | if (paramInput [i] instanceof ConstantValueProvider) { 199 | final var cwd = (ConstantValueProvider) paramInput [i]; 200 | if (cwd.sequenceSrc != null) { 201 | if (paramInput [cwd.sequenceSrc] instanceof SequenceWithStatistics) { 202 | final var sws = (SequenceWithStatistics ) paramInput [cwd.sequenceSrc]; 203 | if (parameters [i].getType () == int.class) { 204 | input [i] = (int) cwd.getValue (sws, random); 205 | } else { 206 | input [i] = cwd.getValue (sws, random); 207 | } 208 | } else { 209 | throw new IllegalArgumentException (String.format ( 210 | "In method `%s` parameter #%d depends on parameter #%d that mast be " 211 | + "a collection with @TestInputCollection annotation", 212 | method.getName (), i, cwd.sequenceSrc 213 | )); 214 | } 215 | } else { 216 | if (parameters [i].getType () == int.class) { 217 | input [i] = (int) cwd.getValue (null, random); 218 | } else { 219 | input [i] = cwd.getValue (null, random); 220 | } 221 | } 222 | } else if (acceptablePrimitives.contains (paramInput [i].getClass ())) { 223 | input [i] = paramInput [i]; 224 | } else { 225 | requestAnnotation (method, i, TestInputConstant.class); 226 | } 227 | } 228 | } 229 | 230 | try { 231 | final var start = System.currentTimeMillis (); 232 | final var result = method.invoke (implementation, input); 233 | final var runtime = System.currentTimeMillis () - start; 234 | 235 | return new InvocationResult (result, runtime, consumersValues); 236 | } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException ite) { 237 | if (ite.getCause () instanceof UnsupportedOperationException) { 238 | throw (UnsupportedOperationException) ite.getCause (); 239 | } else if (ite.getCause () instanceof AssertionError) { 240 | throw (AssertionError) ite.getCause (); 241 | } 242 | 243 | throw new AssertionError ("Failed to check results"); 244 | } 245 | } 246 | 247 | private void requestAnnotation (Method method, int parameterIndex, Class annotation) { 248 | throw new IllegalArgumentException (String.format ( 249 | "In method `%s` parameter #%d should be annotated with @%s", 250 | method.getName (), parameterIndex, annotation.getSimpleName () 251 | )); 252 | } 253 | 254 | private void compareAnswers (Object implementation, Object reference, boolean parallel) { 255 | final var iType = implementation instanceof IntStream ? IntStream.class 256 | : implementation instanceof Stream ? Stream.class 257 | : implementation instanceof Integer ? Integer.class 258 | : implementation instanceof List ? List.class 259 | : implementation instanceof Map ? Map.class 260 | : implementation instanceof Set ? Set.class : null; 261 | final var rType = reference instanceof IntStream ? IntStream.class 262 | : reference instanceof Stream ? Stream.class 263 | : reference instanceof Integer ? Integer.class 264 | : reference instanceof List ? List.class 265 | : reference instanceof Map ? Map.class 266 | : reference instanceof Set ? Set.class : null; 267 | if (iType == null || rType == null) { 268 | throw new IllegalArgumentException (String.format ( 269 | "Can't detect assertion types for values: `%s` and `%s`%n", 270 | implementation, reference 271 | )); 272 | } 273 | 274 | try { 275 | if (iType == IntStream.class || iType == Stream.class) { 276 | OutputAssertions.class.getMethod ("assertOutput", iType, boolean.class, rType) 277 | .invoke (null, implementation, parallel, reference); 278 | } else { 279 | OutputAssertions.class.getMethod ("assertOutput", iType, rType) 280 | .invoke (null, implementation, reference); 281 | } 282 | } catch (NoSuchMethodException | SecurityException | IllegalAccessException re) { 283 | re.printStackTrace (); 284 | throw new IllegalStateException ("Failed to check results"); 285 | } catch (InvocationTargetException ite) { 286 | if (ite.getCause () instanceof AssertionError) { 287 | throw (AssertionError) ite.getCause (); 288 | } 289 | 290 | throw new AssertionError ("Failed to check results"); 291 | } 292 | } 293 | 294 | private void compareConsumerAnswers (int index, Object implementation, Object reference) { 295 | assert implementation.getClass () == reference.getClass () : String.format ( 296 | "Consumer values should have same type: %s and %s (comparing pair #d)", 297 | implementation.getClass (), reference.getClass (), index 298 | ); 299 | 300 | if (reference instanceof List) { 301 | compareAnswers (implementation, reference, false); 302 | } else if (reference instanceof AtomicInteger) { 303 | final var sumImpl = ((AtomicInteger) implementation).get (); 304 | final var sumRef = ((AtomicInteger) reference).get (); 305 | 306 | compareAnswers (sumImpl, sumRef, false); 307 | } else if (reference instanceof StringJoiner) { 308 | final var strImpl = ((StringJoiner) implementation).toString (); 309 | final var strRef = ((StringJoiner) reference).toString (); 310 | 311 | assert Objects.equals (strImpl, strRef) : String.format ( 312 | "String `%s` was expected (actual given: %s)", 313 | strImpl, strRef 314 | ); 315 | } 316 | } 317 | 318 | } 319 | -------------------------------------------------------------------------------- /src/tests/TestVerdict.java: -------------------------------------------------------------------------------- 1 | package tests; 2 | 3 | 4 | public enum TestVerdict { 5 | 6 | ACCEPTED ("accepted"), 7 | NOT_IMPL ("not implemented"), 8 | WA ("wrong answer"), 9 | NPE ("missed NULL check"), 10 | RE ("runtime exception") 11 | 12 | ; 13 | 14 | public final String text; 15 | 16 | TestVerdict (String text) { 17 | this.text = text; 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /src/tests/TestsPool.java: -------------------------------------------------------------------------------- 1 | package tests; 2 | 3 | import java.lang.reflect.Executable; 4 | import java.lang.reflect.Method; 5 | import java.lang.reflect.Modifier; 6 | import java.util.ArrayList; 7 | import java.util.Arrays; 8 | import java.util.Comparator; 9 | import java.util.List; 10 | import java.util.Random; 11 | import java.util.function.Predicate; 12 | import java.util.stream.Collectors; 13 | 14 | import tests.utils.Test; 15 | import tests.utils.TestResult; 16 | 17 | public class TestsPool { 18 | 19 | /*******************************/ 20 | /* DO NOT TOUCH METHODS BELLOW */ 21 | /*******************************/ 22 | 23 | private final TestInvokerGenerator invokerGenerator = new TestInvokerGenerator (); 24 | private final TestInputGenerator inputGenerator = new TestInputGenerator (); 25 | private final List pool; 26 | 27 | public TestsPool (Class solutions) { 28 | pool = loadTests (solutions); 29 | } 30 | 31 | private List loadTests (Class solution) { 32 | System.out.println ("Loading tests..."); 33 | final var tests = new ArrayList (); 34 | final var random = new Random (1L); 35 | 36 | final Predicate isPublic = e -> Modifier.isPublic (e.getModifiers ()); 37 | final Predicate isStatic = e -> Modifier.isStatic (e.getModifiers ()); 38 | final Predicate isAbs = e -> Modifier.isAbstract (e.getModifiers ()); 39 | final Predicate isTest = e -> e.isAnnotationPresent (Test.class); 40 | 41 | final var methods = Arrays.stream (solution.getDeclaredMethods ()) 42 | . filter (isPublic.and (isStatic.negate ()).and (isAbs).and (isTest)) 43 | . sorted (Comparator.comparingInt (Test.GET_ORDER).thenComparing (Method::getName)) 44 | . collect (Collectors.toList ()); 45 | 46 | for (final var method : methods) { 47 | //System.out.println (method); // SYSOUT 48 | tests.add (prepareTestsForMethod (method, random, tests)); 49 | } 50 | 51 | System.out.printf ("%n%d tests loaded%n%n", tests.size ()); 52 | return tests; 53 | } 54 | 55 | public TaskTests prepareTestsForMethod (Method method, Random random, List pool) { 56 | return prepareTestsForMethod (method, random, pool, -1, null, false); 57 | } 58 | 59 | public TaskTests prepareTestsForMethod ( 60 | Method method, Random random, List pool, 61 | int index, Object parameterValue, boolean forImpl 62 | ) { 63 | if (method == null || index != -1) { 64 | method = pool.get (index).getMethod (); 65 | } 66 | 67 | final var result = method.getAnnotation (TestResult.class); 68 | final var parameters = method.getParameters (); 69 | 70 | final var inputs = Arrays.stream (parameters).map ( 71 | p -> inputGenerator.prepareInputDataForParameter (p, random) 72 | ).collect (Collectors.toList ()); 73 | 74 | var maxCases = inputs.stream ().mapToInt (List::size).max ().orElse (0); 75 | maxCases = maxCases == 0 ? result.repeat () : Math.max (maxCases, result.repeat ()); 76 | 77 | final var tests = new TaskTests (method, inputs); 78 | 79 | int customParameterIndex = -1; 80 | if (parameterValue != null) { 81 | for (int i = 0; i < parameters.length; i++) { 82 | if (canAssignRightToLeft (parameters [i].getType (), parameterValue.getClass ())) { 83 | customParameterIndex = i; 84 | break; 85 | } 86 | } 87 | } 88 | 89 | if (customParameterIndex == -1) { 90 | for (int i = 0; i < maxCases; i++) { 91 | try { 92 | final var paramInput = prepareParametersInput (inputs, parameters.length, i); 93 | 94 | tests.addCase (invokerGenerator.prepareInvoker ( 95 | method, paramInput, random, result, this, pool 96 | )); 97 | } catch (IllegalArgumentException iae) { 98 | final var j = Integer.parseInt (iae.getMessage ()); 99 | 100 | throw new IllegalArgumentException (String.format ( 101 | "Parameter `%s %s` of method `%s` should have at least 1 input values", 102 | parameters [j].getType (), parameters [j].getName (), method.getName () 103 | )); 104 | } 105 | } 106 | } else { 107 | final var input = random.nextInt (inputs.size ()); 108 | final var paramInput = prepareParametersInput (inputs, parameters.length, input); 109 | paramInput [customParameterIndex] = parameterValue; 110 | 111 | tests.addCase (invokerGenerator.prepareSingleInvoker ( 112 | method, paramInput, random, result, this, pool, forImpl 113 | )); 114 | } 115 | 116 | return tests; 117 | } 118 | 119 | private boolean canAssignRightToLeft (Class a, Class b) { 120 | return (a == int.class && b == Integer.class) || (a == double.class && b == Double.class) 121 | || (a.isAssignableFrom (b)); 122 | } 123 | 124 | private Object [] prepareParametersInput (List > inputs, int parameters, int index) { 125 | final var paramInput = new Object [parameters]; 126 | for (int j = 0; j < parameters; j++) { 127 | final var inp = inputs.get (j); 128 | if (inp.isEmpty ()) { 129 | throw new IllegalArgumentException (String.valueOf (j)); 130 | } 131 | 132 | paramInput [j] = inp.get (index % inp.size ()); 133 | } 134 | 135 | return paramInput; 136 | } 137 | 138 | public int getTestsNumber () { 139 | return pool.size (); 140 | } 141 | 142 | public InvocationResult runTest (int index, StreamTasksTests implementation, StreamTasksTests reference) { 143 | return pool.get (index).runTests (implementation, reference); 144 | } 145 | 146 | } 147 | -------------------------------------------------------------------------------- /src/tests/TestsRunner.java: -------------------------------------------------------------------------------- 1 | package tests; 2 | 3 | import java.util.Locale; 4 | import java.util.Optional; 5 | 6 | public class TestsRunner { 7 | 8 | /*******************************/ 9 | /* DO NOT TOUCH METHODS BELLOW */ 10 | /*******************************/ 11 | 12 | private final StreamTasksTests implementation, reference; 13 | private final TestsPool testsPool; 14 | 15 | public TestsRunner (StreamTasksTests implementation, StreamTasksTests reference) { 16 | testsPool = new TestsPool (StreamTasksTests.class); 17 | this.implementation = implementation; 18 | this.reference = reference; 19 | } 20 | 21 | public int test () { 22 | Locale.setDefault (Locale.ENGLISH); 23 | 24 | final var testsNumber = testsPool.getTestsNumber (); 25 | int failed = 0; 26 | 27 | System.out.printf ("Running tests...%n%n"); 28 | 29 | for (int i = 0; i < testsNumber; i++) { 30 | System.out.printf ("Test %3d -- ", i + 1); 31 | 32 | final var start = System.currentTimeMillis (); 33 | long internalRuntime = Long.MAX_VALUE; 34 | Throwable throwable = null; 35 | TestVerdict verdict = null; 36 | 37 | try { 38 | internalRuntime = testsPool.runTest (i, implementation, reference).getRuntime (); 39 | verdict = TestVerdict.ACCEPTED; 40 | } catch (UnsupportedOperationException uoe) { 41 | verdict = TestVerdict.NOT_IMPL; 42 | } catch (AssertionError ae) { 43 | verdict = TestVerdict.WA; 44 | throwable = ae.getMessage () != null ? ae : null; 45 | } catch (NullPointerException npe) { 46 | verdict = TestVerdict.NPE; 47 | throwable = npe.getMessage () != null ? npe : null; 48 | } catch (Throwable t) { 49 | verdict = TestVerdict.RE; 50 | throwable = t.getMessage () != null ? t : null; 51 | } finally { 52 | final var end = System.currentTimeMillis (); 53 | 54 | final var runtime = Math.min (end - start, internalRuntime); 55 | System.out.printf ("[%6dms] %-20s%n", runtime, verdict.text); 56 | Optional.ofNullable (throwable).ifPresent (t -> { 57 | System.out.printf (" %s%n", t.getMessage ()); 58 | }); 59 | 60 | failed += verdict == TestVerdict.ACCEPTED ? 0 : 1; 61 | } 62 | } 63 | 64 | System.out.printf ( 65 | "%nSummary: %d tests, %d successful, %d failed%n", 66 | testsNumber, testsNumber - failed, failed 67 | ); 68 | 69 | return -failed; 70 | } 71 | 72 | } 73 | -------------------------------------------------------------------------------- /src/tests/inputs/ConstantValueProvider.java: -------------------------------------------------------------------------------- 1 | package tests.inputs; 2 | 3 | import java.util.Random; 4 | 5 | public class ConstantValueProvider { 6 | 7 | public final Double value; 8 | public final int variation; 9 | 10 | public final Integer sequenceSrc; 11 | public final Integer sequenceParameter; 12 | 13 | public ConstantValueProvider (double value, int variation) { 14 | this.sequenceSrc = null; this.sequenceParameter = null; 15 | this.value = value; this.variation = variation; 16 | } 17 | 18 | public ConstantValueProvider (int sequenceSrc, int sequenceParameter, int variation) { 19 | this.sequenceParameter = sequenceParameter; 20 | this.sequenceSrc = sequenceSrc; 21 | this.variation = variation; 22 | this.value = null; 23 | } 24 | 25 | public double getValue (SequenceWithStatistics sequence, Random random) { 26 | if (value != null) { 27 | return value.doubleValue () + random.nextDouble () * variation; 28 | } else if (sequence != null && sequenceParameter != null) { 29 | final var tmp = sequenceParameter == 0 ? sequence.length 30 | : sequenceParameter == 1 ? sequence.min 31 | : sequenceParameter == 2 ? sequence.max 32 | : sequenceParameter == 3 ? sequence.average 33 | : sequenceParameter == 4 ? sequence.median 34 | : 0.0; 35 | return tmp + random.nextDouble () * variation; 36 | } 37 | 38 | return 0.0; 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /src/tests/inputs/ConsumerGenerator.java: -------------------------------------------------------------------------------- 1 | package tests.inputs; 2 | 3 | import java.util.ArrayList; 4 | import java.util.StringJoiner; 5 | import java.util.concurrent.atomic.AtomicInteger; 6 | import java.util.function.Consumer; 7 | import java.util.function.Supplier; 8 | 9 | import tests.utils.Pair; 10 | 11 | public class ConsumerGenerator implements Supplier , Object>> { 12 | 13 | private final ConsumerMode mode; 14 | 15 | public ConsumerGenerator (ConsumerMode mode) { 16 | if (mode == null) { 17 | throw new IllegalArgumentException ("Consumer mode is not defined"); 18 | } 19 | 20 | this.mode = mode; 21 | } 22 | 23 | public Pair , Object> get () { 24 | if (mode == ConsumerMode.LIST_COLLECTOR) { 25 | final var collector = new ArrayList (); 26 | return new Pair <> (collector::add, collector); 27 | } else if (mode == ConsumerMode.SUMMATOR) { 28 | final var summator = new AtomicInteger (); 29 | return new Pair <> (v -> { 30 | if (v instanceof Integer) { 31 | summator.addAndGet ((Integer) v); 32 | } 33 | }, summator); 34 | } else if (mode == ConsumerMode.JOINER) { 35 | final var sj = new StringJoiner (", "); 36 | return new Pair <> (v -> sj.add (String.valueOf (v)), sj); 37 | } 38 | 39 | throw new IllegalStateException ("Consumer mode is not defined"); 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /src/tests/inputs/ConsumerMode.java: -------------------------------------------------------------------------------- 1 | package tests.inputs; 2 | 3 | 4 | public enum ConsumerMode { 5 | 6 | LIST_COLLECTOR, SUMMATOR, JOINER 7 | 8 | } 9 | -------------------------------------------------------------------------------- /src/tests/inputs/SequenceWithStatistics.java: -------------------------------------------------------------------------------- 1 | package tests.inputs; 2 | 3 | import java.util.List; 4 | 5 | public class SequenceWithStatistics { 6 | 7 | public final List data; 8 | 9 | public final int length; 10 | public final double min, max, average, median; 11 | 12 | public SequenceWithStatistics ( 13 | List data, int length, double min, double max, 14 | double average, double median 15 | ) { 16 | this.average = average; 17 | this.length = length; 18 | this.median = median; 19 | this.data = data; 20 | this.min = min; 21 | this.max = max; 22 | } 23 | 24 | public SequenceWithStatistics (List data) { 25 | this (data, 0, 0.0, 0.0, 0.0, 0.0); 26 | } 27 | 28 | @Override 29 | public String toString () { 30 | return String.format ( 31 | "|min: %.3f; max: %.3f; avg: %.3f; med: %.3f| (%d) %s", 32 | min, max, average, median, length, data 33 | ); 34 | } 35 | 36 | private boolean parallel; 37 | 38 | public SequenceWithStatistics markParallelStream () { 39 | parallel = true; 40 | return this; 41 | } 42 | 43 | public SequenceWithStatistics setParallelStream (boolean parallel) { 44 | this.parallel = parallel; 45 | return this; 46 | } 47 | 48 | public boolean isParallelStream () { 49 | return parallel; 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /src/tests/inputs/SupplierMode.java: -------------------------------------------------------------------------------- 1 | package tests.inputs; 2 | 3 | 4 | public enum SupplierMode { 5 | 6 | SEQUENTIAL, SHUFFLED_SEQUENTIAL, RANDOM 7 | 8 | } 9 | -------------------------------------------------------------------------------- /src/tests/inputs/package-info.java: -------------------------------------------------------------------------------- 1 | package tests.inputs; 2 | -------------------------------------------------------------------------------- /src/tests/package-info.java: -------------------------------------------------------------------------------- 1 | package tests; 2 | -------------------------------------------------------------------------------- /src/tests/presets/Boxes.java: -------------------------------------------------------------------------------- 1 | package tests.presets; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Collections; 5 | import java.util.List; 6 | import java.util.Random; 7 | import java.util.function.ToDoubleFunction; 8 | import java.util.stream.IntStream; 9 | 10 | import tasks.utils.Box; 11 | import tasks.utils.Item; 12 | 13 | public class Boxes implements DataMappingPreset { 14 | 15 | private final List boxes = new ArrayList <> (); 16 | 17 | @Override 18 | public void initialize (Random r, DataPreset items) { 19 | items.getRandomSequence (200 / 10 + r.nextInt (10), r, false); 20 | IntStream.range (0, 1000).mapToObj (i -> items.getRandomSequence (i / 10 + r.nextInt (10), r, false).data) 21 | . map (its -> its.stream ().reduce (new Box (), Box::addItem, (a, b) -> a.addItems (b.getItems ()))) 22 | . forEach (boxes::add); 23 | } 24 | 25 | @Override 26 | public List getData () { 27 | return Collections.unmodifiableList (boxes); 28 | } 29 | 30 | @Override 31 | public boolean doesSupportStatistics () { 32 | return true; 33 | } 34 | 35 | @Override 36 | public ToDoubleFunction getStatisticsConverter () { 37 | return Box::getWeight; 38 | } 39 | 40 | @Override 41 | public Class > getSourcePreset () { 42 | return Items.class; 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /src/tests/presets/DataMappingPreset.java: -------------------------------------------------------------------------------- 1 | package tests.presets; 2 | 3 | import java.util.Random; 4 | 5 | public interface DataMappingPreset extends DataPreset { 6 | 7 | Class > getSourcePreset (); 8 | 9 | void initialize (Random r, DataPreset preset); 10 | 11 | @Override 12 | default void initialize (Random r) { 13 | throw new UnsupportedOperationException (); 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /src/tests/presets/DataPreset.java: -------------------------------------------------------------------------------- 1 | package tests.presets; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Collections; 5 | import java.util.List; 6 | import java.util.Random; 7 | import java.util.Set; 8 | import java.util.function.ToDoubleFunction; 9 | import java.util.stream.Collectors; 10 | import java.util.stream.IntStream; 11 | 12 | import tests.inputs.SequenceWithStatistics; 13 | 14 | public interface DataPreset { 15 | 16 | void initialize (Random r); 17 | 18 | List getData (); 19 | 20 | default int getSize () { 21 | return getData ().size (); 22 | } 23 | 24 | boolean doesSupportStatistics (); 25 | 26 | ToDoubleFunction getStatisticsConverter (); 27 | 28 | default SequenceWithStatistics getRandomSequence (int length, Random r, boolean unique) { 29 | List sequence = List.of (); 30 | 31 | if (unique) { 32 | final var uniques = new ArrayList <> (Set.copyOf (getData ())); 33 | if (uniques.size () < length) { 34 | throw new IllegalArgumentException (String.format ( 35 | "Requested number of unique value (%d) is more than actual number of unique values (%d)", 36 | length, uniques.size () 37 | )); 38 | } 39 | 40 | Collections.shuffle (uniques, r); 41 | sequence = uniques.subList (0, length); 42 | } else { 43 | final var data = getData (); 44 | 45 | sequence = IntStream.range (0, length).map (i -> r.nextInt (data.size ())) 46 | . mapToObj (data::get).collect (Collectors.toUnmodifiableList ()); 47 | } 48 | 49 | if (doesSupportStatistics () && !sequence.isEmpty ()) { 50 | final var conv = getStatisticsConverter (); 51 | 52 | final var statistics = sequence.stream ().mapToDouble (conv).summaryStatistics (); 53 | double avg = statistics.getAverage (), min = statistics.getMin (), max = statistics.getMax (); 54 | double med = sequence.stream ().mapToDouble (conv).sorted ().skip (length / 2).findFirst ().orElse (0.0); 55 | 56 | return new SequenceWithStatistics <> (sequence, length, min, max, avg, med); 57 | } else { 58 | return new SequenceWithStatistics <> (sequence); 59 | } 60 | } 61 | 62 | } 63 | -------------------------------------------------------------------------------- /src/tests/presets/HexStrNumbers.java: -------------------------------------------------------------------------------- 1 | package tests.presets; 2 | 3 | import java.util.Random; 4 | import java.util.function.ToDoubleFunction; 5 | import java.util.stream.IntStream; 6 | 7 | public class HexStrNumbers extends IntStrNumbers { 8 | 9 | @Override 10 | public void initialize (Random r) { 11 | IntStream.range (0, 1000).map (__ -> r.nextInt (1000)) 12 | .mapToObj (n -> String.format ("0x%x", n)) 13 | .forEach (numbers::add); 14 | } 15 | 16 | @Override 17 | public ToDoubleFunction getStatisticsConverter () { 18 | return num -> Integer.parseInt (num.substring (2), 16); 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/tests/presets/IntNumbers.java: -------------------------------------------------------------------------------- 1 | package tests.presets; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Collections; 5 | import java.util.List; 6 | import java.util.Random; 7 | import java.util.function.ToDoubleFunction; 8 | import java.util.stream.IntStream; 9 | 10 | public class IntNumbers implements DataPreset { 11 | 12 | private final List numbers = new ArrayList <> (); 13 | 14 | @Override 15 | public void initialize (Random r) { 16 | IntStream.range (0, 1000).map (__ -> r.nextInt (1000)).forEach (numbers::add); 17 | } 18 | 19 | @Override 20 | public List getData () { 21 | return Collections.unmodifiableList (numbers); 22 | } 23 | 24 | @Override 25 | public boolean doesSupportStatistics () { 26 | return true; 27 | } 28 | 29 | @Override 30 | public ToDoubleFunction getStatisticsConverter () { 31 | return Integer::doubleValue; 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /src/tests/presets/IntStrNumbers.java: -------------------------------------------------------------------------------- 1 | package tests.presets; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Collections; 5 | import java.util.List; 6 | import java.util.Random; 7 | import java.util.function.ToDoubleFunction; 8 | import java.util.stream.IntStream; 9 | 10 | public class IntStrNumbers implements DataPreset { 11 | 12 | protected final List numbers = new ArrayList <> (); 13 | 14 | @Override 15 | public void initialize (Random r) { 16 | IntStream.range (0, 1000).map (__ -> r.nextInt (1000)) 17 | .mapToObj (String::valueOf).forEach (numbers::add); 18 | } 19 | 20 | @Override 21 | public List getData () { 22 | return Collections.unmodifiableList (numbers); 23 | } 24 | 25 | @Override 26 | public boolean doesSupportStatistics () { 27 | return true; 28 | } 29 | 30 | @Override 31 | public ToDoubleFunction getStatisticsConverter () { 32 | return Integer::parseInt; 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/tests/presets/Items.java: -------------------------------------------------------------------------------- 1 | package tests.presets; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Collections; 5 | import java.util.List; 6 | import java.util.Random; 7 | import java.util.function.ToDoubleFunction; 8 | import java.util.stream.IntStream; 9 | 10 | import tasks.utils.Item; 11 | 12 | public class Items implements DataPreset { 13 | 14 | private final List items = new ArrayList <> (); 15 | 16 | @Override 17 | public void initialize (Random r) { 18 | IntStream.range (0, 1000).mapToObj (__ -> { 19 | final var item = new Item (); 20 | 21 | final var barcode = r.nextInt (10000); 22 | 23 | item.setWeight (500.0 + 3.0 * barcode / 10.0 + (r.nextDouble () - 0.5) * 250); 24 | item.setBarcode (String.format ("%04d", barcode)); 25 | item.setCategory (randomCategory (r)); 26 | 27 | return item; 28 | }).forEach (items::add); 29 | } 30 | 31 | public static char randomCategory (Random r) { 32 | return (char) ('A' + r.nextInt (26)); 33 | } 34 | 35 | @Override 36 | public List getData () { 37 | return Collections.unmodifiableList (items); 38 | } 39 | 40 | @Override 41 | public boolean doesSupportStatistics () { 42 | return true; 43 | } 44 | 45 | @Override 46 | public ToDoubleFunction getStatisticsConverter () { 47 | return Item::getWeight; 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /src/tests/presets/Names.java: -------------------------------------------------------------------------------- 1 | package tests.presets; 2 | 3 | import java.util.List; 4 | import java.util.Random; 5 | import java.util.function.ToDoubleFunction; 6 | 7 | public class Names implements DataPreset { 8 | 9 | private final List names = List.of ( 10 | "Andrey", "Boris", "Clement", "David", "Efim", "Feofan", 11 | "Grigory", "Georgy", "Hoang", "Ilon", "Igor", "Jastin", 12 | "Kevin", "Lewis", "Leander", "Marko", "Natan" 13 | ); 14 | 15 | @Override 16 | public List getData () { 17 | return names; 18 | } 19 | 20 | @Override 21 | public void initialize (Random r) {} 22 | 23 | @Override 24 | public boolean doesSupportStatistics () { 25 | return true; 26 | } 27 | 28 | @Override 29 | public ToDoubleFunction getStatisticsConverter () { 30 | return String::length; 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /src/tests/presets/package-info.java: -------------------------------------------------------------------------------- 1 | package tests.presets; 2 | -------------------------------------------------------------------------------- /src/tests/utils/F3.java: -------------------------------------------------------------------------------- 1 | package tests.utils; 2 | 3 | @FunctionalInterface 4 | public interface F3 { 5 | 6 | public R apply (I1 i1, I2 i2, I3 i3); 7 | 8 | } 9 | -------------------------------------------------------------------------------- /src/tests/utils/F4.java: -------------------------------------------------------------------------------- 1 | package tests.utils; 2 | 3 | @FunctionalInterface 4 | public interface F4 { 5 | 6 | public R apply (I1 i1, I2 i2, I3 i3, I4 i4); 7 | 8 | } 9 | -------------------------------------------------------------------------------- /src/tests/utils/F5.java: -------------------------------------------------------------------------------- 1 | package tests.utils; 2 | 3 | @FunctionalInterface 4 | public interface F5 { 5 | 6 | public R apply (I1 i1, I2 i2, I3 i3, I4 i4, I5 i5); 7 | 8 | } 9 | -------------------------------------------------------------------------------- /src/tests/utils/Pair.java: -------------------------------------------------------------------------------- 1 | package tests.utils; 2 | 3 | 4 | public class Pair { 5 | 6 | public final F F; 7 | public final S S; 8 | 9 | public Pair (F F, S S) { 10 | this.F = F; this.S = S; 11 | } 12 | 13 | public F f () { return F; } 14 | public S s () { return S; } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /src/tests/utils/Test.java: -------------------------------------------------------------------------------- 1 | package tests.utils; 2 | 3 | import static java.lang.annotation.ElementType.*; 4 | import static java.lang.annotation.RetentionPolicy.*; 5 | 6 | import java.lang.annotation.Retention; 7 | import java.lang.annotation.Target; 8 | import java.lang.reflect.Method; 9 | import java.util.function.ToIntFunction; 10 | 11 | 12 | @Target (METHOD) 13 | @Retention (RUNTIME) 14 | public @interface Test { 15 | 16 | public static final ToIntFunction GET_ORDER = m -> m.getAnnotation (Test.class).order (); 17 | 18 | int order (); 19 | 20 | String description () default ""; 21 | 22 | } 23 | -------------------------------------------------------------------------------- /src/tests/utils/TestInputCollection.java: -------------------------------------------------------------------------------- 1 | package tests.utils; 2 | 3 | import static java.lang.annotation.ElementType.*; 4 | import static java.lang.annotation.RetentionPolicy.*; 5 | 6 | import java.lang.annotation.Retention; 7 | import java.lang.annotation.Target; 8 | 9 | import tests.presets.DataPreset; 10 | 11 | 12 | @Target (PARAMETER) 13 | @Retention (RUNTIME) 14 | public @interface TestInputCollection { 15 | 16 | Class > [] presets () default {}; 17 | 18 | int [] constant () default {}; 19 | 20 | double [] percentage () default {}; 21 | 22 | int variation () default 0; 23 | 24 | boolean allUnique () default false; 25 | 26 | boolean parallel () default false; 27 | 28 | } 29 | -------------------------------------------------------------------------------- /src/tests/utils/TestInputConstant.java: -------------------------------------------------------------------------------- 1 | package tests.utils; 2 | 3 | import static java.lang.annotation.ElementType.*; 4 | import static java.lang.annotation.RetentionPolicy.*; 5 | 6 | import java.lang.annotation.Retention; 7 | import java.lang.annotation.Target; 8 | 9 | 10 | @Target (PARAMETER) 11 | @Retention (RUNTIME) 12 | public @interface TestInputConstant { 13 | 14 | double [] constant () default {}; 15 | 16 | int [] sequence () default {}; 17 | 18 | int parameter () default -1; 19 | 20 | int variation () default 0; 21 | 22 | } 23 | -------------------------------------------------------------------------------- /src/tests/utils/TestInputConsumer.java: -------------------------------------------------------------------------------- 1 | package tests.utils; 2 | 3 | import static java.lang.annotation.ElementType.*; 4 | import static java.lang.annotation.RetentionPolicy.*; 5 | 6 | import java.lang.annotation.Retention; 7 | import java.lang.annotation.Target; 8 | 9 | import tests.inputs.ConsumerMode; 10 | 11 | 12 | @Target (PARAMETER) 13 | @Retention (RUNTIME) 14 | public @interface TestInputConsumer { 15 | 16 | ConsumerMode mode () default ConsumerMode.LIST_COLLECTOR; 17 | 18 | } 19 | -------------------------------------------------------------------------------- /src/tests/utils/TestInputFunction.java: -------------------------------------------------------------------------------- 1 | package tests.utils; 2 | 3 | import static java.lang.annotation.ElementType.*; 4 | import static java.lang.annotation.RetentionPolicy.*; 5 | 6 | import java.lang.annotation.Retention; 7 | import java.lang.annotation.Target; 8 | 9 | 10 | @Target (PARAMETER) 11 | @Retention (RUNTIME) 12 | public @interface TestInputFunction { 13 | 14 | int [] indices (); 15 | 16 | } 17 | -------------------------------------------------------------------------------- /src/tests/utils/TestInputPredicate.java: -------------------------------------------------------------------------------- 1 | package tests.utils; 2 | 3 | import static java.lang.annotation.ElementType.*; 4 | import static java.lang.annotation.RetentionPolicy.*; 5 | 6 | import java.lang.annotation.Retention; 7 | import java.lang.annotation.Target; 8 | 9 | 10 | @Target (PARAMETER) 11 | @Retention (RUNTIME) 12 | public @interface TestInputPredicate { 13 | 14 | int [] indices (); 15 | 16 | } 17 | -------------------------------------------------------------------------------- /src/tests/utils/TestInputSupplier.java: -------------------------------------------------------------------------------- 1 | package tests.utils; 2 | 3 | import static java.lang.annotation.ElementType.*; 4 | import static java.lang.annotation.RetentionPolicy.*; 5 | 6 | import java.lang.annotation.Retention; 7 | import java.lang.annotation.Target; 8 | 9 | import tests.inputs.SupplierMode; 10 | import tests.presets.DataPreset; 11 | 12 | 13 | @Target (PARAMETER) 14 | @Retention (RUNTIME) 15 | public @interface TestInputSupplier { 16 | 17 | Class > [] presets (); 18 | 19 | SupplierMode mode () default SupplierMode.SHUFFLED_SEQUENTIAL; 20 | 21 | int [] cycles () default {-1}; 22 | 23 | } 24 | -------------------------------------------------------------------------------- /src/tests/utils/TestResult.java: -------------------------------------------------------------------------------- 1 | package tests.utils; 2 | 3 | import static java.lang.annotation.ElementType.*; 4 | import static java.lang.annotation.RetentionPolicy.*; 5 | 6 | import java.lang.annotation.Retention; 7 | import java.lang.annotation.Target; 8 | 9 | 10 | @Target (METHOD) 11 | @Retention (RUNTIME) 12 | public @interface TestResult { 13 | 14 | Class wrap () default Void.class; 15 | 16 | boolean parallel () default false; 17 | 18 | int checkBy () default -1; 19 | 20 | /** 21 | * Works clearly only for methods without parameters. 22 | * In case of method with parameters it will have effect only 23 | * if this value is more then number of parameters combinations. 24 | * @return 25 | */ 26 | int repeat () default 1; 27 | 28 | } 29 | -------------------------------------------------------------------------------- /src/tests/utils/package-info.java: -------------------------------------------------------------------------------- 1 | package tests.utils; 2 | -------------------------------------------------------------------------------- /test.cmd: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | ::: compile and run java sources (your implementation and tests) 4 | javac -sourcepath src -d bin src/tasks/StreamTasksMain.java && java -ea -cp bin tasks.StreamTasksMain %* 5 | 6 | echo Exit code %errorlevel% 7 | 8 | ::: wait until you typed some key (to see testing results) 9 | pause -------------------------------------------------------------------------------- /test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # compile and run java sources (your implementation and tests) 4 | javac -sourcepath src -d bin src/tasks/StreamTasksMain.java && java -ea -cp bin tasks.StreamTasksMain $* 5 | 6 | echo Exit code $? --------------------------------------------------------------------------------