Add missing loop detection tests

Adds tests related to symlink loop detection that were missed in
previous CLs related to making FSTestOSWrapper symlink-aware.

Bug: 436025865
Change-Id: Idb5181c0e95ce27f8565ecd0d07320034a6100ab
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/276601
Reviewed-by: Ryan Harrison <rharrison@chromium.org>
Commit-Queue: Brian Sheedy <bsheedy@google.com>
diff --git a/tools/src/oswrapper/fstestoswrapper_test.go b/tools/src/oswrapper/fstestoswrapper_test.go
index 6cada60..fc124be 100644
--- a/tools/src/oswrapper/fstestoswrapper_test.go
+++ b/tools/src/oswrapper/fstestoswrapper_test.go
@@ -808,6 +808,20 @@
 				wantErrIs: os.ErrExist,
 			},
 		},
+		{
+			name: "Open symlink loop",
+			path: filepath.Join(root, "loop1"),
+			flag: os.O_RDONLY,
+			setup: unittestSetup{
+				initialSymlinks: map[string]string{
+					filepath.Join(root, "loop1"): "loop2",
+					filepath.Join(root, "loop2"): "loop1",
+				},
+			},
+			expectedError: expectedError{
+				wantErrIs: syscall.ELOOP,
+			},
+		},
 	}
 
 	for _, tc := range tests {
@@ -1032,6 +1046,17 @@
 			path: "link",
 			flag: os.O_WRONLY | os.O_CREATE | os.O_EXCL,
 		},
+		{
+			name: "Open symlink loop",
+			setup: matchesRealSetup{unittestSetup{
+				initialSymlinks: map[string]string{
+					"loop1": "loop2",
+					"loop2": "loop1",
+				},
+			}},
+			path: "loop1",
+			flag: os.O_RDONLY,
+		},
 	}
 
 	for _, tc := range tests {
@@ -1319,6 +1344,19 @@
 				wantErrIs: os.ErrNotExist,
 			},
 		},
+		{
+			name: "Read symlink loop",
+			path: filepath.Join(root, "loop1"),
+			setup: unittestSetup{
+				initialSymlinks: map[string]string{
+					filepath.Join(root, "loop1"): "loop2",
+					filepath.Join(root, "loop2"): "loop1",
+				},
+			},
+			expectedError: expectedError{
+				wantErrIs: syscall.ELOOP,
+			},
+		},
 	}
 
 	for _, tc := range tests {
@@ -1392,6 +1430,16 @@
 			}},
 			path: "broken_link",
 		},
+		{
+			name: "Read symlink loop",
+			setup: matchesRealSetup{unittestSetup{
+				initialSymlinks: map[string]string{
+					"loop1": "loop2",
+					"loop2": "loop1",
+				},
+			}},
+			path: "loop1",
+		},
 	}
 
 	for _, tc := range tests {
@@ -1496,6 +1544,19 @@
 				wantErrIs: os.ErrNotExist,
 			},
 		},
+		{
+			name: "ReadDir symlink loop",
+			path: filepath.Join(root, "loop1"),
+			setup: unittestSetup{
+				initialSymlinks: map[string]string{
+					filepath.Join(root, "loop1"): "loop2",
+					filepath.Join(root, "loop2"): "loop1",
+				},
+			},
+			expectedError: expectedError{
+				wantErrIs: syscall.ELOOP,
+			},
+		},
 	}
 
 	for _, tc := range tests {
@@ -1586,6 +1647,16 @@
 			}},
 			path: "broken_link",
 		},
+		{
+			name: "ReadDir symlink loop",
+			setup: matchesRealSetup{unittestSetup{
+				initialSymlinks: map[string]string{
+					"loop1": "loop2",
+					"loop2": "loop1",
+				},
+			}},
+			path: "loop1",
+		},
 	}
 
 	for _, tc := range tests {
@@ -1801,6 +1872,16 @@
 			}},
 			path: "broken_link",
 		},
+		{
+			name: "Stat symlink loop",
+			setup: matchesRealSetup{unittestSetup{
+				initialSymlinks: map[string]string{
+					"loop1": "loop2",
+					"loop2": "loop1",
+				},
+			}},
+			path: "loop1",
+		},
 	}
 
 	for _, tc := range tests {
@@ -3274,6 +3355,21 @@
 				wantErrMsg: "is a directory",
 			},
 		},
+		{
+			name: "Write to symlink loop",
+			path: filepath.Join(root, "loop1"),
+			setup: unittestSetup{
+				initialSymlinks: map[string]string{
+					filepath.Join(root, "loop1"): "loop2",
+					filepath.Join(root, "loop2"): "loop1",
+				},
+			},
+			content: []byte("fail"),
+			mode:    0666,
+			expectedError: expectedError{
+				wantErrIs: syscall.ELOOP,
+			},
+		},
 	}
 
 	for _, tc := range tests {
@@ -3386,6 +3482,17 @@
 			path:    "link_to_dir",
 			content: []byte("fail"),
 		},
+		{
+			name: "Write to symlink loop",
+			setup: matchesRealSetup{unittestSetup{
+				initialSymlinks: map[string]string{
+					"loop1": "loop2",
+					"loop2": "loop1",
+				},
+			}},
+			path:    "loop1",
+			content: []byte("fail"),
+		},
 	}
 
 	for _, tc := range tests {