ronantakizawa/codereview-bench huggingface dataset:
Repository: fyne-io/fyne
File: widget/richtext_objects.go (Go)

Code before:
}

// ListSegment includes an itemised list with the content set using the Items field.
//
// Since: 2.1
type ListSegment struct {
	Items   []RichTextSegment
	Ordered bool

	// Start is the number an ordered list will start counting from
	//
	// Since: 2.7
	Start int
}

// Inline returns false as a list should be in a block.
func (l *ListSegment) Inline() bool {
	return false
}

// Segments returns the segments required to draw bullets before each item
func (l *ListSegment) Segments() []RichTextSegment {
	out := make([]RichTextSegment, len(l.Items))
	if l.Start == 0 {
		l.Start = 1
	}
	for i, in := range l.Items {
		txt := "• "
		if l.Ordered {
			txt = strconv.Itoa(i+l.Start) + "."
		}
		bullet := &TextSegment{Text: txt + " ", Style: RichTextStyleStrong}
		out[i] = &ParagraphSegment{Texts: []RichTextSegment{
			bullet,
			in,
		}}
	}
	return out
}

// Textual returns no content for a list as the content is in sub-segments.
func (l *ListSegment) Textual() string {
	return ""
}

// Visual returns no additional elements for this segment.
func (l *ListSegment) Visual() fyne.CanvasObject {
	return nil
}

// Update doesn't need to change a list visual.

Review comment (suggestion):
TBH I'm not sure about this approach. Maybe its better to set a local variable here instead of mutating the struct state, i.e:
```suggestion
    start := l.Start
	if start == 0 {
		start = 1
	}
```
LMK if that's better

Code after:
}

// ListSegment includes an itemised list with the content set using the Items field.
//
// Since: 2.1
type ListSegment struct {
	Items   []RichTextSegment
	Ordered bool

	// startIndex is the starting number - 1 (If it is ordered). Unordered lists
	// ignore startIndex.
	//
	// startIndex is set to start - 1 to allow the empty value of ListSegment to have a starting
	// number of 1, while also allowing the caller to override the starting
	// number to any int, including 0.
	startIndex int
}

// SetStartNumber sets the starting number for an ordered list.
// Unordered lists are not affected.
//
// Since: 2.7
func (l *ListSegment) SetStartNumber(s int) {
	l.startIndex = s - 1
}

// StartNumber return the starting number for an ordered list.
//
// Since: 2.7
func (l *ListSegment) StartNumber() int {
	return l.startIndex + 1
}

// Inline returns false as a list should be in a block.
func (l *ListSegment) Inline() bool {
	return false
}

// Segments returns the segments required to draw bullets before each item
func (l *ListSegment) Segments() []RichTextSegment {
	out := make([]RichTextSegment, len(l.Items))
	for i, in := range l.Items {
		txt := "• "
		if l.Ordered {
			txt = strconv.Itoa(i+l.startIndex+1) + "."
		}
		bullet := &TextSegment{Text: txt + " ", Style: RichTextStyleStrong}
		out[i] = &ParagraphSegment{Texts: []RichTextSegment{
			bullet,
			in,
		}}
Repository: fyne-io/fyne
File: internal/async/queue_migratedfynedo.go (Go)

Code before:

// CanvasObjectQueue represents a simple single threaded queue for managing canvas objects.
type CanvasObjectQueue struct {
	items []fyne.CanvasObject
}

// NewCanvasObjectQueue returns a queue for caching values.
func NewCanvasObjectQueue() *CanvasObjectQueue {
	return &CanvasObjectQueue{items: make([]fyne.CanvasObject, 0, 32)}
}

// In puts the given value at the tail of the queue.
func (q *CanvasObjectQueue) In(v fyne.CanvasObject) {
	q.items = append(q.items, v)
}

// Out removes and returns the value at the head of the queue.
// It returns nil if the queue is empty.
func (q *CanvasObjectQueue) Out() fyne.CanvasObject {
	if len(q.items) == 0 {
		return nil
	}

	head := q.items[0]
	q.items[0] = nil
	q.items = q.items[1:]
	return head
}

// Len returns the number of items in the queue.
func (q *CanvasObjectQueue) Len() uint64 {
	return uint64(len(q.items))
}


Review comment (suggestion):
Definitely a nice idea for an improvement! I think we want an expandable ring buffer implementation, so that we can re-use the array space for objects that have been dequeued. As is, I believe this will re-allocate a new backing slice at a minimum every 32 items enqueued, even if only a few are actually in the queue at a time before being dequeued.

Code after:

const defaultQueueCapacity = 64

// CanvasObjectQueue represents a single-threaded queue for managing canvas objects using a ring buffer.
type CanvasObjectQueue struct {
	buffer []fyne.CanvasObject
	head   int
	size   int
}

// NewCanvasObjectQueue returns a queue for caching values with an initial capacity.
func NewCanvasObjectQueue() *CanvasObjectQueue {
	return &CanvasObjectQueue{buffer: make([]fyne.CanvasObject, defaultQueueCapacity)}
}

// In adds the given value to the tail of the queue.
// If the queue is full, it grows the buffer dynamically.
func (q *CanvasObjectQueue) In(v fyne.CanvasObject) {
	if q.size == len(q.buffer) {
		buffer := make([]fyne.CanvasObject, len(q.buffer)*2)
		copy(buffer, q.buffer[q.head:])
		copy(buffer[len(q.buffer)-q.head:], q.buffer[:q.head])
		q.buffer = buffer
		q.head = 0
	}

	tail := (q.head + q.size) % len(q.buffer)
	q.buffer[tail] = v
	q.size++
}

// Out removes and returns the value at the head of the queue.
// It returns nil if the queue is empty.
func (q *CanvasObjectQueue) Out() fyne.CanvasObject {
	if q.size == 0 {
		return nil
	}

	first := q.buffer[q.head]
	q.buffer[q.head] = nil
	q.head = (q.head + 1) % len(q.buffer)
	q.size--

	if q.size == 0 && len(q.buffer) > 4*defaultQueueCapacity {
		q.buffer = make([]fyne.CanvasObject, defaultQueueCapacity)
	}

	return first
}

// Len returns the number of items in the queue.
Repository: fyne-io/fyne
File: internal/theme/render.go (Go)

Code before:
	"fyne.io/fyne/v2"
)

var themeStack []fyne.Theme

// CurrentlyRenderingWithFallback returns the theme that is currently being used during rendering or layout
// calculations. If there is no override in effect then the fallback is returned.
func CurrentlyRenderingWithFallback(f fyne.Theme) fyne.Theme {
	if len(themeStack) == 0 {
		return f
	}

	return themeStack[len(themeStack)-1]
}

// PushRenderingTheme is used by the ThemeOverride container to stack the current theme during rendering
// and calculations.
func PushRenderingTheme(th fyne.Theme) {
	themeStack = append(themeStack, th)
}

// PopRenderingTheme is used by the ThemeOverride container to remove an overridden theme during rendering
// and calculations.
func PopRenderingTheme() {
	themeStack = themeStack[:len(themeStack)-1]
}


Review comment (suggestion):
```suggestion
	themeStack[len(themeStack)-1] = nil
	themeStack = themeStack[:len(themeStack)-1]
```

Code after:
	"fyne.io/fyne/v2"
)

var themeStack []fyne.Theme

// CurrentlyRenderingWithFallback returns the theme that is currently being used during rendering or layout
// calculations. If there is no override in effect then the fallback is returned.
func CurrentlyRenderingWithFallback(f fyne.Theme) fyne.Theme {
	if len(themeStack) == 0 {
		return f
	}

	return themeStack[len(themeStack)-1]
}

// PushRenderingTheme is used by the ThemeOverride container to stack the current theme during rendering
// and calculations.
func PushRenderingTheme(th fyne.Theme) {
	themeStack = append(themeStack, th)
}

// PopRenderingTheme is used by the ThemeOverride container to remove an overridden theme during rendering
// and calculations.
func PopRenderingTheme() {
	themeStack[len(themeStack)-1] = nil
	themeStack = themeStack[:len(themeStack)-1]
}
Repository: fyne-io/fyne
File: internal/widget/scroller_behavior_darwin.go (Go)

Code before:
//go:build darwin

package widget

/*
int getScrollerPagingBehavior();
*/
import "C"

func isScrollerPageOnTap() bool {
	if C.getScrollerPagingBehavior() == 0 {
		return true
	}
	return false
}


Review comment (suggestion):
```suggestion
	return C.getScrollerPagingBehavior() == 0
```

Code after:
//go:build darwin

package widget

/*
int getScrollerPagingBehavior();
*/
import "C"

