mirror of
https://github.com/wagoodman/dive
synced 2026-03-14 14:25:50 +01:00
feat: enhance filetree pane interaction and add tests
- Improved mouse event handling in the filetree pane to correctly account for content offsets, ensuring proper scrolling and item selection. - Added comprehensive unit tests for the filetree pane, covering various states including empty tree, tree with items, focused state, and different dimensions. - Updated tree traversal logic to improve visual representation of nodes. - Introduced new test utilities for loading test image data and managing layout messages. - Added snapshot tests for image and layers panes to ensure consistent rendering across different states.
This commit is contained in:
parent
76b8f2034f
commit
83a648b3ef
14 changed files with 1564 additions and 19 deletions
134
AGENTS.md
Normal file
134
AGENTS.md
Normal file
|
|
@ -0,0 +1,134 @@
|
|||
# AGENTS.md
|
||||
|
||||
Инструкции для AI агентов, работающих с этим репозиторием.
|
||||
|
||||
## 🔥 КРИТИЧЕСКИ ВАЖНО: Snapshot тесты для UI
|
||||
|
||||
### Почему это важно
|
||||
|
||||
В этом проекте используется **snapshot тестирование** для UI компонентов (TUI). Это критически важно для предотвращения случайных изменений в визуальной части приложения.
|
||||
|
||||
**ВАЖНО:** Любые изменения в коде UI могут сломать верстку. Snapshot тесты гарантируют, что дизайн останется стабильным.
|
||||
|
||||
### Что делать ПЕРЕД внесением изменений в UI
|
||||
|
||||
**НЕОБХОДИМО** запустить snapshot тесты:
|
||||
|
||||
```bash
|
||||
# Запустить тесты файлового дерева (ОБЯЗАТЕЛЬНО)
|
||||
go test -v ./cmd/dive/cli/internal/ui/v2/panes/filetree
|
||||
|
||||
# Или все UI тесты сразу
|
||||
go test -v ./cmd/dive/cli/internal/ui/v2/panes/...
|
||||
```
|
||||
|
||||
### Что делать ПОСЛЕ внесения изменений в UI
|
||||
|
||||
Если вы изменили что-то в UI (стили, верстку, отступы и т.д.):
|
||||
|
||||
1. **ОБЯЗАТЕЛЬНО** обновите snapshot файлы:
|
||||
```bash
|
||||
task unit-update-snapshots
|
||||
```
|
||||
|
||||
2. **ПРОВЕРЬТЕ** что изменения визуально корректны:
|
||||
```bash
|
||||
go test -v ./cmd/dive/cli/internal/ui/v2/panes/...
|
||||
```
|
||||
|
||||
3. **УБЕДИТЕЛЬНО** что все тесты проходят
|
||||
|
||||
### Правила работы с UI кодом
|
||||
|
||||
#### ✅ ДОПУСТИМЫЕ ИЗМЕНЕНИЯ:
|
||||
|
||||
- Изменение логики работы компонента (если визуально ничего не меняется)
|
||||
- Оптимизация производительности
|
||||
- Рефакторинг (если результат визуально идентичен)
|
||||
- Добавление новых фич (с обновлением snapshot)
|
||||
|
||||
#### ❌ ЗАПРЕЩЕНО:
|
||||
|
||||
- Вносить изменения в UI БЕЗ запуска тестов
|
||||
- Игнорировать падающие snapshot тесты
|
||||
- Обновлять snapshot файлы "на всякий случай" (только если есть реальные изменения)
|
||||
|
||||
### Что делать если тесты падают
|
||||
|
||||
1. **Посмотрите на diff** - тест покажет что именно изменилось
|
||||
2. **Если изменениеEXPECTED** (вы намеренно меняли дизайн):
|
||||
- Обновите snapshot: `task unit-update-snapshots`
|
||||
3. **Если изменение НЕОЖИДАНО** (случайно сломали верстку):
|
||||
- Исправьте код
|
||||
- НЕ обновляйте snapshot файлы
|
||||
|
||||
### Структура snapshot тестов
|
||||
|
||||
```
|
||||
cmd/dive/cli/internal/ui/v2/panes/
|
||||
├── filetree/
|
||||
│ ├── pane.go
|
||||
│ ├── pane_test.go # Тесты
|
||||
│ └── __snapshots__/
|
||||
│ └── pane_test.snap # Golden файлы (эталоны)
|
||||
├── layers/
|
||||
│ ├── pane.go
|
||||
│ ├── pane_test.go
|
||||
│ └── __snapshots__/
|
||||
│ └── pane_test.snap
|
||||
├── details/
|
||||
│ ├── pane.go
|
||||
│ ├── pane_test.go
|
||||
│ └── __snapshots__/
|
||||
│ └── pane_test.snap
|
||||
└── image/
|
||||
├── pane.go
|
||||
├── pane_test.go
|
||||
└── __snapshots__/
|
||||
└── pane_test.snap
|
||||
```
|
||||
|
||||
### Дополнительные ресурсы
|
||||
|
||||
- Документация по snapshot тестам: `cmd/dive/cli/internal/ui/v2/panes/README.md`
|
||||
- [go-snaps documentation](https://github.com/gkampitakis/go-snaps)
|
||||
|
||||
---
|
||||
|
||||
## Другие важные инструкции
|
||||
|
||||
### Запуск всех тестов
|
||||
|
||||
```bash
|
||||
# Все unit тесты
|
||||
task unit
|
||||
|
||||
# Все тесты (unit + CLI)
|
||||
task test
|
||||
```
|
||||
|
||||
### Проверка качества кода
|
||||
|
||||
```bash
|
||||
# Форматирование
|
||||
task format
|
||||
|
||||
# Линтинг
|
||||
task lint
|
||||
|
||||
# Все проверки
|
||||
task pr-validations
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🚨 CHECKLIST для агента
|
||||
|
||||
Перед тем как сказать "я закончил", агент ДОЛЖЕН:
|
||||
|
||||
- [ ] Запустил `go test -v ./cmd/dive/cli/internal/ui/v2/panes/filetree`
|
||||
- [ ] Если тесты падают → понял почему (случайное изменение или реальное)
|
||||
- [ ] Если вносил изменения в UI → обновил snapshot файлы
|
||||
- [ ] Все тесты проходят SUCCESSFULLY
|
||||
|
||||
**НЕ ЗАБУДЬТЕ ПРО СNAPSHOT ТЕСТЫ! Это критически важно для стабильности UI!** 🎨
|
||||
|
|
@ -182,6 +182,16 @@ tasks:
|
|||
- cmd: ".github/scripts/coverage.py {{ .COVERAGE_THRESHOLD }} {{ .TMP_DIR }}/unit-coverage-details.txt"
|
||||
silent: true
|
||||
|
||||
unit-update-snapshots:
|
||||
desc: Update snapshot test golden files
|
||||
deps:
|
||||
- tmpdir
|
||||
vars:
|
||||
TEST_PKGS:
|
||||
sh: "go list ./... | grep -v '^github.com/wagoodman/dive/cmd/dive/cli$' | tr '\n' ' '"
|
||||
cmds:
|
||||
- "go test {{ .TEST_PKGS }} -update -v"
|
||||
|
||||
cli:
|
||||
desc: Run CLI tests
|
||||
cmds:
|
||||
|
|
|
|||
118
cmd/dive/cli/internal/ui/v2/panes/README.md
Normal file
118
cmd/dive/cli/internal/ui/v2/panes/README.md
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
# UI v2 Snapshot Testing
|
||||
|
||||
Этот каталог содержит snapshot тесты для UI компонентов v2. Snapshot тестирование гарантирует визуальную стабильность TUI компонентов.
|
||||
|
||||
## Зачем это нужно?
|
||||
|
||||
В TUI приложениях самая частая проблема — "я поправил отступ здесь, а развалилась верстка там". Snapshot тесты решают эту проблему:
|
||||
|
||||
1. **Гарантия визуальной стабильности**: Любое случайное изменение в отступах или верстке будет немедленно обнаружено
|
||||
2. **Документация**: Golden-файлы служат примерами того, как должен выглядеть компонент в разных состояниях
|
||||
3. **Безопасный рефакторинг**: Можно смело менять стили, зная что тесты покажут диффер
|
||||
|
||||
## Структура
|
||||
|
||||
```
|
||||
panes/
|
||||
├── filetree/
|
||||
│ ├── pane.go
|
||||
│ ├── pane_test.go # Snapshot тесты
|
||||
│ └── __snapshots__/
|
||||
│ └── pane_test.snap # Golden файлы
|
||||
├── layers/
|
||||
│ ├── pane.go
|
||||
│ ├── pane_test.go
|
||||
│ └── __snapshots__/
|
||||
│ └── pane_test.snap
|
||||
├── details/
|
||||
│ ├── pane.go
|
||||
│ ├── pane_test.go
|
||||
│ └── __snapshots__/
|
||||
│ └── pane_test.snap
|
||||
└── image/
|
||||
├── pane.go
|
||||
├── pane_test.go
|
||||
└── __snapshots__/
|
||||
└── pane_test.snap
|
||||
```
|
||||
|
||||
## Запуск тестов
|
||||
|
||||
### Запустить все snapshot тесты:
|
||||
```bash
|
||||
task unit
|
||||
```
|
||||
|
||||
### Обновить golden файлы (после изменения UI):
|
||||
```bash
|
||||
task unit-update-snapshots
|
||||
```
|
||||
|
||||
### Запустить тесты для конкретной панели:
|
||||
```bash
|
||||
go test -v ./cmd/dive/cli/internal/ui/v2/panes/filetree
|
||||
```
|
||||
|
||||
### Обновить snapshot для конкретной панели:
|
||||
```bash
|
||||
go test -v ./cmd/dive/cli/internal/ui/v2/panes/filetree -update
|
||||
```
|
||||
|
||||
## Написание snapshot тестов
|
||||
|
||||
Пример теста:
|
||||
|
||||
```go
|
||||
func TestPane_View_Focused(t *testing.T) {
|
||||
// 1. Подготовка тестовых данных
|
||||
testData := testutils.LoadTestImage(t)
|
||||
|
||||
// 2. Создание компонента
|
||||
pane := New(testData.TreeVM)
|
||||
pane.SetSize(50, 20)
|
||||
|
||||
// 3. Изменение состояния
|
||||
pane.Update(FocusStateMsg{Focused: true})
|
||||
|
||||
// 4. Сравнение с эталоном
|
||||
view := pane.View()
|
||||
snaps.MatchSnapshot(t, view)
|
||||
}
|
||||
```
|
||||
|
||||
## Лучшие практики
|
||||
|
||||
1. **Тестируйте разные состояния**: Unfocused, Focused, Different Sizes, Different Data
|
||||
2. **Используйте описательные имена тестов**: `TestPane_View_Focused`, `TestPane_View_SmallWidth`
|
||||
3. **Не тестируйте каждую комбинацию**: Фокусируйтесь на важных edge cases
|
||||
4. **Обновляйте snapshot осознанно**: Каждый раз при обновлении проверяйте diff
|
||||
|
||||
## Когда обновлять golden файлы?
|
||||
|
||||
Обновляйте snapshot когда:
|
||||
- ✅ Вы намеренно меняете стиль или верстку
|
||||
- ✅ Вы добавляете новый фичу в UI
|
||||
- ✅ Вы рефакторите и результат визуально идентичен
|
||||
|
||||
НЕ обновляйте когда:
|
||||
- ❌ Вы случайно сломали верстку
|
||||
- ❌ Вы не понимаете почему изменился вывод
|
||||
- ❌ Тест падает на CI (это значит есть проблема)
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Тест падает с "Snapshot not found"
|
||||
Это нормально при первом запуске. Запустите с `-update` чтобы создать snapshot.
|
||||
|
||||
### Тест падает с "Snapshot mismatch"
|
||||
1. Посмотрите на diff в выводе теста
|
||||
2. Если изменение ожидаемое → запустите с `-update`
|
||||
3. Если нет → исправьте код
|
||||
|
||||
### Проблемы с путями к файлам
|
||||
Убедитесь что вы запускаете тесты из корня репозитория.
|
||||
|
||||
## Дополнительные ресурсы
|
||||
|
||||
- [go-snaps documentation](https://github.com/gkampitakis/go-snaps)
|
||||
- [Bubbletea testing best practices](https://github.com/charmbracelet/bubbletea/tree/master/tutorials)
|
||||
122
cmd/dive/cli/internal/ui/v2/panes/details/__snapshots__/pane_test.snap
Executable file
122
cmd/dive/cli/internal/ui/v2/panes/details/__snapshots__/pane_test.snap
Executable file
|
|
@ -0,0 +1,122 @@
|
|||
|
||||
[TestPane_View_NoLayer - 1]
|
||||
╭────────────────────────────────────────────────╮
|
||||
│Layer Details │
|
||||
│ │
|
||||
│No details │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
╰────────────────────────────────────────────────╯
|
||||
---
|
||||
|
||||
[TestPane_View_WithLayer - 1]
|
||||
╭──────────────────────────────────────────────────────────────────────────────╮
|
||||
│Layer Details │
|
||||
│ │
|
||||
│Tags: (unavailable) │
|
||||
│Id: 28cfe03618aa2e914e81fdd90345245c15f4478e35252c06ca52d238fd3cc694 │
|
||||
│Size: 1.1 MB │
|
||||
│Digest: sha256:23bc2b70b2014dec0ac22f27bb93e9babd08cdd6f1115d0c955b9ff22b38...│
|
||||
│Command: │
|
||||
│#(nop) ADD │
|
||||
│file:ce026b62356eec3ad1214f92be2c9dc063fe205bd5e600be3492c4dfb17148bd in / │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
╰──────────────────────────────────────────────────────────────────────────────╯
|
||||
---
|
||||
|
||||
[TestPane_View_Focused - 1]
|
||||
╭──────────────────────────────────────────────────────────────────────────────╮
|
||||
│Layer Details │
|
||||
│ │
|
||||
│Tags: (unavailable) │
|
||||
│Id: 28cfe03618aa2e914e81fdd90345245c15f4478e35252c06ca52d238fd3cc694 │
|
||||
│Size: 1.1 MB │
|
||||
│Digest: sha256:23bc2b70b2014dec0ac22f27bb93e9babd08cdd6f1115d0c955b9ff22b38...│
|
||||
│Command: │
|
||||
│#(nop) ADD │
|
||||
│file:ce026b62356eec3ad1214f92be2c9dc063fe205bd5e600be3492c4dfb17148bd in / │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
╰──────────────────────────────────────────────────────────────────────────────╯
|
||||
---
|
||||
|
||||
[TestPane_View_SmallWidth - 1]
|
||||
╭────────────────────────────╮
|
||||
│Layer Details │
|
||||
│ │
|
||||
│Tags: (unavailable) │
|
||||
│Id: │
|
||||
│28cfe03618aa2e914e81fdd90345│
|
||||
│245c15f4478e35252c06ca52d238│
|
||||
│fd3cc694 │
|
||||
│Size: 1.1 MB │
|
||||
│Digest: sha256:23bc2b70b2...│
|
||||
│Command: │
|
||||
│#(nop) ADD │
|
||||
│...e3492c4dfb17148bd in... │
|
||||
│ │
|
||||
╰────────────────────────────╯
|
||||
---
|
||||
|
||||
[TestPane_View_SmallHeight - 1]
|
||||
╭──────────────────────────────────────────────────────────────────────────────╮
|
||||
│Layer Details │
|
||||
│ │
|
||||
│Tags: (unavailable) │
|
||||
│Id: 28cfe03618aa2e914e81fdd90345245c15f4478e35252c06ca52d238fd3cc694 │
|
||||
╰──────────────────────────────────────────────────────────────────────────────╯
|
||||
---
|
||||
|
||||
[TestPane_View_LargeSize - 1]
|
||||
╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
|
||||
│Layer Details │
|
||||
│ │
|
||||
│Tags: (unavailable) │
|
||||
│Id: 28cfe03618aa2e914e81fdd90345245c15f4478e35252c06ca52d238fd3cc694 │
|
||||
│Size: 1.1 MB │
|
||||
│Digest: sha256:23bc2b70b2014dec0ac22f27bb93e9babd08cdd6f1115d0c955b9ff22b382f5a │
|
||||
│Command: │
|
||||
│#(nop) ADD file:ce026b62356eec3ad1214f92be2c9dc063fe205bd5e600be3492c4dfb17148bd in / │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
|
||||
---
|
||||
|
||||
[TestPane_Update_WithLayoutMsg - 1]
|
||||
╭────────────────────────────────────────────────╮
|
||||
│Layer Details │
|
||||
│ │
|
||||
│Tags: (unavailable) │
|
||||
│Id: │
|
||||
│28cfe03618aa2e914e81fdd90345245c15f4478e35252c06│
|
||||
│ca52d238fd3cc694 │
|
||||
│Size: 1.1 MB │
|
||||
│Digest: sha256:23bc2b70b2014dec0ac22f27bb93e9...│
|
||||
╰────────────────────────────────────────────────╯
|
||||
---
|
||||
164
cmd/dive/cli/internal/ui/v2/panes/details/pane_test.go
Normal file
164
cmd/dive/cli/internal/ui/v2/panes/details/pane_test.go
Normal file
|
|
@ -0,0 +1,164 @@
|
|||
package details
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/gkampitakis/go-snaps/snaps"
|
||||
|
||||
"github.com/wagoodman/dive/cmd/dive/cli/internal/ui/v2/testutils"
|
||||
"github.com/wagoodman/dive/dive/image"
|
||||
)
|
||||
|
||||
func TestPane_View_NoLayer(t *testing.T) {
|
||||
pane := New()
|
||||
pane.SetSize(50, 10)
|
||||
|
||||
view := pane.View()
|
||||
snaps.MatchSnapshot(t, view)
|
||||
}
|
||||
|
||||
func TestPane_View_WithLayer(t *testing.T) {
|
||||
// Load test image data
|
||||
testData := testutils.LoadTestImage(t)
|
||||
|
||||
// Get first layer
|
||||
if len(testData.Analysis.Layers) == 0 {
|
||||
t.Skip("No layers in test data")
|
||||
}
|
||||
|
||||
layer := testData.Analysis.Layers[0]
|
||||
|
||||
pane := New()
|
||||
pane.SetLayer(layer)
|
||||
pane.SetSize(80, 15)
|
||||
|
||||
view := pane.View()
|
||||
snaps.MatchSnapshot(t, view)
|
||||
}
|
||||
|
||||
func TestPane_View_Focused(t *testing.T) {
|
||||
// Load test image data
|
||||
testData := testutils.LoadTestImage(t)
|
||||
|
||||
// Get first layer
|
||||
if len(testData.Analysis.Layers) == 0 {
|
||||
t.Skip("No layers in test data")
|
||||
}
|
||||
|
||||
layer := testData.Analysis.Layers[0]
|
||||
|
||||
pane := New()
|
||||
pane.SetLayer(layer)
|
||||
pane.SetSize(80, 15)
|
||||
|
||||
// Send focus message
|
||||
updatedPane, _ := pane.Update(FocusStateMsg{Focused: true})
|
||||
|
||||
view := updatedPane.(Pane).View()
|
||||
snaps.MatchSnapshot(t, view)
|
||||
}
|
||||
|
||||
func TestPane_View_SmallWidth(t *testing.T) {
|
||||
// Load test image data
|
||||
testData := testutils.LoadTestImage(t)
|
||||
|
||||
// Get first layer
|
||||
if len(testData.Analysis.Layers) == 0 {
|
||||
t.Skip("No layers in test data")
|
||||
}
|
||||
|
||||
layer := testData.Analysis.Layers[0]
|
||||
|
||||
pane := New()
|
||||
pane.SetLayer(layer)
|
||||
pane.SetSize(30, 15) // Very narrow width
|
||||
|
||||
view := pane.View()
|
||||
snaps.MatchSnapshot(t, view)
|
||||
}
|
||||
|
||||
func TestPane_View_SmallHeight(t *testing.T) {
|
||||
// Load test image data
|
||||
testData := testutils.LoadTestImage(t)
|
||||
|
||||
// Get first layer
|
||||
if len(testData.Analysis.Layers) == 0 {
|
||||
t.Skip("No layers in test data")
|
||||
}
|
||||
|
||||
layer := testData.Analysis.Layers[0]
|
||||
|
||||
pane := New()
|
||||
pane.SetLayer(layer)
|
||||
pane.SetSize(80, 6) // Very short height
|
||||
|
||||
view := pane.View()
|
||||
snaps.MatchSnapshot(t, view)
|
||||
}
|
||||
|
||||
func TestPane_View_LargeSize(t *testing.T) {
|
||||
// Load test image data
|
||||
testData := testutils.LoadTestImage(t)
|
||||
|
||||
// Get first layer
|
||||
if len(testData.Analysis.Layers) == 0 {
|
||||
t.Skip("No layers in test data")
|
||||
}
|
||||
|
||||
layer := testData.Analysis.Layers[0]
|
||||
|
||||
pane := New()
|
||||
pane.SetLayer(layer)
|
||||
pane.SetSize(120, 30) // Large dimensions
|
||||
|
||||
view := pane.View()
|
||||
snaps.MatchSnapshot(t, view)
|
||||
}
|
||||
|
||||
func TestPane_View_LongCommand(t *testing.T) {
|
||||
// Load test image data
|
||||
testData := testutils.LoadTestImage(t)
|
||||
|
||||
// Find a layer with a long command
|
||||
var targetLayer *image.Layer
|
||||
for _, layer := range testData.Analysis.Layers {
|
||||
if len(layer.Command) > 100 {
|
||||
targetLayer = layer
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if targetLayer == nil {
|
||||
t.Skip("No layer with long command found")
|
||||
}
|
||||
|
||||
pane := New()
|
||||
pane.SetLayer(targetLayer)
|
||||
pane.SetSize(80, 15)
|
||||
|
||||
view := pane.View()
|
||||
snaps.MatchSnapshot(t, view)
|
||||
}
|
||||
|
||||
func TestPane_Update_WithLayoutMsg(t *testing.T) {
|
||||
// Load test image data
|
||||
testData := testutils.LoadTestImage(t)
|
||||
|
||||
// Get first layer
|
||||
if len(testData.Analysis.Layers) == 0 {
|
||||
t.Skip("No layers in test data")
|
||||
}
|
||||
|
||||
layer := testData.Analysis.Layers[0]
|
||||
|
||||
pane := New()
|
||||
pane.SetLayer(layer)
|
||||
|
||||
// Send layout message
|
||||
layoutMsg := testutils.TestLayout()
|
||||
updatedPane, _ := pane.Update(layoutMsg)
|
||||
|
||||
// Verify size was updated
|
||||
view := updatedPane.(Pane).View()
|
||||
snaps.MatchSnapshot(t, view)
|
||||
}
|
||||
203
cmd/dive/cli/internal/ui/v2/panes/filetree/__snapshots__/pane_test.snap
Executable file
203
cmd/dive/cli/internal/ui/v2/panes/filetree/__snapshots__/pane_test.snap
Executable file
|
|
@ -0,0 +1,203 @@
|
|||
|
||||
[TestPane_View_EmptyTree - 1]
|
||||
╭────────────────────────────────────────────────╮
|
||||
│Current Layer Contents │
|
||||
│ │
|
||||
│Name Size UID:GID Permissions│
|
||||
│No items. │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
╰────────────────────────────────────────────────╯
|
||||
---
|
||||
|
||||
[TestPane_View_WithTree - 1]
|
||||
╭────────────────────────────────────────────────╮
|
||||
│Current Layer Contents │
|
||||
│ │
|
||||
│Name Size UID:GID Permissions│
|
||||
│├─ bin - drwxr-xr-x│
|
||||
││ ├─ [ 1.0 MB - -rwxr-xr-x│
|
||||
││ ├─ [[ 0 B - -rwxr-xr-x│
|
||||
││ ├─ acpid 0 B - -rwxr-xr-x│
|
||||
││ ├─ add-shell 0 B - -rwxr-xr-x│
|
||||
││ ├─ addgroup 0 B - -rwxr-xr-x│
|
||||
││ ├─ adduser 0 B - -rwxr-xr-x│
|
||||
││ ├─ adjtimex 0 B - -rwxr-xr-x│
|
||||
││ ├─ ar 0 B - -rwxr-xr-x│
|
||||
││ ├─ arch 0 B - -rwxr-xr-x│
|
||||
││ ├─ arp 0 B - -rwxr-xr-x│
|
||||
││ ├─ arping 0 B - -rwxr-xr-x│
|
||||
││ ├─ ash 0 B - -rwxr-xr-x│
|
||||
││ ├─ awk 0 B - -rwxr-xr-x│
|
||||
││ ├─ base64 0 B - -rwxr-xr-x│
|
||||
╰────────────────────────────────────────────────╯
|
||||
---
|
||||
|
||||
[TestPane_View_Focused - 1]
|
||||
╭────────────────────────────────────────────────╮
|
||||
│Current Layer Contents │
|
||||
│ │
|
||||
│Name Size UID:GID Permissions│
|
||||
│├─ bin - drwxr-xr-x│
|
||||
││ ├─ [ 1.0 MB - -rwxr-xr-x│
|
||||
││ ├─ [[ 0 B - -rwxr-xr-x│
|
||||
││ ├─ acpid 0 B - -rwxr-xr-x│
|
||||
││ ├─ add-shell 0 B - -rwxr-xr-x│
|
||||
││ ├─ addgroup 0 B - -rwxr-xr-x│
|
||||
││ ├─ adduser 0 B - -rwxr-xr-x│
|
||||
││ ├─ adjtimex 0 B - -rwxr-xr-x│
|
||||
││ ├─ ar 0 B - -rwxr-xr-x│
|
||||
││ ├─ arch 0 B - -rwxr-xr-x│
|
||||
││ ├─ arp 0 B - -rwxr-xr-x│
|
||||
││ ├─ arping 0 B - -rwxr-xr-x│
|
||||
││ ├─ ash 0 B - -rwxr-xr-x│
|
||||
││ ├─ awk 0 B - -rwxr-xr-x│
|
||||
││ ├─ base64 0 B - -rwxr-xr-x│
|
||||
╰────────────────────────────────────────────────╯
|
||||
---
|
||||
|
||||
[TestPane_View_SmallWidth - 1]
|
||||
╭──────────────────────────────────╮
|
||||
│Current Layer Contents │
|
||||
│ │
|
||||
│Name Size UID:GID │
|
||||
│Permissions │
|
||||
│├─ bin - │
|
||||
│drwxr-xr-x │
|
||||
││ ├─ [ 1.0 MB - │
|
||||
│-rwxr-xr-x │
|
||||
││ ├─ [[ 0 B - │
|
||||
│-rwxr-xr-x │
|
||||
││ ├─ acpid 0 B │
|
||||
│- -rwxr-xr-x │
|
||||
││ ├─ add-shell 0 B │
|
||||
│- -rwxr-xr-x │
|
||||
││ ├─ addgroup 0 B │
|
||||
│- -rwxr-xr-x │
|
||||
││ ├─ adduser 0 B │
|
||||
│- -rwxr-xr-x │
|
||||
││ ├─ adjtimex 0 B │
|
||||
│- -rwxr-xr-x │
|
||||
││ ├─ ar 0 B - │
|
||||
│-rwxr-xr-x │
|
||||
││ ├─ arch 0 B │
|
||||
│- -rwxr-xr-x │
|
||||
││ ├─ arp 0 B │
|
||||
│- -rwxr-xr-x │
|
||||
││ ├─ arping 0 B │
|
||||
│- -rwxr-xr-x │
|
||||
││ ├─ ash 0 B │
|
||||
│- -rwxr-xr-x │
|
||||
││ ├─ awk 0 B │
|
||||
│- -rwxr-xr-x │
|
||||
││ ├─ base64 0 B │
|
||||
│- -rwxr-xr-x │
|
||||
╰──────────────────────────────────╯
|
||||
---
|
||||
|
||||
[TestPane_View_SmallHeight - 1]
|
||||
╭────────────────────────────────────────────────╮
|
||||
│Current Layer Contents │
|
||||
│ │
|
||||
│Name Size UID:GID Permissions│
|
||||
│├─ bin - drwxr-xr-x│
|
||||
││ ├─ [ 1.0 MB - -rwxr-xr-x│
|
||||
││ ├─ [[ 0 B - -rwxr-xr-x│
|
||||
╰────────────────────────────────────────────────╯
|
||||
---
|
||||
|
||||
[TestPane_View_LargeSize - 1]
|
||||
╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
|
||||
│Current Layer Contents │
|
||||
│ │
|
||||
│Name Size UID:GID Permissions│
|
||||
│├─ bin - drwxr-xr-x│
|
||||
││ ├─ [ 1.0 MB - -rwxr-xr-x│
|
||||
││ ├─ [[ 0 B - -rwxr-xr-x│
|
||||
││ ├─ acpid 0 B - -rwxr-xr-x│
|
||||
││ ├─ add-shell 0 B - -rwxr-xr-x│
|
||||
││ ├─ addgroup 0 B - -rwxr-xr-x│
|
||||
││ ├─ adduser 0 B - -rwxr-xr-x│
|
||||
││ ├─ adjtimex 0 B - -rwxr-xr-x│
|
||||
││ ├─ ar 0 B - -rwxr-xr-x│
|
||||
││ ├─ arch 0 B - -rwxr-xr-x│
|
||||
││ ├─ arp 0 B - -rwxr-xr-x│
|
||||
││ ├─ arping 0 B - -rwxr-xr-x│
|
||||
││ ├─ ash 0 B - -rwxr-xr-x│
|
||||
││ ├─ awk 0 B - -rwxr-xr-x│
|
||||
││ ├─ base64 0 B - -rwxr-xr-x│
|
||||
││ ├─ basename 0 B - -rwxr-xr-x│
|
||||
││ ├─ beep 0 B - -rwxr-xr-x│
|
||||
││ ├─ blkdiscard 0 B - -rwxr-xr-x│
|
||||
││ ├─ blkid 0 B - -rwxr-xr-x│
|
||||
││ ├─ blockdev 0 B - -rwxr-xr-x│
|
||||
││ ├─ bootchartd 0 B - -rwxr-xr-x│
|
||||
││ ├─ brctl 0 B - -rwxr-xr-x│
|
||||
││ ├─ bunzip2 0 B - -rwxr-xr-x│
|
||||
││ ├─ busybox 0 B - -rwxr-xr-x│
|
||||
││ ├─ bzcat 0 B - -rwxr-xr-x│
|
||||
││ ├─ bzip2 0 B - -rwxr-xr-x│
|
||||
││ ├─ cal 0 B - -rwxr-xr-x│
|
||||
││ ├─ cat 0 B - -rwxr-xr-x│
|
||||
││ ├─ chat 0 B - -rwxr-xr-x│
|
||||
││ ├─ chattr 0 B - -rwxr-xr-x│
|
||||
││ ├─ chgrp 0 B - -rwxr-xr-x│
|
||||
││ ├─ chmod 0 B - -rwxr-xr-x│
|
||||
││ ├─ chown 0 B - -rwxr-xr-x│
|
||||
││ ├─ chpasswd 0 B - -rwxr-xr-x│
|
||||
││ ├─ chpst 0 B - -rwxr-xr-x│
|
||||
╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
|
||||
---
|
||||
|
||||
[TestPane_Update_WithLayoutMsg - 1]
|
||||
╭────────────────────────────────────────────────╮
|
||||
│Current Layer Contents │
|
||||
│ │
|
||||
│Name Size UID:GID Permissions│
|
||||
│├─ bin - drwxr-xr-x│
|
||||
││ ├─ [ 1.0 MB - -rwxr-xr-x│
|
||||
││ ├─ [[ 0 B - -rwxr-xr-x│
|
||||
││ ├─ acpid 0 B - -rwxr-xr-x│
|
||||
││ ├─ add-shell 0 B - -rwxr-xr-x│
|
||||
││ ├─ addgroup 0 B - -rwxr-xr-x│
|
||||
││ ├─ adduser 0 B - -rwxr-xr-x│
|
||||
││ ├─ adjtimex 0 B - -rwxr-xr-x│
|
||||
││ ├─ ar 0 B - -rwxr-xr-x│
|
||||
││ ├─ arch 0 B - -rwxr-xr-x│
|
||||
╰────────────────────────────────────────────────╯
|
||||
---
|
||||
|
||||
[TestPane_Update_TreeNavigation - 1]
|
||||
╭────────────────────────────────────────────────╮
|
||||
│Current Layer Contents │
|
||||
│ │
|
||||
│Name Size UID:GID Permissions│
|
||||
│├─ bin - drwxr-xr-x│
|
||||
││ ├─ [ 1.0 MB - -rwxr-xr-x│
|
||||
││ ├─ [[ 0 B - -rwxr-xr-x│
|
||||
││ ├─ acpid 0 B - -rwxr-xr-x│
|
||||
││ ├─ add-shell 0 B - -rwxr-xr-x│
|
||||
││ ├─ addgroup 0 B - -rwxr-xr-x│
|
||||
││ ├─ adduser 0 B - -rwxr-xr-x│
|
||||
││ ├─ adjtimex 0 B - -rwxr-xr-x│
|
||||
││ ├─ ar 0 B - -rwxr-xr-x│
|
||||
││ ├─ arch 0 B - -rwxr-xr-x│
|
||||
││ ├─ arp 0 B - -rwxr-xr-x│
|
||||
││ ├─ arping 0 B - -rwxr-xr-x│
|
||||
││ ├─ ash 0 B - -rwxr-xr-x│
|
||||
││ ├─ awk 0 B - -rwxr-xr-x│
|
||||
││ ├─ base64 0 B - -rwxr-xr-x│
|
||||
╰────────────────────────────────────────────────╯
|
||||
---
|
||||
|
|
@ -128,31 +128,33 @@ func (p Pane) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|||
case common.LocalMouseMsg:
|
||||
// Handle mouse events manually since bubbles/list doesn't understand LocalMouseMsg
|
||||
if msg.Action == tea.MouseActionPress {
|
||||
// Content offsets relative to the panel:
|
||||
// Y: 1 (top border) + 1 (box title) + 1 (empty line) + 1 (table header) = 4
|
||||
// X: 1 (left border)
|
||||
const contentOffsetY = 4
|
||||
const contentOffsetX = 1
|
||||
|
||||
switch msg.Button {
|
||||
case tea.MouseButtonWheelUp, tea.MouseButtonWheelDown:
|
||||
// IMPORTANT: For scrolling, pass the ORIGINAL message (msg.MouseMsg)
|
||||
// directly to the list component. bubbles/list knows how to properly
|
||||
// scroll the viewport when it receives standard wheel events.
|
||||
// Using CursorUp/Down here was incorrect as they only move the cursor,
|
||||
// not the viewport.
|
||||
// CRITICAL FIX:
|
||||
// bubbles/list has Hit Test: if Y < 0 or Y > Height, event is ignored.
|
||||
// We must pass coordinates RELATIVE TO THE LIST ITSELF (accounting for offsets),
|
||||
// otherwise scroll only works at the top of the list.
|
||||
localMsg := msg.MouseMsg
|
||||
localMsg.X = msg.LocalX - contentOffsetX
|
||||
localMsg.Y = msg.LocalY - contentOffsetY
|
||||
|
||||
var cmd tea.Cmd
|
||||
p.list, cmd = p.list.Update(msg.MouseMsg)
|
||||
p.list, cmd = p.list.Update(localMsg)
|
||||
return p, cmd
|
||||
|
||||
case tea.MouseButtonLeft:
|
||||
// Calculate item index from Y coordinate
|
||||
// Content offset consists of:
|
||||
// 1 (top border) + 1 (box title) + 1 (empty line) + 1 (table header) = 4
|
||||
const contentOffsetY = 4
|
||||
|
||||
// Local Y coordinate within the list
|
||||
// For clicks, use the same Y offset logic
|
||||
clickY := msg.LocalY - contentOffsetY
|
||||
|
||||
// Ignore clicks above/below the list content
|
||||
// Ignore clicks on headers (negative coordinates relative to list)
|
||||
if clickY >= 0 {
|
||||
// Calculate absolute index of the item in the list
|
||||
// Start() returns the index of the first visible item
|
||||
// (p.list.Index() - p.list.Cursor()) is the index of the top item
|
||||
// Calculate absolute item index
|
||||
firstVisibleIndex := p.list.Index() - p.list.Cursor()
|
||||
targetIndex := firstVisibleIndex + clickY
|
||||
|
||||
|
|
@ -160,7 +162,6 @@ func (p Pane) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|||
if targetIndex >= 0 && targetIndex < len(p.list.Items()) {
|
||||
p.list.Select(targetIndex)
|
||||
// Click selects file and toggles folder
|
||||
// Send selection changed message and toggle command
|
||||
return p, tea.Batch(
|
||||
func() tea.Msg { return TreeSelectionChangedMsg{NodeIndex: targetIndex} },
|
||||
p.toggleCollapse(),
|
||||
|
|
|
|||
115
cmd/dive/cli/internal/ui/v2/panes/filetree/pane_test.go
Normal file
115
cmd/dive/cli/internal/ui/v2/panes/filetree/pane_test.go
Normal file
|
|
@ -0,0 +1,115 @@
|
|||
package filetree
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/gkampitakis/go-snaps/snaps"
|
||||
"github.com/stretchr/testify/require"
|
||||
tea "github.com/charmbracelet/bubbletea"
|
||||
|
||||
"github.com/wagoodman/dive/cmd/dive/cli/internal/ui/v2/testutils"
|
||||
)
|
||||
|
||||
func TestPane_View_EmptyTree(t *testing.T) {
|
||||
// Test with nil treeVM
|
||||
pane := New(nil)
|
||||
pane.SetSize(50, 20)
|
||||
|
||||
view := pane.View()
|
||||
snaps.MatchSnapshot(t, view)
|
||||
}
|
||||
|
||||
func TestPane_View_WithTree(t *testing.T) {
|
||||
// Load test image data
|
||||
testData := testutils.LoadTestImage(t)
|
||||
|
||||
pane := New(testData.TreeVM)
|
||||
pane.SetSize(50, 20)
|
||||
|
||||
// Initialize the pane
|
||||
cmd := pane.Init()
|
||||
require.Nil(t, cmd)
|
||||
|
||||
view := pane.View()
|
||||
snaps.MatchSnapshot(t, view)
|
||||
}
|
||||
|
||||
func TestPane_View_Focused(t *testing.T) {
|
||||
// Load test image data
|
||||
testData := testutils.LoadTestImage(t)
|
||||
|
||||
pane := New(testData.TreeVM)
|
||||
pane.SetSize(50, 20)
|
||||
|
||||
// Send focus message
|
||||
updatedPane, _ := pane.Update(FocusStateMsg{Focused: true})
|
||||
|
||||
view := updatedPane.(Pane).View()
|
||||
snaps.MatchSnapshot(t, view)
|
||||
}
|
||||
|
||||
func TestPane_View_SmallWidth(t *testing.T) {
|
||||
// Load test image data
|
||||
testData := testutils.LoadTestImage(t)
|
||||
|
||||
pane := New(testData.TreeVM)
|
||||
pane.SetSize(30, 20) // Very narrow width
|
||||
|
||||
view := pane.View()
|
||||
snaps.MatchSnapshot(t, view)
|
||||
}
|
||||
|
||||
func TestPane_View_SmallHeight(t *testing.T) {
|
||||
// Load test image data
|
||||
testData := testutils.LoadTestImage(t)
|
||||
|
||||
pane := New(testData.TreeVM)
|
||||
pane.SetSize(50, 8) // Very short height
|
||||
|
||||
view := pane.View()
|
||||
snaps.MatchSnapshot(t, view)
|
||||
}
|
||||
|
||||
func TestPane_View_LargeSize(t *testing.T) {
|
||||
// Load test image data
|
||||
testData := testutils.LoadTestImage(t)
|
||||
|
||||
pane := New(testData.TreeVM)
|
||||
pane.SetSize(120, 40) // Large dimensions
|
||||
|
||||
view := pane.View()
|
||||
snaps.MatchSnapshot(t, view)
|
||||
}
|
||||
|
||||
func TestPane_Update_WithLayoutMsg(t *testing.T) {
|
||||
// Load test image data
|
||||
testData := testutils.LoadTestImage(t)
|
||||
|
||||
pane := New(testData.TreeVM)
|
||||
|
||||
// Send layout message
|
||||
layoutMsg := testutils.TestLayout()
|
||||
updatedPane, _ := pane.Update(layoutMsg)
|
||||
|
||||
// Verify size was updated
|
||||
view := updatedPane.(Pane).View()
|
||||
snaps.MatchSnapshot(t, view)
|
||||
}
|
||||
|
||||
func TestPane_Update_TreeNavigation(t *testing.T) {
|
||||
// Load test image data
|
||||
testData := testutils.LoadTestImage(t)
|
||||
|
||||
pane := New(testData.TreeVM)
|
||||
pane.SetSize(50, 20)
|
||||
|
||||
// Focus the pane
|
||||
pane.Update(FocusStateMsg{Focused: true})
|
||||
|
||||
// Move down a few items
|
||||
pane.Update(tea.KeyMsg{Type: tea.KeyRunes, Runes: []rune{'j'}})
|
||||
pane.Update(tea.KeyMsg{Type: tea.KeyRunes, Runes: []rune{'j'}})
|
||||
|
||||
view := pane.View()
|
||||
snaps.MatchSnapshot(t, view)
|
||||
}
|
||||
|
|
@ -34,7 +34,7 @@ func CollectVisibleNodes(root *filetree.FileNode) []VisibleNode {
|
|||
if i == len(levels)-1 {
|
||||
// Current level (the node itself) - 2 chars
|
||||
if isLast {
|
||||
prefixBuilder.WriteString("└─") // Was "└── "
|
||||
prefixBuilder.WriteString("╰─") // Was "└── "
|
||||
} else {
|
||||
prefixBuilder.WriteString("├─") // Was "├── "
|
||||
}
|
||||
|
|
@ -77,7 +77,7 @@ func CollectVisibleNodes(root *filetree.FileNode) []VisibleNode {
|
|||
sortedChildren := SortChildren(root.Children)
|
||||
count := len(sortedChildren)
|
||||
for i, child := range sortedChildren {
|
||||
traverse(child, []bool{i == count - 1})
|
||||
traverse(child, []bool{i == count-1})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
161
cmd/dive/cli/internal/ui/v2/panes/image/__snapshots__/pane_test.snap
Executable file
161
cmd/dive/cli/internal/ui/v2/panes/image/__snapshots__/pane_test.snap
Executable file
|
|
@ -0,0 +1,161 @@
|
|||
|
||||
[TestPane_View_NoAnalysis - 1]
|
||||
╭──────────────────────────────────────────────────────────────────────────────╮
|
||||
│Image Details │
|
||||
│ │
|
||||
│No image data │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
╰──────────────────────────────────────────────────────────────────────────────╯
|
||||
---
|
||||
|
||||
[TestPane_View_WithAnalysis - 1]
|
||||
╭──────────────────────────────────────────────────────────────────────────────╮
|
||||
│Image Details │
|
||||
│ │
|
||||
│Image name: /Users/aslan/Documents/oss/dive/.data/test-docker-image.tar │
|
||||
│Total Image size: 1.2 MB │
|
||||
│Potential wasted space: 31.3 KB │
|
||||
│Image efficiency score: 98% │
|
||||
│Files > 0 KB total: 0 │
|
||||
│ │
|
||||
│Count Total Space Path │
|
||||
│2 6.3 KB /root/example/somefile3.txt │
|
||||
│2 12.5 KB /root/example/somefile1.txt │
|
||||
│2 12.5 KB /root/saved.txt │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
╰──────────────────────────────────────────────────────────────────────────────╯
|
||||
---
|
||||
|
||||
[TestPane_View_Focused - 1]
|
||||
╭──────────────────────────────────────────────────────────────────────────────╮
|
||||
│Image Details │
|
||||
│ │
|
||||
│Image name: /Users/aslan/Documents/oss/dive/.data/test-docker-image.tar │
|
||||
│Total Image size: 1.2 MB │
|
||||
│Potential wasted space: 31.3 KB │
|
||||
│Image efficiency score: 98% │
|
||||
│Files > 0 KB total: 0 │
|
||||
│ │
|
||||
│Count Total Space Path │
|
||||
│2 6.3 KB /root/example/somefile3.txt │
|
||||
│2 12.5 KB /root/example/somefile1.txt │
|
||||
│2 12.5 KB /root/saved.txt │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
╰──────────────────────────────────────────────────────────────────────────────╯
|
||||
---
|
||||
|
||||
[TestPane_View_SmallWidth - 1]
|
||||
╭──────────────────────────────────────╮
|
||||
│Image Details │
|
||||
│ │
|
||||
│Image name: /Users/aslan/Documents/oss│
|
||||
│Total Image size: 1.2 MB │
|
||||
│Potential wasted space: 31.3 KB │
|
||||
│Image efficiency score: 98% │
|
||||
│Files > 0 KB total: 0 │
|
||||
│ │
|
||||
│Count Total Space Path │
|
||||
│2 6.3 KB /root/example/so...│
|
||||
│2 12.5 KB /root/example/so...│
|
||||
│2 12.5 KB /root/saved.txt │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
╰──────────────────────────────────────╯
|
||||
---
|
||||
|
||||
[TestPane_View_SmallHeight - 1]
|
||||
╭──────────────────────────────────────────────────────────────────────────────╮
|
||||
│Image Details │
|
||||
│ │
|
||||
│Image name: /Users/aslan/Documents/oss/dive/.data/test-docker-image.tar │
|
||||
│Total Image size: 1.2 MB │
|
||||
│Potential wasted space: 31.3 KB │
|
||||
│Image efficiency score: 98% │
|
||||
╰──────────────────────────────────────────────────────────────────────────────╯
|
||||
---
|
||||
|
||||
[TestPane_View_LargeSize - 1]
|
||||
╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
|
||||
│Image Details │
|
||||
│ │
|
||||
│Image name: /Users/aslan/Documents/oss/dive/.data/test-docker-image.tar │
|
||||
│Total Image size: 1.2 MB │
|
||||
│Potential wasted space: 31.3 KB │
|
||||
│Image efficiency score: 98% │
|
||||
│Files > 0 KB total: 0 │
|
||||
│ │
|
||||
│Count Total Space Path │
|
||||
│2 6.3 KB /root/example/somefile3.txt │
|
||||
│2 12.5 KB /root/example/somefile1.txt │
|
||||
│2 12.5 KB /root/saved.txt │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
|
||||
---
|
||||
|
||||
[TestPane_Update_WithLayoutMsg - 1]
|
||||
╭────────────────────────────────────────────────╮
|
||||
│Image Details │
|
||||
│ │
|
||||
│Image name: /Users/aslan/Documents/oss/dive/.dat│
|
||||
│Total Image size: 1.2 MB │
|
||||
│Potential wasted space: 31.3 KB │
|
||||
│Image efficiency score: 98% │
|
||||
│Files > 0 KB total: 0 │
|
||||
│ │
|
||||
│Count Total Space Path │
|
||||
│2 6.3 KB /root/example/somefile3.txt │
|
||||
╰────────────────────────────────────────────────╯
|
||||
---
|
||||
96
cmd/dive/cli/internal/ui/v2/panes/image/pane_test.go
Normal file
96
cmd/dive/cli/internal/ui/v2/panes/image/pane_test.go
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
package image
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/gkampitakis/go-snaps/snaps"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/wagoodman/dive/cmd/dive/cli/internal/ui/v2/testutils"
|
||||
)
|
||||
|
||||
func TestPane_View_NoAnalysis(t *testing.T) {
|
||||
// Test with nil analysis
|
||||
pane := New(nil)
|
||||
pane.SetSize(80, 20)
|
||||
|
||||
view := pane.View()
|
||||
snaps.MatchSnapshot(t, view)
|
||||
}
|
||||
|
||||
func TestPane_View_WithAnalysis(t *testing.T) {
|
||||
// Load test image data
|
||||
testData := testutils.LoadTestImage(t)
|
||||
|
||||
pane := New(testData.Analysis)
|
||||
pane.SetSize(80, 20)
|
||||
|
||||
// Initialize the pane
|
||||
cmd := pane.Init()
|
||||
require.Nil(t, cmd)
|
||||
|
||||
view := pane.View()
|
||||
snaps.MatchSnapshot(t, view)
|
||||
}
|
||||
|
||||
func TestPane_View_Focused(t *testing.T) {
|
||||
// Load test image data
|
||||
testData := testutils.LoadTestImage(t)
|
||||
|
||||
pane := New(testData.Analysis)
|
||||
pane.SetSize(80, 20)
|
||||
|
||||
// Send focus message
|
||||
updatedPane, _ := pane.Update(FocusStateMsg{Focused: true})
|
||||
|
||||
view := updatedPane.(Pane).View()
|
||||
snaps.MatchSnapshot(t, view)
|
||||
}
|
||||
|
||||
func TestPane_View_SmallWidth(t *testing.T) {
|
||||
// Load test image data
|
||||
testData := testutils.LoadTestImage(t)
|
||||
|
||||
pane := New(testData.Analysis)
|
||||
pane.SetSize(40, 20) // Narrow width
|
||||
|
||||
view := pane.View()
|
||||
snaps.MatchSnapshot(t, view)
|
||||
}
|
||||
|
||||
func TestPane_View_SmallHeight(t *testing.T) {
|
||||
// Load test image data
|
||||
testData := testutils.LoadTestImage(t)
|
||||
|
||||
pane := New(testData.Analysis)
|
||||
pane.SetSize(80, 8) // Short height
|
||||
|
||||
view := pane.View()
|
||||
snaps.MatchSnapshot(t, view)
|
||||
}
|
||||
|
||||
func TestPane_View_LargeSize(t *testing.T) {
|
||||
// Load test image data
|
||||
testData := testutils.LoadTestImage(t)
|
||||
|
||||
pane := New(testData.Analysis)
|
||||
pane.SetSize(120, 40) // Large dimensions
|
||||
|
||||
view := pane.View()
|
||||
snaps.MatchSnapshot(t, view)
|
||||
}
|
||||
|
||||
func TestPane_Update_WithLayoutMsg(t *testing.T) {
|
||||
// Load test image data
|
||||
testData := testutils.LoadTestImage(t)
|
||||
|
||||
pane := New(testData.Analysis)
|
||||
|
||||
// Send layout message
|
||||
layoutMsg := testutils.TestLayout()
|
||||
updatedPane, _ := pane.Update(layoutMsg)
|
||||
|
||||
// Verify size was updated
|
||||
view := updatedPane.(Pane).View()
|
||||
snaps.MatchSnapshot(t, view)
|
||||
}
|
||||
179
cmd/dive/cli/internal/ui/v2/panes/layers/__snapshots__/pane_test.snap
Executable file
179
cmd/dive/cli/internal/ui/v2/panes/layers/__snapshots__/pane_test.snap
Executable file
|
|
@ -0,0 +1,179 @@
|
|||
|
||||
[TestPane_View_EmptyState - 1]
|
||||
╭────────────────────────────────────────────────╮
|
||||
│Layers │
|
||||
│ │
|
||||
│No layer data │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
╰────────────────────────────────────────────────╯
|
||||
---
|
||||
|
||||
[TestPane_View_WithLayers - 1]
|
||||
╭──────────────────────────────────────────────────────────────────────────────╮
|
||||
│Layers │
|
||||
│ │
|
||||
│[1/14] 28cfe03618aa 1.1 MB 0 0 0 #(nop) ADD f... 23bc2b70b201 │
|
||||
│[2/14] 1871059774ab 6.3 KB +1 0 0 #(nop) ADD f... a65b7d7ac139 │
|
||||
│[3/14] 49fe2a475548 0 B +1 0 0 mkdir -p /ro... 93e208d47175 │
|
||||
│[4/14] 80cd2ca1ffc8 6.3 KB +1 0 0 cp /somefile... 4abad3abe3cb │
|
||||
│[5/14] c99e2f8d3f62 6.3 KB 0 ~1 0 chmod 444 /r... 14c9a6ffcb6a │
|
||||
│[6/14] 5eca617bdc3b 6.3 KB +1 0 0 cp /somefile... 778fb5770ef4 │
|
||||
│[7/14] f07c3eb88757 6.3 KB +1 0 0 cp /somefile... f275b8a31a71 │
|
||||
│[8/14] 461885fc2258 6.3 KB +1 0 -1 mv /root/exa... dd1effc5eb19 │
|
||||
│[9/14] a10327f68ffe 6.3 KB +1 0 0 cp /root/sav... 8d1869a0a066 │
|
||||
│[10/14] f2fc54e25cb7 0 B 0 0 -3 rm -rf /root... bc2e36423fa3 │
|
||||
│[11/14] aad36d0b05e7 2.1 KB +2 0 0 #(nop) ADD d... 7f648d45ee7b │
|
||||
│[12/14] 3d4ad907517a 6.3 KB +1 0 0 cp /root/sav... a4b8f95f266d │
|
||||
│[13/14] 81b1b002d4b4 6.3 KB +1 0 0 cp /root/sav... 22a44d45780a │
|
||||
│[14/14] cfb35bb5c127 6.3 KB 0 ~1 0 chmod +x /ro... ba689cac6a98 │
|
||||
│ │
|
||||
│ │
|
||||
╰──────────────────────────────────────────────────────────────────────────────╯
|
||||
---
|
||||
|
||||
[TestPane_View_Focused - 1]
|
||||
╭──────────────────────────────────────────────────────────────────────────────╮
|
||||
│Layers │
|
||||
│ │
|
||||
│[1/14] 28cfe03618aa 1.1 MB 0 0 0 #(nop) ADD f... 23bc2b70b201 │
|
||||
│[2/14] 1871059774ab 6.3 KB +1 0 0 #(nop) ADD f... a65b7d7ac139 │
|
||||
│[3/14] 49fe2a475548 0 B +1 0 0 mkdir -p /ro... 93e208d47175 │
|
||||
│[4/14] 80cd2ca1ffc8 6.3 KB +1 0 0 cp /somefile... 4abad3abe3cb │
|
||||
│[5/14] c99e2f8d3f62 6.3 KB 0 ~1 0 chmod 444 /r... 14c9a6ffcb6a │
|
||||
│[6/14] 5eca617bdc3b 6.3 KB +1 0 0 cp /somefile... 778fb5770ef4 │
|
||||
│[7/14] f07c3eb88757 6.3 KB +1 0 0 cp /somefile... f275b8a31a71 │
|
||||
│[8/14] 461885fc2258 6.3 KB +1 0 -1 mv /root/exa... dd1effc5eb19 │
|
||||
│[9/14] a10327f68ffe 6.3 KB +1 0 0 cp /root/sav... 8d1869a0a066 │
|
||||
│[10/14] f2fc54e25cb7 0 B 0 0 -3 rm -rf /root... bc2e36423fa3 │
|
||||
│[11/14] aad36d0b05e7 2.1 KB +2 0 0 #(nop) ADD d... 7f648d45ee7b │
|
||||
│[12/14] 3d4ad907517a 6.3 KB +1 0 0 cp /root/sav... a4b8f95f266d │
|
||||
│[13/14] 81b1b002d4b4 6.3 KB +1 0 0 cp /root/sav... 22a44d45780a │
|
||||
│[14/14] cfb35bb5c127 6.3 KB 0 ~1 0 chmod +x /ro... ba689cac6a98 │
|
||||
│ │
|
||||
│ │
|
||||
╰──────────────────────────────────────────────────────────────────────────────╯
|
||||
---
|
||||
|
||||
[TestPane_View_SmallWidth - 1]
|
||||
╭──────────────────────────────────────╮
|
||||
│Layers │
|
||||
│ │
|
||||
│[1/14] 28cfe03618aa 1.1 MB 0 0 0 #(│
|
||||
│[2/14] 1871059774ab 6.3 KB +1 0 0 #│
|
||||
│[3/14] 49fe2a475548 0 B +1 0 0 m│
|
||||
│[4/14] 80cd2ca1ffc8 6.3 KB +1 0 0 c│
|
||||
│[5/14] c99e2f8d3f62 6.3 KB 0 ~1 0 c│
|
||||
│[6/14] 5eca617bdc3b 6.3 KB +1 0 0 c│
|
||||
│[7/14] f07c3eb88757 6.3 KB +1 0 0 c│
|
||||
│[8/14] 461885fc2258 6.3 KB +1 0 -1 │
|
||||
│[9/14] a10327f68ffe 6.3 KB +1 0 0 c│
|
||||
│[10/14] f2fc54e25cb7 0 B 0 0 -3 │
|
||||
│[11/14] aad36d0b05e7 2.1 KB +2 0 0 │
|
||||
│[12/14] 3d4ad907517a 6.3 KB +1 0 0 │
|
||||
│[13/14] 81b1b002d4b4 6.3 KB +1 0 0 │
|
||||
│[14/14] cfb35bb5c127 6.3 KB 0 ~1 0 │
|
||||
│ │
|
||||
│ │
|
||||
╰──────────────────────────────────────╯
|
||||
---
|
||||
|
||||
[TestPane_View_SmallHeight - 1]
|
||||
╭──────────────────────────────────────────────────────────────────────────────╮
|
||||
│Layers │
|
||||
│ │
|
||||
│[1/14] 28cfe03618aa 1.1 MB 0 0 0 #(nop) ADD f... 23bc2b70b201 │
|
||||
╰──────────────────────────────────────────────────────────────────────────────╯
|
||||
---
|
||||
|
||||
[TestPane_View_LargeSize - 1]
|
||||
╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
|
||||
│Layers │
|
||||
│ │
|
||||
│[1/14] 28cfe03618aa 1.1 MB 0 0 0 #(nop) ADD f... 23bc2b70b201 │
|
||||
│[2/14] 1871059774ab 6.3 KB +1 0 0 #(nop) ADD f... a65b7d7ac139 │
|
||||
│[3/14] 49fe2a475548 0 B +1 0 0 mkdir -p /ro... 93e208d47175 │
|
||||
│[4/14] 80cd2ca1ffc8 6.3 KB +1 0 0 cp /somefile... 4abad3abe3cb │
|
||||
│[5/14] c99e2f8d3f62 6.3 KB 0 ~1 0 chmod 444 /r... 14c9a6ffcb6a │
|
||||
│[6/14] 5eca617bdc3b 6.3 KB +1 0 0 cp /somefile... 778fb5770ef4 │
|
||||
│[7/14] f07c3eb88757 6.3 KB +1 0 0 cp /somefile... f275b8a31a71 │
|
||||
│[8/14] 461885fc2258 6.3 KB +1 0 -1 mv /root/exa... dd1effc5eb19 │
|
||||
│[9/14] a10327f68ffe 6.3 KB +1 0 0 cp /root/sav... 8d1869a0a066 │
|
||||
│[10/14] f2fc54e25cb7 0 B 0 0 -3 rm -rf /root... bc2e36423fa3 │
|
||||
│[11/14] aad36d0b05e7 2.1 KB +2 0 0 #(nop) ADD d... 7f648d45ee7b │
|
||||
│[12/14] 3d4ad907517a 6.3 KB +1 0 0 cp /root/sav... a4b8f95f266d │
|
||||
│[13/14] 81b1b002d4b4 6.3 KB +1 0 0 cp /root/sav... 22a44d45780a │
|
||||
│[14/14] cfb35bb5c127 6.3 KB 0 ~1 0 chmod +x /ro... ba689cac6a98 │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
|
||||
---
|
||||
|
||||
[TestPane_View_SecondLayerSelected - 1]
|
||||
╭──────────────────────────────────────────────────────────────────────────────╮
|
||||
│Layers │
|
||||
│ │
|
||||
│[1/14] 28cfe03618aa 1.1 MB 0 0 0 #(nop) ADD f... 23bc2b70b201 │
|
||||
│[2/14] 1871059774ab 6.3 KB +1 0 0 #(nop) ADD f... a65b7d7ac139 │
|
||||
│[3/14] 49fe2a475548 0 B +1 0 0 mkdir -p /ro... 93e208d47175 │
|
||||
│[4/14] 80cd2ca1ffc8 6.3 KB +1 0 0 cp /somefile... 4abad3abe3cb │
|
||||
│[5/14] c99e2f8d3f62 6.3 KB 0 ~1 0 chmod 444 /r... 14c9a6ffcb6a │
|
||||
│[6/14] 5eca617bdc3b 6.3 KB +1 0 0 cp /somefile... 778fb5770ef4 │
|
||||
│[7/14] f07c3eb88757 6.3 KB +1 0 0 cp /somefile... f275b8a31a71 │
|
||||
│[8/14] 461885fc2258 6.3 KB +1 0 -1 mv /root/exa... dd1effc5eb19 │
|
||||
│[9/14] a10327f68ffe 6.3 KB +1 0 0 cp /root/sav... 8d1869a0a066 │
|
||||
│[10/14] f2fc54e25cb7 0 B 0 0 -3 rm -rf /root... bc2e36423fa3 │
|
||||
│[11/14] aad36d0b05e7 2.1 KB +2 0 0 #(nop) ADD d... 7f648d45ee7b │
|
||||
│[12/14] 3d4ad907517a 6.3 KB +1 0 0 cp /root/sav... a4b8f95f266d │
|
||||
│[13/14] 81b1b002d4b4 6.3 KB +1 0 0 cp /root/sav... 22a44d45780a │
|
||||
│[14/14] cfb35bb5c127 6.3 KB 0 ~1 0 chmod +x /ro... ba689cac6a98 │
|
||||
│ │
|
||||
│ │
|
||||
╰──────────────────────────────────────────────────────────────────────────────╯
|
||||
---
|
||||
|
||||
[TestPane_Update_WithLayoutMsg - 1]
|
||||
╭────────────────────────────────────────────────╮
|
||||
│Layers │
|
||||
│ │
|
||||
│[1/14] 28cfe03618aa 1.1 MB 0 0 0 #(nop) ADD f│
|
||||
│[2/14] 1871059774ab 6.3 KB +1 0 0 #(nop) ADD │
|
||||
│[3/14] 49fe2a475548 0 B +1 0 0 mkdir -p /r│
|
||||
│[4/14] 80cd2ca1ffc8 6.3 KB +1 0 0 cp /somefil│
|
||||
│[5/14] c99e2f8d3f62 6.3 KB 0 ~1 0 chmod 444 /│
|
||||
│[6/14] 5eca617bdc3b 6.3 KB +1 0 0 cp /somefil│
|
||||
╰────────────────────────────────────────────────╯
|
||||
---
|
||||
150
cmd/dive/cli/internal/ui/v2/panes/layers/pane_test.go
Normal file
150
cmd/dive/cli/internal/ui/v2/panes/layers/pane_test.go
Normal file
|
|
@ -0,0 +1,150 @@
|
|||
package layers
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/gkampitakis/go-snaps/snaps"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/wagoodman/dive/cmd/dive/cli/internal/ui/v1/viewmodel"
|
||||
"github.com/wagoodman/dive/cmd/dive/cli/internal/ui/v2/testutils"
|
||||
)
|
||||
|
||||
func TestPane_View_EmptyState(t *testing.T) {
|
||||
// Test with nil layerVM
|
||||
pane := New(nil, testutils.LoadTestImage(t).Comparer)
|
||||
pane.SetSize(50, 20)
|
||||
|
||||
view := pane.View()
|
||||
snaps.MatchSnapshot(t, view)
|
||||
}
|
||||
|
||||
func TestPane_View_WithLayers(t *testing.T) {
|
||||
// Load test image data
|
||||
testData := testutils.LoadTestImage(t)
|
||||
|
||||
// Create layer viewmodel
|
||||
layerVM := &viewmodel.LayerSetState{
|
||||
Layers: testData.Analysis.Layers,
|
||||
LayerIndex: 0,
|
||||
}
|
||||
|
||||
pane := New(layerVM, testData.Comparer)
|
||||
pane.SetSize(80, 20)
|
||||
|
||||
// Initialize the pane
|
||||
cmd := pane.Init()
|
||||
require.Nil(t, cmd)
|
||||
|
||||
view := pane.View()
|
||||
snaps.MatchSnapshot(t, view)
|
||||
}
|
||||
|
||||
func TestPane_View_Focused(t *testing.T) {
|
||||
// Load test image data
|
||||
testData := testutils.LoadTestImage(t)
|
||||
|
||||
// Create layer viewmodel
|
||||
layerVM := &viewmodel.LayerSetState{
|
||||
Layers: testData.Analysis.Layers,
|
||||
LayerIndex: 0,
|
||||
}
|
||||
|
||||
pane := New(layerVM, testData.Comparer)
|
||||
pane.SetSize(80, 20)
|
||||
|
||||
// Send focus message
|
||||
updatedPane, _ := pane.Update(FocusStateMsg{Focused: true})
|
||||
|
||||
view := updatedPane.(Pane).View()
|
||||
snaps.MatchSnapshot(t, view)
|
||||
}
|
||||
|
||||
func TestPane_View_SmallWidth(t *testing.T) {
|
||||
// Load test image data
|
||||
testData := testutils.LoadTestImage(t)
|
||||
|
||||
// Create layer viewmodel
|
||||
layerVM := &viewmodel.LayerSetState{
|
||||
Layers: testData.Analysis.Layers,
|
||||
LayerIndex: 0,
|
||||
}
|
||||
|
||||
pane := New(layerVM, testData.Comparer)
|
||||
pane.SetSize(40, 20) // Narrow width
|
||||
|
||||
view := pane.View()
|
||||
snaps.MatchSnapshot(t, view)
|
||||
}
|
||||
|
||||
func TestPane_View_SmallHeight(t *testing.T) {
|
||||
// Load test image data
|
||||
testData := testutils.LoadTestImage(t)
|
||||
|
||||
// Create layer viewmodel
|
||||
layerVM := &viewmodel.LayerSetState{
|
||||
Layers: testData.Analysis.Layers,
|
||||
LayerIndex: 0,
|
||||
}
|
||||
|
||||
pane := New(layerVM, testData.Comparer)
|
||||
pane.SetSize(80, 5) // Very short height
|
||||
|
||||
view := pane.View()
|
||||
snaps.MatchSnapshot(t, view)
|
||||
}
|
||||
|
||||
func TestPane_View_LargeSize(t *testing.T) {
|
||||
// Load test image data
|
||||
testData := testutils.LoadTestImage(t)
|
||||
|
||||
// Create layer viewmodel
|
||||
layerVM := &viewmodel.LayerSetState{
|
||||
Layers: testData.Analysis.Layers,
|
||||
LayerIndex: 0,
|
||||
}
|
||||
|
||||
pane := New(layerVM, testData.Comparer)
|
||||
pane.SetSize(120, 40) // Large dimensions
|
||||
|
||||
view := pane.View()
|
||||
snaps.MatchSnapshot(t, view)
|
||||
}
|
||||
|
||||
func TestPane_View_SecondLayerSelected(t *testing.T) {
|
||||
// Load test image data
|
||||
testData := testutils.LoadTestImage(t)
|
||||
|
||||
// Create layer viewmodel with second layer selected
|
||||
layerVM := &viewmodel.LayerSetState{
|
||||
Layers: testData.Analysis.Layers,
|
||||
LayerIndex: 1, // Select second layer
|
||||
}
|
||||
|
||||
pane := New(layerVM, testData.Comparer)
|
||||
pane.SetSize(80, 20)
|
||||
|
||||
view := pane.View()
|
||||
snaps.MatchSnapshot(t, view)
|
||||
}
|
||||
|
||||
func TestPane_Update_WithLayoutMsg(t *testing.T) {
|
||||
// Load test image data
|
||||
testData := testutils.LoadTestImage(t)
|
||||
|
||||
// Create layer viewmodel
|
||||
layerVM := &viewmodel.LayerSetState{
|
||||
Layers: testData.Analysis.Layers,
|
||||
LayerIndex: 0,
|
||||
}
|
||||
|
||||
pane := New(layerVM, testData.Comparer)
|
||||
|
||||
// Send layout message
|
||||
layoutMsg := testutils.TestLayout()
|
||||
updatedPane, _ := pane.Update(layoutMsg)
|
||||
|
||||
// Verify size was updated
|
||||
view := updatedPane.(Pane).View()
|
||||
snaps.MatchSnapshot(t, view)
|
||||
}
|
||||
92
cmd/dive/cli/internal/ui/v2/testutils/helpers.go
Normal file
92
cmd/dive/cli/internal/ui/v2/testutils/helpers.go
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
package testutils
|
||||
|
||||
import (
|
||||
"os/exec"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/wagoodman/dive/cmd/dive/cli/internal/ui/v1"
|
||||
"github.com/wagoodman/dive/cmd/dive/cli/internal/ui/v1/viewmodel"
|
||||
"github.com/wagoodman/dive/cmd/dive/cli/internal/ui/v2/common"
|
||||
"github.com/wagoodman/dive/dive/filetree"
|
||||
"github.com/wagoodman/dive/dive/image"
|
||||
"github.com/wagoodman/dive/dive/image/docker"
|
||||
)
|
||||
|
||||
var repoRootCache string
|
||||
|
||||
// TestImageData provides test image data for snapshot tests
|
||||
type TestImageData struct {
|
||||
Analysis *image.Analysis
|
||||
TreeVM *viewmodel.FileTreeViewModel
|
||||
Comparer filetree.Comparer
|
||||
}
|
||||
|
||||
// repoRoot returns the root directory of the git repository
|
||||
func repoRoot(t testing.TB) string {
|
||||
t.Helper()
|
||||
if repoRootCache != "" {
|
||||
return repoRootCache
|
||||
}
|
||||
// use git to find the root of the repo
|
||||
out, err := exec.Command("git", "rev-parse", "--show-toplevel").Output()
|
||||
if err != nil {
|
||||
t.Fatalf("failed to get repo root: %v", err)
|
||||
}
|
||||
repoRootCache = strings.TrimSpace(string(out))
|
||||
return repoRootCache
|
||||
}
|
||||
|
||||
// repoPath returns a path relative to the repository root
|
||||
func repoPath(t testing.TB, path string) string {
|
||||
t.Helper()
|
||||
root := repoRoot(t)
|
||||
return root + "/" + strings.TrimPrefix(path, "./")
|
||||
}
|
||||
|
||||
// LoadTestImage loads test image data from the test archive
|
||||
func LoadTestImage(t *testing.T) TestImageData {
|
||||
t.Helper()
|
||||
|
||||
// Load test image - use repoPath to get absolute path
|
||||
result := docker.TestAnalysisFromArchive(t, repoPath(t, ".data/test-docker-image.tar"))
|
||||
require.NotNil(t, result, "unable to load test data")
|
||||
|
||||
// Create filetree viewmodel
|
||||
vm, err := viewmodel.NewFileTreeViewModel(
|
||||
v1.Config{
|
||||
Analysis: *result,
|
||||
Preferences: v1.DefaultPreferences(),
|
||||
},
|
||||
0,
|
||||
)
|
||||
require.NoError(t, err, "unable to create viewmodel")
|
||||
|
||||
// Initialize ViewTree by calling Update (this sets ViewTree = ModelTree.Copy())
|
||||
err = vm.Update(nil, 100, 100)
|
||||
require.NoError(t, err, "unable to update viewmodel")
|
||||
|
||||
// Get comparer
|
||||
comparer := filetree.NewComparer(result.RefTrees)
|
||||
errs := comparer.BuildCache()
|
||||
require.Empty(t, errs, "unable to build comparer")
|
||||
|
||||
return TestImageData{
|
||||
Analysis: result,
|
||||
TreeVM: vm,
|
||||
Comparer: comparer,
|
||||
}
|
||||
}
|
||||
|
||||
// TestLayout provides a test layout message for panes
|
||||
func TestLayout() common.LayoutMsg {
|
||||
return common.LayoutMsg{
|
||||
LeftWidth: 50,
|
||||
RightWidth: 50,
|
||||
LayersHeight: 10,
|
||||
DetailsHeight: 8,
|
||||
ImageHeight: 12,
|
||||
TreeHeight: 15,
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue