Skip to content

Commit 2faa8b1

Browse files
authored
feat: adds toby's custom classes (#570)
* feat(lesson-16): add Status enum * feat(lesson-16): add custom exception InvalidOrderOperationException * test(lesson-16): TDD tests for VideoProject custom type * feat(lesson-16): implement VideoProject (enum, collection, constructor, loop, conditionals, custom exception) * style(lesson-16): apply Spotless formatting to Lesson 16 files
1 parent bba6ec1 commit 2faa8b1

File tree

4 files changed

+163
-0
lines changed

4 files changed

+163
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package com.codedifferently.lesson16.tobyevans;
2+
3+
public class InvalidOrderOperationException extends RuntimeException {
4+
public InvalidOrderOperationException(String message) {
5+
super(message);
6+
}
7+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package com.codedifferently.lesson16.tobyevans;
2+
3+
public enum Status {
4+
PENDING,
5+
PAID,
6+
CANCELLED
7+
}
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
package com.codedifferently.lesson16.tobyevans;
2+
3+
import java.util.ArrayList;
4+
import java.util.List;
5+
6+
public class VideoProject {
7+
private String ownerName;
8+
private List<String> clips;
9+
private int totalSeconds;
10+
private Status status;
11+
private boolean monetized;
12+
private int clipCount;
13+
14+
public VideoProject(String ownerName, boolean monetized) {
15+
this.ownerName = ownerName;
16+
this.monetized = monetized;
17+
this.clips = new ArrayList<>();
18+
this.totalSeconds = 0;
19+
this.status = Status.PENDING;
20+
this.clipCount = 0;
21+
}
22+
23+
public void addClip(String name, int seconds) {
24+
if (name == null || name.isEmpty() || seconds < 0) {
25+
throw new InvalidOrderOperationException("Invalid clip");
26+
}
27+
clips.add(name);
28+
totalSeconds += seconds;
29+
clipCount = clips.size();
30+
}
31+
32+
public void trim(int seconds) {
33+
if (seconds < 0 || seconds > totalSeconds) {
34+
throw new InvalidOrderOperationException("Trim out of range");
35+
}
36+
totalSeconds -= seconds;
37+
}
38+
39+
public void publish() {
40+
if (status != Status.PENDING) {
41+
throw new InvalidOrderOperationException("Only pending can publish");
42+
}
43+
status = Status.PAID;
44+
}
45+
46+
public void cancel() {
47+
if (status == Status.PAID) {
48+
throw new InvalidOrderOperationException("Cannot cancel after publish");
49+
}
50+
status = Status.CANCELLED;
51+
}
52+
53+
public String getSummary() {
54+
StringBuilder sb = new StringBuilder();
55+
sb.append("VideoProject{owner=")
56+
.append(ownerName)
57+
.append(", status=")
58+
.append(status)
59+
.append(", clips=[");
60+
for (int i = 0; i < clips.size(); i++) {
61+
sb.append(clips.get(i));
62+
if (i < clips.size() - 1) sb.append(",");
63+
}
64+
sb.append("], totalSeconds=")
65+
.append(totalSeconds)
66+
.append(", monetized=")
67+
.append(monetized)
68+
.append("}");
69+
return sb.toString();
70+
}
71+
72+
public String getOwnerName() {
73+
return ownerName;
74+
}
75+
76+
public int getClipCount() {
77+
return clipCount;
78+
}
79+
80+
public int getTotalSeconds() {
81+
return totalSeconds;
82+
}
83+
84+
public Status getStatus() {
85+
return status;
86+
}
87+
88+
public boolean isMonetized() {
89+
return monetized;
90+
}
91+
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
package com.codedifferently.lesson16.tobyevans;
2+
3+
import static org.junit.jupiter.api.Assertions.*;
4+
5+
import org.junit.jupiter.api.Test;
6+
7+
public class VideoProjectTest {
8+
@Test
9+
void addClip_increasesCountAndDuration() {
10+
VideoProject v = new VideoProject("Toby", true);
11+
v.addClip("Intro", 10);
12+
v.addClip("Main", 20);
13+
assertEquals(2, v.getClipCount());
14+
assertEquals(30, v.getTotalSeconds());
15+
}
16+
17+
@Test
18+
void trim_reducesDuration() {
19+
VideoProject v = new VideoProject("Toby", false);
20+
v.addClip("A", 50);
21+
v.trim(10);
22+
assertEquals(40, v.getTotalSeconds());
23+
}
24+
25+
@Test
26+
void trim_tooMuch_throws() {
27+
VideoProject v = new VideoProject("Toby", false);
28+
v.addClip("A", 30);
29+
assertThrows(InvalidOrderOperationException.class, () -> v.trim(40));
30+
}
31+
32+
@Test
33+
void publish_changesStatus() {
34+
VideoProject v = new VideoProject("Toby", true);
35+
assertEquals(Status.PENDING, v.getStatus());
36+
v.publish();
37+
assertEquals(Status.PAID, v.getStatus());
38+
}
39+
40+
@Test
41+
void getSummary_containsClipsAndStatus() {
42+
VideoProject v = new VideoProject("Toby", true);
43+
v.addClip("X", 5);
44+
v.addClip("Y", 7);
45+
String s = v.getSummary();
46+
assertTrue(s.contains("X"));
47+
assertTrue(s.contains("Y"));
48+
assertTrue(s.toLowerCase().contains("status"));
49+
}
50+
51+
@Test
52+
void cancel_afterPublish_throws() {
53+
VideoProject v = new VideoProject("Toby", false);
54+
v.addClip("A", 10);
55+
v.publish();
56+
assertThrows(InvalidOrderOperationException.class, v::cancel);
57+
}
58+
}

0 commit comments

Comments
 (0)