func isScrollerPageOnTap() bool {
	return C.getScrollerPagingBehavior() == 0
}
Repository: fyne-io/fyne
File: container/clip.go (Go)

Code before:
package container

import (
	"fyne.io/fyne/v2"
	"fyne.io/fyne/v2/widget"
)

// Declare conformity with CanvasObject interface
var _ fyne.CanvasObject = (*Clip)(nil)

// Clip describes a rectangular region  that will clip anything outside its bounds.
//
// Since: 2.7
type Clip struct {
	widget.BaseWidget
	Content fyne.CanvasObject
}

// NewClip returns a new rectangular clipping object.
//
// Since: 2.7
func NewClip(content fyne.CanvasObject) *Clip {
	return &Clip{Content: content}
}

func (c *Clip) CreateRenderer() fyne.WidgetRenderer {
	c.ExtendBaseWidget(c)
	return newClipRenderer(c)
}

// MinSize for a Clip simply returns Size{1, 1} as there is no
// explicit content
func (c *Clip) MinSize() fyne.Size {
	c.ExtendBaseWidget(c)

Review comment (suggestion):
shouldn't this be asserting against the `fyne.Widget` interface, since it's a widget, and the fact that it's clipping is actually looked up based on the renderer in the driver? (In other words, it would not work if container.Clip were "merely" a fyne.CanvasObject)

Code after:
package container

import (
	"fyne.io/fyne/v2"
	"fyne.io/fyne/v2/widget"
)

// Declare conformity with Widget interface
var _ fyne.Widget = (*Clip)(nil)

// Clip describes a rectangular region  that will clip anything outside its bounds.
//
// Since: 2.7
type Clip struct {
	widget.BaseWidget
	Content fyne.CanvasObject
}

// NewClip returns a new rectangular clipping object.
//
// Since: 2.7
func NewClip(content fyne.CanvasObject) *Clip {
	return &Clip{Content: content}
}

func (c *Clip) CreateRenderer() fyne.WidgetRenderer {
	c.ExtendBaseWidget(c)
	return newClipRenderer(c)
}

// MinSize for a Clip simply returns Size{1, 1} as there is no
// explicit content
func (c *Clip) MinSize() fyne.Size {
	c.ExtendBaseWidget(c)
Repository: fyne-io/fyne
File: internal/repository/file.go (Go)

Code before:

	return storage.NewFileURI(parent), nil
}

// Child implements repository.HierarchicalRepository.Child
//
// Since: 2.0
func (r *FileRepository) Child(u fyne.URI, component string) (fyne.URI, error) {
	child := strings.Builder{}

	child.WriteString(u.Scheme())
	child.WriteString("://")
	child.WriteString(u.Authority())
	child.WriteString(path.Join(u.Path(), component))

	// stick the query and fragment back on the end
	if query := u.Query(); len(query) > 0 {
		child.WriteByte('?')
		child.WriteString(query)
	}
	if fragment := u.Fragment(); len(fragment) > 0 {
		child.WriteByte('#')
		child.WriteString(fragment)
	}

	return storage.ParseURI(child.String())
}

// List implements repository.ListableRepository.List()
//
// Since: 2.0
func (r *FileRepository) List(u fyne.URI) ([]fyne.URI, error) {
	p := u.Path()
	files, err := os.ReadDir(p)
	if err != nil {
		return nil, err
	}

	urilist := make([]fyne.URI, 0, len(files))
	for _, f := range files {
		uri := storage.NewFileURI(path.Join(p, f.Name()))
		urilist = append(urilist, uri)
	}

	return urilist, nil
}

// CreateListable implements repository.ListableRepository.CreateListable.
func (r *FileRepository) CreateListable(u fyne.URI) error {
	path := u.Path()
	return os.Mkdir(path, 0o755)

Review comment (suggestion):
Note to self: this can be factored out as a `internal/repository.URIBuilder` which we then can use in `storage` as well.

Code after:
	return storage.NewFileURI(parent), nil
}

// Child implements repository.HierarchicalRepository.Child
//
// Since: 2.0
func (r *FileRepository) Child(u fyne.URI, component string) (fyne.URI, error) {
	return storage.NewFileURI(path.Join(u.Path(), component)), nil
}

// List implements repository.ListableRepository.List()
//
// Since: 2.0
func (r *FileRepository) List(u fyne.URI) ([]fyne.URI, error) {
	p := u.Path()
	files, err := os.ReadDir(p)
	if err != nil {
		return nil, err
	}

	urilist := make([]fyne.URI, len(files))
	for i, f := range files {
		urilist[i] = storage.NewFileURI(path.Join(p, f.Name()))
	}

	return urilist, nil
}

// CreateListable implements repository.ListableRepository.CreateListable.
func (r *FileRepository) CreateListable(u fyne.URI) error {
	path := u.Path()
	return os.Mkdir(path, 0o755)
}

// CanList implements repository.ListableRepository.CanList()
//
// Since: 2.0
func (r *FileRepository) CanList(u fyne.URI) (bool, error) {
	p := u.Path()
	info, err := os.Stat(p)
	if err != nil {
		if os.IsNotExist(err) {
			return false, nil
		}
		return false, err
	}

	if !info.IsDir() {
		return false, nil
	}
Repository: fyne-io/fyne
File: theme/json_test.go (Go)

Code before:
        "focus": "#473847FF",
        "foreground": "#CDD6F4FF",
        "foregroundOnError": "#1E1E2EFF",
        "foregroundOnPrimary": "#1E1E2EFF",
        "foregroundOnSuccess": "#1E1E2EFF",
        "foregroundOnWarning": "#1E1E2EFF",
        "headerBackground": "#313244FF",
        "hover": "#322B3AFF",
        "hyperlink": "#EBA0ACFF",
        "inputBackground": "#181825FF",
        "inputBorder": "#313244FF",
        "menuBackground": "#181825FF",
        "overlayBackground": "#181825FF",
        "placeholder": "#9399B2FF",
        "pressed": "#31324466",
        "primary": "#EBA0ACFF",
        "scrollBar": "#18182599",
        "selection": "#513E4DFF",
        "separator": "#11111BFF",
        "success": "#A6E3A1FF",
        "warning": "#F9E2AFFF"
    }
}`)

	assert.NoError(b, err)

	for i := 0; i < b.N; i++ {
		_ = th.Color("primary", theme.VariantDark)
		_ = th.Color("disabledButton", theme.VariantDark)
	}
}


Review comment (suggestion):
You'll want to reset the benchmark timer here. You can call `b.ResetTimer()`, I think. Otherwise you'll get the JSON setup included as part of the calculated time.

Code after:
        "disabled": "#CDD6F4FF",
        "error": "#F38BA8FF",
        "focus": "#473847FF",
        "foreground": "#CDD6F4FF",
        "foregroundOnError": "#1E1E2EFF",
        "foregroundOnPrimary": "#1E1E2EFF",
        "foregroundOnSuccess": "#1E1E2EFF",
        "foregroundOnWarning": "#1E1E2EFF",
        "headerBackground": "#313244FF",
        "hover": "#322B3AFF",
        "hyperlink": "#EBA0ACFF",
        "inputBackground": "#181825FF",
        "inputBorder": "#313244FF",
        "menuBackground": "#181825FF",
        "overlayBackground": "#181825FF",
        "placeholder": "#9399B2FF",
        "pressed": "#31324466",
        "primary": "#EBA0ACFF",
        "scrollBar": "#18182599",
        "selection": "#513E4DFF",
        "separator": "#11111BFF",
        "success": "#A6E3A1FF",
        "warning": "#F9E2AFFF"
    }
}`)

	assert.NoError(b, err)
	var localResult color.Color
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		localResult = th.Color("primary", theme.VariantDark)
	}
	result = localResult
}
Repository: fyne-io/fyne
File: theme/json_test.go (Go)

