ronantakizawa/codereview-bench huggingface dataset:
Repository: jiahaog/nativefier
File: app/src/components/menu.ts (TypeScript)

Code before:
        role: 'undo',
      },
      {
        label: 'Redo',
        accelerator: 'Shift+CmdOrCtrl+Z',
        role: 'redo',
      },
      {
        type: 'separator',
      },
      {
        label: 'Cut',
        accelerator: 'CmdOrCtrl+X',
        role: 'cut',
      },
      {
        label: 'Copy',
        accelerator: 'CmdOrCtrl+C',
        role: 'copy',
      },
      {
        label: 'Copy as Plain Text',
        accelerator: 'CmdOrCtrl+Shift+C',
        click: (): void => {
          const text = clipboard.readText('selection');
          clipboard.writeText(getPlainTextWithoutFormatting(text), 'clipboard');
        },
      },
      {
        label: 'Copy Current URL',
        accelerator: 'CmdOrCtrl+L',
        click: (): void => clipboard.writeText(getCurrentURL()),
      },
      {
        label: 'Paste',
        accelerator: 'CmdOrCtrl+V',
        role: 'paste',
      },
      {
        label: 'Paste and Match Style',
        accelerator: 'CmdOrCtrl+Shift+V',
        role: 'pasteAndMatchStyle',
      },
      {
        label: 'Select All',
        accelerator: 'CmdOrCtrl+A',
        role: 'selectAll',
      },
      {
        label: 'Clear App Data',
        click: (

Review comment (suggestion):
Let's document that the bulk of the work happens here
```suggestion
          // We use clipboard.readText to strip down formatting
          const plainText = clipboard.readText('selection');
          clipboard.writeText(getPlainTextWithoutFormatting(plainText), 'clipboard');
```

Code after:
        accelerator: 'Shift+CmdOrCtrl+Z',
        role: 'redo',
      },
      {
        type: 'separator',
      },
      {
        label: 'Cut',
        accelerator: 'CmdOrCtrl+X',
        role: 'cut',
      },
      {
        label: 'Copy',
        accelerator: 'CmdOrCtrl+C',
        role: 'copy',
      },
      {
        label: 'Copy as Plain Text',
        accelerator: 'CmdOrCtrl+Shift+C',
        click: (): void => {
          // We use clipboard.readText to strip down formatting
          const text = clipboard.readText('selection');
          clipboard.writeText(cleanupPlainText(text), 'clipboard');
        },
      },
      {
        label: 'Copy Current URL',
        accelerator: 'CmdOrCtrl+L',
        click: (): void => clipboard.writeText(getCurrentURL()),
      },
      {
        label: 'Paste',
        accelerator: 'CmdOrCtrl+V',
        role: 'paste',
      },
      {
        label: 'Paste and Match Style',
        accelerator: 'CmdOrCtrl+Shift+V',
        role: 'pasteAndMatchStyle',
      },
      {
        label: 'Select All',
        accelerator: 'CmdOrCtrl+A',
        role: 'selectAll',
      },
      {
        label: 'Clear App Data',
        click: (
          item: MenuItem,
          focusedWindow: BrowserWindow | undefined,
        ): void => {
Repository: jiahaog/nativefier
File: app/src/helpers/helpers.ts (TypeScript)

Code before:
}

export function openExternal(
  url: string,
  options?: OpenExternalOptions,
): Promise<void> {
  log.debug('openExternal', { url, options });
  return shell.openExternal(url, options);
}

export function removeUserAgentSpecifics(
  userAgentFallback: string,
  appName: string,
  appVersion: string,
): string {
  // Electron userAgentFallback is the user agent used if none is specified when creating a window.
  // For our purposes, it's useful because its format is similar enough to a real Chrome's user agent to not need
  // to infer the userAgent. userAgentFallback normally looks like this:
  // Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) app-nativefier-804458/1.0.0 Chrome/89.0.4389.128 Electron/12.0.7 Safari/537.36
  // We just need to strip out the appName/1.0.0 and Electron/electronVersion
  return userAgentFallback
    .replace(`Electron/${process.versions.electron} `, '')
    .replace(`${appName}/${appVersion} `, ' ');
}

// Removes extra spaces from a text
export function cleanupPlainText(text: string): string {
  return text.trim().replace(/\s+/g, ' ');
}


Review comment (suggestion):
If you want to keep this comment, let's make it a proper JSDoc recognized as such by editors and showing up on function mouseover.
```suggestion
/** Removes extra spaces from a text */
```

Code after:
}

export function openExternal(
  url: string,
  options?: OpenExternalOptions,
): Promise<void> {
  log.debug('openExternal', { url, options });
  return shell.openExternal(url, options);
}

export function removeUserAgentSpecifics(
  userAgentFallback: string,
  appName: string,
  appVersion: string,
): string {
  // Electron userAgentFallback is the user agent used if none is specified when creating a window.
  // For our purposes, it's useful because its format is similar enough to a real Chrome's user agent to not need
  // to infer the userAgent. userAgentFallback normally looks like this:
  // Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) app-nativefier-804458/1.0.0 Chrome/89.0.4389.128 Electron/12.0.7 Safari/537.36
  // We just need to strip out the appName/1.0.0 and Electron/electronVersion
  return userAgentFallback
    .replace(`Electron/${process.versions.electron} `, '')
    .replace(`${appName}/${appVersion} `, ' ');
}

/** Removes extra spaces from a text */
export function cleanupPlainText(text: string): string {
  return text.trim().replace(/\s+/g, ' ');
}
Repository: koishijs/novelai-bot
File: src/index.ts (TypeScript)

Code before:
      try {
        token = await getToken()
      } catch (err) {
        if (err instanceof NetworkError) {
          return session.text(err.message, err.params)
        }
        logger.error(err)
        return session.text('.unknown-error')
      }

      const model = modelMap[options.model]
      const seed = options.seed || Math.floor(Math.random() * Math.pow(2, 32))

      const parameters: Dict = {
        seed,
        prompt,
        n_samples: 1,
        uc,
        // 0: low quality + bad anatomy
        // 1: low quality
        // 2: none
        ucPreset: 2,
        qualityToggle: false,
      }
      
      let image: ImageData

      if (imgUrl) {
        try {
          image = await download(ctx, imgUrl)
        } catch (err) {
          if (err instanceof NetworkError) {
            return session.text(err.message, err.params)
          }
          logger.error(err)
          return session.text('.download-error')
        }

        Object.assign(parameters, {
          scale: options.scale ?? 11,
          steps: options.steps ?? 50,
        })
        if (options.enhance) {
          const size = getImageSize(image.buffer)
          if (size.width + size.height !== 1280) {
            return session.text('.invalid-size')
          }
          Object.assign(parameters, {
            height: size.height * 1.5,
            width: size.width * 1.5,
            noise: options.noise ?? 0,

Review comment (suggestion):
This can be grouped with above code for better SoC:

```ts
let imgUrl: string, image: ImageData
```

Code after:
      try {
        token = await getToken()
      } catch (err) {
        if (err instanceof NetworkError) {
          return session.text(err.message, err.params)
        }
        logger.error(err)
        return session.text('.unknown-error')
      }

      const model = modelMap[options.model]
      const seed = options.seed || Math.floor(Math.random() * Math.pow(2, 32))

      const parameters: Dict = {
        seed,
        prompt,
        n_samples: 1,
        uc,
        // 0: low quality + bad anatomy
        // 1: low quality
        // 2: none
        ucPreset: 2,
        qualityToggle: false,
      }

      if (imgUrl) {
        try {
          image = await download(ctx, imgUrl)
        } catch (err) {
          if (err instanceof NetworkError) {
            return session.text(err.message, err.params)
          }
          logger.error(err)
          return session.text('.download-error')
        }

        Object.assign(parameters, {
          scale: options.scale ?? 11,
          steps: options.steps ?? 50,
        })
        if (options.enhance) {
          const size = getImageSize(image.buffer)
          if (size.width + size.height !== 1280) {
            return session.text('.invalid-size')
          }
          Object.assign(parameters, {
            height: size.height * 1.5,
            width: size.width * 1.5,
            noise: options.noise ?? 0,
            strength: options.strength ?? 0.2,
          })
Repository: koishijs/novelai-bot
File: src/config.ts (TypeScript)

Code before:
    'k_dpmpp_2m': 'DPM++ 2M',
    'k_dpm_fast': 'DPM fast',
    'k_dpm_ad': 'DPM adaptive',
    'k_lms_ka': 'LMS Karras',
    'k_dpm_2_ka': 'DPM2 Karras',
    'k_dpm_2_a_ka': 'DPM2 a Karras',
    'k_dpmpp_2s_a_ka': 'DPM++ 2S a Karras',
    'k_dpmpp_2m_ka': 'DPM++ 2M Karras',
    'ddim': 'DDIM',
    'plms': 'PLMS',
  }

  export function createSchema(map: Dict<string>) {
    return Schema.union(Object.entries(map).map(([key, value]) => {
      return Schema.const(key).description(value)
    })).description('默认的采样器。').default('k_euler_a')
  }

  export function sd2nai(sampler: string): string {
    if (sampler === 'k_euler_a') return 'k_euler_ancestral'
    if (sampler in nai) return sampler
    return 'k_euler_ancestral'
  }
}

export const sdUpscalers = [
  // built-in upscalers
  'None',
  'Lanczos',
  'Nearest',
  // third-party upscalers (might not be available)
  'LDSR',
  'ESRGAN_4x',
  'R-ESRGAN General 4xV3',
  'R-ESRGAN General WDN 4xV3',
  'R-ESRGAN AnimeVideo',
  'R-ESRGAN 4x+',
  'R-ESRGAN 4x+ Anime6B',
  'R-ESRGAN 2x+',
  'ScuNET GAN',
  'ScuNET PSNR',
  'SwinIR 4x',
] as const

export interface Options {
  enhance: boolean
  model: string
  resolution: Size
  sampler: string
  seed: string
  steps: number

Review comment (suggestion):
```suggestion
export const upscalers = [
```

No need to say SD here.

Code after:
    'k_dpmpp_2m': 'DPM++ 2M',
    'k_dpm_fast': 'DPM fast',
    'k_dpm_ad': 'DPM adaptive',
    'k_lms_ka': 'LMS Karras',
    'k_dpm_2_ka': 'DPM2 Karras',
    'k_dpm_2_a_ka': 'DPM2 a Karras',
    'k_dpmpp_2s_a_ka': 'DPM++ 2S a Karras',
    'k_dpmpp_2m_ka': 'DPM++ 2M Karras',
    'ddim': 'DDIM',
    'plms': 'PLMS',
  }

  export function createSchema(map: Dict<string>) {
    return Schema.union(Object.entries(map).map(([key, value]) => {
      return Schema.const(key).description(value)
    })).description('默认的采样器。').default('k_euler_a')
  }

  export function sd2nai(sampler: string): string {
    if (sampler === 'k_euler_a') return 'k_euler_ancestral'
    if (sampler in nai) return sampler
    return 'k_euler_ancestral'
  }
}

export const upscalers = [
  // built-in upscalers
  'None',
  'Lanczos',
  'Nearest',
  // third-party upscalers (might not be available)
  'LDSR',
  'ESRGAN_4x',
  'R-ESRGAN General 4xV3',
  'R-ESRGAN General WDN 4xV3',
  'R-ESRGAN AnimeVideo',
  'R-ESRGAN 4x+',
  'R-ESRGAN 4x+ Anime6B',
  'R-ESRGAN 2x+',
  'ScuNET GAN',
  'ScuNET PSNR',
  'SwinIR 4x',
] as const

export interface Options {
  enhance: boolean
  model: string
  resolution: Size
  sampler: string
  seed: string
  steps: number
Repository: koishijs/novelai-bot
File: src/index.ts (TypeScript)

Code before:
      const data: StableDiffusionWebUI.ExtraSingleImageRequest = {
        image: image.dataUrl,
        resize_mode: !!options.resolution ? 1 : 0,
        show_extras_results: true,
        upscaling_resize: options.scale,
        upscaling_resize_h: options.resolution?.height,
        upscaling_resize_w: options.resolution?.width,
        upscaling_crop: options.crop,
        upscaler_1: options.upscaler,
        upscaler_2: options.upscaler2 ?? 'None',
        extras_upscaler_2_visibility: options.upscaler2visibility ?? 1,
        upscale_first: options.upscaleFirst,
      }

      try {
        const resp = await ctx.http.axios(trimSlash(config.endpoint) + '/sdapi/v1/extra-single-image', {
          method: 'POST',
          timeout: config.requestTimeout,
          headers: {
            ...config.headers,
          },
          data,
        })
        const base64 = stripDataPrefix((resp.data as StableDiffusionWebUI.ExtraSingleImageResponse).image)
        return segment.image('base64://' + base64)
      } catch (e) { console.log (e) }
    })

  ctx.accept(['upscaler'], (config) => {
    subcmd._options.upscaler.fallback = config.upscaler
    subcmd._options.upscaler.type = sdUpscalers
  }, { immediate: true })
}


Review comment (suggestion):
It's better to handle the error, like `return session.text('.unknown-error')`.

Also you should use `logger.warn()` instead of `console.log()`.

Code after:
        upscaling_resize: options.scale,
        upscaling_resize_h: options.resolution?.height,
        upscaling_resize_w: options.resolution?.width,
        upscaling_crop: options.crop,
        upscaler_1: options.upscaler,
        upscaler_2: options.upscaler2 ?? 'None',
        extras_upscaler_2_visibility: options.visibility ?? 1,
        upscale_first: options.upscaleFirst,
      }

      try {
        const resp = await ctx.http.axios(trimSlash(config.endpoint) + '/sdapi/v1/extra-single-image', {
          method: 'POST',
          timeout: config.requestTimeout,
          headers: {
            ...config.headers,
          },
          data,
        })
        const base64 = stripDataPrefix((resp.data as StableDiffusionWebUI.ExtraSingleImageResponse).image)
        return segment.image('base64://' + base64)
      } catch (e) {
        logger.warn(e)
        return session.text('.unknown-error')
      }
    })

  ctx.accept(['upscaler'], (config) => {
    subcmd._options.upscaler.fallback = config.upscaler
  }, { immediate: true })
}
Repository: koishijs/novelai-bot
File: src/index.ts (TypeScript)

