Add rest
3
.vscode/settings.json
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"java.configuration.updateBuildConfiguration": "automatic"
|
||||
}
|
@ -2,12 +2,12 @@
|
||||
|
||||
Denne mappen inneholder øvingstekster for TDT4100 - Objektorientert programmering våren 2021. Tabellen under inneholder linker til hver enkelt oppgavetekst og tema for øvingen. Linker vil bli oppdatert underveis.
|
||||
|
||||
| Øving | Tema |
|
||||
| ----------------- | ---------------------------------------- |
|
||||
| Øving | Tema |
|
||||
| --------------------------- | ---------------------------------------- |
|
||||
| [Øving 1](oving1/README.md) | Tilstand og oppførsel |
|
||||
| Øving 2 | Innkapsling og validering |
|
||||
| Øving 3 | Klasser og testing |
|
||||
| Øving 4 | Objektstrukturer |
|
||||
| Øving 5 | Grensesnitt |
|
||||
| Øving 6 | Observatør-observert og delegering |
|
||||
| Øving 7 | Arv og abstrakte klasser |
|
||||
| [Øving 2](oving2/README.md) | Innkapsling og validering |
|
||||
| [Øving 3](oving3/README.md) | Klasser og testing |
|
||||
| [Øving 4](oving4/README.md) | Objektstrukturer |
|
||||
| [Øving 5](oving5/README.md) | Grensesnitt |
|
||||
| [Øving 6](oving6/README.md) | Observatør-observert og delegering |
|
||||
| [Øving 7](oving7/README.md) | Arv og abstrakte klasser |
|
||||
|
18
oppgavetekster/classpath_fix/README.md
Normal file
@ -0,0 +1,18 @@
|
||||
# Fiks ved problemer med å pulle i Eclipse
|
||||
|
||||
Dersom du får problemer med å pulle øvinger i Eclipse, med feilmelding som vist i bildet under ("Checkout conflict with files: `<prosjektnavn>/.classpath`), kan du følge denne guiden for å løse problemet.
|
||||
|
||||
**NB!** Bildene i denne guiden går ut i fra at problemfilen ligger i `ovinger`-prosjektet, men det kan også være under et av de andre prosjektene.
|
||||
Du kan se hvilke filer som er problematiske i feilmeldinga du får når du puller.
|
||||
|
||||
![Feilmelding ved pull](img/2.png)
|
||||
|
||||
| Beskrivelse | Bilde |
|
||||
|------|-------|
|
||||
| I Project-explorer i Eclipse, trykk på de tre prikkene i øvre høyre hjørne. I menyen som kommer opp velger du *Filters and Customization...* (I MacOS står det kun *Filters...*). | ![Meny](img/3.png) ![Filters and customization](img/4.png) |
|
||||
| I vinduet som kommer opp, pass på at valget `.* resources` **IKKE** er valgt, og trykk ok. | ![Vis skjulte](img/5.png) |
|
||||
| Åpne prosjektet du hadde konflikter i, dette er sannsynligvis ovinger. Du vil se at det har dukket opp en fil som heter `.classpath` under prosjektmappa. | ![Prosjekt med .classpath](img/6.png) |
|
||||
| Høyreklikk på `.classpath`-fila, og velg *Replace With* -> *HEAD Revision*. Trykk *Discard Changes* i vinduet som kommer opp. | ![Replace with](img/7.png)) |
|
||||
| Nå kan du prøve å pulle igjen (høyreklikk på prosjektet og velg *Team* -> *Pull*). Sannsynligvis vil prosjektet nå se ganske kaotisk ut, med veldig mange mapper. Det fikser du enkelt ved å høyreklikke på det, og velge *Maven* -> *Update Project*, velge alle prosjektene, og trykke *OK* | ![Mvn update](img/9.png) |
|
||||
|
||||
Etter denne prosessen skal alt fungere som før. Har du problemer, ta kontakt med undass.
|
BIN
oppgavetekster/classpath_fix/img/1.png
Normal file
After Width: | Height: | Size: 8.3 KiB |
BIN
oppgavetekster/classpath_fix/img/2.png
Normal file
After Width: | Height: | Size: 15 KiB |
BIN
oppgavetekster/classpath_fix/img/3.png
Normal file
After Width: | Height: | Size: 31 KiB |
BIN
oppgavetekster/classpath_fix/img/4.png
Normal file
After Width: | Height: | Size: 25 KiB |
BIN
oppgavetekster/classpath_fix/img/5.png
Normal file
After Width: | Height: | Size: 34 KiB |
BIN
oppgavetekster/classpath_fix/img/6.png
Normal file
After Width: | Height: | Size: 24 KiB |
BIN
oppgavetekster/classpath_fix/img/7.png
Normal file
After Width: | Height: | Size: 64 KiB |
BIN
oppgavetekster/classpath_fix/img/8.png
Normal file
After Width: | Height: | Size: 13 KiB |
BIN
oppgavetekster/classpath_fix/img/9.png
Normal file
After Width: | Height: | Size: 44 KiB |
@ -1,7 +1,7 @@
|
||||
# Interface - CardContainer-oppgave
|
||||
Denne oppgaven handler om å lage et felles grensesnitt for `CardDeck`- og `CardHand`-klassene, laget i oppgavene
|
||||
[Innkapsling - Card-oppgave](../oving3/Card.md) og
|
||||
[Objektstrukturer - Card-oppgave del 2](../oving5/Card.md).
|
||||
[Objektstrukturer - Card-oppgave del 2](../oving4/Card.md).
|
||||
Her skal du lage og implementere et grensenitt kalt `CardContainer`, som spesifiserer metoder for lesing av samlinger av Card-objekter.
|
||||
|
||||
#### Del 1 - CardContainer interface
|
||||
|
74
oppgavetekster/oving7/AbstractAccount.md
Normal file
@ -0,0 +1,74 @@
|
||||
# Arv - AbstractAccount-oppgave
|
||||
Denne oppgaven handler om å lage en felles abstrakt superklasse `AbstractAccount`
|
||||
for `CreditAccount`, `DebitAccount`- og `SavingsAccount2`-klassene.
|
||||
|
||||
Denne oppgaven er en annen variant av
|
||||
[SavingsAccount](./SavingsAccount.md)-oppgaven, med fokus
|
||||
på bruk av abstrakte klasser og arv.
|
||||
|
||||
### Del 1 - Abstrakt klasse AbstractAccount
|
||||
En bank består av mange ulike type kontoer: sparekontoer, brukskontoer,
|
||||
depositumskontoer, støttekontoer etc. Siden disse har mye felles, f.eks.
|
||||
har alle en balanse, så er det praktisk å samle så mye som mulig av den
|
||||
felles logikken i en superklasse, som alle kan arve fra. Denne superklassen
|
||||
er imidlertid ikke noen egen type konto, og derfor gjør vi den abstrakt,
|
||||
slik at den ikke kan instansieres. De konkrete konto-klassene som arver
|
||||
fra den, må selvsagt være instansierbare.
|
||||
|
||||
Metodene i `AbstractAccount`-klassen, er omtrent de samme som dem vi definerte
|
||||
i `Account`-grensesnittet i [SavingsAccount](./SavingsAccount.md)-oppgaven,
|
||||
og er som følger:
|
||||
|
||||
* `void deposit(double)` - øker kontobalansen med innskutt beløp. Merk at det
|
||||
innskutte beløpet må være positivt. Ved ulovlig innskudd skal en
|
||||
`IllegalArgumentException` utløses.
|
||||
* `void withdraw(double)` - Metoden kaller <code>internalWithdraw(<i>uttaksbeløp</i>)</code>,
|
||||
som implementeres i hver subklasse. Hvis uttaksbeløpet er negativt skal
|
||||
metoden utløse en `IllegalArgumentException`.
|
||||
* `abstract void internalWithdraw(double)` - minsker kontobalansen med beløpet
|
||||
som blir tatt ut. Merk at reglene for uttak er ulik for klassene som
|
||||
implementerer `AbstractAccount`, og må derfor implementeres i hver klasse.
|
||||
Hvis det ikke er mulig å ta ut det angitte beløpet skal metoden utløse en
|
||||
`IllegalStateException`.
|
||||
* `double getBalance()` - returnerer kontobalansen.
|
||||
|
||||
Alle metodene utenom den absktrakte må implementeres. I tillegg må
|
||||
`AbstractAccount` ha en tilstand *balance* for saldo på kontoen.
|
||||
Saldoen skal settes til 0 i konstruktøren.
|
||||
|
||||
Vær oppmerksom på at du i Del 2 skal lage subklasser av `AbstractAccount`
|
||||
og at du ved å bruke rett innkapsling (hint: `protected`-modifikatoren) skal
|
||||
la *subklassene* nyttiggjøre seg *superklassen* i størst mulig grad.
|
||||
|
||||
|
||||
### Del 2 - DebitAccount extends AbstractAccount
|
||||
En debetkonto er den enkleste formen for konto, hvor det eneste kravet er at
|
||||
saldoen til enhver tid må være større eller lik 0. `DebitAccount` skal utvide
|
||||
(arve fra med `extends`) `AbstractAccount` og sikre at saldoen aldri blir
|
||||
lavere enn 0.
|
||||
|
||||
Testkode for oppgavene finner du her: [inheritance/DebitAccountTest.java](../../src/test/java/inheritance/DebitAccountTest.java).
|
||||
|
||||
### Del 3 - CreditAccount extends AbstractAccount
|
||||
En `CreditAccount` har i tillegg til *balance* en tilstand for *creditLine*,
|
||||
altså tilgjengelig kreditt på kontoen. Denne kredittlinjen tillater at kontoen
|
||||
kan overtrekkes (at saldoen er negativ) innenfor kredittlinjen. Klassen må ha
|
||||
*tilgangsmetoder* (getters and setters) for *creditLine*. Merk at
|
||||
kredittlinjen alltid må være større eller lik 0, hvis ikke skal det utløses
|
||||
en `IllegalArgumentException`. Hvis en ny kredittlinje settes og balansen er
|
||||
negativ, må den nye kredittlinjen dekke den eksisterende balansen. Ellers skal
|
||||
det utløses en `IllegalStateException` og ingen endring i kredittlinjen.
|
||||
|
||||
Konstruktøren `CreditAccount(double)` skal sette kredittlinjen.
|
||||
|
||||
Testkode for oppgavene finner du her: [inheritance/CreditAccountTest.java](../../src/test/java/inheritance/CreditAccountTest.java).
|
||||
|
||||
### Del 4 - SavingsAccount2 extends AbstractAccount
|
||||
En `SavingsAccount2` (*merk at navnet er endret, for ikke å kræsje med
|
||||
SavingsAccount-klassen fra den tidligere oppgaven!*) kan kun ha positiv saldo.
|
||||
I tillegg har kontoen uttaksbegrensinger. En `SavingsAccount2` har *x* antall
|
||||
*uttak* (**withdrawals**). Dersom man ønsker å ta ut penger etter alle uttak er
|
||||
brukt opp, skal saldoen belastes med et *gebyr* (**fee**). Både **withdrawals**
|
||||
(antall) og **fee** (beløp) settes i konstruktøren `SavingsAccount2(int, double)`.
|
||||
|
||||
Testkode for oppgavene finner du her: [inheritance/SavingsAccount2Test.java](../../src/test/java/inheritance/SavingsAccount2Test.java).
|
38
oppgavetekster/oving7/CardContainerImpl.md
Normal file
@ -0,0 +1,38 @@
|
||||
# Arv - CardContainerImpl-oppgave
|
||||
|
||||
Denne oppgaven handler om å lage en felles superklasse `CardContainerImpl`
|
||||
for `CardDeck`- og `CardHand`-klassene, laget i [Card-oppgaven](../oving4/Card.md)
|
||||
og [CardContainer-oppgaven](../oving5/CardContainer.md).
|
||||
|
||||
**Merk:** Om du ikke har gjort Card-oppgaven og CardContainer-oppgaven allerede,
|
||||
kan du bruke løsningsforslaget som er lagt ut for disse under `lf/src/interfaces`.
|
||||
|
||||
### Del 1 - Superklassen CardContainerImpl
|
||||
Lag en `CardContainerImpl`-superklasse, som implementerer grensesnittet
|
||||
`CardContainer` (se [CardContainer-oppgaven](../oving5/CardContainer.md)) og
|
||||
inneholder koden som er felles for `CardDeck` og `CardHand`.
|
||||
|
||||
La `CardDeck` og `CardHand` arve `CardContainerImpl` og gjør nødvendige endringer
|
||||
i disse klassene, slik at totaloppførselen er som før. F.eks. skal `CardDeck`
|
||||
-objektet ha samme konstruktør som før, som skal sikre samme initielle tilstand
|
||||
(men ikke nødvendigvis med samme konstruktør-kode).
|
||||
|
||||
Merk at målet er at mest mulig kode skal flyttes til *superklassen* og gjenbrukes
|
||||
i *subklassene*. Det er viktig å bruke innkapsling rett
|
||||
(hint: `protected`-modifikatoren) for å nyttiggjøre seg superklassen i størst
|
||||
mulig grad.
|
||||
|
||||
### Del 2 - Regler for maksimalt antall kort
|
||||
Anta at en ønsker å unngå at instanser av `CardContainerImpl` (eller av en av
|
||||
subklassene) inneholder for mange kort. Legg til et *privat* `maxCardCount`-felt
|
||||
i `CardContainerImpl`, en konstruktør som *initialiserer* feltet og en *getter*
|
||||
for å lese verdien. Legg så til evt. endre kode i `CardContainerImpl` som sikrer
|
||||
at antall kort ikke overstiger dette tallet og at subklassene ikke kan omgå
|
||||
denne valideringen.
|
||||
|
||||
`CardContainerImpl`-subklassene `CardDeck` og `CardHand` skal sette maks-antallet
|
||||
som følger: `CardDeck` skal sette makstallet til *52* og `CardHand` skal ta
|
||||
inn maks-antallet i *sin* konstruktør. Hvis man forsøker å legge til flere kort
|
||||
enn hva som er tillatt i `CardHand`, skal det utløses en `IllegalStateException`.
|
||||
|
||||
Testkode for oppgavene finner du her: [inheritance/CardDeckTest.java](../../src/test/java/inheritance/CardDeckTest.java) og [inheritance/CardHandTest.java](../../src/test/java/inheritance/CardHandTest.java).
|
140
oppgavetekster/oving7/ObservableList.md
Normal file
@ -0,0 +1,140 @@
|
||||
# Observatør-observert-teknikken og arv - HighscoreList-oppgave med ObservableList
|
||||
Denne oppgaven handler om å bruke observatør-observert-teknikken for å bli
|
||||
informert om endringer i en highscore-liste. Vi bruker også arv for å skille
|
||||
ut gjenbrukbar kode for en generell, observerbar liste.
|
||||
|
||||
Observatør-observert-teknikken går ut på at det observerte objektet sier ifra
|
||||
til en eller flere observatører om at tilstanden er endret. I denne oppgaven
|
||||
skal vi lage en `HighscoreList` som kan si fra til lyttere av typen
|
||||
`ListListener` når nye resultater blir registrert. En hovedprogramklasse kalt
|
||||
`HighscoreProgram` vil bli brukt til å sjekke at det virker. Denne klassen
|
||||
oppretter en `HighscoreList`-instans, legger inn resultater (tall) fra
|
||||
konsollet som legges til lista og skriver ut lista hver gang et nytt resultat
|
||||
faktisk blir lagt til.
|
||||
|
||||
Klassene skal legges i `src/main/java/patterns.observable/` og tilhørende
|
||||
tester ligger i `src/test/java/patterns.observable/`.
|
||||
|
||||
### Del 1: Implementasjon av ObservableList og ObservableHighscoreList
|
||||
En `ObservableHighscoreList` skal holde styr på heltallsresultater (av typen
|
||||
int/Integer). Lista skal være *observerbar* ved at den kan registrere lyttere
|
||||
(`ObservableListListener`-instanser) og si fra til dem når lista blir endret.
|
||||
Lista skal ha en maksimal lengde, som settes i *konstruktøren*, f.eks. skal en
|
||||
topp 10-liste kunne opprettes med `new ObservableHighscoreList(10)`.
|
||||
Nye resultater registreres med metoden `addResult(int)`, som skal finne riktig
|
||||
posisjon og legge resultatet inn (dersom det er godt nok). Dersom lista er for
|
||||
lang, så skal det dårligste resultatet fjernes. NB: *Lavest verdi er best*,
|
||||
f.eks. antall sekunder på en oppgave eller antall flytt i Sokoban.
|
||||
|
||||
`ObservableListListener`-grensesnittet er vist i klassediagrammet nedenfor og
|
||||
må implementers av alle klasser som ønsker å fungere som lyttere for
|
||||
`ObservableHighscoreList`-instanser. Lyttere registrerer seg med
|
||||
`ObservableHighscoreList` sin `addObservableListListener`-metode og vil siden
|
||||
få beskjed om nye resultater ved at `listChanged`-metoden kalles. Argumentene
|
||||
som tas inn er `ObservableHighscoreList`-objektet som ble endret og *posisjonen*
|
||||
i lista der endringen skjedde.
|
||||
|
||||
Merk at første argument til `listChanged`-metoden er av typen `ObservableList`.
|
||||
Dette er en abstrakt superklasse for `ObservableHighscoreList`, som først
|
||||
brukes i del 3 og som da skal holde orden på lista. `ObservableList` vil ha en
|
||||
del generelle metoder som `ObservableHighscoreList` arver og kan bruke. For å
|
||||
kunne kjøre testene for `ObservableHighscoreList` allerede i del 1, så må
|
||||
`ObservableList` være definert fra starten. Lag derfor en tom
|
||||
`ObservableList`-klasse og bruk denne som superklasse for
|
||||
`ObservableHighscoreList`.
|
||||
|
||||
Her er en oversikt over metoden som må implementeres:
|
||||
|
||||
* `ObservableHighscoreList(int maxSize)` - konstruktøren tar inn *maks antall*
|
||||
resultater som lista skal kunne holde. Denne verdien må brukes av `addResult`,
|
||||
slik at resultater som er for dårlige kastes.
|
||||
* `size()` - returnerer antall elementer i lista, som altså aldri skal
|
||||
overstige maks-antallet
|
||||
* `int getElement(int)` - returnerer resultatet i posisjonen angitt av
|
||||
argumentet
|
||||
* `void addResult(int)` - registrere et nytt resultat, og dersom resultatet er
|
||||
godt nok til å komme med på lista, så legges det inn på riktig plass.
|
||||
Dersom lista blir for lang, så må dårligste resultat kastes. Alle registrerte
|
||||
lyttere må få beskjed om en evt. endring av lista, inkludert hvilken
|
||||
posisjon som ble endret.
|
||||
* `addObservableListListener(ObservableListListener)` - registrerer en ny lytter
|
||||
* `removeObservableListListener(ObservableListListener)` - fjerner en tidligere
|
||||
registrert lytter
|
||||
|
||||
Klassediagram for `HighscoreList`, `ListListener` og `ObservableList`:
|
||||
<img src="images/ObservableList_del1.png" width="570">
|
||||
|
||||
Testkode for denne oppgaven finner du her: [patterns/observable/ObservableHighscoreListTest.java](../../src/test/java/patterns/observable/ObservableHighscoreListTest.java).
|
||||
|
||||
### Del 2: Hovedprogram ObservableHighscoreListProgram
|
||||
Lag en hovedprogramklasse kalt `ObservableHighscoreListProgram`, som tester at
|
||||
`ObservableHighscoreList`-klassen din virker som den skal. La den opprette en
|
||||
`ObservableHighscoreList`-instans, lese inn tall fra konsollet (f.eks. med en
|
||||
`Scanner` og `nextInt`-metoden) og legge disse inn i lista. Sørg for at
|
||||
`ObservableHighscoreListProgram` implementerer
|
||||
`ObservableListListener`-grensesnittet og registrerer seg som lytter på
|
||||
`HighscoreList`-instansen. La lyttermetoden `listChanged` skrive ut informasjon
|
||||
og resultatene i `HighscoreList`-instansen og posisjonsargumentet, slik at du
|
||||
ser at alt virker som det skal.
|
||||
|
||||
Vi foreslår følgende metoder og oppførsel:
|
||||
|
||||
* `void init()` - oppretter en ny `ObservableHighscoreList` og registrerer seg
|
||||
selv (altså `ObservableHighscoreListProgram`-instansen) som lytter
|
||||
* `void run()` - leser inn tall (resultater) fra konsollet og legger dem til i
|
||||
listen
|
||||
* `void listChanged(ObservableList, int)` - observerer endringer i
|
||||
`ObservableHighscoreList`-instansen og skriver ut posisjonsargumentet, samt
|
||||
selve listen, til konsollet
|
||||
|
||||
Klassediagrammet viser hvordan klassene henger sammen, og vårt forslag til
|
||||
metoder:
|
||||
<img src="images/ObservableList_del2.png" width="670">
|
||||
|
||||
### Del 3: ObservableList
|
||||
Den abstrakte superklassen `ObservableList` skal legges til som en generell
|
||||
superklasse for observerbare lister, som `ObservableHighscoreList` skal arve
|
||||
fra. Denne klassen skal både holde en liste med objekter (`Object`) og håndtere
|
||||
registrering av lyttere, altså en liste med `ObservableListListener`-instanse,
|
||||
som får beskjed om endringer i lista (slik at lista dermed er *observerbar*).
|
||||
Dette betyr at `ObservableList` overtar håndtering av både resultater og
|
||||
lyttere fra `ObservableHighscoreList`-klassen. For å gjøre `ObservableList` mer
|
||||
generell og gjenbrukbar, så lar vi den håndtere `Object`-instanser (heller enn
|
||||
`Integer`). Samtidig deklarerer den en *abstrakt* metode `acceptsElement`, som
|
||||
subklasser må *redefinere* for å bestemme hva slags objekter det skal være lov
|
||||
å legge inn. `ObservableHighscoreList` vil f.eks måtte redefinere den slik
|
||||
at bare `Integer`-objekter aksepteres.
|
||||
|
||||
`ObservableList` skal ha følgende metoder (noen er altså overtatt fra
|
||||
`ObservableHighscoreList`):
|
||||
|
||||
* `int size()` - returnerer antall elementer i lista
|
||||
* `Object getElement(int)` - returnerer elementet i posisjonen angitt av
|
||||
argumentet
|
||||
* `abstract boolean acceptsElement(Object)` - returnerer hvorvidt *subklassen*
|
||||
aksepterer at objektet legges inn i lista (f.eks. aksepterer `HighscoreList`
|
||||
kun `Integer`-objekter).
|
||||
* `void addElement(int, Object)` - legger til et element på posisjonen angitt
|
||||
av argumentet, men bare dersom det *aksepteres* som element. Dersom elementet
|
||||
ikke aksepteres, så skal `IllegalArgumentException` utløses. Dersom posisjonen
|
||||
er ulovlig så skal `IndexOutOfBoundsException` utløses.
|
||||
* `void addElement(Object)` - legger til et element bakerst i lista, men bare
|
||||
dersom det *aksepteres* som element. Dersom elementet ikke aksepteres, så skal
|
||||
`IllegalArgumentException` utløses.
|
||||
* `void removeElement(int)` - fjerner elementet på posisjonen angitt av
|
||||
argumentet. Dersom posisjonen er ulovlig så skal `IndexOutOfBoundsException`
|
||||
utløses.
|
||||
|
||||
`ObservableHighscoreList` skal endres slik at den i størst mulig grad bruker
|
||||
metodene som arves fra `ObservableList`, men forøvrig ikke endrer oppførsel.
|
||||
Kjør hovedprogramklassen `ObservableHighscoreListProgram` for å sjekke at dette
|
||||
faktisk stemmer.
|
||||
|
||||
Klassediagrammet viser hvordan klassene henger sammen, og hvor metodene nå er
|
||||
deklarert/implementert. Merk at `addElement`- og `removeElement`-metodene er
|
||||
angitt som `protected` (ruter-symbolet), slik at kun subklasser skal kunne
|
||||
bruke dem.
|
||||
<img src="images/ObservableList_del3.png" width="670">
|
||||
|
||||
Testkode for denne oppgaven finner du her: [patterns/observable/ObservableListTest.java](../../src/test/java/patterns/observable/ObservableListTest.java).
|
||||
|
40
oppgavetekster/oving7/README.md
Normal file
@ -0,0 +1,40 @@
|
||||
# Øving 07: Arv og abstrakte klasser
|
||||
|
||||
**Øvingsmål**
|
||||
* Lære hvordan arv-mekansimen brukes i OO
|
||||
* Lære om instanser, typer, deklarasjoner og tilordninger
|
||||
* Lære om sub- og superklasser samt om synlighetsmodifikatorer som brukes ved arv
|
||||
* Lære om abstrakte klasser, deres bruksområder og fordeler
|
||||
|
||||
**Øvingskrav**
|
||||
* Kunne bruke arv til å modellerere enkle(re) objektstrukturer- og relasjoner i Java
|
||||
* Kunne la flere subklasser bruke funksjonalitet definert i samme superklasse
|
||||
* Kunne la en subklasse redefinere metoder definert i en superklasse
|
||||
* Kunne samle felles oppførsel til to eller flere subklasser i en felles abstrakt klasse
|
||||
|
||||
## Dette må du gjøre
|
||||
Oppgavene skal lagres i `ovinger/src/main/java/inheritance`.
|
||||
|
||||
I begge delene er antageligvis vanskelighetsgraden stigende. Alle er høyst eksamensrelevante og det anbefales følgelig å ta en titt på samtlige.
|
||||
|
||||
### Del 1: Arv
|
||||
Velg og gjennomfør *minst én* av oppgavene om arv:
|
||||
|
||||
* [CardContainerImpl](./CardContainerImpl.md)
|
||||
* [Train](./Train.md)
|
||||
* [SavingsAccount](./SavingsAccount.md)
|
||||
|
||||
### Del 2: Abstrakte klasser og arv
|
||||
Velg og gjennomfør *minst én* av oppgavene om abstrakte klasser og arv:
|
||||
|
||||
* [AbstractAccount](./AbstractAccount.md)
|
||||
* [ObservableList](./ObservableList.md)
|
||||
|
||||
|
||||
### 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.
|
117
oppgavetekster/oving7/SavingsAccount.md
Normal file
@ -0,0 +1,117 @@
|
||||
# Arv - SavingsAccount-oppgave
|
||||
Denne oppgaven handler om å lage en felles superklasse `SavingsAccount` for
|
||||
`BSU`- og `ForeldreSpar`-klassene. `SavingsAccount` skal dessuten implementere
|
||||
`Account`-grensesnittet.
|
||||
|
||||
Denne oppgaven bygger videre på `Account`-oppgavene under
|
||||
[Innkapsling](../oving2/Account.md) og [Tilstand og oppførsel](../oving1/Account.md).
|
||||
|
||||
### Del 1 - SavingsAccount implements Account
|
||||
En bank består av mange ulike type kontoer: sparekontoer, brukskontoer,
|
||||
depositumskontoer, støttekontoer etc. Felles for alle kontoer er
|
||||
`Account`-grensesnittet, som er definert under:
|
||||
|
||||
```java
|
||||
package inheritance;
|
||||
|
||||
public interface Account {
|
||||
public void deposit(double amount);
|
||||
public void withdraw(double amount);
|
||||
public double getBalance();
|
||||
}
|
||||
```
|
||||
|
||||
Vi skal i denne oppgaven fokusere på sparekontoer og du skal nå lage en
|
||||
`SavingsAccount`-superklasse, som implementerer `Account`-grensesnittet.
|
||||
Funksjonaliteten som hver av metodene definert i grensesnittet over skal
|
||||
støtte er:
|
||||
|
||||
* `void deposit(double)` - øker kontobalansen med innskutt beløp. Merk at det
|
||||
innskutte beløpet må være positivt. Ved ulovlig innskudd skal en
|
||||
`IllegalArgumentException` utløses.
|
||||
* `void withdraw(double)` - minsker kontobalansen med beløpet som blir tatt ut.
|
||||
Merk at uttaksbeløpet må være positivt, ellers skal et unntak av typen
|
||||
`IllegalArgumentException` utløses. Dersom det ikke er dekning på kontoen
|
||||
(en `SavingsAccount` kan ikke ha negativ balanse) skal et unntak av typen
|
||||
`IllegalStateException` utløses.
|
||||
* `double getbalance()` - returnerer kontobalansen.
|
||||
|
||||
I tillegg til å støtte `Account`-grensesnittet over, som er felles for alle
|
||||
kontoer, skal sparekontoer ha en rentefot og en metode som forrenter kontoen.
|
||||
Denne kalles av bankene for hver sparekonto på slutten av året slik at alle
|
||||
dets kunder opptjener renter (ikke tenk på at banker egentlig holder styr på
|
||||
hvor stor balansen har vært gjennom hele året eller forrenter kontoen
|
||||
kontinuerlig - her skal vi bare anta at innestående kontobalanse ved årsslutt
|
||||
forrentes i sin helhet) - derfor heter metoden `endYearUpdate()`. I tillegg
|
||||
skal `SavingsAccount`-klassen ha en konstruktør som tvinger alle objekter
|
||||
av denne typen til å bli instansiert med en rentefot. Dette er oppsummert her:
|
||||
|
||||
* `SavingsAccount(double)` - konstruktør som tar inn rentefoten på kontoen
|
||||
(et desimaltall, f.eks. 0.05 tilsvarer en rente på 5 %). Åpningsbalansen
|
||||
skal være 0.
|
||||
* `void endYearUpdate()` - forrenter kontobalansen basert på rentefoten.
|
||||
Vi tenker oss at denne kalles av kode utenfor denne klassen, f.eks. resten
|
||||
av et tenkt banksystem ved årsoppgjør, som et signal på at nå er et nytt år
|
||||
over.
|
||||
|
||||
Vær oppmerksom på at du i Del 2 og 3 skal lage *subklasser* av `SavingsAccount`
|
||||
og at du ved å bruke rett innkapsling (hint: `protected`-modifikatoren) kan la
|
||||
*subklassene* nyttiggjøre seg *superklassen* i størst mulig grad.
|
||||
|
||||
Testkode for oppgavene finner du her: [inheritance/SavingsAccountTest.java](../../src/test/java/inheritance/SavingsAccountTest.java).
|
||||
|
||||
### Del 2 - BSU extends SavingsAccount
|
||||
I tillegg til generelle sparekontoer finnes det en spesiell type sparekonto
|
||||
som heter BSU. Du skal nå lage en `BSU`-klasse som arver fra
|
||||
`SavingsAccount`-superklassen. Her er målet at du skal gjenbruke mest mulig
|
||||
av *superklassen* og samtidig støtte BSU-spesifikk oppførsel. En BSU-konto er,
|
||||
i tillegg til å være en sparekonto, spesiell i den forstand at det kun er
|
||||
lovlig å sette inn inntil et forhåndsbestemt beløp per år
|
||||
(den gamle regjeringen fastslo at BSU-kontoer i 2014 skulle ha en
|
||||
innskuddsgrense på kr 25 000, men din kode skal ha støtte for å ha en vilkårlig
|
||||
grense) og at det kun er lovlig å ta ut av det beløpet som er satt inn siste
|
||||
år. M.a.o. vil en ved årsskifte få mulighet til å sette inn nye innskudd
|
||||
innenfor innskuddsgrensen, men en har ikke lenger mulighet til å ta ut hele
|
||||
balansen (innskudd fra tidligere år låses). Dessuten gir en vanlig BSU-konto
|
||||
20% skattefradrag for årets innskudd.
|
||||
|
||||
Du må selv avgjøre hvilke felt som må legges til for å støtte den beskrevne
|
||||
oppførsel. I tillegg stilles følgende krav til klassen:
|
||||
|
||||
* `BSU(double, double)` - konstruktør som tar inn rentefoten på kontoen og et
|
||||
desimaltall som angir hvor mye det er tillatt å sette inn på kontoen per år.
|
||||
* `double getTaxDeduction()` - returnerer skattefradrag for inneværende år.
|
||||
Dette vil være 20% av innskutt(e) beløp siste år.
|
||||
|
||||
Testkode for oppgavene finner du her: [inheritance/BSUTest.java](../../src/test/java/inheritance/BSUTest.java).
|
||||
|
||||
### Del 3 - ForeldreSpar extends SavingsAccount
|
||||
En annen spesiell type sparekonto, her kalt ForeldreSpar, har et begrenset
|
||||
antall lovlige uttak per år (ofte i bytte mot en høyere rente). Du skal nå
|
||||
lage en slik `ForeldreSpar`-klasse som arver fra `SavingsAccount`-superklassen.
|
||||
Her er igjen målet at du skal gjenbruke mest mulig av *superklassen* og
|
||||
samtidig støtte ForeldreSpar-spesifikk oppførsel. Denne klassen skal sikre at
|
||||
kun det lovlige antallet uttak gjøres i løpet av et år.
|
||||
|
||||
Du må selv avgjøre hvilke felt som må legges til før å støtte den beskrevne
|
||||
oppførsel. I tillegg stilles følgende krav til klassen:
|
||||
|
||||
* `ForeldreSpar(double, int)` - konstruktør som tar inn rentefoten på kontoen
|
||||
og et heltall som angir antall lovlige uttak per år.
|
||||
* `int getRemainingWithdrawals()` - returnerer antall gjenstående uttak fra
|
||||
sparekontoen.
|
||||
|
||||
Testkode for oppgavene finner du her: [inheritance/ForeldreSparTest.java](../../src/test/java/inheritance/ForeldreSparTest.java).
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
72
oppgavetekster/oving7/Train.md
Normal file
@ -0,0 +1,72 @@
|
||||
# Arv - Train-oppgave
|
||||
|
||||
I denne oppgaven skal vi modellere to typer togvogner og bruke dem i et tog. Vi vil bruke
|
||||
arv og samle det som er felles for togvognene i en *superklasse*.
|
||||
|
||||
### Del 1 - TrainCar
|
||||
<img src="images/Train_del1.png" width="170">
|
||||
|
||||
I denne delen skal du lage en klasse kalt `TrainCar` for en enkel og generell
|
||||
togvogn, med følgende funksjonalitet (se også diagrammet over):
|
||||
|
||||
* `TrainCar(int)` - en konstruktør som tar inn hvor mye en tom vogn veier.
|
||||
* `int getTotalWeight` - returnerer vognas totale vekt. Merk at denne også skal
|
||||
kunne kalles på *subklasser* og fortsatt returnere totalvekta til vogna
|
||||
(stikkord: *redefinering*).
|
||||
* `setDeadWeight(int)` - setter hvor mye en tom vogn veier. Altså vekten til
|
||||
kun vognen, uten passasjerer eller last.
|
||||
* `int getDeadWeight()` - returnerer hvor mye en tom vogn veier. Altså vekten til
|
||||
kun vognen, uten passasjerer eller last.
|
||||
|
||||
Testkode for oppgaven finner du her: [inheritance/TrainCarTest.java](../../src/test/java/inheritance/TrainCarTest.java).
|
||||
|
||||
### Del 2 - CargoCar og PassengerCar
|
||||
<img src="images/Train_del2.png" width="350">
|
||||
|
||||
I denne delen skal du lage to forskjellige typer togvogner som er spesialiserte
|
||||
for sitt bruk. Begge skal arve fra `TrainCar`.
|
||||
##### CargoCar extends TrainCar:
|
||||
Denne klassen skal gjenspeile en lastevogn som frakter diverse ting og tang.
|
||||
Følgende funksjonalitet trengs (se også diagrammet over):
|
||||
|
||||
* `CargoCar(int, int)` - her tas inn hvor mye en tom vogn veier (som i `TrainCar`),
|
||||
og hvor mye vogna sin last veier.
|
||||
* `int getCargoWeight()` - returnerer hvor mye lasten veier.
|
||||
* `setCargoWeight(int)` - setter en ny verdi for vekten til lasten.
|
||||
|
||||
##### PassengerCar extends TrainCar:
|
||||
Denne klassen gjenspeiler en passasjervogn. Legg til følgende metoder
|
||||
(se også diagrammet over):
|
||||
|
||||
* `PassengerCar(int, int)` - her tas inn hvor mye en tom vogn veier
|
||||
(som i `TrainCar`), og hvor mange passasjerer det er i vogna.
|
||||
* `int getPassengerCount()` - returner antall passasjerer.
|
||||
* `setPassengerCount(int)` - setter en ny verdi for antall passasjerer.
|
||||
|
||||
For å beregne totalvekta, så kan du anta at en gjennomsnittspassasjer veier 80 kg.
|
||||
|
||||
Testkode for oppgavene finner du her: [inheritance/PassengerCarTest.java](../../src/test/java/inheritance/PassengerCarTest.java) og [inheritance/CargoCarTest.java](../../src/test/java/inheritance/CargoCarTest.java).
|
||||
|
||||
|
||||
### Del 3 - Train
|
||||
<img src="images/Train_del3.png" width="450">
|
||||
|
||||
Klassen `Train` skal forestille et tog bestående av et sett vogner.
|
||||
Klassen skal ha følgende metoder (se også diagrammet over):
|
||||
|
||||
* `addTrainCar(TrainCar)` - denne metoden skal ta inn en togvogn og knytte den
|
||||
til dette lokomotivet.
|
||||
* `boolean contains(TrainCar)` - Sjekker om lokomotivet har `TrainCar`-argument
|
||||
knyttet til seg.
|
||||
* `int getTotalWeight()` - returner alle vognene sin totale vekt. Vi tar ikke
|
||||
høyde for lokomotivet sin eventuelle vekt.
|
||||
* `int getPassengerCount()` - tilsvarende `PassengerCar` sin metode, men
|
||||
returnerer antallet for alle vognene.
|
||||
* `int getCargoWeight()` - tilsvarende `CargoCar` sin metode, men returnerer
|
||||
lastevekten for alle vognene.
|
||||
* `String toString()` - `toString`-metoden skal sette sammen en *String* med
|
||||
oversikt over alle vognene som er knyttet til den. For hver vogn skal vogntype
|
||||
og totalvekt være med. Passasjervogner skal i tillegg ha med antall passasjerer
|
||||
og lastevogner skal ha med hvor mye lasten veier.
|
||||
|
||||
Testkode for oppgaven finner du her: [inheritance/TrainTest.java](../../src/test/java/inheritance/TrainTest.java).
|
BIN
oppgavetekster/oving7/images/ObservableList_del1.png
Normal file
After Width: | Height: | Size: 81 KiB |
BIN
oppgavetekster/oving7/images/ObservableList_del2.png
Normal file
After Width: | Height: | Size: 116 KiB |
BIN
oppgavetekster/oving7/images/ObservableList_del3.png
Normal file
After Width: | Height: | Size: 118 KiB |
BIN
oppgavetekster/oving7/images/Train_del1.png
Normal file
After Width: | Height: | Size: 16 KiB |
BIN
oppgavetekster/oving7/images/Train_del2.png
Normal file
After Width: | Height: | Size: 52 KiB |
BIN
oppgavetekster/oving7/images/Train_del3.png
Normal file
After Width: | Height: | Size: 103 KiB |
25
src/main/java/inheritance/AbstractAccount.java
Normal file
@ -0,0 +1,25 @@
|
||||
package inheritance;
|
||||
|
||||
public abstract class AbstractAccount {
|
||||
|
||||
protected double balance;
|
||||
|
||||
public void deposit(double amount) {
|
||||
if (amount < 0)
|
||||
throw new IllegalArgumentException("Can not deposit a negative amount of money.");
|
||||
this.balance += amount;
|
||||
}
|
||||
|
||||
public void withdraw(double amount) {
|
||||
if (amount < 0)
|
||||
throw new IllegalArgumentException("Can not withdraw a negative amount of money.");
|
||||
internalWithdraw(amount);
|
||||
}
|
||||
|
||||
public abstract void internalWithdraw(double amount);
|
||||
|
||||
public double getBalance() {
|
||||
return balance;
|
||||
}
|
||||
|
||||
}
|
36
src/main/java/inheritance/CargoCar.java
Normal file
@ -0,0 +1,36 @@
|
||||
package inheritance;
|
||||
|
||||
public class CargoCar extends TrainCar {
|
||||
|
||||
private int cargoWeight;
|
||||
|
||||
public CargoCar(int deadWeight, int cargoWeight){
|
||||
super(deadWeight);
|
||||
this.setCargoWeight(cargoWeight);
|
||||
}
|
||||
|
||||
public int getCargoWeight() {
|
||||
return this.cargoWeight;
|
||||
}
|
||||
|
||||
public void setCargoWeight(int cargoWeight) {
|
||||
if (cargoWeight < 0)
|
||||
throw new IllegalArgumentException("Cargo weight cannot be less than 0");
|
||||
this.cargoWeight = cargoWeight;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTotalWeight() {
|
||||
return this.getDeadWeight() + this.getCargoWeight();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format(
|
||||
"(Cargo w:%d, cw:%d)",
|
||||
this.getTotalWeight(),
|
||||
this.getCargoWeight()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
34
src/main/java/inheritance/CreditAccount.java
Normal file
@ -0,0 +1,34 @@
|
||||
package inheritance;
|
||||
|
||||
public class CreditAccount extends AbstractAccount {
|
||||
|
||||
private double creditLine;
|
||||
|
||||
public CreditAccount(double creditLine) {
|
||||
this.setCreditLine(creditLine);
|
||||
}
|
||||
|
||||
public double getCreditLine() {
|
||||
return creditLine;
|
||||
}
|
||||
|
||||
public void setCreditLine(double creditLine) {
|
||||
if (creditLine < 0)
|
||||
throw new IllegalArgumentException();
|
||||
|
||||
if (creditLine + super.getBalance() < 0)
|
||||
throw new IllegalStateException();
|
||||
|
||||
this.creditLine = creditLine;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void internalWithdraw(double amount) {
|
||||
|
||||
if (creditLine + super.getBalance() - amount < 0)
|
||||
throw new IllegalStateException();
|
||||
|
||||
super.balance -= amount;
|
||||
}
|
||||
|
||||
}
|
12
src/main/java/inheritance/DebitAccount.java
Normal file
@ -0,0 +1,12 @@
|
||||
package inheritance;
|
||||
|
||||
public class DebitAccount extends AbstractAccount {
|
||||
|
||||
@Override
|
||||
public void internalWithdraw(double amount) {
|
||||
if (this.balance - amount < 0)
|
||||
throw new IllegalStateException("The account does not contain enough money for the withdrawal.");
|
||||
super.balance -= amount;
|
||||
}
|
||||
|
||||
}
|
40
src/main/java/inheritance/PassengerCar.java
Normal file
@ -0,0 +1,40 @@
|
||||
package inheritance;
|
||||
|
||||
public class PassengerCar extends TrainCar {
|
||||
|
||||
private int passengerCount;
|
||||
private static int passengerWeight = 80;
|
||||
|
||||
public PassengerCar(int deadWeight, int passengerCount) {
|
||||
super(deadWeight);
|
||||
this.setPassengerCount(passengerCount);
|
||||
}
|
||||
|
||||
public int getPassengerCount() {
|
||||
return this.passengerCount;
|
||||
}
|
||||
|
||||
public void setPassengerCount(int passengerCount) {
|
||||
if (passengerCount < 0)
|
||||
throw new IllegalArgumentException("Passenger count cannot be less than 0");
|
||||
this.passengerCount = passengerCount;
|
||||
}
|
||||
|
||||
private int getTotalPassengerWeight() {
|
||||
return this.getPassengerCount() * passengerWeight;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTotalWeight() {
|
||||
return this.getDeadWeight() + this.getTotalPassengerWeight();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format(
|
||||
"(Passengers w:%d, pc:%d)",
|
||||
this.getTotalWeight(),
|
||||
this.getPassengerCount()
|
||||
);
|
||||
}
|
||||
}
|
38
src/main/java/inheritance/SavingsAccount2.java
Normal file
@ -0,0 +1,38 @@
|
||||
package inheritance;
|
||||
|
||||
public class SavingsAccount2 extends AbstractAccount {
|
||||
|
||||
int withdrawals;
|
||||
int withdrawalCount;
|
||||
double fee;
|
||||
|
||||
public SavingsAccount2(int withdrawals, double fee) {
|
||||
this.setWithdrawals(withdrawals);
|
||||
this.setFee(fee);
|
||||
}
|
||||
|
||||
public void setWithdrawals(int withdrawals) {
|
||||
if (withdrawals < 0)
|
||||
throw new IllegalArgumentException();
|
||||
this.withdrawals = withdrawals;
|
||||
}
|
||||
|
||||
public void setFee(double fee) {
|
||||
if (fee < 0)
|
||||
throw new IllegalArgumentException();
|
||||
this.fee = fee;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void internalWithdraw(double amount) {
|
||||
if (withdrawalCount >= withdrawals)
|
||||
amount += fee;
|
||||
|
||||
if (this.balance - amount < 0)
|
||||
throw new IllegalStateException("The account does not contain enough money for the withdrawal.");
|
||||
|
||||
withdrawalCount++;
|
||||
super.balance -= amount;
|
||||
}
|
||||
|
||||
}
|
55
src/main/java/inheritance/Train.java
Normal file
@ -0,0 +1,55 @@
|
||||
package inheritance;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class Train {
|
||||
private Collection<TrainCar> cars = new ArrayList<>();
|
||||
|
||||
public void addTrainCar(TrainCar car) {
|
||||
this.cars.add(car);
|
||||
}
|
||||
|
||||
public boolean contains(TrainCar car) {
|
||||
return this.cars.contains(car);
|
||||
}
|
||||
|
||||
public int getTotalWeight() {
|
||||
return
|
||||
this.cars
|
||||
.stream()
|
||||
.map(car -> car.getTotalWeight())
|
||||
.reduce(0, (a, b) -> a+b);
|
||||
}
|
||||
|
||||
public int getPassengerCount() {
|
||||
return
|
||||
this.cars
|
||||
.stream()
|
||||
.filter(car -> car instanceof PassengerCar)
|
||||
.map(car -> (PassengerCar) car)
|
||||
.map(pcar -> pcar.getPassengerCount())
|
||||
.reduce(0, (a, b) -> a+b);
|
||||
}
|
||||
|
||||
public int getCargoWeight() {
|
||||
return
|
||||
this.cars
|
||||
.stream()
|
||||
.filter(car -> car instanceof CargoCar)
|
||||
.map(car -> (CargoCar) car)
|
||||
.map(ccar -> ccar.getCargoWeight())
|
||||
.reduce(0, (a, b) -> a+b);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return
|
||||
"\uD83D\uDE82 - "
|
||||
+ this.cars
|
||||
.stream()
|
||||
.map(car -> car.toString())
|
||||
.collect(Collectors.joining(" - "));
|
||||
}
|
||||
}
|
34
src/main/java/inheritance/TrainCar.java
Normal file
@ -0,0 +1,34 @@
|
||||
package inheritance;
|
||||
|
||||
|
||||
public class TrainCar {
|
||||
private int deadWeight;
|
||||
|
||||
public TrainCar(int deadWeight) {
|
||||
this.setDeadWeight(deadWeight);
|
||||
}
|
||||
|
||||
public int getTotalWeight() {
|
||||
return deadWeight;
|
||||
}
|
||||
|
||||
public void setDeadWeight(int deadWeight) {
|
||||
if (deadWeight < 0)
|
||||
throw new IllegalArgumentException("Deadweight cannot be less than 0");
|
||||
this.deadWeight = deadWeight;
|
||||
}
|
||||
|
||||
public int getDeadWeight() {
|
||||
return this.deadWeight;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format(
|
||||
"(Car w:%d)",
|
||||
this.getTotalWeight()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
63
src/main/java/patterns/observable/HighscoreList.java
Normal file
@ -0,0 +1,63 @@
|
||||
package patterns.observable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
class HighscoreList {
|
||||
|
||||
private int maxSize;
|
||||
private List<Integer> results;
|
||||
private List<HighscoreListListener> listeners;
|
||||
|
||||
public HighscoreList(int maxSize) {
|
||||
this.maxSize = maxSize;
|
||||
this.results = new ArrayList<>();
|
||||
this.listeners = new ArrayList<>();
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return results.size();
|
||||
}
|
||||
|
||||
public int getElement(int n) {
|
||||
return results.get(n);
|
||||
}
|
||||
|
||||
public void addResult(int result) {
|
||||
|
||||
int i = 0;
|
||||
|
||||
if (results.isEmpty())
|
||||
results.add(result);
|
||||
|
||||
else {
|
||||
while (i + 1 < results.size() && results.get(i) <= result)
|
||||
i++;
|
||||
|
||||
if (i + 1 == results.size())
|
||||
results.add(result);
|
||||
else
|
||||
results.add(i, result);
|
||||
}
|
||||
|
||||
if (results.size() > maxSize)
|
||||
results.remove(maxSize);
|
||||
|
||||
System.out.println(results);
|
||||
System.out.println(i);
|
||||
|
||||
boolean elementWasDeleted = i + 1 == this.maxSize;
|
||||
|
||||
for (var listener : listeners)
|
||||
listener.listChanged(this, elementWasDeleted ? -1 : i);
|
||||
|
||||
}
|
||||
|
||||
public void addHighscoreListListener(HighscoreListListener listener) {
|
||||
this.listeners.add(listener);
|
||||
}
|
||||
|
||||
public void removeHighscoreListListener(HighscoreListListener listener) {
|
||||
this.listeners.remove(listener);
|
||||
}
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
package patterns.observable;
|
||||
|
||||
interface HighscoreListListener {
|
||||
void listChanged(HighscoreList list, int n);
|
||||
}
|
37
src/main/java/patterns/observable/HighscoreListProgram.java
Normal file
@ -0,0 +1,37 @@
|
||||
package patterns.observable;
|
||||
|
||||
import java.util.Scanner;
|
||||
|
||||
public class HighscoreListProgram implements HighscoreListListener {
|
||||
|
||||
private HighscoreList list;
|
||||
|
||||
/** oppretter en ny HighscoreList og registrerer seg selv (altså HighscoreListProgram-instansen) som lytter */
|
||||
public void init() {
|
||||
this.list = new HighscoreList(4);
|
||||
|
||||
this.list.addHighscoreListListener(this);
|
||||
}
|
||||
|
||||
/** leser inn tall (resultater) fra konsollet og legger dem til i listen */
|
||||
public void run() {
|
||||
try(Scanner scanner = new Scanner(System.in)){
|
||||
var i = scanner.nextInt();
|
||||
// this.list.addResult(i);
|
||||
System.out.println(i);
|
||||
}
|
||||
}
|
||||
|
||||
/** observerer endringer i HighscoreList-instansen og skriver ut posisjonsargumentet, samt selve listen, til konsollen. */
|
||||
public void listChanged(HighscoreList list, int i) {
|
||||
System.out.println(list.toString() + " " + i);
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
HighscoreListProgram prog = new HighscoreListProgram();
|
||||
prog.init();
|
||||
while (true) {
|
||||
prog.run();
|
||||
}
|
||||
}
|
||||
}
|
25
src/test/java/inheritance/CargoCarTest.java
Normal file
@ -0,0 +1,25 @@
|
||||
package inheritance;
|
||||
|
||||
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 CargoCarTest {
|
||||
|
||||
private CargoCar cc;
|
||||
|
||||
@BeforeEach
|
||||
public void setup() {
|
||||
cc = new CargoCar(3000, 2000);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Sjekke totalvekt")
|
||||
public void testWeight() {
|
||||
Assertions.assertEquals(5000, cc.getTotalWeight(), "Totalvekt ble feil etter initialisering");
|
||||
cc.setCargoWeight(4000);
|
||||
Assertions.assertEquals(7000, cc.getTotalWeight(), "Totalvekt ble feil etter endret cargo-vekt");
|
||||
Assertions.assertEquals(4000, cc.getCargoWeight(), "Cargo-vekt ble feil etter endring i cargo-vekt");
|
||||
}
|
||||
}
|
65
src/test/java/inheritance/CreditAccountTest.java
Normal file
@ -0,0 +1,65 @@
|
||||
package inheritance;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class CreditAccountTest {
|
||||
private CreditAccount sub;
|
||||
private static double epsilon = 0.0005d;
|
||||
|
||||
@BeforeEach
|
||||
public void setUp() {
|
||||
sub = new CreditAccount(10000.0);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Sjekk at innskudd fungerer som det skal")
|
||||
void testDeposit() {
|
||||
assertEquals(0.0, sub.getBalance(), epsilon, "Saldoen på kontoen ble feil");
|
||||
sub.deposit(10000.0);
|
||||
assertEquals(10000.0, sub.getBalance(), epsilon, "Saldoen på kontoen ble feil");
|
||||
assertThrows(IllegalArgumentException.class, () -> {
|
||||
sub.deposit(-10000.0);
|
||||
}, "Negativt innskudd burde gitt utløst IllegalArugment-unntak!");
|
||||
assertEquals(10000.0, sub.getBalance(), epsilon, "Saldoen på kontoen ble feil");
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Sjekk at uttak fungerer som det skal")
|
||||
void testWithdraw() {
|
||||
sub.deposit(20000.0);
|
||||
sub.withdraw(5000.0);
|
||||
assertEquals(15000.0, sub.getBalance(), epsilon, "Saldoen på kontoen ble feil");
|
||||
assertThrows(IllegalArgumentException.class, () -> {
|
||||
sub.withdraw(-10000.0);
|
||||
}, "Negativt uttak burde gitt utløst IllegalArugment-unntak!");
|
||||
assertEquals(15000.0, sub.getBalance(), epsilon, "Saldoen på kontoen ble feil");
|
||||
sub.withdraw(20000.0);
|
||||
assertEquals(-5000.0, sub.getBalance(), epsilon, "Saldoen på kontoen ble feil");
|
||||
assertThrows(IllegalStateException.class, () -> {
|
||||
sub.withdraw(20000.0);
|
||||
}, "Uttak på mer enn kredittgrense burde utløst IllegalState-unntak");
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Sjekk at kredittgrensen fungerer som den skal")
|
||||
void testCreditLine() {
|
||||
assertEquals(10000.0, sub.getCreditLine(), epsilon, "Kredittgrensen var feil");
|
||||
sub.setCreditLine(5000.0);
|
||||
assertEquals(5000.0, sub.getCreditLine(), epsilon, "Kredittgrensen var feil");
|
||||
assertThrows(IllegalArgumentException.class, () -> {
|
||||
sub.setCreditLine(-5000.0);
|
||||
}, "Kan ikke ha negativ kredittgrense");
|
||||
assertEquals(5000.0, sub.getCreditLine(), epsilon, "Kredittgrensen var feil");
|
||||
sub.withdraw(4000.0);
|
||||
assertThrows(IllegalStateException.class, () -> {
|
||||
sub.setCreditLine(3000.0);
|
||||
}, "Kan ikke sette kredittgrense som vil gi ugyldig saldo");
|
||||
assertEquals(-4000.0, sub.getBalance(), epsilon, "Saldoen var feil");
|
||||
assertEquals(5000.0, sub.getCreditLine(), epsilon, "Kredittgrensen var feil");
|
||||
}
|
||||
}
|
45
src/test/java/inheritance/DebitAccountTest.java
Normal file
@ -0,0 +1,45 @@
|
||||
package inheritance;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class DebitAccountTest {
|
||||
private DebitAccount sub;
|
||||
private static double epsilon = 0.0005d;
|
||||
|
||||
@BeforeEach
|
||||
public void setUp() {
|
||||
sub = new DebitAccount();
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Sjekk at innskudd fungerer som det skal")
|
||||
void testDeposit() {
|
||||
assertEquals(0.0, sub.getBalance(), epsilon, "Saldoen på kontoen ble feil");
|
||||
sub.deposit(10000.0);
|
||||
assertEquals(10000.0, sub.getBalance(), epsilon, "Saldoen på kontoen ble feil");
|
||||
assertThrows(IllegalArgumentException.class, () -> {
|
||||
sub.deposit(-10000.0);
|
||||
}, "Negativt innskudd burde gitt utløst IllegalArugment-unntak!");
|
||||
assertEquals(10000.0, sub.getBalance(), epsilon, "Saldoen på kontoen ble feil");
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Sjekk at uttak fungerer som det skal")
|
||||
void testWithdraw() {
|
||||
sub.deposit(20000.0);
|
||||
sub.withdraw(5000.0);
|
||||
assertEquals(15000.0, sub.getBalance(), epsilon, "Saldoen på kontoen ble feil");
|
||||
assertThrows(IllegalArgumentException.class, () -> {
|
||||
sub.withdraw(-10000.0);
|
||||
}, "Negativt uttak burde gitt utløst IllegalArugment-unntak!");
|
||||
assertEquals(15000.0, sub.getBalance(), epsilon, "Saldoen på kontoen ble feil");
|
||||
assertThrows(IllegalStateException.class, () -> {
|
||||
sub.withdraw(20000.0);
|
||||
}, "Uttak på mer enn saldo burde utløst IllegalState-unntak");
|
||||
}
|
||||
}
|
27
src/test/java/inheritance/PassengerCarTest.java
Normal file
@ -0,0 +1,27 @@
|
||||
package inheritance;
|
||||
|
||||
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 PassengerCarTest {
|
||||
|
||||
private PassengerCar pc;
|
||||
|
||||
@BeforeEach
|
||||
public void setup() {
|
||||
pc = new PassengerCar(3000, 200);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Sjekke totalvekt med passasjerer")
|
||||
public void testWeight() {
|
||||
Assertions.assertEquals(3000 + (200 * 80), pc.getTotalWeight(), "Totalvekt ble feil etter initialisering");
|
||||
pc.setPassengerCount(100);
|
||||
Assertions.assertEquals(3000 + (100 * 80), pc.getTotalWeight(),
|
||||
"Totalvekt ble feil etter endret passasjer-antall");
|
||||
Assertions.assertEquals(100, pc.getPassengerCount(),
|
||||
"Antall passasjerer ble feil etter kall av setPassengerCount");
|
||||
}
|
||||
}
|
53
src/test/java/inheritance/SavingsAccount2Test.java
Normal file
@ -0,0 +1,53 @@
|
||||
package inheritance;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class SavingsAccount2Test {
|
||||
private SavingsAccount2 sub;
|
||||
private static double epsilon = 0.0005d;
|
||||
|
||||
@BeforeEach
|
||||
public void setUp() {
|
||||
sub = new SavingsAccount2(1, 50.0);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Sjekk at innskudd fungerer som det skal")
|
||||
void testDeposit() {
|
||||
assertEquals(0.0, sub.getBalance(), epsilon, "Saldoen på kontoen ble feil");
|
||||
sub.deposit(10000.0);
|
||||
assertEquals(10000.0, sub.getBalance(), epsilon, "Saldoen på kontoen ble feil");
|
||||
assertThrows(IllegalArgumentException.class, () -> {
|
||||
sub.deposit(-10000.0);
|
||||
}, "Negativt innskudd burde utløst IllegalArugment-unntak!");
|
||||
assertEquals(10000.0, sub.getBalance(), epsilon, "Saldoen på kontoen ble feil");
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Sjekk at uttak fungerer som det skal")
|
||||
void testWithdraw() {
|
||||
sub.deposit(20000.0);
|
||||
sub.withdraw(5000.0);
|
||||
assertEquals(15000.0, sub.getBalance(), epsilon, "Saldoen på kontoen ble feil");
|
||||
assertThrows(IllegalArgumentException.class, () -> {
|
||||
sub.withdraw(-10000.0);
|
||||
}, "Negativt uttak burde utløst IllegalArugment-unntak!");
|
||||
assertEquals(15000.0, sub.getBalance(), epsilon, "Saldoen på kontoen ble feil");
|
||||
assertThrows(IllegalStateException.class, () -> {
|
||||
sub.withdraw(20000.0);
|
||||
}, "Uttak på mer enn saldo burde utløst IllegalState-unntak");
|
||||
assertEquals(15000.0, sub.getBalance(), epsilon, "Saldoen på kontoen ble feil");
|
||||
sub.withdraw(10000.0);
|
||||
assertEquals(4950.0, sub.getBalance(), epsilon, "Saldoen på kontoen ble feil etter at gebyret var trukket fra");
|
||||
assertThrows(IllegalStateException.class, () -> {
|
||||
sub.withdraw(4930.0);
|
||||
}, "Uttak på mer enn saldo + gebyr burde utløst IllegalState-unntak");
|
||||
assertEquals(4950.0, sub.getBalance(), epsilon, "Saldoen på kontoen ble feil etter at gebyret var trukket fra");
|
||||
}
|
||||
|
||||
}
|
24
src/test/java/inheritance/TrainCarTest.java
Normal file
@ -0,0 +1,24 @@
|
||||
package inheritance;
|
||||
|
||||
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 TrainCarTest {
|
||||
|
||||
private TrainCar tc;
|
||||
|
||||
@BeforeEach
|
||||
public void setup() {
|
||||
tc = new TrainCar(3000);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Sjekk at dødvekt er det samme som totalvekt")
|
||||
public void testDeadWeight() {
|
||||
Assertions.assertEquals(3000, tc.getTotalWeight(), "Totalvekt skulle vært samme som dødvekt");
|
||||
tc.setDeadWeight(5000);
|
||||
Assertions.assertEquals(5000, tc.getTotalWeight(), "Totalvekt skulle vært samme som dødvekt");
|
||||
}
|
||||
}
|
73
src/test/java/inheritance/TrainTest.java
Normal file
@ -0,0 +1,73 @@
|
||||
package inheritance;
|
||||
|
||||
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 TrainTest {
|
||||
|
||||
private Train train;
|
||||
private PassengerCar pc1, pc2;
|
||||
private CargoCar cc1, cc2;
|
||||
|
||||
@BeforeEach
|
||||
public void setup() {
|
||||
train = new Train();
|
||||
pc1 = new PassengerCar(2000, 200);
|
||||
pc2 = new PassengerCar(1500, 100);
|
||||
cc1 = new CargoCar(3000, 5000);
|
||||
cc2 = new CargoCar(2500, 7000);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Sjekk at toget inneholder vogner etter at de er lagt til")
|
||||
public void testAddCarToTrain() {
|
||||
train.addTrainCar(pc1);
|
||||
train.addTrainCar(pc2);
|
||||
train.addTrainCar(cc1);
|
||||
Assertions.assertTrue(train.contains(pc1), "Toget skulle inneholdt passasjervogn 1 etter at det er lagt til");
|
||||
Assertions.assertTrue(train.contains(pc2), "Toget skulle inneholdt passasjervogn 2 etter at det er lagt til");
|
||||
Assertions.assertTrue(train.contains(cc1), "Toget skulle inneholdt lastvogn 1 etter at det er lagt til");
|
||||
Assertions.assertFalse(train.contains(cc2), "Toget skulle inneholdt lastvogn 2 etter at det er lagt til");
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Sjekke totalvekt på toget etter å ha lagt til vogner")
|
||||
public void testTotalTrainWeight() {
|
||||
train.addTrainCar(pc1);
|
||||
train.addTrainCar(cc1);
|
||||
|
||||
Assertions.assertEquals(8000 + (2000 + (200 * 80)), train.getTotalWeight(),
|
||||
"Togets totalvekt ble feil etter å ha lagt til to vogner");
|
||||
|
||||
train.addTrainCar(pc2);
|
||||
|
||||
Assertions.assertEquals(8000 + (2000 + (200 * 80)) + (1500 + (100 * 80)), train.getTotalWeight(),
|
||||
"Togets totalvekt ble feil etter å ha lagt til enda en passasjervogn");
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Sjekk total passajerantall etter å ha lagt til to passasjervogner")
|
||||
public void testPassengerCount() {
|
||||
train.addTrainCar(pc1);
|
||||
train.addTrainCar(pc2);
|
||||
Assertions.assertEquals(300, train.getPassengerCount(),
|
||||
"Passasjerantall ble feil etter å ha lagt til to passasjervogner");
|
||||
train.addTrainCar(cc1);
|
||||
Assertions.assertEquals(300, train.getPassengerCount(),
|
||||
"Passasjerantall ble feil etter å ha lagt til en lastvogn");
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Sjekk lastvekt på toget etter å ha lagt til to lastvogner")
|
||||
public void testCargoWeight() {
|
||||
train.addTrainCar(cc1);
|
||||
train.addTrainCar(cc2);
|
||||
Assertions.assertEquals(12000, train.getCargoWeight(), "Lastvekt ble feil etter å ha lagt til to lastvogner");
|
||||
|
||||
train.addTrainCar(pc1);
|
||||
Assertions.assertEquals(12000, train.getCargoWeight(),
|
||||
"Lastvekt ble feil etter å ha lagt til en passasjervogn");
|
||||
}
|
||||
}
|
8
src/test/java/patterns/observable/.gitignore
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
/.ObservableHighscoreListTest.java._trace
|
||||
/.HighscoreListTest.java._trace
|
||||
/.ObservableListTest.java._trace
|
||||
/.StockTest.java._trace
|
||||
/.StockIndexTest.java._trace
|
||||
/.StopWatchManagerTest.java._trace
|
||||
/.StopWatchTest.java._trace
|
||||
/.SmartStockTest.java._trace
|
140
src/test/java/patterns/observable/HighscoreListTest.java
Normal file
@ -0,0 +1,140 @@
|
||||
package patterns.observable;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
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 HighscoreListTest{
|
||||
|
||||
private HighscoreList highscoreList;
|
||||
private int pos1, pos2;
|
||||
|
||||
private void checkHighscoreList(String contextMessage, HighscoreList list, List<Integer> elements) {
|
||||
Assertions.assertEquals(elements.size(), list.size(), contextMessage + " -> Teste lengden på highscore-listen");
|
||||
int i = 0;
|
||||
for (int element:elements) {
|
||||
Assertions.assertEquals(element, list.getElement(i), contextMessage + " -> Teste at element på plass " + i + " stemmer");
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
private void addResultWithListener(int pos, int element) {
|
||||
pos1 = pos;
|
||||
highscoreList.addResult(element);
|
||||
|
||||
// Sjekke at posisjonen som ble endret er den samme som ble sendt til lytteren
|
||||
Assertions.assertEquals(pos1, pos2, "La til " + element + " på posisjon " + pos + " -> Teste posisjonen mottatt av lytter");
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
public void setup() {
|
||||
highscoreList = new HighscoreList(3);
|
||||
pos1 = -1;
|
||||
pos2 = -1;
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Teste konstruktør")
|
||||
public void testConstructor() {
|
||||
Assertions.assertEquals(0, highscoreList.size(), "Teste initialisering av highscore-listen");
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Legge til resultater (enkel)")
|
||||
public void testAddElementSimple() {
|
||||
highscoreList.addResult(5);
|
||||
checkHighscoreList("La til 5 i tom liste",highscoreList, Arrays.asList(5));
|
||||
|
||||
highscoreList.addResult(6);
|
||||
checkHighscoreList("La til 6 i listen [5]",highscoreList, Arrays.asList(5, 6));
|
||||
|
||||
highscoreList.addResult(2);
|
||||
checkHighscoreList("La til 2 i listen [5, 6]", highscoreList, Arrays.asList(2, 5, 6));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Legge til resultater - listen blir for lang")
|
||||
public void testAddElementMoreThanMax() {
|
||||
highscoreList.addResult(5);
|
||||
highscoreList.addResult(6);
|
||||
highscoreList.addResult(2);
|
||||
checkHighscoreList("La til 5, 6 og 2 i listen", highscoreList, Arrays.asList(2, 5, 6));
|
||||
|
||||
highscoreList.addResult(3);
|
||||
checkHighscoreList("La til 3 i listen [2, 5, 6]", highscoreList, Arrays.asList(2, 3, 5));
|
||||
|
||||
highscoreList.addResult(7);
|
||||
checkHighscoreList("La til 7 i listen [2, 3, 5]", highscoreList, Arrays.asList(2, 3, 5));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Legge til to like elementer")
|
||||
public void testAddElementDuplicate() {
|
||||
highscoreList.addResult(5);
|
||||
highscoreList.addResult(6);
|
||||
highscoreList.addResult(2);
|
||||
checkHighscoreList("La til 5, 6 og 2 i listen", highscoreList, Arrays.asList(2, 5, 6));
|
||||
|
||||
highscoreList.addResult(2);
|
||||
checkHighscoreList("La til 2 i listen [2, 5, 6]", highscoreList, Arrays.asList(2, 2, 5));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Teste lyttere (enkel)")
|
||||
public void testListListenersSimple() {
|
||||
// Mocke en lytter
|
||||
HighscoreListListener listener = (list, pos) -> pos2 = pos;
|
||||
highscoreList.addHighscoreListListener(listener);
|
||||
|
||||
addResultWithListener(0, 5);
|
||||
checkHighscoreList("La til 5 i listen []", highscoreList, Arrays.asList(5));
|
||||
|
||||
addResultWithListener(1, 6);
|
||||
checkHighscoreList("La til 6 i listen [5]",highscoreList, Arrays.asList(5, 6));
|
||||
|
||||
addResultWithListener(0, 2);
|
||||
checkHighscoreList("La til 2 i listen [5, 6]", highscoreList, Arrays.asList(2, 5, 6));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Med lytter - listen blir for lang")
|
||||
public void testListListenerMoreThanMax() {
|
||||
// Mocke en lytter
|
||||
HighscoreListListener listener = (list, pos) -> pos2 = pos;
|
||||
highscoreList.addHighscoreListListener(listener);
|
||||
|
||||
highscoreList.addResult(5);
|
||||
highscoreList.addResult(6);
|
||||
highscoreList.addResult(2);
|
||||
checkHighscoreList("La til 5, 6 og 2 i listen",highscoreList, Arrays.asList(2, 5, 6));
|
||||
|
||||
addResultWithListener(1, 3);
|
||||
checkHighscoreList("La til 3 i listen [2, 5, 6]", highscoreList, Arrays.asList(2, 3, 5));
|
||||
|
||||
// Nullstille pos2 siden neste element havner utenfor listen og blir dermed ikke oppdatert av seg selv og sendt til lytter
|
||||
pos2 = -1;
|
||||
addResultWithListener(-1, 7);
|
||||
checkHighscoreList("La til 7 i listen [2, 3, 5]", highscoreList, Arrays.asList(2, 3, 5));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Med lytter - to like elementer")
|
||||
public void testListListenerDuplicate() {
|
||||
// Mocke en lytter
|
||||
HighscoreListListener listener = (list, pos) -> pos2 = pos;
|
||||
highscoreList.addHighscoreListListener(listener);
|
||||
|
||||
highscoreList.addResult(5);
|
||||
highscoreList.addResult(6);
|
||||
highscoreList.addResult(2);
|
||||
checkHighscoreList("La til 5, 6 og 2 i listen",highscoreList, Arrays.asList(2, 5, 6));
|
||||
|
||||
addResultWithListener(1, 2);
|
||||
checkHighscoreList("La til 2 i listen [2, 5, 6]", highscoreList, Arrays.asList(2, 2, 5));
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,143 @@
|
||||
package patterns.observable;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
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 ObservableHighscoreListTest {
|
||||
|
||||
private ObservableHighscoreList highscoreList;
|
||||
private int pos1, pos2;
|
||||
|
||||
private void checkHighscoreList(String contextMessage, ObservableHighscoreList list, List<Integer> elements) {
|
||||
Assertions.assertEquals(elements.size(), list.size(),
|
||||
contextMessage + " -> Lengden på highscore-listen ble feil");
|
||||
int i = 0;
|
||||
for (int element : elements) {
|
||||
Assertions.assertEquals(element, list.getElement(i),
|
||||
contextMessage + String.format(" -> Elementet på plass %d ble feil", i));
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
private void addResultWithListener(int pos, int element) {
|
||||
pos1 = pos;
|
||||
highscoreList.addResult(element);
|
||||
|
||||
// Sjekke at posisjonen som ble endret er den samme som ble sendt til lytteren
|
||||
Assertions.assertEquals(pos1, pos2, "La til " + element + " på posisjon " + pos
|
||||
+ "Posisjonen som ble endret var ikke samme som ble sendt til lytteren");
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
public void setup() {
|
||||
highscoreList = new ObservableHighscoreList(3);
|
||||
pos1 = -1;
|
||||
pos2 = -1;
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Teste konstruktør")
|
||||
public void testConstructor() {
|
||||
Assertions.assertEquals(0, highscoreList.size(), "Highscorelist ble ikke initialisert til en tom liste");
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Legge til resultater (enkel)")
|
||||
public void testAddElementSimple() {
|
||||
highscoreList.addResult(5);
|
||||
checkHighscoreList("La til 5 i tom liste", highscoreList, Arrays.asList(5));
|
||||
|
||||
highscoreList.addResult(6);
|
||||
checkHighscoreList("La til 6 i listen [5]", highscoreList, Arrays.asList(5, 6));
|
||||
|
||||
highscoreList.addResult(2);
|
||||
checkHighscoreList("La til 2 i listen [5, 6]", highscoreList, Arrays.asList(2, 5, 6));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Legge til resultater - listen blir for lang")
|
||||
public void testAddElementMoreThanMax() {
|
||||
highscoreList.addResult(5);
|
||||
highscoreList.addResult(6);
|
||||
highscoreList.addResult(2);
|
||||
checkHighscoreList("La til 5, 6 og 2 i listen", highscoreList, Arrays.asList(2, 5, 6));
|
||||
|
||||
highscoreList.addResult(3);
|
||||
checkHighscoreList("La til 3 i listen [2, 5, 6]", highscoreList, Arrays.asList(2, 3, 5));
|
||||
|
||||
highscoreList.addResult(7);
|
||||
checkHighscoreList("La til 7 i listen [2, 3, 5]", highscoreList, Arrays.asList(2, 3, 5));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Legge til to like elementer")
|
||||
public void testAddElementDuplicate() {
|
||||
highscoreList.addResult(5);
|
||||
highscoreList.addResult(6);
|
||||
highscoreList.addResult(2);
|
||||
checkHighscoreList("La til 5, 6 og 2 i listen", highscoreList, Arrays.asList(2, 5, 6));
|
||||
|
||||
highscoreList.addResult(2);
|
||||
checkHighscoreList("La til 2 i listen [2, 5, 6]", highscoreList, Arrays.asList(2, 2, 5));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Teste lyttere (enkel)")
|
||||
public void testListListenersSimple() {
|
||||
// Mocke en lytter
|
||||
ObservableListListener listener = (list, pos) -> pos2 = pos;
|
||||
highscoreList.addObservableListListener(listener);
|
||||
|
||||
addResultWithListener(0, 5);
|
||||
checkHighscoreList("La til 5 i listen []", highscoreList, Arrays.asList(5));
|
||||
|
||||
addResultWithListener(1, 6);
|
||||
checkHighscoreList("La til 6 i listen [5]", highscoreList, Arrays.asList(5, 6));
|
||||
|
||||
addResultWithListener(0, 2);
|
||||
checkHighscoreList("La til 2 i listen [5, 6]", highscoreList, Arrays.asList(2, 5, 6));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Med lytter - listen blir for lang")
|
||||
public void testListListenerMoreThanMax() {
|
||||
// Mocke en lytter
|
||||
ObservableListListener listener = (list, pos) -> pos2 = pos;
|
||||
highscoreList.addObservableListListener(listener);
|
||||
|
||||
highscoreList.addResult(5);
|
||||
highscoreList.addResult(6);
|
||||
highscoreList.addResult(2);
|
||||
checkHighscoreList("La til 5, 6 og 2 i listen", highscoreList, Arrays.asList(2, 5, 6));
|
||||
|
||||
addResultWithListener(1, 3);
|
||||
checkHighscoreList("La til 3 i listen [2, 5, 6]", highscoreList, Arrays.asList(2, 3, 5));
|
||||
|
||||
// Nullstille pos2 siden neste element havner utenfor listen og blir dermed ikke
|
||||
// oppdatert av seg selv og sendt til lytter
|
||||
pos2 = -1;
|
||||
addResultWithListener(-1, 7);
|
||||
checkHighscoreList("La til 7 i listen [2, 3, 5]", highscoreList, Arrays.asList(2, 3, 5));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Med lytter - to like elementer")
|
||||
public void testListListenerDuplicate() {
|
||||
// Mocke en lytter
|
||||
ObservableListListener listener = (list, pos) -> pos2 = pos;
|
||||
highscoreList.addObservableListListener(listener);
|
||||
|
||||
highscoreList.addResult(5);
|
||||
highscoreList.addResult(6);
|
||||
highscoreList.addResult(2);
|
||||
checkHighscoreList("La til 5, 6 og 2 i listen", highscoreList, Arrays.asList(2, 5, 6));
|
||||
|
||||
addResultWithListener(1, 2);
|
||||
checkHighscoreList("La til 2 i listen [2, 5, 6]", highscoreList, Arrays.asList(2, 2, 5));
|
||||
}
|
||||
}
|
94
src/test/java/patterns/observable/ObservableListTest.java
Normal file
@ -0,0 +1,94 @@
|
||||
package patterns.observable;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
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 ObservableListTest {
|
||||
|
||||
private ObservableList observableList;
|
||||
private int pos1, pos2;
|
||||
|
||||
private void checkObservableList(ObservableList list, List<Integer> elements, String contextMessage) {
|
||||
Assertions.assertEquals(elements.size(), list.size(),
|
||||
contextMessage + " -> Lengden på ObservableList ble feil");
|
||||
|
||||
int i = 0;
|
||||
for (int element : elements) {
|
||||
Assertions.assertEquals(element, list.getElement(i),
|
||||
contextMessage + String.format(" -> Element på plass %d var feil", i));
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
private void addElementWithListener(int pos, int element) {
|
||||
pos1 = pos;
|
||||
observableList.addElement(pos, element);
|
||||
|
||||
// Sjekke at posisjonen som ble endret er den samme som ble sendt til lytteren
|
||||
Assertions.assertEquals(pos1, pos2,
|
||||
"La til " + element + " på posisjon " + pos + "posisjonen mottat av lytter ble feil, den var " + pos2);
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
public void setup() {
|
||||
observableList = new ObservableList() {
|
||||
@Override
|
||||
public boolean acceptsElement(final Object element) {
|
||||
return (element instanceof Integer);
|
||||
}
|
||||
};
|
||||
pos1 = -1;
|
||||
pos2 = -1;
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Test konstruktør")
|
||||
public void testConstructor() {
|
||||
Assertions.assertEquals(0, observableList.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Sjekk at listen aksepterer riktige elementer")
|
||||
public void testAcceptsElement() {
|
||||
Assertions.assertTrue(observableList.acceptsElement(5), "Listen skulle akseptert integers");
|
||||
Assertions.assertFalse(observableList.acceptsElement("5"), "Listen skulle ikke akseptert strenger");
|
||||
|
||||
Assertions.assertThrows(IllegalArgumentException.class, () -> {
|
||||
observableList.addElement("5");
|
||||
}, "Listen skulle utløst et IllegalArgument-unntak når man prøver å legge til en streng");
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Teste å legge til elementer")
|
||||
public void testAddElement() {
|
||||
observableList.addElement(5);
|
||||
checkObservableList(observableList, Arrays.asList(5), "La til 5 i tom liste");
|
||||
|
||||
observableList.addElement(6);
|
||||
checkObservableList(observableList, Arrays.asList(5, 6), "La til 6 i listen [5]");
|
||||
|
||||
observableList.addElement(0, 2);
|
||||
checkObservableList(observableList, Arrays.asList(2, 5, 6), "La til 2 på posisjon 0 i listen [5, 6]");
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Teste lytter")
|
||||
public void testListListener() {
|
||||
ObservableListListener listener = (list, pos) -> pos2 = pos;
|
||||
observableList.addObservableListListener(listener);
|
||||
|
||||
addElementWithListener(0, 5);
|
||||
checkObservableList(observableList, Arrays.asList(5), "La til 5 i listen []");
|
||||
|
||||
addElementWithListener(1, 6);
|
||||
checkObservableList(observableList, Arrays.asList(5, 6), "La til 6 i listen [5]");
|
||||
|
||||
addElementWithListener(0, 2);
|
||||
checkObservableList(observableList, Arrays.asList(2, 5, 6), "La til 2 i listen [5, 6]");
|
||||
}
|
||||
}
|
111
src/test/java/patterns/observable/SmartStockTest.java
Normal file
@ -0,0 +1,111 @@
|
||||
package patterns.observable;
|
||||
|
||||
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 SmartStockTest{
|
||||
|
||||
private SmartStock stock;
|
||||
|
||||
private double oldPrice, newPrice;
|
||||
|
||||
// Brukes for å sjekke at lyttere funker
|
||||
private double oldPriceListener, newPriceListener;
|
||||
|
||||
private void setPriceForListener(double oldPrice, double newPrice) {
|
||||
oldPriceListener = oldPrice;
|
||||
newPriceListener = newPrice;
|
||||
}
|
||||
|
||||
private void setPriceCheckListener(String contextMessage, double newPrice, double expectedOldPrice, double expectedNewPrice) {
|
||||
// Oppdatere prisen
|
||||
this.oldPrice = this.newPrice;
|
||||
this.newPrice = newPrice;
|
||||
stock.setPrice(newPrice);
|
||||
|
||||
// Sjekke at lytter har mottatt endring
|
||||
Assertions.assertEquals(expectedOldPrice, this.oldPriceListener, contextMessage + " -> Teste gammel pris for lytter etter å ha oppdatert pris fra " + oldPrice + " til " + newPrice);
|
||||
Assertions.assertEquals(expectedNewPrice, this.newPriceListener, contextMessage + " -> Teste ny pris for lytter etter å ha oppdatert pris fra " + oldPrice + " til " + newPrice);
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
public void setup() {
|
||||
stock = new SmartStock("APPL", 110.0);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Teste kontruktør")
|
||||
public void testConstructor() {
|
||||
Assertions.assertEquals("APPL", stock.getTicker(), "Teste ticker");
|
||||
Assertions.assertEquals(110.0, stock.getPrice(), "Teste aksjeprisen");
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Negativ aksjepris gir feilmelding")
|
||||
public void testSetNegativePrice() {
|
||||
Assertions.assertThrows(IllegalArgumentException.class, () -> {
|
||||
stock.setPrice(-20.0);
|
||||
}, "Teste å sette negativ aksjepris");
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Aksjepris lik null gir feilmelding")
|
||||
public void testSetZeroPrice() {
|
||||
Assertions.assertThrows(IllegalArgumentException.class, () -> {
|
||||
stock.setPrice(0);
|
||||
}, "Teste å sette aksjepris lik null");
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Legge til lytter")
|
||||
public void testStockListener() {
|
||||
StockListener listener = (Stock stock, double oldPrice, double newPrice) -> setPriceForListener(oldPrice, newPrice);
|
||||
stock.addStockListener(listener);
|
||||
|
||||
setPriceCheckListener("Lytter på alt", 118.0, 110.0, 118.0);
|
||||
Assertions.assertEquals(118.0, stock.getPrice(), "Teste aksjepris etter å ha oppdatert pris");
|
||||
|
||||
setPriceCheckListener("Lytter på alt", 121.0, 118.0, 121.0);
|
||||
Assertions.assertEquals(121.0, stock.getPrice(), "Teste aksjepris etter å ha oppdatert pris 2 ganger");
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Teste lytter på prisintervall")
|
||||
public void testIntervalListener() {
|
||||
StockListener listener = (Stock stock, double oldPrice, double newPrice) -> setPriceForListener(oldPrice, newPrice);
|
||||
stock.addStockListener(listener, 110.0, 120.0);
|
||||
|
||||
// Pris innenfor intervallet gir ingen beskjed til lytter
|
||||
setPriceCheckListener("Lytter på prisintervall", 118.0, 0.0, 0.0);
|
||||
Assertions.assertEquals(118.0, stock.getPrice(), "Teste aksjepris etter å ha oppdatert pris");
|
||||
|
||||
// Pris utenfor intervallet gir beskjed til lytter
|
||||
setPriceCheckListener("Lytter på prisintervall",121.0, 118.0, 121.0);
|
||||
Assertions.assertEquals(121.0, stock.getPrice(), "Teste aksjepris etter å ha oppdatert pris for andre gang");
|
||||
|
||||
// Pris innenfor intervallet gir ingen beskjed til lytter (forventende verdier forblir det de var)
|
||||
setPriceCheckListener("Lytter på prisintervall",115.0, 118.0, 121.0);
|
||||
Assertions.assertEquals(115.0, stock.getPrice(), "Teste aksjepris etter å ha oppdatert pris for tredje gang");
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Teste lytter på differanse")
|
||||
public void testDifferenceListener() {
|
||||
StockListener listener = (Stock stock, double oldPrice, double newPrice) -> setPriceForListener(oldPrice, newPrice);
|
||||
stock.addStockListener(listener, 10.0);
|
||||
|
||||
// Pris med differanse mindre enn 10 varsler ikke lytter
|
||||
setPriceCheckListener("Lytter på differanse",118.0, 0.0, 0.0);
|
||||
Assertions.assertEquals(118.0, stock.getPrice());
|
||||
|
||||
// Pris med differanse større enn 10 varsler lytter
|
||||
setPriceCheckListener("Lytter på differanse",121.0, 110.0, 121.0);
|
||||
Assertions.assertEquals(121.0, stock.getPrice());
|
||||
|
||||
// Pris med differanse mindre enn 10 varsler ikke lytter (forventende verdier forblir det de var)
|
||||
setPriceCheckListener("Lytter på differanse", 115.0, 110.0, 121.0);
|
||||
Assertions.assertEquals(115.0, stock.getPrice());
|
||||
}
|
||||
}
|
84
src/test/java/patterns/observable/StockIndexTest.java
Normal file
@ -0,0 +1,84 @@
|
||||
package patterns.observable;
|
||||
|
||||
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 StockIndexTest{
|
||||
|
||||
private static final double facebookPrice = 67.80d;
|
||||
private static final double applePrice = 534.98;
|
||||
private static final double epsilon = 0.000001d;
|
||||
|
||||
private Stock facebook, apple;
|
||||
private StockIndex index0, index1, indexN;
|
||||
|
||||
@BeforeEach
|
||||
public void setup() {
|
||||
facebook = new Stock("FB", facebookPrice);
|
||||
apple = new Stock("AAPL", applePrice);
|
||||
|
||||
index0 = new StockIndex("OSEBX");
|
||||
index1 = new StockIndex("OSEBX", facebook);
|
||||
indexN = new StockIndex("OSEBX", facebook, apple);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Teste konstruktør")
|
||||
public void testConstructor() {
|
||||
Assertions.assertEquals(0.0, index0.getIndex(), epsilon, "Teste verdien til indeks med 0 aksjer ");
|
||||
Assertions.assertEquals(facebookPrice, index1.getIndex(), epsilon, "Teste verdien til indeks med 1 aksje");
|
||||
Assertions.assertEquals(facebookPrice + applePrice, indexN.getIndex(), epsilon, "Teste verdien til indeks med 2 aksjer");
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Legge til aksje")
|
||||
public void testAddStock() {
|
||||
Assertions.assertEquals(0.0, index0.getIndex(), epsilon, "Teste verdien til indeks med 0 aksjer");
|
||||
index0.addStock(facebook);
|
||||
Assertions.assertEquals(facebookPrice, index0.getIndex(), epsilon, "Teste verdien til indeks etter å ha lagt til 1 aksje");
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Legge til samme aksje to ganger")
|
||||
public void testAddDuplicateStocks() {
|
||||
Assertions.assertEquals(0.0, index0.getIndex(), epsilon, "Teste verdien til indeks med 0 aksjer");
|
||||
|
||||
index0.addStock(facebook);
|
||||
Assertions.assertEquals(facebookPrice, index0.getIndex(), epsilon, "Teste verdien til indeks etter å ha lagt til 1 aksje");
|
||||
|
||||
index0.addStock(facebook);
|
||||
Assertions.assertEquals(facebookPrice, index0.getIndex(), epsilon, "Teste verdien til indeks etter å ha lagt til aksje som allerede er med i indeks");
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Fjerne aksje")
|
||||
public void testRemoveStock() {
|
||||
Assertions.assertEquals(facebookPrice + applePrice, indexN.getIndex(), epsilon, "Teste verdien til indeks med 2 aksjer");
|
||||
|
||||
indexN.removeStock(apple);
|
||||
Assertions.assertEquals(facebookPrice, indexN.getIndex(), epsilon, "Teste verdien til indeks etter å ha fjernet 1 aksje");
|
||||
|
||||
indexN.removeStock(apple);
|
||||
Assertions.assertEquals(facebookPrice, indexN.getIndex(), epsilon, "Teste verdien til indeks etter å ha fjernet 1 aksje som ikke var med i indeks");
|
||||
|
||||
indexN.removeStock(facebook);
|
||||
Assertions.assertEquals(0.0, indexN.getIndex(), epsilon, "Teste verdien til indeks etter å ha fjernet eneste aksje i indeks");
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Endre aksjepris")
|
||||
public void testChangePrice() {
|
||||
double facebookPrice2 = 67.0;
|
||||
double facebookPrice3 = 69.0;
|
||||
|
||||
facebook.setPrice(facebookPrice2);
|
||||
Assertions.assertEquals(facebookPrice2, index1.getIndex(), epsilon, "Teste verdien til indeks med 1 aksje etter å ha endret prisen på aksje");
|
||||
Assertions.assertEquals(facebookPrice2 + applePrice, indexN.getIndex(), epsilon, "Teste verdien til indeks med 2 aksjer etter å ha endret prisen til 1 av aksjene");
|
||||
|
||||
facebook.setPrice(facebookPrice3);
|
||||
Assertions.assertEquals(facebookPrice3, index1.getIndex(), epsilon, "Teste verdien til indeks med 1 aksje etter å ha endret prisen på aksje for andre gang");
|
||||
Assertions.assertEquals(facebookPrice3 + applePrice, indexN.getIndex(), epsilon, "Teste verdien til indeks med 2 aksjer etter å ha endret prisen til 1 av aksjene for andre gang");
|
||||
}
|
||||
}
|
74
src/test/java/patterns/observable/StockTest.java
Normal file
@ -0,0 +1,74 @@
|
||||
package patterns.observable;
|
||||
|
||||
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 StockTest{
|
||||
|
||||
private Stock stock;
|
||||
private double oldPrice, newPrice;
|
||||
|
||||
// Brukes for å sjekke at lyttere funker
|
||||
private double oldPriceListener, newPriceListener;
|
||||
|
||||
private void setPriceForListener(double oldPrice, double newPrice) {
|
||||
oldPriceListener = oldPrice;
|
||||
newPriceListener = newPrice;
|
||||
}
|
||||
|
||||
private void setPriceCheckListener(double newPrice, double expectedOldPrice, double expectedNewPrice) {
|
||||
// Oppdatere prisen
|
||||
this.oldPrice = this.newPrice;
|
||||
this.newPrice = newPrice;
|
||||
stock.setPrice(newPrice);
|
||||
|
||||
// Sjekke at lytter har mottatt endring
|
||||
Assertions.assertEquals(expectedOldPrice, this.oldPriceListener, "Teste gammel pris for lytter etter å ha oppdatert pris fra " + oldPrice + " til " + newPrice);
|
||||
Assertions.assertEquals(expectedNewPrice, this.newPriceListener, "Teste ny pris for lytter etter å ha oppdatert pris fra " + oldPrice + " til " + newPrice);
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
public void setup() {
|
||||
stock = new Stock("APPL", 110.0);
|
||||
oldPrice = 0.0; newPrice = 110.0;
|
||||
oldPriceListener = 0.0; newPriceListener = 0.0;
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Teste kontruktør")
|
||||
public void testConstructor() {
|
||||
Assertions.assertEquals("APPL", stock.getTicker(), "Teste ticker");
|
||||
Assertions.assertEquals(110.0, stock.getPrice(), "Teste aksjeprisen");
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Negativ aksjepris gir feilmelding")
|
||||
public void testSetNegativePrice() {
|
||||
Assertions.assertThrows(IllegalArgumentException.class, () -> {
|
||||
stock.setPrice(-20.0);
|
||||
}, "Teste å sette negativ aksjepris");
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Aksjepris lik null gir feilmelding")
|
||||
public void testSetZeroPrice() {
|
||||
Assertions.assertThrows(IllegalArgumentException.class, () -> {
|
||||
stock.setPrice(0);
|
||||
}, "Teste å sette aksjepris lik null");
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Legge til lytter")
|
||||
public void testStockListener() {
|
||||
StockListener listener = (Stock stock, double oldPrice, double newPrice) -> setPriceForListener(oldPrice, newPrice);
|
||||
stock.addStockListener(listener);
|
||||
|
||||
setPriceCheckListener(118.0, 110.0, 118.0);
|
||||
Assertions.assertEquals(118.0, stock.getPrice(), "Teste aksjepris etter å ha oppdatert pris");
|
||||
|
||||
setPriceCheckListener(121.0, 118.0, 121.0);
|
||||
Assertions.assertEquals(121.0, stock.getPrice(), "Teste aksjepris etter å ha oppdatert pris 2 ganger");
|
||||
}
|
||||
}
|