Code before:
        "foregroundOnPrimary": "#1E1E2EFF",
        "foregroundOnSuccess": "#1E1E2EFF",
        "foregroundOnWarning": "#1E1E2EFF",
        "headerBackground": "#313244FF",
        "hover": "#322B3AFF",
        "hyperlink": "#EBA0ACFF",
        "inputBackground": "#181825FF",
        "inputBorder": "#313244FF",
        "menuBackground": "#181825FF",
        "overlayBackground": "#181825FF",
        "placeholder": "#9399B2FF",
        "pressed": "#31324466",
        "primary": "#EBA0ACFF",
        "scrollBar": "#18182599",
        "selection": "#513E4DFF",
        "separator": "#11111BFF",
        "success": "#A6E3A1FF",
        "warning": "#F9E2AFFF"
    }
}`)

	assert.NoError(b, err)

	for i := 0; i < b.N; i++ {
		_ = th.Color("primary", theme.VariantDark)
		_ = th.Color("disabledButton", theme.VariantDark)
	}
}


Review comment (bug):
These will likely be partially optimized out by the compiler because it sees that the results are never used. What you want to do is place a global variable "a sink" to prevent your variables in the benchmark loop to not be optimised out. Place a local variable in the function, set the local variable in the loop and then set the global variable to the local variable after the loop.

Also FYI: Just keep in mind that the per operation time in the benchmark will be for two calls to the function and not one in this case. Not necessarily wrong but might make the function look slower than what it is. If you want a more realistic benchmark, you can of course add more calls instead.

Code after:
        "foreground": "#CDD6F4FF",
        "foregroundOnError": "#1E1E2EFF",
        "foregroundOnPrimary": "#1E1E2EFF",
        "foregroundOnSuccess": "#1E1E2EFF",
        "foregroundOnWarning": "#1E1E2EFF",
        "headerBackground": "#313244FF",
        "hover": "#322B3AFF",
        "hyperlink": "#EBA0ACFF",
        "inputBackground": "#181825FF",
        "inputBorder": "#313244FF",
        "menuBackground": "#181825FF",
        "overlayBackground": "#181825FF",
        "placeholder": "#9399B2FF",
        "pressed": "#31324466",
        "primary": "#EBA0ACFF",
        "scrollBar": "#18182599",
        "selection": "#513E4DFF",
        "separator": "#11111BFF",
        "success": "#A6E3A1FF",
        "warning": "#F9E2AFFF"
    }
}`)

	assert.NoError(b, err)
	var localResult color.Color
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		localResult = th.Color("primary", theme.VariantDark)
	}
	result = localResult
}
Repository: fyne-io/fyne
File: dialog/file.go (Go)

Code before:
		}

		return strings.ToLower(icons[i].Name()) < strings.ToLower(icons[j].Name())
	})
	f.data = icons

	f.files.Refresh()
	f.filesScroll.Offset = fyne.NewPos(0, 0)
	f.filesScroll.Refresh()
}

func (f *fileDialog) setLocation(dir fyne.URI) error {
	if dir == nil {
		return errors.New("failed to open nil directory")
	}

	if f.selectedID > -1 {
		f.files.Unselect(f.selectedID)
	}

	list, err := storage.ListerForURI(dir)
	if err != nil {
		return err
	}

	isDir, err := storage.CanList(dir)
	if err != nil {
		return err
	} else if !isDir {
		return errors.New("location was not a listable URI")
	}

	fyne.CurrentApp().Preferences().SetString(lastFolderKey, dir.String())
	isFav := false
	for i, fav := range f.favorites {
		if storage.EqualURI(fav.loc, dir) {
			f.favoritesList.Select(i)
			isFav = true
			break
		}
	}
	if !isFav {
		f.favoritesList.UnselectAll()
	}

	f.setSelected(nil, -1)
	f.dir = list

	f.breadcrumb.Objects = nil
	for parent := dir; parent != nil && err == nil; parent, err = storage.Parent(parent) {
		currentParent := parent

Review comment (bug):
I don't know if it's related to the failures but this refactor seems to change behaviour.

This particular line won't add anything because the previous line got a lister, which will error if it cannot list.

I think this code came form inside a for loop so I'm not clear if it wasn't needed or if it was moved to the wrong location.

Code after:
		}

		return strings.ToLower(icons[i].Name()) < strings.ToLower(icons[j].Name())
	})
	f.data = icons

	f.files.Refresh()
	f.filesScroll.Offset = fyne.NewPos(0, 0)
	f.filesScroll.Refresh()
}

