Commit 1668fb65 authored by Jostein Hjortland Tysse's avatar Jostein Hjortland Tysse
Browse files

Merge branch 'oving4' into 'main'

Add tests and descriptions for øving 4

See merge request tdt4100/v2022/students!5
parents e4c18285 832bbc17
......@@ -7,7 +7,7 @@ Denne mappen inneholder øvingstekster for TDT4100 - Objektorientert programmeri
| [Øving 1](oving1/README.md) | Tilstand og oppførsel |
| [Øving 2](oving2/README.md) | Innkapsling og validering |
| [Øving 3](oving3/README.md) | Klasser og testing |
| Øving 4 | Objektstrukturer |
| [Øving 4](oving4/README.md) | Objektstrukturer |
| Øving 5 | Grensesnitt |
| Øving 6 | Observatør-observert og delegering |
| Øving 7 | Arv og abstrakte klasser |
# Objektstrukturer - Card-oppgave del 2
Denne oppgaven handler om klasser for kortspill: `Card` (kort), `CardDeck` (kortstokk) og `CardHand` (korthånd), hvorav de to siste inneholder én eller flere `Card`-objekter. Oppgaven bygger på `Card` og `CardDeck` i [Innkapsling - Card-oppgave](../oving3/Card.md).
**Merk**: Om du ikke har gjort `Card`-oppgaven allerede, kan du bruke løsningsforslaget som er lagt ut under `lf/src/main/java/encapsulation`.
I mange sammenhenger vil objekter av en klasse inneholde eller "eie" objekter av andre klasser, og de underordnede objektene vil kunne flyttes/overføres mellom de overordnede. Når en klasse er assosiert med én instans av en (annen) klasse er dette en [1-1-assosiasjon](https://www.ntnu.no/wiki/display/tdt4100/Koding+av+1-1-assosiasjoner) og når en klasse er assosiert med flere instanser av en annen klasse er dette en [1-n-assosiasjon](https://www.ntnu.no/wiki/display/tdt4100/Koding+av+1-n-assosiasjoner). Et eksempel er kortspill, hvor kortene starter i kortstokken, fordeles på korthender og til slutt ender i en kortbunke. Et kort kan bare være ett sted om gangen, og må overføres fra ett sted til et annet, f.eks. fra kortstokk til korthender i utdelingsfasen. I [Innkapsling - Card-oppgave](../oving3/Card.md) ble det lagd logikk for kortstokk og enkeltkort. I denne oppgaven skal du implementere logikk for korthender, og utvide kortstokkens logikk litt.
`Card`-klassen har du allerede implementert, men du må sannsynligvis kopiere koden over fra `encapsulation` til `objectstructures`. Her er det enklest å lage en ny `Card`-klasse i `objectstructures` og så lime inn innholdet fra den gamle.
`CardDeck`-klassen har du også implementert, og denne må også flyttes på samme måte som Card. Denne klassen skal utvides:
- `deal(CardHand, int n)` - flytter n kort fra kortstokken (`CardDeck`-objektet) til korthånda (`CardHand`-objektet, som er første argument), ved å ta ett og ett kort med høyeste gyldige indeks, fjerne det fra `CardDeck`-objektet og legge det til `CardHand`-objektet.
`CardHand` er en ny klasse som skal implementeres. `CardHand`-objekter inneholder initielt ingen kort, og klassen inneholder de samme standardmetodene som `CardDeck`, altså `getCardCount()` og `getCard(int)`, for å lese hvor mange og hvilke kort den inneholder. I tillegg har den to metoder for å endre tilstand:
- `addCard(Card)` - legger argumentet til dette `CardHand`-objektet
- `play(int n)` - returnerer og fjerner kort nr. n (første kort har nr. 0) fra dette `CardHand`-objektet (som om det ble spilt ut)
**Java-kode**
Utvid `CardDeck` og lag `CardHand` som beskrevet over. Test klassene med selvlagde main-metoder og ved å kjøre JUnit-testene.
Testkode for denne oppgaven finner du her: [CardTest.java](../../src/test/java/oving4/CardTest.java), [CardDeckTest.java](../../src/test/java/oving4/CardDeckTest.java), [CardHandTest.java](../../src/test/java/oving4/CardHandTest.java).
# Objektstrukturer - Partner-oppgave
Denne oppgaven handler om en `Partner`-klasse med en [1-1-assosiasjon](https://www.ntnu.no/wiki/display/tdt4100/Koding+av+1-1-assosiasjoner)
kalt partner tilbake til samme klasse (altså kjønnsnøytralt partnerskap)
og det å sikre konsistens, slik at Partner-objekter er parvis knyttet sammen.
En viktig del av det å implementere assosiasjoner er å sikre konsistens, dvs. at objekter i hver ende av en kobling refererer korrekt til
hverandre. Et eksempel på dette for [1-1-assosiasjoner](https://www.ntnu.no/wiki/display/tdt4100/Koding+av+1-1-assosiasjoner) er
(kjønnsnøytralt) partnerskap, hvor to partnere er koblet til hverandre når partnerskap
inngås og kobles fra hverandre ved en evt. skillsmisse. I denne oppgaven skal en `Partner`-klasse implementeres og ulike situasjoner håndteres
korrekt, som illustrert nedenfor.
`Partner`-klassen skal inneholde informasjon om _navn_ (en String), som bare skal kunne settes i konstruktøren, og _partneren_, som er et annet
Partner-objekt. Navnet er ikke viktig for oppførselen, men er grei å ha med i en `toString()`-metode, for å skille Partner-objektene fra
hverandre. `Partner`-klassen skal ha følgende metoder for å lese tilstanden:
- `getName()` - returnerer navnet knyttet til dette Partner-objektet
- `getPartner()` - returnerer Partner-objektet som er knyttet til dette Partner-objektet, evt. null, hvis partnerskap ikke er inngått
`Partner`-klassen har kun én endringsmetode, `setPartner(Partner)`, som brukes både for å inngå partnerskap, når argumentet er et Partner-objekt,
og oppløse det, når argumentet er null. List og figurene under illustrerer de tre tilfellene som må kunne håndteres, og som JUnit-testene sjekker.
### 1. Inngåelse av partnerskap:
**Kall**: p1.setPartner(p2)
**Beskrivlse**: Partner-objektene p1 og p2 kobles sammen med ett kall til setPartner. Før kallet er p1 og p2 ikke koblet sammen,
og etter kallet er det koblet sammen.
**Før kall**:
![](img/partner1.png)
**Etter kall**:
![](img/partner2.png)
### 2. Oppløsning av partnerskap:
**Kall**: p1.setPartner(null)
**Beskrivlse**: Partner-objektene p1 og p2 kobles fra hverandre med ett kall til setPartner med null som argument.
Før kallet er p1 og p2 koblet sammen, og etter kallet er det ikke lenger koblet sammen.
**Før kall**:
![](img/partner2.png)
**Etter kall**:
![](img/partner1.png)
### 3. Oppløsning og inngåelse av partnerskap i ett:
**Kall**: p1.setPartner(p3)
**Beskrivlse**: Partner-objektene p1, p2, p3 og p4 er parvis koblet sammen, før ett kall til setPartner kobler
sammen p1 og p3, mens p2 og p4 kobles fra deres tidligere partnere.
**Før kall**:
![](img/partner3.png)
**Etter kall**:
![](img/partner4.png)
## Gjøremål
Oppgaven er (enkelt og greit) å implementere `Partner`-klassen og sjekke (f.eks. med en `main`-metode) at Partner-objektene oppfører seg som de skal.
Testkode for denne oppgaven finner du her: [oving4/PartnerTest.java](../../src/test/java/oving4/PartnerTest.java).
# Objektstrukturer - Person-oppgave
Denne oppgaven handler om en `Person`-klasse med en [1-n-assosiasjon](https://www.ntnu.no/wiki/display/tdt4100/Koding+av+1-n-assosiasjoner)
med rollene _children_ og _mother_/_father_ til samme klasse (altså barn-mor/far-forhold) og det å sikre konsistens, slik at foreldre og barn
er korrekt knyttet sammen.
En viktig del av det å implementere assosiasjoner er å sikre konsistens, dvs. at objekter i hver ende av en kobling refererer korrekt
til hverandre. Et eksempel på dette for [1-n-assosiasjoner](https://www.ntnu.no/wiki/display/tdt4100/Koding+av+1-n-assosiasjoner) er
foreldreskap, hvor foreldre og barn er koblet til samme i et slektstre. I denne oppgaven skal en `Person`-klasse implementeres og det å
legge til (og fjerne) barn håndteres korrekt, som illustrert nedenfor.
`Person`-klassen skal inneholde informasjon om _navn_ (en String) og _kjønn_ (en char, 'F' eller 'M'), som bare skal kunne settes i
konstruktøren, og _mor_, _far_ og _barn_, som er andre Person-objekter. Navnet er ikke viktig for oppførselen, men er grei å ha med
i en `toString()`-metode, for å skille Person-objektene fra hverandre. `Person`-klassen skal ha følgende metoder for å lese tilstanden:
- `getName()` - returnerer navnet knyttet til dette Person-objektet
- `getGender()` - returnerer tegnet som representerer kjønnet, enten 'F' eller 'M'
- `getMother()` - returnerer Person-objektet som er moren, evt. `null`
- `getFather()` - returnerer Person-objektet som er faren, evt. `null`
- `getChildCount()` - returnerer antall barn dette Person-objektet har
- `getChild(int n)` - returnerer barn nr. n (altså et Person-objekt), evt. utløser (et passende) unntak om `n` er for stor (eller liten)
`Person`-klassen har to sett med endringsmetoder, knyttet til de to rollene i hver ende av _children_-_mother_/_father_-assosiasjonen.
Fra _children_-perspektivet har vi følgende to metoder:
- `addChild(Person)` - oppretter en kobling til et barn (et annet Person-objekt). Dersom Person-objektet som metoden kalles på, er
en _kvinne_, så skal denne bli barnets _mor_, og motsatt, dersom Person-objektet som metoden kalles på, er en _mann_, så skal denne
bli barnets _far_.
- `removeChild(Person)` - fjerner en kobling til et barn (et annet Person-objekt). Dersom Person-objektet som metoden kalles på, er _moren_
til argumentet, så skal _mother_-koblingen fjernes, og motsatt, dersom Person-objektet som metoden kalles på, er argumentets _far_, så skal
_father_-koblingen fjernes.
Fra _mother_/_father_-perspektivet har vi følgende to metoder:
- `setMother(Person)` - setter argumentet (en kvinne) som _moren_ til Person-objektet som metoden kalles på. Argumentet får samtidig
registrert Person-objektet som metoden kalles på, som sitt _barn_.
- `setFather(Person)` - setter argumentet (en mann) som _faren_ til Person-objektet som metoden kalles på. Argumentet får samtidig
registrert Person-objektet som metoden kalles på, som sitt _barn_.
Det som er verd å merke seg er at begge sett med metoder, `addChild`/`removeChild` og `setMother`/`setFather`, må ha logikk
som håndterer koblingen den andre veien, så `addChild`/`removeChild` må kalle `setMother`/`setFather` og omvendt, eller ha kode
med tilsvarende effekt. Dette kan være nokså fiklete, fordi en både må sikre konsistens og unngå uendelig nøstede kall
(inntil du får StackOverflowException).
Listen og figurene under illustrerer de fem tilfellene som må kunne håndteres, og som testes av testene det er lenket til.
### 1. Opprettelse av koblinger med `addChild`
**Kall**:
marit.addChild(jens)
hallvard.addChild(jens)
(Dette har samme effekt som kallene under punkt 2.)
**Før kall**:
![](img/person1.png)
**Etter kall**:
![](img/person2.png)
### 2. Opprettelse av koblinger med `setMother` og `setFather`
**Kall**:
jens.setMother(marit)
jens.setFather(hallvard)
(Dette har samme effekt som kallene under punkt 1.)
**Før kall**:
![](img/person1.png)
**Etter kall**:
![](img/person2.png)
### 3. Fjerning av koblinger med `removeChild`
**Kall**:
marit.removeChild(jens)
hallvard.removeChild(jens)
(Dette har samme effekt som kallene under punkt 4.)
**Før kall**:
![](img/person2.png)
**Etter kall**:
![](img/person1.png)
### 4. Fjerning av koblinger med `setMother` og `setFather`
**Kall**:
jens.setMother(null)
jens.setFather(null)
(Dette har samme effekt som kallene under punkt 3.)
**Før kall**:
![](img/person2.png)
**Etter kall**:
![](img/person1.png)
### 5. Fjerning og oppretting av kobling med `setMother` og `setFather`, en slags "adoption"
**Kall**:
jens.setFather(torkel)
jens.setMother(jorunn)
**Før kall**:
![](img/person3.png)
**Etter kall**:
![](img/person4.png)
## Oppgaven
Oppgaven er delt i to trinn, den første håndterer _children_- og _mother_/_father_-rollen isolert og uten krav om konsistens,
mens det andre skal sikre konsistens.
### Del 1
- Implementer `addChild`- og `removeChild`-metodene slik at `getChildCount`- og `getChild`-metodene virker som forventet.
Disse metodene håndterer altså kun _children_-rollen.
- Implementer `setMother`- og `setFather`-metodene slik at `getMother`- og `getFather`-metodene virker som forventet.
Disse metodene håndteres altså kun _mother_/_father_-rollen.
Test metodene ved å koble opp Person-objekter tilsvarende din egen familie. Du blir nødt til å bruke de tre metodene `addChild`, `setMother`
og `setFather`. Prøv å få med minst tre generasjoner.
### Del 2
Utvid metodene til å sikre konsistens. Test at det fortsatt virker å koble opp din egen familie, denne gangen ved å bare bruke
`addChild` og ved å bare bruke `setMother` og `setFather`. Kjør JUnit-testene som hører til oppgaven.
Testkode for denne oppgaven finner du her: [oving4/PersonTest.java](../../src/test/java/oving4/PersonTest.java).
# Øving 4: Objektstrukturer
**Øvingsmål**
- Lære hva assosiasjoner er og hvordan dette brukes i OO
- Lære hvordan man sikrer konsistent oppførsel mellom assosierte objekter
**Øvingskrav**
- Kunne implementere klasser som har assosiasjoner til én eller flere andre klasser
- Kunne sikre at disse assosiasjon er konsistente i enkle objektstrukturer
- Kunne implementere metoder som oppretter, oppdaterer og fjerner slike assosiasjoner
## Dette må du gjøre
### Del 1: Programmering
I denne øvingen skal du velge og gjennomføre ENTEN både Partner- og Card del 2-oppgavene ELLER minst én av Twitter-, Stopwatch- og Person-oppgavene.
Merk at **noen av oppgavene i neste øving (øving 5), bygger videre på noen av oppgavene under**, disse er uthevet med **fet skrift**.
Det er ikke et krav at man gjør de uthevede oppgavene, men de gir flere oppgaver å velge mellom i øving 6.
**Gjør enten _begge_ disse:**
- [Partner](./Partner.md) (lett)
- **[Card del 2](./Card.md)** (lett)
**Eller _minst én_ av følgende oppgaver:**
- **[Twitter](./Twitter.md)** (medium, men lang)
- [Stopwatch](./Stopwatch.md) (medium)
- [Person](./Person.md) (medium/vanskelig)
Oppgavene for denne øvingen skal du lagre i `ovinger/src/main/java/oving4`. Test-filene ligger i `ovinger/src/test/java/oving4`.
Alle oppgavene ovenfor er høyst eksamensrelevante og det anbefales å ta en titt på alle sammen.
### Del 2: Klassediagram
- Lag et [klassediagram](https://www.ntnu.no/wiki/display/tdt4100/Klassediagrammer) for en av oppgavene du velger. Husk å få med relasjonene mellom klassene.
Diagrammet kan for eksempel skrives på papir eller tegnes/lages i et valgfritt program. Du trenger ikke levere inn diagrammene, men de skal vises til studass under godkjenning av øvingen.
### Del 3: Testing
Skriv kode som tester oppførselen til `CoffeeCup`-klassen, dvs. at du skal teste om metodene i listen under har rett oppførsel og returnerer det de skal, i tillegg til at du skal teste konstruktørene. Det er ikke nødvendig å teste absolutt alle mulige tilfeller, men det kreves at du tester den grunnleggende funksjonaliteten.
- `getCapacity`
- `getCurrentVolume`
- `increaseCupSize`
- `drinkCoffee`
- `fillCoffee`
Du finner `CoffeeCup`-klassen under `ovinger/src/main/java/oving4/testing`.
Her er det anbefalt å bruke [JUnit](https://www.ntnu.no/wiki/display/tdt4100/Enhetstesting+med+JUnit),
men det er lov å teste vha. main-metoden også. Dersom du bruker JUnit må du opprette testen i `oving/src/test/java/oving4/testing`.
### 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/).
### Godkjenning
Last opp kildekode på Blackboard innen den angitte innleveringsfristen. Innlevert kode skal demonstreres for en læringsassistent innen én uke etter innleveringsfrist. Se for øvrig Blackboard-sidene for informasjon rundt organisering av øvingsopplegget og det tilhørende øvingsreglementet.
# Objektstrukturer - StopWatchManager-oppgave
Denne oppgaven handler om en `StopWatchManager`-klasse som inneholder flere `StopWatch`-objekter. Oppgaven bygger på klassen lagd i [StopWatch-oppgaven](../oving1/Stopwatch.md) fra "tilstand og oppførsel".
I mange sammenhenger vil objekter av en klasse inneholde eller "eie" objekter av andre klasser. Når en klasse er assosiert med én instans av en (annen) klasse er dette en [1-1-assosiasjon](https://www.ntnu.no/wiki/display/tdt4100/Koding+av+1-1-assosiasjoner) og når en klasse er assosiert med flere instanser av en annen klasse er dette en [1-n-assosiasjon](https://www.ntnu.no/wiki/display/tdt4100/Koding+av+1-n-assosiasjoner).
I denne oppgaven skal du implementere en `StopWatchManager`-klasse som kan holde styr på flere stoppeklokker. Ved hjelp av `StopWatchManager` skal man enkelt kunne holde styr på flere stoppeklokker og sørge for at alle stoppeklokker får beskjed om tiden som går. Dette kan være nyttig hvis man f.eks. ønsker å holde styr på flere løpere i et skirenn der ikke alle starter og fullfører samtidig, men hvor allikevel klokken må gå for alle.
Det skal være mulig å opprette nye stoppeklokker med et tilhørende navn (streng). Navnet skal man senere kunne bruke til å hente stoppeklokken igjen eller fjerne stoppeklokken fra `StopWatchManager`. For å få til dette kan det være lurt å se litt på `Map` fra [Collection-rammeverket](https://www.ntnu.no/wiki/display/tdt4100/Collection-rammeverket).
`StopWatchManager` skal ha følgende endringsmetoder:
- `StopWatch newStopWatch(String name)` - Oppretter en ny stoppeklokke knyttet til navnet `name`. Returnerer den nye stoppeklokken.
- `void removeStopWatch(String name)` - Fjerner stoppeklokken tilknyttet navnet `name`.
- `void tick(int ticks)` - Informerer alle stoppeklokkene om at ticks tikk har gått.
`StopWatchManager` skal ha følgende lesemetoder:
- `StopWatch getStopWatch(String name)` - returnerer stoppeklokken tilknyttet navnet `name`.
- `Collection<StopWatch> getAllWatches()` - returnerer alle stoppeklokkene.
- `Collection<StopWatch> getStartedWatches()` - returnerer alle stoppeklokkene som er startet.
- `Collection<StopWatch> getStoppedWatches()` - returnerer alle stoppeklokkene som er stoppet.
**Merk**: Det er viktig at de metodene som returnerer en samling av stoppeklokker returnerer nye samlinger. De som får en samling må kunne endre på den (f.eks. fjerne elementer) uten at dette forstyrrer `StopWatchManager` eller andre som har fått samlinger tidligere.
**Java-kode**
Kopier `StopWatch` fra `encapsulation`-pakken og lag `StopWatchManager` som beskrevet over. Test klassen med selvlagde main-metoder og ved å kjøre JUnit-testene.
Testkode for denne oppgaven finner du her: [oving4/StopWatchTest.java](../../src/test/java/oving4/StopWatchTest.java) og [oving4/StopWatchManagerTest.java](../../src/test/java/oving4/StopWatchManagerTest.java).
# Objektstrukturer - Twitter-oppgave
Denne oppgaven handler om en begrenset klone av `Twitter`, med to klasser, `TwitterAccount` og `Tweet`.
En Twitter-konto kan følge andre Twitter-kontoer og motsatt: en Twitter-konto kan bli fulgt av andre Twitter-kontoer.
Dette er altså en gjensidig kobling: Hvis konto A følger konto B, så er konto B fulgt av konto A. En kan selvsagt ikke følge seg selv.
I tillegg har hver Twitter-konto en mengde _tweets_, som er små, korte tekster. En tweet hører til den kontoen den ble sendt fra.
Hvis noen finner en annen sin tweet interessant har man muligheten til å retweete denne. Da lager man en tweet som refererer til originalen,
og (implisitt) få original-tweeten sin tekst. Merk at i en kjede av retweets, så vil alle referere til samme original-tweet. Mao.,
hvis tweet B er en retweet av A og tweet C er en retweet av B, vil både tweet B og C ha A som original-tweet, slik det er vist under.
**Riktig objektstrutur**, når B er en retweet av A og C er en retweet av B:
![](img/twitter1.png)
**Feil objektstrutur**, når B er en retweet av A og C er en retweet av B:
![](img/twitter2.png)
## Tweet-klassen
`Tweet` skal ha to konstruktører, en for hver måte å tweete på:
- `Tweet(TwitterAccount, String)` - En ny original-tweet
- `Tweet(TwitterAccount, Tweet)` - En retweet av Tweet-argumentet. Utløser et passende unntak, hvis original-tweeten er fra samme konto.
`Tweet` skal ha metodene:
- `String getText()` - returnerer teksten til en tweet
- `TwitterAccount getOwner()` - returnerer kontoen som tweeten kom fra
- `Tweet getOriginalTweet()` - returnerer original-tweeten, hvis den er en retweet, ellers null
- `int getRetweetCount()` - returnerer antall ganger denne tweeten har blitt retweetet
## TwitterAccount-klassen
`TwitterAccount` skal ha konstruktøren:
- `TwitterAccount(String)` - som tar inn brukernavnet
`TwitterAccount` skal ha metodene:
- `String getUserName()` - returnerer brukernavnet
- `void follow(TwitterAccount account)` - denne (this) kontoen starter å følge account
- `void unfollow(TwitterAccount account)` - slutt å følge account
- `boolean isFollowing(TwitterAccount account)` - returnerer om denne kontoen følger account
- `boolean isFollowedBy(TwitterAccount account)` - returnerer om account følger denne kontoen
- `void tweet(String)` - lager en ny tweet for denne kontoen
- `void retweet(Tweet tweet)` - retweeter tweet fra denne kontoen
- `Tweet getTweet(int i)` - returner tweet nummer i, der 1 er den nyeste, 2 den nest nyeste, … (merk rekkefølgen!)
- `int getTweetCount()` - returner antall tweets til kontoen
- `int getRetweetCount()` - returner antall retweets av tweets fra denne kontoen
## Del 1
- Implementer `Tweet`-klassen.
- For å teste klassen må du sende inn TwitterAccount-objekter i konstruktøren. Lag en forenklet versjon av `TwitterAccount`-klassen
for dette formålet, der du kun implementerer konstruktøren og evt. en passende toString(). Dette gjør det mulig å teste `Tweet`-klassen
din uten at du må implementere hele `TwitterAccount`-klassen først.
## Del 2
- Implementer `TwitterAccount`-klassen.
- Test klassen og dens samspill med `Tweet`-klassen ved å lage Twitter-konto for deg selv og noen av vennene dine.
La noen av kontoene følge hverandre, tweete og retweete.
Testkode for denne oppgaven finner du her: [oving4/TweetTest.java](../../src/test/java/oving4/TweetTest.java) og [oving4/TwitterAccountTest.java](../../src/test/java/oving4/TwitterAccountTest.java).
## Frivillig utvidelse
På Twitter kan man markere en annen sin tweet som en favoritt. Implementer passende metoder for å kunne gjøre dette.
En konto må ha oversikt over hvilke tweets den har markert som favoritter, og en tweet må vite hvem og hvor mange som har markert den
som favoritt. Hva synes du burde skje hvis man markerer en retweet som en favoritt?
package oving4.testing;
public class CoffeeCup {
private double capacity;
private double currentVolume;
public CoffeeCup() {
this.capacity = 0.0;
this.currentVolume = 0.0;
}
public CoffeeCup(double capacity, double currentVolume) {
if (isValidCapacity(capacity)) {
this.capacity = capacity;
} else {
throw new IllegalArgumentException("Illegal capacity given.");
}
if (isValidVolume(currentVolume)) {
this.currentVolume = currentVolume;
} else {
throw new IllegalArgumentException("Illegal volume given.");
}
}
public double getCapacity() {
return capacity;
}
public double getCurrentVolume() {
return currentVolume;
}
public void increaseCupSize(double biggerCapacity) {
if (isValidCapacity(biggerCapacity)) {
this.capacity += biggerCapacity;
}
}
private boolean isValidVolume(double volume) {
if (volume > this.capacity || volume < 0.0) {
return false;
}
return true;
}
private boolean canDrink(double volume) {
if (this.currentVolume >= volume) {
return true;
}
return false;
}
public void drinkCoffee(double volume) {
if (isValidVolume(volume) && canDrink(volume)) {
this.currentVolume -= volume;
} else {
throw new IllegalArgumentException("You can't drink that much coffee!");
}
}
public void fillCoffee(double volume) {
if (isValidVolume(this.currentVolume + volume)) {
this.currentVolume += volume;
} else {
throw new IllegalArgumentException("You just poured coffee all over the table. Good job.");
}
}
private boolean isValidCapacity(double capacity) {
if (capacity >= 0.0) {
return true;
}
return false;
}
@Override
public String toString() {
return "CoffeeCup [capacity=" + capacity + ", currentVolume=" + currentVolume + "]";
}
}
package oving4;
import java.util.Arrays;
import java.util.Collection;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
public class CardDeckTest {
private CardDeck cardDeck;
private void checkDeck(CardDeck deck, String deckAsString) {
Collection<String> toStrings = Arrays.asList(deckAsString.split(","));
Assertions.assertEquals(toStrings.size(), deck.getCardCount(), "CardDeck har ikke korrekt størrelse");
int i = 0;
for (String toString : toStrings) {
Card card = deck.getCard(i);
String cardString = String.valueOf(card.getSuit()) + card.getFace();
Assertions.assertEquals(toString, cardString,
String.format("Card på plass %d var feil. CardDeck skulle vært %s", i + 1, toStrings));
i++;
}
}
@BeforeEach
public void setup() {
cardDeck = new CardDeck(2);
}
@Test
@DisplayName("Sjekk at Deck blir initialisert til to S1,S2,H1,H2,D1,D2,C1,C2")
public void testConstructor() {
checkDeck(cardDeck, "S1,S2,H1,H2,D1,D2,C1,C2");
}
@Test
@DisplayName("Sjekk at CardDeck blir stokket til S1,D1,S2,D2,H1,C1,H2,C2")
public void testShufflePerfectly() {
cardDeck.shufflePerfectly();
checkDeck(cardDeck, "S1,D1,S2,D2,H1,C1,H2,C2");
}
@Test
@DisplayName("Sjekk at deal gir ut de tre siste kortene")
public void testDeal() {
CardHand hand = new CardHand();
cardDeck.deal(hand, 3);
checkDeck(cardDeck, "S1,S2,H1,H2,D1");
}
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment