Skip to content

Commit 4383d6e

Browse files
aksOpsclaude
andcommitted
test: add extended tests to boost JaCoCo coverage from 77% to 87%
Add 14 new test files covering CLI commands, config classes, detectors (config, csharp, frontend, generic, go, iac, java, rust, typescript), graph store, and model classes. This brings line coverage above the 85% minimum enforced by the JaCoCo check rule. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent d605e48 commit 4383d6e

14 files changed

Lines changed: 3583 additions & 0 deletions

src/test/java/io/github/randomcodespace/iq/cli/CliExtendedTest.java

Lines changed: 475 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package io.github.randomcodespace.iq.config;
2+
3+
import com.fasterxml.jackson.databind.ObjectMapper;
4+
import org.junit.jupiter.api.Test;
5+
6+
import static org.junit.jupiter.api.Assertions.assertNotNull;
7+
8+
class JacksonConfigTest {
9+
10+
@Test
11+
void objectMapperBeanIsCreated() {
12+
JacksonConfig config = new JacksonConfig();
13+
ObjectMapper mapper = config.objectMapper();
14+
assertNotNull(mapper);
15+
}
16+
17+
@Test
18+
void objectMapperCanSerializeEmptyBeans() throws Exception {
19+
JacksonConfig config = new JacksonConfig();
20+
ObjectMapper mapper = config.objectMapper();
21+
// This should not throw with FAIL_ON_EMPTY_BEANS disabled
22+
String json = mapper.writeValueAsString(new Object());
23+
assertNotNull(json);
24+
}
25+
}
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
package io.github.randomcodespace.iq.config;
2+
3+
import org.junit.jupiter.api.Test;
4+
import org.neo4j.driver.Values;
5+
6+
import java.util.HashMap;
7+
import java.util.Map;
8+
9+
import static org.junit.jupiter.api.Assertions.*;
10+
11+
class MapToJsonConverterTest {
12+
13+
private final MapToJsonConverter converter = new MapToJsonConverter();
14+
15+
@Test
16+
void writeNullReturnsEmptyJson() {
17+
var result = converter.write(null);
18+
assertEquals("{}", result.asString());
19+
}
20+
21+
@Test
22+
void writeEmptyMapReturnsEmptyJson() {
23+
var result = converter.write(Map.of());
24+
assertEquals("{}", result.asString());
25+
}
26+
27+
@Test
28+
void writePopulatedMapReturnsJson() {
29+
Map<String, Object> map = new HashMap<>();
30+
map.put("key", "value");
31+
map.put("count", 42);
32+
var result = converter.write(map);
33+
String json = result.asString();
34+
assertTrue(json.contains("\"key\""));
35+
assertTrue(json.contains("\"value\""));
36+
assertTrue(json.contains("42"));
37+
}
38+
39+
@Test
40+
void readNullReturnsEmptyMap() {
41+
var result = converter.read(null);
42+
assertNotNull(result);
43+
assertTrue(result.isEmpty());
44+
}
45+
46+
@Test
47+
void readNullValueReturnsEmptyMap() {
48+
var result = converter.read(Values.NULL);
49+
assertNotNull(result);
50+
assertTrue(result.isEmpty());
51+
}
52+
53+
@Test
54+
void readValidJsonReturnsMap() {
55+
var result = converter.read(Values.value("{\"name\":\"test\",\"count\":5}"));
56+
assertEquals("test", result.get("name"));
57+
assertEquals(5, result.get("count"));
58+
}
59+
60+
@Test
61+
void readInvalidJsonReturnsEmptyMap() {
62+
var result = converter.read(Values.value("not-json"));
63+
assertNotNull(result);
64+
assertTrue(result.isEmpty());
65+
}
66+
67+
@Test
68+
void roundTrip() {
69+
Map<String, Object> original = new HashMap<>();
70+
original.put("framework", "spring");
71+
original.put("version", 3);
72+
73+
var written = converter.write(original);
74+
var readBack = converter.read(written);
75+
76+
assertEquals("spring", readBack.get("framework"));
77+
assertEquals(3, readBack.get("version"));
78+
}
79+
}
Lines changed: 234 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,234 @@
1+
package io.github.randomcodespace.iq.detector.config;
2+
3+
import io.github.randomcodespace.iq.detector.DetectorContext;
4+
import io.github.randomcodespace.iq.detector.DetectorTestUtils;
5+
import io.github.randomcodespace.iq.model.NodeKind;
6+
import org.junit.jupiter.api.Nested;
7+
import org.junit.jupiter.api.Test;
8+
9+
import java.util.HashMap;
10+
import java.util.List;
11+
import java.util.Map;
12+
13+
import static org.junit.jupiter.api.Assertions.*;
14+
15+
class ConfigDetectorsExtendedTest {
16+
17+
// ==================== DockerComposeDetector ====================
18+
@Nested
19+
class DockerComposeExtended {
20+
private final DockerComposeDetector d = new DockerComposeDetector();
21+
22+
@Test
23+
void detectsServicesWithNetworksAndVolumes() {
24+
Map<String, Object> parsed = Map.of("type", "yaml", "data", Map.of(
25+
"services", Map.of(
26+
"web", Map.of("image", "nginx:latest", "ports", List.of("80:80"),
27+
"depends_on", List.of("api"), "networks", List.of("frontend")),
28+
"api", Map.of("build", "./api", "depends_on", List.of("db"),
29+
"environment", List.of("DB_HOST=db")),
30+
"db", Map.of("image", "postgres:15", "volumes", List.of("pgdata:/var/lib/postgresql/data"))
31+
),
32+
"networks", Map.of("frontend", Map.of()),
33+
"volumes", Map.of("pgdata", Map.of())
34+
));
35+
var ctx = new DetectorContext("docker-compose.yml", "yaml", "", parsed, null);
36+
var r = d.detect(ctx);
37+
assertTrue(r.nodes().size() >= 3);
38+
assertFalse(r.edges().isEmpty());
39+
}
40+
41+
@Test
42+
void detectsServiceWithBuildContext() {
43+
Map<String, Object> parsed = Map.of("type", "yaml", "data", Map.of(
44+
"services", Map.of(
45+
"app", Map.of("build", Map.of("context", ".", "dockerfile", "Dockerfile.prod"),
46+
"ports", List.of("3000:3000")),
47+
"worker", Map.of("build", "./worker", "command", "python worker.py")
48+
)
49+
));
50+
var ctx = new DetectorContext("docker-compose.yml", "yaml", "", parsed, null);
51+
var r = d.detect(ctx);
52+
assertTrue(r.nodes().size() >= 2);
53+
}
54+
}
55+
56+
// ==================== CloudFormationDetector ====================
57+
@Nested
58+
class CloudFormationExtended {
59+
private final CloudFormationDetector d = new CloudFormationDetector();
60+
61+
@Test
62+
void detectsMultipleResourceTypes() {
63+
Map<String, Object> resources = new HashMap<>();
64+
resources.put("WebServer", Map.of("Type", "AWS::EC2::Instance",
65+
"Properties", Map.of("InstanceType", "t3.micro")));
66+
resources.put("AppBucket", Map.of("Type", "AWS::S3::Bucket",
67+
"Properties", Map.of("BucketName", "my-app")));
68+
resources.put("Lambda", Map.of("Type", "AWS::Lambda::Function",
69+
"Properties", Map.of("Runtime", "python3.11")));
70+
resources.put("UserTable", Map.of("Type", "AWS::DynamoDB::Table",
71+
"Properties", Map.of("TableName", "users")));
72+
73+
Map<String, Object> parsed = Map.of("type", "yaml", "data", Map.of(
74+
"AWSTemplateFormatVersion", "2010-09-09",
75+
"Resources", resources
76+
));
77+
var ctx = new DetectorContext("template.yml", "yaml", "", parsed, null);
78+
var r = d.detect(ctx);
79+
assertTrue(r.nodes().size() >= 4);
80+
}
81+
82+
@Test
83+
void detectsWithOutputsAndParameters() {
84+
Map<String, Object> parsed = Map.of("type", "yaml", "data", Map.of(
85+
"AWSTemplateFormatVersion", "2010-09-09",
86+
"Parameters", Map.of("Environment", Map.of("Type", "String", "Default", "dev")),
87+
"Resources", Map.of("VPC", Map.of("Type", "AWS::EC2::VPC",
88+
"Properties", Map.of("CidrBlock", "10.0.0.0/16"))),
89+
"Outputs", Map.of("VpcId", Map.of("Value", "!Ref VPC"))
90+
));
91+
var ctx = new DetectorContext("template.yml", "yaml", "", parsed, null);
92+
var r = d.detect(ctx);
93+
assertFalse(r.nodes().isEmpty());
94+
}
95+
}
96+
97+
// ==================== GitLabCiDetector ====================
98+
@Nested
99+
class GitLabCiExtended {
100+
private final GitLabCiDetector d = new GitLabCiDetector();
101+
102+
@Test
103+
void detectsJobsWithStages() {
104+
Map<String, Object> data = new HashMap<>();
105+
data.put("stages", List.of("build", "test", "deploy"));
106+
data.put("build_job", Map.of("stage", "build", "script", List.of("mvn package")));
107+
data.put("test_job", Map.of("stage", "test", "script", List.of("mvn test"),
108+
"needs", List.of("build_job")));
109+
data.put("deploy_prod", Map.of("stage", "deploy", "script", List.of("kubectl apply -f k8s/"),
110+
"when", "manual"));
111+
112+
Map<String, Object> parsed = Map.of("type", "yaml", "data", data);
113+
var ctx = new DetectorContext(".gitlab-ci.yml", "yaml", "", parsed, null);
114+
var r = d.detect(ctx);
115+
assertTrue(r.nodes().size() >= 3);
116+
}
117+
118+
@Test
119+
void detectsIncludesAndVariables() {
120+
Map<String, Object> data = new HashMap<>();
121+
data.put("include", List.of(
122+
Map.of("template", "Security/SAST.gitlab-ci.yml")
123+
));
124+
data.put("variables", Map.of("DOCKER_HOST", "tcp://docker:2376"));
125+
data.put("build", Map.of("stage", "build", "image", "maven:3.9",
126+
"script", List.of("mvn clean install")));
127+
128+
Map<String, Object> parsed = Map.of("type", "yaml", "data", data);
129+
var ctx = new DetectorContext(".gitlab-ci.yml", "yaml", "", parsed, null);
130+
var r = d.detect(ctx);
131+
assertFalse(r.nodes().isEmpty());
132+
}
133+
}
134+
135+
// ==================== KubernetesDetector ====================
136+
@Nested
137+
class KubernetesExtended {
138+
private final KubernetesDetector d = new KubernetesDetector();
139+
140+
@Test
141+
void detectsDeployment() {
142+
Map<String, Object> parsed = Map.of("type", "yaml", "data", Map.of(
143+
"apiVersion", "apps/v1",
144+
"kind", "Deployment",
145+
"metadata", Map.of("name", "web-app", "namespace", "production"),
146+
"spec", Map.of("replicas", 3,
147+
"selector", Map.of("matchLabels", Map.of("app", "web-app")))
148+
));
149+
var ctx = new DetectorContext("deployment.yml", "yaml", "", parsed, null);
150+
var r = d.detect(ctx);
151+
assertFalse(r.nodes().isEmpty());
152+
}
153+
154+
@Test
155+
void detectsService() {
156+
Map<String, Object> parsed = Map.of("type", "yaml", "data", Map.of(
157+
"apiVersion", "v1",
158+
"kind", "Service",
159+
"metadata", Map.of("name", "web-service"),
160+
"spec", Map.of("type", "LoadBalancer",
161+
"selector", Map.of("app", "web-app"),
162+
"ports", List.of(Map.of("port", 80, "targetPort", 8080)))
163+
));
164+
var ctx = new DetectorContext("service.yml", "yaml", "", parsed, null);
165+
var r = d.detect(ctx);
166+
assertFalse(r.nodes().isEmpty());
167+
}
168+
169+
@Test
170+
void detectsConfigMap() {
171+
Map<String, Object> parsed = Map.of("type", "yaml", "data", Map.of(
172+
"apiVersion", "v1",
173+
"kind", "ConfigMap",
174+
"metadata", Map.of("name", "app-config"),
175+
"data", Map.of("DATABASE_URL", "postgres://localhost/mydb")
176+
));
177+
var ctx = new DetectorContext("config.yml", "yaml", "", parsed, null);
178+
var r = d.detect(ctx);
179+
assertFalse(r.nodes().isEmpty());
180+
}
181+
182+
@Test
183+
void detectsStatefulSet() {
184+
Map<String, Object> parsed = Map.of("type", "yaml", "data", Map.of(
185+
"apiVersion", "apps/v1",
186+
"kind", "StatefulSet",
187+
"metadata", Map.of("name", "database"),
188+
"spec", Map.of("replicas", 3,
189+
"selector", Map.of("matchLabels", Map.of("app", "db")))
190+
));
191+
var ctx = new DetectorContext("statefulset.yml", "yaml", "", parsed, null);
192+
var r = d.detect(ctx);
193+
assertFalse(r.nodes().isEmpty());
194+
}
195+
}
196+
197+
// ==================== HelmChartDetector ====================
198+
@Nested
199+
class HelmChartExtended {
200+
private final HelmChartDetector d = new HelmChartDetector();
201+
202+
@Test
203+
void detectsChartWithDependencies() {
204+
Map<String, Object> parsed = Map.of("type", "yaml", "data", Map.of(
205+
"apiVersion", "v2",
206+
"name", "my-app",
207+
"version", "1.0.0",
208+
"type", "application",
209+
"dependencies", List.of(
210+
Map.of("name", "postgresql", "version", "12.1.0",
211+
"repository", "https://charts.bitnami.com/bitnami"),
212+
Map.of("name", "redis", "version", "17.0.0",
213+
"repository", "https://charts.bitnami.com/bitnami")
214+
)
215+
));
216+
var ctx = new DetectorContext("Chart.yaml", "yaml", "", parsed, null);
217+
var r = d.detect(ctx);
218+
assertFalse(r.nodes().isEmpty());
219+
}
220+
221+
@Test
222+
void detectsValuesYaml() {
223+
Map<String, Object> parsed = Map.of("type", "yaml", "data", Map.of(
224+
"replicaCount", 3,
225+
"image", Map.of("repository", "myapp", "tag", "latest"),
226+
"service", Map.of("type", "ClusterIP", "port", 80)
227+
));
228+
// values.yaml must be under charts/ or helm/ directory
229+
var ctx = new DetectorContext("helm/myapp/values.yaml", "yaml", "", parsed, null);
230+
var r = d.detect(ctx);
231+
assertFalse(r.nodes().isEmpty());
232+
}
233+
}
234+
}

0 commit comments

Comments
 (0)