func (f *fileDialog) setLocation(dir fyne.URI) error {
	if dir == nil {
		return errors.New("failed to open nil directory")
	}

	if f.selectedID > -1 {
		f.files.Unselect(f.selectedID)
	}

	list, err := storage.ListerForURI(dir)
	if err != nil {
		return err
	}

	fyne.CurrentApp().Preferences().SetString(lastFolderKey, dir.String())
	isFav := false
	for i, fav := range f.favorites {
		if storage.EqualURI(fav.loc, dir) {
			f.favoritesList.Select(i)
			isFav = true
			break
		}
	}
	if !isFav {
		f.favoritesList.UnselectAll()
	}

	f.setSelected(nil, -1)
	f.dir = list

	f.breadcrumb.Objects = nil
	for parent := dir; parent != nil && err == nil; parent, err = storage.Parent(parent) {
		currentParent := parent
		f.breadcrumb.Add(
			widget.NewButton(currentParent.Name(), func() {
				err := f.setLocation(currentParent)
				if err != nil {
					fyne.LogError("Failed to set directory", err)
				}
			}),
Repository: fyne-io/fyne
File: widget/markdown_test.go (Go)

Code before:
	} {
		t.Run(name, func(t *testing.T) {
			r := NewRichTextFromMarkdown(tt.text)

			assert.Len(t, r.Segments, 1)
			if list, ok := r.Segments[0].(*ListSegment); ok {
				assert.Equal(t, tt.Start, list.StartNumber())
				assert.Equal(t, tt.startIndex, list.startIndex)
			} else {
				t.Error("Segment should be a List")
			}
		})
	}
}

func TestRichTextMarkdown_Separator(t *testing.T) {
	r := NewRichTextFromMarkdown("---\n")

	assert.Len(t, r.Segments, 1)
	if _, ok := r.Segments[0].(*SeparatorSegment); !ok {
		t.Error("Segment should be a separator")
	}
}

func TestRichTextMarkdown_Paragraph(t *testing.T) {
	r := NewRichTextFromMarkdown("foo")

	assert.Len(t, r.Segments, 2)
	if text, ok := r.Segments[1].(*TextSegment); ok {
		assert.Equal(t, "", text.Text)
		assert.Equal(t, RichTextStyleParagraph, text.Style)
	} else {
		t.Error("Last segment of paragraph should be empty text")
	}
}

func TestRichTextMarkdown_NewlinesAroundEmphasis(t *testing.T) {
	r := NewRichTextFromMarkdown("foo\n*bar*\nbaz")
	assert.Equal(t, "foo bar baz", r.String())
}

func TestRichTextMarkdown_NewlinesAroundStrong(t *testing.T) {
	r := NewRichTextFromMarkdown("foo\n**bar**\nbaz")
	assert.Equal(t, "foo bar baz", r.String())
}

func TestRichTextMarkdown_NewlinesAroundHyperlink(t *testing.T) {
	r := NewRichTextFromMarkdown("foo\n[bar](https://fyne.io/)\nbaz")
	assert.Equal(t, "foo bar baz", r.String())
}


Review comment (security):
Are `&mdash;` style HTML-escapes part of the Markdown spec? If not, I think this is beyond our level of concern, and the client code should be expected to remove HTML escapes/tags if needed

Code after:
	} {
		t.Run(name, func(t *testing.T) {
			r := NewRichTextFromMarkdown(tt.text)

			assert.Len(t, r.Segments, 1)
			if list, ok := r.Segments[0].(*ListSegment); ok {
				assert.Equal(t, tt.Start, list.StartNumber())
				assert.Equal(t, tt.startIndex, list.startIndex)
			} else {
				t.Error("Segment should be a List")
			}
		})
	}
}

func TestRichTextMarkdown_Separator(t *testing.T) {
	r := NewRichTextFromMarkdown("---\n")

	assert.Len(t, r.Segments, 1)
	if _, ok := r.Segments[0].(*SeparatorSegment); !ok {
		t.Error("Segment should be a separator")
	}
}

func TestRichTextMarkdown_TextEncode(t *testing.T) {
	r := NewRichTextFromMarkdown("a&mdash;b")

	assert.GreaterOrEqual(t, len(r.Segments), 1)
	if _, ok := r.Segments[0].(*TextSegment); !ok {
		t.Error("Segment should be a text segment")
	}

	assert.Equal(t, "a—b", r.Segments[0].(*TextSegment).Text)
}

func TestRichTextMarkdown_Paragraph(t *testing.T) {
	r := NewRichTextFromMarkdown("foo")

	assert.Len(t, r.Segments, 2)
	if text, ok := r.Segments[1].(*TextSegment); ok {
		assert.Equal(t, "", text.Text)
		assert.Equal(t, RichTextStyleParagraph, text.Style)
	} else {
		t.Error("Last segment of paragraph should be empty text")
	}
}

func TestRichTextMarkdown_NewlinesAroundEmphasis(t *testing.T) {
	r := NewRichTextFromMarkdown("foo\n*bar*\nbaz")
	assert.Equal(t, "foo bar baz", r.String())
}