Code before:
        upscaling_resize_h: options.resolution?.height,
        upscaling_resize_w: options.resolution?.width,
        upscaling_crop: options.crop,
        upscaler_1: options.upscaler,
        upscaler_2: options.upscaler2 ?? 'None',
        extras_upscaler_2_visibility: options.upscaler2visibility ?? 1,
        upscale_first: options.upscaleFirst,
      }

      try {
        const resp = await ctx.http.axios(trimSlash(config.endpoint) + '/sdapi/v1/extra-single-image', {
          method: 'POST',
          timeout: config.requestTimeout,
          headers: {
            ...config.headers,
          },
          data,
        })
        const base64 = stripDataPrefix((resp.data as StableDiffusionWebUI.ExtraSingleImageResponse).image)
        return segment.image('base64://' + base64)
      } catch (e) { console.log (e) }
    })

  ctx.accept(['upscaler'], (config) => {
    subcmd._options.upscaler.fallback = config.upscaler
    subcmd._options.upscaler.type = sdUpscalers
  }, { immediate: true })
}


Review comment (suggestion):
```suggestion
```

This is not related to config change. You should write them above.

Code after:
        upscaler_2: options.upscaler2 ?? 'None',
        extras_upscaler_2_visibility: options.visibility ?? 1,
        upscale_first: options.upscaleFirst,
      }

      try {
        const resp = await ctx.http.axios(trimSlash(config.endpoint) + '/sdapi/v1/extra-single-image', {
          method: 'POST',
          timeout: config.requestTimeout,
          headers: {
            ...config.headers,
          },
          data,
        })
        const base64 = stripDataPrefix((resp.data as StableDiffusionWebUI.ExtraSingleImageResponse).image)
        return segment.image('base64://' + base64)
      } catch (e) {
        logger.warn(e)
        return session.text('.unknown-error')
      }
    })

  ctx.accept(['upscaler'], (config) => {
    subcmd._options.upscaler.fallback = config.upscaler
  }, { immediate: true })
}
Repository: koishijs/novelai-bot
File: src/index.ts (TypeScript)

