diff --git a/README.md b/README.md index c9af80a..4cce06a 100644 --- a/README.md +++ b/README.md @@ -5,3 +5,4 @@ Denne mappen inneholder øvingstekster for TDT4100 - Objektorientert programmeri | Øving | Tema | | -------------------------------------------- | ----------------------------------------- | | [Øving 0](./oppgavetekster/oving0/README.md) | Introduksjon og oppsett av Java | +| [Øving 1](./oppgavetekster/oving1/README.md) | Java-syntaks og objektorientert tankegang | diff --git a/oppgavetekster/oving0/README.md b/oppgavetekster/oving0/README.md index e96af31..1074332 100644 --- a/oppgavetekster/oving0/README.md +++ b/oppgavetekster/oving0/README.md @@ -18,7 +18,7 @@ For å kunne programmere i Java må du installere Java Development Kit (JDK). Vi ### Del 2: Sette opp øvingsprosjektet -For å kunne gjøre øvingene i TDT4100 må du sette opp et prosjekt i VS Code. Dette gjør du ved å følge instruksjonene på [denne siden](https://www.ntnu.no/wiki/x/Ggb6DQ). Husk å følge instruksjonene for ditt operativsystem. **På grunn av samme feil som nevnt i forrige del vil også denne siden være litt utdatert. Dere vil ikke klone fra "", men fra [https://git.ntnu.no/tdt4100/tdt4100-ovinger-25](https://git.ntnu.no/tdt4100/tdt4100-ovinger-25).** +For å kunne gjøre øvingene i TDT4100 må du sette opp et prosjekt i VS Code. Dette gjør du ved å følge instruksjonene på [denne siden](https://www.ntnu.no/wiki/x/Ggb6DQ). Husk å følge instruksjonene for ditt operativsystem. **På grunn av samme feil som nevnt i forrige del vil også denne siden være litt utdatert. Dere vil ikke klone fra "", men fra [https://git.ntnu.no/tdt4100/tdt4100_ovinger-26](https://git.ntnu.no/tdt4100/tdt4100_ovinger-26).** ### Del 3: Hello world diff --git a/oppgavetekster/oving1/Account.md b/oppgavetekster/oving1/Account.md new file mode 100644 index 0000000..4672cd9 --- /dev/null +++ b/oppgavetekster/oving1/Account.md @@ -0,0 +1,24 @@ +# Tilstand og oppførsel – Account + +Oppgaven handler om en `Account`-klasse, som håndterer data i en bankkonto. Tilstanden i `Account`-objekter er som følger: + +- `balance` - et desimaltall som angir beløpet som er på kontoen +- `interestRate` - et desimaltall som angir rentefot som prosentpoeng. + +Begge verdiene skal være satt til `0.0` når klassen opprettes. + +`Account`-klassen har fem metoder, med følgende oppførsel: + +- `deposit(double)` - øker konto-beløpet med den angitte argument-verdien (et desimaltall), men kun dersom det er positivt. Dersom det er negativt skal ingen endring skje. +- `addInterest()` - beregner rente og legger det til konto-beløpet +- `getBalance()` - returnerer beløpet som er på kontoen. +- `getInterestRate()` - returnerer rentefoten +- `setInterestRate(double)` - oppdaterer renten til å være den nye verdien + +## Java-kode + +Skriv Java-kode for `Account`-klassen med oppførsel som er beskrevet over. + +Lag en passende `toString()`-metode og en `main`-metode, slik at du kan sjekke at oppførselen stemmer med tilstandsdiagrammet (bruk samme start-tilstand og sekvens av kall) + +Testkode for denne oppgaven finner du her: [src/test/java/oving1/AccountTest.java](../../src/test/java/oving1/AccountTest.java). diff --git a/oppgavetekster/oving1/Digit.md b/oppgavetekster/oving1/Digit.md new file mode 100644 index 0000000..65bdd84 --- /dev/null +++ b/oppgavetekster/oving1/Digit.md @@ -0,0 +1,28 @@ +# Tilstand og oppførsel – Digit + +Oppgaven handler om en `Digit`-klasse, som representerer ett siffer i et gitt tallsystem. + +Tilstanden i `Digit`-objekter er todelt: + +- en `int` som angir tallsystemet, f.eks. 10 for titallssystemet, som oppgis i konstruktøren. Denne verdien vil ikke bli satt over 36. +- en `int`-verdi, som representerer siffer-verdien i det angitt tallsystem og må være fra og med 0 til (men ikke med) tallsystem-verdien + +Konstruktøren tar inn en `int`, som initialiserer tallsystem-verdien, mens siffer-verdien settes til 0. + +`Digit`-tilstanden leses og oppdateres med følgende metoder: + +- `int getValue()` - returnerer siffer-verdien +- `boolean increment()` - øker siffer-verdien med én. Dersom den da når tallsystem-verdien, så (re)settes den til 0 og metoden returnerer `true`, ellers returnerer den `false`. +- `int getBase()` - returnerer tallsystemet. + +## Java-kode + +Skriv Java-kode for `Digit`-klassen med oppførsel som er beskrevet over. Lag også en `toString()`-metode som returnerer siffer-verdien som en `String`, hvor sifrene 0-9 etterfølges av A-Z. F.eks. skal siffer-verdien 10 i sekstentallssystemet gi "A" som returverdi. + +Lag en `main`-metode, slik at du kan sjekke at oppførselen stemmer med tilstandsdiagrammet (bruk samme sekvens av kall). + +Testkode for denne oppgaven finner du her: [src/test/java/oving1/DigitTest.java](../../src/test/java/oving1/DigitTest.java). + +## Ekstraoppgave + +La hovedprogrammet opprette tre `Digit`-objekter, som fungerer som sifre i et tre-sifret tall. Lag en løkke som teller fra 0 til høyest mulig verdi som kan representeres i tallsystemet. Legg så til 1 så verdien av det tre-sifrede tallet igjen blir 0. Velg selv hvilket tallsystem du vil bruke. diff --git a/oppgavetekster/oving1/LineEditor.md b/oppgavetekster/oving1/LineEditor.md new file mode 100644 index 0000000..13ee18c --- /dev/null +++ b/oppgavetekster/oving1/LineEditor.md @@ -0,0 +1,35 @@ +# Tilstand og oppførsel – LineEditor + +Oppgaven handler om en `LineEditor`-klasse, som håndterer data for redigering av en linje med tekst (altså tekst uten linjeskift). + +`LineEditor`-klassen holder rede på en `String`-verdi og en tekstinnsettingsposisjon og har metoder for å redigere teksten. Tekstinnsettingsposisjonen er et heltall som angir hvor endringer skjer, tilsvarende en (blinkende) cursor som står mellom tegn. Verdien `0` tilsvarer foran første tegn, og høyeste mulige verdi er lengden på teksten, som tilsvarer at cursoren står bak siste tegn. Tilstanden er altså som følger: + +- `text` (en `String`-verdi) - teksten +- `insertionIndex` - heltall som angir hvor i teksten redigeringer vil skje + +Klassen har metoder med følgende oppførsel: + +- `void left()` - flytter tekstinnsettingsposisjonen ett tegn til venstre (tilsvarende bruk av venstre piltast) +- `void right()` - flytter tekstinnsettingsposisjonen ett tegn til høyre (tilsvarende bruk av høyre piltast) +- `void insertString(String s)` - skyter teksten angitt av argumentet `s` inn i teksten på tekstinnsettingsposisjonen og forskyver tekstinnsettingsposisjonen mot høyre tilsvarende +- `void deleteLeft()` - fjerner tegnet til venstre for tekstinnsettingsposisjonen +- `void deleteRight()` - fjerner tegnet til høyre for tekstinnsettingsposisjonen +- `String getText()` - Returnerer teksten +- `void setText(String)` - oppdaterer teksten til å være den nye teksten +- `int getInsertionIndex` - returnerer hvor i teksten redigeringer nå skjer +- `void setInsertionIndex(int)` - oppdaterer hvor i teksten redigeringer skal skje + +## Java-kode + +Skriv Java-kode for `LineEditor`-klassen med oppførsel som beskrevet over. + +Lag en `toString()`-metode som viser teksten med tegnet `'|'` skutt inn på tekstinnsettingsposisjonen. Lag så en `main`-metode, slik at du kan sjekke at oppførselen stemmer med tilstandsdiagrammet (bruk samme start-tilstand og sekvens av kall). + +Testkode for oppgaven finner du her: [src/test/java/oving1/LineEditorTest.java](../../src/test/java/oving1/LineEditorTest.java). + +## Ekstraoppgave - frivillige utvidelser + +- Legg til metoden `void insert(Object o)`, som skyter inn en tekstlig representasjon av objektet `o` som gis som argument. +- Legg til metoden `void left(int n)`, som flytter tekstinnsettingsposisjonen `n` tegn til venstre, og skriv om `left()` til å bruke denne. Hva bør skje dersom tekstinnsettingsposisjonen er mindre enn `n`? +- Legg til metoden `right(int n)`, som flytter tekstinnsettingsposisjonen `n` tegn til høyre, og skriv om `right()` til å bruke denne. Hva bør skje dersom det er færre enn `n` tegn til høyre for tekstinnsettingsposisjonen? +- Utvid tilstanden og legg til metoder for å håndtere markering av region, tilsvarende bruk av shift og piltaster i en vanlig teksteditor. Husk at også de eksisterende metodene må endres til å håndtere dette riktig. diff --git a/oppgavetekster/oving1/Location.md b/oppgavetekster/oving1/Location.md new file mode 100644 index 0000000..1ebee5c --- /dev/null +++ b/oppgavetekster/oving1/Location.md @@ -0,0 +1,24 @@ +# Tilstand og oppførsel – Location + +Oppgaven handler om en `Location`-klasse, som holder rede på `(x,y)`-posisjonen til en figur som beveger seg i et rutenett. + +`Location`-klassen har følgende metoder: + +- `up()` - beveger figuren en rute opp +- `down()` - beveger figuren en rute ned +- `left()` - beveger figuren en rute til venstre +- `right()` - beveger figuren en rute til høyre +- `getX()` - returnerer x-posisjonen til figuren +- `getY()` - returnerer y-posisjonen til figuren + +Merk at konvensjonen innen datagrafikk og rutenettbaserte spill er at `x` øker mot høyre (som i matte) og `y` nedover (altså motsatt av i matte). + +![Koordinatsystem](./img/coordinate.png) + +## Java-kode + +Skriv Java-kode for `Location`-klassen med oppførsel som beskrevet over. + +Lag en passende `toString()`-metode og en `main`-metode, slik at du kan sjekke at oppførselen stemmer med tilstandsdiagrammet (bruk samme start-tilstand og sekvens av kall). + +Testkode for oppgaven finner du her: [src/test/java/oving1/LocationTest.java](../../src/test/java/oving1/LocationTest.java). diff --git a/oppgavetekster/oving1/README.md b/oppgavetekster/oving1/README.md new file mode 100644 index 0000000..5d45df8 --- /dev/null +++ b/oppgavetekster/oving1/README.md @@ -0,0 +1,57 @@ +# Øving 1: Objekter og klasser, tilstand og oppførsel + +## Øvingsmål + +- Bli kjent med Java-syntaks og bruk av VS Code +- Lære (enkel) objektorientert tankegang +- Lære å lage enkle Java-klasser og -programmer + +## Øvingskrav + +- Kunne tegne enkle tilstandsdiagrammer +- Kunne deklarere klasser, med data og kode, iht. oppgavespesifikasjon +- Kunne skrive main-metoder for å teste objekter +- Kunne bruke standardtyper og -metoder (e.g. `toString()`-metoden) + +## NB: Viktig beskjed + +For å få testene og eventuell kode til øvingene lokalt brukes systemet git. Det er flere måter å hente nye øvinger: + +- I VS Code kan du klikke på Source Control (Venstresiden av programmet) -> Tre prikker øverst -> Pull for å hente den nye øvingen ved hjelp av dette. +- Du kan også bruke terminalen til å skrive `git pull` i mappen til øvingen for å hente den nye øvingen. + +## Dette må du gjøre + +Oppgavene for denne øvingen skal lagres i [`src/main/java/oving1`](../../src/main/java/oving1). Test-filene som kjøres for å teste koden ligger i [`src/test/java/oving1`](../../src/test/java/oving1). + +Hvis du ikke allerede har gjort det, må du installere VS Code med det forhåndskonfigurerte oppsettet for TDT4100. Se [denne](https://www.ntnu.no/wiki/display/tdt4100/VS+Code) wikisiden for en guide. Dersom du opplever problemer med oppsett/installasjon send oss gjerne en melding på Teams i "Teknisk Hjelp" kanalen, still et spørsmål på Piazza eller spør din læringsassistent! + +### Del 1 - Tilstandsdiagram + +For én av oppgavene du gjør i del 2: Tegn et [objekttilstandsdiagram](https://www.ntnu.no/wiki/x/gSfuAw) for en tenkt bruk av klassen. Velg selv en passende start-tilstand og en sekvens av kall. Lag dette diagrammet før du begynner med koden. + +### Del 2 - Java-kode + +Du skal velge og gjennomføre minst tre av de følgende oppgavene angående [Tilstand og oppførsel](https://www.ntnu.no/wiki/pages/viewpage.action?pageId=65937373). + +- [Account (Lett)](./Account.md) +- [Location (Lett)](./Location.md) +- [Digit (Lett)](./Digit.md) +- [UpOrDownCounter (Medium)](./UpOrDownCounter.md) +- [LineEditor (Vanskelig)](./LineEditor.md) +- [Rectangle (Vanskelig)](./Rectangle.md) +- [StopWatch (Vanskelig)](./StopWatch.md) + +Oppgavene er merket med en vanskelighetsgrad relativt til hverandre. Det er en god idé å begynne med de lettere oppgavene dersom du ikke er komfortabel med pensum så langt, men det er anbefalt å prøve seg på de vanskeligere oppgavene om du synes de første oppgavene er uproblematiske. Dersom du allerede føler deg trygg på punktene i øvingskravene kan du forsøke å gå rett på de vanskeligere oppgavene. Du er selvfølgelig velkommen til å løse flere oppgaver enn minstekravet, hvilket lurt gjøres med tanke på eksamen og et langt liv som programmerende. + +Før du setter i gang kan det vært lurt å lese wiki-siden om [Tilstand og oppførsel](https://www.ntnu.no/wiki/pages/viewpage.action?pageId=65937373) nøye, samt ta en titt på det tilhørende `Counter`-eksempelet. Forelesningene og tilhørende øvingsforelesning er selvsagt også lure å få med seg + +Det finnes masse ressurser på [wikien](https://www.ntnu.no/wiki/display/tdt4100/Faginnhold) om hvordan ulike metoder skal fungere, f.eks `toString()`-metoden og ulike metoder for teksthåndtering. Naviger deg litt rundt om du lurer på noe. + +## Hjelp/Mistanke om bugs + +Ved spørsmål eller behov for hjelp konsulter studassen din i saltiden hans / hennes. Du kan også oppsøke andre studasser på sal eller legge ut et innlegg på [Piazza](https://piazza.com/ntnu.no/spring2025/tdt4100). + +## Godkjenning + +Last opp kildekode på Blackboard innen den angitte innleveringsfristen. Innlevert kode skal demonstreres for læringsassistent innen én uke etter innleveringsfrist. Se Blackboard-sidene for mer informasjon rundt organisering av øvingsopplegget og det tilhørende øvingsreglementet. diff --git a/oppgavetekster/oving1/Rectangle.md b/oppgavetekster/oving1/Rectangle.md new file mode 100644 index 0000000..1793780 --- /dev/null +++ b/oppgavetekster/oving1/Rectangle.md @@ -0,0 +1,51 @@ +# Tilstand og oppførsel – Rectangle + +Oppgaven handler om en `Rectangle`-klasse, som håndterer et firkantet område i et koordinatsystem, med sider parallelle med koordinataksene. + +Tilstanden i `Rectangle`-objekter er ikke spesifisert eksplisitt, men må velges slik at metodene nedenfor kan implementerers. Merk at alle metodene jobber med heltallsstørrelser. + +`Rectangle`-klassen har metoder for å spørre om tilstanden og endre tilstanden. Spørremetodene dekker høyde og bredde og koordinatene til øverste venstre og nederste høyre hjørne og om rektanglet inneholder spesifikke punkt(er). Endringsmetodene dekker utviding ved å legge til punkter. + +Logikken til metodene må tilfredsstille følgende krav: + +- Når en utvider et `Rectangle`-objekt med en av `add`-metodene, så skal ikke rektanglet bli større enn nødvendig, dvs. at dersom man må utvide rektangelet skal det bare utvides slik at det akkurat inneholder det nye punktet. +- Et rektangel er tomt dersom enten bredden eller høyden er 0. + +Konstruktører: + +- `Rectangle(int x1, int y1, int x2, int y2)` - Lager et minst mulig rektangel som inneholder både punktene `(x1, y1)` og `(x2, y2)` + +Spørremetoder: + +- `int getMinX()` og `int getMinY()` - returnerer henholdsvis `x`- og `y`-koordinatene til punktet med lavest `(x,y)`-verdier som er inneholdt i dette rektanglet. +- `int getMaxX()` og `int getMaxY()` - returnerer henholdsvis `x`- og `y`-koordinatene til punktet med høyest `(x,y)`-verdier som er inneholdt i dette rektanglet. +- `int getWidth()` og `int getHeight()` - returnerer henholdsvis bredden og høyden til rektanglet. Begge skal returnere `0`, dersom dette rektanglet er tomt. +- `boolean isEmpty()` - returnerer `true` om rektanglet er tomt, dvs. om bredden og/eller høyden er `0`. +- `boolean contains(int x, int y)` - returnerer `true` om punktet `(x,y)` er inneholdt i dette rektanglet, og `false` ellers. +- `boolean contains(Rectangle rect)` - returnerer `true` om hele `rect`, dvs. alle hjørnepunktene i `rect`, er inneholdt i dette rektanglet, og false ellers. + +Endringsmetoder: + +- `boolean add(int x, int y)` - utvider (om nødvendig) dette rektanglet slik at det (akkurat) inneholder punktet `(x,y)`. Returnerer `true` om dette rektanglet faktisk ble endret, ellers `false`. +- `boolean add(Rectangle rect)` - utvider (om nødvendig) dette rektanglet slik at det (akkurat) inneholder hele `rect`-argumentet. Returnerer `true` om dette rektanglet faktisk ble endret, ellers `false`. Dersom `rect` er tomt, så skal dette rektanglet ikke endres. + +Andre metoder: + +- `Rectangle union(Rectangle rect)` - returnerer et nytt `Rectangle`-objekt som tilsvarer kombisjonen av dette rektanglet og `rect`-argumentet. Alle punktene som finnes i ett av rektanglene skal altså være inneholdt i rektanglet som returneres. + +## Java-kode + +Skriv Java-kode for `Rectangle`-klassen med oppførsel som er beskrevet over. + +Lag en passende `toString()`-metode og et hovedprogram, slik at du kan sjekke at oppførselen stemmer med tilstandsdiagrammet (bruk samme sekvens av kall). + +Testkode for denne oppgaven finner du her: [src/test/java/oving1/RectangleTest.java](../../src/test/java/oving1/RectangleTest.java). + +## Ekstraoppgave + +Implementer følgende metoder: + +- `Rectangle intersection(Rectangle rect)` - returnerer et nytt `Rectangle`-objekt som tilsvarer overlappet mellom dette rektanglet og `rect`-argumentet. Alle punktene som finnes i begge rektanglene skal altså være inneholdt i rektanglet som returneres. Dersom rektanglene ikke overlapper skal `null` returneres. +- `boolean intersects(Rectangle rect)` - returnerer `true` om dette rektanglet og `rect`-argumentet overlapper, dvs. om det finnes ett eller flere punkter som er inneholdt i begge disse rektanglene. + +Testkode for ekstraoppgaven finner du her: [src/test/java/oving1/RectangleExtraTest.java](../../src/test/java/oving1/RectangleExtraTest.java). diff --git a/oppgavetekster/oving1/StopWatch.md b/oppgavetekster/oving1/StopWatch.md new file mode 100644 index 0000000..fbaa10e --- /dev/null +++ b/oppgavetekster/oving1/StopWatch.md @@ -0,0 +1,47 @@ +# Tilstand og oppførsel – StopWatch + +Oppgaven handler om en `StopWatch`-klasse, som implementerer en stoppeklokke med funksjoner for å starte, ta rundetider og stoppe. + +Klassen skal implementere logikken ofte funnet på stoppeklokker på smarttelefoner. + +![StopWatch](./img/stopwatch.gif) + +For å holde styr på tiden som går vil `StopWatch`-klassen bli kalt utenfra (altså noe du slipper å implementere i denne oppgaven) på en `tick(int)`-metode. I dataverdenen er et tick (tikk på norsk) minste målbare diskret tidsenhet. I denne oppgaven er 1 tikk = 1 millisekund. F.eks. vil et kall `tick(3)` fortelle en `StopWatch`-instans at `3` tikk har gått siden sist gang `tick()` ble kalt. + +> Spesielt i denne oppgaven kan det være fordelaktig å lese testene for å forstå hva som forventes av koden. Dette er en god øvelse for videre øvinger og eksamen. + +StopWatch skal fungere på følgende måte: + +- Klokken startes når man ønsker å starte tidtakningen. +- Alle tikk etter at klokken har blitt startet skal medregnes i tidtakningen. +- Klokken stoppes når man ønsker å stoppe tidtakningen. Da er tidtakningen helt ferdig. Det er ikke en pause i tidtakningen - klokken skal ikke startes igjen. +- Det skal være mulig å ta rundetider. +- Første rundetid startes når klokken starter. +- Under tidtakningen kan man starte en ny rundetid, og dermed implisitt avslutte den nåværende. +- Siste rundetid avsluttes når klokken stoppes. + +`StopWatch`-klassen må ha metoder for å spørre om tilstanden og metoder for å endre tilstanden. + +Klassen skal ha følgende spørremetoder: + +- `boolean isStarted()` - returnerer `true` om klokken har blitt startet eller `false` om den ikke har blitt startet. +- `boolean isStopped()` - returnerer `true` om klokken har blitt stoppet eller `false` om den ikke har blitt stoppet. Merk at her snakker vi om at klokken har blitt stoppet minst én gang, ikke om klokken går eller ikke. +- `int getTicks()` - returnerer det totale antall tikk (millisekunder) som har gått i levetiden til klokken uavhengig om klokken har vært startet eller stoppet. +- `int getTime()` - returnerer antall tikk som har gått under tidtakningen. Hvis tidtakningen ikke har startet returner `-1`. Merk at hvis klokken er startet, men ikke stoppet, skal metoden returnere antall tikk som har gått siden klokken ble startet til nå. Hvis klokken er stoppet skal metoden returnere antall tikk som har gått fra klokken ble startet til klokken ble stoppet. +- `int getLapTime()` - returnerer antall tikk som har gått under nåværende rundetid til nå. Hvis tidtakningen ikke har startet returner `-1`. +- `int getLastLapTime()` - returnerer lengden på forrige avsluttede rundetid. Hvis det ikke er noen tidligere rundetider returner `-1`. + +Klassen skal ha følgende metoder for å endre tilstanden: + +- `void tick(int ticks)` - forteller klokken at `ticks` antall tikk har gått. +- `void start()` - starter klokken. +- `void lap()` - avslutter nåværende rundetid og starter en ny. +- `void stop()` - stopper klokken. + +## Java-kode + +Skriv Java-kode for `StopWatch`-klassen med oppførsel som er beskrevet over. + +Lag en passende `toString()`-metode og en `main()`-metode, slik at du kan sjekke at oppførselen stemmer med tilstandsdiagrammet (bruk samme sekvens av kall). + +Testkode for denne oppgaven finner du her: [src/test/java/oving1/StopWatchTest.java](../../src/test/java/oving1/StopWatchTest.java). diff --git a/oppgavetekster/oving1/UpOrDownCounter.md b/oppgavetekster/oving1/UpOrDownCounter.md new file mode 100644 index 0000000..67a71a0 --- /dev/null +++ b/oppgavetekster/oving1/UpOrDownCounter.md @@ -0,0 +1,13 @@ +# Tilstand og oppførsel – UpOrDownCounter + +I denne oppgaven skal du programmere en teller, ikke ulik den som er beskrevet i [Tilstand og oppførsel](https://www.ntnu.no/wiki/pages/viewpage.action?pageId=65937373) og kodet i [Tilstand og oppførsel - Java-kode for Counter-eksempel](https://www.ntnu.no/wiki/pages/viewpage.action?pageId=65937823), som også skal håndtere tilfellet hvor slutt-verdien er lavere enn start-verdien ved å telle nedover. + +## Java-kode + +`UpOrDownCounter`-klassen skal altså ha de samme konstruktørene/metodene: + +- `UpOrDownCounter(int start, int end)` - initialiserer objektet med angitte start- og slutt-verdier, hvor altså slutt kan være større eller mindre enn start, slik at telleren teller henholdsvis opp eller ned. Lik start og slutt-verdi skal utløse unntak av typen `IllegalArgumentException` (se [Koding av valideringsmetoder](https://www.ntnu.no/wiki/display/tdt4100/Koding+av+valideringsmetoder)). +- `int getCounter()` - returnerer telleren +- `boolean count()` - beveger telleren i retning av slutt-verdien og returnerer true så lenge den ikke har nådd den, altså om telleren har mer igjen, og false ellers. + +Testkode for oppgaven finner du her: [src/test/java/oving1/UpOrDownCounterTest.java](../../src/test/java/oving1/UpOrDownCounterTest.java) diff --git a/oppgavetekster/oving1/img/coordinate.png b/oppgavetekster/oving1/img/coordinate.png new file mode 100644 index 0000000..cb75085 Binary files /dev/null and b/oppgavetekster/oving1/img/coordinate.png differ diff --git a/oppgavetekster/oving1/img/stopwatch.gif b/oppgavetekster/oving1/img/stopwatch.gif new file mode 100644 index 0000000..e5c39dd Binary files /dev/null and b/oppgavetekster/oving1/img/stopwatch.gif differ diff --git a/src/main/java/oving1/.gitkeep b/src/main/java/oving1/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/src/test/java/oving1/AccountTest.java b/src/test/java/oving1/AccountTest.java new file mode 100644 index 0000000..bd916db --- /dev/null +++ b/src/test/java/oving1/AccountTest.java @@ -0,0 +1,55 @@ +package oving1; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +public class AccountTest { + + private double delta = 1e-8; + private Account account; + + @BeforeEach + public void setUp() { + account = new Account(); + } + + @Test + @DisplayName("Constructor") + public void testConstructor() { + assertEquals(0.0, account.getBalance(), delta, "Wrong balance for newly created account"); + } + + @Test + @DisplayName("Deposit") + public void testDeposit() { + account.deposit(100); + + assertEquals(100.0, account.getBalance(), delta, "Wrong balance after depositing"); + } + + @Test + @DisplayName("Negative deposit") + public void testNegativeDeposit() { + account.deposit(-50); + + assertEquals(0.0, account.getBalance(), delta, + "Wrong balance after making negative deposit"); + } + + @Test + @DisplayName("Adding interest") + public void testAddInterest() { + account.setInterestRate(5); + assertEquals(0, account.getBalance(), delta, "Wrong balance after updating interest rate"); + assertEquals(5, account.getInterestRate(), delta, + "Wrong interest rate after updating interest rate"); + + account.deposit(100); + assertEquals(100, account.getBalance(), delta, "Wrong balance after depositing"); + + account.addInterest(); + assertEquals(105, account.getBalance(), delta, "Wrong balance after adding interest"); + } +} diff --git a/src/test/java/oving1/DigitTest.java b/src/test/java/oving1/DigitTest.java new file mode 100644 index 0000000..e32d45d --- /dev/null +++ b/src/test/java/oving1/DigitTest.java @@ -0,0 +1,69 @@ +package oving1; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + + +public class DigitTest { + + private String digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + + @Test + @DisplayName("Constructor") + public void testConstructor() { + Digit digit = new Digit(10); + assertEquals(0, digit.getValue(), "Wrong value when using constructor"); + assertEquals(10, digit.getBase(), "Wrong base when using constructor"); + } + + @Test + @DisplayName("Increment value") + public void testIncrementedValue() { + for (int base = 2; base < 17; base++) { + Digit digit = new Digit(base); + assertEquals(0, digit.getValue(), "Wrong value for created digit"); + + int i = 1; + + while (i < base) { + boolean result = digit.increment(); + assertEquals(i, digit.getValue(), "The value was not incremented correctly"); + assertFalse(result, + "Increment should return false when the value is less than the base"); + i++; + } + + boolean result = digit.increment(); + assertEquals(0, digit.getValue(), + "The value was not reset to 0 when it became equal to the base"); + assertTrue(result, "Increment should return true when the value is reset to 0"); + } + } + + @Test + @DisplayName("Increment value and convert to string") + public void testIncrementedToString() { + for (int base = 2; base < 17; base++) { + Digit digit = new Digit(base); + assertEquals("0", digit.toString(), "Wrong string representation"); + + int i = 1; + + while (i < base) { + boolean result = digit.increment(); + assertEquals(String.valueOf(digits.charAt(i)), digit.toString(), + "Wrong string representation"); + assertFalse(result, + "Increment should return false when the value is less than the base"); + i++; + } + + boolean result = digit.increment(); + assertEquals("0", digit.toString(), "Wrong string representation"); + assertTrue(result, "Increment should return true when the value is reset to 0"); + } + } +} diff --git a/src/test/java/oving1/LineEditorTest.java b/src/test/java/oving1/LineEditorTest.java new file mode 100644 index 0000000..4b6cd2c --- /dev/null +++ b/src/test/java/oving1/LineEditorTest.java @@ -0,0 +1,137 @@ +package oving1; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +public class LineEditorTest { + + private LineEditor lineEditor; + + private void checkEditorContent(String s) { + assertEquals(s, lineEditor.toString(), "Wrong value returned by toString()"); + + int pos = s.indexOf('|'); + assertEquals(s.substring(0, pos) + s.substring(pos + 1), lineEditor.getText(), + "Wrong text value returned"); + assertEquals(pos, lineEditor.getInsertionIndex(), "Wrong insertion index"); + } + + @BeforeEach + public void setUp() { + lineEditor = new LineEditor(); + } + + @Test + @DisplayName("Constructor") + public void testContstructor() { + this.checkEditorContent("|"); + } + + @Test + @DisplayName("Setter methods") + public void testSetters() { + lineEditor.setText("Hello World!"); + this.checkEditorContent("|Hello World!"); + + lineEditor.setInsertionIndex(5); + this.checkEditorContent("Hello| World!"); + } + + @Test + @DisplayName("Insert string at end") + public void testInsertStringAtEnd() { + lineEditor.insertString(""); + this.checkEditorContent("|"); + + lineEditor.insertString("Java"); + this.checkEditorContent("Java|"); + + lineEditor.insertString(" er gøy!"); + this.checkEditorContent("Java er gøy!|"); + } + + @Test + @DisplayName("Insert string in the middle") + public void testInsertStringMiddle() { + lineEditor.setText("Javagøy!"); + lineEditor.setInsertionIndex(4); + lineEditor.insertString(" er "); + this.checkEditorContent("Java er |gøy!"); + } + + @Test + @DisplayName("Insert string at the begginning") + public void testInsertStringAtBeginning() { + lineEditor.setText("er gøy!"); + lineEditor.setInsertionIndex(0); + lineEditor.insertString("Java "); + this.checkEditorContent("Java |er gøy!"); + } + + @Test + @DisplayName("Move left") + public void testLeft() { + lineEditor.left(); + this.checkEditorContent("|"); + + lineEditor.setText("J"); + lineEditor.setInsertionIndex(1); + this.checkEditorContent("J|"); + + lineEditor.left(); + this.checkEditorContent("|J"); + } + + @Test + @DisplayName("Move right") + public void testRight() { + lineEditor.right(); + this.checkEditorContent("|"); + + lineEditor.setText("J"); + lineEditor.setInsertionIndex(0); + this.checkEditorContent("|J"); + + lineEditor.right(); + this.checkEditorContent("J|"); + } + + @Test + @DisplayName("Delete left") + public void testDeleteLeft() { + lineEditor.deleteLeft(); + this.checkEditorContent("|"); + + lineEditor.insertString("J"); + lineEditor.deleteLeft(); + this.checkEditorContent("|"); + + lineEditor.insertString("Java"); + lineEditor.setInsertionIndex(2); + this.checkEditorContent("Ja|va"); + + lineEditor.deleteLeft(); + this.checkEditorContent("J|va"); + } + + @Test + @DisplayName("Delete right") + public void testDeleteRight() { + lineEditor.deleteRight(); + this.checkEditorContent("|"); + + lineEditor.insertString("J"); + lineEditor.setInsertionIndex(0); + lineEditor.deleteRight(); + this.checkEditorContent("|"); + + lineEditor.insertString("Java"); + lineEditor.setInsertionIndex(2); + this.checkEditorContent("Ja|va"); + + lineEditor.deleteRight(); + this.checkEditorContent("Ja|a"); + } +} diff --git a/src/test/java/oving1/LocationTest.java b/src/test/java/oving1/LocationTest.java new file mode 100644 index 0000000..95b5d18 --- /dev/null +++ b/src/test/java/oving1/LocationTest.java @@ -0,0 +1,101 @@ +package oving1; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +public class LocationTest { + + private Location loc; + + /** + * Check that the position of {@link #loc} is equal to the parameters. + * + * @param x Expected x position + * @param y Expected y position + */ + private void checkPos(int x, int y) { + assertEquals(x, loc.getX(), "Wrong x coordinate"); + assertEquals(y, loc.getY(), "Wrong y coordinate"); + } + + @BeforeEach + public void beforeEach() { + loc = new Location(); + } + + @Test + @DisplayName("Constructor") + public void testConstructor() { + this.checkPos(0, 0); + } + + @Test + @DisplayName("Move up") + public void testUp() { + loc.up(); + this.checkPos(0, -1); + + loc.up(); + this.checkPos(0, -2); + } + + @Test + @DisplayName("Move down") + public void testDown() { + loc.down(); + this.checkPos(0, 1); + + loc.down(); + this.checkPos(0, 2); + } + + @Test + @DisplayName("Move left") + public void testLeft() { + loc.left(); + this.checkPos(-1, 0); + + loc.left(); + this.checkPos(-2, 0); + } + + @Test + @DisplayName("Move right") + public void testRight() { + loc.right(); + this.checkPos(1, 0); + + loc.right(); + this.checkPos(2, 0); + } + + @Test + @DisplayName("Move multiple directions") + public void testComplexMovement() { + loc.right(); + this.checkPos(1, 0); + + loc.down(); + this.checkPos(1, 1); + + loc.right(); + this.checkPos(2, 1); + + loc.down(); + this.checkPos(2, 2); + + loc.left(); + this.checkPos(1, 2); + + loc.up(); + this.checkPos(1, 1); + + loc.up(); + this.checkPos(1, 0); + + loc.left(); + this.checkPos(0, 0); + } +} diff --git a/src/test/java/oving1/RectangleExtraTest.java b/src/test/java/oving1/RectangleExtraTest.java new file mode 100644 index 0000000..a55c070 --- /dev/null +++ b/src/test/java/oving1/RectangleExtraTest.java @@ -0,0 +1,31 @@ +package oving1; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static oving1.RectangleTest.assertValues; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +public class RectangleExtraTest { + + @Test + @DisplayName("Intersecting rectangles") + public void testIntersection() { + Rectangle rect1 = new Rectangle(0, 0, 5, 5); + Rectangle rect2 = new Rectangle(3, 3, 7, 7); + Rectangle intersection = rect1.intersection(rect2); + assertValues(intersection, 3, 3, 5, 5, 2, 2, " for intersecting rectangle"); + assertTrue(rect1.intersects(rect2), "Wrong value from #intersects(Rectangle)"); + } + + @Test + @DisplayName("Non-intersecting rectangles") + public void testNonIntersection() { + Rectangle rect1 = new Rectangle(-3, -3, 0, 0); + Rectangle rect2 = new Rectangle(3, 3, 7, 7); + Rectangle intersection = rect1.intersection(rect2); + assertNull(intersection, "Intersection of two non-intersecting rectangles should be null"); + assertFalse(rect1.intersects(rect2), "Wrong value from #intersects(Rectangle)"); + } +} diff --git a/src/test/java/oving1/RectangleTest.java b/src/test/java/oving1/RectangleTest.java new file mode 100644 index 0000000..9db9c8e --- /dev/null +++ b/src/test/java/oving1/RectangleTest.java @@ -0,0 +1,271 @@ +package oving1; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +public class RectangleTest { + + // Used in RectangleExtraTest as well + /** + * Compares all values in a given {@link Rectangle} to a set of expected values. + * + * @param rect The rectangle to check + * @param minX The expected minimum x value of rect + * @param minY The expected minimum y value of rect + * @param maxX The expected maximum x value of rect + * @param maxY The expected maximum y value of rect + * @param width The expected width of rect + * @param height The expected height of rect + */ + public static void assertValues(Rectangle rect, int minX, int minY, int maxX, int maxY, + int width, int height, String suffix) { + assertEquals(minX, rect.getMinX(), "Wrong minX " + suffix); + assertEquals(minY, rect.getMinY(), "Wrong minY " + suffix); + assertEquals(maxX, rect.getMaxX(), "Wrong maxX " + suffix); + assertEquals(maxY, rect.getMaxY(), "Wrong maxY " + suffix); + assertEquals(width, rect.getWidth(), "Wrong width " + suffix); + assertEquals(height, rect.getHeight(), "Wrong height " + suffix); + } + + /** + * Check that a rectangle is empty. + * + * @param rect The rectangle to check + */ + private static void assertEmpty(Rectangle rect) { + assertTrue(rect.isEmpty(), "Expected rectangle to be empty!"); + assertTrue(rect.getWidth() == 0 || rect.getHeight() == 0, + "Empty rectangle should either have a width or height of 0!"); + } + + @Test + @DisplayName("Empty rectangle") + public void testEmpty() { + // Test creating empty rectangle + Rectangle rect1 = new Rectangle(0, 0, 0, 0); + assertEmpty(rect1); + + // Test creating empty rectangle with only 0 height + Rectangle rect2 = new Rectangle(3, 2, 1, 2); + assertEmpty(rect2); + + // Test creating empty rectangle with only 0 width + Rectangle rect3 = new Rectangle(3, 1, 3, 2); + assertEmpty(rect3); + } + + @Test + @DisplayName("Rectangle constructor") + public void testConstructor() { + // Simple test + Rectangle rect1 = new Rectangle(0, 0, 1, 2); + RectangleTest.assertValues(rect1, 0, 0, 1, 2, 1, 2, "when testing constructor"); + + // Test providing points in opposite order + Rectangle rect2 = new Rectangle(1, 2, 0, 0); + RectangleTest.assertValues(rect2, 0, 0, 1, 2, 1, 2, "when testing constructor"); + + // Test negative values + Rectangle rect3 = new Rectangle(3, 3, -1, 5); + RectangleTest.assertValues(rect3, -1, 3, 3, 5, 4, 2, "when testing constructor"); + } + + private void testAdd(Rectangle rect, int x, int y, boolean expected) { + assertEquals(expected, rect.add(x, y), + "Wrong value returned when adding (" + x + ", " + y + ") to " + rect); + assertFalse(rect.isEmpty(), "Rectangle should not be empty after adding a point!"); + assertTrue(rect.contains(x, y), + "Rectangle should contain the point that has been just added!"); + } + + @Test + @DisplayName("Adding point to rectangle") + public void testAddXY() { + int x1 = 13; + int y1 = -27; + int x2 = -11; + int y2 = 23; + int x3 = 15; + int y3 = 33; + + Rectangle rect = new Rectangle(x1, y1, x2, y2); + + // Add (x3, y3) and check that rect is updated accordingly + this.testAdd(rect, x3, y3, true); + + int minX1X2 = Math.min(x1, x2), minY1Y2 = Math.min(y1, y2); + int maxX1X2 = Math.max(x1, x2), maxY1Y2 = Math.max(y1, y2); + int minX1X2X3 = Math.min(minX1X2, x3), minY1Y2Y3 = Math.min(minY1Y2, y3); + int maxX1X2X3 = Math.max(maxX1X2, x3), maxY1Y2Y3 = Math.max(maxY1Y2, y3); + + RectangleTest.assertValues(rect, minX1X2X3, minY1Y2Y3, maxX1X2X3, maxY1Y2Y3, + maxX1X2X3 - minX1X2X3, maxY1Y2Y3 - minY1Y2Y3, + "when adding point that is not in rectangle"); + } + + @Test + @DisplayName("Adding point already in rectangle") + public void testAddSameXY() { + int x1 = 13; + int y1 = -27; + int x2 = -11; + int y2 = 23; + int x3 = 15; + int y3 = 33; + + int minX1X2 = Math.min(x1, x2); + int minY1Y2 = Math.min(y1, y2); + int maxX1X2 = Math.max(x1, x2); + int maxY1Y2 = Math.max(y1, y2); + int minX1X2X3 = Math.min(minX1X2, x3); + int minY1Y2Y3 = Math.min(minY1Y2, y3); + int maxX1X2X3 = Math.max(maxX1X2, x3); + int maxY1Y2Y3 = Math.max(maxY1Y2, y3); + + Rectangle rect = new Rectangle(x1, y1, x2, y2); + + // Add (x3, y3) and check that rect is updated accordingly + this.testAdd(rect, x3, y3, true); + RectangleTest.assertValues(rect, minX1X2X3, minY1Y2Y3, maxX1X2X3, maxY1Y2Y3, + maxX1X2X3 - minX1X2X3, maxY1Y2Y3 - minY1Y2Y3, + "when adding point that is not in rectangle"); + + // Add (x3, y3) again and check that all state is the same, with false response + this.testAdd(rect, x3, y3, false); + RectangleTest.assertValues(rect, minX1X2X3, minY1Y2Y3, maxX1X2X3, maxY1Y2Y3, + maxX1X2X3 - minX1X2X3, maxY1Y2Y3 - minY1Y2Y3, + "when adding point that is in rectangle"); + } + + @Test + @DisplayName("Adding other rectangle") + public void testAddRectangle() { + // Add a point to this.rect + int x1 = 13; + int y1 = -27; + int x2 = -11; + int y2 = 23; + int x3 = 15; + int y3 = 33; + int minX1X2 = Math.min(x1, x2); + int minY1Y2 = Math.min(y1, y2); + int maxX1X2 = Math.max(x1, x2); + int maxY1Y2 = Math.max(y1, y2); + int minX1X3 = Math.min(x1, x3); + int minY1Y3 = Math.min(y1, y3); + int maxX1X3 = Math.max(x1, x3); + int maxY1Y3 = Math.max(y1, y3); + + int minX1X2X3 = Math.min(minX1X2, x3); + int minY1Y2Y3 = Math.min(minY1Y2, y3); + int maxX1X2X3 = Math.max(maxX1X2, x3); + int maxY1Y2Y3 = Math.max(maxY1Y2, y3); + int widthX1X2X3 = maxX1X2X3 - minX1X2X3; + int heightX1X2X3 = maxY1Y2Y3 - minY1Y2Y3; + + // Create a rectangle and fill it with some points. Assert that this rect is correct + Rectangle rect = new Rectangle(x1, y1, x2, y2); + RectangleTest.assertValues(rect, minX1X2, minY1Y2, maxX1X2, maxY1Y2, maxX1X2 - minX1X2, + maxY1Y2 - minY1Y2, "when creating new rectangle"); + + // Create another rectangle and fill it with some points. Assert that this rect is correct + Rectangle rect2 = new Rectangle(x1, y1, x3, y3); + RectangleTest.assertValues(rect2, minX1X3, minY1Y3, maxX1X3, maxY1Y3, maxX1X3 - minX1X3, + maxY1Y3 - minY1Y3, "when creating new rectangle"); + + // Add rect to this.rect, and check correctness + assertTrue(rect.add(rect2)); + RectangleTest.assertValues(rect, minX1X2X3, minY1Y2Y3, maxX1X2X3, maxY1Y2Y3, widthX1X2X3, + heightX1X2X3, "when adding another rectangle"); + } + + @Test + @DisplayName("Adding rectangle to itself") + public void testAddSameRectangle() { + int x1 = 13; + int y1 = -27; + int x2 = -11; + int y2 = 23; + int width = Math.abs(x1 - x2); + int height = Math.abs(y1 - y2); + int minX1X2 = Math.min(x1, x2); + int minY1Y2 = Math.min(y1, y2); + int maxX1X2 = Math.max(x1, x2); + int maxY1Y2 = Math.max(y1, y2); + + // Create a rectangle and fill it with some points. Assert that this rect is correct + Rectangle rect = new Rectangle(x1, y1, x2, y2); + RectangleTest.assertValues(rect, minX1X2, minY1Y2, maxX1X2, maxY1Y2, width, height, + "when creating new rectangle"); + + // Add rectangle to itself and check that state stays the same + assertFalse(rect.add(rect), + "Expected no change when adding equal rectangle using #add(Rectangle)"); + RectangleTest.assertValues(rect, minX1X2, minY1Y2, maxX1X2, maxY1Y2, width, height, + "when adding the same rectangle to itself"); + } + + @Test + @DisplayName("Rectangle union") + public void testUnion() { + int x1 = 13; + int y1 = -27; + int x2 = -11; + int y2 = 23; + int x3 = 15; + int y3 = 33; + int x4 = 17; + int y4 = -33; + + int minX1X2 = Math.min(x1, x2); + int minY1Y2 = Math.min(y1, y2); + int maxX1X2 = Math.max(x1, x2); + int maxY1Y2 = Math.max(y1, y2); + int minX3X4 = Math.min(x3, x4); + int minY3Y4 = Math.min(y3, y4); + int maxX3X4 = Math.max(x3, x4); + int maxY3Y4 = Math.max(y3, y4); + + // Create two rectangles and check correctness + Rectangle rect1 = new Rectangle(x1, y1, x2, y2); + RectangleTest.assertValues(rect1, minX1X2, minY1Y2, maxX1X2, maxY1Y2, maxX1X2 - minX1X2, + maxY1Y2 - minY1Y2, "when creating new rectangle"); + + Rectangle rect2 = new Rectangle(x3, y3, x4, y4); + RectangleTest.assertValues(rect2, minX3X4, minY3Y4, maxX3X4, maxY3Y4, maxX3X4 - minX3X4, + maxY3Y4 - minY3Y4, "when creating new rectangle"); + + // Take the union (both ways), and check that both are the same + int minX = Math.min(minX1X2, minX3X4); + int minY = Math.min(minY1Y2, minY3Y4); + int maxX = Math.max(maxX1X2, maxX3X4); + int maxY = Math.max(maxY1Y2, maxY3Y4); + + Rectangle union1 = rect1.union(rect2); + RectangleTest.assertValues(union1, minX, minY, maxX, maxY, maxX - minX, maxY - minY, + "when calling #union with another rectangle"); + RectangleTest.assertValues(rect1, minX1X2, minY1Y2, maxX1X2, maxY1Y2, maxX1X2 - minX1X2, + maxY1Y2 - minY1Y2, + "Values changed when calling #union with another rectangle! Make sure to not " + + "create a new Rectangle and not modify the current ones!"); + RectangleTest.assertValues(rect2, minX3X4, minY3Y4, maxX3X4, maxY3Y4, maxX3X4 - minX3X4, + maxY3Y4 - minY3Y4, + "Values changed when calling #union with another rectangle! Make sure to not " + + "create a new Rectangle and not modify the current ones!"); + + Rectangle union2 = rect2.union(rect1); + RectangleTest.assertValues(union2, minX, minY, maxX, maxY, maxX - minX, maxY - minY, + "when calling #union with another rectangle"); + RectangleTest.assertValues(rect1, minX1X2, minY1Y2, maxX1X2, maxY1Y2, maxX1X2 - minX1X2, + maxY1Y2 - minY1Y2, + "Values changed when calling #union with another rectangle! Make sure to not " + + "create a new Rectangle and not modify the current ones!"); + RectangleTest.assertValues(rect2, minX3X4, minY3Y4, maxX3X4, maxY3Y4, maxX3X4 - minX3X4, + maxY3Y4 - minY3Y4, + "Values changed when calling #union with another rectangle! Make sure to not " + + "create a new Rectangle and not modify the current ones!"); + } +} diff --git a/src/test/java/oving1/StopWatchTest.java b/src/test/java/oving1/StopWatchTest.java new file mode 100644 index 0000000..57923fd --- /dev/null +++ b/src/test/java/oving1/StopWatchTest.java @@ -0,0 +1,153 @@ +package oving1; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + + +public class StopWatchTest { + + private StopWatch stopWatch; + + @BeforeEach + public void beforeEach() { + stopWatch = new StopWatch(); + } + + @Test + @DisplayName("Constructor") + public void testConstructor() { + assertFalse(stopWatch.isStarted(), "Stopwatch should not be started"); + assertFalse(stopWatch.isStopped(), "Stopwatch should not be stopped"); + assertEquals(0, stopWatch.getTicks(), "Wrong ticks returned"); + assertEquals(-1, stopWatch.getTime(), "Time should be -1 when not started"); + assertEquals(-1, stopWatch.getLapTime(), "Lap time should be -1 when not started"); + assertEquals(-1, stopWatch.getLastLapTime(), "Last lap time should be -1 when not started"); + } + + @Test + @DisplayName("Tick without starting") + public void testTicksWithoutStart() { + stopWatch.tick(1); + assertEquals(-1, stopWatch.getTime(), "Time should be -1 when not started"); + assertEquals(1, stopWatch.getTicks(), "Ticks should be 1 after calling #tick(1)"); + + stopWatch.tick(4); + assertEquals(-1, stopWatch.getTime(), "Time should be -1 when not started"); + assertEquals(5, stopWatch.getTicks(), "Ticks should be 5 after calling #tick(4)"); + } + + @Test + @DisplayName("Tick, start and stop 1") + public void testStartTickStop() { + stopWatch.start(); + assertEquals(0, stopWatch.getTime(), "Time should be 0 when just started"); + assertEquals(0, stopWatch.getTicks(), "Ticks should be 0 when #tick() has not been called"); + assertTrue(stopWatch.isStarted(), "Should be started after calling #start()"); + assertFalse(stopWatch.isStopped(), "Should not be stopped before calling #stop()"); + + stopWatch.tick(3); + assertEquals(3, stopWatch.getTime(), + "Time should be 3 when started and #tick(3) has been called"); + assertEquals(3, stopWatch.getTicks(), "Ticks should be 3 when #tick(3) has been called"); + assertTrue(stopWatch.isStarted(), "Should be started after calling #start()"); + assertFalse(stopWatch.isStopped(), "Should not be stopped before calling #stop()"); + + stopWatch.tick(5); + assertEquals(8, stopWatch.getTime(), + "Time should be 8 when started and #tick(5) has been called"); + assertEquals(8, stopWatch.getTicks(), "Ticks should be 8 when #tick(5) has been called"); + assertTrue(stopWatch.isStarted(), "Should be started after calling #start()"); + assertFalse(stopWatch.isStopped(), "Should not be stopped before calling #stop()"); + + stopWatch.stop(); + assertEquals(8, stopWatch.getTime(), "Time should be 8 after #stop() has been called"); + assertEquals(8, stopWatch.getTicks(), "Ticks should be 8 after #stop() has been called"); + assertTrue(stopWatch.isStarted(), "Should be started even after #stop() has been called"); + assertTrue(stopWatch.isStopped(), "Should be stopped after calling #stop()"); + } + + @Test + @DisplayName("Tick, start and stop 2") + public void testTickStartTickStopTick() { + stopWatch.tick(2); + assertEquals(-1, stopWatch.getTime(), "Time should be -1 when not started"); + assertEquals(2, stopWatch.getTicks(), "Ticks should be 2 when #tick(2) has been called"); + assertFalse(stopWatch.isStarted(), "Stopwatch should not be started"); + assertFalse(stopWatch.isStopped(), "Stopwatch should not be stopped"); + + stopWatch.start(); + assertEquals(0, stopWatch.getTime(), "Time should be 0 when just started"); + assertEquals(2, stopWatch.getTicks(), "Ticks should be 2 after #start() has been called"); + assertTrue(stopWatch.isStarted(), "Should be started after calling #start()"); + assertFalse(stopWatch.isStopped(), "Should not be stopped before calling #stop()"); + + stopWatch.tick(3); + assertEquals(3, stopWatch.getTime(), + "Time should be 3 when started and #tick(3) has been called"); + assertEquals(5, stopWatch.getTicks(), "Ticks should be 5 when #tick(3) has been called"); + assertTrue(stopWatch.isStarted(), "Should be started after calling #tick(3)"); + assertFalse(stopWatch.isStopped(), "Should not be stopped before calling #tick(3)"); + + stopWatch.tick(5); + assertEquals(8, stopWatch.getTime(), + "Time should be 8 when started and #tick(5) has been called"); + assertEquals(10, stopWatch.getTicks(), "Ticks should be 10 when #tick(5) has been called"); + assertTrue(stopWatch.isStarted(), "Should be started after calling #tick(5)"); + assertFalse(stopWatch.isStopped(), "Should not be stopped before calling #tick(5)"); + + stopWatch.stop(); + assertEquals(8, stopWatch.getTime(), "Time should be 8 after #stop() has been called"); + assertEquals(10, stopWatch.getTicks(), "Ticks should be 10 after #stop() has been called"); + assertTrue(stopWatch.isStarted(), "Should be started even after #stop() has been called"); + assertTrue(stopWatch.isStopped(), "Should be stopped after calling #stop()"); + + stopWatch.tick(3); + assertEquals(8, stopWatch.getTime(), + "Time should be 8 after #tick(3) has been called while stopped"); + assertEquals(13, stopWatch.getTicks(), + "Ticks should be 13 when #tick(3) has been called while stopped"); + assertTrue(stopWatch.isStarted(), + "Should be started even after #tick() has been called while stopped"); + assertTrue(stopWatch.isStopped(), "Should be stopped after calling #tick() while stopped"); + } + + @Test + @DisplayName("Lap times") + public void testLaps() { + stopWatch.start(); + assertEquals(0, stopWatch.getTime(), "Time should be 0 when just started"); + assertEquals(0, stopWatch.getLapTime(), "Lap time should be 0 when just started"); + assertEquals(-1, stopWatch.getLastLapTime(), + "Last lap time should be -1 when there is no previous lap"); + + stopWatch.tick(3); + assertEquals(3, stopWatch.getTime(), "Time should be 3 after #tick(3) has been called"); + assertEquals(3, stopWatch.getLapTime(), + "Lap time should be 3 after calling #tick(3) while started"); + assertEquals(-1, stopWatch.getLastLapTime(), + "Last lap time should be -1 when there is no previous lap"); + + stopWatch.lap(); + assertEquals(3, stopWatch.getTime(), "Time should still be 3 after starting a new lap"); + assertEquals(0, stopWatch.getLapTime(), "Current lap time should be 0 when just started"); + assertEquals(3, stopWatch.getLastLapTime(), + "Last lap time should be 3 when we just started a new lap"); + + stopWatch.tick(5); + assertEquals(8, stopWatch.getTime(), "Time should be 8 after #tick(5) has been called"); + assertEquals(5, stopWatch.getLapTime(), + "Current lap time should be 5 after calling #tick(5)"); + assertEquals(3, stopWatch.getLastLapTime(), + "Last lap time should be 3 even after time passes"); + + stopWatch.stop(); + assertEquals(8, stopWatch.getTime(), "Time should be 8 after stopping"); + assertEquals(0, stopWatch.getLapTime(), "Current lap time should be 0 when stopped"); + assertEquals(5, stopWatch.getLastLapTime(), + "Last lap should be the lap time of the current lap when stopping"); + } +} diff --git a/src/test/java/oving1/UpOrDownCounterTest.java b/src/test/java/oving1/UpOrDownCounterTest.java new file mode 100644 index 0000000..948d39e --- /dev/null +++ b/src/test/java/oving1/UpOrDownCounterTest.java @@ -0,0 +1,57 @@ +package oving1; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + + +public class UpOrDownCounterTest { + + @Test + @DisplayName("Count up") + public void testCountUp() { + UpOrDownCounter counter = new UpOrDownCounter(1, 5); + assertEquals(1, counter.getCounter(), + "Counter value should be equal to starting value when created"); + + for (int i = 2; i < 5; i++) { + boolean result = counter.count(); + assertEquals(i, counter.getCounter(), "Wrong counter value"); + assertTrue(result, "#count() should return true while within legal values"); + } + + boolean result = counter.count(); + assertEquals(5, counter.getCounter(), "Wrong counter value"); + assertFalse(result, "#count() should return false when we cannot count further"); + + result = counter.count(); + assertEquals(5, counter.getCounter(), + "Counter value should not change when counting beyond legal values"); + assertFalse(result, "#count() should return false when we cannot count further"); + } + + @Test + @DisplayName("Count down") + public void testCountDown() { + UpOrDownCounter counter = new UpOrDownCounter(1, -5); + assertEquals(1, counter.getCounter(), + "Counter value should be equal to starting value when created"); + + for (int i = 0; i > -5; i--) { + boolean result = counter.count(); + assertEquals(i, counter.getCounter(), "Wrong counter value"); + assertTrue(result, "#count() should return true while within legal values"); + } + + boolean result = counter.count(); + assertEquals(-5, counter.getCounter(), "Wrong counter value"); + assertFalse(result, "#count() should return false when we cannot count further"); + + result = counter.count(); + assertEquals(-5, counter.getCounter(), + "Counter value should not change when counting beyond legal values"); + assertFalse(result, "#count() should return false when we cannot count further"); + } +}