diff --git a/Doc/Sd1/Appendix/Exam/2022/Winter/exam.xml b/Doc/Sd1/Appendix/Exam/2022/Winter/exam.xml new file mode 100644 index 0000000000000000000000000000000000000000..fd0cff0c66df7549683770ff6de44033384df50e --- /dev/null +++ b/Doc/Sd1/Appendix/Exam/2022/Winter/exam.xml @@ -0,0 +1,384 @@ +<?xml version="1.0" encoding="UTF-8"?> +<section version="5.0" xml:id="sd1_exam_2022_summer" xml:lang="en" + xmlns="http://docbook.org/ns/docbook" + xmlns:xlink="http://www.w3.org/1999/xlink" + xmlns:xila="http://www.w3.org/2001/XInclude/local-attributes" + xmlns:xi="http://www.w3.org/2001/XInclude" + xmlns:trans="http://docbook.org/ns/transclusion" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns:m="http://www.w3.org/1998/Math/MathML" + xmlns:html="http://www.w3.org/1999/xhtml" + xmlns:db="http://docbook.org/ns/docbook"> + <title>Sd1 examination winter 2022</title> + + <section xml:id="sd1_exam_2022_winter_task1"> + <title>Implementing tasks</title> + + <section xml:id="sd1_exam_2022_winter_task1_preparation"> + <title>Preparation</title> + + <orderedlist> + <listitem> + <para>Download and unzip the above file + <filename>exam.zip</filename>. You should see a directory + »<filename>Exam</filename>« containing a pom.xml file.</para> + </listitem> + + <listitem> + <para>Open this project in your <productname>IDEA</productname> IDE + selecting the <filename>Exam/pom.xml</filename> file.</para> + </listitem> + + <listitem> + <para>Open a terminal in your <productname>IDEA</productname> IDE + and type »<command>mvn</command> <option>javadoc:javadoc</option>«. + This will generate the API documentation rooted at + <filename>target/site/apidocs/index.html</filename>.</para> + </listitem> + + <listitem> + <para>Open <filename>target/site/apidocs/index.html</filename> in + your browser of choice and navigate to the individual classes to be + implemented. Read both class and method descriptions.</para> + </listitem> + </orderedlist> + </section> + + <section xml:id="sd1_exam_2022_winter_task1_description"> + <title>Description</title> + + <para>Your imported project contains:</para> + + <itemizedlist> + <listitem> + <para>Partial implementations of classes and methods.</para> + </listitem> + + <listitem> + <para><productname>Javadoc</productname> comments describing the + desired (not yet implemented) behaviour.</para> + </listitem> + + <listitem> + <para><productname>Junit</productname> tests for testing the desired + behaviour.</para> + </listitem> + </itemizedlist> + </section> + + <section xml:id="sd1_exam_2022_winter_task1_tasks"> + <title>Tasks</title> + + <para>Complete the implementation of classes and methods in both + packages <package>de.hdm_stuttgart.mi.sd1.task1</package> and + <package>de.hdm_stuttgart.mi.sd1.task2</package>. Your project's + <filename>test</filename> branch contains corresponding + <productname>Junit</productname> tests for each class / method to be + implemented.</para> + </section> + + <section xml:id="sd1_exam_2022_winter_task1_hints"> + <title>Hints</title> + + <itemizedlist> + <listitem> + <para>Your score solely depends on the number of successfully + executing unit tests. A »nearly correct« implementation failing with + respect to a given unit tests will not contribute any points at + all.</para> + + <para>General advice: Implement less but correctly.</para> + </listitem> + + <listitem> + <para>Mind special cases <abbrev>i.e.</abbrev> <code>null</code> + variable values or <code>null</code> values being contained in + arrays.</para> + </listitem> + + <listitem> + <para>In case of test failures both the + <productname>IDEA</productname> debugger and logging statements are + your friend.</para> + </listitem> + + <listitem> + <para>Executing + <package>de.hdm_stuttgart.mi.sd1</package>.<classname>ShowReachedPoints</classname> + in your project's <filename>test</filename> branch as a + <productname>Java</productname> application (not as + <productname>Junit</productname> test!) shows your number of points + reached so far.</para> + </listitem> + + <listitem> + <para>Do not model your implementations along unit test definitions + i.e avoid <link + xlink:href="https://freedocs.mi.hdm-stuttgart.de/__slidesd1_appendix.html#/sd1_fig_testDontCheat">cheating + this way</link>! Such behaviour will be regarded as an attempt at + deception (<foreignphrase + xml:lang="de">Täuschungsversuch</foreignphrase>).</para> + </listitem> + </itemizedlist> + </section> + + <section version="5.1" xml:id="sd1_exam_2022_winter_uploadFirst"> + <title>Project upload</title> + + <orderedlist> + <listitem> + <para>Export your project by hitting »File« --> »Export« --> + »Project to Zip File« in IDEA creating <abbrev>e.g.</abbrev> a file + <filename>solution-1.zip</filename>.</para> + </listitem> + + <listitem> + <para>Hit the <quote>choose file</quote> button in your + <productname>ILIAS</productname> browser tab and select + <filename>solution-1.zip</filename>.</para> + </listitem> + + <listitem> + <para>Click <quote>upload</quote>.</para> + </listitem> + + <listitem> + <para><emphasis role="red">Save your upload</emphasis> by advancing + to the next question. (<emphasis role="red">THIS IS + IMPORTANT!!!!!</emphasis>)</para> + </listitem> + </orderedlist> + + <para>Common pitfalls:</para> + + <itemizedlist> + <listitem> + <para>Do not select the wrong archive! In particular avoid choosing + the original <filename>exam.zip</filename> file.</para> + </listitem> + + <listitem> + <para>After uploading check for <filename>solution_1.zip</filename> + being visible in the examination system.</para> + </listitem> + + <listitem> + <para>On advancing your implementation you may upload improved + versions i.e. <filename>solution_2.zip</filename> + <acronym>etc.</acronym> of your project at any time. Only your least + uploaded archive will become subject to marking.</para> + </listitem> + </itemizedlist> + </section> + + <section xml:id="sd1_exam_2022_winter_examCaveats"> + <title>Caveats</title> + + <itemizedlist> + <listitem> + <para>When approaching end of examination check your input for + completeness prior to being automatically logged out by the system. + Remember: There is 120 minutes for the examination and another 5 + minutes to check for completeness.</para> + </listitem> + + <listitem> + <para>Projects residing just on your local workstation's file system + cannot be recovered after finishing the exam.</para> + </listitem> + </itemizedlist> + </section> + </section> + + <section xml:id="sd1_exam_2022_winter_task2"> + <title>Extraterrestrial integer value representation</title> + + <qandaset defaultlabel="qanda" xml:id="sd1_exam_2022_winter_task2Qanda"> + <qandadiv> + <qandaentry> + <question> + <para>A group of scientists captured an extraterrestrial radio + signal. While deciphering its content the group concludes the + three subsequently provided words represent three different + integer values:</para> + + <screen>xzqllxv vlf yppa</screen> + + <para>The alien civilization uses {x,z,q,...} rather than + {0,1,2,3,4,5,6,7,8,9} for representing digits. The scientists + assume »regular« numbering behaviour like <acronym>e.g.</acronym> + being used in position based number representations you've learned + about in your lectures.</para> + + <para>The radio signal is limited: The scientists thus neither + know the individual digits' values nor their overall count.</para> + + <para>For practical reasons we typically use base 2 (binary), base + 8 (octal), base 10 (decimal) or base 16 (hexadecimal) number + representing schemes. From a fundamental point of view however + every base value starting from 2 onwards might be chosen.</para> + + <para>Which number base values of the underlying representation + can be ruled out by the above three integer sample values? Could + it for example be binary? Explain your answer.</para> + </question> + + <answer> + <para>The yet unknown numbering scheme uses at least 9 + digits:</para> + + <screen>{a,l,f,p,q,v,x,y,z}</screen> + + <para>The integer representing system's base must thus be 9 or + larger ruling out base values ranging from 2 (binary) to 8 + (octal).</para> + </answer> + </qandaentry> + </qandadiv> + </qandaset> + </section> + + <section xml:id="sd1_exam_2022_winter_task3"> + <title>An initialization issue</title> + + <qandaset defaultlabel="qanda" xml:id="sd1_exam_2022_winter_task3Qanda"> + <qandadiv> + <qandaentry> + <question> + <para>We consider a class representing book instances containing a + compiler error in line 3:</para> + + <programlisting language="java" linenumbering="numbered">01 public class Book { +02 +03 final int numberOfPages; <emphasis role="red">// Error: Variable 'numberOfPages'</emphasis> +04 <emphasis role="red">//might not have been initialized</emphasis> +05 String title; +06 +07 public Book(final String title, final int numberOfPages) { +08 this.numberOfPages = numberOfPages; +09 this.title = title; +10 } +11 +12 public Book() {} +13 }</programlisting> + + <para>Answer the following questions:</para> + + <orderedlist> + <listitem> + <para>Why is <code language="java">numberOfPages</code> in + contrast to <code language="java">title</code> being flagged + for »possibly not being initialized«?</para> + </listitem> + + <listitem> + <para>The instance variable <code + language="java">numberOfPages</code> does get initialized in + Line 8. Why does the error appear anyway?</para> + </listitem> + + <listitem> + <para>Give a sensitive way solving the problem</para> + </listitem> + </orderedlist> + + <tip> + <para>Consider the default constructor's role.</para> + </tip> + </question> + + <answer> + <para>Having two constructors <methodname>public Book(String, + int)</methodname> and <methodname>public Book()</methodname> there + are thus two ways creating book instances:</para> + + <itemizedlist> + <listitem> + <programlisting language="java">// Neither numberOfPages nor title will be initialized +final book = new Book();</programlisting> + </listitem> + + <listitem> + <programlisting language="java">// Both numberOfPages and title will be initialized +final book = new Book("Learning Java", 120);</programlisting> + </listitem> + </itemizedlist> + + <para>The three answers thus are:</para> + + <orderedlist> + <listitem> + <para><code language="java">title</code> is being declared + without using <code language="java">final</code> and may thus + be assigned or changed at any time after instance + creation.</para> + + <para>On contrary <code language="java">numberOfPages</code> + is being declared as final. Therefore initialization can only + happen (once) at object creation time. The initialization must + thus be part of <emphasis role="red">every</emphasis> + constructor within class <classname>Book</classname>.</para> + </listitem> + + <listitem> + <para>Initialization does happen in <methodname>Book(String, + int)</methodname> but not within the default constructor + <methodname>public Book()</methodname>. This allows for <code + language="java">numberOfPages</code> not being initialized + during instance creation. The <code + language="java">final</code> modifier disallows any subsequent + assignment.</para> + </listitem> + + <listitem> + <para>There are multiple solutions resolving the issue:</para> + + <orderedlist> + <listitem> + <para>Removing the <code language="java">final</code> + modifier in the definition of <code + language="java">numberOfPages</code>:</para> + + <programlisting language="java" linenumbering="numbered">01 public class Book { +02 +03 int numberOfPages; +04 +05 String title; ...</programlisting> + </listitem> + + <listitem> + <para>Adding a parameter <code + language="java">numberOfPages</code> to the default + constructor as well:</para> + + <programlisting language="java" linenumbering="numbered">01 public class Book { +02 +03 final int numberOfPages; + ... +12 public Book(final int numberOfPages) {this.numberOfPages = numberOfPages;} +13 }</programlisting> + </listitem> + + <listitem> + <para>Assigning a default value:</para> + + <programlisting language="java" linenumbering="numbered">01 public class Book { +02 +03 final int numberOfPages; + .... +12 public Book() {this.numberOfPages = 0;} +13 }</programlisting> + + <para>Albeit being syntactically possible this solution + obviously lacks consistency since any book of zero pages + does not make sense.</para> + </listitem> + </orderedlist> + </listitem> + </orderedlist> + </answer> + </qandaentry> + </qandadiv> + </qandaset> + </section> +</section> diff --git a/Doc/Sd1/Appendix/appendix.xml b/Doc/Sd1/Appendix/appendix.xml index 0321113fe573e07b55f95cba24f92af71d05e54e..556acd41c2b99bd6dfaeade3f3e9d0a095fb41ca 100644 --- a/Doc/Sd1/Appendix/appendix.xml +++ b/Doc/Sd1/Appendix/appendix.xml @@ -2355,6 +2355,9 @@ Value 2147483645 is not prime. </listitem> </orderedlist> + <xi:include href="Exam/2022/Winter/exam.xml" xpointer="element(/1)" + ns:idfixup="auto"/> + <xi:include href="Exam/2021/Winter/exam.xml" xpointer="element(/1)" ns:idfixup="auto"/> diff --git a/Klausuren/Sd1/2022winter/Exam/Readme.md b/Klausuren/Sd1/2022winter/Exam/Readme.md new file mode 100644 index 0000000000000000000000000000000000000000..91e86977953438510dc414f062aba7312bdda9ca --- /dev/null +++ b/Klausuren/Sd1/2022winter/Exam/Readme.md @@ -0,0 +1,60 @@ +# Generate ond open class/method javadoc for browsing + +Grab a terminal in this IDE (Alt+F12) and issue the following command: + +``` +Exam> mvn javadoc:javadoc +``` + +Issue a `pwd` command to see your project's working directory: + +``` +Exam> pwd +/home/student/Downloads/Exam +``` +- Your project's root path will likely differ. Copy and open it in your web browser of choice (Chrome / Firefox). +- From there navigate to `target/site/apidocs` and open the generated documentation's root file `index.html`. + +# Implementation tasks + +Your project's following packages do contain implementation tasks: + +- de.hdm_stuttgart.mi.sd1.task1 (50 Points) + +- de.hdm_stuttgart.mi.sd1.task2 (20 points, more difficult) + +Read the generated documentation and implement the skeleton methods and classes. + +Your project's `test` branch does contain corresponding unit tests for verifying your solutions' correctness. + +# Hints + +- Your score solely depends on the number of successfully executing unit tests. A »nearly correct« implementation failing +with respect to a given unit tests will not contribute any points at all. + +- General advice: Implement less but correctly. + +- Mind special cases i.e. `null` variable values or null values being contained in arrays. + +- In case of test failures both the IDEA debugger and logging statements are your friend. + +Executing de.hdm_stuttgart.mi.sd1.ShowReachedPoints in your project's test branch as a Java application +(not as Junit test!) shows your number of points reached so far. + +Do not model your implementations along unit test definitions i.e avoid cheating this way! Such behaviour will be +regarded as an attempt at deception (Täuschungsversuch). + +# Exam system upload + +After finishing implementing: + +1. Export this project by hitting **»File ➔ Export ➔ Project to Zip File«**. +2. Use a self-explanatory file name like e.g. `solution1.zip`. +3. Go to your exam browser window and upload `solution1.zip` . +4. Complete by **clicking the »<span style="background: #527A35;color:white;">Speichern + weiter ➞ </span>«** button. +5. Hit **<span style="background: #446684;color:white;"> 🠬 Speichern + zurück</span>** and check if your + upload is visible. +6. If you advance on implementing: Repeat steps 1. to 5.: Only the least uploaded `.zip` archive will become subject to + marking. + + diff --git a/Klausuren/Sd1/2022winter/Exam/pom.xml b/Klausuren/Sd1/2022winter/Exam/pom.xml new file mode 100644 index 0000000000000000000000000000000000000000..4431d6a7e8b13eba120a33dc7f247911e15045ce --- /dev/null +++ b/Klausuren/Sd1/2022winter/Exam/pom.xml @@ -0,0 +1,113 @@ +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + + <groupId>de.hdm_stuttgart.mi.sd1</groupId> + <artifactId>sd1_2022winter_exam</artifactId> + <version>0.9</version> + <packaging>jar</packaging> + + <name>sd1_2022winter_exam</name> + + <url>https://freedocs.mi.hdm-stuttgart.de/sd1_sect_mavenCli.html</url> + + <properties> + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> + + <maven.compiler.target>17</maven.compiler.target> + <maven.compiler.source>17</maven.compiler.source> + + <freedocs.url>https://freedocs.mi.hdm-stuttgart.de</freedocs.url> + <jdk.api_17.url>${freedocs.url}/doc/openjdk-17-doc/api/</jdk.api_17.url> + <mathjax.url>${freedocs.url}/lib/MathJax/es5/tex-chtml.js</mathjax.url> + <libhighlight.url>${freedocs.url}/lib/highlight.js</libhighlight.url> + </properties> + + <repositories> + <repository> + <id>hdm-mi-internal-maven-repo</id> + <url>https://maven.mi.hdm-stuttgart.de/nexus/repository/mi-maven</url> + </repository> + </repositories> + + <dependencies> + <dependency> + <groupId>de.hdm_stuttgart.mi.exam</groupId> + <artifactId>unitmarking</artifactId> + <version>1.2</version> + </dependency> + + </dependencies> + + <build> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-compiler-plugin</artifactId> + <version>3.10.1</version> + </plugin> + + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-javadoc-plugin</artifactId> + <version>3.4.1</version> + <configuration> + <release>17</release> + <doclint>all</doclint> + <show>public</show> + <docfilessubdirs>true</docfilessubdirs> + <addStylesheets> + <stylesheet>resources/jdocSupplement.css</stylesheet> + </addStylesheets> + + <windowtitle>Exam documentation</windowtitle> + + <links> + <link>https://freedocs.mi.hdm-stuttgart.de/doc/openjdk-17-doc/api/</link> + </links> + + <additionalOptions> + <additionalOption>-html5 --allow-script-in-comments</additionalOption> + </additionalOptions> + <nohelp>true</nohelp> + + <header><![CDATA[ + <script type="text/javascript" src="${mathjax.url}"></script> + <script type="text/javascript" src="{@docRoot}/resources/jdocSupplement.js"></script> + + <link rel="stylesheet" href="${libhighlight.url}/styles/idea.min.css"> + <script src="${libhighlight.url}/highlight.min.js"></script> + <script type="text/javascript">hljs.highlightAll();</script>]]> + </header> + </configuration> + </plugin> + + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-assembly-plugin</artifactId> + <version>3.4.2</version> + <configuration> + <descriptors> + <descriptor>src/main/assembly/assembly.xml</descriptor> + </descriptors> + </configuration> + <executions> + <execution> + <id>make-assembly</id> + <phase>package</phase> + <goals> + <goal>single</goal> + </goals> + <configuration> + <archive> + <manifest> + <mainClass>de.hdm_stuttgart.mi.sd1.ShowReachedPoints</mainClass> + </manifest> + </archive> + </configuration> + </execution> + </executions> + </plugin> + </plugins> + </build> +</project> diff --git a/Klausuren/Sd1/2022winter/Exam/src/main/assembly/assembly.xml b/Klausuren/Sd1/2022winter/Exam/src/main/assembly/assembly.xml new file mode 100644 index 0000000000000000000000000000000000000000..85268e2965620878373d76337f524d8785fd0e1f --- /dev/null +++ b/Klausuren/Sd1/2022winter/Exam/src/main/assembly/assembly.xml @@ -0,0 +1,36 @@ +<assembly + xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.3" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.3 http://maven.apache.org/xsd/assembly-1.1.3.xsd"> + <id>fat-tests</id> + <formats> + <format>jar</format> + </formats> + <includeBaseDirectory>false</includeBaseDirectory> + <dependencySets> + <dependencySet> + <outputDirectory/> + <useProjectArtifact>true</useProjectArtifact> + <unpack>true</unpack> + <scope>test</scope> + </dependencySet> + </dependencySets> + <fileSets> + <fileSet> + <directory>${project.build.directory}/test-classes</directory> + <outputDirectory/> + <includes> + <include>**/*.class</include> + </includes> + <useDefaultExcludes>true</useDefaultExcludes> + </fileSet> + <fileSet> + <directory>${project.build.directory}/classes</directory> + <outputDirectory/> + <includes> + <include>**/*.class</include> + </includes> + <useDefaultExcludes>true</useDefaultExcludes> + </fileSet> + </fileSets> +</assembly> \ No newline at end of file diff --git a/Klausuren/Sd1/2022winter/Exam/src/main/java/de/hdm_stuttgart/mi/sd1/task1/A_Party.java b/Klausuren/Sd1/2022winter/Exam/src/main/java/de/hdm_stuttgart/mi/sd1/task1/A_Party.java new file mode 100644 index 0000000000000000000000000000000000000000..51765a012b806f17d936ab02a20901e86e9aa2f3 --- /dev/null +++ b/Klausuren/Sd1/2022winter/Exam/src/main/java/de/hdm_stuttgart/mi/sd1/task1/A_Party.java @@ -0,0 +1,37 @@ +package de.hdm_stuttgart.mi.sd1.task1; + +/** + * <p>Organizing a party.</p> + */ +public class A_Party { + /** + * <p>Choose people to invite.</p> + * + * <p>While organizing a party the host categorizes his contacts with respect to: + * + * <ul> + * <li>Being a friend.</li> + * <li>Being a customer.</li> + * <li>Past years average annual business related revenue. (Welcome to capitalism 💰 🤑)</li> + * </ul> + * + * <p>A contact will be invited if at least one of the following is true:</p> + * + * <ul> + * <li>The contact is a friend</li> + * <li>The contact is a customer giving rise to at least 20000€ of annual revenue.</li> + * + * </ul> + * @param isFriend Contact is a friend. + * @param isCustomer Contact is a customer. + * @param annualRevenue Past years average annual revenue. + * + * @return <code>true</code> if contact receives an invitation. + */ + static public boolean getInvitation(boolean isFriend, boolean isCustomer, int annualRevenue) { + return true; // Implement me correctly + } + + private A_Party(){/* Ignore me: My sole purpose is suppressing default constructor javadoc generation */} + +} diff --git a/Klausuren/Sd1/2022winter/Exam/src/main/java/de/hdm_stuttgart/mi/sd1/task1/B_Backup.java b/Klausuren/Sd1/2022winter/Exam/src/main/java/de/hdm_stuttgart/mi/sd1/task1/B_Backup.java new file mode 100644 index 0000000000000000000000000000000000000000..01fcdd56f318140d59a006fead1b30c504d5793f --- /dev/null +++ b/Klausuren/Sd1/2022winter/Exam/src/main/java/de/hdm_stuttgart/mi/sd1/task1/B_Backup.java @@ -0,0 +1,92 @@ +package de.hdm_stuttgart.mi.sd1.task1; + +/** + * Creating backup filenames + */ +public class B_Backup { + + /** + * <p>Filename extension character e.g. in <code>index<span style="color:red;">.</span>html</code> </p> + */ + static public final char EXTENSION_SEPARATOR = '.'; + + /** + * <p>Create a backup filename from a given filename and backup extension string.</p> + * + * <p>Rules:</p> + * + * <ul> + * <li> + * <p>If the given filename itself does not have an extension the backup extension string gets + * appended.</p> + * </li> + * + * <li> + * <p>In case of an extension being denoted by a period (.) the backup extension string will + * be inserted prior to the filename's extension.</p> + * </li> + * + * <li> + * <p>In case of multiple period characters only the very last one denotes an extension's beginning.</p> + * </li> + * + * </ul> + * + * <p>We provide some samples:</p> + * + * <table class="goikTableDefaults"> + * <caption>Creating a backup filename</caption> + * <tbody> + * <tr> + * <th>filename</th> + * <th>backupExtension</th> + * <th>return</th> + * </tr> + * <tr> + * <td><code>testfilename</code></td> + * <td><code style='color:red;'>_bak</code></td> + * <td><code>testfilename<span style='color:red;'>_bak</span></code></td> + * </tr> + * <tr> + * <td><code>register.docx</code></td> + * <td><code style='color:red;'>.bak</code></td> + * <td><code>register<span style='color:red;'>.bak</span>.docx</code></td> + * </tr> + * <tr> + * <td><code>.cfgfile</code></td> + * <td><code style='color:red;'>.bak</code></td> + * <td><code><span style='color:red;'>.bak</span>.cfgfile</code></td> + * </tr> + * <tr> + * <td><code>file.c.q.xml</code></td> + * <td><code style='color:red;'>-backup</code></td> + * <td><code>file.c.q<span style='color:red;'>-backup</span>.xml</code></td> + * </tr> + * </tbody> + * </table> + * + * <section class="implementationHints"> + * <h4 class="implementationHints">Hints:</h4> + * + * <ul> + * <li>{@link String#lastIndexOf(int)} allows for searching the last occurrence of the filename period + * separator character <code>'.'</code>.</li> + * + * <li>{@link String#substring(int, int)} allows for selecting portions of a string by means of from and to + * index values.</li> + * </ul> + * + * </section> + * + * @param filename A non-null file name string. + * @param backupExtension The desired extension string to be inserted / appended. + * + * @return The backup file's name. + */ + static public String createBackupFilename(final String filename, final String backupExtension) { + return "blahblahblah"; // Implement me correctly + } + + private B_Backup(){/* Ignore me: My sole purpose is suppressing default constructor javadoc generation */} + +} diff --git a/Klausuren/Sd1/2022winter/Exam/src/main/java/de/hdm_stuttgart/mi/sd1/task1/C_Range.java b/Klausuren/Sd1/2022winter/Exam/src/main/java/de/hdm_stuttgart/mi/sd1/task1/C_Range.java new file mode 100644 index 0000000000000000000000000000000000000000..bf03419fe2fe33bb50aebf2ea31ec4fe83b31c9e --- /dev/null +++ b/Klausuren/Sd1/2022winter/Exam/src/main/java/de/hdm_stuttgart/mi/sd1/task1/C_Range.java @@ -0,0 +1,85 @@ +package de.hdm_stuttgart.mi.sd1.task1; + +/** + * <p>Handling integer ranges</p> + */ +public class C_Range { + + /** + * <p>Displaying a range of integer values.</p> + * + * <p>Integer ranges being defined by [start, end] (inclusive) shall be displayed in a user friendly way:</p> + * + * <ul> + * <li>Up to a range of four all values shall be displayed.</li> + * <li>Starting from five values onwards only the first, second and last value shall be visible with »...« + * denoting intermediate values being omitted on display</li> + * </ul> + * + * <p>We provide some samples:</p> + * + * <table class="goikTableDefaults"> + * <caption>Display of ranges</caption> + * <tbody> + * <tr> + * <th>Range</th> + * <th>Display</th> + * <th>Explanation</th> + * </tr> + * <tr> + * <td> + * <pre><code class="nohighlight">[5, 5]</code></pre> + * </td> + * <td> + * <pre><code class="nohighlight">"5"</code></pre> + * </td> + * <td>Start equals end, just one value.</td> + * </tr> + * <tr> + * <td> + * <pre><code class="nohighlight">[1, 3]</code></pre> + * </td> + * <td> + * <pre><code class="nohighlight">"1, 2, 3"</code></pre> + * </td> + * <td>Less than five elements, showing all values</td> + * </tr> + * <tr> + * <td> + * <pre><code class="nohighlight">[-2, 7]</code></pre> + * </td> + * <td> + * <pre><code class="nohighlight">"-2, -1, ..., 7"</code></pre> + * </td> + * <td>More than four elements thus using dots.</td> + * </tr> + * </tbody> + * </table> + * + * <section class="implementationHints"> + * <h4 class="implementationHints">Hint:</h4> + * + * <p>Be careful with respect to relentless unit tests! The following two display strings differ by + * space (<code>' '</code>) characters:</p> + * + * <pre> "1,2,3" + * "1, 2, 3"</pre> + * + * <p>Denoting invisible spaces by »<span style='color:red;font-weight:bold;'>⎵</span>« the intended display value + * explicitly reads:</p> + * + * <pre> <code class="nohighlight">1,<span style='color:red;font-weight:bold;'>⎵</span>2,<span style='color:red;font-weight:bold;'>⎵</span>3</code></pre> + * + * </section> + * + * @param start The range's lowest value. Must be smaller than or equal to end. + * @param end The range's highest value. Must be larger or equal to start. + * + * @return A range describing string. + * + */ + static public String displayRange(int start, int end) { + return "blahblahblah"; // Implement me correctly + } + private C_Range(){/* Ignore me: My sole purpose is suppressing default constructor javadoc generation */} +} diff --git a/Klausuren/Sd1/2022winter/Exam/src/main/java/de/hdm_stuttgart/mi/sd1/task1/D_Clump.java b/Klausuren/Sd1/2022winter/Exam/src/main/java/de/hdm_stuttgart/mi/sd1/task1/D_Clump.java new file mode 100644 index 0000000000000000000000000000000000000000..7c4e4ec4eb53b7e050fbbcd352f96eaea99513a7 --- /dev/null +++ b/Klausuren/Sd1/2022winter/Exam/src/main/java/de/hdm_stuttgart/mi/sd1/task1/D_Clump.java @@ -0,0 +1,78 @@ +package de.hdm_stuttgart.mi.sd1.task1; + + +/** + * <p>Getting clumps in array values.</p> + */ +public class D_Clump { + + /** + * <p>Finding the number of clumps of identical values.</p> + * + * <p>A group of at least two mutually adjacent array members of identical value is being called a clump. Example:</p> + * + * <p>{0, <span style='color:red;font-weight:bold;'>-1, -1</span>, 3, 2, <span style='color:red;font-weight:bold;'>4, 4, 4</span>}</p> + * + * <p>This array harbours two clumps <code style='color:red;font-weight:bold;'>-1, -1</code> and + * <code style='color:red;font-weight:bold;'>4, 4, 4</code> of adjacent identical values. Its clump count is + * thus 2. Some more examples:</p> + * + * <table class="goikTableDefaults"> + * <caption>Clump count examples</caption> + * <tbody> + * <tr> + * <th>Array</th> + * <th>Clump count</th> + * </tr> + * <tr> + * <td><code>null</code></td> + * <td>0</td> + * </tr> + * <tr> + * <td><code>{}</code></td> + * <td>0</td> + * </tr> + * <tr> + * <td><code>{4}</code></td> + * <td>0</td> + * </tr> + * <tr> + * <td><code>{4, -3, 4}</code></td> + * <td>0</td> + * </tr> + * <tr> + * <td><code>{0, <span style='color:red;font-weight:bold;'>9, 9</span>}</code></td> + * <td>1</td> + * </tr> + * <tr> + * <td><code>{<span style='color:red;font-weight:bold;'>-1, -1, -1</span>, 5, <span style='color:red;font-weight:bold;'>-1, -1, -1</span>, 4, <span style='color:red;font-weight:bold;'>3, 3, 3</span>}</code></td> + * <td>3</td> + * </tr> + * <tr> + * <td><code>{<span style='color:red;font-weight:bold;'>3, 3, 3, 3, 3, 3, 3, 3</span>}</code></td> + * <td>1</td> + * </tr> + * </tbody> + * </table> + * + * <section class="implementationHints"> + * <h4 class="implementationHints">Hints:</h4> + * + * <ul> + * <li>You'll receive points for handling special cases e.g. <code>null</code> and + * <code>{ }</code>.</li> + * </ul> + * + * </section> + * + * @param values Integer values or <code>null</code> being treated like an empty array. + * + * @return The number of clumps containing neighbouring identical values or zero for an array value of + * <code class="java">null</code>. + */ + static public int getClumpCount(final int[] values) { + return -42; // Implement me correctly + } + + private D_Clump(){/* Ignore me: My sole purpose is suppressing default constructor javadoc generation */} +} diff --git a/Klausuren/Sd1/2022winter/Exam/src/main/java/de/hdm_stuttgart/mi/sd1/task1/package-info.java b/Klausuren/Sd1/2022winter/Exam/src/main/java/de/hdm_stuttgart/mi/sd1/task1/package-info.java new file mode 100644 index 0000000000000000000000000000000000000000..fb7bb58c281c72e0241b31061906c3bf633172d2 --- /dev/null +++ b/Klausuren/Sd1/2022winter/Exam/src/main/java/de/hdm_stuttgart/mi/sd1/task1/package-info.java @@ -0,0 +1,17 @@ +/** + * <p>This package mostly (if not completely) contains static methods.</p> + * + * <p>The ordering being implied by class names reflects the author's opinion with respect to ascending implementation + * difficulty. Hints:</p> + * + * <ul> + * <li>Run <code>mvn javadoc:javadoc</code> and open the generated + * <code>/home/.../target/site/apidocs/index.html</code> file in your browser of choice.</li> + * + * <li>Use the corresponding unit tests to check your implementation's consistency and class + * <code>de.hdm_stuttgart.mi.sd1.test.ShowReachedPoints</code> from your project's “unit test†branch.</li> + * + * </ul> + * + */ +package de.hdm_stuttgart.mi.sd1.task1; \ No newline at end of file diff --git a/Klausuren/Sd1/2022winter/Exam/src/main/java/de/hdm_stuttgart/mi/sd1/task2/BatteryPlanner.java b/Klausuren/Sd1/2022winter/Exam/src/main/java/de/hdm_stuttgart/mi/sd1/task2/BatteryPlanner.java new file mode 100644 index 0000000000000000000000000000000000000000..10fb95992d37fda6308f3540d5cefb9ae37f5bf8 --- /dev/null +++ b/Klausuren/Sd1/2022winter/Exam/src/main/java/de/hdm_stuttgart/mi/sd1/task2/BatteryPlanner.java @@ -0,0 +1,115 @@ +package de.hdm_stuttgart.mi.sd1.task2; + +/** + * <p>Simulating driving a car, draining and charging its battery.</p> + * + * <p>An electric car's driving range is being determined by:</p> + * + * <ul> + * <li>The battery's state of charge measured in kilowatt hours (kwh). A battery + * does have a capacity e.g. 50 Kwh. </li> + * <li>Its weight and other factors allow for a given number of kilometer per 1 Kwh. </li> + * </ul> + * + * <p>Example: A car delivering 200 km before completely draining a battery of 50 kwh requires + * 1 Kwh per 4Km of driving. We show some samples using the simulator class.</p> + * + * <table class="goikTableDefaults"> + * <caption>Creating a simulator of 50 Kwh capacity and 4 Km per 1 Kwh driving range</caption> + * <tbody> + * <tr> + * <th>Code</th> + * <th>Result</th> + * </tr> + * <tr> + * <td> + * <pre><code class="java"> // fully charged 50 Kwh battery capacity, 4 Km per 1 Kwh driving range + * BatteryPlanner planner = new BatteryPlanner(50, 4); // int arguments! + * + * // Get battery state of charge category + * System.out.println(planner.getState());</code></pre> + * </td> + * <td> + * <pre>HIGH</pre> + * <p>Fully charged, see {@link BatteryState}</p> + * </td> + * </tr> + * </tbody> + * </table> + * + * <p>These charging state categories are being defined by the battery's state of charge in relation to its capacity:</p> + * + * <ul> + * <li> 0 <= percentage < 10% : {@link BatteryState#LOW}</li> + * <li> 10 <= percentage < 90% : {@link BatteryState#NORMAL}</li> + * <li> 90 <= percentage <= 100% : {@link BatteryState#HIGH}</li> + * </ul> + * + * + * <p>Driving a car drains the battery:</p> + * + * <table class="goikTableDefaults"> + * <caption>Driving a fully charged car</caption> + * <tbody> + * <tr> + * <th>Code</th> + * <th>Result</th> + * </tr> + * <tr> + * <td> + * <pre><code class="java"> //... + * // Drive 150 Km of 50 Km x 4 = 200 Km driving range + * double actualDistance = planner.drive(150.0); + * System.out.println("Actual distance: " + actualDistance); + * + * // Trying to drive another 200 Km, but only 50 are left by battery power + * actualDistance = planner.drive(200.0); + * System.out.println("Actual distance: " + actualDistance); + * + * // Battery completely drained + * System.out.println("Battery state of charge: " + planner.getState());</code></pre> + * </td> + * <td> + * <pre> Actual distance: 150.0 + * Actual distance: 50.0 + * Battery state of charge: LOW</pre> + * </td> + * </tr> + * </tbody> + * </table> + * + * <p>Now recharging is being required:</p> + * + * <table class="goikTableDefaults"> + * <caption>Charging the battery</caption> + * <tbody> + * <tr> + * <th>Code</th> + * <th>Result and explanation</th> + * </tr> + * <tr> + * <td> + * <pre><code class="java"> // ... starting from previous empty battery ... + * double excess = planner.charge(30.0); + * System.out.println("Excess:" + excess); + * + * excess = planner.charge(50.0); + * System.out.println("Excess:" + excess);</code></pre> + * </td> + * <td> + * <pre> Excess:-20.0 + * Excess:30.0</pre> + * <ul> + * <li>-20 indicating 20 Kwh lacking to fully charged state.</li> + * <li>30 Kwh indicating that 30 Kwh out of 50 Kwh offered exceed the + * battery's capacity.</li> + * </ul> + * </td> + * </tr> + * </tbody> + * </table> + * + */ +public class BatteryPlanner { + // Implement me +} diff --git a/Klausuren/Sd1/2022winter/Exam/src/main/java/de/hdm_stuttgart/mi/sd1/task2/BatteryState.java b/Klausuren/Sd1/2022winter/Exam/src/main/java/de/hdm_stuttgart/mi/sd1/task2/BatteryState.java new file mode 100644 index 0000000000000000000000000000000000000000..d2f562017130132335c7827bf91f09ab0674deee --- /dev/null +++ b/Klausuren/Sd1/2022winter/Exam/src/main/java/de/hdm_stuttgart/mi/sd1/task2/BatteryState.java @@ -0,0 +1,20 @@ +package de.hdm_stuttgart.mi.sd1.task2; + +/** + * Describing a battery's state of charge categories. You may modify this enum. + */ +public enum BatteryState { + + /** + * State of charge is below 10% of the battery's capacity. + */ + LOW, + /** + * State of charge is in between and including 10% and 90% of the battery's capacity. + */ + NORMAL, + /** + * State of charge is above 90% of the battery's capacity. + */ + HIGH; +} diff --git a/Klausuren/Sd1/2022winter/Exam/src/main/javadoc/resources/fonts/dejavu.css b/Klausuren/Sd1/2022winter/Exam/src/main/javadoc/resources/fonts/dejavu.css new file mode 100644 index 0000000000000000000000000000000000000000..4fec2b593cdcc719fd7edd6744a33a3395ca8401 --- /dev/null +++ b/Klausuren/Sd1/2022winter/Exam/src/main/javadoc/resources/fonts/dejavu.css @@ -0,0 +1,3 @@ +/* shame on you, javadoc! Still providing +@import url('resources/fonts/dejavu.css') line in stylesheet.css +*/ \ No newline at end of file diff --git a/Klausuren/Sd1/2022winter/Exam/src/main/javadoc/resources/jdocSupplement.css b/Klausuren/Sd1/2022winter/Exam/src/main/javadoc/resources/jdocSupplement.css new file mode 100644 index 0000000000000000000000000000000000000000..08840cdbf55d1f43368245d0a965659c4411b2ee --- /dev/null +++ b/Klausuren/Sd1/2022winter/Exam/src/main/javadoc/resources/jdocSupplement.css @@ -0,0 +1,72 @@ +/* Javadoc extensions: */ + +ul > li > ul { + list-style-type: circle; +} + +table.goikTableDefaults, +table.goikTableDefaults>caption, +table.goikTableDefaults>tr>th, +table.goikTableDefaults>tr>td, +table.goikTableDefaults>tbody>tr>th, +table.goikTableDefaults>tbody>tr>td { + border: 2px solid black; + border-collapse: collapse; + padding: 1ex; + vertical-align: top; +} + +table.goikTableDefaults>caption { + /* border-top-style: solid; border-left-style: solid; border-right-style: solid' */ + border-bottom-style: none; + font-weight: bold; + background:#dee3e9; + text-align:left; + padding:8px 3px 3px 7px; +} + +table.goikTableDefaults>tbody>tr>td { + vertical-align:top; +} +table.goikTableDefaults { + border-spacing: 0px !important; +} + +table.indexTable { + border-collapse: collapse; + border-style: hidden; +} + +table.indexTable caption { + text-align: left; +} + +table.indexTable td, table.indexTable th { + border: 1px solid black; + padding: 0.5ex; +} + +em { + font-weight: bold; + font-style: normal; +} +section.implementationHints>h3 { + font-weight: bold; + background-color: rgb(222, 227, 233); +} + +code { + white-space: pre; +} + +.implementationHints { + background-color: hsl(120, 100%, 95%) !important; +} + +.myRed { + color: red; +} + +.myGreen { + color: limegreen; +} diff --git a/Klausuren/Sd1/2022winter/Exam/src/main/javadoc/resources/jdocSupplement.js b/Klausuren/Sd1/2022winter/Exam/src/main/javadoc/resources/jdocSupplement.js new file mode 100644 index 0000000000000000000000000000000000000000..97911e5581090aac5e37323427450f8c8c8a3f94 --- /dev/null +++ b/Klausuren/Sd1/2022winter/Exam/src/main/javadoc/resources/jdocSupplement.js @@ -0,0 +1,7 @@ +for(var i in document.links) { + var link = document.links[i]; + if (link.href && link.href.indexOf('http') === 0) { + link.target = '_blank'; + } +} + diff --git a/Klausuren/Sd1/2022winter/Exam/src/main/resources/log4j2.xml b/Klausuren/Sd1/2022winter/Exam/src/main/resources/log4j2.xml new file mode 100644 index 0000000000000000000000000000000000000000..130f87a144c4eb0107a846e580c8fa7f5e819fc1 --- /dev/null +++ b/Klausuren/Sd1/2022winter/Exam/src/main/resources/log4j2.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="UTF-8"?> +<Configuration> + <Appenders> + <File name="A1" fileName="A1.log" append="false"> + <PatternLayout pattern="%t %-5p %c{2} - %m%n"/> + </File> + <Console name="STDOUT" target="SYSTEM_OUT"> + <PatternLayout pattern="%d %-5p [%t] %C{2} (%F:%L) - %m%n"/> + </Console> + </Appenders> + <Loggers> + + <!-- You my want to define class or package level per-logger rules --> + <Logger name="de.hdm_stuttgart.mi.sd1.App" level="debug"> + <AppenderRef ref="A1"/> + </Logger> + <Root level="info"> + <AppenderRef ref="STDOUT"/> + </Root> + </Loggers> +</Configuration> \ No newline at end of file diff --git a/Klausuren/Sd1/2022winter/Exam/src/test/java/de/hdm_stuttgart/mi/sd1/ShowReachedPoints.java b/Klausuren/Sd1/2022winter/Exam/src/test/java/de/hdm_stuttgart/mi/sd1/ShowReachedPoints.java new file mode 100644 index 0000000000000000000000000000000000000000..23a37acb9ebfda05710206f5c4e439ae5b576094 --- /dev/null +++ b/Klausuren/Sd1/2022winter/Exam/src/test/java/de/hdm_stuttgart/mi/sd1/ShowReachedPoints.java @@ -0,0 +1,22 @@ +package de.hdm_stuttgart.mi.sd1; + +import de.hdm_stuttgart.mi.exam.unitmarking.RunTests; + +import de.hdm_stuttgart.mi.sd1.task1.*; +import de.hdm_stuttgart.mi.sd1.task2.TestBatteryPlanner; + +public class ShowReachedPoints { + + /** + * Revealing total number of reached points fromm all tasks. + * + * @param args Unused + */ + public static void main(String[] args) { + RunTests.exec( + "Task 1" + , A_PartyTest.class, B_BackupTest.class, C_RangeTest.class, D_ClumpTest.class + ); + RunTests.exec("Task 2", TestBatteryPlanner.class); + } +} \ No newline at end of file diff --git a/Klausuren/Sd1/2022winter/Exam/src/test/java/de/hdm_stuttgart/mi/sd1/ignore_me/ObjectWrapper.java b/Klausuren/Sd1/2022winter/Exam/src/test/java/de/hdm_stuttgart/mi/sd1/ignore_me/ObjectWrapper.java new file mode 100644 index 0000000000000000000000000000000000000000..1ed49868d156121e9a440e00ebb2d03dc56988c0 --- /dev/null +++ b/Klausuren/Sd1/2022winter/Exam/src/test/java/de/hdm_stuttgart/mi/sd1/ignore_me/ObjectWrapper.java @@ -0,0 +1,270 @@ +package de.hdm_stuttgart.mi.sd1.ignore_me; + +import org.junit.Assert; + +import java.lang.reflect.*; +import java.util.Arrays; +import java.util.StringJoiner; +import java.util.stream.Collectors; + +public class ObjectWrapper<T> { + + private final Class classz; + private final T instance; + + static public void assertFinal(final Class classZ, final String fieldName) { + try { + final int modifier = classZ.getDeclaredField(fieldName).getModifiers(); + Assert.assertTrue("»" + fieldName + "« can be modified, no immutable!", Modifier.isFinal(modifier)); + + } catch (NoSuchFieldException e) { + Assert.fail("No such field »" + fieldName + "«"); + } + } + + public ObjectWrapper(final Class<T> classz, final Object ... parameter) { + this.classz = classz; + T tmpInstance = null; + final Constructor<?>[] candidates = Arrays. + stream(classz.getDeclaredConstructors()). + filter(c -> matchesArgumentList(c, parameter)). + toArray(Constructor<?>[]::new); + if (0 == candidates.length) { + Assert.fail("No suitable constructor in class »" + classz.getName() + "« matching arguments »(" + + Arrays.stream(parameter).map(Object::toString).collect(Collectors.joining(", ")) + + ")«"); + } else if (1 < candidates.length) { + Assert.fail("Multiple constructor matches due to ambiguous signature"); + } else { + try { + tmpInstance = (T) candidates[0].newInstance( + Arrays.stream(parameter).toArray()); + } catch (final IllegalAccessException e) { + Assert.fail("Unable to instantiate instance of class »" + classz.getName() + "«:\n" + + "Cannot access constructor " + candidates[0].toString()); + } catch (Exception e) { + Assert.fail("Unable to instantiate instance of class »" + classz.getName() + "«:\n "+ e); + } + } + instance = tmpInstance; + } + + public ObjectWrapper(final Class<T> classz, final Class<? extends Throwable> expectedException, final Object ... parameter) { + this.classz = classz; + T tmpInstance = null; + final Constructor<?>[] candidates = Arrays. + stream(classz.getConstructors()). + filter(c -> matchesArgumentList(c, parameter)). + toArray(Constructor<?>[]::new); + if (0 == candidates.length) { + Assert.fail("No suitable constructor in class »" + classz.getName() + "« matching arguments »(" + + Arrays.stream(parameter).map(Object::toString).collect(Collectors.joining(", ")) + + ")«"); + } else if (1 < candidates.length) { + Assert.fail("Multiple constructor matches due to ambiguous signature"); + } else { + try { + tmpInstance = (T) candidates[0].newInstance( + Arrays.stream(parameter).toArray()); + Assert.fail("Expected exception of type »" + expectedException.getName() + "« to be thrown"); + } catch (InstantiationException|IllegalAccessException|IllegalArgumentException|InvocationTargetException e) { + if (e.getCause().getClass() != expectedException) { + Assert.fail("Unable to instantiate: " + e + ", cause:\n Expected exception of type »" + + expectedException.getName() + "« but was »"+ e.getCause().getClass().getName() + "«"); + } + } + } + instance = tmpInstance; + } + + public <R> void assertFieldExists(final Class<R> valueType, final String name) { + try { + final Field field = classz.getField(name); + if (!valueType.equals(field.getType())) { + Assert.fail("Field »" + name + "« in class »" + classz.getName() + "« is not of type »" + + valueType.getName() + "«"); + } + } catch (final NoSuchFieldException e) { + Assert.fail("No such field »" + name + "« in class »" + classz.getName() + "«"); + } + } + + public <R> R get(final Class<R> valueType, final String name) { + + try { + final Field field = classz.getField(name); + if (valueType.equals(field.getType())) { + return (R) field.get(instance); + } else { + Assert.fail("Field »" + name + "« in class »" + classz.getName() + "« is not of type »" + + valueType.getName() + "«"); + } + } catch (final NoSuchFieldException e) { + Assert.fail("No such field »" + name + "« in class »" + classz.getName() + "«"); + } catch (final IllegalAccessException e) { + Assert.fail("Unable to access field »" + name + "« in class »" + classz.getName() + "«: " + e.getMessage()); + } + return null; + } + public void set(final String name, final Object value) { + + try { + final Field field = classz.getField(name); + final Class argumentType = value.getClass(); + if (field.getType().equals(argumentType) || + field.getType().equals(getPrimitiveType(argumentType))){ + field.set(instance, value); + } else { + Assert.fail("Field »" + name + "« in class »" + classz.getName() + "« is not of type »" + + argumentType.getName() + "«"); + } + } catch (final NoSuchFieldException e) { + Assert.fail("No such field »" + name + "« in class »" + classz.getName() + "«"); + } catch (final IllegalAccessException e) { + Assert.fail("Unable to access field »" + name + "« in class »" + classz.getName() + "«: " + e.getMessage()); + } + } + + public <R> R invoke(final Class<R> returnType, final String name, final Object ... parameter) { + + final Method[] candidates = Arrays. + stream(classz.getDeclaredMethods()). + filter(m-> m.getName().equals(name) && matchesArgumentList(m, parameter)). + toArray(Method[]::new); + + if (0 == candidates.length) { + Assert.fail("No suitable method " + getSignature(returnType, name, parameter) + + " found"); + } else if (1 < candidates.length) { + Assert.fail("Multiple method matches due to ambiguous signature"); + } else { + final Method method = candidates[0]; + if (method.getReturnType().equals(returnType)) { + try { + return (R) method.invoke(instance, parameter); + } catch (final IllegalAccessException e) { + Assert.fail("Unable to execute existing method: »" + method.toString() + "«"); + }catch (final IllegalArgumentException|InvocationTargetException e) { + Assert.fail("Unable to execute existing method: »" + method.toString() + "«\n" + + e + ", cause:" + e.getCause()); + } + } else { + Assert.fail("Method »" + method.getName() + "« does have return type »" + method.getReturnType() + "«" + + "rather then »" + returnType.getName() + "«"); + } + } + return null; + } + + private <R> StringBuilder getSignature(final Class<R> returnType, final String name, final Object ... parameter) { + + final StringBuilder ret = new StringBuilder(); + appendType(returnType, ret); + + return ret.append(' ').append(name).append('(') + .append(Arrays.stream(parameter).map(this::appendObjectsType).collect(Collectors.joining(", "))) + .append(')'); + } + + private StringBuilder appendObjectsType (final Object object) { + final StringBuilder builder = new StringBuilder(); + if (null == object) { + builder.append("null"); + } else { + appendType(object.getClass(), builder); + } + return builder; + } + + private <R> void appendType(final Class<R> type, StringBuilder result) { + + if (type.isArray()) { + final Class <?> componentType = type.getComponentType(); + result.append(componentType.getName()).append("[]"); + } else { + result.append(type.getName()); + } + } + + public <R> R invoke(final Class<R> returnType, final String name, + final Class<? extends Throwable> expectedException, final Object ... parameter) { + + final Method[] candidates = Arrays. + stream(classz.getMethods()). + filter(m-> m.getName().equals(name) && matchesArgumentList(m, parameter)). + toArray(Method[]::new); + + if (0 == candidates.length) { + Assert.fail("No suitable method found"); + } else if (1 < candidates.length) { + Assert.fail("Multiple method matches due to ambiguous signature"); + } else { + final Method method = candidates[0]; + if (method.getReturnType().equals(returnType)) { + try { + R ret = (R) method.invoke(instance, parameter); + Assert.fail("Expected exception of type »" + expectedException.getName() + "«"); + return ret; + } catch (final IllegalAccessException| IllegalArgumentException|InvocationTargetException e) { + if (e.getCause().getClass() != expectedException) { + Assert.fail("Unable to execute method: " + e + ", cause:\n Expected exception of type »" + + expectedException.getName() + "« but was »"+ e.getCause().getClass().getName() + "«"); + } + } + } else { + Assert.fail("Method »" + method.getName() + "« does have return type »" + method.getReturnType() + "«" + + "rather then »" + returnType.getName() + "«"); + } + } + return null; + } + + /** + * Check for a given array of objects matching an {@link Executable}'s argument list. + * + * @param executable + * @param parameter + * @return <code>true</code> if parameters match the {@link Executable}'s argument list, <code>false</code> + * otherwise. + */ + private boolean matchesArgumentList(final Executable executable, final Object ... parameter) { + + if (executable.getParameterCount() != parameter.length) { + return false; + } else { + final Class<?>[] formalArgumentTypes = executable.getParameterTypes(); + for (int i = 0; i < formalArgumentTypes.length; i++) { + final Class parametersClass = parameter[i].getClass(); + + if (!formalArgumentTypes[i].equals(parametersClass) && + !formalArgumentTypes[i].equals(getPrimitiveType(parametersClass))) { + return false; + } + } + } + return true; + } + + static private Class<?> getPrimitiveType (final Class<?> in) { + if (in.equals(Byte.class)) { + return byte.class; + } else if (in.equals(Short.class)) { + return short.class; + } else if (in.equals(Integer.class)) { + return int.class; + } else if (in.equals(Long.class)) { + return long.class; + } else if (in.equals(Float.class)) { + return float.class; + } else if (in.equals(Double.class)) { + return double.class; + } else if (in.equals(Boolean.class)) { + return boolean.class; + } else if (in.equals(Character.class)) { + return char.class; + } else { + return in; // Type is no primitive + } + } + +} diff --git a/Klausuren/Sd1/2022winter/Exam/src/test/java/de/hdm_stuttgart/mi/sd1/task1/A_PartyTest.java b/Klausuren/Sd1/2022winter/Exam/src/test/java/de/hdm_stuttgart/mi/sd1/task1/A_PartyTest.java new file mode 100644 index 0000000000000000000000000000000000000000..3bd60fa702a305825fdc6e51cdf9ab676b10601d --- /dev/null +++ b/Klausuren/Sd1/2022winter/Exam/src/test/java/de/hdm_stuttgart/mi/sd1/task1/A_PartyTest.java @@ -0,0 +1,47 @@ +package de.hdm_stuttgart.mi.sd1.task1; + +import de.hdm_stuttgart.mi.exam.unitmarking.ExaminationTestDefaults; +import de.hdm_stuttgart.mi.exam.unitmarking.Marking; +import org.junit.Assert; +import org.junit.FixMethodOrder; +import org.junit.Test; +import org.junit.runners.MethodSorters; + +import static de.hdm_stuttgart.mi.sd1.task1.A_Party.getInvitation; + + +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +public class A_PartyTest extends ExaminationTestDefaults { + + @Test + @Marking(points = 20) + public void test_100() { + Assert.assertFalse( getInvitation(false, false, -10)); + Assert.assertFalse( getInvitation(false, false, 0)); + Assert.assertFalse( getInvitation(false, false, 10)); + Assert.assertFalse( getInvitation(false, false, 19999)); + Assert.assertFalse( getInvitation(false, false, 20000)); + Assert.assertFalse( getInvitation(false, false, 20001)); + + Assert.assertFalse( getInvitation(false, true, -10)); + Assert.assertFalse( getInvitation(false, true, 0)); + Assert.assertFalse( getInvitation(false, true, 10)); + Assert.assertFalse( getInvitation(false, true, 19999)); + Assert.assertTrue( getInvitation(false, true, 20000)); + Assert.assertTrue( getInvitation(false, true, 20001)); + + Assert.assertTrue( getInvitation(true, false, -10)); + Assert.assertTrue( getInvitation(true, false, 0)); + Assert.assertTrue( getInvitation(true, false, 10)); + Assert.assertTrue( getInvitation(true, false, 19999)); + Assert.assertTrue( getInvitation(true, false, 20000)); + Assert.assertTrue( getInvitation(true, false, 20001)); + + Assert.assertTrue( getInvitation(true, true, -10)); + Assert.assertTrue( getInvitation(true, true, 0)); + Assert.assertTrue( getInvitation(true, true, 10)); + Assert.assertTrue( getInvitation(true, true, 19999)); + Assert.assertTrue( getInvitation(true, true, 20000)); + Assert.assertTrue( getInvitation(true, true, 20001)); + } +} diff --git a/Klausuren/Sd1/2022winter/Exam/src/test/java/de/hdm_stuttgart/mi/sd1/task1/B_BackupTest.java b/Klausuren/Sd1/2022winter/Exam/src/test/java/de/hdm_stuttgart/mi/sd1/task1/B_BackupTest.java new file mode 100644 index 0000000000000000000000000000000000000000..ce60f1d69393523a7169b92106662a3e466eca9b --- /dev/null +++ b/Klausuren/Sd1/2022winter/Exam/src/test/java/de/hdm_stuttgart/mi/sd1/task1/B_BackupTest.java @@ -0,0 +1,34 @@ +package de.hdm_stuttgart.mi.sd1.task1; + +import de.hdm_stuttgart.mi.exam.unitmarking.ExaminationTestDefaults; +import de.hdm_stuttgart.mi.exam.unitmarking.Marking; +import org.junit.Assert; +import org.junit.FixMethodOrder; +import org.junit.Test; +import org.junit.runners.MethodSorters; + +import static de.hdm_stuttgart.mi.sd1.task1.B_Backup.createBackupFilename; + +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +public class B_BackupTest extends ExaminationTestDefaults { + + @Test + @Marking(points = 5) + public void test_100_noExtension() { + Assert.assertEquals("starter_backup", createBackupFilename("starter", "_backup")); + Assert.assertEquals("ab", createBackupFilename("a", "b")); + } + + @Test + @Marking(points = 5) + public void test_200_singleExtension() { + Assert.assertEquals("calc-b.ods", createBackupFilename("calc.ods", "-b")); + Assert.assertEquals("backup.config", createBackupFilename(".config", "backup")); + } + + @Test + @Marking(points = 2) + public void test_300_multipleExtensions() { + Assert.assertEquals("file.b.c+backup.d", createBackupFilename("file.b.c.d", "+backup")); + } +} diff --git a/Klausuren/Sd1/2022winter/Exam/src/test/java/de/hdm_stuttgart/mi/sd1/task1/C_RangeTest.java b/Klausuren/Sd1/2022winter/Exam/src/test/java/de/hdm_stuttgart/mi/sd1/task1/C_RangeTest.java new file mode 100644 index 0000000000000000000000000000000000000000..7961d5a90dd81a37bff97b3ee1b7523b1d47903a --- /dev/null +++ b/Klausuren/Sd1/2022winter/Exam/src/test/java/de/hdm_stuttgart/mi/sd1/task1/C_RangeTest.java @@ -0,0 +1,38 @@ +package de.hdm_stuttgart.mi.sd1.task1; + +import de.hdm_stuttgart.mi.exam.unitmarking.ExaminationTestDefaults; +import de.hdm_stuttgart.mi.exam.unitmarking.Marking; +import org.junit.Assert; +import org.junit.FixMethodOrder; +import org.junit.Test; +import org.junit.runners.MethodSorters; + +import static de.hdm_stuttgart.mi.sd1.task1.C_Range.displayRange; + +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +public class C_RangeTest extends ExaminationTestDefaults { + + @Test + @Marking(points = 6) + public void test_100_single() { + Assert.assertEquals("-5", displayRange(-5, -5)); + Assert.assertEquals("1111", displayRange(1111, 1111)); + } + + @Test + @Marking(points = 3) + public void test_200_four() { + Assert.assertEquals("1", displayRange(1, 1)); + Assert.assertEquals("-1, 0", displayRange(-1, 0)); + Assert.assertEquals("4, 5, 6", displayRange(4, 6)); + Assert.assertEquals("-10, -9, -8, -7", displayRange(-10, -7)); + } + + + @Test + @Marking(points = 2) + public void test_300_dots() { + Assert.assertEquals("1, 2, ..., 5", displayRange(1, 5)); + Assert.assertEquals("-20, -19, ..., 10", displayRange(-20, 10)); + } +} diff --git a/Klausuren/Sd1/2022winter/Exam/src/test/java/de/hdm_stuttgart/mi/sd1/task1/D_ClumpTest.java b/Klausuren/Sd1/2022winter/Exam/src/test/java/de/hdm_stuttgart/mi/sd1/task1/D_ClumpTest.java new file mode 100644 index 0000000000000000000000000000000000000000..087fcfedcbd46bc780b2c1c7b1a69cbbf4be01a2 --- /dev/null +++ b/Klausuren/Sd1/2022winter/Exam/src/test/java/de/hdm_stuttgart/mi/sd1/task1/D_ClumpTest.java @@ -0,0 +1,83 @@ +package de.hdm_stuttgart.mi.sd1.task1; + +import de.hdm_stuttgart.mi.exam.unitmarking.ExaminationTestDefaults; +import de.hdm_stuttgart.mi.exam.unitmarking.Marking; +import org.junit.Assert; +import org.junit.FixMethodOrder; +import org.junit.Test; +import org.junit.runners.MethodSorters; + +import static de.hdm_stuttgart.mi.sd1.task1.D_Clump.getClumpCount; +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +public class D_ClumpTest extends ExaminationTestDefaults { + + @Test + public void test_20_null() { + Assert.assertEquals(0, getClumpCount(null)); + } + @Test + public void test_40_empty() { + Assert.assertEquals(0, getClumpCount(new int[]{})); + } + + @Test + public void test_100_one() { + Assert.assertEquals(0, getClumpCount(new int[]{-5})); + } + + @Test + public void test_200_two() { + Assert.assertEquals(0, getClumpCount(new int[]{1, 0})); + Assert.assertEquals(1, getClumpCount(new int[]{-2, -2})); + } + @Test + public void test_300_three() { + Assert.assertEquals(0, getClumpCount(new int[]{1, 2, 3})); + Assert.assertEquals(1, getClumpCount(new int[]{1, 1, 3})); + Assert.assertEquals(1, getClumpCount(new int[]{-7, 4, 4})); + Assert.assertEquals(1, getClumpCount(new int[]{6, 6, 6})); + } + @Test + public void test_400_four() { + Assert.assertEquals(0, getClumpCount(new int[]{1, 2, -3, 50})); + Assert.assertEquals(1, getClumpCount(new int[]{-3, -3, 0, 30})); + Assert.assertEquals(1, getClumpCount(new int[]{-3, 7, 7, -70})); + Assert.assertEquals(1, getClumpCount(new int[]{-3, 6, 0, 0})); + Assert.assertEquals(1, getClumpCount(new int[]{4, 4, 4, 1})); + Assert.assertEquals(1, getClumpCount(new int[]{1, 7, 7, 7})); + Assert.assertEquals(1, getClumpCount(new int[]{1, 1, 1, 1})); + + Assert.assertEquals(2, getClumpCount(new int[]{1, 1, -5, -5})); + } + @Test + public void test_500_five_six() { + + // five + Assert.assertEquals(0, getClumpCount(new int[]{-6, -3, 0, 30, 1})); + + Assert.assertEquals(1, getClumpCount(new int[]{1, 1, 2, 3, 4})); + Assert.assertEquals(1, getClumpCount(new int[]{1, 2, 2, 3, 4})); + Assert.assertEquals(1, getClumpCount(new int[]{1, 2, 3, 3, 4})); + Assert.assertEquals(1, getClumpCount(new int[]{1, 2, 3, 4, 4})); + + Assert.assertEquals(1, getClumpCount(new int[]{1, 1, 1, 3, 4})); + Assert.assertEquals(1, getClumpCount(new int[]{0, 2, 2, 2, 4})); + Assert.assertEquals(1, getClumpCount(new int[]{1, 2, 3, 3, 3})); + + Assert.assertEquals(1, getClumpCount(new int[]{1, 1, 1, 1, 4})); + Assert.assertEquals(1, getClumpCount(new int[]{0, 2, 2, 2, 2})); + Assert.assertEquals(1, getClumpCount(new int[]{4, 4, 4, 4, 4})); + + Assert.assertEquals(2, getClumpCount(new int[]{-3, -3, 5, 5, 10})); + Assert.assertEquals(2, getClumpCount(new int[]{-3, 7, 7, 1, 1})); + Assert.assertEquals(2, getClumpCount(new int[]{-3, -3, 0, 10, 10})); + + // Six + Assert.assertEquals(3, getClumpCount(new int[]{0, 1, 1, 4, 7, 10, 10, 5, 9, 9, 9, 6})); + Assert.assertEquals(3, getClumpCount(new int[]{1, 1, 4, 7, 10, 10, 5, 9, 9, 9, 8})); + Assert.assertEquals(3, getClumpCount(new int[]{2, 1, 1, 4, 7, 10, 10, 5, 9, 9, 9})); + Assert.assertEquals(3, getClumpCount(new int[]{1, 1, 1, 4, 7, 10, 10, 5, 9, 9, 9})); + Assert.assertEquals(1, getClumpCount(new int[]{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1})); + Assert.assertEquals(1, getClumpCount(new int[]{3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0})); + } +} diff --git a/Klausuren/Sd1/2022winter/Exam/src/test/java/de/hdm_stuttgart/mi/sd1/task2/TestBatteryPlanner.java b/Klausuren/Sd1/2022winter/Exam/src/test/java/de/hdm_stuttgart/mi/sd1/task2/TestBatteryPlanner.java new file mode 100644 index 0000000000000000000000000000000000000000..62c0824e19472fbd2cc24f27c65cebdecfcb7c39 --- /dev/null +++ b/Klausuren/Sd1/2022winter/Exam/src/test/java/de/hdm_stuttgart/mi/sd1/task2/TestBatteryPlanner.java @@ -0,0 +1,141 @@ +package de.hdm_stuttgart.mi.sd1.task2; + +import de.hdm_stuttgart.mi.exam.unitmarking.ExaminationTestDefaults; +import de.hdm_stuttgart.mi.exam.unitmarking.Marking; +import de.hdm_stuttgart.mi.sd1.ignore_me.ObjectWrapper; +import org.junit.Assert; +import org.junit.FixMethodOrder; +import org.junit.Test; +import org.junit.runners.MethodSorters; +@FixMethodOrder(MethodSorters.NAME_ASCENDING) + +public class TestBatteryPlanner extends ExaminationTestDefaults { + + private final double deltaDistance = 1.E-14; + + /** + * Create new instance of {@link BatteryPlanner} + */ + @Test + @Marking(points = 2) + public void test_100CreateBatteryPlanner() { + new ObjectWrapper<>(BatteryPlanner.class,50, 6); + } + + /** + * Check for {@link BatteryState#HIGH} + * <ol> + * <li>Create an instance</li> + * <li></li> + * </ol> + */ + @Test + @Marking(points = 2) + public void test_200() { + final ObjectWrapper<BatteryPlanner> planner = new ObjectWrapper<>(BatteryPlanner.class,100, 5); + + // New instance is expected to be fully charged + Assert.assertSame(BatteryState.HIGH, planner.invoke(BatteryState.class, "getState")); + } + + /** + * <ol> + * <li>Create an instance</li> + * <li>Intended driving distance exceeding battery's capacity</li> + * </ol> + */ + @Test + @Marking(points = 2) + public void test_300() { + // 100 Kwh and 5 Km per 1 Kwh driving range + final ObjectWrapper<BatteryPlanner> planner = new ObjectWrapper<>(BatteryPlanner.class,100, 5); + + // Intending 600 Km of driving, reducing state of charge to 0 Kwh, actually driving just 5 x 100 Km = 500 Km + Assert.assertEquals(500., planner.invoke(double.class, "drive", 600.), deltaDistance); + } + /** + * <ol> + * <li>Create an instance</li> + * <li>Drive till completely draining battery</li> + * <li>Check for {@link BatteryState#LOW}</li> + * </ol> + */ + @Test + @Marking(points = 2) + public void test_340() { + // 100 Kwh and 5 Km per 1 Kwh driving range + final ObjectWrapper<BatteryPlanner> planner = new ObjectWrapper<>(BatteryPlanner.class,100, 5); + + // Fully charged at 100 Kwh + Assert.assertSame(BatteryState.HIGH, planner.invoke(BatteryState.class, "getState")); + + // Intending 600 Km of driving, reducing state of charge to 0 Kwh, actually driving 5 x 100 Km = 500 Km + Assert.assertEquals(500., planner.invoke(double.class, "drive", 600.), deltaDistance); + Assert.assertSame(BatteryState.LOW, planner.invoke(BatteryState.class, "getState")); + } + + /** + * <ol> + * <li>Create an instance</li> + * <li>Drive till completely draining battery</li> + * <li>Two step check for complete charging requiring battery capacity amount.</li> + * </ol> + */ + @Test + @Marking(points = 2) + public void test_360() { + // 100 Kwh and 5 Km per 1 Kwh driving range + final ObjectWrapper<BatteryPlanner> planner = new ObjectWrapper<>(BatteryPlanner.class,100, 5); + + // Intending 500 Km of driving draining battery to zero. + Assert.assertEquals(500., planner.invoke(double.class, "drive", 500.), deltaDistance); + Assert.assertSame(BatteryState.LOW, planner.invoke(BatteryState.class, "getState")); + + // Battery capacity is 100 Kwh. So charging 60 Kwh still lacks another 40 Kwh towards 100% state of charge. + Assert.assertEquals(-40., planner.invoke(double.class, "charge", 60.), deltaDistance); + + // Battery now at 60 Kwh will only consume another 40 Kwh leaving us with an excess of 30 Kwh. + Assert.assertEquals(30., planner.invoke(double.class, "charge", 70.), deltaDistance); + } + + /** + * Driving, checking, charging, repeating ... + */ + @Test + @Marking(points = 10) + public void test_800() { + // 50 Kwh and 4 Km per 1 Kwh driving range + final ObjectWrapper<BatteryPlanner> planner = new ObjectWrapper<>(BatteryPlanner.class,50, 4); + + // Fully charged at 50 Kwh + Assert.assertSame(BatteryState.HIGH, planner.invoke(BatteryState.class, "getState")); + + // Charging impossible, battery is full + Assert.assertEquals(20., planner.invoke(double.class, "charge", 20.), deltaDistance); + Assert.assertSame(BatteryState.HIGH, planner.invoke(BatteryState.class, "getState")); + + // Driving 100 Km, reducing state of charge to 25 Kwh + Assert.assertEquals(100., planner.invoke(double.class, "drive", 100.), deltaDistance); + Assert.assertSame(BatteryState.NORMAL, planner.invoke(BatteryState.class, "getState")); + + // Driving 88 Km, reducing state of charge to 3 Kwh + Assert.assertEquals(88., planner.invoke(double.class, "drive", 88.), deltaDistance); + Assert.assertSame(BatteryState.LOW, planner.invoke(BatteryState.class, "getState")); + + // Intending 20 Km of driving, reducing state of charge to 0 Kwh, actually driving 12 Km + Assert.assertEquals(12., planner.invoke(double.class, "drive", 20.), deltaDistance); + Assert.assertSame(BatteryState.LOW, planner.invoke(BatteryState.class, "getState")); + + // Charging 20 Kwh, 30 Kwh missing for complete charging. + Assert.assertEquals(-30., planner.invoke(double.class, "charge", 20.), deltaDistance); + Assert.assertSame(BatteryState.NORMAL, planner.invoke(BatteryState.class, "getState")); + + // Driving 80 Km, draining battery to zero + Assert.assertEquals(80., planner.invoke(double.class, "drive", 80.), deltaDistance); + Assert.assertSame(BatteryState.LOW, planner.invoke(BatteryState.class, "getState")); + + // Charging 60 Kwh, 10 Kwh exceeding capacity. + Assert.assertEquals(10., planner.invoke(double.class, "charge", 60.), deltaDistance); + Assert.assertSame(BatteryState.HIGH, planner.invoke(BatteryState.class, "getState")); + } +} diff --git a/Klausuren/Sd1/2022winter/Solve/pom.xml b/Klausuren/Sd1/2022winter/Solve/pom.xml new file mode 100644 index 0000000000000000000000000000000000000000..c4b4826357d7f53b4cc91e1d68d55015866fb348 --- /dev/null +++ b/Klausuren/Sd1/2022winter/Solve/pom.xml @@ -0,0 +1,113 @@ +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + + <groupId>de.hdm_stuttgart.mi.sd1</groupId> + <artifactId>sd1_2022winter_solve</artifactId> + <version>0.9</version> + <packaging>jar</packaging> + + <name>sd1_2022winter_solve</name> + + <url>https://freedocs.mi.hdm-stuttgart.de/sd1_sect_mavenCli.html</url> + + <properties> + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> + + <maven.compiler.target>17</maven.compiler.target> + <maven.compiler.source>17</maven.compiler.source> + + <freedocs.url>https://freedocs.mi.hdm-stuttgart.de</freedocs.url> + <jdk.api_17.url>${freedocs.url}/doc/openjdk-17-doc/api/</jdk.api_17.url> + <mathjax.url>${freedocs.url}/lib/MathJax/es5/tex-chtml.js</mathjax.url> + <libhighlight.url>${freedocs.url}/lib/highlight.js</libhighlight.url> + </properties> + + <repositories> + <repository> + <id>hdm-mi-internal-maven-repo</id> + <url>https://maven.mi.hdm-stuttgart.de/nexus/repository/mi-maven</url> + </repository> + </repositories> + + <dependencies> + <dependency> + <groupId>de.hdm_stuttgart.mi.exam</groupId> + <artifactId>unitmarking</artifactId> + <version>1.2</version> + </dependency> + + </dependencies> + + <build> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-compiler-plugin</artifactId> + <version>3.10.1</version> + </plugin> + + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-javadoc-plugin</artifactId> + <version>3.4.1</version> + <configuration> + <release>17</release> + <doclint>all</doclint> + <show>public</show> + <docfilessubdirs>true</docfilessubdirs> + <addStylesheets> + <stylesheet>resources/jdocSupplement.css</stylesheet> + </addStylesheets> + + <windowtitle>Exam documentation</windowtitle> + + <links> + <link>https://freedocs.mi.hdm-stuttgart.de/doc/openjdk-17-doc/api/</link> + </links> + + <additionalOptions> + <additionalOption>-html5 --allow-script-in-comments</additionalOption> + </additionalOptions> + <nohelp>true</nohelp> + + <header><![CDATA[ + <script type="text/javascript" src="${mathjax.url}"></script> + <script type="text/javascript" src="{@docRoot}/resources/jdocSupplement.js"></script> + + <link rel="stylesheet" href="${libhighlight.url}/styles/idea.min.css"> + <script src="${libhighlight.url}/highlight.min.js"></script> + <script type="text/javascript">hljs.highlightAll();</script>]]> + </header> + </configuration> + </plugin> + + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-assembly-plugin</artifactId> + <version>3.4.2</version> + <configuration> + <descriptors> + <descriptor>src/main/assembly/assembly.xml</descriptor> + </descriptors> + </configuration> + <executions> + <execution> + <id>make-assembly</id> + <phase>package</phase> + <goals> + <goal>single</goal> + </goals> + <configuration> + <archive> + <manifest> + <mainClass>de.hdm_stuttgart.mi.sd1.ShowReachedPoints</mainClass> + </manifest> + </archive> + </configuration> + </execution> + </executions> + </plugin> + </plugins> + </build> +</project> diff --git a/Klausuren/Sd1/2022winter/Solve/src/main/assembly/assembly.xml b/Klausuren/Sd1/2022winter/Solve/src/main/assembly/assembly.xml new file mode 100644 index 0000000000000000000000000000000000000000..85268e2965620878373d76337f524d8785fd0e1f --- /dev/null +++ b/Klausuren/Sd1/2022winter/Solve/src/main/assembly/assembly.xml @@ -0,0 +1,36 @@ +<assembly + xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.3" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.3 http://maven.apache.org/xsd/assembly-1.1.3.xsd"> + <id>fat-tests</id> + <formats> + <format>jar</format> + </formats> + <includeBaseDirectory>false</includeBaseDirectory> + <dependencySets> + <dependencySet> + <outputDirectory/> + <useProjectArtifact>true</useProjectArtifact> + <unpack>true</unpack> + <scope>test</scope> + </dependencySet> + </dependencySets> + <fileSets> + <fileSet> + <directory>${project.build.directory}/test-classes</directory> + <outputDirectory/> + <includes> + <include>**/*.class</include> + </includes> + <useDefaultExcludes>true</useDefaultExcludes> + </fileSet> + <fileSet> + <directory>${project.build.directory}/classes</directory> + <outputDirectory/> + <includes> + <include>**/*.class</include> + </includes> + <useDefaultExcludes>true</useDefaultExcludes> + </fileSet> + </fileSets> +</assembly> \ No newline at end of file diff --git a/Klausuren/Sd1/2022winter/Solve/src/main/java/de/hdm_stuttgart/mi/sd1/only_in_solve/Book.java b/Klausuren/Sd1/2022winter/Solve/src/main/java/de/hdm_stuttgart/mi/sd1/only_in_solve/Book.java new file mode 100644 index 0000000000000000000000000000000000000000..f9ae38b88facc475104f281dace4713281e65151 --- /dev/null +++ b/Klausuren/Sd1/2022winter/Solve/src/main/java/de/hdm_stuttgart/mi/sd1/only_in_solve/Book.java @@ -0,0 +1,25 @@ +package de.hdm_stuttgart.mi.sd1.only_in_solve; + +/** + * Intended for creating exam questions + */ +public class Book { + + /*final*/ int numberOfPages; + String title; + + /** + * Non-default constructor + * @param title Unused + * @param numberOfPages Unused + */ + public Book(final String title, final int numberOfPages) { + this.numberOfPages = numberOfPages; + this.title = title; + } + + /** + * Default constructor + */ + public Book() {} +} diff --git a/Klausuren/Sd1/2022winter/Solve/src/main/java/de/hdm_stuttgart/mi/sd1/only_in_solve/CarSimulate.java b/Klausuren/Sd1/2022winter/Solve/src/main/java/de/hdm_stuttgart/mi/sd1/only_in_solve/CarSimulate.java new file mode 100644 index 0000000000000000000000000000000000000000..314cb5cc60cafcdd7bc6d5e77d6a6837c5f13679 --- /dev/null +++ b/Klausuren/Sd1/2022winter/Solve/src/main/java/de/hdm_stuttgart/mi/sd1/only_in_solve/CarSimulate.java @@ -0,0 +1,32 @@ +package de.hdm_stuttgart.mi.sd1.only_in_solve; + +import de.hdm_stuttgart.mi.sd1.task2.BatteryPlanner; + +public class CarSimulate { + + public static void main(String[] args) { + + // fully charged 50 Kwh battery capacity, 4 Km per 1 Kwh driving range + BatteryPlanner planner = new BatteryPlanner(50, 4); + + // Drive 150 Km of 50 Km x 4 = 200 Km driving range + double actualDistance = planner.drive(150.0); + System.out.println("Actual distance: " + actualDistance); + + // Trying to drive another 200 Km, but only 50 are left by battery power + actualDistance = planner.drive(200.0); + System.out.println("Actual distance: " + actualDistance); + + // Battery completely drained + System.out.println("Battery state of charge: " + planner.getState()); + + + double excess = planner.charge(30.0); + System.out.println("Excess:" + excess); + + excess = planner.charge(50.0); + System.out.println("Excess:" + excess); + + } + +} diff --git a/Klausuren/Sd1/2022winter/Solve/src/main/java/de/hdm_stuttgart/mi/sd1/task1/A_Party.java b/Klausuren/Sd1/2022winter/Solve/src/main/java/de/hdm_stuttgart/mi/sd1/task1/A_Party.java new file mode 100644 index 0000000000000000000000000000000000000000..8f2072d32aa70ad00535ce357eacccdf6df9eb4c --- /dev/null +++ b/Klausuren/Sd1/2022winter/Solve/src/main/java/de/hdm_stuttgart/mi/sd1/task1/A_Party.java @@ -0,0 +1,36 @@ +package de.hdm_stuttgart.mi.sd1.task1; + +/** + * <p>Organizing a party.</p> + */ +public class A_Party { + /** + * <p>Choose people to invite.</p> + * + * <p>While organizing a party the host categorizes his contacts with respect to: + * + * <ul> + * <li>Being a friend.</li> + * <li>Being a customer.</li> + * <li>Past years average annual business related revenue. (Welcome to capitalism 💰 🤑)</li> + * </ul> + * + * <p>A contact will be invited if at least one of the following is true:</p> + * + * <ul> + * <li>The contact is a friend</li> + * <li>The contact is a customer giving rise to at least 20000€ of annual revenue.</li> + * + * </ul> + * @param isFriend Contact is a friend. + * @param isCustomer Contact is a customer. + * @param annualRevenue Past years average annual revenue. + * + * @return <code>true</code> if contact receives an invitation. + */ + static public boolean getInvitation(boolean isFriend, boolean isCustomer, int annualRevenue) { + return isFriend || isCustomer && 20000 <= annualRevenue; + } + + private A_Party(){/* Ignore me: My sole purpose is suppressing default constructor javadoc generation */} +} diff --git a/Klausuren/Sd1/2022winter/Solve/src/main/java/de/hdm_stuttgart/mi/sd1/task1/B_Backup.java b/Klausuren/Sd1/2022winter/Solve/src/main/java/de/hdm_stuttgart/mi/sd1/task1/B_Backup.java new file mode 100644 index 0000000000000000000000000000000000000000..d764f60238105e82c8d7a6204d382668dea4241a --- /dev/null +++ b/Klausuren/Sd1/2022winter/Solve/src/main/java/de/hdm_stuttgart/mi/sd1/task1/B_Backup.java @@ -0,0 +1,88 @@ +package de.hdm_stuttgart.mi.sd1.task1; + +/** + * Creating backup filenames + */ +public class B_Backup { + + /** + * <p>Filename extension character e.g. in <code>index<span style="color:red;">.</span>html</code> </p> + */ + static public final char EXTENSION_SEPARATOR = '.'; + + /** + * <p>Create a backup filename from a given filename and backup extension string.</p> + * + * <p>Rules:</p> + * + * <ul> + * <li> + * <p>If the given filename itself does not have an extension the backup extension string gets + * appended.</p> + * </li> + * + * <li> + * <p>In case of an extension being denoted by a period (.) the backup extension string will + * be inserted prior to the filename's extension.</p> + * </li> + * + * <li> + * <p>In case of multiple period characters only the very last one denotes an extension's beginning.</p> + * </li> + * + * </ul> + * + * <p>We provide some samples:</p> + * + * <table class="goikTableDefaults"> + * <caption>Creating a backup filename</caption> + * <tbody> + * <tr> + * <th>filename</th> + * <th>backupExtension</th> + * <th>return</th> + * </tr> + * <tr> + * <td><code>testfilename</code></td> + * <td><code style='color:red;'>_bak</code></td> + * <td><code>testfilename<span style='color:red;'>_bak</span></code></td> + * </tr> + * <tr> + * <td><code>register.docx</code></td> + * <td><code style='color:red;'>.bak</code></td> + * <td><code>register<span style='color:red;'>.bak</span>.docx</code></td> + * </tr> + * <tr> + * <td><code>.cfgfile</code></td> + * <td><code style='color:red;'>.bak</code></td> + * <td><code><span style='color:red;'>.bak</span>.cfgfile</code></td> + * </tr> + * <tr> + * <td><code>file.c.q.xml</code></td> + * <td><code style='color:red;'>-backup</code></td> + * <td><code>file.c.q<span style='color:red;'>-backup</span>.xml</code></td> + * </tr> + * </tbody> + * </table> + * + * @param filename A non-null file name string. + * @param backupExtension The desired extension string to be inserted / appended. + * + * @return The backup file's name. + */ + static public String createBackupFilename(final String filename, final String backupExtension) { + + final int separatorIndex = filename.lastIndexOf(EXTENSION_SEPARATOR); + + if (0 <= separatorIndex) { // filename does have an extension + + return filename.substring(0, separatorIndex) + .concat(backupExtension).concat(filename.substring(separatorIndex, filename.length())); + } else { // filename without extension + return filename + backupExtension; + } + } + + private B_Backup(){/* Ignore me: My sole purpose is suppressing default constructor javadoc generation */} + +} diff --git a/Klausuren/Sd1/2022winter/Solve/src/main/java/de/hdm_stuttgart/mi/sd1/task1/C_Range.java b/Klausuren/Sd1/2022winter/Solve/src/main/java/de/hdm_stuttgart/mi/sd1/task1/C_Range.java new file mode 100644 index 0000000000000000000000000000000000000000..b709231acec5e838ee39c1346b1454009663810f --- /dev/null +++ b/Klausuren/Sd1/2022winter/Solve/src/main/java/de/hdm_stuttgart/mi/sd1/task1/C_Range.java @@ -0,0 +1,79 @@ +package de.hdm_stuttgart.mi.sd1.task1; + +/** + * <p>Handling integer ranges</p> + */ +public class C_Range { + + /** + * <p>Displaying a range of integer values.</p> + * + * <p>Integer ranges being defined by [start, end] (inclusive) shall be displayed in a user friendly way:</p> + * + * <ul> + * <li>Up to a range of four all values shall be displayed.</li> + * <li>Starting from five values onwards only the first, second and last value shall be visible with »...« + * denoting intermediate values being omitted on display</li> + * </ul> + * + * <p>We provide some samples:</p> + * + * <table class="goikTableDefaults"> + * <caption>Display of ranges</caption> + * <tbody> + * <tr> + * <th>Range</th> + * <th>Display</th> + * <th>Explanation</th> + * </tr> + * <tr> + * <td> + * <pre><code class="nohighlight">[5, 5]</code></pre> + * </td> + * <td> + * <pre><code class="nohighlight">"5"</code></pre> + * </td> + * <td>Start equals end, just one value.</td> + * </tr> + * <tr> + * <td> + * <pre><code class="nohighlight">[1, 3]</code></pre> + * </td> + * <td> + * <pre><code class="nohighlight">"1, 2, 3"</code></pre> + * </td> + * <td>Less than five elements, showing all values</td> + * </tr> + * <tr> + * <td> + * <pre><code class="nohighlight">[-2, 7]</code></pre> + * </td> + * <td> + * <pre><code class="nohighlight">"-2, -1, ..., 7"</code></pre> + * </td> + * <td>More than four elements thus using dots.</td> + * </tr> + * </tbody> + * </table> + * + * @param start The range's lowest value. Must be smaller than or equal to end. + * @param end The range's highest value. Must be larger or equal to start. + * + * @return A range describing string. + * + */ + static public String displayRange(int start, int end) { + + final StringBuilder s = new StringBuilder(Integer.toString(start)); + if (3 < end - start) { + s.append(", ").append(start + 1) + .append(", ..., ").append(end); + } else { + for (int i = start + 1; i <= end; i++) { + s.append(", ").append(Integer.toString(i)); + } + } + return s.toString(); + } + private C_Range(){/* Ignore me: My sole purpose is suppressing default constructor javadoc generation */} +} diff --git a/Klausuren/Sd1/2022winter/Solve/src/main/java/de/hdm_stuttgart/mi/sd1/task1/D_Clump.java b/Klausuren/Sd1/2022winter/Solve/src/main/java/de/hdm_stuttgart/mi/sd1/task1/D_Clump.java new file mode 100644 index 0000000000000000000000000000000000000000..6e7cc7317f9696afb4f4833499a167c62a40de7d --- /dev/null +++ b/Klausuren/Sd1/2022winter/Solve/src/main/java/de/hdm_stuttgart/mi/sd1/task1/D_Clump.java @@ -0,0 +1,87 @@ +package de.hdm_stuttgart.mi.sd1.task1; + + +/** + * <p>Getting clumps in array values.</p> + */ +public class D_Clump { + + /** + * <p>Finding the number of clumps of identical values.</p> + * + * <p>A group of at least two mutually adjacent array members of identical value is being called a clump. Example:</p> + * + * <p>{0, <span style='color:red;font-weight:bold;'>-1, -1</span>, 3, 2, <span style='color:red;font-weight:bold;'>4, 4, 4</span>}</p> + * + * <p>This array harbours two clumps <code style='color:red;font-weight:bold;'>-1, -1</code> and + * <code style='color:red;font-weight:bold;'>4, 4, 4</code> of adjacent identical values. Its clump count is + * thus 2. Some more examples:</p> + * + * <table class="goikTableDefaults"> + * <caption>Clump count examples</caption> + * <tbody> + * <tr> + * <th>Array</th> + * <th>Clump count</th> + * </tr> + * <tr> + * <td><code>null</code></td> + * <td>0</td> + * </tr> + * <tr> + * <td><code>{}</code></td> + * <td>0</td> + * </tr> + * <tr> + * <td><code>{4}</code></td> + * <td>0</td> + * </tr> + * <tr> + * <td><code>{4, -3, 4}</code></td> + * <td>0</td> + * </tr> + * <tr> + * <td><code>{0, <span style='color:red;font-weight:bold;'>9, 9</span>}</code></td> + * <td>1</td> + * </tr> + * <tr> + * <td><code>{<span style='color:red;font-weight:bold;'>-1, -1, -1</span>, 5, <span style='color:red;font-weight:bold;'>-1, -1, -1</span>, 4, <span style='color:red;font-weight:bold;'>3, 3, 3</span>}</code></td> + * <td>3</td> + * </tr> + * <tr> + * <td><code>{<span style='color:red;font-weight:bold;'>3, 3, 3, 3, 3, 3, 3, 3</span>}</code></td> + * <td>1</td> + * </tr> + * </tbody> + * </table> + * + * @param values Integer values or <code>null</code> being treated like an empty array. + * + * @return The number of clumps containing neighbouring identical values or zero for an array value of + * <code class="java">null</code>. + */ + static public int getClumpCount(final int[] values) { + + if (null == values || values.length < 2) { + return 0; + } else { + int clumpCount = 0; + int previous = values[0]; + boolean inClump = false; + for (int i = 1; i < values.length; i++) { + final int current = values[i]; + if (current == previous) { + if (!inClump) { + inClump = true; + clumpCount++; + } + } else { + inClump = false; + } + previous = current; + } + return clumpCount; + } + } + private D_Clump(){/* Ignore me: My sole purpose is suppressing default constructor javadoc generation */} +} diff --git a/Klausuren/Sd1/2022winter/Solve/src/main/java/de/hdm_stuttgart/mi/sd1/task1/package-info.java b/Klausuren/Sd1/2022winter/Solve/src/main/java/de/hdm_stuttgart/mi/sd1/task1/package-info.java new file mode 100644 index 0000000000000000000000000000000000000000..fb7bb58c281c72e0241b31061906c3bf633172d2 --- /dev/null +++ b/Klausuren/Sd1/2022winter/Solve/src/main/java/de/hdm_stuttgart/mi/sd1/task1/package-info.java @@ -0,0 +1,17 @@ +/** + * <p>This package mostly (if not completely) contains static methods.</p> + * + * <p>The ordering being implied by class names reflects the author's opinion with respect to ascending implementation + * difficulty. Hints:</p> + * + * <ul> + * <li>Run <code>mvn javadoc:javadoc</code> and open the generated + * <code>/home/.../target/site/apidocs/index.html</code> file in your browser of choice.</li> + * + * <li>Use the corresponding unit tests to check your implementation's consistency and class + * <code>de.hdm_stuttgart.mi.sd1.test.ShowReachedPoints</code> from your project's “unit test†branch.</li> + * + * </ul> + * + */ +package de.hdm_stuttgart.mi.sd1.task1; \ No newline at end of file diff --git a/Klausuren/Sd1/2022winter/Solve/src/main/java/de/hdm_stuttgart/mi/sd1/task2/BatteryPlanner.java b/Klausuren/Sd1/2022winter/Solve/src/main/java/de/hdm_stuttgart/mi/sd1/task2/BatteryPlanner.java new file mode 100644 index 0000000000000000000000000000000000000000..248664b2d824bb5a353ac871a55a731dbaad5b18 --- /dev/null +++ b/Klausuren/Sd1/2022winter/Solve/src/main/java/de/hdm_stuttgart/mi/sd1/task2/BatteryPlanner.java @@ -0,0 +1,120 @@ +package de.hdm_stuttgart.mi.sd1.task2; + +/** + * <p>Simulating car battery power.</p> + * + */ +public class BatteryPlanner { + + /** + * <p>How many kilometer (Km) does 1 Kwh (Kilowatt hour) of energy allow you to drive? + * See {@link #BatteryPlanner(int, int)} for details.</p> + */ + public final int kilometerByKwh; + + /** + * The battery's capacity in kilowatt-hours (kwh). See {@link #BatteryPlanner(int, int)} for details. + */ + public final int capacity; + + private double stateOfCharge; + + /** + * <p>Offering a certain amount of energy for charging.</p> + * + * <p>The battery may be charged up to its capacity thereby raising its internal state of charge. </p> + * + * <ul> + * <li>In case the offered amount is too large the excess value is being returned as a positive value.</li> + * + * <li>A negative return value indicates the amount still being required for the battery's complete recharge.</li> + * + * </ul> + * + * <p>Example: We assume a battery having a capacity of 60 kwh being charged with 20 kwh. We may + * thus charge 60 kwh - 20 kwh = 40 kwh at maximum. + * + * <ul> + * <li>When offering 50 kwh the excess of 50kwh - 40kwh = 10 kwh cannot be used for charging and will thus be + * returned.</li> + * + * <li>Offering just 30 kwh results in an incomplete 50Kwh state of charge and an excess of -10 Kwh. This + * indicates another 10Kwh being required for a complete battery charge.</li> + * </ul> + * + * @param chargeOffer The amount of energy in kwh being offered for charging. + * + * @return Positive values indicate excess energy and negative values indicate lack of energy with respect to + * the battery's capacity and given state of charge. + */ + public double charge (final double chargeOffer) { + final double excess = chargeOffer + stateOfCharge - capacity; + if (excess <= 0) { + stateOfCharge += chargeOffer; + } else { + stateOfCharge = capacity; + } + return excess; + } + + /** + * <p>Driving an intended distance:</p> + * + * <p>Depending on the battery's state of charge either the intended distance or a smaller value + * being covered by the stored amount of Kwh will be returned. We consider an intended + * distance of 100 Km:</p> + * + * <ul> + * <li>The battery allows for 200 Km. In this case the full 100 Km intended distance is being + * returned and the battery's state of charge will be reduced accordingly.</li> + * + * <li>The battery's state of charge only allows for 40 Km. This value is being returned an the + * battery's state of charge will drain to zero.</li> + * </ul> + * + * @param intendedDistance The intended driving distance in kilometer (km). + * @return The distance actually being covered. + */ + public double drive (final double intendedDistance) { + final double currentRange = stateOfCharge * kilometerByKwh; + + if (intendedDistance <= currentRange) { + stateOfCharge -= intendedDistance / kilometerByKwh; + return intendedDistance; + } else { + stateOfCharge = 0; + return currentRange; + } + } + + /** + * <p>Return the battery's state of charge in terms of {@link BatteryState} categories.</p> + * + * @return An enum value from {@link BatteryState}. + */ + public BatteryState getState() { + return BatteryState.getState(stateOfCharge * 100. / capacity); + } + + /** + * <p>A car / battery system of given capacity being fully charged initially.</p> + * + * <p>An electric car's driving range is (among other factors) being determined by:</p> + * + * <ul> + * <li>Battery capacity being measured in kilowatt hours (kwh).</li> + * <li>Its weight and other factors demanding a certain amount of energy per driven kilometer.</li> + * </ul> + * + * <p>Example: A car delivering 200 km before completely draining a battery of 50 kwh requires + * 1 Kwh per 4Km of driving.</p> + * + * @param capacity See {@link #capacity}. + * @param kilometerByKwh See {@link #kilometerByKwh}. + */ + public BatteryPlanner(final int capacity, final int kilometerByKwh) { + this.capacity = capacity; + this.kilometerByKwh = kilometerByKwh; + this.stateOfCharge = capacity; + } +} diff --git a/Klausuren/Sd1/2022winter/Solve/src/main/java/de/hdm_stuttgart/mi/sd1/task2/BatteryState.java b/Klausuren/Sd1/2022winter/Solve/src/main/java/de/hdm_stuttgart/mi/sd1/task2/BatteryState.java new file mode 100644 index 0000000000000000000000000000000000000000..9774cbfd6705136360faff730df8779d0193a910 --- /dev/null +++ b/Klausuren/Sd1/2022winter/Solve/src/main/java/de/hdm_stuttgart/mi/sd1/task2/BatteryState.java @@ -0,0 +1,49 @@ +package de.hdm_stuttgart.mi.sd1.task2; + +/** + * Describing a battery's state of charge categories. + */ +public enum BatteryState { + + /** + * State of charge is below 10% of the battery's capacity. + */ + LOW("SOC below 10 %"), + /** + * State of charge is in between and including 10% and 90% of the battery's capacity. + */ + NORMAL("SOC between 10% and 90%"), + /** + * State of charge is above 90% of the battery's capacity. + */ + HIGH("SOC above 90%"); + + /** + * <p>Turn the state of charge percentage into categories:</p> + * + * @param socPercentage State of charge as a percentage of the battery's {@link BatteryPlanner#capacity}. + * + * @return + * <ul> + * <li> 0 <= percentage < 10% : return {@link #LOW}</li> + * <li> 10 <= percentage < 90% : return {@link #NORMAL}</li> + * <li> 90 <= percentage <= 100% : return {@link #HIGH}</li> + * </ul> + * + */ + static public BatteryState getState(final double socPercentage) { + if (socPercentage < 10) { + return BatteryState.LOW; + } else if (socPercentage <= 90) { + return BatteryState.NORMAL; + } else { + return BatteryState.HIGH; + } + } + + final String description; + + BatteryState(final String description) { + this.description = description; + } +} diff --git a/Klausuren/Sd1/2022winter/Solve/src/main/javadoc/resources/fonts/dejavu.css b/Klausuren/Sd1/2022winter/Solve/src/main/javadoc/resources/fonts/dejavu.css new file mode 100644 index 0000000000000000000000000000000000000000..4fec2b593cdcc719fd7edd6744a33a3395ca8401 --- /dev/null +++ b/Klausuren/Sd1/2022winter/Solve/src/main/javadoc/resources/fonts/dejavu.css @@ -0,0 +1,3 @@ +/* shame on you, javadoc! Still providing +@import url('resources/fonts/dejavu.css') line in stylesheet.css +*/ \ No newline at end of file diff --git a/Klausuren/Sd1/2022winter/Solve/src/main/javadoc/resources/jdocSupplement.css b/Klausuren/Sd1/2022winter/Solve/src/main/javadoc/resources/jdocSupplement.css new file mode 100644 index 0000000000000000000000000000000000000000..08840cdbf55d1f43368245d0a965659c4411b2ee --- /dev/null +++ b/Klausuren/Sd1/2022winter/Solve/src/main/javadoc/resources/jdocSupplement.css @@ -0,0 +1,72 @@ +/* Javadoc extensions: */ + +ul > li > ul { + list-style-type: circle; +} + +table.goikTableDefaults, +table.goikTableDefaults>caption, +table.goikTableDefaults>tr>th, +table.goikTableDefaults>tr>td, +table.goikTableDefaults>tbody>tr>th, +table.goikTableDefaults>tbody>tr>td { + border: 2px solid black; + border-collapse: collapse; + padding: 1ex; + vertical-align: top; +} + +table.goikTableDefaults>caption { + /* border-top-style: solid; border-left-style: solid; border-right-style: solid' */ + border-bottom-style: none; + font-weight: bold; + background:#dee3e9; + text-align:left; + padding:8px 3px 3px 7px; +} + +table.goikTableDefaults>tbody>tr>td { + vertical-align:top; +} +table.goikTableDefaults { + border-spacing: 0px !important; +} + +table.indexTable { + border-collapse: collapse; + border-style: hidden; +} + +table.indexTable caption { + text-align: left; +} + +table.indexTable td, table.indexTable th { + border: 1px solid black; + padding: 0.5ex; +} + +em { + font-weight: bold; + font-style: normal; +} +section.implementationHints>h3 { + font-weight: bold; + background-color: rgb(222, 227, 233); +} + +code { + white-space: pre; +} + +.implementationHints { + background-color: hsl(120, 100%, 95%) !important; +} + +.myRed { + color: red; +} + +.myGreen { + color: limegreen; +} diff --git a/Klausuren/Sd1/2022winter/Solve/src/main/javadoc/resources/jdocSupplement.js b/Klausuren/Sd1/2022winter/Solve/src/main/javadoc/resources/jdocSupplement.js new file mode 100644 index 0000000000000000000000000000000000000000..97911e5581090aac5e37323427450f8c8c8a3f94 --- /dev/null +++ b/Klausuren/Sd1/2022winter/Solve/src/main/javadoc/resources/jdocSupplement.js @@ -0,0 +1,7 @@ +for(var i in document.links) { + var link = document.links[i]; + if (link.href && link.href.indexOf('http') === 0) { + link.target = '_blank'; + } +} + diff --git a/Klausuren/Sd1/2022winter/Solve/src/main/resources/log4j2.xml b/Klausuren/Sd1/2022winter/Solve/src/main/resources/log4j2.xml new file mode 100644 index 0000000000000000000000000000000000000000..130f87a144c4eb0107a846e580c8fa7f5e819fc1 --- /dev/null +++ b/Klausuren/Sd1/2022winter/Solve/src/main/resources/log4j2.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="UTF-8"?> +<Configuration> + <Appenders> + <File name="A1" fileName="A1.log" append="false"> + <PatternLayout pattern="%t %-5p %c{2} - %m%n"/> + </File> + <Console name="STDOUT" target="SYSTEM_OUT"> + <PatternLayout pattern="%d %-5p [%t] %C{2} (%F:%L) - %m%n"/> + </Console> + </Appenders> + <Loggers> + + <!-- You my want to define class or package level per-logger rules --> + <Logger name="de.hdm_stuttgart.mi.sd1.App" level="debug"> + <AppenderRef ref="A1"/> + </Logger> + <Root level="info"> + <AppenderRef ref="STDOUT"/> + </Root> + </Loggers> +</Configuration> \ No newline at end of file diff --git a/Klausuren/Sd1/2022winter/Solve/src/test/java/de/hdm_stuttgart/mi/sd1/ShowReachedPoints.java b/Klausuren/Sd1/2022winter/Solve/src/test/java/de/hdm_stuttgart/mi/sd1/ShowReachedPoints.java new file mode 100644 index 0000000000000000000000000000000000000000..23a37acb9ebfda05710206f5c4e439ae5b576094 --- /dev/null +++ b/Klausuren/Sd1/2022winter/Solve/src/test/java/de/hdm_stuttgart/mi/sd1/ShowReachedPoints.java @@ -0,0 +1,22 @@ +package de.hdm_stuttgart.mi.sd1; + +import de.hdm_stuttgart.mi.exam.unitmarking.RunTests; + +import de.hdm_stuttgart.mi.sd1.task1.*; +import de.hdm_stuttgart.mi.sd1.task2.TestBatteryPlanner; + +public class ShowReachedPoints { + + /** + * Revealing total number of reached points fromm all tasks. + * + * @param args Unused + */ + public static void main(String[] args) { + RunTests.exec( + "Task 1" + , A_PartyTest.class, B_BackupTest.class, C_RangeTest.class, D_ClumpTest.class + ); + RunTests.exec("Task 2", TestBatteryPlanner.class); + } +} \ No newline at end of file diff --git a/Klausuren/Sd1/2022winter/Solve/src/test/java/de/hdm_stuttgart/mi/sd1/ignore_me/ObjectWrapper.java b/Klausuren/Sd1/2022winter/Solve/src/test/java/de/hdm_stuttgart/mi/sd1/ignore_me/ObjectWrapper.java new file mode 100644 index 0000000000000000000000000000000000000000..85ea78ca4b9c3fd5a617f4074b1d0a4c9b847d54 --- /dev/null +++ b/Klausuren/Sd1/2022winter/Solve/src/test/java/de/hdm_stuttgart/mi/sd1/ignore_me/ObjectWrapper.java @@ -0,0 +1,231 @@ +package de.hdm_stuttgart.mi.sd1.ignore_me; + +import org.junit.Assert; + +import java.lang.reflect.*; +import java.util.Arrays; +import java.util.stream.Collectors; + +public class ObjectWrapper<T> { + + private final Class classz; + private final T instance; + + static public void assertFinal(final Class classZ, final String fieldName) { + try { + final int modifier = classZ.getDeclaredField(fieldName).getModifiers(); + Assert.assertTrue("»" + fieldName + "« can be modified, no immutable!", Modifier.isFinal(modifier)); + + } catch (NoSuchFieldException e) { + Assert.fail("No such field »" + fieldName + "«"); + } + } + + public ObjectWrapper(final Class<T> classz, final Object ... parameter) { + this.classz = classz; + T tmpInstance = null; + final Constructor<?>[] candidates = Arrays. + stream(classz.getConstructors()). + filter(c -> matchesArgumentList(c, parameter)). + toArray(Constructor<?>[]::new); + if (0 == candidates.length) { + Assert.fail("No suitable constructor in class »" + classz.getName() + "« matching arguments »(" + + Arrays.stream(parameter).map(Object::toString).collect(Collectors.joining(", ")) + + ")«"); + } else if (1 < candidates.length) { + Assert.fail("Multiple constructor matches due to ambiguous signature"); + } else { + try { + tmpInstance = (T) candidates[0].newInstance( + Arrays.stream(parameter).toArray()); + } catch (Exception e) { + Assert.fail("Unable to instantiate instance of class »" + classz.getName() + "«: "+ e); + } + } + instance = tmpInstance; + } + + public ObjectWrapper(final Class<T> classz, final Class<? extends Throwable> expectedException, final Object ... parameter) { + this.classz = classz; + T tmpInstance = null; + final Constructor<?>[] candidates = Arrays. + stream(classz.getConstructors()). + filter(c -> matchesArgumentList(c, parameter)). + toArray(Constructor<?>[]::new); + if (0 == candidates.length) { + Assert.fail("No suitable constructor in class »" + classz.getName() + "« matching arguments »(" + + Arrays.stream(parameter).map(Object::toString).collect(Collectors.joining(", ")) + + ")«"); + } else if (1 < candidates.length) { + Assert.fail("Multiple constructor matches due to ambiguous signature"); + } else { + try { + tmpInstance = (T) candidates[0].newInstance( + Arrays.stream(parameter).toArray()); + Assert.fail("Expected exception of type »" + expectedException.getName() + "« to be thrown"); + } catch (InstantiationException|IllegalAccessException|IllegalArgumentException|InvocationTargetException e) { + if (e.getCause().getClass() != expectedException) { + Assert.fail("Unable to instantiate: " + e + ", cause:\n Expected exception of type »" + + expectedException.getName() + "« but was »"+ e.getCause().getClass().getName() + "«"); + } + } + } + instance = tmpInstance; + } + + public <R> void assertFieldExists(final Class<R> valueType, final String name) { + try { + final Field field = classz.getField(name); + if (!valueType.equals(field.getType())) { + Assert.fail("Field »" + name + "« in class »" + classz.getName() + "« is not of type »" + + valueType.getName() + "«"); + } + } catch (final NoSuchFieldException e) { + Assert.fail("No such field »" + name + "« in class »" + classz.getName() + "«"); + } + } + + public <R> R get(final Class<R> valueType, final String name) { + + try { + final Field field = classz.getField(name); + if (valueType.equals(field.getType())) { + return (R) field.get(instance); + } else { + Assert.fail("Field »" + name + "« in class »" + classz.getName() + "« is not of type »" + + valueType.getName() + "«"); + } + } catch (final NoSuchFieldException e) { + Assert.fail("No such field »" + name + "« in class »" + classz.getName() + "«"); + } catch (final IllegalAccessException e) { + Assert.fail("Unable to access field »" + name + "« in class »" + classz.getName() + "«: " + e.getMessage()); + } + return null; + } + public void set(final String name, final Object value) { + + try { + final Field field = classz.getField(name); + final Class argumentType = value.getClass(); + if (field.getType().equals(argumentType) || + field.getType().equals(getPrimitiveType(argumentType))){ + field.set(instance, value); + } else { + Assert.fail("Field »" + name + "« in class »" + classz.getName() + "« is not of type »" + + argumentType.getName() + "«"); + } + } catch (final NoSuchFieldException e) { + Assert.fail("No such field »" + name + "« in class »" + classz.getName() + "«"); + } catch (final IllegalAccessException e) { + Assert.fail("Unable to access field »" + name + "« in class »" + classz.getName() + "«: " + e.getMessage()); + } + } + + public <R> R invoke(final Class<R> returnType, final String name, final Object ... parameter) { + + final Method[] candidates = Arrays. + stream(classz.getMethods()). + filter(m-> m.getName().equals(name) && matchesArgumentList(m, parameter)). + toArray(Method[]::new); + + if (0 == candidates.length) { + Assert.fail("No suitable method found"); + } else if (1 < candidates.length) { + Assert.fail("Multiple method matches due to ambiguous signature"); + } else { + final Method method = candidates[0]; + if (method.getReturnType().equals(returnType)) { + try { + return (R) method.invoke(instance, parameter); + } catch (final IllegalAccessException| IllegalArgumentException|InvocationTargetException e) { + Assert.fail("Unable to execute method: " + e + ", cause:" + e.getCause()); + } + } else { + Assert.fail("Method »" + method.getName() + "« does have return type »" + method.getReturnType() + "«" + + "rather then »" + returnType.getName() + "«"); + } + } + return null; + } + public <R> R invoke(final Class<R> returnType, final String name, + final Class<? extends Throwable> expectedException, final Object ... parameter) { + + final Method[] candidates = Arrays. + stream(classz.getMethods()). + filter(m-> m.getName().equals(name) && matchesArgumentList(m, parameter)). + toArray(Method[]::new); + + if (0 == candidates.length) { + Assert.fail("No suitable method found"); + } else if (1 < candidates.length) { + Assert.fail("Multiple method matches due to ambiguous signature"); + } else { + final Method method = candidates[0]; + if (method.getReturnType().equals(returnType)) { + try { + R ret = (R) method.invoke(instance, parameter); + Assert.fail("Expected exception of type »" + expectedException.getName() + "«"); + return ret; + } catch (final IllegalAccessException| IllegalArgumentException|InvocationTargetException e) { + if (e.getCause().getClass() != expectedException) { + Assert.fail("Unable to execute method: " + e + ", cause:\n Expected exception of type »" + + expectedException.getName() + "« but was »"+ e.getCause().getClass().getName() + "«"); + } + } + } else { + Assert.fail("Method »" + method.getName() + "« does have return type »" + method.getReturnType() + "«" + + "rather then »" + returnType.getName() + "«"); + } + } + return null; + } + + /** + * Check for a given array of objects matching an {@link Executable}'s argument list. + * + * @param executable + * @param parameter + * @return <code>true</code> if parameters match the {@link Executable}'s argument list, <code>false</code> + * otherwise. + */ + private boolean matchesArgumentList(final Executable executable, final Object ... parameter) { + + if (executable.getParameterCount() != parameter.length) { + return false; + } else { + final Class<?>[] formalArgumentTypes = executable.getParameterTypes(); + for (int i = 0; i < formalArgumentTypes.length; i++) { + final Class parametersClass = parameter[i].getClass(); + + if (!formalArgumentTypes[i].equals(parametersClass) && + !formalArgumentTypes[i].equals(getPrimitiveType(parametersClass))) { + return false; + } + } + } + return true; + } + + static private Class<?> getPrimitiveType (final Class<?> in) { + if (in.equals(Byte.class)) { + return byte.class; + } else if (in.equals(Short.class)) { + return short.class; + } else if (in.equals(Integer.class)) { + return int.class; + } else if (in.equals(Long.class)) { + return long.class; + } else if (in.equals(Float.class)) { + return float.class; + } else if (in.equals(Double.class)) { + return double.class; + } else if (in.equals(Boolean.class)) { + return boolean.class; + } else if (in.equals(Character.class)) { + return char.class; + } else { + return in; // Type is no primitive + } + } + +} diff --git a/Klausuren/Sd1/2022winter/Solve/src/test/java/de/hdm_stuttgart/mi/sd1/task1/A_PartyTest.java b/Klausuren/Sd1/2022winter/Solve/src/test/java/de/hdm_stuttgart/mi/sd1/task1/A_PartyTest.java new file mode 100644 index 0000000000000000000000000000000000000000..3bd60fa702a305825fdc6e51cdf9ab676b10601d --- /dev/null +++ b/Klausuren/Sd1/2022winter/Solve/src/test/java/de/hdm_stuttgart/mi/sd1/task1/A_PartyTest.java @@ -0,0 +1,47 @@ +package de.hdm_stuttgart.mi.sd1.task1; + +import de.hdm_stuttgart.mi.exam.unitmarking.ExaminationTestDefaults; +import de.hdm_stuttgart.mi.exam.unitmarking.Marking; +import org.junit.Assert; +import org.junit.FixMethodOrder; +import org.junit.Test; +import org.junit.runners.MethodSorters; + +import static de.hdm_stuttgart.mi.sd1.task1.A_Party.getInvitation; + + +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +public class A_PartyTest extends ExaminationTestDefaults { + + @Test + @Marking(points = 20) + public void test_100() { + Assert.assertFalse( getInvitation(false, false, -10)); + Assert.assertFalse( getInvitation(false, false, 0)); + Assert.assertFalse( getInvitation(false, false, 10)); + Assert.assertFalse( getInvitation(false, false, 19999)); + Assert.assertFalse( getInvitation(false, false, 20000)); + Assert.assertFalse( getInvitation(false, false, 20001)); + + Assert.assertFalse( getInvitation(false, true, -10)); + Assert.assertFalse( getInvitation(false, true, 0)); + Assert.assertFalse( getInvitation(false, true, 10)); + Assert.assertFalse( getInvitation(false, true, 19999)); + Assert.assertTrue( getInvitation(false, true, 20000)); + Assert.assertTrue( getInvitation(false, true, 20001)); + + Assert.assertTrue( getInvitation(true, false, -10)); + Assert.assertTrue( getInvitation(true, false, 0)); + Assert.assertTrue( getInvitation(true, false, 10)); + Assert.assertTrue( getInvitation(true, false, 19999)); + Assert.assertTrue( getInvitation(true, false, 20000)); + Assert.assertTrue( getInvitation(true, false, 20001)); + + Assert.assertTrue( getInvitation(true, true, -10)); + Assert.assertTrue( getInvitation(true, true, 0)); + Assert.assertTrue( getInvitation(true, true, 10)); + Assert.assertTrue( getInvitation(true, true, 19999)); + Assert.assertTrue( getInvitation(true, true, 20000)); + Assert.assertTrue( getInvitation(true, true, 20001)); + } +} diff --git a/Klausuren/Sd1/2022winter/Solve/src/test/java/de/hdm_stuttgart/mi/sd1/task1/B_BackupTest.java b/Klausuren/Sd1/2022winter/Solve/src/test/java/de/hdm_stuttgart/mi/sd1/task1/B_BackupTest.java new file mode 100644 index 0000000000000000000000000000000000000000..ce60f1d69393523a7169b92106662a3e466eca9b --- /dev/null +++ b/Klausuren/Sd1/2022winter/Solve/src/test/java/de/hdm_stuttgart/mi/sd1/task1/B_BackupTest.java @@ -0,0 +1,34 @@ +package de.hdm_stuttgart.mi.sd1.task1; + +import de.hdm_stuttgart.mi.exam.unitmarking.ExaminationTestDefaults; +import de.hdm_stuttgart.mi.exam.unitmarking.Marking; +import org.junit.Assert; +import org.junit.FixMethodOrder; +import org.junit.Test; +import org.junit.runners.MethodSorters; + +import static de.hdm_stuttgart.mi.sd1.task1.B_Backup.createBackupFilename; + +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +public class B_BackupTest extends ExaminationTestDefaults { + + @Test + @Marking(points = 5) + public void test_100_noExtension() { + Assert.assertEquals("starter_backup", createBackupFilename("starter", "_backup")); + Assert.assertEquals("ab", createBackupFilename("a", "b")); + } + + @Test + @Marking(points = 5) + public void test_200_singleExtension() { + Assert.assertEquals("calc-b.ods", createBackupFilename("calc.ods", "-b")); + Assert.assertEquals("backup.config", createBackupFilename(".config", "backup")); + } + + @Test + @Marking(points = 2) + public void test_300_multipleExtensions() { + Assert.assertEquals("file.b.c+backup.d", createBackupFilename("file.b.c.d", "+backup")); + } +} diff --git a/Klausuren/Sd1/2022winter/Solve/src/test/java/de/hdm_stuttgart/mi/sd1/task1/C_RangeTest.java b/Klausuren/Sd1/2022winter/Solve/src/test/java/de/hdm_stuttgart/mi/sd1/task1/C_RangeTest.java new file mode 100644 index 0000000000000000000000000000000000000000..7961d5a90dd81a37bff97b3ee1b7523b1d47903a --- /dev/null +++ b/Klausuren/Sd1/2022winter/Solve/src/test/java/de/hdm_stuttgart/mi/sd1/task1/C_RangeTest.java @@ -0,0 +1,38 @@ +package de.hdm_stuttgart.mi.sd1.task1; + +import de.hdm_stuttgart.mi.exam.unitmarking.ExaminationTestDefaults; +import de.hdm_stuttgart.mi.exam.unitmarking.Marking; +import org.junit.Assert; +import org.junit.FixMethodOrder; +import org.junit.Test; +import org.junit.runners.MethodSorters; + +import static de.hdm_stuttgart.mi.sd1.task1.C_Range.displayRange; + +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +public class C_RangeTest extends ExaminationTestDefaults { + + @Test + @Marking(points = 6) + public void test_100_single() { + Assert.assertEquals("-5", displayRange(-5, -5)); + Assert.assertEquals("1111", displayRange(1111, 1111)); + } + + @Test + @Marking(points = 3) + public void test_200_four() { + Assert.assertEquals("1", displayRange(1, 1)); + Assert.assertEquals("-1, 0", displayRange(-1, 0)); + Assert.assertEquals("4, 5, 6", displayRange(4, 6)); + Assert.assertEquals("-10, -9, -8, -7", displayRange(-10, -7)); + } + + + @Test + @Marking(points = 2) + public void test_300_dots() { + Assert.assertEquals("1, 2, ..., 5", displayRange(1, 5)); + Assert.assertEquals("-20, -19, ..., 10", displayRange(-20, 10)); + } +} diff --git a/Klausuren/Sd1/2022winter/Solve/src/test/java/de/hdm_stuttgart/mi/sd1/task1/D_ClumpTest.java b/Klausuren/Sd1/2022winter/Solve/src/test/java/de/hdm_stuttgart/mi/sd1/task1/D_ClumpTest.java new file mode 100644 index 0000000000000000000000000000000000000000..087fcfedcbd46bc780b2c1c7b1a69cbbf4be01a2 --- /dev/null +++ b/Klausuren/Sd1/2022winter/Solve/src/test/java/de/hdm_stuttgart/mi/sd1/task1/D_ClumpTest.java @@ -0,0 +1,83 @@ +package de.hdm_stuttgart.mi.sd1.task1; + +import de.hdm_stuttgart.mi.exam.unitmarking.ExaminationTestDefaults; +import de.hdm_stuttgart.mi.exam.unitmarking.Marking; +import org.junit.Assert; +import org.junit.FixMethodOrder; +import org.junit.Test; +import org.junit.runners.MethodSorters; + +import static de.hdm_stuttgart.mi.sd1.task1.D_Clump.getClumpCount; +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +public class D_ClumpTest extends ExaminationTestDefaults { + + @Test + public void test_20_null() { + Assert.assertEquals(0, getClumpCount(null)); + } + @Test + public void test_40_empty() { + Assert.assertEquals(0, getClumpCount(new int[]{})); + } + + @Test + public void test_100_one() { + Assert.assertEquals(0, getClumpCount(new int[]{-5})); + } + + @Test + public void test_200_two() { + Assert.assertEquals(0, getClumpCount(new int[]{1, 0})); + Assert.assertEquals(1, getClumpCount(new int[]{-2, -2})); + } + @Test + public void test_300_three() { + Assert.assertEquals(0, getClumpCount(new int[]{1, 2, 3})); + Assert.assertEquals(1, getClumpCount(new int[]{1, 1, 3})); + Assert.assertEquals(1, getClumpCount(new int[]{-7, 4, 4})); + Assert.assertEquals(1, getClumpCount(new int[]{6, 6, 6})); + } + @Test + public void test_400_four() { + Assert.assertEquals(0, getClumpCount(new int[]{1, 2, -3, 50})); + Assert.assertEquals(1, getClumpCount(new int[]{-3, -3, 0, 30})); + Assert.assertEquals(1, getClumpCount(new int[]{-3, 7, 7, -70})); + Assert.assertEquals(1, getClumpCount(new int[]{-3, 6, 0, 0})); + Assert.assertEquals(1, getClumpCount(new int[]{4, 4, 4, 1})); + Assert.assertEquals(1, getClumpCount(new int[]{1, 7, 7, 7})); + Assert.assertEquals(1, getClumpCount(new int[]{1, 1, 1, 1})); + + Assert.assertEquals(2, getClumpCount(new int[]{1, 1, -5, -5})); + } + @Test + public void test_500_five_six() { + + // five + Assert.assertEquals(0, getClumpCount(new int[]{-6, -3, 0, 30, 1})); + + Assert.assertEquals(1, getClumpCount(new int[]{1, 1, 2, 3, 4})); + Assert.assertEquals(1, getClumpCount(new int[]{1, 2, 2, 3, 4})); + Assert.assertEquals(1, getClumpCount(new int[]{1, 2, 3, 3, 4})); + Assert.assertEquals(1, getClumpCount(new int[]{1, 2, 3, 4, 4})); + + Assert.assertEquals(1, getClumpCount(new int[]{1, 1, 1, 3, 4})); + Assert.assertEquals(1, getClumpCount(new int[]{0, 2, 2, 2, 4})); + Assert.assertEquals(1, getClumpCount(new int[]{1, 2, 3, 3, 3})); + + Assert.assertEquals(1, getClumpCount(new int[]{1, 1, 1, 1, 4})); + Assert.assertEquals(1, getClumpCount(new int[]{0, 2, 2, 2, 2})); + Assert.assertEquals(1, getClumpCount(new int[]{4, 4, 4, 4, 4})); + + Assert.assertEquals(2, getClumpCount(new int[]{-3, -3, 5, 5, 10})); + Assert.assertEquals(2, getClumpCount(new int[]{-3, 7, 7, 1, 1})); + Assert.assertEquals(2, getClumpCount(new int[]{-3, -3, 0, 10, 10})); + + // Six + Assert.assertEquals(3, getClumpCount(new int[]{0, 1, 1, 4, 7, 10, 10, 5, 9, 9, 9, 6})); + Assert.assertEquals(3, getClumpCount(new int[]{1, 1, 4, 7, 10, 10, 5, 9, 9, 9, 8})); + Assert.assertEquals(3, getClumpCount(new int[]{2, 1, 1, 4, 7, 10, 10, 5, 9, 9, 9})); + Assert.assertEquals(3, getClumpCount(new int[]{1, 1, 1, 4, 7, 10, 10, 5, 9, 9, 9})); + Assert.assertEquals(1, getClumpCount(new int[]{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1})); + Assert.assertEquals(1, getClumpCount(new int[]{3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0})); + } +} diff --git a/Klausuren/Sd1/2022winter/Solve/src/test/java/de/hdm_stuttgart/mi/sd1/task2/TestBatteryPlanner.java b/Klausuren/Sd1/2022winter/Solve/src/test/java/de/hdm_stuttgart/mi/sd1/task2/TestBatteryPlanner.java new file mode 100644 index 0000000000000000000000000000000000000000..62c0824e19472fbd2cc24f27c65cebdecfcb7c39 --- /dev/null +++ b/Klausuren/Sd1/2022winter/Solve/src/test/java/de/hdm_stuttgart/mi/sd1/task2/TestBatteryPlanner.java @@ -0,0 +1,141 @@ +package de.hdm_stuttgart.mi.sd1.task2; + +import de.hdm_stuttgart.mi.exam.unitmarking.ExaminationTestDefaults; +import de.hdm_stuttgart.mi.exam.unitmarking.Marking; +import de.hdm_stuttgart.mi.sd1.ignore_me.ObjectWrapper; +import org.junit.Assert; +import org.junit.FixMethodOrder; +import org.junit.Test; +import org.junit.runners.MethodSorters; +@FixMethodOrder(MethodSorters.NAME_ASCENDING) + +public class TestBatteryPlanner extends ExaminationTestDefaults { + + private final double deltaDistance = 1.E-14; + + /** + * Create new instance of {@link BatteryPlanner} + */ + @Test + @Marking(points = 2) + public void test_100CreateBatteryPlanner() { + new ObjectWrapper<>(BatteryPlanner.class,50, 6); + } + + /** + * Check for {@link BatteryState#HIGH} + * <ol> + * <li>Create an instance</li> + * <li></li> + * </ol> + */ + @Test + @Marking(points = 2) + public void test_200() { + final ObjectWrapper<BatteryPlanner> planner = new ObjectWrapper<>(BatteryPlanner.class,100, 5); + + // New instance is expected to be fully charged + Assert.assertSame(BatteryState.HIGH, planner.invoke(BatteryState.class, "getState")); + } + + /** + * <ol> + * <li>Create an instance</li> + * <li>Intended driving distance exceeding battery's capacity</li> + * </ol> + */ + @Test + @Marking(points = 2) + public void test_300() { + // 100 Kwh and 5 Km per 1 Kwh driving range + final ObjectWrapper<BatteryPlanner> planner = new ObjectWrapper<>(BatteryPlanner.class,100, 5); + + // Intending 600 Km of driving, reducing state of charge to 0 Kwh, actually driving just 5 x 100 Km = 500 Km + Assert.assertEquals(500., planner.invoke(double.class, "drive", 600.), deltaDistance); + } + /** + * <ol> + * <li>Create an instance</li> + * <li>Drive till completely draining battery</li> + * <li>Check for {@link BatteryState#LOW}</li> + * </ol> + */ + @Test + @Marking(points = 2) + public void test_340() { + // 100 Kwh and 5 Km per 1 Kwh driving range + final ObjectWrapper<BatteryPlanner> planner = new ObjectWrapper<>(BatteryPlanner.class,100, 5); + + // Fully charged at 100 Kwh + Assert.assertSame(BatteryState.HIGH, planner.invoke(BatteryState.class, "getState")); + + // Intending 600 Km of driving, reducing state of charge to 0 Kwh, actually driving 5 x 100 Km = 500 Km + Assert.assertEquals(500., planner.invoke(double.class, "drive", 600.), deltaDistance); + Assert.assertSame(BatteryState.LOW, planner.invoke(BatteryState.class, "getState")); + } + + /** + * <ol> + * <li>Create an instance</li> + * <li>Drive till completely draining battery</li> + * <li>Two step check for complete charging requiring battery capacity amount.</li> + * </ol> + */ + @Test + @Marking(points = 2) + public void test_360() { + // 100 Kwh and 5 Km per 1 Kwh driving range + final ObjectWrapper<BatteryPlanner> planner = new ObjectWrapper<>(BatteryPlanner.class,100, 5); + + // Intending 500 Km of driving draining battery to zero. + Assert.assertEquals(500., planner.invoke(double.class, "drive", 500.), deltaDistance); + Assert.assertSame(BatteryState.LOW, planner.invoke(BatteryState.class, "getState")); + + // Battery capacity is 100 Kwh. So charging 60 Kwh still lacks another 40 Kwh towards 100% state of charge. + Assert.assertEquals(-40., planner.invoke(double.class, "charge", 60.), deltaDistance); + + // Battery now at 60 Kwh will only consume another 40 Kwh leaving us with an excess of 30 Kwh. + Assert.assertEquals(30., planner.invoke(double.class, "charge", 70.), deltaDistance); + } + + /** + * Driving, checking, charging, repeating ... + */ + @Test + @Marking(points = 10) + public void test_800() { + // 50 Kwh and 4 Km per 1 Kwh driving range + final ObjectWrapper<BatteryPlanner> planner = new ObjectWrapper<>(BatteryPlanner.class,50, 4); + + // Fully charged at 50 Kwh + Assert.assertSame(BatteryState.HIGH, planner.invoke(BatteryState.class, "getState")); + + // Charging impossible, battery is full + Assert.assertEquals(20., planner.invoke(double.class, "charge", 20.), deltaDistance); + Assert.assertSame(BatteryState.HIGH, planner.invoke(BatteryState.class, "getState")); + + // Driving 100 Km, reducing state of charge to 25 Kwh + Assert.assertEquals(100., planner.invoke(double.class, "drive", 100.), deltaDistance); + Assert.assertSame(BatteryState.NORMAL, planner.invoke(BatteryState.class, "getState")); + + // Driving 88 Km, reducing state of charge to 3 Kwh + Assert.assertEquals(88., planner.invoke(double.class, "drive", 88.), deltaDistance); + Assert.assertSame(BatteryState.LOW, planner.invoke(BatteryState.class, "getState")); + + // Intending 20 Km of driving, reducing state of charge to 0 Kwh, actually driving 12 Km + Assert.assertEquals(12., planner.invoke(double.class, "drive", 20.), deltaDistance); + Assert.assertSame(BatteryState.LOW, planner.invoke(BatteryState.class, "getState")); + + // Charging 20 Kwh, 30 Kwh missing for complete charging. + Assert.assertEquals(-30., planner.invoke(double.class, "charge", 20.), deltaDistance); + Assert.assertSame(BatteryState.NORMAL, planner.invoke(BatteryState.class, "getState")); + + // Driving 80 Km, draining battery to zero + Assert.assertEquals(80., planner.invoke(double.class, "drive", 80.), deltaDistance); + Assert.assertSame(BatteryState.LOW, planner.invoke(BatteryState.class, "getState")); + + // Charging 60 Kwh, 10 Kwh exceeding capacity. + Assert.assertEquals(10., planner.invoke(double.class, "charge", 60.), deltaDistance); + Assert.assertSame(BatteryState.HIGH, planner.invoke(BatteryState.class, "getState")); + } +}