Code before:
import { Computed, Context, Dict, h, Logger, omit, Quester, Session, SessionError, trimSlash } from 'koishi'
import { Config, modelMap, models, orientMap, parseInput, sampler, upscalers, scheduler } from './config'
import { ImageData, StableDiffusionWebUI } from './types'
import { closestMultiple, download, forceDataPrefix, getImageSize, login, NetworkError, project, resizeInput, Size } from './utils'
import { } from '@koishijs/translator'
import { } from '@koishijs/plugin-help'
import AdmZip from 'adm-zip'
import { resolve } from 'path'

export * from './config'

export const reactive = true
export const name = 'novelai'

const logger = new Logger('novelai')

function handleError(session: Session, err: Error) {
  if (Quester.Error.is(err)) {
    if (err.response?.status === 402) {
      return session.text('.unauthorized')
    } else if (err.response?.status) {
      return session.text('.response-error', [err.response.status])
    } else if (err.code === 'ETIMEDOUT') {
      return session.text('.request-timeout')
    } else if (err.code) {
      return session.text('.request-failed', [err.code])
    }
  }
  logger.error(err)
  return session.text('.unknown-error')
}

export const inject = {

Review comment (suggestion):
```suggestion
import { resolve } from 'path'
import { readFile } from 'fs/promises'
```

Code after:
import { Computed, Context, Dict, h, Logger, omit, Quester, Session, SessionError, trimSlash } from 'koishi'
import { Config, modelMap, models, orientMap, parseInput, sampler, upscalers, scheduler } from './config'
import { ImageData, StableDiffusionWebUI } from './types'
import { closestMultiple, download, forceDataPrefix, getImageSize, login, NetworkError, project, resizeInput, Size } from './utils'
import { } from '@koishijs/translator'
import { } from '@koishijs/plugin-help'
import AdmZip from 'adm-zip'
import { resolve } from 'path'
import { readFile } from 'fs/promises'

export * from './config'

export const reactive = true
export const name = 'novelai'

const logger = new Logger('novelai')

function handleError(session: Session, err: Error) {
  if (Quester.Error.is(err)) {
    if (err.response?.status === 402) {
      return session.text('.unauthorized')
    } else if (err.response?.status) {
      return session.text('.response-error', [err.response.status])
    } else if (err.code === 'ETIMEDOUT') {
      return session.text('.request-timeout')
    } else if (err.code) {
      return session.text('.request-failed', [err.code])
    }
  }
  logger.error(err)
  return session.text('.unknown-error')
}
Repository: labstack/echo
File: context.go (Go)

Code before:

func (c *context) Render(code int, name string, data interface{}) (err error) {
	if c.echo.Renderer == nil {
		return ErrRendererNotRegistered
	}
	buf := new(bytes.Buffer)
	if err = c.echo.Renderer.Render(buf, name, data, c); err != nil {
		return
	}
	return c.HTMLBlob(code, buf.Bytes())
}

func (c *context) HTML(code int, html string) (err error) {
	return c.HTMLBlob(code, []byte(html))
}

func (c *context) HTMLBlob(code int, b []byte) (err error) {
	return c.Blob(code, MIMETextHTMLCharsetUTF8, b)
}

func (c *context) String(code int, s string) (err error) {
	return c.Blob(code, MIMETextPlainCharsetUTF8, []byte(s))
}

func (c *context) JSON(code int, i interface{}) (err error) {
	query := c.request.URL.Query()
	_, isPretty := query["pretty"]

	if c.echo.Debug || isPretty {
		return c.JSONPretty(code, i, "  ")
	}
	b, err := json.Marshal(i)
	if err != nil {
		return
	}
	return c.JSONBlob(code, b)
}

func (c *context) JSONPretty(code int, i interface{}, indent string) (err error) {
	b, err := json.MarshalIndent(i, "", indent)
	if err != nil {
		return
	}
	return c.JSONBlob(code, b)
}

func (c *context) JSONBlob(code int, b []byte) (err error) {
	return c.Blob(code, MIMEApplicationJSONCharsetUTF8, b)
}

func (c *context) JSONP(code int, callback string, i interface{}) (err error) {

Review comment (suggestion):
You can directly use `_, pretty := c.QueryParams()["pretty"]`. Just for consistency please rename the `isPretty` to `pretty`.

PS: Same for XML

Code after:

func (c *context) Render(code int, name string, data interface{}) (err error) {
	if c.echo.Renderer == nil {
		return ErrRendererNotRegistered
	}
	buf := new(bytes.Buffer)
	if err = c.echo.Renderer.Render(buf, name, data, c); err != nil {
		return
	}
	return c.HTMLBlob(code, buf.Bytes())
}

func (c *context) HTML(code int, html string) (err error) {
	return c.HTMLBlob(code, []byte(html))
}

func (c *context) HTMLBlob(code int, b []byte) (err error) {
	return c.Blob(code, MIMETextHTMLCharsetUTF8, b)
}

func (c *context) String(code int, s string) (err error) {
	return c.Blob(code, MIMETextPlainCharsetUTF8, []byte(s))
}

func (c *context) JSON(code int, i interface{}) (err error) {
	_, pretty := c.request.URL.Query()["pretty"]
	if c.echo.Debug || pretty {
		return c.JSONPretty(code, i, "  ")
	}
	b, err := json.Marshal(i)
	if err != nil {
		return
	}
	return c.JSONBlob(code, b)
}

func (c *context) JSONPretty(code int, i interface{}, indent string) (err error) {
	b, err := json.MarshalIndent(i, "", indent)
	if err != nil {
		return
	}
	return c.JSONBlob(code, b)
}

func (c *context) JSONBlob(code int, b []byte) (err error) {
	return c.Blob(code, MIMEApplicationJSONCharsetUTF8, b)
}

func (c *context) JSONP(code int, callback string, i interface{}) (err error) {
	b, err := json.Marshal(i)
	if err != nil {
Repository: labstack/echo
File: middleware/redirect_test.go (Go)

Code before:
package middleware

import (
	"net/http"
	"net/http/httptest"
	"testing"

	"github.com/labstack/echo"
	"github.com/stretchr/testify/assert"
)

type redirectFunc func() echo.MiddlewareFunc

func TestRedirectHTTPSRedirect(t *testing.T) {
	res := redirectTest(HTTPSRedirect, "labstack.com")

	assert.Equal(t, http.StatusMovedPermanently, res.Code)
	assert.Equal(t, "https://labstack.com/", res.Header().Get(echo.HeaderLocation))
}

func TestRedirectHTTPSWWWRedirect(t *testing.T) {
	res := redirectTest(HTTPSWWWRedirect, "labstack.com")

	assert.Equal(t, http.StatusMovedPermanently, res.Code)
	assert.Equal(t, "https://www.labstack.com/", res.Header().Get(echo.HeaderLocation))
}

func TestRedirectHTTPSNonWWWRedirect(t *testing.T) {
	res := redirectTest(HTTPSNonWWWRedirect, "www.labstack.com")

	assert.Equal(t, http.StatusMovedPermanently, res.Code)
	assert.Equal(t, "https://labstack.com/", res.Header().Get(echo.HeaderLocation))
}

func TestRedirectWWWRedirect(t *testing.T) {
	res := redirectTest(WWWRedirect, "labstack.com")


Review comment (suggestion):
This is probably not the best name for this type, as it's nothing specific to redirect, it's just a function that returns a middleware (and all middleware "generators" do this). Is there a type for this already? If not what should we call it? `middlewareGen` ? `middlewareConstructor` ? ... 

Code after:
package middleware

import (
	"net/http"
	"net/http/httptest"
	"testing"

	"github.com/labstack/echo"
	"github.com/stretchr/testify/assert"
)

type middlewareGenerator func() echo.MiddlewareFunc

func TestRedirectHTTPSRedirect(t *testing.T) {
	res := redirectTest(HTTPSRedirect, "labstack.com")

	assert.Equal(t, http.StatusMovedPermanently, res.Code)
	assert.Equal(t, "https://labstack.com/", res.Header().Get(echo.HeaderLocation))
}

func TestRedirectHTTPSWWWRedirect(t *testing.T) {
	res := redirectTest(HTTPSWWWRedirect, "labstack.com")

	assert.Equal(t, http.StatusMovedPermanently, res.Code)
	assert.Equal(t, "https://www.labstack.com/", res.Header().Get(echo.HeaderLocation))
}

func TestRedirectHTTPSNonWWWRedirect(t *testing.T) {
	res := redirectTest(HTTPSNonWWWRedirect, "www.labstack.com")

	assert.Equal(t, http.StatusMovedPermanently, res.Code)
	assert.Equal(t, "https://labstack.com/", res.Header().Get(echo.HeaderLocation))
}

func TestRedirectWWWRedirect(t *testing.T) {
	res := redirectTest(WWWRedirect, "labstack.com")