Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
cs2-20wi
project08
Commits
0a900ed5
Commit
0a900ed5
authored
5 years ago
by
Adam Blank
Browse files
Options
Download
Email Patches
Plain Diff
Initial commit
parents
master
No related merge requests found
Pipeline
#28879
canceled with stage
Changes
83
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
tests/edu/caltech/cs2/project08/GraphTests.java
+213
-0
tests/edu/caltech/cs2/project08/GraphTests.java
tests/edu/caltech/cs2/project08/MarvelParser.java
+78
-0
tests/edu/caltech/cs2/project08/MarvelParser.java
tests/edu/caltech/cs2/project08/MarvelTests.java
+164
-0
tests/edu/caltech/cs2/project08/MarvelTests.java
with
455 additions
and
0 deletions
+455
-0
tests/edu/caltech/cs2/project08/GraphTests.java
0 → 100644
View file @
0a900ed5
package
edu.caltech.cs2.project08
;
import
java.time.Duration
;
import
java.util.HashSet
;
import
java.util.List
;
import
java.util.Set
;
import
edu.caltech.cs2.datastructures.Graph
;
import
edu.caltech.cs2.helpers.Inspection
;
import
edu.caltech.cs2.interfaces.IGraph
;
import
org.hamcrest.MatcherAssert
;
import
org.hamcrest.collection.IsIterableContainingInAnyOrder
;
import
org.junit.jupiter.api.DisplayName
;
import
org.junit.jupiter.api.Tag
;
import
org.junit.jupiter.api.Test
;
import
static
org
.
junit
.
jupiter
.
api
.
Assertions
.*;
@Tag
(
"C"
)
public
class
GraphTests
{
private
static
final
String
GRAPH_SOURCE
=
"src/edu/caltech/cs2/datastructures/Graph.java"
;
private
static
final
int
SIMPLE_OP_TIMEOUT_MS
=
300
;
private
static
final
int
MEDIUM_OP_TIMEOUT_MS
=
500
;
private
static
final
int
STRESS_OP_TIMEOUT_MS
=
2200
;
@DisplayName
(
"Does not use or import disallowed classes"
)
@Test
public
void
testForInvalidClasses
()
{
List
<
String
>
graphDisallow
=
List
.
of
(
"java\\.util\\.(?!Iterator)"
,
"java\\.io"
,
"java\\.lang\\.reflect"
);
Inspection
.
assertNoImportsOf
(
GRAPH_SOURCE
,
graphDisallow
);
Inspection
.
assertNoUsageOf
(
GRAPH_SOURCE
,
graphDisallow
);
}
@Test
public
void
emptyGraphTest
()
{
IGraph
<
String
,
String
>
g
=
new
Graph
<>();
assertTimeout
(
Duration
.
ofMillis
(
SIMPLE_OP_TIMEOUT_MS
),
()
->
assertEquals
(
0
,
g
.
vertices
().
size
(),
"Empty graph should have no vertices"
)
);
}
/**
* Ensure that we can create a small graph with some edges.
*/
@Test
public
void
secondCreateTest
()
{
IGraph
<
String
,
Integer
>
g
=
new
Graph
<>();
assertTimeout
(
Duration
.
ofMillis
(
SIMPLE_OP_TIMEOUT_MS
),
()
->
{
assertTrue
(
g
.
addVertex
(
"0"
),
"Should be able to add a vertex"
);
assertTrue
(
g
.
addVertex
(
"1"
),
"Should be able to add a vertex"
);
assertTrue
(
g
.
addVertex
(
"2"
),
"Should be able to add a vertex"
);
assertTrue
(
g
.
addVertex
(
"3"
),
"Should be able to add a vertex"
);
assertTrue
(
g
.
addEdge
(
"0"
,
"1"
,
2
),
"Should be able to add an edge"
);
assertTrue
(
g
.
addEdge
(
"2"
,
"1"
,
4
),
"Should be able to add an edge"
);
assertTrue
(
g
.
addEdge
(
"1"
,
"2"
,
3
),
"Should be able to add an edge"
);
assertTrue
(
g
.
addEdge
(
"1"
,
"3"
,
1
),
"Should be able to add an edge"
);
assertTrue
(
g
.
addEdge
(
"3"
,
"1"
,
-
1
),
"Should be able to add an edge"
);
assertEquals
(
g
.
vertices
().
size
(),
4
,
"Graph should have correct number of vertices"
);
assertEquals
(
2
,
(
int
)
g
.
adjacent
(
"0"
,
"1"
),
"Edges added should all be present"
);
assertEquals
(
4
,
(
int
)
g
.
adjacent
(
"2"
,
"1"
),
"Edges added should all be present"
);
assertEquals
(
3
,
(
int
)
g
.
adjacent
(
"1"
,
"2"
),
"Edges added should all be present"
);
assertEquals
(
1
,
(
int
)
g
.
adjacent
(
"1"
,
"3"
),
"Edges added should all be present"
);
assertEquals
((
int
)
g
.
adjacent
(
"3"
,
"1"
),
-
1
,
"Edges added should all be present"
);
});
}
@Test
public
void
addIllegalEdgeTest
()
{
// Test adding edge where neither src, dest exists
IGraph
<
String
,
Integer
>
g
=
new
Graph
<>();
assertThrows
(
IllegalArgumentException
.
class
,
()
->
g
.
addEdge
(
""
,
""
,
1
));
}
@Test
public
void
addIllegalEdgeTest2
()
{
// Test adding edge where dest does not exist
IGraph
<
String
,
Integer
>
g
=
new
Graph
<>();
assertTrue
(
g
.
addVertex
(
"0"
));
assertThrows
(
IllegalArgumentException
.
class
,
()
->
g
.
addEdge
(
"0"
,
""
,
1
));
}
@Test
public
void
addIllegalEdgeTest3
()
{
// Test adding edge where src does not exist
IGraph
<
String
,
Integer
>
g
=
new
Graph
<>();
assertTrue
(
g
.
addVertex
(
"0"
));
assertThrows
(
IllegalArgumentException
.
class
,
()
->
g
.
addEdge
(
""
,
"0"
,
1
));
}
@Test
public
void
simpleAddTest
()
{
assertTimeout
(
Duration
.
ofMillis
(
SIMPLE_OP_TIMEOUT_MS
),
()
->
{
IGraph
<
String
,
Integer
>
g
=
new
Graph
<>();
assertTrue
(
g
.
addVertex
(
"1"
),
"Should be able to add a vertex"
);
assertEquals
(
1
,
g
.
vertices
().
size
(),
"Should have correct number of vertices"
);
assertTrue
(
g
.
addVertex
(
"2"
),
"Should be able to add a vertex"
);
assertEquals
(
2
,
g
.
vertices
().
size
(),
"Should have correct number of vertices"
);
assertTrue
(
g
.
addVertex
(
"3"
),
"Should be able to add a vertex"
);
assertEquals
(
3
,
g
.
vertices
().
size
(),
"Should have correct number of vertices"
);
assertTrue
(
g
.
addEdge
(
"1"
,
"2"
,
5
),
"Should be able to add new edge"
);
assertFalse
(
g
.
addEdge
(
"1"
,
"2"
,
5
),
"Should not be able to add an existing edge"
);
assertFalse
(
g
.
addEdge
(
"1"
,
"2"
,
3
),
"Should not be able to add an existing edge"
);
assertTrue
(
g
.
addEdge
(
"2"
,
"1"
,
5
),
"Should be able to add new edge"
);
assertFalse
(
g
.
addEdge
(
"2"
,
"1"
,
5
),
"Should not be able to add an existing edge"
);
assertFalse
(
g
.
addEdge
(
"2"
,
"1"
,
3
),
"Should not be able to add an existing edge"
);
assertTrue
(
g
.
addEdge
(
"1"
,
"3"
,
5
),
"Should be able to add new edge"
);
assertFalse
(
g
.
addEdge
(
"1"
,
"3"
,
5
),
"Should not be able to add an existing edge"
);
assertFalse
(
g
.
addEdge
(
"1"
,
"3"
,
3
),
"Should not be able to add an existing edge"
);
assertNotNull
(
g
.
adjacent
(
"1"
,
"2"
),
"Edge should exist in the graph"
);
assertNotNull
(
g
.
adjacent
(
"2"
,
"1"
),
"Edge should exist in the graph"
);
assertNotNull
(
g
.
adjacent
(
"1"
,
"3"
),
"Edge should exist in the graph"
);
assertNull
(
g
.
adjacent
(
"2"
,
"3"
),
"Edge should not exist in graph"
);
assertNull
(
g
.
adjacent
(
"3"
,
"1"
),
"Edge should not exist in graph"
);
});
}
@Test
public
void
simpleRemoveTest
()
{
assertTimeout
(
Duration
.
ofMillis
(
SIMPLE_OP_TIMEOUT_MS
),
()
->
{
IGraph
<
String
,
Integer
>
g
=
new
Graph
<>();
assertTrue
(
g
.
addVertex
(
"1"
),
"Should be able to add vertex"
);
assertTrue
(
g
.
addVertex
(
"2"
),
"Should be able to add vertex"
);
assertTrue
(
g
.
addEdge
(
"1"
,
"2"
,
5
),
"Should be able to add edge"
);
assertEquals
(
5
,
(
int
)
g
.
adjacent
(
"1"
,
"2"
),
"Added edge should be present in graph"
);
assertTrue
(
g
.
removeEdge
(
"1"
,
"2"
),
"Should be able to remove an edge from the graph"
);
assertFalse
(
g
.
removeEdge
(
"1"
,
"2"
),
"Should not be able to remove already-removed edge"
);
});
}
@Test
public
void
creationTest
()
{
assertTimeout
(
Duration
.
ofMillis
(
MEDIUM_OP_TIMEOUT_MS
),
()
->
{
GraphMaker
.
graph1
();
GraphMaker
.
graph2Test
(
GraphMaker
.
graph2
(
100
),
100
);
GraphMaker
.
graph3Test
(
GraphMaker
.
graph3
(
100
),
100
);
GraphMaker
.
graph4Test
(
GraphMaker
.
graph4
(
100
),
100
);
GraphMaker
.
graph5Test
(
GraphMaker
.
graph5
(
100
),
100
);
});
}
/* Make sure that they test .equals, rather than ==, to determine
* if an edge is already there. */
@Test
public
void
equalsTest
()
{
IGraph
<
Integer
,
Integer
>
g
=
new
Graph
<>();
// Actually prevent the JVM from caching these values.
// This should be tested in the backing DSs anyway...
Integer
i1
=
1000
;
Integer
i2
=
1000
;
assertTrue
(
g
.
addVertex
(
i1
),
"Attempting to add missing vertex returned false"
);
assertFalse
(
g
.
addVertex
(
i2
),
"Attempting to add present vertex returned true"
);
}
@Test
public
void
adjacentStressTest
()
{
assertTimeout
(
Duration
.
ofMillis
(
STRESS_OP_TIMEOUT_MS
),
()
->
{
IGraph
<
Integer
,
Integer
>
g
=
GraphMaker
.
graph4
(
400
);
for
(
int
i
=
0
;
i
<
400
;
i
++)
for
(
int
j
=
0
;
j
<
400
;
j
++)
if
(
i
!=
j
)
assertNotNull
(
g
.
adjacent
(
i
,
j
),
"Edge should be present in the graph"
);
});
}
@Test
public
void
testNeighbors
()
{
assertTimeout
(
Duration
.
ofMillis
(
SIMPLE_OP_TIMEOUT_MS
),
()
->
{
IGraph
<
Integer
,
Integer
>
g
=
GraphMaker
.
graph3
(
10
);
Set
<
Integer
>
vertices
=
new
HashSet
<
Integer
>();
for
(
int
i
=
0
;
i
<
10
;
i
++)
{
MatcherAssert
.
assertThat
(
g
.
neighbors
(
i
),
IsIterableContainingInAnyOrder
.
containsInAnyOrder
(
vertices
.
toArray
()));
vertices
.
add
(
i
);
}
});
}
@Test
public
void
stringEdgeTest
()
{
assertTimeout
(
Duration
.
ofMillis
(
SIMPLE_OP_TIMEOUT_MS
),
()
->
{
IGraph
<
Integer
,
Integer
>
g
=
new
Graph
<>();
assertTrue
(
g
.
addVertex
(
1
),
"Should be able to add vertex"
);
assertTrue
(
g
.
addVertex
(
2
),
"Should be able to add vertex"
);
assertTrue
(
g
.
addVertex
(
3
),
"Should be able to add vertex"
);
assertTrue
(
g
.
addEdge
(
1
,
2
,
0
),
"Should be able to add edge"
);
assertTrue
(
g
.
addEdge
(
1
,
3
,
0
),
"Should be able to add edge"
);
assertTrue
(
g
.
addEdge
(
2
,
3
,
0
),
"Should be able to add edge"
);
assertNotNull
(
g
.
adjacent
(
1
,
2
),
"Added edge should be present in graph"
);
assertNotNull
(
g
.
adjacent
(
1
,
3
),
"Added edge should be present in graph"
);
assertNotNull
(
g
.
adjacent
(
2
,
3
),
"Added edge should be present in graph"
);
assertTrue
(
g
.
removeEdge
(
1
,
2
),
"Should be able to remove an edge from the graph"
);
assertFalse
(
g
.
removeEdge
(
1
,
2
),
"Should not be able to remove already-removed edge"
);
assertTrue
(
g
.
removeEdge
(
1
,
3
),
"Should be able to remove an edge from the graph"
);
assertFalse
(
g
.
removeEdge
(
1
,
3
),
"Should not be able to remove already-removed edge"
);
assertTrue
(
g
.
removeEdge
(
2
,
3
),
"Should be able to remove an edge from the graph"
);
assertFalse
(
g
.
removeEdge
(
2
,
3
),
"Should not be able to remove already-removed edge"
);
});
}
}
\ No newline at end of file
This diff is collapsed.
Click to expand it.
tests/edu/caltech/cs2/project08/MarvelParser.java
0 → 100644
View file @
0a900ed5
package
edu.caltech.cs2.project08
;
import
java.io.*
;
import
java.util.*
;
/**
* Parser utility to load the Marvel Comics dataset.
*/
public
class
MarvelParser
{
/**
* Reads the Marvel Universe dataset.
* Each line of the input file contains a character name and a comic
* book the character appeared in, separated by a tab character
*
* @param filename the file that will be read
* @param characters list in which all character names will be stored;
* typically empty when the routine is called
* @param books map from titles of comic books to characters that
* appear in them; typically empty when the routine is called
* @requires file is well-formed, with each line containing exactly two
* quote-delimited tokens separated by a tab, or else starting with
* a # symbol to indicate a comment line.
* @modifies characters, books
* @effects fills characters with a list of all unique character names
* @effects fills books with a map from each comic book to all characters
* appearing in it
*/
public
static
void
parseData
(
String
filename
,
Set
<
String
>
characters
,
Map
<
String
,
List
<
String
>>
books
)
throws
Exception
{
// Why does this method accept the Collections to be filled as
// parameters rather than making them a return value? To allows us to
// "return" two different Collections. If only one or neither Collection
// needs to be returned to the caller, feel free to rewrite this method
// without the parameters. Generally this is better style.
BufferedReader
reader
=
null
;
try
{
reader
=
new
BufferedReader
(
new
FileReader
(
filename
));
// Construct the collections of characters and books, one
// <character, book> pair at a time.
String
inputLine
;
while
((
inputLine
=
reader
.
readLine
())
!=
null
)
{
// Ignore comment lines.
if
(
inputLine
.
startsWith
(
"#"
))
{
continue
;
}
// Parse the data, stripping out quotation marks and throwing
// an exception for malformed lines.
inputLine
=
inputLine
.
replace
(
"\""
,
""
);
String
[]
tokens
=
inputLine
.
split
(
"\t"
);
if
(
tokens
.
length
!=
2
)
{
throw
new
Exception
(
"Line should contain exactly one tab: "
+
inputLine
);
}
String
character
=
tokens
[
0
];
String
book
=
tokens
[
1
];
// Add the parsed data to the character and book collections.
characters
.
add
(
character
);
if
(!
books
.
containsKey
(
book
))
{
books
.
put
(
book
,
new
ArrayList
<
String
>());
}
books
.
get
(
book
).
add
(
character
);
}
}
catch
(
IOException
e
)
{
System
.
err
.
println
(
e
.
toString
());
e
.
printStackTrace
(
System
.
err
);
}
finally
{
if
(
reader
!=
null
)
{
reader
.
close
();
}
}
}
}
This diff is collapsed.
Click to expand it.
tests/edu/caltech/cs2/project08/MarvelTests.java
0 → 100644
View file @
0a900ed5
package
edu.caltech.cs2.project08
;
import
edu.caltech.cs2.datastructures.Graph
;
import
org.hamcrest.MatcherAssert
;
import
org.hamcrest.collection.IsIterableContainingInAnyOrder
;
import
org.junit.jupiter.api.*
;
import
java.io.File
;
import
java.io.FileNotFoundException
;
import
java.time.Duration
;
import
java.util.*
;
import
static
org
.
junit
.
jupiter
.
api
.
Assertions
.*;
@Tag
(
"C"
)
public
class
MarvelTests
{
private
static
Graph
<
String
,
Integer
>
MARVEL_GRAPH
;
private
static
final
int
COMMON_TIMEOUT_MS
=
1500
;
@BeforeAll
public
static
void
populateMarvelGraph
()
{
MARVEL_GRAPH
=
new
Graph
<>();
Set
<
String
>
characters
=
new
HashSet
<>();
Map
<
String
,
List
<
String
>>
books
=
new
HashMap
<>();
try
{
MarvelParser
.
parseData
(
"data/marvel/marvel.tsv"
,
characters
,
books
);
}
catch
(
Exception
e
)
{
fail
(
"Could not read input file."
);
}
for
(
String
c
:
characters
)
{
MARVEL_GRAPH
.
addVertex
(
c
);
}
for
(
String
book
:
books
.
keySet
())
{
// This will add symmetric edges automatically - no need to add undirected edge
for
(
String
c1
:
books
.
get
(
book
))
{
for
(
String
c2
:
books
.
get
(
book
))
{
if
(!
c1
.
equals
(
c2
))
{
Integer
num
=
MARVEL_GRAPH
.
adjacent
(
c1
,
c2
);
if
(
num
==
null
)
{
num
=
0
;
}
MARVEL_GRAPH
.
addEdge
(
c1
,
c2
,
num
+
1
);
}
}
}
}
}
@Test
@Order
(
0
)
public
void
testSingletons
()
{
List
<
String
>
singletons
=
new
ArrayList
<>();
for
(
String
c
:
MARVEL_GRAPH
.
vertices
())
{
if
(
MARVEL_GRAPH
.
neighbors
(
c
).
isEmpty
())
{
singletons
.
add
(
c
);
}
}
loadAndMatch
(
singletons
,
"data/marvel/singletons_output"
);
}
@Test
@Order
(
1
)
public
void
testPopular
()
{
List
<
String
>
populars
=
new
ArrayList
<>();
for
(
String
c
:
MARVEL_GRAPH
.
vertices
())
{
if
(
MARVEL_GRAPH
.
neighbors
(
c
).
size
()
>
20
)
{
populars
.
add
(
c
);
}
}
loadAndMatch
(
populars
,
"data/marvel/popular_output"
);
}
@Test
@Order
(
2
)
public
void
testNoLoops
()
{
for
(
String
c
:
MARVEL_GRAPH
.
vertices
())
{
assertNull
(
MARVEL_GRAPH
.
adjacent
(
c
,
c
),
"There is a loop (self-edge) in the graph, when there should be none."
);
}
}
// THIS TEST MUST BE RUN LAST - IT HAS SIDE EFFECTS ON THE STATIC GRAPH
@Test
@Order
(
3
)
public
void
testCommon
()
{
Assertions
.
assertTimeout
(
Duration
.
ofMillis
(
COMMON_TIMEOUT_MS
),
this
::
runCommon
);
}
public
void
runCommon
()
{
List
<
String
>
common
=
new
ArrayList
<>();
for
(
String
c1
:
MARVEL_GRAPH
.
vertices
())
{
Set
<
String
>
toRemove
=
new
HashSet
<>();
for
(
String
c2
:
MARVEL_GRAPH
.
neighbors
(
c1
))
{
Integer
edge
=
MARVEL_GRAPH
.
adjacent
(
c1
,
c2
);
Integer
symedge
=
MARVEL_GRAPH
.
adjacent
(
c2
,
c1
);
assertNotNull
(
edge
,
"An existing edge is null"
);
assertNotNull
(
symedge
,
"An existing edge is not symmetric in the graph"
);
toRemove
.
add
(
c2
);
// Sort here to ignore dependency on hashing order
if
(
edge
>
80
)
{
if
(
c1
.
compareTo
(
c2
)
<
0
)
{
common
.
add
(
c1
.
strip
()
+
" --"
+
edge
+
"-- "
+
c2
.
strip
());
}
else
{
common
.
add
(
c2
.
strip
()
+
" --"
+
edge
+
"-- "
+
c1
.
strip
());
}
}
}
// Process removals separately to prevent modifying neighbors while iterating on it
for
(
String
c2
:
toRemove
)
{
Integer
symedge
=
MARVEL_GRAPH
.
adjacent
(
c2
,
c1
);
MARVEL_GRAPH
.
removeEdge
(
c1
,
c2
);
assertNull
(
MARVEL_GRAPH
.
adjacent
(
c1
,
c2
),
"An edge is not null after removal"
);
assertEquals
(
symedge
,
MARVEL_GRAPH
.
adjacent
(
c2
,
c1
),
"An edge is null after its symmetric edge is removed"
);
MARVEL_GRAPH
.
removeEdge
(
c2
,
c1
);
assertNull
(
MARVEL_GRAPH
.
adjacent
(
c2
,
c1
),
"An edge is not null after removal"
);
}
assertTrue
(
MARVEL_GRAPH
.
neighbors
(
c1
).
isEmpty
(),
"After removing all of a vertex's neighbors, neighbors() is non-empty"
);
}
loadAndMatch
(
common
,
"data/marvel/common_output"
);
}
private
void
loadAndMatch
(
List
<
String
>
actual
,
String
filename
)
{
List
<
String
>
expected
=
new
ArrayList
<>();
Scanner
fr
=
null
;
try
{
fr
=
new
Scanner
(
new
File
(
filename
));
}
catch
(
FileNotFoundException
e
)
{
fail
(
"Could not open test results file."
);
}
while
(
fr
.
hasNextLine
())
{
String
l
=
fr
.
nextLine
();
// is edge - sort to remove dependence on directionality for correctness
if
(
l
.
contains
(
"--"
))
{
String
[]
spl
=
l
.
split
(
"--"
);
String
v1
=
spl
[
0
].
strip
();
String
v2
=
spl
[
2
].
strip
();
String
e
=
spl
[
1
];
if
(
v1
.
compareTo
(
v2
)
<
0
)
{
l
=
v1
+
" --"
+
e
+
"-- "
+
v2
;
}
else
{
l
=
v2
+
" --"
+
e
+
"-- "
+
v1
;
}
}
expected
.
add
(
l
);
}
MatcherAssert
.
assertThat
(
actual
,
IsIterableContainingInAnyOrder
.
containsInAnyOrder
(
expected
.
toArray
()));
}
}
\ No newline at end of file
This diff is collapsed.
Click to expand it.
Prev
1
2
3
4
5
Next
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment
Menu
Projects
Groups
Snippets
Help